Commit f108d478a8206b5a0a76968014d6e7001235a31b

Authored by jason
1 parent 1c5544fc

调整渠道支付通知地址为统一的地址

Showing 14 changed files with 332 additions and 232 deletions
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java
@@ -24,9 +24,9 @@ public interface PayErrorCodeCoreConstants { @@ -24,9 +24,9 @@ public interface PayErrorCodeCoreConstants {
24 ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在"); 24 ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在");
25 ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道"); 25 ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道");
26 ErrorCode CHANNEL_WECHAT_VERSION_2_MCH_KEY_IS_NULL = new ErrorCode(1007001006,"微信渠道v2版本中商户密钥不可为空"); 26 ErrorCode CHANNEL_WECHAT_VERSION_2_MCH_KEY_IS_NULL = new ErrorCode(1007001006,"微信渠道v2版本中商户密钥不可为空");
27 - ErrorCode CHANNEL_WECHAT_VERSION_3_PRIVATE_KEY_IS_NULL = new ErrorCode(1007001006,"微信渠道v3版本apiclient_key.pem不可为空");  
28 - ErrorCode CHANNEL_WECHAT_VERSION_3_CERT_KEY_IS_NULL = new ErrorCode(1007001006,"微信渠道v3版本中apiclient_cert.pem不可为空");  
29 - 27 + ErrorCode CHANNEL_WECHAT_VERSION_3_PRIVATE_KEY_IS_NULL = new ErrorCode(1007001007,"微信渠道v3版本apiclient_key.pem不可为空");
  28 + ErrorCode CHANNEL_WECHAT_VERSION_3_CERT_KEY_IS_NULL = new ErrorCode(1007001008,"微信渠道v3版本中apiclient_cert.pem不可为空");
  29 + ErrorCode PAY_CHANNEL_NOTIFY_VERIFY_FAILED = new ErrorCode(1007001009, "渠道通知校验失败");
30 /** 30 /**
31 * ========== ORDER 模块 1-007-002-000 ========== 31 * ========== ORDER 模块 1-007-002-000 ==========
32 */ 32 */
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayCommonCoreService.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.pay.service.order;
  2 +
  3 +import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
  4 +
  5 +/**
  6 + * 支付通用 Core Service
  7 + *
  8 + * @author jason
  9 + */
  10 +public interface PayCommonCoreService {
  11 +
  12 + /**
  13 + * 验证是否是渠道通知
  14 + * @param notifyData 通知数据
  15 + */
  16 + void verifyNotifyData(Long channelId, PayNotifyDataDTO notifyData);
  17 +
  18 + /**
  19 + * 支付宝的支付回调通知,和退款回调通知 地址是同一个
  20 + * 是否是退款回调通知
  21 + * @param notifyData 通知数据
  22 + * @return
  23 + */
  24 + boolean isRefundNotify(Long channelId, PayNotifyDataDTO notifyData);
  25 +}
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java
@@ -43,10 +43,9 @@ public interface PayOrderCoreService { @@ -43,10 +43,9 @@ public interface PayOrderCoreService {
43 * 通知支付单成功 43 * 通知支付单成功
44 * 44 *
45 * @param channelId 渠道编号 45 * @param channelId 渠道编号
46 - * @param channelCode 渠道编码  
47 * @param notifyData 通知数据 46 * @param notifyData 通知数据
48 */ 47 */
49 - void notifyPayOrder(Long channelId, String channelCode, PayNotifyDataDTO notifyData) throws Exception; 48 + void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
50 49
51 50
52 51
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayRefundCoreService.java
@@ -23,11 +23,10 @@ public interface PayRefundCoreService { @@ -23,11 +23,10 @@ public interface PayRefundCoreService {
23 /** 23 /**
24 * 渠道的退款通知 24 * 渠道的退款通知
25 * @param channelId 渠道编号 25 * @param channelId 渠道编号
26 - * @param channelCode 渠道编码  
27 * @param notifyData 通知数据 26 * @param notifyData 通知数据
28 * @throws Exception 退款通知异常 27 * @throws Exception 退款通知异常
29 */ 28 */
30 - void notifyPayRefund(Long channelId, String channelCode, PayNotifyDataDTO notifyData) throws Exception; 29 + void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
31 30
32 31
33 32
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayCommonCoreServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
  2 +
  3 +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
  4 +import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService;
  5 +import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayCommonCoreService;
  6 +import cn.iocoder.yudao.framework.pay.core.client.PayClient;
  7 +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
  8 +import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.stereotype.Service;
  11 +
  12 +import javax.annotation.Resource;
  13 +
  14 +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
  15 +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_NOTIFY_VERIFY_FAILED;
  16 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  17 +
  18 +/**
  19 + * 支付通用 Core Service 实现类
  20 + *
  21 + * @author jason
  22 + */
  23 +@Service
  24 +@Slf4j
  25 +public class PayCommonCoreServiceImpl implements PayCommonCoreService {
  26 +
  27 + @Resource
  28 + private PayChannelCoreService payChannelCoreService;
  29 +
  30 + @Resource
  31 + private PayClientFactory payClientFactory;
  32 +
  33 + @Override
  34 + public void verifyNotifyData(Long channelId, PayNotifyDataDTO notifyData) {
  35 + // 校验支付渠道是否有效
  36 + PayChannelDO channel = payChannelCoreService.validPayChannel(channelId);
  37 + // 校验支付客户端是否正确初始化
  38 + PayClient client = payClientFactory.getPayClient(channel.getId());
  39 + if (client == null) {
  40 + log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
  41 + throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
  42 + }
  43 + boolean verifyResult = client.verifyNotifyData(notifyData);
  44 + if(!verifyResult){
  45 + //渠道通知验证失败
  46 + throw exception(PAY_CHANNEL_NOTIFY_VERIFY_FAILED);
  47 + }
  48 + }
  49 +
  50 + @Override
  51 + public boolean isRefundNotify(Long channelId, PayNotifyDataDTO notifyData) {
  52 + // 校验支付渠道是否有效
  53 + PayChannelDO channel = payChannelCoreService.validPayChannel(channelId);
  54 + // 校验支付客户端是否正确初始化
  55 + PayClient client = payClientFactory.getPayClient(channel.getId());
  56 + if (client == null) {
  57 + log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
  58 + throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
  59 + }
  60 + return client.isRefundNotify(notifyData);
  61 + }
  62 +}
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java
@@ -155,24 +155,22 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @@ -155,24 +155,22 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
155 155
156 /** 156 /**
157 * 根据支付渠道的编码,生成支付渠道的返回地址 157 * 根据支付渠道的编码,生成支付渠道的返回地址
158 - * @param channel  
159 - * @return 158 + * @param channel 支付渠道
  159 + * @return 支付成功返回的地址。 配置地址 + "/" + channel id
160 */ 160 */
161 private String genChannelReturnUrl(PayChannelDO channel) { 161 private String genChannelReturnUrl(PayChannelDO channel) {
162 - return payProperties.getPayReturnUrl() + "/" + StrUtil.replace(channel.getCode(), "_", "-")  
163 - + "/" + channel.getId(); 162 + return payProperties.getPayReturnUrl() + "/" + channel.getId();
164 } 163 }
165 164
166 /** 165 /**
167 * 根据支付渠道的编码,生成支付渠道的回调地址 166 * 根据支付渠道的编码,生成支付渠道的回调地址
168 * 167 *
169 * @param channel 支付渠道 168 * @param channel 支付渠道
170 - * @return 支付渠道的回调地址 169 + * @return 支付渠道的回调地址 配置地址 + "/" + channel id
171 */ 170 */
172 private String genChannelPayNotifyUrl(PayChannelDO channel) { 171 private String genChannelPayNotifyUrl(PayChannelDO channel) {
173 - // _ 转化为 - 的原因,是因为 URL 我们统一采用中划线的原则  
174 - return payProperties.getPayNotifyUrl() + "/" + StrUtil.replace(channel.getCode(), "_", "-")  
175 - + "/" + channel.getId(); 172 + //去掉channel code, 似乎没啥用, 用统一的回调地址
  173 + return payProperties.getPayNotifyUrl() + "/" + channel.getId();
176 } 174 }
177 175
178 private String generateOrderExtensionNo() { 176 private String generateOrderExtensionNo() {
@@ -195,7 +193,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @@ -195,7 +193,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
195 193
196 @Override 194 @Override
197 @Transactional 195 @Transactional
198 - public void notifyPayOrder(Long channelId, String channelCode, PayNotifyDataDTO notifyData) throws Exception { 196 + public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception {
199 // TODO 芋艿,记录回调日志 197 // TODO 芋艿,记录回调日志
200 log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getBody()); 198 log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
201 199
@@ -207,7 +205,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @@ -207,7 +205,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
207 log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); 205 log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
208 throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); 206 throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
209 } 207 }
210 - //TODO @jason 校验 是否支付宝调用。 使用 支付宝publickey 或者payclient 加一个校验方法 208 +
211 // 解析支付结果 209 // 解析支付结果
212 PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData); 210 PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData);
213 211
@@ -222,7 +220,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @@ -222,7 +220,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
222 throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 220 throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
223 } 221 }
224 // 1.2 更新 PayOrderExtensionDO 222 // 1.2 更新 PayOrderExtensionDO
225 - //TODO @jason notifyRespDTO.getTradeStatus() 需要根据不同的状态更新成不同的值 PayOrderStatusEnum 223 + //TODO 支付宝交易超时 TRADE_FINISHED 需要更新交易关闭
226 int updateCounts = payOrderExtensionCoreMapper.updateByIdAndStatus(orderExtension.getId(), 224 int updateCounts = payOrderExtensionCoreMapper.updateByIdAndStatus(orderExtension.getId(),
227 PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId()) 225 PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId())
228 .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData.getBody()).build()); 226 .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData.getBody()).build());
@@ -241,7 +239,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @@ -241,7 +239,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
241 } 239 }
242 // 2.2 更新 PayOrderDO 240 // 2.2 更新 PayOrderDO
243 updateCounts = payOrderCoreMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(), 241 updateCounts = payOrderCoreMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
244 - PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelId(channelId).channelCode(channelCode) 242 + PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelId(channelId).channelCode(channel.getCode())
245 .successTime(notifyRespDTO.getSuccessTime()).successExtensionId(orderExtension.getId()) 243 .successTime(notifyRespDTO.getSuccessTime()).successExtensionId(orderExtension.getId())
246 .channelOrderNo(notifyRespDTO.getChannelOrderNo()).channelUserId(notifyRespDTO.getChannelUserId()) 244 .channelOrderNo(notifyRespDTO.getChannelOrderNo()).channelUserId(notifyRespDTO.getChannelUserId())
247 .notifyTime(new Date()).build()); 245 .notifyTime(new Date()).build());
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundChannelQueryHandler.java
@@ -40,7 +40,9 @@ public class PayRefundChannelQueryHandler extends PayRefundAbstractChannelPostHa @@ -40,7 +40,9 @@ public class PayRefundChannelQueryHandler extends PayRefundAbstractChannelPostHa
40 //更新退款单表 40 //更新退款单表
41 PayRefundDO updateRefundDO = new PayRefundDO(); 41 PayRefundDO updateRefundDO = new PayRefundDO();
42 updateRefundDO.setId(respBO.getRefundId()) 42 updateRefundDO.setId(respBO.getRefundId())
43 - .setStatus(refundStatus.getStatus()); 43 + .setStatus(refundStatus.getStatus())
  44 + .setChannelErrorCode(respBO.getChannelErrCode())
  45 + .setChannelErrorMsg(respBO.getChannelErrMsg());
44 updatePayRefund(updateRefundDO); 46 updatePayRefund(updateRefundDO);
45 47
46 PayOrderDO updateOrderDO = new PayOrderDO(); 48 PayOrderDO updateOrderDO = new PayOrderDO();
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundCoreServiceImpl.java
@@ -182,7 +182,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -182,7 +182,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
182 182
183 183
184 @Override 184 @Override
185 - public void notifyPayRefund(Long channelId, String channelCode, PayNotifyDataDTO notifyData) { 185 + public void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) {
186 log.info("[notifyPayRefund][channelId({}) 回调数据({})]", channelId, notifyData.getBody()); 186 log.info("[notifyPayRefund][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
187 // 校验支付渠道是否有效 187 // 校验支付渠道是否有效
188 PayChannelDO channel = payChannelCoreService.validPayChannel(channelId); 188 PayChannelDO channel = payChannelCoreService.validPayChannel(channelId);
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
@@ -49,4 +49,22 @@ public interface PayClient { @@ -49,4 +49,22 @@ public interface PayClient {
49 */ 49 */
50 PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData); 50 PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData);
51 51
  52 +
  53 + /**
  54 + * 验证是否渠道通知
  55 + * @param notifyData 通知数据
  56 + * @return 默认是 true
  57 + */
  58 + default boolean verifyNotifyData(PayNotifyDataDTO notifyData){
  59 + return true;
  60 + }
  61 +
  62 + /**
  63 + * 是否退款通知
  64 + * @param notifyData 通知数据
  65 + * @return 默认是 false
  66 + */
  67 + default boolean isRefundNotify(PayNotifyDataDTO notifyData){
  68 + return false;
  69 + }
52 } 70 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
  2 +
  3 +import cn.hutool.core.bean.BeanUtil;
  4 +import cn.hutool.core.date.DateUtil;
  5 +import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping;
  6 +import cn.iocoder.yudao.framework.pay.core.client.dto.*;
  7 +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
  8 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;
  9 +import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
  10 +import com.alipay.api.AlipayApiException;
  11 +import com.alipay.api.AlipayConfig;
  12 +import com.alipay.api.DefaultAlipayClient;
  13 +import com.alipay.api.domain.AlipayTradeRefundModel;
  14 +import com.alipay.api.internal.util.AlipaySignature;
  15 +import com.alipay.api.request.AlipayTradeRefundRequest;
  16 +import com.alipay.api.response.AlipayTradeRefundResponse;
  17 +import lombok.SneakyThrows;
  18 +import lombok.extern.slf4j.Slf4j;
  19 +
  20 +import java.net.SocketTimeoutException;
  21 +import java.nio.charset.StandardCharsets;
  22 +import java.util.Map;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  25 +
  26 +/**
  27 + * 支付宝抽象类, 实现支付宝统一的接口。如退款
  28 + *
  29 + * @author jason
  30 + */
  31 +@Slf4j
  32 +public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayClientConfig> {
  33 +
  34 + protected DefaultAlipayClient client;
  35 +
  36 + public AbstractAlipayClient(Long channelId, String channelCode,
  37 + AlipayPayClientConfig config, AbstractPayCodeMapping codeMapping) {
  38 + super(channelId, channelCode, config, codeMapping);
  39 + }
  40 +
  41 + @Override
  42 + @SneakyThrows
  43 + protected void doInit() {
  44 + AlipayConfig alipayConfig = new AlipayConfig();
  45 + BeanUtil.copyProperties(config, alipayConfig, false);
  46 + this.client = new DefaultAlipayClient(alipayConfig);
  47 + }
  48 +
  49 + /**
  50 + * 从支付宝通知返回参数中解析 PayOrderNotifyRespDTO, 通知具体参数参考
  51 + * //https://opendocs.alipay.com/open/203/105286
  52 + * @param data 通知结果
  53 + * @return 解析结果 PayOrderNotifyRespDTO
  54 + * @throws Exception 解析失败,抛出异常
  55 + */
  56 + @Override
  57 + public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception {
  58 + Map<String, String> params = data.getParams();
  59 + return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("out_trade_no"))
  60 + .channelOrderNo(params.get("trade_no")).channelUserId(params.get("seller_id"))
  61 + .tradeStatus(params.get("trade_status"))
  62 + .successTime(DateUtil.parse(params.get("notify_time"), "yyyy-MM-dd HH:mm:ss"))
  63 + .data(data.getBody()).build();
  64 + }
  65 +
  66 + @Override
  67 + public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
  68 + Map<String, String> params = notifyData.getParams();
  69 + PayRefundNotifyDTO notifyDTO = PayRefundNotifyDTO.builder().channelOrderNo(params.get("trade_no"))
  70 + .tradeNo(params.get("out_trade_no"))
  71 + .reqNo(params.get("out_biz_no"))
  72 + .status(PayNotifyRefundStatusEnum.SUCCESS)
  73 + .refundSuccessTime(DateUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))
  74 + .build();
  75 + return notifyDTO;
  76 + }
  77 +
  78 + @Override
  79 + public boolean isRefundNotify(PayNotifyDataDTO notifyData) {
  80 + if (notifyData.getParams().containsKey("refund_fee")) {
  81 + return true;
  82 + } else {
  83 + return false;
  84 + }
  85 + }
  86 +
  87 + @Override
  88 + public boolean verifyNotifyData(PayNotifyDataDTO notifyData) {
  89 + boolean verifyResult = false;
  90 + try {
  91 + verifyResult = AlipaySignature.rsaCheckV1(notifyData.getParams(), config.getAlipayPublicKey(), StandardCharsets.UTF_8.name(), "RSA2");
  92 + } catch (AlipayApiException e) {
  93 + log.error("[AlipayClient verifyNotifyData][(notify param is :{}) 验证失败]", toJsonString(notifyData.getParams()), e);
  94 + }
  95 + return verifyResult;
  96 + }
  97 +
  98 + /**
  99 + * 支付宝统一的退款接口 alipay.trade.refund
  100 + * @param reqDTO 退款请求 request DTO
  101 + * @return 退款请求 Response
  102 + */
  103 + @Override
  104 + protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
  105 + AlipayTradeRefundModel model=new AlipayTradeRefundModel();
  106 + model.setTradeNo(reqDTO.getChannelOrderNo());
  107 + model.setOutTradeNo(reqDTO.getPayTradeNo());
  108 + model.setOutRequestNo(reqDTO.getRefundReqNo());
  109 + model.setRefundAmount(calculateAmount(reqDTO.getAmount()).toString());
  110 + model.setRefundReason(reqDTO.getReason());
  111 + AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
  112 + refundRequest.setBizModel(model);
  113 + PayRefundUnifiedRespDTO respDTO = new PayRefundUnifiedRespDTO();
  114 + try {
  115 + AlipayTradeRefundResponse response = client.execute(refundRequest);
  116 + log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response));
  117 + if (response.isSuccess()) {
  118 + //退款成功,更新为PROCESSING_NOTIFY, 而不是 SYNC_SUCCESS 通过支付宝回调接口处理。退款导致触发的异步通知,
  119 + //退款导致触发的异步通知是发送到支付接口中设置的notify_url
  120 + //TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对?
  121 + respDTO.setRespEnum(PayChannelRespEnum.PROCESSING_NOTIFY);
  122 + }else{
  123 + //特殊处理 sub_code ACQ.SYSTEM_ERROR(系统错误), 需要调用重试任务
  124 + //沙箱环境返回的貌似是”aop.ACQ.SYSTEM_ERROR“, 用contain
  125 + if (response.getSubCode().contains("ACQ.SYSTEM_ERROR")) {
  126 + respDTO.setRespEnum(PayChannelRespEnum.RETRY_FAILURE)
  127 + .setChannelErrMsg(response.getSubMsg())
  128 + .setChannelErrCode(response.getSubCode());
  129 + }else{
  130 + //交易已关闭,需要查询确认退款是否已经完成
  131 + if("ACQ.TRADE_HAS_CLOSE".equals(response.getSubCode())){
  132 + respDTO.setRespEnum(PayChannelRespEnum.PROCESSING_QUERY)
  133 + .setChannelErrMsg(response.getSubMsg())
  134 + .setChannelErrCode(response.getSubCode());
  135 + }else {
  136 + //其他当做不可以重试的错误
  137 + respDTO.setRespEnum(PayChannelRespEnum.CAN_NOT_RETRY_FAILURE)
  138 + .setChannelErrCode(response.getSubCode())
  139 + .setChannelErrMsg(response.getSubMsg());
  140 + }
  141 + }
  142 + }
  143 + return respDTO;
  144 + } catch (AlipayApiException e) {
  145 + //TODO 记录异常日志
  146 + log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e);
  147 + Throwable cause = e.getCause();
  148 + //网络 read time out 异常, 退款状态未知
  149 + if (cause instanceof SocketTimeoutException) {
  150 + respDTO.setExceptionMsg(e.getMessage())
  151 + .setRespEnum(PayChannelRespEnum.READ_TIME_OUT_EXCEPTION);
  152 + }else{
  153 + respDTO.setExceptionMsg(e.getMessage())
  154 + .setChannelErrCode(e.getErrCode())
  155 + .setChannelErrMsg(e.getErrMsg())
  156 + .setRespEnum(PayChannelRespEnum.CALL_EXCEPTION);
  157 + }
  158 + return respDTO;
  159 + }
  160 + }
  161 +
  162 +}
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; 1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
3 -import cn.hutool.core.bean.BeanUtil;  
4 -import cn.hutool.core.date.DateUtil;  
5 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; 3 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
6 -import cn.iocoder.yudao.framework.pay.core.client.dto.*;  
7 -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 4 +import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
8 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; 5 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
9 import com.alipay.api.AlipayApiException; 6 import com.alipay.api.AlipayApiException;
10 -import com.alipay.api.AlipayConfig;  
11 -import com.alipay.api.DefaultAlipayClient;  
12 import com.alipay.api.domain.AlipayTradePrecreateModel; 7 import com.alipay.api.domain.AlipayTradePrecreateModel;
13 import com.alipay.api.request.AlipayTradePrecreateRequest; 8 import com.alipay.api.request.AlipayTradePrecreateRequest;
14 import com.alipay.api.response.AlipayTradePrecreateResponse; 9 import com.alipay.api.response.AlipayTradePrecreateResponse;
15 -import lombok.SneakyThrows;  
16 import lombok.extern.slf4j.Slf4j; 10 import lombok.extern.slf4j.Slf4j;
17 11
18 -import java.util.Map;  
19 -  
20 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 12 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
21 13
22 /** 14 /**
@@ -26,24 +18,13 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString @@ -26,24 +18,13 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString
26 * @author 芋道源码 18 * @author 芋道源码
27 */ 19 */
28 @Slf4j 20 @Slf4j
29 -public class AlipayQrPayClient extends AbstractPayClient<AlipayPayClientConfig> {  
30 -  
31 - private DefaultAlipayClient client; 21 +public class AlipayQrPayClient extends AbstractAlipayClient {
32 22
33 public AlipayQrPayClient(Long channelId, AlipayPayClientConfig config) { 23 public AlipayQrPayClient(Long channelId, AlipayPayClientConfig config) {
34 super(channelId, PayChannelEnum.ALIPAY_QR.getCode(), config, new AlipayPayCodeMapping()); 24 super(channelId, PayChannelEnum.ALIPAY_QR.getCode(), config, new AlipayPayCodeMapping());
35 } 25 }
36 26
37 @Override 27 @Override
38 - @SneakyThrows  
39 - protected void doInit() {  
40 - AlipayConfig alipayConfig = new AlipayConfig();  
41 - BeanUtil.copyProperties(config, alipayConfig, false);  
42 - // 真实客户端  
43 - this.client = new DefaultAlipayClient(alipayConfig);  
44 - }  
45 -  
46 - @Override  
47 public PayCommonResult<AlipayTradePrecreateResponse> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { 28 public PayCommonResult<AlipayTradePrecreateResponse> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
48 // 构建 AlipayTradePrecreateModel 请求 29 // 构建 AlipayTradePrecreateModel 请求
49 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); 30 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
@@ -56,7 +37,7 @@ public class AlipayQrPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt; @@ -56,7 +37,7 @@ public class AlipayQrPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt;
56 AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); 37 AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
57 request.setBizModel(model); 38 request.setBizModel(model);
58 request.setNotifyUrl(reqDTO.getNotifyUrl()); 39 request.setNotifyUrl(reqDTO.getNotifyUrl());
59 - 40 + request.setReturnUrl(reqDTO.getReturnUrl());
60 // 执行请求 41 // 执行请求
61 AlipayTradePrecreateResponse response; 42 AlipayTradePrecreateResponse response;
62 try { 43 try {
@@ -68,30 +49,4 @@ public class AlipayQrPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt; @@ -68,30 +49,4 @@ public class AlipayQrPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt;
68 // TODO 芋艿:sub Code 需要测试下各种失败的情况 49 // TODO 芋艿:sub Code 需要测试下各种失败的情况
69 return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping); 50 return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping);
70 } 51 }
71 -  
72 -  
73 -  
74 - @Override  
75 - public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception {  
76 - //结果转换  
77 - Map<String, String> params = data.getParams();  
78 - return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("out_trade_no"))  
79 - .channelOrderNo(params.get("trade_no")).channelUserId(params.get("seller_id"))  
80 - .tradeStatus(params.get("trade_status"))  
81 - .successTime(DateUtil.parse(params.get("notify_time"), "yyyy-MM-dd HH:mm:ss"))  
82 - .data(data.getBody()).build();  
83 -  
84 - }  
85 -  
86 - @Override  
87 - public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {  
88 - //TODO 需要实现  
89 - throw new UnsupportedOperationException("需要实现");  
90 - }  
91 -  
92 - @Override  
93 - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {  
94 - //TODO 需要实现  
95 - throw new UnsupportedOperationException();  
96 - }  
97 } 52 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; 1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
3 -import cn.hutool.core.bean.BeanUtil;  
4 import cn.hutool.core.date.DateUtil; 3 import cn.hutool.core.date.DateUtil;
5 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; 4 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
6 -import cn.iocoder.yudao.framework.pay.core.client.dto.*;  
7 -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 5 +import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
8 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; 6 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
9 -import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;  
10 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
11 import com.alipay.api.AlipayApiException; 7 import com.alipay.api.AlipayApiException;
12 -import com.alipay.api.AlipayConfig;  
13 -import com.alipay.api.DefaultAlipayClient;  
14 -import com.alipay.api.domain.AlipayTradeRefundModel;  
15 import com.alipay.api.domain.AlipayTradeWapPayModel; 8 import com.alipay.api.domain.AlipayTradeWapPayModel;
16 -import com.alipay.api.request.AlipayTradeRefundRequest;  
17 import com.alipay.api.request.AlipayTradeWapPayRequest; 9 import com.alipay.api.request.AlipayTradeWapPayRequest;
18 -import com.alipay.api.response.AlipayTradeRefundResponse;  
19 import com.alipay.api.response.AlipayTradeWapPayResponse; 10 import com.alipay.api.response.AlipayTradeWapPayResponse;
20 -import lombok.SneakyThrows;  
21 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
22 12
23 -import java.net.SocketTimeoutException;  
24 -import java.util.Map;  
25 import java.util.Objects; 13 import java.util.Objects;
26 14
27 -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;  
28 -  
29 /** 15 /**
30 * 支付宝【手机网站】的 PayClient 实现类 16 * 支付宝【手机网站】的 PayClient 实现类
31 * 文档:https://opendocs.alipay.com/apis/api_1/alipay.trade.wap.pay 17 * 文档:https://opendocs.alipay.com/apis/api_1/alipay.trade.wap.pay
@@ -33,23 +19,14 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString @@ -33,23 +19,14 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString
33 * @author 芋道源码 19 * @author 芋道源码
34 */ 20 */
35 @Slf4j 21 @Slf4j
36 -public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig> { 22 +public class AlipayWapPayClient extends AbstractAlipayClient {
37 23
38 - private DefaultAlipayClient client;  
39 24
40 public AlipayWapPayClient(Long channelId, AlipayPayClientConfig config) { 25 public AlipayWapPayClient(Long channelId, AlipayPayClientConfig config) {
41 super(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config, new AlipayPayCodeMapping()); 26 super(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config, new AlipayPayCodeMapping());
42 } 27 }
43 28
44 @Override 29 @Override
45 - @SneakyThrows  
46 - protected void doInit() {  
47 - AlipayConfig alipayConfig = new AlipayConfig();  
48 - BeanUtil.copyProperties(config, alipayConfig, false);  
49 - this.client = new DefaultAlipayClient(alipayConfig);  
50 - }  
51 -  
52 - @Override  
53 public PayCommonResult<AlipayTradeWapPayResponse> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { 30 public PayCommonResult<AlipayTradeWapPayResponse> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
54 // 构建 AlipayTradeWapPayModel 请求 31 // 构建 AlipayTradeWapPayModel 请求
55 AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); 32 AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
@@ -69,6 +46,7 @@ public class AlipayWapPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt; @@ -69,6 +46,7 @@ public class AlipayWapPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt;
69 request.setBizModel(model); 46 request.setBizModel(model);
70 request.setNotifyUrl(reqDTO.getNotifyUrl()); 47 request.setNotifyUrl(reqDTO.getNotifyUrl());
71 request.setReturnUrl(reqDTO.getReturnUrl()); 48 request.setReturnUrl(reqDTO.getReturnUrl());
  49 +
72 // 执行请求 50 // 执行请求
73 AlipayTradeWapPayResponse response; 51 AlipayTradeWapPayResponse response;
74 try { 52 try {
@@ -87,85 +65,11 @@ public class AlipayWapPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt; @@ -87,85 +65,11 @@ public class AlipayWapPayClient extends AbstractPayClient&lt;AlipayPayClientConfig&gt;
87 } 65 }
88 66
89 67
90 - /**  
91 - * 从支付宝通知返回参数中解析 PayOrderNotifyRespDTO, 通知具体参数参考  
92 - * //https://opendocs.alipay.com/open/203/105286  
93 - * @param data 通知结果  
94 - * @return 解析结果 PayOrderNotifyRespDTO  
95 - * @throws Exception 解析失败,抛出异常  
96 - */  
97 - @Override  
98 - public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception {  
99 - Map<String, String> params = data.getParams();  
100 - return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("out_trade_no"))  
101 - .channelOrderNo(params.get("trade_no")).channelUserId(params.get("seller_id"))  
102 - .tradeStatus(params.get("trade_status"))  
103 - .successTime(DateUtil.parse(params.get("notify_time"), "yyyy-MM-dd HH:mm:ss"))  
104 - .data(data.getBody()).build();  
105 - }  
106 68
107 - @Override  
108 - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {  
109 - AlipayTradeRefundModel model=new AlipayTradeRefundModel();  
110 - model.setTradeNo(reqDTO.getChannelOrderNo());  
111 - model.setOutTradeNo(reqDTO.getPayTradeNo());  
112 - model.setOutRequestNo(reqDTO.getRefundReqNo());  
113 - model.setRefundAmount(calculateAmount(reqDTO.getAmount()).toString());  
114 - model.setRefundReason(reqDTO.getReason());  
115 - AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();  
116 - refundRequest.setBizModel(model);  
117 - PayRefundUnifiedRespDTO respDTO = new PayRefundUnifiedRespDTO();  
118 - try {  
119 - AlipayTradeRefundResponse response = client.execute(refundRequest);  
120 - log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response));  
121 - if (response.isSuccess()) {  
122 - //退款成功,更新为PROCESSING_NOTIFY, 而不是 SYNC_SUCCESS 通过支付宝回调接口处理。退款导致触发的异步通知,  
123 - //退款导致触发的异步通知是发送到支付接口中设置的notify_url  
124 - //TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对?  
125 - respDTO.setRespEnum(PayChannelRespEnum.PROCESSING_NOTIFY);  
126 - }else{  
127 - //特殊处理 sub_code ACQ.SYSTEM_ERROR(系统错误), 需要调用重试任务  
128 - //沙箱环境返回的貌似是”aop.ACQ.SYSTEM_ERROR“, 用contain  
129 - if (response.getSubCode().contains("ACQ.SYSTEM_ERROR")) {  
130 - respDTO.setRespEnum(PayChannelRespEnum.RETRY_FAILURE)  
131 - .setChannelErrMsg(response.getSubMsg())  
132 - .setChannelErrCode(response.getSubCode());  
133 - }else{  
134 - //其他当做不可以重试的错误  
135 - respDTO.setRespEnum(PayChannelRespEnum.CAN_NOT_RETRY_FAILURE)  
136 - .setChannelErrCode(response.getSubCode())  
137 - .setChannelErrMsg(response.getSubMsg());  
138 - }  
139 - }  
140 - return respDTO;  
141 - } catch (AlipayApiException e) {  
142 - //TODO 记录异常日志  
143 - log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e);  
144 - Throwable cause = e.getCause();  
145 - //网络 read time out 异常, 退款状态未知  
146 - if (cause instanceof SocketTimeoutException) {  
147 - respDTO.setExceptionMsg(e.getMessage())  
148 - .setRespEnum(PayChannelRespEnum.READ_TIME_OUT_EXCEPTION);  
149 - }else{  
150 - respDTO.setExceptionMsg(e.getMessage())  
151 - .setChannelErrCode(e.getErrCode())  
152 - .setChannelErrMsg(e.getErrMsg())  
153 - .setRespEnum(PayChannelRespEnum.CALL_EXCEPTION);  
154 - }  
155 - return respDTO;  
156 - }  
157 - }  
158 69
159 - @Override  
160 - public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {  
161 - Map<String, String> params = notifyData.getParams();  
162 - PayRefundNotifyDTO notifyDTO = PayRefundNotifyDTO.builder().channelOrderNo(params.get("trade_no"))  
163 - .tradeNo(params.get("out_trade_no"))  
164 - .reqNo(params.get("out_biz_no"))  
165 - .status(PayNotifyRefundStatusEnum.SUCCESS)  
166 - .refundSuccessTime(DateUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))  
167 - .build();  
168 - return notifyDTO;  
169 - } 70 +
  71 +
  72 +
  73 +
170 74
171 } 75 }
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/UserServerApplication.java
@@ -4,7 +4,8 @@ import org.springframework.boot.SpringApplication; @@ -4,7 +4,8 @@ import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 5
6 @SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} 和 ${yudao.core-service.base-package} 6 @SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} 和 ${yudao.core-service.base-package}
7 -@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"})public class UserServerApplication { 7 +@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"})
  8 +public class UserServerApplication {
8 9
9 public static void main(String[] args) { 10 public static void main(String[] args) {
10 SpringApplication.run(UserServerApplication.class, args); 11 SpringApplication.run(UserServerApplication.class, args);
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayOrderController.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.userserver.modules.pay.controller.order; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.userserver.modules.pay.controller.order;
2 2
3 import cn.hutool.core.bean.BeanUtil; 3 import cn.hutool.core.bean.BeanUtil;
4 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; 4 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
  5 +import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayCommonCoreService;
5 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreService; 6 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreService;
6 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService; 7 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService;
7 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO; 8 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO;
@@ -38,6 +39,9 @@ public class PayOrderController { @@ -38,6 +39,9 @@ public class PayOrderController {
38 @Resource 39 @Resource
39 private PayRefundCoreService payRefundCoreService; 40 private PayRefundCoreService payRefundCoreService;
40 41
  42 + @Resource PayCommonCoreService commonCoreService;
  43 +
  44 +
41 @PostMapping("/submit") 45 @PostMapping("/submit")
42 @ApiOperation("提交支付订单") 46 @ApiOperation("提交支付订单")
43 // @PreAuthenticated // TODO 暂时不加登陆验证,前端暂时没做好 47 // @PreAuthenticated // TODO 暂时不加登陆验证,前端暂时没做好
@@ -57,82 +61,53 @@ public class PayOrderController { @@ -57,82 +61,53 @@ public class PayOrderController {
57 } 61 }
58 62
59 // ========== 支付渠道的回调 ========== 63 // ========== 支付渠道的回调 ==========
60 - 64 + //TODO 芋道源码 换成了统一的地址了 /notify/{channelId},测试通过可以删除
61 @PostMapping("/notify/wx-pub/{channelId}") 65 @PostMapping("/notify/wx-pub/{channelId}")
62 @ApiOperation("通知微信公众号支付的结果") 66 @ApiOperation("通知微信公众号支付的结果")
63 public String notifyWxPayOrder(@PathVariable("channelId") Long channelId, 67 public String notifyWxPayOrder(@PathVariable("channelId") Long channelId,
64 @RequestBody String xmlData) throws Exception { 68 @RequestBody String xmlData) throws Exception {
65 - payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.WX_PUB.getCode(), PayNotifyDataDTO.builder().body(xmlData).build()); 69 + payOrderCoreService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().body(xmlData).build());
66 return "success"; 70 return "success";
67 } 71 }
68 72
69 - @PostMapping("/notify/alipay-qr/{channelId}")  
70 - @ApiOperation("通知支付宝扫码支付的结果")  
71 - public String notifyAlipayQrPayOrder(@PathVariable("channelId") Long channelId,  
72 - @RequestParam Map<String, String> params,  
73 - @RequestBody String originData) throws Exception{  
74 - payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.ALIPAY_QR.getCode(),  
75 - PayNotifyDataDTO.builder().params(params).body(originData).build());  
76 - return "success";  
77 - }  
78 -  
79 - @GetMapping(value = "/return/alipay-qr/{channelId}")  
80 - @ApiOperation("支付宝 wap 页面回跳")  
81 - public String returnAliPayQrPayOrder(@PathVariable("channelId") Long channelId){  
82 - //TODO @jason 校验 是否支付宝调用。 支付宝publickey 可以根据 appId 跳转不同的页面  
83 - System.out.println("支付成功");  
84 - return "支付成功";  
85 - }  
86 -  
87 - @PostMapping(value = "/notify/alipay-wap/{channelId}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)  
88 - @ApiOperation("支付宝 wap 页面回调")  
89 - public String notifyAliPayWapPayOrder(@PathVariable("channelId") Long channelId,  
90 - @RequestParam Map<String, String> params,  
91 - @RequestBody String originData) throws Exception {  
92 - //TODO 校验是否支付宝调用。 payclient 中加一个校验方法  
93 - //支付宝退款交易也会触发支付回调接口  
94 - //参考 https://opensupport.alipay.com/support/helpcenter/193/201602484851  
95 - //判断是否为支付宝的退款交易  
96 - if(isAliPayRefund(params)) {  
97 - //退款通知  
98 - payRefundCoreService.notifyPayRefund(channelId,PayChannelEnum.ALIPAY_WAP.getCode(), PayNotifyDataDTO.builder().params(params).body(originData).build());  
99 - }else{  
100 - //支付通知  
101 - payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), PayNotifyDataDTO.builder().params(params).body(originData).build());  
102 - }  
103 - return "success";  
104 - }  
105 -  
106 -  
107 /** 73 /**
  74 + * 统一的跳转页面, 支付宝跳转参数说明
108 * https://opendocs.alipay.com/open/203/105285#%E5%89%8D%E5%8F%B0%E5%9B%9E%E8%B7%B3%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E 75 * https://opendocs.alipay.com/open/203/105285#%E5%89%8D%E5%8F%B0%E5%9B%9E%E8%B7%B3%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E
109 * @param channelId 渠道id 76 * @param channelId 渠道id
110 * @return 返回跳转页面 77 * @return 返回跳转页面
111 */ 78 */
112 - @GetMapping(value = "/return/alipay-wap/{channelId}")  
113 - @ApiOperation("支付宝 wap 页面回跳")  
114 - public String returnAliPayWapPayOrder(@PathVariable("channelId") Long channelId){  
115 - //TODO 校验 是否支付宝调用。 可以根据 appId 跳转不同的页面  
116 - return "支付成功"; 79 + @GetMapping(value = "/return/{channelId}")
  80 + @ApiOperation("渠道统一的支付成功返回地址")
  81 + public String returnAliPayOrder(@PathVariable("channelId") Long channelId, @RequestParam Map<String, String> params){
  82 + //TODO 可以根据渠道和 app_id 返回不同的页面
  83 + log.info("app_id is {}", params.get("app_id"));
  84 + return String.format("渠道[%s]支付成功", String.valueOf(channelId));
117 } 85 }
118 86
119 /** 87 /**
120 - * 是否是支付宝的退款交易  
121 - * @param params http content-type application/x-www-form-urlencoded 的参数  
122 - * @return 88 + * 统一的渠道支付回调,支付宝的退款回调
  89 + * @param channelId 渠道编号
  90 + * @param params form 参数
  91 + * @param originData http request body
  92 + * @return 成功返回 "success"
123 */ 93 */
124 - private boolean isAliPayRefund(Map<String, String> params) {  
125 - if (params.containsKey("refund_fee")) {  
126 - return true;  
127 - } else {  
128 - return false; 94 + @PostMapping(value = "/notify/{channelId}")
  95 + @ApiOperation("渠道统一的支付成功,或退款成功 通知url")
  96 + public String notifyChannelPay(@PathVariable("channelId") Long channelId,
  97 + @RequestParam Map<String, String> params,
  98 + @RequestBody String originData) throws Exception {
  99 + //校验是否是渠道回调
  100 + commonCoreService.verifyNotifyData(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
  101 + //支付宝退款交易也会触发支付回调接口
  102 + //参考 https://opensupport.alipay.com/support/helpcenter/193/201602484851
  103 + //判断是否为退款通知
  104 + if(commonCoreService.isRefundNotify(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build())) {
  105 + //退款通知
  106 + payRefundCoreService.notifyPayRefund(channelId,PayNotifyDataDTO.builder().params(params).body(originData).build());
  107 + }else{
  108 + //支付通知
  109 + payOrderCoreService.notifyPayOrder(channelId,PayNotifyDataDTO.builder().params(params).body(originData).build());
129 } 110 }
130 - }  
131 -  
132 - @RequestMapping("/notify/test")  
133 - @ApiOperation("通知的测试接口")  
134 - public String notifyTest() {  
135 -// System.out.println(data);  
136 return "success"; 111 return "success";
137 } 112 }
138 113