提交 7e119aa2 编写于 作者: terrfly's avatar terrfly

完善退款申请api;

上级 36f9aa52
...@@ -282,6 +282,7 @@ CREATE TABLE `t_pay_order` ( ...@@ -282,6 +282,7 @@ CREATE TABLE `t_pay_order` (
`channel_extra` VARCHAR(512) DEFAULT NULL COMMENT '特定渠道发起额外参数', `channel_extra` VARCHAR(512) DEFAULT NULL COMMENT '特定渠道发起额外参数',
`channel_user` VARCHAR(64) DEFAULT NULL COMMENT '渠道用户标识,如微信openId,支付宝账号', `channel_user` VARCHAR(64) DEFAULT NULL COMMENT '渠道用户标识,如微信openId,支付宝账号',
`channel_order_no` VARCHAR(64) DEFAULT NULL COMMENT '渠道订单号', `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_times` INT NOT NULL DEFAULT 0 COMMENT '退款次数',
`refund_amount` BIGINT(20) NOT NULL DEFAULT 0 COMMENT '退款总金额,单位分', `refund_amount` BIGINT(20) NOT NULL DEFAULT 0 COMMENT '退款总金额,单位分',
`division_flag` TINYINT(6) DEFAULT 0 COMMENT '订单分账标志:0-否 1-是', `division_flag` TINYINT(6) DEFAULT 0 COMMENT '订单分账标志:0-否 1-是',
......
...@@ -55,6 +55,9 @@ public class PayOrder extends BaseModel implements Serializable { ...@@ -55,6 +55,9 @@ public class PayOrder extends BaseModel implements Serializable {
public static final byte STATE_REFUND = 5; //已退款 public static final byte STATE_REFUND = 5; //已退款
public static final byte STATE_CLOSED = 6; //订单关闭 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 { ...@@ -152,6 +155,11 @@ public class PayOrder extends BaseModel implements Serializable {
*/ */
private String channelOrderNo; private String channelOrderNo;
/**
* 退款状态: 0-未发生实际退款, 1-部分退款, 2-全额退款
*/
private Byte refundState;
/** /**
* 退款次数 * 退款次数
*/ */
......
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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;
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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;
}
...@@ -55,7 +55,7 @@ public class AlipayKit { ...@@ -55,7 +55,7 @@ public class AlipayKit {
else if(req instanceof AlipayTradePrecreateRequest) ((AlipayTradePrecreateRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); 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 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 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(); ExtendParams extendParams = new ExtendParams();
......
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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;
}
}
...@@ -15,14 +15,18 @@ ...@@ -15,14 +15,18 @@
*/ */
package com.jeequan.jeepay.pay.ctrl.refund; 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.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes; import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.SeqKit; import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil; import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.core.utils.StringKit; 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.ctrl.ApiController;
import com.jeequan.jeepay.pay.exception.ChannelException;
import com.jeequan.jeepay.pay.model.MchAppConfigContext; import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg; import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ; import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ;
...@@ -57,10 +61,14 @@ public class RefundOrderController extends ApiController { ...@@ -57,10 +61,14 @@ public class RefundOrderController extends ApiController {
@PostMapping("/api/refund/refundOrder") @PostMapping("/api/refund/refundOrder")
public ApiRes refundOrder(){ public ApiRes refundOrder(){
RefundOrder refundOrder = null;
//获取参数 & 验签
RefundOrderRQ rq = getRQByWithMchSign(RefundOrderRQ.class);
try { try {
//获取参数 & 验签
RefundOrderRQ rq = getRQByWithMchSign(RefundOrderRQ.class);
if(StringUtils.isAllEmpty(rq.getMchOrderNo(), rq.getPayOrderId())){ if(StringUtils.isAllEmpty(rq.getMchOrderNo(), rq.getPayOrderId())){
throw new BizException("mchOrderNo 和 payOrderId不能同时为空"); throw new BizException("mchOrderNo 和 payOrderId不能同时为空");
...@@ -68,13 +76,39 @@ public class RefundOrderController extends ApiController { ...@@ -68,13 +76,39 @@ public class RefundOrderController extends ApiController {
PayOrder payOrder = payOrderService.queryMchOrder(rq.getMchNo(), rq.getPayOrderId(), rq.getMchOrderNo()); PayOrder payOrder = payOrderService.queryMchOrder(rq.getMchNo(), rq.getPayOrderId(), rq.getMchOrderNo());
if(payOrder == null){ 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 mchNo = rq.getMchNo();
String appId = rq.getAppId(); String appId = rq.getAppId();
// 只有新订单模式,进行校验 // 校验退款单号是否重复
if(refundOrderService.count(RefundOrder.gw().eq(RefundOrder::getMchNo, mchNo).eq(RefundOrder::getMchRefundNo, rq.getMchRefundNo())) > 0){ if(refundOrderService.count(RefundOrder.gw().eq(RefundOrder::getMchNo, mchNo).eq(RefundOrder::getMchRefundNo, rq.getMchRefundNo())) > 0){
throw new BizException("商户退款订单号["+rq.getMchRefundNo()+"]已存在"); throw new BizException("商户退款订单号["+rq.getMchRefundNo()+"]已存在");
} }
...@@ -93,33 +127,44 @@ public class RefundOrderController extends ApiController { ...@@ -93,33 +127,44 @@ public class RefundOrderController extends ApiController {
MchApp mchApp = mchAppConfigContext.getMchApp(); MchApp mchApp = mchAppConfigContext.getMchApp();
//获取支付接口 //获取退款接口
// 接口代码 TODO IRefundService refundService = SpringBeansUtil.getBean(payOrder.getIfCode() + "RefundService", IRefundService.class);
IPaymentService paymentService = SpringBeansUtil.getBean(payOrder.getIfCode() + "PaymentService", IPaymentService.class); if(refundService == null){
if(paymentService == null){
throw new BizException("当前通道不支持退款!"); throw new BizException("当前通道不支持退款!");
} }
refundOrder = genRefundOrder(rq, payOrder, mchInfo, mchApp);
RefundOrder refundOrder = genRefundOrder(rq, payOrder, mchInfo, mchApp); //退款单入库 退款单状态:生成状态 此时没有和任何上游渠道产生交互。
//订单入库 订单状态: 生成状态 此时没有和任何上游渠道产生交互。
refundOrderService.save(refundOrder); 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); RefundOrderRS bizRes = RefundOrderRS.buildByRefundOrder(refundOrder);
return ApiRes.okWithSign(bizRes, configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId()).getMchApp().getAppSecret()); return ApiRes.okWithSign(bizRes, configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId()).getMchApp().getAppSecret());
} catch (BizException e) { } catch (BizException e) {
return ApiRes.customFail(e.getMessage()); 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) { } catch (Exception e) {
log.error("系统异常:{}", e); log.error("系统异常:{}", e);
return ApiRes.customFail("系统异常"); return ApiRes.customFail("系统异常");
...@@ -160,38 +205,36 @@ public class RefundOrderController extends ApiController { ...@@ -160,38 +205,36 @@ public class RefundOrderController extends ApiController {
} }
/** 处理返回的渠道信息,并更新单状态 /** 处理返回的渠道信息,并更新退款单状态
* payOrder将对部分信息进行 赋值操作。 * payOrder将对部分信息进行 赋值操作。
* **/ * **/
private void processChannelMsg(ChannelRetMsg channelRetMsg, PayOrder payOrder){ private void processChannelMsg(ChannelRetMsg channelRetMsg, RefundOrder refundOrder){
//对象为空 || 上游返回状态为空, 则无需操作 //对象为空 || 上游返回状态为空, 则无需操作
if(channelRetMsg == null || channelRetMsg.getChannelState() == null){ if(channelRetMsg == null || channelRetMsg.getChannelState() == null){
return ; return ;
} }
String payOrderId = payOrder.getPayOrderId();
//明确成功 //明确成功
if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) { if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) {
this.updateInitOrderStateThrowException(PayOrder.STATE_SUCCESS, payOrder, channelRetMsg); this.updateInitOrderStateThrowException(RefundOrder.STATE_SUCCESS, refundOrder, channelRetMsg);
// payMchNotifyService.payOrderNotify(payOrder); // payMchNotifyService.payOrderNotify(payOrder);
//明确失败 //明确失败
}else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) { }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() || }else if( ChannelRetMsg.ChannelState.WAITING == channelRetMsg.getChannelState() ||
ChannelRetMsg.ChannelState.UNKNOWN == channelRetMsg.getChannelState() || ChannelRetMsg.ChannelState.UNKNOWN == channelRetMsg.getChannelState() ||
ChannelRetMsg.ChannelState.API_RET_ERROR == 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 if( ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState()){
}else{ }else{
...@@ -199,34 +242,28 @@ public class RefundOrderController extends ApiController { ...@@ -199,34 +242,28 @@ public class RefundOrderController extends ApiController {
throw new BizException("ChannelState 返回异常!"); 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); refundOrder.setState(orderState);
payOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId()); refundOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId());
payOrder.setErrCode(channelRetMsg.getChannelErrCode()); refundOrder.setChannelErrCode(channelRetMsg.getChannelErrCode());
payOrder.setErrMsg(channelRetMsg.getChannelErrMsg()); refundOrder.setChannelErrMsg(channelRetMsg.getChannelErrMsg());
boolean isSuccess = payOrderService.updateInit2Ing(payOrder.getPayOrderId(), payOrder.getIfCode(), payOrder.getWayCode()); boolean isSuccess = refundOrderService.updateInit2Ing(refundOrder.getRefundOrderId());
if(!isSuccess){ 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()); channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
if(!isSuccess){ if(!isSuccess){
throw new BizException("更新单异常!"); throw new BizException("更新退款单异常!");
} }
} }
} }
...@@ -41,7 +41,7 @@ public class ChannelException extends RuntimeException{ ...@@ -41,7 +41,7 @@ public class ChannelException extends RuntimeException{
/** 未知状态 **/ /** 未知状态 **/
public static ChannelException unknown(String channelErrMsg){ public static ChannelException unknown(String channelErrMsg){
return new ChannelException(ChannelRetMsg.sysError(channelErrMsg)); return new ChannelException(ChannelRetMsg.unknown(channelErrMsg));
} }
/** 系统内异常 **/ /** 系统内异常 **/
......
...@@ -113,6 +113,11 @@ public class ChannelRetMsg implements Serializable { ...@@ -113,6 +113,11 @@ public class ChannelRetMsg implements Serializable {
return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, null); return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, null);
} }
/** 状态未知的情况 **/
public static ChannelRetMsg unknown(String channelErrMsg){
return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, channelErrMsg);
}
} }
......
...@@ -15,10 +15,17 @@ ...@@ -15,10 +15,17 @@
*/ */
package com.jeequan.jeepay.service.impl; package com.jeequan.jeepay.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.entity.RefundOrder; 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 com.jeequan.jeepay.service.mapper.RefundOrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/** /**
* <p> * <p>
...@@ -31,4 +38,74 @@ import org.springframework.stereotype.Service; ...@@ -31,4 +38,74 @@ import org.springframework.stereotype.Service;
@Service @Service
public class RefundOrderService extends ServiceImpl<RefundOrderMapper, RefundOrder> { public class RefundOrderService extends ServiceImpl<RefundOrderMapper, RefundOrder> {
@Autowired private PayOrderMapper payOrderMapper;
/** 更新退款单状态 【退款单生成】 --》 【退款中】 **/
public boolean updateInit2Ing(String refundOrderId){
RefundOrder updateRecord = new RefundOrder();
updateRecord.setState(RefundOrder.STATE_ING);
return update(updateRecord, new LambdaUpdateWrapper<RefundOrder>()
.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<RefundOrder>()
.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<RefundOrder>()
.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;
}
} }
...@@ -17,6 +17,7 @@ package com.jeequan.jeepay.service.mapper; ...@@ -17,6 +17,7 @@ package com.jeequan.jeepay.service.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jeequan.jeepay.core.entity.PayOrder; import com.jeequan.jeepay.core.entity.PayOrder;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -38,4 +39,7 @@ public interface PayOrderMapper extends BaseMapper<PayOrder> { ...@@ -38,4 +39,7 @@ public interface PayOrderMapper extends BaseMapper<PayOrder> {
Map selectTotalCount(Map param); Map selectTotalCount(Map param);
List<Map> selectOrderCount(Map param); List<Map> selectOrderCount(Map param);
/** 更新订单退款金额和次数 **/
int updateRefundAmountAndCount(@Param("payOrderId") String payOrderId, @Param("currentRefundAmount") Long currentRefundAmount);
} }
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
<result column="channel_extra" property="channelExtra" /> <result column="channel_extra" property="channelExtra" />
<result column="channel_user" property="channelUser" /> <result column="channel_user" property="channelUser" />
<result column="channel_order_no" property="channelOrderNo" /> <result column="channel_order_no" property="channelOrderNo" />
<result column="refund_state" property="refundState" />
<result column="refund_times" property="refundTimes" /> <result column="refund_times" property="refundTimes" />
<result column="refund_amount" property="refundAmount" /> <result column="refund_amount" property="refundAmount" />
<result column="division_flag" property="divisionFlag" /> <result column="division_flag" property="divisionFlag" />
...@@ -86,4 +87,19 @@ ...@@ -86,4 +87,19 @@
GROUP BY groupDate GROUP BY groupDate
ORDER BY groupDate desc ORDER BY groupDate desc
</select> </select>
<!-- 更新订单退款金额和次数 -->
<update id="updateRefundAmountAndCount">
update t_pay_order
set refund_times = refund_times + 1, <!-- 退款次数 +1 -->
refund_state = CASE WHEN refund_amount + #{currentRefundAmount} >= amount THEN 2 ELSE 1 END, <!-- 更新是否已全额退款。 此更新需在refund_amount更新之前,否则需要去掉累加逻辑 -->
refund_amount = refund_amount + #{currentRefundAmount} <!-- 退款金额累加 -->
where
pay_order_id = #{payOrderId} and `state` = 2 <!-- 订单号 & 成功状态的可退款 -->
and refund_amount + #{currentRefundAmount} &lt;= amount <!-- 已退款金额 + 本次退款金额 小于等于订单金额 -->
and refund_state in (0, 1) <!-- 只有未发生退款和部分退款可退 -->
</update>
</mapper> </mapper>
...@@ -28,4 +28,7 @@ import com.jeequan.jeepay.core.entity.RefundOrder; ...@@ -28,4 +28,7 @@ import com.jeequan.jeepay.core.entity.RefundOrder;
*/ */
public interface RefundOrderMapper extends BaseMapper<RefundOrder> { public interface RefundOrderMapper extends BaseMapper<RefundOrder> {
/** 查询全部退成功金额 **/
Long sumSuccessRefundAmount(String payOrderId);
} }
...@@ -32,4 +32,9 @@ ...@@ -32,4 +32,9 @@
<result column="updated_at" property="updatedAt" /> <result column="updated_at" property="updatedAt" />
</resultMap> </resultMap>
<select id="sumSuccessRefundAmount" resultType="Long">
select ifnull(sum(refund_amount), 0) from t_refund_order
where pay_order_id = #{payOrderId} and state = 2
</select>
</mapper> </mapper>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册