feat 云闪付回调处理和一些接口联调, 优化精简统一SDK

This commit is contained in:
bootx
2024-10-09 23:03:39 +08:00
parent 5101625ad2
commit 6cd49a4ba3
17 changed files with 274 additions and 988 deletions

View File

@@ -1,9 +1,15 @@
package org.dromara.daxpay.channel.union.controller;
import cn.bootx.platform.core.annotation.IgnoreAuth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.dromara.daxpay.channel.union.service.callback.UnionPayCallbackService;
import org.dromara.daxpay.channel.union.service.callback.UnionRefundCallbackService;
import org.dromara.daxpay.service.service.assist.PaymentAssistService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -15,24 +21,27 @@ import org.springframework.web.bind.annotation.RestController;
@IgnoreAuth
@Tag(name = "银联回调通知")
@RestController
@RequestMapping("/unipay/callback/{AppId}")
@RequestMapping("/unipay/callback/{AppId}/union")
@RequiredArgsConstructor
public class UnionPayCallbackController {
private final PaymentAssistService paymentAssistService;
private final UnionPayCallbackService unionPayCallbackService;
// @Operation(summary = "云闪付支付回调")
// @PostMapping("/pay")
// public String wechatPayNotify(@PathVariable("AppId") String appId, HttpServletRequest request) {
// paymentAssistService.initMchApp(appId);
// return payCallbackService.payHandle(request);
// }
//
//
// @Operation(summary = "云闪付退款回调")
// @PostMapping("/refund")
// public String wechatRefundNotify(@PathVariable("AppId") String appId,HttpServletRequest request) {
// paymentAssistService.initMchApp(appId);
// return refundCallbackService.refundHandle(request);
// }
private final PaymentAssistService paymentAssistService;
private final UnionRefundCallbackService refundCallbackService;
@Operation(summary = "云闪付支付回调")
@PostMapping("/pay")
public String wechatPayNotify(@PathVariable("AppId") String appId, HttpServletRequest request) {
paymentAssistService.initMchApp(appId);
return unionPayCallbackService.payHandle(request);
}
@Operation(summary = "云闪付退款回调")
@PostMapping("/refund")
public String wechatRefundNotify(@PathVariable("AppId") String appId, HttpServletRequest request) {
paymentAssistService.initMchApp(appId);
return refundCallbackService.refundHandle(request);
}
}

View File

@@ -23,7 +23,6 @@ import org.dromara.daxpay.unisdk.common.util.sign.encrypt.RSA2;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.cert.*;
@@ -146,18 +145,15 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
}
/**
* 后台通知地址
* 初始化异步通知地址
*
* @param parameters 预订单信息
* @param order 订单
* @return 预订单信息
*/
private Map<String, Object> initNotifyUrl(Map<String, Object> parameters, AssistOrder order) {
//后台通知地址
private void initNotifyUrl(Map<String, Object> parameters, AssistOrder order) {
OrderParaStructure.loadParameters(parameters, SDKConstants.param_backUrl, payConfigStorage.getNotifyUrl());
OrderParaStructure.loadParameters(parameters, SDKConstants.param_backUrl, order.getNotifyUrl());
OrderParaStructure.loadParameters(parameters, SDKConstants.param_backUrl, order);
return parameters;
}
@@ -178,8 +174,6 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
//订单发送时间
params.put(SDKConstants.param_txnTime, DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN));
//后台通知地址
params.put(SDKConstants.param_backUrl, payConfigStorage.getNotifyUrl());
//交易币种
params.put(SDKConstants.param_currencyCode, "156");
@@ -197,7 +191,7 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
*/
@Override
public boolean verify(NoticeParams noticeParams) {
final Map<String, Object> result = noticeParams.getBody();
final Map<String, ?> result = noticeParams.getBody();
if (null == result || result.get(SDKConstants.param_signature) == null) {
log.debug("银联支付验签异常params{}", result);
return false;
@@ -212,7 +206,7 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
* @param sign 签名原文
* @return 签名校验 true通过
*/
public boolean signVerify(Map<String, Object> params, String sign) {
public boolean signVerify(Map<String, ?> params, String sign) {
SignUtils signUtils = SignUtils.valueOf(payConfigStorage.getSignType());
String data = SignTextUtils.parameterText(params, "&", "signature");
@@ -244,7 +238,6 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
* @return 具体的时间字符串
*/
private String getPayTimeout(Date expirationTime) {
//
if (null != expirationTime) {
return DateUtil.format(expirationTime, DatePattern.PURE_DATETIME_PATTERN);
}
@@ -445,8 +438,7 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
@Override
public Map<String, Object> microPay(UniOrder order) {
order.setTransactionType(UnionTransactionType.CONSUME);
JSONObject response = postOrder(order, getBackTransUrl());
return response;
return postOrder(order, getBackTransUrl());
}
@@ -570,50 +562,6 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
return UriVariables.getParametersToMap(responseStr);
}
/**
* 消费撤销/退货接口
*
* @param origQryId 原交易查询流水号.
* @param orderId 退款单号
* @param refundAmount 退款金额
* @param type UnionTransactionType.REFUND 或者UnionTransactionType.CONSUME_UNDO
* @return 返回支付方申请退款后的结果
*/
public UnionRefundResult unionRefundOrConsumeUndo(String origQryId, String orderId, BigDecimal refundAmount, UnionTransactionType type) {
return unionRefundOrConsumeUndo(new UniRefundOrder(orderId, origQryId, refundAmount), type);
}
/**
* 消费撤销/退货接口
*
* @param refundOrder 退款订单信息
* @param type UnionTransactionType.REFUND 或者UnionTransactionType.CONSUME_UNDO
* @return 返回支付方申请退款后的结果
*/
public UnionRefundResult unionRefundOrConsumeUndo(UniRefundOrder refundOrder, UnionTransactionType type) {
Map<String, Object> params = this.getCommonParam();
type.convertMap(params);
params.put(SDKConstants.param_orderId, refundOrder.getRefundNo());
params.put(SDKConstants.param_txnAmt, Util.conversionCentAmount(refundOrder.getRefundAmount()));
params.put(SDKConstants.param_origQryId, refundOrder.getTradeNo());
params.putAll(refundOrder.getAttrs());
this.setSign(params);
String responseStr = getHttpRequestTemplate().postForObject(this.getBackTransUrl(), params, String.class);
JSONObject response = UriVariables.getParametersToMap(responseStr);
if (this.verify(new NoticeParams(response))) {
final UnionRefundResult refundResult = UnionRefundResult.create(response);
if (SDKConstants.OK_RESP_CODE.equals(refundResult.getRespCode())) {
return refundResult;
}
throw new PayErrorException(new PayException(response.getString(SDKConstants.param_respCode), response.getString(SDKConstants.param_respMsg), response.toJSONString()));
}
throw new PayErrorException(new PayException("failure", "验证签名失败", response.toJSONString()));
}
/**
* 交易关闭接口
* TODO 这个是冲正接口, 后续进行迁移
@@ -639,9 +587,34 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
return UriVariables.getParametersToMap(responseStr);
}
/**
* 消费撤销/退货接口
*
* @param refundOrder 退款订单信息
* @return 返回支付方申请退款后的结果
*/
@Override
public UnionRefundResult refund(UniRefundOrder refundOrder) {
return unionRefundOrConsumeUndo(refundOrder, UnionTransactionType.REFUND);
Map<String, Object> params = this.getCommonParam();
initNotifyUrl(params, refundOrder);
UnionTransactionType.REFUND.convertMap(params);
params.put(SDKConstants.param_orderId, refundOrder.getRefundNo());
params.put(SDKConstants.param_txnAmt, Util.conversionCentAmount(refundOrder.getRefundAmount()));
params.put(SDKConstants.param_origQryId, refundOrder.getTradeNo());
params.putAll(refundOrder.getAttrs());
this.setSign(params);
String responseStr = getHttpRequestTemplate().postForObject(this.getBackTransUrl(), params, String.class);
JSONObject response = UriVariables.getParametersToMap(responseStr);
if (this.verify(new NoticeParams(response))) {
final UnionRefundResult refundResult = UnionRefundResult.create(response);
if (SDKConstants.OK_RESP_CODE.equals(refundResult.getRespCode())) {
return refundResult;
}
throw new PayErrorException(new PayException(response.getString(SDKConstants.param_respCode), response.getString(SDKConstants.param_respMsg), response.toJSONString()));
}
throw new PayErrorException(new PayException("failure", "验证签名失败", response.toJSONString()));
}
@@ -690,7 +663,7 @@ public class UnionPayKit extends BasePayService<UnionPayConfigStorage> {
JSONObject response = UriVariables.getParametersToMap(responseStr);
// if (this.verify(response)) {
// if (SDKConstants.OK_RESP_CODE.equals(response.get(SDKConstants.param_respCode))) {
return response;
return response;
// }
// throw new PayErrorException(new PayException(response.get(SDKConstants.param_respCode).toString(), response.get(SDKConstants.param_respMsg).toString(), response.toString()));
// }

View File

@@ -1,6 +1,8 @@
package org.dromara.daxpay.channel.union.sdk.bean;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import org.dromara.daxpay.unisdk.common.bean.BaseRefundResult;
import org.dromara.daxpay.unisdk.common.bean.CurType;
@@ -14,6 +16,8 @@ import java.util.Map;
* email egzosn@gmail.com
* date 2020/8/16 22:15
*/
@Setter
@Getter
public class UnionRefundResult extends BaseRefundResult {
/**
@@ -182,142 +186,6 @@ public class UnionRefundResult extends BaseRefundResult {
return null;
}
public String getQrCode() {
return qrCode;
}
public void setQrCode(String qrCode) {
this.qrCode = qrCode;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getSignMethod() {
return signMethod;
}
public void setSignMethod(String signMethod) {
this.signMethod = signMethod;
}
public String getRespCode() {
return respCode;
}
public void setRespCode(String respCode) {
this.respCode = respCode;
}
public String getRespMsg() {
return respMsg;
}
public void setRespMsg(String respMsg) {
this.respMsg = respMsg;
}
public String getSignPubKeyCert() {
return signPubKeyCert;
}
public void setSignPubKeyCert(String signPubKeyCert) {
this.signPubKeyCert = signPubKeyCert;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public String getBizType() {
return bizType;
}
public void setBizType(String bizType) {
this.bizType = bizType;
}
public String getTxnTime() {
return txnTime;
}
public void setTxnTime(String txnTime) {
this.txnTime = txnTime;
}
public String getTxnType() {
return txnType;
}
public void setTxnType(String txnType) {
this.txnType = txnType;
}
public String getTxnSubType() {
return txnSubType;
}
public void setTxnSubType(String txnSubType) {
this.txnSubType = txnSubType;
}
public String getAccessType() {
return accessType;
}
public void setAccessType(String accessType) {
this.accessType = accessType;
}
public String getReqReserved() {
return reqReserved;
}
public void setReqReserved(String reqReserved) {
this.reqReserved = reqReserved;
}
public String getMerId() {
return merId;
}
public void setMerId(String merId) {
this.merId = merId;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getReserved() {
return reserved;
}
public void setReserved(String reserved) {
this.reserved = reserved;
}
public static UnionRefundResult create(Map<String, Object> result){
UnionRefundResult refundResult = new JSONObject(result).toJavaObject(UnionRefundResult.class);
refundResult.setAttrs(result);

View File

@@ -0,0 +1,99 @@
package org.dromara.daxpay.channel.union.service.callback;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.channel.union.code.UnionPayCode;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.sdk.bean.SDKConstants;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.core.enums.CallbackStatusEnum;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.core.enums.PayStatusEnum;
import org.dromara.daxpay.core.enums.TradeTypeEnum;
import org.dromara.daxpay.core.util.PayUtil;
import org.dromara.daxpay.service.common.context.CallbackLocal;
import org.dromara.daxpay.service.common.local.PaymentContextLocal;
import org.dromara.daxpay.service.service.record.callback.TradeCallbackRecordService;
import org.dromara.daxpay.service.service.trade.pay.PayCallbackService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 云闪付支付回调
* @author xxm
* @since 2024/10/9
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UnionPayCallbackService {
private final PayCallbackService payCallbackService;
private final TradeCallbackRecordService tradeCallbackRecordService;
private final UnionPayConfigService unionPayConfigService;
/**
* 支付回调处理
*/
public String payHandle(HttpServletRequest request){
// 解析数据
if (this.resolve(request)){
// 执行回调业务处理
payCallbackService.payCallback();
// 保存记录
tradeCallbackRecordService.saveCallbackRecord();
return "success";
} else {
// 保存记录
tradeCallbackRecordService.saveCallbackRecord();
return "fail";
}
}
/**
* 解析支付回调数据并放到上下文中
*/
@SneakyThrows
public boolean resolve(HttpServletRequest request) {
Map<String, String> callbackParam = PayUtil.toMap(request);
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
// 设置类型和通道
callbackInfo.setCallbackType(TradeTypeEnum.PAY)
.setChannel(ChannelEnum.UNION_PAY.getCode())
.setCallbackData(callbackParam);
// 签名校验
UnionPayKit unionPayKit = unionPayConfigService.initPayKit();
boolean verify = unionPayKit.signVerify(callbackParam, callbackParam.get(SDKConstants.param_signature));
if (!verify){
callbackInfo.setCallbackStatus(CallbackStatusEnum.FAIL);
return false;
}
// 网关支付号
callbackInfo.setOutTradeNo(callbackParam.get(UnionPayCode.QUERY_ID));
// 支付号
callbackInfo.setTradeNo(callbackParam.get(UnionPayCode.ORDER_ID));
// 支付结果
String resultCode = callbackParam.get(UnionPayCode.RESP_CODE);
PayStatusEnum payStatus = UnionPayCode.RESP_SUCCESS.equals(resultCode) ? PayStatusEnum.SUCCESS : PayStatusEnum.FAIL;
// 支付状态
callbackInfo.setTradeStatus(payStatus.getCode());
// 支付金额
String amount = callbackParam.get(UnionPayCode.TXN_AMT);
callbackInfo.setAmount(PayUtil.conversionAmount(Integer.parseInt(amount)));
String timeEnd = callbackParam.get(UnionPayCode.TXN_TIME);
if (StrUtil.isNotBlank(timeEnd)) {
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
callbackInfo.setFinishTime(time);
} else {
callbackInfo.setFinishTime(LocalDateTime.now());
}
return true;
}
}

View File

@@ -0,0 +1,98 @@
package org.dromara.daxpay.channel.union.service.callback;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.channel.union.code.UnionPayCode;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.sdk.bean.SDKConstants;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.core.enums.CallbackStatusEnum;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.core.enums.RefundStatusEnum;
import org.dromara.daxpay.core.enums.TradeTypeEnum;
import org.dromara.daxpay.core.util.PayUtil;
import org.dromara.daxpay.service.common.context.CallbackLocal;
import org.dromara.daxpay.service.common.local.PaymentContextLocal;
import org.dromara.daxpay.service.service.record.callback.TradeCallbackRecordService;
import org.dromara.daxpay.service.service.trade.refund.RefundCallbackService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 云闪付退款回调
* @author xxm
* @since 2024/10/9
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UnionRefundCallbackService {
private final RefundCallbackService refundCallbackService;
private final TradeCallbackRecordService tradeCallbackRecordService;
private final UnionPayConfigService unionPayConfigService;
/**
* 退款回调处理
*/
public String refundHandle(HttpServletRequest request){
// 解析数据
if (this.resolve(request)){
// 执行回调业务处理
refundCallbackService.refundCallback();
// 保存记录
tradeCallbackRecordService.saveCallbackRecord();
return "success";
} else {
// 保存记录
tradeCallbackRecordService.saveCallbackRecord();
return "fail";
}
}
@SneakyThrows
public boolean resolve(HttpServletRequest request) {
Map<String, String> callbackParam = PayUtil.toMap(request);
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
// 设置类型和通道
callbackInfo.setCallbackType(TradeTypeEnum.REFUND)
.setChannel(ChannelEnum.UNION_PAY.getCode())
.setCallbackData(callbackParam);
// 签名校验
UnionPayKit unionPayKit = unionPayConfigService.initPayKit();
boolean verify = unionPayKit.signVerify(callbackParam, callbackParam.get(SDKConstants.param_signature));
if (!verify){
callbackInfo.setCallbackStatus(CallbackStatusEnum.FAIL);
return false;
}
// 网关退款号
callbackInfo.setOutTradeNo(callbackParam.get(UnionPayCode.QUERY_ID));
// 退款订单号
callbackInfo.setTradeNo(callbackParam.get(UnionPayCode.ORDER_ID));
// 退款金额
String amount = callbackParam.get(UnionPayCode.TXN_AMT);
callbackInfo.setAmount(PayUtil.conversionAmount(Integer.parseInt(amount)));
// 交易状态
String resultCode = callbackParam.get(UnionPayCode.RESP_CODE);
RefundStatusEnum refundStatus = UnionPayCode.RESP_SUCCESS.equals(resultCode) ? RefundStatusEnum.SUCCESS : RefundStatusEnum.FAIL;
callbackInfo.setTradeStatus(refundStatus.getCode());
// 退款时间
String timeEnd = callbackParam.get(UnionPayCode.TXN_TIME);
if (StrUtil.isNotBlank(timeEnd)) {
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
callbackInfo.setFinishTime(time);
} else {
callbackInfo.setFinishTime(LocalDateTime.now());
}
return true;
}
}

View File

@@ -115,14 +115,6 @@ public class UnionPayConfigService {
return UnionPayConfig.convertConfig(channelConfig);
}
/**
* 获取异步通知地址
*/
public String getNotifyUrl() {
var mchAppInfo = PaymentContextLocal.get().getMchAppInfo();
var platformInfo = platformConfigService.getConfig();
return StrUtil.format("{}/unipay/callback/{}/{}/union",platformInfo.getGatewayServiceUrl(),mchAppInfo.getAppId());
}
/**
* 获取支付异步通知地址
@@ -130,7 +122,7 @@ public class UnionPayConfigService {
public String getPayNotifyUrl() {
MchAppLocal mchAppInfo = PaymentContextLocal.get().getMchAppInfo();
var platformInfo = platformConfigService.getConfig();
return StrUtil.format("{}/unipay/callback/{}/{}/wechat/pay",platformInfo.getGatewayServiceUrl(),mchAppInfo.getAppId());
return StrUtil.format("{}/unipay/callback/{}/union/pay",platformInfo.getGatewayServiceUrl(),mchAppInfo.getAppId());
}
/**
@@ -139,7 +131,7 @@ public class UnionPayConfigService {
public String getRefundNotifyUrl() {
MchAppLocal mchAppInfo = PaymentContextLocal.get().getMchAppInfo();
var platformInfo = platformConfigService.getConfig();
return StrUtil.format("{}/unipay/callback/{}/{}/wechat/refund",platformInfo.getGatewayServiceUrl(), mchAppInfo.getAppId());
return StrUtil.format("{}/unipay/callback/{}/union/refund",platformInfo.getGatewayServiceUrl(), mchAppInfo.getAppId());
}
/**