mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-01 02:38:43 +08:00 
			
		
		
		
	增加微信公众号的支付回调接口
This commit is contained in:
		| @@ -120,6 +120,10 @@ public class PayOrderDO extends BaseDO { | ||||
|      * 订单支付成功时间 | ||||
|      */ | ||||
|     private Date successTime; | ||||
|     /** | ||||
|      * 订单支付通知时间,即支付渠道的通知时间 | ||||
|      */ | ||||
|     private Date notifyTime; | ||||
|     /** | ||||
|      * 支付成功的订单拓展单编号 | ||||
|      * | ||||
|   | ||||
| @@ -77,6 +77,6 @@ public class PayOrderExtensionDO extends BaseDO { | ||||
|      * | ||||
|      * 在支持成功后,会记录回调的数据 | ||||
|      */ | ||||
|     private String channelCallbackData; | ||||
|     private String channelNotifyData; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order; | ||||
|  | ||||
| import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; | ||||
| import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
| @@ -13,4 +14,9 @@ public interface PayOrderCoreMapper extends BaseMapperX<PayOrderDO> { | ||||
|                 .eq("merchant_order_id", merchantOrderId)); | ||||
|     } | ||||
|  | ||||
|     default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) { | ||||
|         return update(update, new QueryWrapper<PayOrderDO>() | ||||
|                 .eq("id", id).eq("status", status)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order; | ||||
|  | ||||
| import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; | ||||
| import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||
| @@ -9,4 +8,13 @@ import org.apache.ibatis.annotations.Mapper; | ||||
| @Mapper | ||||
| public interface PayOrderExtensionCoreMapper extends BaseMapperX<PayOrderExtensionDO> { | ||||
|  | ||||
|     default PayOrderExtensionDO selectByOrderExtensionNo(String orderExtensionNo) { | ||||
|         return selectOne("order_extension_no", orderExtensionNo); | ||||
|     } | ||||
|  | ||||
|     default int updateByIdAndStatus(Long id, Integer status, PayOrderExtensionDO update) { | ||||
|         return update(update, new QueryWrapper<PayOrderExtensionDO>() | ||||
|                 .eq("id", id).eq("status", status)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -19,13 +19,13 @@ public interface PayErrorCodeCoreConstants { | ||||
|     ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在"); | ||||
|  | ||||
|     // ========== ORDER 模块 1-007-002-000 ========== | ||||
|     ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(100401000, "支付订单不存在"); | ||||
|     ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(100401001, "支付订单不处于待支付"); | ||||
|     ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(100401002, "支付订单不处于已支付"); | ||||
|     ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(100401003, "支付订单用户不正确"); | ||||
|  | ||||
|     ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(100401050, "支付交易拓展单不存在"); | ||||
|     ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(100401051, "支付交易拓展单不处于待支付"); | ||||
|     ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(100401052, "支付订单不处于已支付"); | ||||
|     ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在"); | ||||
|     ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付"); | ||||
|     ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付"); | ||||
|     ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(1007002003, "支付订单用户不正确"); | ||||
|     // ========== ORDER 模块(拓展单) 1-007-003-000 ========== | ||||
|     ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在"); | ||||
|     ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付"); | ||||
|     ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007003002, "支付订单不处于已支付"); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -39,4 +39,13 @@ public interface PayOrderCoreService { | ||||
|     */ | ||||
|    PayOrderSubmitRespDTO submitPayOrder(@Valid PayOrderSubmitReqDTO reqDTO); | ||||
|  | ||||
|    /** | ||||
|     * 通知支付单成功 | ||||
|     * | ||||
|     * @param channelId 渠道编号 | ||||
|     * @param channelCode 渠道编码 | ||||
|     * @param notifyData 通知数据 | ||||
|     */ | ||||
|    void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||
| import cn.iocoder.yudao.framework.pay.config.PayProperties; | ||||
| 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.PayOrderNotifyRespDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.stereotype.Service; | ||||
| @@ -99,7 +100,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { | ||||
|     @Override | ||||
|     public PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO) { | ||||
|         // 校验 App | ||||
|         PayAppDO app = payAppCoreService.validPayApp(reqDTO.getAppId()); | ||||
|        payAppCoreService.validPayApp(reqDTO.getAppId()); | ||||
|         // 校验支付渠道是否有效 | ||||
|         PayChannelDO channel = payChannelCoreService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode()); | ||||
|         // 校验支付客户端是否正确初始化 | ||||
| @@ -172,4 +173,61 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { | ||||
|                 ; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception { | ||||
|         // TODO 芋艿,记录回调日志 | ||||
|         log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData); | ||||
|  | ||||
|         // 校验支付渠道是否有效 | ||||
|         PayChannelDO channel = payChannelCoreService.validPayChannel(channelId, channelCode); | ||||
|         // 校验支付客户端是否正确初始化 | ||||
|         PayClient client = payClientFactory.getPayClient(channel.getId()); | ||||
|         if (client == null) { | ||||
|             log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); | ||||
|             throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); | ||||
|         } | ||||
|         // 解析支付结果 | ||||
|         PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData); | ||||
|  | ||||
|         // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。 | ||||
|         // 1.1 查询 PayOrderExtensionDO | ||||
|         PayOrderExtensionDO orderExtension = payOrderExtensionCoreMapper.selectByOrderExtensionNo( | ||||
|                 notifyRespDTO.getOrderExtensionNo()); | ||||
|         if (orderExtension == null) { | ||||
|             throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); | ||||
|         } | ||||
|         if (!PayOrderStatusEnum.WAITING.getStatus().equals(orderExtension.getStatus())) { // 校验状态,必须是待支付 | ||||
|             throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); | ||||
|         } | ||||
|         // 1.2 更新 PayOrderExtensionDO | ||||
|         int updateCounts = payOrderExtensionCoreMapper.updateByIdAndStatus(orderExtension.getOrderId(), | ||||
|                 PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId()) | ||||
|                         .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData).build()); | ||||
|         if (updateCounts == 0) { // 校验状态,必须是待支付 | ||||
|             throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); | ||||
|         } | ||||
|         log.info("[notifyPayOrder][支付拓展单({}) 更新为已支付]", orderExtension.getId()); | ||||
|  | ||||
|         // 2.1 判断 PayOrderDO 是否处于待支付 | ||||
|         PayOrderDO order = payOrderCoreMapper.selectById(orderExtension.getOrderId()); | ||||
|         if (order == null) { | ||||
|             throw exception(PAY_ORDER_NOT_FOUND); | ||||
|         } | ||||
|         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 | ||||
|             throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); | ||||
|         } | ||||
|         // 2.2 更新 PayOrderDO | ||||
|         updateCounts = payOrderCoreMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(), | ||||
|                 PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelId(channelId).channelCode(channelCode) | ||||
|                         .successTime(notifyRespDTO.getSuccessTime()).notifyTime(new Date()) | ||||
|                         .successExtensionId(orderExtension.getId()).build()); | ||||
|         if (updateCounts == 0) { // 校验状态,必须是待支付 | ||||
|             throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); | ||||
|         } | ||||
|         log.info("[notifyPayOrder][支付订单({}) 更新为已支付]", order.getId()); | ||||
|  | ||||
|         // 3. 插入支付通知记录 | ||||
| //        payNotifyService.addPayTransactionNotifyTask(order, orderExtension); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.framework.pay.core.client; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; | ||||
|  | ||||
| /** | ||||
| @@ -24,4 +25,13 @@ public interface PayClient { | ||||
|      */ | ||||
|     PayCommonResult<?> unifiedOrder(PayOrderUnifiedReqDTO reqDTO); | ||||
|  | ||||
|     /** | ||||
|      * 解析支付单的通知结果 | ||||
|      * | ||||
|      * @param data 通知结果 | ||||
|      * @return 解析结果 | ||||
|      * @throws Exception 解析失败,抛出异常 | ||||
|      */ | ||||
|     PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,39 @@ | ||||
| package cn.iocoder.yudao.framework.pay.core.client.dto; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.util.Date; | ||||
|  | ||||
| /** | ||||
|  * 支付通知 Response DTO | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class PayOrderNotifyRespDTO { | ||||
|  | ||||
|     /** | ||||
|      * 支付订单号(支付模块的) | ||||
|      */ | ||||
|     private String orderExtensionNo; | ||||
|     /** | ||||
|      * 支付渠道 | ||||
|      */ | ||||
|     private String channelOrderNo; | ||||
|     /** | ||||
|      * 支付渠道 | ||||
|      */ | ||||
|     private Date successTime; | ||||
|  | ||||
|     /** | ||||
|      * 通知的原始数据 | ||||
|      * | ||||
|      * 主要用于持久化,方便后续修复数据,或者排错 | ||||
|      */ | ||||
|     private String data; | ||||
|  | ||||
| } | ||||
| @@ -12,6 +12,8 @@ import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 统一下单 Request DTO | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| @Data | ||||
| public class PayOrderUnifiedReqDTO { | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; | ||||
|  | ||||
| import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | ||||
| import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | ||||
| @@ -65,4 +66,9 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayClientConfig> | ||||
|         return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception { | ||||
|         // TODO 芋艿:待完成 | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; | ||||
|  | ||||
| import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | ||||
| import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | ||||
| @@ -61,4 +62,9 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig> | ||||
|         return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception { | ||||
|         // TODO 芋艿:待完成 | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,14 +2,17 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx; | ||||
|  | ||||
| import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.hutool.core.date.DateUtil; | ||||
| import cn.hutool.core.lang.Assert; | ||||
| import cn.hutool.core.map.MapUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.util.io.FileUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; | ||||
| import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | ||||
| import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | ||||
| import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; | ||||
| import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; | ||||
| import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; | ||||
| import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; | ||||
| @@ -22,6 +25,8 @@ import com.github.binarywang.wxpay.service.WxPayService; | ||||
| import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
|  | ||||
| import java.util.Objects; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | ||||
| import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.CODE_SUCCESS; | ||||
| import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.MESSAGE_SUCCESS; | ||||
| @@ -126,4 +131,13 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | ||||
|         return openid; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public PayOrderNotifyRespDTO parseOrderNotify(String data) throws WxPayException { | ||||
|         WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data); | ||||
|         Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS"); | ||||
|         // 转换结果 | ||||
|         return new PayOrderNotifyRespDTO(notifyResult.getOutTradeNo(), notifyResult.getTransactionId(), | ||||
|                 DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"), data); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV