完善退款申请api;
This commit is contained in:
parent
36f9aa5251
commit
7e119aa212
|
|
@ -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-是',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 退款次数
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 {
|
|||
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();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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 @@
|
|||
*/
|
||||
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("更新退款单异常!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
/** 系统内异常 **/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -31,4 +38,74 @@ import org.springframework.stereotype.Service;
|
|||
@Service
|
||||
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;
|
|||
|
||||
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<PayOrder> {
|
|||
Map selectTotalCount(Map param);
|
||||
|
||||
List<Map> selectOrderCount(Map param);
|
||||
|
||||
/** 更新订单退款金额和次数 **/
|
||||
int updateRefundAmountAndCount(@Param("payOrderId") String payOrderId, @Param("currentRefundAmount") Long currentRefundAmount);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
<result column="channel_extra" property="channelExtra" />
|
||||
<result column="channel_user" property="channelUser" />
|
||||
<result column="channel_order_no" property="channelOrderNo" />
|
||||
<result column="refund_state" property="refundState" />
|
||||
<result column="refund_times" property="refundTimes" />
|
||||
<result column="refund_amount" property="refundAmount" />
|
||||
<result column="division_flag" property="divisionFlag" />
|
||||
|
|
@ -86,4 +87,19 @@
|
|||
GROUP BY groupDate
|
||||
ORDER BY groupDate desc
|
||||
</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} <= amount <!-- 已退款金额 + 本次退款金额 小于等于订单金额 -->
|
||||
and refund_state in (0, 1) <!-- 只有未发生退款和部分退款可退 -->
|
||||
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -28,4 +28,7 @@ import com.jeequan.jeepay.core.entity.RefundOrder;
|
|||
*/
|
||||
public interface RefundOrderMapper extends BaseMapper<RefundOrder> {
|
||||
|
||||
/** 查询全部退成功金额 **/
|
||||
Long sumSuccessRefundAmount(String payOrderId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,4 +32,9 @@
|
|||
<result column="updated_at" property="updatedAt" />
|
||||
</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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue