diff --git a/docs/sql/init.sql b/docs/sql/init.sql index 53bc846a0ff8abb5bba80f394a24d4e3bcc4de31..c59f0d80e4ac92dcd7d2eafcaa8ae1923305bf2b 100644 --- a/docs/sql/init.sql +++ b/docs/sql/init.sql @@ -282,6 +282,7 @@ CREATE TABLE `t_pay_order` ( `channel_extra` VARCHAR(512) DEFAULT NULL COMMENT '特定渠道发起额外参数', `channel_user` VARCHAR(64) DEFAULT NULL COMMENT '渠道用户标识,如微信openId,支付宝账号', `channel_order_no` VARCHAR(64) DEFAULT NULL COMMENT '渠道订单号', + `refund_state` TINYINT(6) NOT NULL DEFAULT '0' COMMENT '退款状态: 0-未发生实际退款, 1-部分退款, 2-全额退款', `refund_times` INT NOT NULL DEFAULT 0 COMMENT '退款次数', `refund_amount` BIGINT(20) NOT NULL DEFAULT 0 COMMENT '退款总金额,单位分', `division_flag` TINYINT(6) DEFAULT 0 COMMENT '订单分账标志:0-否 1-是', diff --git a/jeepay-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrder.java b/jeepay-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrder.java index 3f9aea02d20f0f16d8f0d5970f5dcc666c6ee751..57fd0f43548e7aa77d1fe04c053dd79d4a120180 100644 --- a/jeepay-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrder.java +++ b/jeepay-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrder.java @@ -55,6 +55,9 @@ public class PayOrder extends BaseModel implements Serializable { public static final byte STATE_REFUND = 5; //已退款 public static final byte STATE_CLOSED = 6; //订单关闭 + public static final byte REFUND_STATE_NONE = 0; //未发生实际退款 + public static final byte REFUND_STATE_SUB = 1; //部分退款 + public static final byte REFUND_STATE_ALL = 2; //全额退款 /** * 支付订单号 @@ -152,6 +155,11 @@ public class PayOrder extends BaseModel implements Serializable { */ private String channelOrderNo; + /** + * 退款状态: 0-未发生实际退款, 1-部分退款, 2-全额退款 + */ + private Byte refundState; + /** * 退款次数 */ diff --git a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/AbstractRefundService.java b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/AbstractRefundService.java new file mode 100644 index 0000000000000000000000000000000000000000..e13bf3d383fc1c60c798dc8e17ed9f4c67f843f0 --- /dev/null +++ b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/AbstractRefundService.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jeequan.jeepay.pay.channel; + + +import com.jeequan.jeepay.pay.util.ChannelCertConfigKitBean; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; + +/* +* 退款接口抽象类 +* +* @author terrfly +* @site https://www.jeepay.vip +* @date 2021/6/17 9:37 +*/ +public abstract class AbstractRefundService implements IRefundService{ + + @Autowired protected SysConfigService sysConfigService; + @Autowired protected ChannelCertConfigKitBean channelCertConfigKitBean; + + protected String getNotifyUrl(){ + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/refund/notify/" + getIfCode(); + } + + protected String getNotifyUrl(String payOrderId){ + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/refund/notify/" + getIfCode() + "/" + payOrderId; + } + +} diff --git a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/IRefundService.java b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/IRefundService.java new file mode 100644 index 0000000000000000000000000000000000000000..e8e77aea4960f06fedc2dab81ca08de2e81ec70d --- /dev/null +++ b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/IRefundService.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jeequan.jeepay.pay.channel; + +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.pay.model.MchAppConfigContext; +import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ; + +/* +* 调起上游渠道侧退款接口 +* +* @author terrfly +* @site https://www.jeepay.vip +* @date 2021/6/17 9:35 +*/ +public interface IRefundService { + + /* 获取到接口code **/ + String getIfCode(); + + /** 前置检查如参数等信息是否符合要求, 返回错误信息或直接抛出异常即可 */ + String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder); + + /** 调起退款接口,并响应数据; 内部处理普通商户和服务商模式 **/ + ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception; + +} diff --git a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayKit.java b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayKit.java index 235515d603f59b2299cd8cf9898e4bf07ec4f833..ad17ef08f0d7d47522d30035858df00097cf6507 100644 --- a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayKit.java +++ b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayKit.java @@ -55,7 +55,7 @@ public class AlipayKit { else if(req instanceof AlipayTradePrecreateRequest) ((AlipayTradePrecreateRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); else if(req instanceof AlipayTradeWapPayRequest) ((AlipayTradeWapPayRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); else if(req instanceof AlipayTradeQueryRequest) ((AlipayTradeQueryRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); - + else if(req instanceof AlipayTradeRefundRequest) ((AlipayTradeRefundRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); // 服务商信息 ExtendParams extendParams = new ExtendParams(); diff --git a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayRefundService.java b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayRefundService.java new file mode 100644 index 0000000000000000000000000000000000000000..15e989d89729c89f78a3c864dbe73a89867919b3 --- /dev/null +++ b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayRefundService.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jeequan.jeepay.pay.channel.alipay; + +import com.alipay.api.domain.AlipayTradeRefundModel; +import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.response.AlipayTradeRefundResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.pay.channel.AbstractRefundService; +import com.jeequan.jeepay.pay.model.MchAppConfigContext; +import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ; +import org.springframework.stereotype.Service; + +/* +* 退款接口: 支付宝官方 +* +* @author terrfly +* @site https://www.jeepay.vip +* @date 2021/6/17 9:38 +*/ +@Service +public class AlipayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); + model.setOutTradeNo(refundOrder.getPayOrderId()); + model.setTradeNo(refundOrder.getChannelPayOrderNo()); + model.setOutRequestNo(refundOrder.getRefundOrderId()); + model.setRefundAmount(AmountUtil.convertCent2Dollar(refundOrder.getRefundAmount().toString())); + model.setRefundReason(refundOrder.getRefundReason()); + request.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model); + + AlipayTradeRefundResponse response = mchAppConfigContext.getAlipayClientWrapper().execute(request); + + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelAttach(response.getBody()); + channelRetMsg.setChannelOrderId(response.getTradeNo()); + + // 调用成功 + if(response.isSuccess()){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getSubCode()); + channelRetMsg.setChannelErrMsg(response.getSubMsg()); + } + return channelRetMsg; + } + + +} diff --git a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/refund/RefundOrderController.java b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/refund/RefundOrderController.java index 0763f9d9f2a347ee06ca7f9f3eddf0b29eeb84f4..9091d6b4f4e9aacbef94b465d660a70094dc36ee 100644 --- a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/refund/RefundOrderController.java +++ b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/refund/RefundOrderController.java @@ -15,14 +15,18 @@ */ package com.jeequan.jeepay.pay.ctrl.refund; -import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.entity.MchApp; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; import com.jeequan.jeepay.core.exception.BizException; import com.jeequan.jeepay.core.model.ApiRes; import com.jeequan.jeepay.core.utils.SeqKit; import com.jeequan.jeepay.core.utils.SpringBeansUtil; import com.jeequan.jeepay.core.utils.StringKit; -import com.jeequan.jeepay.pay.channel.IPaymentService; +import com.jeequan.jeepay.pay.channel.IRefundService; import com.jeequan.jeepay.pay.ctrl.ApiController; +import com.jeequan.jeepay.pay.exception.ChannelException; import com.jeequan.jeepay.pay.model.MchAppConfigContext; import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg; import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ; @@ -57,10 +61,14 @@ public class RefundOrderController extends ApiController { @PostMapping("/api/refund/refundOrder") public ApiRes refundOrder(){ + + RefundOrder refundOrder = null; + + //获取参数 & 验签 + RefundOrderRQ rq = getRQByWithMchSign(RefundOrderRQ.class); + try { - //获取参数 & 验签 - RefundOrderRQ rq = getRQByWithMchSign(RefundOrderRQ.class); if(StringUtils.isAllEmpty(rq.getMchOrderNo(), rq.getPayOrderId())){ throw new BizException("mchOrderNo 和 payOrderId不能同时为空"); @@ -68,13 +76,39 @@ public class RefundOrderController extends ApiController { PayOrder payOrder = payOrderService.queryMchOrder(rq.getMchNo(), rq.getPayOrderId(), rq.getMchOrderNo()); if(payOrder == null){ - throw new BizException("订单不存在"); + throw new BizException("退款订单不存在"); + } + + if(payOrder.getState() != PayOrder.STATE_SUCCESS){ + throw new BizException("订单状态不正确, 无法完成退款"); + } + + if(payOrder.getRefundState() == PayOrder.REFUND_STATE_ALL || payOrder.getRefundAmount() >= payOrder.getAmount()){ + throw new BizException("订单已全额退款,本次申请失败"); + } + + if(payOrder.getRefundAmount() + rq.getRefundAmount() > payOrder.getAmount()){ + throw new BizException("申请金额超出订单可退款余额,请检查退款金额"); + } + + if(refundOrderService.count(RefundOrder.gw().eq(RefundOrder::getPayOrderId, payOrder.getPayOrderId()).eq(RefundOrder::getState, RefundOrder.STATE_ING)) > 0){ + throw new BizException("支付订单具有在途退款申请,请稍后再试"); + } + + //全部退款金额 (退款订单表) + Long sumSuccessRefundAmount = refundOrderService.getBaseMapper().sumSuccessRefundAmount(payOrder.getPayOrderId()); + if(sumSuccessRefundAmount >= payOrder.getAmount()){ + throw new BizException("退款单已完成全部订单退款,本次申请失败"); + } + + if(sumSuccessRefundAmount + rq.getRefundAmount() > payOrder.getAmount()){ + throw new BizException("申请金额超出订单可退款余额,请检查退款金额"); } String mchNo = rq.getMchNo(); String appId = rq.getAppId(); - // 只有新订单模式,进行校验 + // 校验退款单号是否重复 if(refundOrderService.count(RefundOrder.gw().eq(RefundOrder::getMchNo, mchNo).eq(RefundOrder::getMchRefundNo, rq.getMchRefundNo())) > 0){ throw new BizException("商户退款订单号["+rq.getMchRefundNo()+"]已存在"); } @@ -93,33 +127,44 @@ public class RefundOrderController extends ApiController { MchApp mchApp = mchAppConfigContext.getMchApp(); - //获取支付接口 - // 接口代码 TODO - IPaymentService paymentService = SpringBeansUtil.getBean(payOrder.getIfCode() + "PaymentService", IPaymentService.class); - if(paymentService == null){ + //获取退款接口 + IRefundService refundService = SpringBeansUtil.getBean(payOrder.getIfCode() + "RefundService", IRefundService.class); + if(refundService == null){ throw new BizException("当前通道不支持退款!"); } + refundOrder = genRefundOrder(rq, payOrder, mchInfo, mchApp); - RefundOrder refundOrder = genRefundOrder(rq, payOrder, mchInfo, mchApp); - - //订单入库 订单状态: 生成状态 此时没有和任何上游渠道产生交互。 + //退款单入库 退款单状态:生成状态 此时没有和任何上游渠道产生交互。 refundOrderService.save(refundOrder); - //调起上游支付接口 -// bizRS = (UnifiedOrderRS) paymentService.pay(bizRQ, payOrder, mchAppConfigContext); - // 调起退款接口 - ChannelRetMsg channelRetMsg = null; + ChannelRetMsg channelRetMsg = refundService.refund(rq, refundOrder, payOrder, mchAppConfigContext); + + + //处理退款单状态 + this.processChannelMsg(channelRetMsg, refundOrder); RefundOrderRS bizRes = RefundOrderRS.buildByRefundOrder(refundOrder); return ApiRes.okWithSign(bizRes, configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId()).getMchApp().getAppSecret()); - } catch (BizException e) { return ApiRes.customFail(e.getMessage()); + } catch (ChannelException e) { + + //处理上游返回数据 + this.processChannelMsg(e.getChannelRetMsg(), refundOrder); + + if(e.getChannelRetMsg().getChannelState() == ChannelRetMsg.ChannelState.SYS_ERROR ){ + return ApiRes.customFail(e.getMessage()); + } + + RefundOrderRS bizRes = RefundOrderRS.buildByRefundOrder(refundOrder); + return ApiRes.okWithSign(bizRes, configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId()).getMchApp().getAppSecret()); + + } catch (Exception e) { log.error("系统异常:{}", e); return ApiRes.customFail("系统异常"); @@ -160,38 +205,36 @@ public class RefundOrderController extends ApiController { } - /** 处理返回的渠道信息,并更新订单状态 + /** 处理返回的渠道信息,并更新退款单状态 * payOrder将对部分信息进行 赋值操作。 * **/ - private void processChannelMsg(ChannelRetMsg channelRetMsg, PayOrder payOrder){ + private void processChannelMsg(ChannelRetMsg channelRetMsg, RefundOrder refundOrder){ //对象为空 || 上游返回状态为空, 则无需操作 if(channelRetMsg == null || channelRetMsg.getChannelState() == null){ return ; } - String payOrderId = payOrder.getPayOrderId(); - //明确成功 if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) { - this.updateInitOrderStateThrowException(PayOrder.STATE_SUCCESS, payOrder, channelRetMsg); + this.updateInitOrderStateThrowException(RefundOrder.STATE_SUCCESS, refundOrder, channelRetMsg); // payMchNotifyService.payOrderNotify(payOrder); //明确失败 }else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) { - this.updateInitOrderStateThrowException(PayOrder.STATE_FAIL, payOrder, channelRetMsg); + this.updateInitOrderStateThrowException(RefundOrder.STATE_FAIL, refundOrder, channelRetMsg); - // 上游处理中 || 未知 || 上游接口返回异常 订单为支付中状态 + // 上游处理中 || 未知 || 上游接口返回异常 退款单为退款中状态 }else if( ChannelRetMsg.ChannelState.WAITING == channelRetMsg.getChannelState() || ChannelRetMsg.ChannelState.UNKNOWN == channelRetMsg.getChannelState() || ChannelRetMsg.ChannelState.API_RET_ERROR == channelRetMsg.getChannelState() ){ - this.updateInitOrderStateThrowException(PayOrder.STATE_ING, payOrder, channelRetMsg); + this.updateInitOrderStateThrowException(RefundOrder.STATE_ING, refundOrder, channelRetMsg); - // 系统异常: 订单不再处理。 为: 生成状态 + // 系统异常: 退款单不再处理。 为: 生成状态 }else if( ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState()){ }else{ @@ -199,34 +242,28 @@ public class RefundOrderController extends ApiController { throw new BizException("ChannelState 返回异常!"); } - //判断是否需要轮询查单 - if(channelRetMsg.isNeedQuery()){ -// mqChannelOrderQueryQueue.send(MqQueue4ChannelOrderQuery.buildMsg(payOrderId, 1), 5 * 1000); - } - } - /** 更新订单状态 --》 订单生成--》 其他状态 (向外抛出异常) **/ - private void updateInitOrderStateThrowException(byte orderState, PayOrder payOrder, ChannelRetMsg channelRetMsg){ + /** 更新退款单状态 --》 退款单生成--》 其他状态 (向外抛出异常) **/ + private void updateInitOrderStateThrowException(byte orderState, RefundOrder refundOrder, ChannelRetMsg channelRetMsg){ - payOrder.setState(orderState); - payOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId()); - payOrder.setErrCode(channelRetMsg.getChannelErrCode()); - payOrder.setErrMsg(channelRetMsg.getChannelErrMsg()); + refundOrder.setState(orderState); + refundOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId()); + refundOrder.setChannelErrCode(channelRetMsg.getChannelErrCode()); + refundOrder.setChannelErrMsg(channelRetMsg.getChannelErrMsg()); - boolean isSuccess = payOrderService.updateInit2Ing(payOrder.getPayOrderId(), payOrder.getIfCode(), payOrder.getWayCode()); + boolean isSuccess = refundOrderService.updateInit2Ing(refundOrder.getRefundOrderId()); if(!isSuccess){ - throw new BizException("更新订单异常!"); + throw new BizException("更新退款单异常!"); } - isSuccess = payOrderService.updateIng2SuccessOrFail(payOrder.getPayOrderId(), payOrder.getState(), + isSuccess = refundOrderService.updateIng2SuccessOrFail(refundOrder.getRefundOrderId(), refundOrder.getState(), channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg()); if(!isSuccess){ - throw new BizException("更新订单异常!"); + throw new BizException("更新退款单异常!"); } } - } diff --git a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/exception/ChannelException.java b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/exception/ChannelException.java index 26f9f6ff5b9255c2c55b91a566a7f87e4f75e717..3506984cc22d909c2204d02b4a3dbfc9639acdc2 100644 --- a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/exception/ChannelException.java +++ b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/exception/ChannelException.java @@ -41,7 +41,7 @@ public class ChannelException extends RuntimeException{ /** 未知状态 **/ public static ChannelException unknown(String channelErrMsg){ - return new ChannelException(ChannelRetMsg.sysError(channelErrMsg)); + return new ChannelException(ChannelRetMsg.unknown(channelErrMsg)); } /** 系统内异常 **/ diff --git a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/msg/ChannelRetMsg.java b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/msg/ChannelRetMsg.java index ecef4e92ca67245893696a2e26801d93000218ee..1f6e11630509b23719246f1a60451b7caf6fc214 100644 --- a/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/msg/ChannelRetMsg.java +++ b/jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/msg/ChannelRetMsg.java @@ -113,6 +113,11 @@ public class ChannelRetMsg implements Serializable { return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, null); } + /** 状态未知的情况 **/ + public static ChannelRetMsg unknown(String channelErrMsg){ + return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, channelErrMsg); + } + } diff --git a/jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/RefundOrderService.java b/jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/RefundOrderService.java index 97c3efee8f6aa858878afb42f026d1f920995fd2..c261e2218ae2f06e46f74ff610dce32959fd32a6 100644 --- a/jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/RefundOrderService.java +++ b/jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/RefundOrderService.java @@ -15,10 +15,17 @@ */ package com.jeequan.jeepay.service.impl; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.service.mapper.PayOrderMapper; import com.jeequan.jeepay.service.mapper.RefundOrderMapper; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; /** *

@@ -31,4 +38,74 @@ import org.springframework.stereotype.Service; @Service public class RefundOrderService extends ServiceImpl { + @Autowired private PayOrderMapper payOrderMapper; + + + /** 更新退款单状态 【退款单生成】 --》 【退款中】 **/ + public boolean updateInit2Ing(String refundOrderId){ + + RefundOrder updateRecord = new RefundOrder(); + updateRecord.setState(RefundOrder.STATE_ING); + + return update(updateRecord, new LambdaUpdateWrapper() + .eq(RefundOrder::getRefundOrderId, refundOrderId).eq(RefundOrder::getState, RefundOrder.STATE_INIT)); + } + + /** 更新退款单状态 【退款中】 --》 【退款成功】 **/ + @Transactional + public boolean updateIng2Success(String refundOrderId, String channelOrderNo){ + + RefundOrder updateRecord = new RefundOrder(); + updateRecord.setState(RefundOrder.STATE_SUCCESS); + updateRecord.setChannelOrderNo(channelOrderNo); + updateRecord.setSuccessTime(new Date()); + + //1. 更新退款订单表数据 + if(! update(updateRecord, new LambdaUpdateWrapper() + .eq(RefundOrder::getRefundOrderId, refundOrderId).eq(RefundOrder::getState, RefundOrder.STATE_ING)) + ){ + return false; + } + + //2. 更新订单表数据 + RefundOrder refundOrder = getOne(RefundOrder.gw().select(RefundOrder::getPayOrderId, RefundOrder::getRefundAmount).eq(RefundOrder::getRefundOrderId, refundOrderId)); + int updateCount = payOrderMapper.updateRefundAmountAndCount(refundOrder.getPayOrderId(), refundOrder.getRefundAmount()); + if(updateCount <= 0){ + throw new BizException("更新订单数据异常"); + } + + return true; + } + + + /** 更新退款单状态 【退款中】 --》 【退款失败】 **/ + @Transactional + public boolean updateIng2Fail(String refundOrderId, String channelOrderNo, String channelErrCode, String channelErrMsg){ + + RefundOrder updateRecord = new RefundOrder(); + updateRecord.setState(RefundOrder.STATE_FAIL); + updateRecord.setChannelErrCode(channelErrCode); + updateRecord.setChannelErrMsg(channelErrMsg); + updateRecord.setChannelOrderNo(channelOrderNo); + + return update(updateRecord, new LambdaUpdateWrapper() + .eq(RefundOrder::getRefundOrderId, refundOrderId).eq(RefundOrder::getState, RefundOrder.STATE_ING)); + } + + + /** 更新退款单状态 【退款中】 --》 【退款成功/退款失败】 **/ + @Transactional + public boolean updateIng2SuccessOrFail(String refundOrderId, Byte updateState, String channelOrderNo, String channelErrCode, String channelErrMsg){ + + if(updateState == RefundOrder.STATE_ING){ + return true; + }else if(updateState == RefundOrder.STATE_SUCCESS){ + return updateIng2Success(refundOrderId, channelOrderNo); + }else if(updateState == RefundOrder.STATE_FAIL){ + return updateIng2Fail(refundOrderId, channelOrderNo, channelErrCode, channelErrMsg); + } + return false; + } + + } diff --git a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.java b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.java index dc188bfaa530eceefdd86e2e5469ce7b2580bd68..60a13b1bdc43dcecab3e393cd07560adaa52124c 100644 --- a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.java +++ b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.java @@ -17,6 +17,7 @@ package com.jeequan.jeepay.service.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.jeequan.jeepay.core.entity.PayOrder; +import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; @@ -38,4 +39,7 @@ public interface PayOrderMapper extends BaseMapper { Map selectTotalCount(Map param); List selectOrderCount(Map param); + + /** 更新订单退款金额和次数 **/ + int updateRefundAmountAndCount(@Param("payOrderId") String payOrderId, @Param("currentRefundAmount") Long currentRefundAmount); } diff --git a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.xml b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.xml index 25595d55714f5ffef4390ab1672fe83343ebd131..72b7d6a0d0284072c8d70e272bdd90b458e7bdcb 100644 --- a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.xml +++ b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/PayOrderMapper.xml @@ -23,6 +23,7 @@ + @@ -86,4 +87,19 @@ GROUP BY groupDate ORDER BY groupDate desc + + + + + update t_pay_order + set refund_times = refund_times + 1, + refund_state = CASE WHEN refund_amount + #{currentRefundAmount} >= amount THEN 2 ELSE 1 END, + refund_amount = refund_amount + #{currentRefundAmount} + where + pay_order_id = #{payOrderId} and `state` = 2 + and refund_amount + #{currentRefundAmount} <= amount + and refund_state in (0, 1) + + + diff --git a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.java b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.java index 6d7fe8e69c0c385422502c7a41ffb108d60a243d..2123c64503f0cf14306bd580de7367a69ed6139f 100644 --- a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.java +++ b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.java @@ -28,4 +28,7 @@ import com.jeequan.jeepay.core.entity.RefundOrder; */ public interface RefundOrderMapper extends BaseMapper { + /** 查询全部退成功金额 **/ + Long sumSuccessRefundAmount(String payOrderId); + } diff --git a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.xml b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.xml index ce528873a537e90983ff559218055266f1102846..921672c2bb4e3a446b56d44cf8f8cf9dcaa406fd 100644 --- a/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.xml +++ b/jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/RefundOrderMapper.xml @@ -32,4 +32,9 @@ + +