mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-02 10:36:57 +00:00
feat 云闪付条码支付/APP支付
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
- [ ] 支付流程涉及异步支付时, 更换支付方式需要控制预防客户重复付款
|
||||
- [ ] 增加撤销功能,用于处理线下支付订单的情况
|
||||
- [ ] 数据库表进行规则, 字段设置长度, 增加索引
|
||||
- [ ] 回调处理可以配置延迟时间,
|
||||
|
||||
**任务池**
|
||||
- [x] 支付SDK编写
|
||||
|
@@ -3,10 +3,12 @@ package cn.bootx.platform.daxpay.gateway.controller;
|
||||
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.notice.service.PayReturnService;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.alipay.AliPayReturnParam;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.union.UnionPayReturnParam;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
@@ -38,8 +40,9 @@ public class PayReturnController {
|
||||
}
|
||||
|
||||
@Operation(summary = "云闪付同步通知")
|
||||
@GetMapping("/union")
|
||||
public ModelAndView union(){
|
||||
return null;
|
||||
@PostMapping("/union")
|
||||
public ModelAndView union(UnionPayReturnParam param){
|
||||
String url = payReturnService.union(param);
|
||||
return new ModelAndView("redirect:" + url);
|
||||
}
|
||||
}
|
||||
|
@@ -10,12 +10,15 @@ import com.egzosn.pay.union.bean.SDKConstants;
|
||||
public interface UnionPayCode {
|
||||
|
||||
|
||||
/** 成功状态 */
|
||||
String SUCCESS = "0";
|
||||
|
||||
/** 状态 00表示成功 */
|
||||
/** 应答码 00表示成功 */
|
||||
String RESP_CODE = SDKConstants.param_respCode;
|
||||
|
||||
/** 原交易应答码 00表示成功 */
|
||||
String RESP_ORIG_CODE = SDKConstants.param_origRespCode;
|
||||
|
||||
/** 应答码信息 */
|
||||
String RESP_MSG = SDKConstants.param_respMsg;
|
||||
|
||||
/** 业务结果 00表示成功 */
|
||||
String RESP_SUCCESS = SDKConstants.OK_RESP_CODE;
|
||||
|
||||
@@ -28,8 +31,8 @@ public interface UnionPayCode {
|
||||
/** 第三方订单号(本地订单号) */
|
||||
String ORDER_ID = "orderId";
|
||||
|
||||
/** 退款ID */
|
||||
String REFUND_ID = "refund_id";
|
||||
/** APP支付 银联订单号 */
|
||||
String PAY_APP_TN = SDKConstants.param_tn;
|
||||
|
||||
/** 交易类型 支付 */
|
||||
String TXN_TYPE_PAY = "01";
|
||||
|
@@ -110,7 +110,7 @@ public class UnionPayCallbackService extends AbsCallbackStrategy {
|
||||
@Override
|
||||
public void resolveRefundData() {
|
||||
// 云闪付需要延迟半秒再进行处理, 不然会出现业务未处理完, 但回调已经到达的情况
|
||||
ThreadUtil.sleep(300);
|
||||
ThreadUtil.sleep(100);
|
||||
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
|
||||
|
@@ -5,6 +5,7 @@ import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.channel.UnionPayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.service.code.AliPayWay;
|
||||
import cn.bootx.platform.daxpay.service.code.UnionPayCode;
|
||||
import cn.bootx.platform.daxpay.service.common.context.PayLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig;
|
||||
@@ -13,6 +14,8 @@ import cn.bootx.platform.daxpay.service.sdk.union.api.UnionPayKit;
|
||||
import cn.bootx.platform.daxpay.service.sdk.union.bean.UnionPayOrder;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.egzosn.pay.common.bean.NoticeParams;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -20,6 +23,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -89,8 +93,17 @@ public class UnionPayService {
|
||||
unionPayOrder.setPrice(amount);
|
||||
unionPayOrder.setExpirationTime(expiredTime);
|
||||
|
||||
Map<String, Object> app = unionPayKit.app(unionPayOrder);
|
||||
return null;
|
||||
Map<String, Object> result = unionPayKit.app(unionPayOrder);
|
||||
String resultCode = MapUtil.getStr(result, UnionPayCode.RESP_CODE);
|
||||
|
||||
// 支付失败
|
||||
if (!(Objects.equals(resultCode, UnionPayCode.RESP_SUCCESS))) {
|
||||
log.warn("云闪付支付失败:{}", result);
|
||||
String errMsg = MapUtil.getStr(result, UnionPayCode.RESP_MSG);
|
||||
throw new PayFailureException(errMsg);
|
||||
}
|
||||
|
||||
return MapUtil.getStr(result, UnionPayCode.PAY_APP_TN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,31 +113,11 @@ public class UnionPayService {
|
||||
Date expiredTime = DateUtil.date(payOrder.getExpiredTime());
|
||||
|
||||
UnionPayOrder unionPayOrder = new UnionPayOrder();
|
||||
|
||||
unionPayOrder.setOutTradeNo(String.valueOf(payOrder.getId()));
|
||||
unionPayOrder.setSubject(payOrder.getTitle());
|
||||
unionPayOrder.setPrice(amount);
|
||||
unionPayOrder.setExpirationTime(expiredTime);
|
||||
|
||||
return unionPayKit.getQrPay(unionPayOrder);
|
||||
|
||||
|
||||
// Map<String, String> params = UnifiedOrderModel.builder()
|
||||
// .service(ServiceEnum.NATIVE.toString())
|
||||
// .mch_id(unionPayKit.getMachId())
|
||||
// .out_trade_no(String.valueOf(payOrder.getId()))
|
||||
// .body(payOrder.getTitle())
|
||||
// .total_fee(amount)
|
||||
// .time_expire(PayUtil.getUnionExpiredTime(payOrder.getExpiredTime()))
|
||||
// .mch_create_ip("127.0.0.1")
|
||||
// .notify_url(unionPayKit.getNotifyUrl())
|
||||
// .nonce_str(WxPayKit.generateStr())
|
||||
// .build()
|
||||
// .createSign(unionPayKit.getAppKey(), SignType.MD5);
|
||||
// String xmlResult = UnionPayApi.execution(unionPayKit.getServerUrl(), params);
|
||||
// Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
// this.verifyErrorMsg(result);
|
||||
// return result.get("code_url");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,28 +127,26 @@ public class UnionPayService {
|
||||
Date expiredTime = DateUtil.date(payOrder.getExpiredTime());
|
||||
|
||||
UnionPayOrder unionPayOrder = new UnionPayOrder();
|
||||
|
||||
unionPayOrder.setAuthCode(authCode);
|
||||
unionPayOrder.setOutTradeNo(String.valueOf(payOrder.getId()));
|
||||
unionPayOrder.setSubject(payOrder.getTitle());
|
||||
unionPayOrder.setPrice(amount);
|
||||
unionPayOrder.setExpirationTime(expiredTime);
|
||||
Map<String, Object> stringObjectMap = unionPayKit.microPay(unionPayOrder);
|
||||
Map<String, Object> result = unionPayKit.microPay(unionPayOrder);
|
||||
|
||||
// Map<String, String> params = MicroPayModel.builder()
|
||||
// .service(ServiceEnum.MICRO_PAY.toString())
|
||||
// .mch_id(unionPayKit.getMachId())
|
||||
// .out_trade_no(WxPayKit.generateStr())
|
||||
// .body(payOrder.getTitle())
|
||||
// .total_fee(amount)
|
||||
// .op_device_id("daxpay")
|
||||
// .mch_create_ip("127.0.0.1")
|
||||
// .auth_code(authCode)
|
||||
// .nonce_str(WxPayKit.generateStr())
|
||||
// .build()
|
||||
// .createSign(unionPayKit.getAppKey(), SignType.MD5);
|
||||
//
|
||||
// String xmlResult = UnionPayApi.execution(unionPayKit.getServerUrl(), params);
|
||||
if (!unionPayKit.verify(new NoticeParams(result))) {
|
||||
log.warn("云闪付支付验签失败:{}", result);
|
||||
throw new PayFailureException("云闪付支付验签失败");
|
||||
}
|
||||
|
||||
String resultCode = MapUtil.getStr(result, UnionPayCode.RESP_CODE);
|
||||
|
||||
// 支付失败
|
||||
if (!(Objects.equals(resultCode, UnionPayCode.RESP_SUCCESS))) {
|
||||
log.warn("云闪付支付失败:{}", result);
|
||||
String errMsg = MapUtil.getStr(result, UnionPayCode.RESP_MSG);
|
||||
throw new PayFailureException(errMsg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -43,7 +43,6 @@ public class UnionPaySyncService {
|
||||
PayGatewaySyncResult syncResult = new PayGatewaySyncResult().setSyncStatus(PaySyncStatusEnum.FAIL);
|
||||
|
||||
AssistOrder query = new AssistOrder();
|
||||
// query.setOutTradeNo("1766811070348001280");
|
||||
query.setOutTradeNo(String.valueOf(order.getId()));
|
||||
|
||||
Map<String, Object> result = unionPayKit.query(query);
|
||||
@@ -87,6 +86,11 @@ public class UnionPaySyncService {
|
||||
return syncResult.setSyncStatus(PaySyncStatusEnum.PROGRESS);
|
||||
}
|
||||
|
||||
// 二维码支付无效
|
||||
if (Objects.equals(origRespCode, "86")) {
|
||||
return syncResult.setSyncStatus(PaySyncStatusEnum.CLOSED).setErrorMsg("支付二维码无效");
|
||||
}
|
||||
|
||||
return syncResult;
|
||||
}
|
||||
|
||||
|
@@ -65,7 +65,6 @@ public class RefundCallbackService {
|
||||
RefundRepairResult repair = reflectionService.repair(refundOrder, RefundRepairWayEnum.REFUND_SUCCESS);
|
||||
callbackInfo.setPayRepairNo(repair.getRepairNo());
|
||||
} else {
|
||||
// 设置退款订单完成时间
|
||||
RefundRepairResult repair = reflectionService.repair(refundOrder, RefundRepairWayEnum.REFUND_FAIL);
|
||||
callbackInfo.setPayRepairNo(repair.getRepairNo());
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
|
||||
import cn.bootx.platform.daxpay.service.core.system.config.service.PlatformConfigService;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.alipay.AliPayReturnParam;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.union.UnionPayReturnParam;
|
||||
import cn.hutool.core.net.URLEncodeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -51,4 +52,23 @@ public class PayReturnService {
|
||||
// 跳转到默认页
|
||||
return StrUtil.format("{}/result/success?msg={}", properties.getFrontH5Url(), URLEncodeUtil.encode("支付成功..."));
|
||||
}
|
||||
|
||||
public String union(UnionPayReturnParam param) {
|
||||
PayOrderExtra payOrderExtra = payOrderExtraManager.findById(param.getOrderNo()).orElse(null);
|
||||
PayOrder prOrder = payOrderQueryService.findById(Long.valueOf(param.getOrderNo())).orElse(null);
|
||||
if (Objects.isNull(payOrderExtra) || Objects.isNull(prOrder)){
|
||||
return StrUtil.format("{}/result/error?msg={}", properties.getFrontH5Url(), URLEncodeUtil.encode("支付订单有问题,请排查"));
|
||||
}
|
||||
|
||||
// 如果同步跳转参数为空, 获取系统配置地址, 系统配置如果也为空, 则返回默认地址
|
||||
String returnUrl = payOrderExtra.getReturnUrl();
|
||||
if (StrUtil.isBlank(returnUrl)){
|
||||
returnUrl = platformConfigService.getConfig().getReturnUrl();
|
||||
}
|
||||
if (StrUtil.isNotBlank(returnUrl)){
|
||||
return StrUtil.format("{}?paymentId={}&businessNo={}", payOrderExtra.getReturnUrl(),prOrder.getId(),prOrder.getBusinessNo());
|
||||
}
|
||||
// 跳转到默认页
|
||||
return StrUtil.format("{}/result/success?msg={}", properties.getFrontH5Url(), URLEncodeUtil.encode("支付成功..."));
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.refund.service;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.CountTime;
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
@@ -67,6 +68,7 @@ public class RefundService {
|
||||
/**
|
||||
* 支付退款
|
||||
*/
|
||||
@CountTime
|
||||
@Transactional(rollbackFor = Exception.class )
|
||||
public RefundResult refund(RefundParam param){
|
||||
return this.refundAdapter(param,false);
|
||||
@@ -75,6 +77,7 @@ public class RefundService {
|
||||
/**
|
||||
* 简单退款
|
||||
*/
|
||||
@CountTime
|
||||
@Transactional(rollbackFor = Exception.class )
|
||||
public RefundResult simpleRefund(SimpleRefundParam param){
|
||||
ValidationUtil.validateParam(param);
|
||||
@@ -273,7 +276,7 @@ public class RefundService {
|
||||
this.successHandler(refundOrder, refundChannelOrders, payOrder);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// 5. 失败处理, 所有记录都会回滚, 可以调用重新
|
||||
// 5. 失败处理, 所有记录都会回滚, 可以调用退款重试
|
||||
PaymentContextLocal.get().getRefundInfo().setStatus(RefundStatusEnum.FAIL);
|
||||
this.errorHandler(refundOrder);
|
||||
throw e;
|
||||
@@ -289,13 +292,10 @@ public class RefundService {
|
||||
int refundableBalance = refundOrder.getRefundableBalance();
|
||||
// 设置支付订单状态
|
||||
if (refundInfo.getStatus() == RefundStatusEnum.PROGRESS) {
|
||||
// 设置为退款中
|
||||
payOrder.setStatus(PayStatusEnum.REFUNDING.getCode());
|
||||
} else if (refundableBalance == 0) {
|
||||
// 退款完成
|
||||
payOrder.setStatus(PayStatusEnum.REFUNDED.getCode());
|
||||
} else {
|
||||
// 部分退款
|
||||
payOrder.setStatus(PayStatusEnum.PARTIAL_REFUND.getCode());
|
||||
}
|
||||
payOrderService.updateById(payOrder);
|
||||
|
@@ -74,7 +74,6 @@ public class PaySyncService {
|
||||
}
|
||||
// 如果不是异步支付, 直接返回返回
|
||||
if (!payOrder.isAsyncPay()){
|
||||
// return new SyncResult().setSuccess(false).setRepair(false).setErrorMsg("订单没有异步支付方式,不需要同步");
|
||||
throw new PayFailureException("订单没有异步支付方式,不需要同步");
|
||||
}
|
||||
// 执行订单同步逻辑
|
||||
|
@@ -6,13 +6,13 @@ import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 微信同步回调参数
|
||||
* 支付宝同步回调参数
|
||||
* @author xxm
|
||||
* @since 2024/2/11
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "微信同步回调参数")
|
||||
@Schema(title = "支付宝同步回调参数")
|
||||
public class AliPayReturnParam {
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,36 @@
|
||||
package cn.bootx.platform.daxpay.service.param.channel.union;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 云闪付同步回调参数
|
||||
* @author xxm
|
||||
* @since 2024/2/11
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "云闪付同步回调参数")
|
||||
public class UnionPayReturnParam {
|
||||
private String orderNo;
|
||||
private String signature;
|
||||
private String merName;
|
||||
private String settleDate;
|
||||
private String certId;
|
||||
private String voucherNum;
|
||||
private String version;
|
||||
private String settleKey;
|
||||
private String termId;
|
||||
private String origReqType;
|
||||
private String qrNo;
|
||||
private String reqReserved;
|
||||
private String reqType;
|
||||
private String origRespMsg;
|
||||
private String comInfo;
|
||||
private String merId;
|
||||
private String merCatCode;
|
||||
private String currencyCode;
|
||||
private String origRespCode;
|
||||
private String txnAmt;
|
||||
}
|
Reference in New Issue
Block a user