mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-07-25 00:15:06 +08:00
mall + pay:
1. 优化 PayClient 支付逻辑,返回业务失败 errorCode + errorMsg 错误码
This commit is contained in:
@ -22,12 +22,12 @@ public class PayRefundApiImpl implements PayRefundApi {
|
||||
private PayRefundService payRefundService;
|
||||
|
||||
@Override
|
||||
public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
|
||||
public Long createRefund(PayRefundCreateReqDTO reqDTO) {
|
||||
return payRefundService.createPayRefund(reqDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayRefundRespDTO getPayRefund(Long id) {
|
||||
public PayRefundRespDTO getRefund(Long id) {
|
||||
return PayRefundConvert.INSTANCE.convert02(payRefundService.getRefund(id));
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.pay.convert.order;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
|
||||
@ -93,7 +92,8 @@ public interface PayOrderConvert {
|
||||
|
||||
PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO, String userIp);
|
||||
|
||||
PayOrderSubmitRespVO convert(PayOrderDO order, PayOrderUnifiedRespDTO unifiedRespDTO);
|
||||
@Mapping(source = "order.status", target = "status")
|
||||
PayOrderSubmitRespVO convert(PayOrderDO order, cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO respDTO);
|
||||
|
||||
AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean);
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.pay.dal.dataobject.order;
|
||||
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@ -65,7 +66,6 @@ public class PayOrderExtensionDO extends BaseDO {
|
||||
* 支付状态
|
||||
*
|
||||
* 枚举 {@link PayOrderStatusEnum}
|
||||
* 注意,只包含上述枚举的 WAITING 和 SUCCESS
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
@ -75,10 +75,20 @@ public class PayOrderExtensionDO extends BaseDO {
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, String> channelExtras;
|
||||
|
||||
/**
|
||||
* 支付渠道异步通知的内容
|
||||
* 调用渠道的错误码
|
||||
*/
|
||||
private String channelErrorCode;
|
||||
/**
|
||||
* 调用渠道报错时,错误信息
|
||||
*/
|
||||
private String channelErrorMsg;
|
||||
|
||||
/**
|
||||
* 支付渠道的同步/异步通知的内容
|
||||
*
|
||||
* 在支持成功后,会记录回调的数据
|
||||
* 对应 {@link PayOrderRespDTO#getRawData()}
|
||||
*/
|
||||
private String channelNotifyData;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.pay.dal.dataobject.refund;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||
@ -151,9 +152,9 @@ public class PayRefundDO extends BaseDO {
|
||||
private String channelErrorMsg;
|
||||
|
||||
/**
|
||||
* 支付渠道异步通知的内容
|
||||
* 支付渠道的同步/异步通知的内容
|
||||
*
|
||||
* 在退款成功后,会记录回调的数据
|
||||
* 对应 {@link PayRefundRespDTO#getRawData()}
|
||||
*/
|
||||
private String channelNotifyData;
|
||||
|
||||
|
@ -189,7 +189,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
||||
// 这里我们是个简单的 demo,所以没有售后维权表,直接使用订单 id + "-refund" 来演示
|
||||
String refundId = order.getId() + "-refund";
|
||||
// 2.2 创建退款单
|
||||
Long payRefundId = payRefundApi.createPayRefund(new PayRefundCreateReqDTO()
|
||||
Long payRefundId = payRefundApi.createRefund(new PayRefundCreateReqDTO()
|
||||
.setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用
|
||||
.setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
|
||||
.setMerchantRefundId(refundId)
|
||||
@ -239,7 +239,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
||||
}
|
||||
|
||||
// 2.1 校验退款订单
|
||||
PayRefundRespDTO payRefund = payRefundApi.getPayRefund(payRefundId);
|
||||
PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
|
||||
if (payRefund == null) {
|
||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
||||
@ -11,7 +12,6 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||
@ -134,8 +134,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override // 注意,这里不能添加事务注解,避免调用支付渠道失败时,将 PayOrderExtensionDO 回滚了
|
||||
public PayOrderSubmitRespVO submitOrder(PayOrderSubmitReqVO reqVO, String userIp) {
|
||||
// 1. 获得 PayOrderDO ,并校验其是否存在
|
||||
PayOrderDO order = validateOrderCanSubmit(reqVO.getId());
|
||||
@ -159,17 +158,20 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
.setReturnUrl(reqVO.getReturnUrl())
|
||||
// 订单相关字段
|
||||
.setPrice(order.getPrice()).setExpireTime(order.getExpireTime());
|
||||
PayOrderUnifiedRespDTO unifiedOrderRespDTO = client.unifiedOrder(unifiedOrderReqDTO);
|
||||
PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO);
|
||||
|
||||
// 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
|
||||
if (unifiedOrderRespDTO.getOrder() != null) {
|
||||
notifyPayOrder(channel, unifiedOrderRespDTO.getOrder());
|
||||
if (unifiedOrderResp != null) {
|
||||
notifyPayOrder(channel, unifiedOrderResp);
|
||||
// 如有渠道错误码,则抛出业务异常,提示用户
|
||||
if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
|
||||
throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
|
||||
unifiedOrderResp.getChannelErrorMsg());
|
||||
}
|
||||
// 此处需要读取最新的状态
|
||||
order = orderMapper.selectById(order.getId());
|
||||
}
|
||||
|
||||
// 返回成功
|
||||
return PayOrderConvert.INSTANCE.convert(order, unifiedOrderRespDTO);
|
||||
return PayOrderConvert.INSTANCE.convert(order, unifiedOrderResp);
|
||||
}
|
||||
|
||||
private PayOrderDO validateOrderCanSubmit(Long id) {
|
||||
@ -269,8 +271,10 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
notifyOrderSuccess(channel, notify);
|
||||
return;
|
||||
}
|
||||
// 情况二:非支付成功的回调,进行忽略
|
||||
log.info("[notifyPayOrder][非支付成功的回调({}),直接忽略]", toJsonString(notify));
|
||||
// 情况二:支付失败的回调
|
||||
if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) {
|
||||
notifyOrderClosed(channel, notify);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
|
||||
@ -300,7 +304,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
||||
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新为已支付]", orderExtension.getId());
|
||||
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId());
|
||||
return orderExtension;
|
||||
}
|
||||
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
||||
@ -327,7 +331,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
* value:PayOrderDO 对象
|
||||
*/
|
||||
private Pair<Boolean, PayOrderDO> updateOrderExtensionSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
|
||||
PayOrderRespDTO notify) {
|
||||
PayOrderRespDTO notify) {
|
||||
// 1. 判断 PayOrderDO 是否处于待支付
|
||||
PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
|
||||
if (order == null) {
|
||||
@ -335,7 +339,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
}
|
||||
if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
|
||||
&& Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) {
|
||||
log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新为已支付]", order.getId());
|
||||
log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新]", order.getId());
|
||||
return Pair.of(true, order);
|
||||
}
|
||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
||||
@ -356,4 +360,37 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
return Pair.of(false, order);
|
||||
}
|
||||
|
||||
private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) {
|
||||
updateOrderExtensionClosed(channel, notify);
|
||||
}
|
||||
|
||||
private void updateOrderExtensionClosed(PayChannelDO channel, PayOrderRespDTO notify) {
|
||||
// 1. 查询 PayOrderExtensionDO
|
||||
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
||||
if (orderExtension == null) {
|
||||
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
|
||||
log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId());
|
||||
return;
|
||||
}
|
||||
// 一般出现先是支付成功,然后支付关闭,都是全部退款导致关闭的场景。这个情况,我们不更新支付拓展单,只通过退款流程,更新支付单
|
||||
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) {
|
||||
log.info("[updateOrderExtensionClosed][支付拓展单({}) 是已支付,无需更新为支付关闭]", orderExtension.getId());
|
||||
return;
|
||||
}
|
||||
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
|
||||
// 2. 更新 PayOrderExtensionDO
|
||||
int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
|
||||
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
|
||||
.channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
|
||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user