mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-04 19:49:07 +00:00
ref 支付上下文优化, 时间戳与java8时间转换, 支付退款移植, 支付流程优化
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package cn.bootx.platform.daxpay;
|
||||
package cn.bootx.platform.daxpay.admin;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
@@ -13,5 +13,5 @@ import org.springframework.context.annotation.ComponentScan;
|
||||
@ConfigurationPropertiesScan
|
||||
@MapperScan(annotationClass = Mapper.class)
|
||||
@ComponentScan
|
||||
public class DaxPaySingleGatewayApp {
|
||||
public class DaxPaySingleAdminApp {
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package cn.bootx.platform.daxpay.openapi.controller.channel;
|
||||
package cn.bootx.platform.daxpay.admin.controller.channel;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
*/
|
||||
@Tag(name = "支付宝配置")
|
||||
@RestController
|
||||
@RequestMapping("/alipay")
|
||||
@RequestMapping("/alipay/config")
|
||||
@AllArgsConstructor
|
||||
public class AlipayConfigController {
|
||||
|
||||
@@ -35,16 +35,16 @@ public class AlipayConfigController {
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "根据Id查询")
|
||||
@GetMapping("/findById")
|
||||
public ResResult<AlipayConfigDto> findById() {
|
||||
@Operation(summary = "获取配置")
|
||||
@GetMapping("/getConfig")
|
||||
public ResResult<AlipayConfigDto> getConfig() {
|
||||
return Res.ok(alipayConfigService.getConfig().toDto());
|
||||
}
|
||||
|
||||
@Operation(summary = "支付宝支持支付方式")
|
||||
@GetMapping("/findPayWayList")
|
||||
public ResResult<List<LabelValue>> findPayWayList() {
|
||||
return Res.ok(alipayConfigService.findPayWayList());
|
||||
@GetMapping("/findPayWays")
|
||||
public ResResult<List<LabelValue>> findPayWays() {
|
||||
return Res.ok(alipayConfigService.findPayWays());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
@@ -0,0 +1,60 @@
|
||||
package cn.bootx.platform.daxpay.admin.controller.channel;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
import cn.bootx.platform.common.core.rest.dto.LabelValue;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.dto.channel.alipay.AlipayConfigDto;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wechat.WeChatPayConfigDto;
|
||||
import cn.bootx.platform.daxpay.param.channel.wechat.WeChatPayConfigParam;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2021/3/19
|
||||
*/
|
||||
@Tag(name = "微信支付配置")
|
||||
@RestController
|
||||
@RequestMapping("/wechat/pay/config")
|
||||
@AllArgsConstructor
|
||||
public class WeChatPayConfigController {
|
||||
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
@Operation(summary = "更新")
|
||||
@PostMapping("/update")
|
||||
public ResResult<Void> update(@RequestBody WeChatPayConfigParam param) {
|
||||
weChatPayConfigService.update(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "获取配置")
|
||||
@GetMapping("/getConfig")
|
||||
public ResResult<WeChatPayConfigDto> getConfig() {
|
||||
return Res.ok(weChatPayConfigService.getConfig().toDto());
|
||||
}
|
||||
|
||||
@Operation(summary = "微信支持支付方式")
|
||||
@GetMapping("/findPayWays")
|
||||
public ResResult<List<LabelValue>> findPayWays() {
|
||||
return Res.ok(weChatPayConfigService.findPayWays());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Operation(summary = "将文件转换成base64")
|
||||
@PostMapping("/toBase64")
|
||||
public ResResult<String> toBase64(MultipartFile file){
|
||||
return Res.ok(Base64.encode(file.getBytes()));
|
||||
}
|
||||
}
|
@@ -1 +1 @@
|
||||
cn.bootx.platform.daxpay.DaxPaySingleGatewayApp
|
||||
cn.bootx.platform.daxpay.DaxPaySingleAdminApp
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package cn.bootx.platform.daxpay;
|
||||
package cn.bootx.platform.daxpay.gateway;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
@@ -1,4 +1,4 @@
|
||||
package cn.bootx.platform.daxpay.openapi.controller;
|
||||
package cn.bootx.platform.daxpay.gateway.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.service.AliPayCallbackService;
|
@@ -1,8 +1,9 @@
|
||||
package cn.bootx.platform.daxpay.openapi.controller;
|
||||
package cn.bootx.platform.daxpay.gateway.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.daxpay.annotation.PaymentApi;
|
||||
import cn.bootx.platform.daxpay.core.payment.pay.service.PayService;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.service.PayRefundService;
|
||||
import cn.bootx.platform.daxpay.param.pay.*;
|
||||
import cn.bootx.platform.daxpay.result.DaxResult;
|
||||
import cn.bootx.platform.daxpay.result.pay.PayResult;
|
||||
@@ -28,20 +29,20 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequiredArgsConstructor
|
||||
public class UniPayController {
|
||||
private final PayService payService;
|
||||
private final PayRefundService payRefundService;
|
||||
|
||||
@PaymentApi("pay")
|
||||
@Operation(summary = "统一下单")
|
||||
@PostMapping("/pay")
|
||||
public DaxResult<PayResult> pay(@RequestBody PayParam payParam){
|
||||
payService.pay(payParam);
|
||||
return DaxRes.ok();
|
||||
return DaxRes.ok(payService.pay(payParam));
|
||||
}
|
||||
|
||||
@PaymentApi("simplePay")
|
||||
@Operation(summary = "简单下单")
|
||||
@PostMapping("/simplePay")
|
||||
public DaxResult<PayResult> simplePay(){
|
||||
return DaxRes.ok();
|
||||
public DaxResult<PayResult> simplePay(@RequestBody SimplePayParam payParam){
|
||||
return DaxRes.ok(payService.simplePay(payParam));
|
||||
}
|
||||
|
||||
@PaymentApi("cancel")
|
||||
@@ -62,7 +63,7 @@ public class UniPayController {
|
||||
@Operation(summary = "统一退款")
|
||||
@PostMapping("/refund")
|
||||
public DaxResult<RefundResult> refund(@RequestBody RefundParam param){
|
||||
return DaxRes.ok();
|
||||
return DaxRes.ok(payRefundService.refund(param));
|
||||
}
|
||||
|
||||
@PaymentApi("simpleRefund")
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.common.context;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
@@ -8,7 +8,7 @@ import lombok.experimental.Accessors;
|
||||
* @author xxm
|
||||
* @since 2023/12/22
|
||||
*/
|
||||
@Data
|
||||
@Getter
|
||||
@Accessors(chain = true)
|
||||
public class PaymentContext {
|
||||
|
||||
@@ -27,4 +27,7 @@ public class PaymentContext {
|
||||
/** 消息通知相关信息 */
|
||||
private final NoticeLocal noticeInfo = new NoticeLocal();
|
||||
|
||||
/** 支付请求相关信息 */
|
||||
private final RequestLocal request = new RequestLocal();
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,34 @@
|
||||
package cn.bootx.platform.daxpay.common.context;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 支付请求相关信息
|
||||
* @author xxm
|
||||
* @since 2023/12/25
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class RequestLocal {
|
||||
|
||||
/** 客户端ip */
|
||||
private String clientIp;
|
||||
|
||||
/** 商户扩展参数,回调时会原样返回 */
|
||||
private String extraParam;
|
||||
|
||||
/** 签名 */
|
||||
private String sign;
|
||||
|
||||
/** API版本号 */
|
||||
private String version;
|
||||
|
||||
/** 请求时间,时间戳转时间 */
|
||||
private LocalDateTime reqTime;
|
||||
|
||||
/** 请求链路id */
|
||||
private String reqId;
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package cn.bootx.platform.daxpay.core.order.pay.entity;
|
||||
package cn.bootx.platform.daxpay.common.entity;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import lombok.Data;
|
||||
@@ -11,7 +11,7 @@ import lombok.experimental.Accessors;
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayOrderRefundableInfo {
|
||||
public class OrderRefundableInfo {
|
||||
/**
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
@@ -38,10 +38,17 @@ public class CallbackNotify extends MpCreateEntity {
|
||||
private String notifyInfo;
|
||||
|
||||
/**
|
||||
* 处理状态
|
||||
* 支付状态
|
||||
* @see PayStatusEnum
|
||||
*/
|
||||
@DbComment("处理状态")
|
||||
@DbComment("支付状态")
|
||||
private String payStatus;
|
||||
|
||||
/**
|
||||
* 回调处理状态
|
||||
* @see
|
||||
*/
|
||||
@DbComment("回调处理状态")
|
||||
private String status;
|
||||
|
||||
/** 提示信息 */
|
||||
|
@@ -6,7 +6,6 @@ import cn.bootx.platform.daxpay.code.AliPayCode;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.core.callback.dao.CallbackNotifyManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.dao.AlipayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.entity.AlipayConfig;
|
||||
import cn.bootx.platform.daxpay.core.payment.callback.service.PayCallbackService;
|
||||
import cn.bootx.platform.daxpay.func.AbsPayCallbackStrategy;
|
||||
@@ -33,12 +32,12 @@ import java.util.Objects;
|
||||
@Service
|
||||
public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
|
||||
private final AlipayConfigManager alipayConfigManager;
|
||||
private final AlipayConfigService aliasConfigService;
|
||||
|
||||
public AliPayCallbackService(RedisClient redisClient, CallbackNotifyManager callbackNotifyManager,
|
||||
PayCallbackService payCallbackService, AlipayConfigManager alipayConfigManager) {
|
||||
PayCallbackService payCallbackService, AlipayConfigService aliasConfigService) {
|
||||
super(redisClient, callbackNotifyManager, payCallbackService);
|
||||
this.alipayConfigManager = alipayConfigManager;
|
||||
this.aliasConfigService = aliasConfigService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +68,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
log.error("支付宝回调报文 appId 为空 {}", callReq);
|
||||
return false;
|
||||
}
|
||||
AlipayConfig alipayConfig = null;
|
||||
AlipayConfig alipayConfig = aliasConfigService.getConfig();
|
||||
if (Objects.isNull(alipayConfig)) {
|
||||
log.error("支付宝支付配置不存在: {}", callReq);
|
||||
return false;
|
||||
|
@@ -6,10 +6,11 @@ import cn.bootx.platform.daxpay.common.context.AsyncPayLocal;
|
||||
import cn.bootx.platform.daxpay.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.dao.AliPayOrderManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.entity.AliPayOrder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderChannelManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderChannel;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -17,7 +18,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -40,30 +40,43 @@ public class AliPayOrderService {
|
||||
|
||||
private final PayOrderManager payOrderManager;
|
||||
|
||||
private final PayOrderChannelManager payOrderChannelManager;
|
||||
|
||||
/**
|
||||
* 支付调起成功 更新payment中异步支付类型信息, 如果支付完成, 创建支付宝支付单
|
||||
*/
|
||||
public void updatePaySuccess(PayOrder payOrder, PayWayParam payWayParam) {
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();
|
||||
payOrder.setAsyncPayMode(true).setAsyncPayChannel(PayChannelEnum.ALI.getCode());
|
||||
payOrder.setAsyncPayMode(true)
|
||||
.setAsyncPayChannel(PayChannelEnum.ALI.getCode());
|
||||
|
||||
// 更新支付宝异步支付类型信息
|
||||
Optional<PayOrderChannel> payOrderChannelOpt = payOrderChannelManager.findByPaymentIdAndChannel(payOrder.getId(), PayChannelEnum.ALI.getCode());
|
||||
if (!payOrderChannelOpt.isPresent()){
|
||||
payOrderChannelManager.deleteByPaymentIdAndAsync(payOrder.getId());
|
||||
payOrderChannelManager.save(new PayOrderChannel()
|
||||
.setPaymentId(payOrder.getId())
|
||||
.setChannel(PayChannelEnum.ALI.getCode())
|
||||
.setAmount(payWayParam.getAmount())
|
||||
.setPayWay(payWayParam.getWay())
|
||||
.setChannelExtra(payWayParam.getChannelExtra())
|
||||
.setAsync(true)
|
||||
);
|
||||
} else {
|
||||
payOrderChannelOpt.get()
|
||||
.setChannelExtra(payWayParam.getChannelExtra())
|
||||
.setPayWay(payWayParam.getWay());
|
||||
payOrderChannelManager.updateById(payOrderChannelOpt.get());
|
||||
}
|
||||
|
||||
|
||||
// TODO 支付
|
||||
List<PayOrderChannel> payChannelInfo = new ArrayList<>();
|
||||
List<PayOrderRefundableInfo> refundableInfos = new ArrayList<>();
|
||||
// 清除已有的异步支付类型信息
|
||||
payChannelInfo.removeIf(payTypeInfo -> PayChannelEnum.ASYNC_TYPE_CODE.contains(payTypeInfo.getChannel()));
|
||||
refundableInfos.removeIf(payTypeInfo -> PayChannelEnum.ASYNC_TYPE_CODE.contains(payTypeInfo.getChannel()));
|
||||
// 更新支付宝支付类型信息
|
||||
payChannelInfo.add(new PayOrderChannel().setChannel(PayChannelEnum.ALI.getCode())
|
||||
.setPayWay(payWayParam.getWay())
|
||||
.setAmount(payWayParam.getAmount())
|
||||
.setChannelExtra(payWayParam.getChannelExtra()));
|
||||
// TODO 更新支付关联信息
|
||||
// payOrder.setPayChannelInfo(payChannelInfo);
|
||||
// 更新支付宝可退款类型信息
|
||||
refundableInfos
|
||||
.add(new PayOrderRefundableInfo().setChannel(PayChannelEnum.ALI.getCode())
|
||||
.setAmount(payWayParam.getAmount()));
|
||||
List<OrderRefundableInfo> refundableInfos = payOrder.getRefundableInfos();
|
||||
refundableInfos.removeIf(payTypeInfo -> PayChannelEnum.ASYNC_TYPE_CODE.contains(payTypeInfo.getChannel()));
|
||||
refundableInfos.add(new OrderRefundableInfo()
|
||||
.setChannel(PayChannelEnum.ALI.getCode())
|
||||
.setAmount(payWayParam.getAmount())
|
||||
);
|
||||
payOrder.setRefundableInfos(refundableInfos);
|
||||
// 如果支付完成(付款码情况) 调用 updateSyncSuccess 创建支付宝支付记录
|
||||
if (Objects.equals(payOrder.getStatus(), PayStatusEnum.SUCCESS.getCode())) {
|
||||
@@ -91,7 +104,7 @@ public class AliPayOrderService {
|
||||
.setAmount(payWayParam.getAmount())
|
||||
.setRefundableBalance(payWayParam.getAmount())
|
||||
.setBusinessNo(payOrder.getBusinessNo())
|
||||
.setStatus(PayStatusEnum.PROGRESS.getCode())
|
||||
.setStatus(PayStatusEnum.SUCCESS.getCode())
|
||||
.setPayTime(LocalDateTime.now());
|
||||
aliPayOrderManager.save(aliPayOrder);
|
||||
}
|
||||
@@ -102,7 +115,7 @@ public class AliPayOrderService {
|
||||
public void updateClose(Long paymentId) {
|
||||
Optional<AliPayOrder> aliPaymentOptional = aliPayOrderManager.findByPaymentId(paymentId);
|
||||
aliPaymentOptional.ifPresent(aliPayOrder -> {
|
||||
aliPayOrder.setStatus(PayStatusEnum.CANCEL.getCode());
|
||||
aliPayOrder.setStatus(PayStatusEnum.CLOSE.getCode());
|
||||
aliPayOrderManager.updateById(aliPayOrder);
|
||||
});
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AlipayConfigService {
|
||||
/** 默认支付包配置的主键ID */
|
||||
/** 默认支付宝配置的主键ID */
|
||||
private final static Long ID = 0L;
|
||||
private final AlipayConfigManager alipayConfigManager;
|
||||
|
||||
@@ -50,7 +50,7 @@ public class AlipayConfigService {
|
||||
/**
|
||||
* 支付宝支持支付方式
|
||||
*/
|
||||
public List<LabelValue> findPayWayList() {
|
||||
public List<LabelValue> findPayWays() {
|
||||
return AliPayWay.getPayWays()
|
||||
.stream()
|
||||
.map(e -> new LabelValue(e.getName(),e.getCode()))
|
||||
|
@@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -192,7 +191,7 @@ public class VoucherPayService {
|
||||
* 部分退款, 会退到指定的一张卡上, 如果不指定, 则自动退到有效期最久的卡上
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void refund(Long paymentId, BigDecimal amount) {
|
||||
public void refund(Long paymentId, Integer amount) {
|
||||
VoucherPayment voucherPayment = voucherPaymentManager.findByPaymentId(paymentId)
|
||||
.orElseThrow(() -> new PayFailureException("储值卡支付记录不存在"));
|
||||
// 全部退款还是部分退款
|
||||
|
@@ -5,7 +5,6 @@ import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.core.callback.dao.CallbackNotifyManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.dao.WeChatPayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.payment.callback.service.PayCallbackService;
|
||||
import cn.bootx.platform.daxpay.func.AbsPayCallbackStrategy;
|
||||
@@ -18,6 +17,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.bootx.platform.daxpay.code.WeChatPayCode.APPID;
|
||||
|
||||
@@ -31,13 +31,12 @@ import static cn.bootx.platform.daxpay.code.WeChatPayCode.APPID;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
|
||||
private final WeChatPayConfigManager weChatPayConfigManager;
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
public WeChatPayCallbackService(RedisClient redisClient, CallbackNotifyManager callbackNotifyManager,
|
||||
PayCallbackService payCallbackService, WeChatPayConfigManager weChatPayConfigManager) {
|
||||
PayCallbackService payCallbackService, WeChatPayConfigService weChatPayConfigService) {
|
||||
super(redisClient, callbackNotifyManager, payCallbackService);
|
||||
this.weChatPayConfigManager = weChatPayConfigManager;
|
||||
this.weChatPayConfigService = weChatPayConfigService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,8 +83,8 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
return false;
|
||||
}
|
||||
|
||||
WeChatPayConfig weChatPayConfig = null;
|
||||
if (weChatPayConfig == null) {
|
||||
WeChatPayConfig weChatPayConfig = weChatPayConfigService.getConfig();
|
||||
if (Objects.isNull(weChatPayConfig)) {
|
||||
log.warn("微信支付配置不存在: {}", callReq);
|
||||
return false;
|
||||
}
|
||||
|
@@ -1,32 +1,23 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.common.spring.exception.RetryableException;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.common.context.AsyncRefundLocal;
|
||||
import cn.bootx.platform.daxpay.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.model.CloseOrderModel;
|
||||
import com.ijpay.wxpay.model.RefundModel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -59,45 +50,6 @@ public class WeChatPayCloseService {
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
public void refund(PayOrder payOrder, BigDecimal amount,
|
||||
WeChatPayConfig weChatPayConfig) {
|
||||
PayOrderRefundableInfo refundableInfo = payOrder.getRefundableInfos().stream()
|
||||
.filter(o -> Objects.equals(o.getChannel(), PayChannelEnum.WECHAT.getCode()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new PayFailureException("未找到微信支付的详细信息"));
|
||||
String refundFee = amount.multiply(BigDecimal.valueOf(100)).toBigInteger().toString();
|
||||
String totalFee = refundableInfo.getAmount().toString();
|
||||
// 设置退款信息
|
||||
AsyncRefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
refundInfo.setRefundNo(IdUtil.getSnowflakeNextIdStr());
|
||||
Map<String, String> params = RefundModel.builder()
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.out_trade_no(String.valueOf(payOrder.getId()))
|
||||
.out_refund_no(refundInfo.getRefundNo())
|
||||
.total_fee(totalFee)
|
||||
.refund_fee(refundFee)
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.build()
|
||||
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
|
||||
// 获取证书文件
|
||||
if (StrUtil.isBlank(weChatPayConfig.getP12())){
|
||||
String errorMsg = "微信p.12证书未配置,无法进行退款";
|
||||
refundInfo.setErrorMsg(errorMsg);
|
||||
refundInfo.setErrorCode(PayRefundStatusEnum.SUCCESS.getCode());
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
byte[] fileBytes = Base64.decode(weChatPayConfig.getP12());
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
|
||||
// 证书密码为 微信商户号
|
||||
String xmlResult = WxPayApi.orderRefund(false, params, inputStream, weChatPayConfig.getWxMchId());
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证错误信息
|
||||
*/
|
||||
@@ -109,7 +61,7 @@ public class WeChatPayCloseService {
|
||||
if (StrUtil.isBlank(errorMsg)) {
|
||||
errorMsg = result.get(WeChatPayCode.RETURN_MSG);
|
||||
}
|
||||
log.error("订单退款/关闭失败 {}", errorMsg);
|
||||
log.error("订单关闭失败 {}", errorMsg);
|
||||
AsyncRefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
refundInfo.setErrorMsg(errorMsg);
|
||||
refundInfo.setErrorCode(Optional.ofNullable(resultCode).orElse(returnCode));
|
||||
|
@@ -1,14 +1,10 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.dto.LabelValue;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.code.WeChatPayWay;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.dao.WeChatPayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wechat.WeChatPayConfigDto;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.channel.wechat.WeChatPayConfigParam;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
@@ -31,49 +27,35 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPayConfigService {
|
||||
|
||||
/** 默认微信支付配置的主键ID */
|
||||
private final static Long ID = 0L;
|
||||
private final WeChatPayConfigManager weChatPayConfigManager;
|
||||
|
||||
/**
|
||||
* 添加微信支付配置
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void add(WeChatPayConfigParam param) {
|
||||
|
||||
WeChatPayConfig weChatPayConfig = WeChatPayConfig.init(param);
|
||||
weChatPayConfigManager.save(weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(WeChatPayConfigParam param) {
|
||||
WeChatPayConfig weChatPayConfig = weChatPayConfigManager.findById(param.getId())
|
||||
WeChatPayConfig weChatPayConfig = weChatPayConfigManager.findById(ID)
|
||||
.orElseThrow(() -> new PayFailureException("微信支付配置不存在"));
|
||||
param.setActivity(null);
|
||||
BeanUtil.copyProperties(param, weChatPayConfig, CopyOptions.create().ignoreNullValue());
|
||||
weChatPayConfigManager.updateById(weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public PageResult<WeChatPayConfigDto> page(PageParam pageParam, WeChatPayConfigParam param) {
|
||||
return MpUtil.convert2DtoPageResult(weChatPayConfigManager.page(pageParam, param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取
|
||||
* 获取支付配置
|
||||
*/
|
||||
public WeChatPayConfigDto findById(Long id) {
|
||||
return weChatPayConfigManager.findById(id).map(WeChatPayConfig::toDto).orElseThrow(DataNotExistException::new);
|
||||
public WeChatPayConfig getConfig(){
|
||||
return weChatPayConfigManager.findById(ID).orElseThrow(() -> new DataNotExistException("微信支付配置不存在"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 微信支持支付方式
|
||||
*/
|
||||
public List<LabelValue> findPayWayList() {
|
||||
public List<LabelValue> findPayWays() {
|
||||
return WeChatPayWay.getPayWays()
|
||||
.stream()
|
||||
.map(e -> new LabelValue(e.getName(),e.getCode()))
|
||||
|
@@ -10,7 +10,7 @@ import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayment;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderChannel;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -45,7 +45,7 @@ public class WeChatPayOrderService {
|
||||
payOrder.setAsyncPayMode(true).setAsyncPayChannel(PayChannelEnum.WECHAT.getCode());
|
||||
|
||||
List<PayOrderChannel> payTypeInfos = new ArrayList<>();
|
||||
List<PayOrderRefundableInfo> refundableInfos = new ArrayList<>();
|
||||
List<OrderRefundableInfo> refundableInfos = new ArrayList<>();
|
||||
// 清除已有的异步支付类型信息
|
||||
payTypeInfos.removeIf(payTypeInfo -> PayChannelEnum.ASYNC_TYPE_CODE.contains(payTypeInfo.getChannel()));
|
||||
refundableInfos.removeIf(payTypeInfo -> PayChannelEnum.ASYNC_TYPE_CODE.contains(payTypeInfo.getChannel()));
|
||||
@@ -57,7 +57,7 @@ public class WeChatPayOrderService {
|
||||
// TODO 更新支付方式列表
|
||||
// 更新微信可退款类型信息
|
||||
refundableInfos.add(
|
||||
new PayOrderRefundableInfo().setChannel(PayChannelEnum.WECHAT.getCode())
|
||||
new OrderRefundableInfo().setChannel(PayChannelEnum.WECHAT.getCode())
|
||||
.setAmount(payWayParam.getAmount()));
|
||||
payOrder.setRefundableInfos(refundableInfos);
|
||||
// 如果支付完成(付款码情况) 调用 updateSyncSuccess 创建微信支付记录
|
||||
|
@@ -78,9 +78,9 @@ public class WeChatPayService {
|
||||
/**
|
||||
* 支付
|
||||
*/
|
||||
public void pay(int amount, PayOrder payOrder, WeChatPayParam weChatPayParam, PayWayParam payWayParam,
|
||||
WeChatPayConfig weChatPayConfig) {
|
||||
// 微信传入的是分, 将元转换为分
|
||||
public void pay(PayOrder payOrder, WeChatPayParam weChatPayParam, PayWayParam payWayParam, WeChatPayConfig weChatPayConfig) {
|
||||
|
||||
Integer amount = payWayParam.getAmount();
|
||||
String totalFee = String.valueOf(amount);
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();;
|
||||
String payBody = null;
|
||||
@@ -105,7 +105,7 @@ public class WeChatPayService {
|
||||
// 付款码支付
|
||||
else if (payWayEnum == PayWayEnum.BARCODE) {
|
||||
String tradeNo = this.barCode(totalFee, payOrder, weChatPayParam.getAuthCode(), weChatPayConfig);
|
||||
asyncPayInfo.setTradeNo(tradeNo).setExpiredTime(false);
|
||||
asyncPayInfo.setTradeNo(tradeNo);
|
||||
}
|
||||
asyncPayInfo.setPayBody(payBody);
|
||||
}
|
||||
@@ -232,6 +232,7 @@ public class WeChatPayService {
|
||||
* 构建参数
|
||||
*/
|
||||
private UnifiedOrderModelBuilder buildParams(String amount, PayOrder payment, WeChatPayConfig weChatPayConfig, String tradeType) {
|
||||
|
||||
LocalDateTime expiredTime = PaymentContextLocal.get()
|
||||
.getAsyncPayInfo()
|
||||
.getExpiredTime();
|
||||
|
@@ -0,0 +1,96 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.common.context.AsyncRefundLocal;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.model.RefundModel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 微信退款服务
|
||||
* @author xxm
|
||||
* @since 2023/12/25
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WechatRefundService {
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
public void refund(PayOrder payOrder, int amount,
|
||||
WeChatPayConfig weChatPayConfig) {
|
||||
OrderRefundableInfo refundableInfo = payOrder.getRefundableInfos().stream()
|
||||
.filter(o -> Objects.equals(o.getChannel(), PayChannelEnum.WECHAT.getCode()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new PayFailureException("未找到微信支付的详细信息"));
|
||||
String refundFee = String.valueOf(amount);
|
||||
String totalFee = refundableInfo.getAmount().toString();
|
||||
// 设置退款信息
|
||||
AsyncRefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
refundInfo.setRefundNo(IdUtil.getSnowflakeNextIdStr());
|
||||
Map<String, String> params = RefundModel.builder()
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.out_trade_no(String.valueOf(payOrder.getId()))
|
||||
.out_refund_no(refundInfo.getRefundNo())
|
||||
.total_fee(totalFee)
|
||||
.refund_fee(refundFee)
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.build()
|
||||
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
|
||||
// 获取证书文件
|
||||
if (StrUtil.isBlank(weChatPayConfig.getP12())){
|
||||
String errorMsg = "微信p.12证书未配置,无法进行退款";
|
||||
refundInfo.setErrorMsg(errorMsg);
|
||||
refundInfo.setErrorCode(PayRefundStatusEnum.SUCCESS.getCode());
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
byte[] fileBytes = Base64.decode(weChatPayConfig.getP12());
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
|
||||
// 证书密码为 微信商户号
|
||||
String xmlResult = WxPayApi.orderRefund(false, params, inputStream, weChatPayConfig.getWxMchId());
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证错误信息
|
||||
*/
|
||||
private void verifyErrorMsg(Map<String, String> result) {
|
||||
String returnCode = result.get(WeChatPayCode.RETURN_CODE);
|
||||
String resultCode = result.get(WeChatPayCode.RESULT_CODE);
|
||||
if (!WxPayKit.codeIsOk(returnCode) || !WxPayKit.codeIsOk(resultCode)) {
|
||||
String errorMsg = result.get(WeChatPayCode.ERR_CODE_DES);
|
||||
if (StrUtil.isBlank(errorMsg)) {
|
||||
errorMsg = result.get(WeChatPayCode.RETURN_MSG);
|
||||
}
|
||||
log.error("订单退款失败 {}", errorMsg);
|
||||
AsyncRefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
refundInfo.setErrorMsg(errorMsg);
|
||||
refundInfo.setErrorCode(Optional.ofNullable(resultCode).orElse(returnCode));
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -3,11 +3,13 @@ package cn.bootx.platform.daxpay.core.order.pay.builder;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.common.context.AsyncPayLocal;
|
||||
import cn.bootx.platform.daxpay.common.context.NoticeLocal;
|
||||
import cn.bootx.platform.daxpay.common.context.PlatformLocal;
|
||||
import cn.bootx.platform.daxpay.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderChannel;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderExtra;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.PayResult;
|
||||
@@ -35,7 +37,7 @@ public class PaymentBuilder {
|
||||
*/
|
||||
public PayOrder buildPayOrder(PayParam payParam) {
|
||||
// 可退款信息
|
||||
List<PayOrderRefundableInfo> refundableInfos = buildRefundableInfo(payParam.getPayWays());
|
||||
List<OrderRefundableInfo> refundableInfos = buildRefundableInfo(payParam.getPayWays());
|
||||
// 计算总价
|
||||
int sumAmount = payParam.getPayWays().stream()
|
||||
.map(PayWayParam::getAmount)
|
||||
@@ -66,16 +68,15 @@ public class PaymentBuilder {
|
||||
* @param paymentId 支付订单id
|
||||
*/
|
||||
public PayOrderExtra buildPayOrderExtra(PayParam payParam, Long paymentId) {
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
NoticeLocal noticeInfo = PaymentContextLocal.get().getNoticeInfo();
|
||||
PayOrderExtra payOrderExtra = new PayOrderExtra()
|
||||
.setClientIp(payParam.getClientIp())
|
||||
.setDescription(payParam.getDescription())
|
||||
.setNotReturn(payParam.isNotReturn())
|
||||
.setReturnUrl(payParam.getReturnUrl())
|
||||
.setNotNotify(payParam.isNotNotify())
|
||||
.setNotifyUrl(payParam.getNotifyUrl())
|
||||
.setNotifyUrl(noticeInfo.getNotifyUrl())
|
||||
.setSign(payParam.getSign())
|
||||
.setSignType(payParam.getSignType())
|
||||
.setSignType(payParam.getSign())
|
||||
.setSignType(platform.getSignType())
|
||||
.setApiVersion(payParam.getVersion())
|
||||
.setReqTime(payParam.getReqTime());
|
||||
payOrderExtra.setId(paymentId);
|
||||
@@ -101,12 +102,12 @@ public class PaymentBuilder {
|
||||
/**
|
||||
* 构建支付订单的可退款信息列表
|
||||
*/
|
||||
private List<PayOrderRefundableInfo> buildRefundableInfo(List<PayWayParam> payWayParamList) {
|
||||
private List<OrderRefundableInfo> buildRefundableInfo(List<PayWayParam> payWayParamList) {
|
||||
if (CollectionUtil.isEmpty(payWayParamList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return payWayParamList.stream()
|
||||
.map(o-> new PayOrderRefundableInfo()
|
||||
.map(o-> new OrderRefundableInfo()
|
||||
.setChannel(o.getChannel())
|
||||
.setAmount(o.getAmount()))
|
||||
.collect(Collectors.toList());
|
||||
@@ -120,11 +121,11 @@ public class PaymentBuilder {
|
||||
*/
|
||||
public PayResult buildPayResultByPayOrder(PayOrder payOrder) {
|
||||
PayResult paymentResult;
|
||||
paymentResult = new PayResult()
|
||||
.setPaymentId(payOrder.getId())
|
||||
.setAsyncPayMode(payOrder.isAsyncPayMode())
|
||||
.setAsyncPayChannel(payOrder.getAsyncPayChannel())
|
||||
.setStatus(payOrder.getStatus());
|
||||
paymentResult = new PayResult();
|
||||
paymentResult.setPaymentId(payOrder.getId());
|
||||
paymentResult.setAsyncPayMode(payOrder.isAsyncPayMode());
|
||||
paymentResult.setAsyncPayChannel(payOrder.getAsyncPayChannel());
|
||||
paymentResult.setStatus(payOrder.getStatus());
|
||||
|
||||
// 设置异步支付参数
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();;
|
||||
|
@@ -20,10 +20,21 @@ public class PayOrderChannelManager extends BaseManager<PayOrderChannelMapper,
|
||||
/**
|
||||
* 根据订单id和支付渠道查询
|
||||
*/
|
||||
public Optional<PayOrderChannel> findByOderIdAndChannel(Long paymentId, String channel) {
|
||||
public Optional<PayOrderChannel> findByPaymentIdAndChannel(Long paymentId, String channel) {
|
||||
return lambdaQuery()
|
||||
.eq(PayOrderChannel::getPaymentId,paymentId)
|
||||
.eq(PayOrderChannel::getChannel,channel)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据订单id删除异步支付记录
|
||||
*/
|
||||
public void deleteByPaymentIdAndAsync(Long paymentId){
|
||||
lambdaUpdate()
|
||||
.eq(PayOrderChannel::getPaymentId,paymentId)
|
||||
.eq(PayOrderChannel::isAsync,true)
|
||||
.remove();
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.handler.JacksonRawTypeHandler;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
|
||||
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
|
||||
@@ -64,13 +65,13 @@ public class PayOrder extends MpBaseEntity {
|
||||
|
||||
/**
|
||||
* 退款信息列表
|
||||
* @see PayOrderRefundableInfo
|
||||
* @see OrderRefundableInfo
|
||||
*/
|
||||
@TableField(typeHandler = JacksonRawTypeHandler.class)
|
||||
@BigField
|
||||
@DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT)
|
||||
@DbColumn(comment = "退款信息列表")
|
||||
private List<PayOrderRefundableInfo> refundableInfos;
|
||||
private List<OrderRefundableInfo> refundableInfos;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.core.order.pay.entity;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpDelEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
|
||||
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.VoucherPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
|
||||
@@ -22,7 +22,7 @@ import lombok.experimental.Accessors;
|
||||
@Accessors(chain = true)
|
||||
@DbTable(comment = "支付订单关联支付时通道信息")
|
||||
@TableName("pay_order_channel")
|
||||
public class PayOrderChannel extends MpDelEntity {
|
||||
public class PayOrderChannel extends MpCreateEntity {
|
||||
|
||||
@DbColumn(comment = "支付id")
|
||||
private Long paymentId;
|
||||
@@ -33,6 +33,9 @@ public class PayOrderChannel extends MpDelEntity {
|
||||
@DbColumn(comment = "支付方式")
|
||||
private String payWay;
|
||||
|
||||
@DbColumn(comment = "异步支付方式")
|
||||
private boolean async;
|
||||
|
||||
@DbColumn(comment = "金额")
|
||||
private Integer amount;
|
||||
|
||||
|
@@ -3,6 +3,8 @@ package cn.bootx.platform.daxpay.core.order.pay.entity;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -21,27 +23,21 @@ import java.time.LocalDateTime;
|
||||
@TableName("pay_order_extra")
|
||||
public class PayOrderExtra extends MpBaseEntity {
|
||||
|
||||
/** 支付终端ip */
|
||||
@DbColumn(comment = "支付终端ip")
|
||||
private String clientIp;
|
||||
|
||||
/** 描述 */
|
||||
@DbColumn(comment = "描述")
|
||||
private String description;
|
||||
|
||||
@DbColumn(comment = "是否不进行同步通知的跳转")
|
||||
private boolean notReturn;
|
||||
|
||||
/** 同步通知URL */
|
||||
@DbColumn(comment = "同步通知URL")
|
||||
private String returnUrl;
|
||||
/** 支付终端ip */
|
||||
@DbColumn(comment = "支付终端ip")
|
||||
private String clientIp;
|
||||
|
||||
/** 是否不启用异步通知 */
|
||||
@DbColumn(comment = "是否不启用异步通知")
|
||||
@DbColumn(comment = "是否不启用异步通知,以最后一次为准")
|
||||
private boolean notNotify;
|
||||
|
||||
/** 异步通知地址 */
|
||||
@DbColumn(comment = "异步通知地址")
|
||||
@DbColumn(comment = "异步通知地址,以最后一次为准")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String notifyUrl;
|
||||
|
||||
/** 签名类型 */
|
||||
@@ -49,15 +45,15 @@ public class PayOrderExtra extends MpBaseEntity {
|
||||
private String signType;
|
||||
|
||||
/** 签名 */
|
||||
@DbColumn(comment = "签名")
|
||||
@DbColumn(comment = "签名,以最后一次为准")
|
||||
private String sign;
|
||||
|
||||
/** API版本号 */
|
||||
@DbColumn(comment = "API版本号")
|
||||
private String apiVersion;
|
||||
|
||||
/** 请求时间,时间戳转时间 */
|
||||
@DbColumn(comment = "请求时间,传输时间戳")
|
||||
/** 请求时间,时间戳转时间, 以最后一次为准 */
|
||||
@DbColumn(comment = "请求时间,传输时间戳,以最后一次为准")
|
||||
private LocalDateTime reqTime;
|
||||
|
||||
/** 错误码 */
|
||||
|
@@ -10,7 +10,7 @@ import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderExtraManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderChannel;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -86,8 +86,8 @@ public class PayOrderService {
|
||||
*/
|
||||
public void updateRefundSuccess(PayOrder payment, int amount, PayChannelEnum payChannelEnum) {
|
||||
// 删除旧有的退款记录, 替换退款完的新的
|
||||
List<PayOrderRefundableInfo> refundableInfos = payment.getRefundableInfos();
|
||||
PayOrderRefundableInfo refundableInfo = refundableInfos.stream()
|
||||
List<OrderRefundableInfo> refundableInfos = payment.getRefundableInfos();
|
||||
OrderRefundableInfo refundableInfo = refundableInfos.stream()
|
||||
.filter(o -> Objects.equals(o.getChannel(), payChannelEnum.getCode()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new PayFailureException("退款数据不存在"));
|
||||
|
@@ -0,0 +1,19 @@
|
||||
package cn.bootx.platform.daxpay.core.order.refund.convert;
|
||||
|
||||
import cn.bootx.platform.daxpay.core.order.refund.entity.PayRefundOrder;
|
||||
import cn.bootx.platform.daxpay.dto.order.refund.PayRefundOrderDto;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2022/3/2
|
||||
*/
|
||||
@Mapper
|
||||
public interface RefundConvert {
|
||||
|
||||
RefundConvert CONVERT = Mappers.getMapper(RefundConvert.class);
|
||||
|
||||
PayRefundOrderDto convert(PayRefundOrder in);
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package cn.bootx.platform.daxpay.core.order.refund.dao;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.core.order.refund.entity.PayRefundOrder;
|
||||
import cn.bootx.platform.daxpay.dto.order.refund.PayRefundOrderDto;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2022/3/2
|
||||
*/
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class PayRefundOrderManager extends BaseManager<PayRefundOrderMapper, PayRefundOrder> {
|
||||
|
||||
public Page<PayRefundOrder> page(PageParam pageParam, PayRefundOrderDto param) {
|
||||
Page<PayRefundOrder> mpPage = MpUtil.getMpPage(pageParam, PayRefundOrder.class);
|
||||
return lambdaQuery().orderByDesc(MpIdEntity::getId)
|
||||
.like(Objects.nonNull(param.getPaymentId()), PayRefundOrder::getPaymentId, param.getPaymentId())
|
||||
.like(Objects.nonNull(param.getBusinessNo()), PayRefundOrder::getBusinessNo, param.getBusinessNo())
|
||||
.like(Objects.nonNull(param.getTitle()), PayRefundOrder::getTitle, param.getTitle())
|
||||
.page(mpPage);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package cn.bootx.platform.daxpay.core.order.refund.dao;
|
||||
|
||||
import cn.bootx.platform.daxpay.core.order.refund.entity.PayRefundOrder;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2022/3/2
|
||||
*/
|
||||
@Mapper
|
||||
public interface PayRefundOrderMapper extends BaseMapper<PayRefundOrder> {
|
||||
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
package cn.bootx.platform.daxpay.core.order.refund.entity;
|
||||
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.handler.JacksonRawTypeHandler;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import cn.bootx.platform.daxpay.core.order.refund.convert.RefundConvert;
|
||||
import cn.bootx.platform.daxpay.dto.order.refund.PayRefundOrderDto;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 退款记录
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/3/2
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName(value = "pay_refund_order", autoResultMap = true)
|
||||
public class PayRefundOrder extends MpBaseEntity implements EntityBaseFunction<PayRefundOrderDto> {
|
||||
|
||||
/** 支付单号 */
|
||||
private Long paymentId;
|
||||
|
||||
/** 关联的业务号 */
|
||||
private String businessNo;
|
||||
|
||||
/** 异步方式关联退款请求号(部分退款情况) */
|
||||
private String refundRequestNo;
|
||||
|
||||
/** 标题 */
|
||||
private String title;
|
||||
|
||||
/** 退款金额 */
|
||||
private Integer amount;
|
||||
|
||||
/** 剩余可退 */
|
||||
private Integer refundableBalance;
|
||||
|
||||
/** 退款终端ip */
|
||||
private String clientIp;
|
||||
|
||||
/** 退款时间 */
|
||||
private LocalDateTime refundTime;
|
||||
|
||||
/**
|
||||
* 退款信息列表
|
||||
*/
|
||||
@TableField(typeHandler = JacksonRawTypeHandler.class)
|
||||
private List<OrderRefundableInfo> refundableInfo;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @see PayStatus#REFUND_PROCESS_FAIL
|
||||
*/
|
||||
private String refundStatus;
|
||||
|
||||
/** 错误码 */
|
||||
private String errorCode;
|
||||
|
||||
/** 错误信息 */
|
||||
private String errorMsg;
|
||||
|
||||
@Override
|
||||
public PayRefundOrderDto toDto() {
|
||||
return RefundConvert.CONVERT.convert(this);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package cn.bootx.platform.daxpay.core.order.refund.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.core.order.refund.dao.PayRefundOrderManager;
|
||||
import cn.bootx.platform.daxpay.core.order.refund.entity.PayRefundOrder;
|
||||
import cn.bootx.platform.daxpay.dto.order.refund.PayRefundOrderDto;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/3/2
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayRefundRecordService {
|
||||
|
||||
private final PayRefundOrderManager refundRecordManager;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*/
|
||||
public PageResult<PayRefundOrderDto> page(PageParam pageParam, PayRefundOrderDto param) {
|
||||
Page<PayRefundOrder> page = refundRecordManager.page(pageParam, param);
|
||||
return MpUtil.convert2DtoPageResult(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id查询
|
||||
*/
|
||||
public PayRefundOrderDto findById(Long id) {
|
||||
return refundRecordManager.findById(id).map(PayRefundOrder::toDto).orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
}
|
@@ -18,7 +18,7 @@ public class PayCallbackResult {
|
||||
* 处理状态
|
||||
* @see PayStatusEnum
|
||||
*/
|
||||
private String code;
|
||||
private String status;
|
||||
|
||||
/** 提示信息 */
|
||||
private String msg;
|
||||
|
@@ -42,22 +42,22 @@ public class PayCallbackService {
|
||||
*/
|
||||
public PayCallbackResult callback(Long paymentId, String tradeStatus, Map<String, String> map) {
|
||||
|
||||
// 获取payment和paymentParam数据
|
||||
// 获取支付单
|
||||
PayOrder payOrder = payOrderService.findById(paymentId).orElse(null);
|
||||
|
||||
// 支付单不存在,记录回调记录
|
||||
if (Objects.isNull(payOrder)) {
|
||||
return new PayCallbackResult().setCode(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单不存在,记录回调记录");
|
||||
return new PayCallbackResult().setStatus(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单不存在,记录回调记录");
|
||||
}
|
||||
|
||||
// 回调时间超出了支付单超时时间, 记录一下, 不做处理
|
||||
// 回调时间超出了支付单超时时间, 记录一下, 不做处理 TODO 这块应该吧订单给正常处理了,
|
||||
if (Objects.nonNull(payOrder.getExpiredTime())
|
||||
&& LocalDateTimeUtil.ge(LocalDateTime.now(), payOrder.getExpiredTime())) {
|
||||
return new PayCallbackResult().setCode(PayNotifyStatusEnum.FAIL.getCode()).setMsg("回调时间超出了支付单支付有效时间");
|
||||
return new PayCallbackResult().setStatus(PayNotifyStatusEnum.FAIL.getCode()).setMsg("回调时间超出了支付单支付有效时间");
|
||||
}
|
||||
|
||||
// 成功状态
|
||||
if (Objects.equals(PayNotifyStatusEnum.SUCCESS, tradeStatus)) {
|
||||
if (Objects.equals(PayNotifyStatusEnum.SUCCESS.getCode(), tradeStatus)) {
|
||||
return this.success(payOrder, map);
|
||||
}
|
||||
else {
|
||||
@@ -70,16 +70,16 @@ public class PayCallbackService {
|
||||
* 成功处理
|
||||
*/
|
||||
private PayCallbackResult success(PayOrder payOrder, Map<String, String> map) {
|
||||
PayCallbackResult result = new PayCallbackResult().setCode(PayNotifyStatusEnum.SUCCESS.getCode());
|
||||
PayCallbackResult result = new PayCallbackResult().setStatus(PayNotifyStatusEnum.SUCCESS.getCode());
|
||||
|
||||
// payment已经被支付,不需要重复处理
|
||||
if (Objects.equals(payOrder.getStatus(), PayStatusEnum.SUCCESS.getCode())) {
|
||||
return result.setCode(PayNotifyStatusEnum.IGNORE.getCode()).setMsg("支付单已经是支付成功状态,不进行处理");
|
||||
return result.setStatus(PayNotifyStatusEnum.IGNORE.getCode()).setMsg("支付单已经是支付成功状态,不进行处理");
|
||||
}
|
||||
|
||||
// payment已被取消,记录回调记录
|
||||
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())) {
|
||||
return result.setCode(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单不是待支付状态,记录回调记录");
|
||||
return result.setStatus(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单不是待支付状态,记录回调记录");
|
||||
}
|
||||
|
||||
// 2.通过工厂生成对应的策略组
|
||||
@@ -87,7 +87,7 @@ public class PayCallbackService {
|
||||
|
||||
List<AbsPayStrategy> paymentStrategyList = PayStrategyFactory.create(payParam.getPayWays());
|
||||
if (CollectionUtil.isEmpty(paymentStrategyList)) {
|
||||
return result.setCode(PayStatusEnum.FAIL.getCode()).setMsg("支付单数据非法,未找到对应的支付方式");
|
||||
return result.setStatus(PayStatusEnum.FAIL.getCode()).setMsg("支付单数据非法,未找到对应的支付方式");
|
||||
}
|
||||
|
||||
// 3.初始化支付的参数
|
||||
@@ -110,7 +110,7 @@ public class PayCallbackService {
|
||||
// eventSender.sendPayComplete(PayEventBuilder.buildPayComplete(payOrder));
|
||||
}
|
||||
else {
|
||||
return result.setCode(PayStatusEnum.FAIL.getCode()).setMsg("回调处理过程报错");
|
||||
return result.setStatus(PayStatusEnum.FAIL.getCode()).setMsg("回调处理过程报错");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -119,23 +119,23 @@ public class PayCallbackService {
|
||||
* 失败处理, 关闭并退款 按说这块不会发生
|
||||
*/
|
||||
private PayCallbackResult fail(PayOrder payOrder, Map<String, String> map) {
|
||||
PayCallbackResult result = new PayCallbackResult().setCode(PayStatusEnum.SUCCESS.getCode());
|
||||
PayCallbackResult result = new PayCallbackResult().setStatus(PayStatusEnum.SUCCESS.getCode());
|
||||
|
||||
// payment已被取消,记录回调记录,后期处理
|
||||
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())) {
|
||||
return result.setCode(PayNotifyStatusEnum.IGNORE.getCode()).setMsg("支付单已经取消,记录回调记录");
|
||||
return result.setStatus(PayNotifyStatusEnum.IGNORE.getCode()).setMsg("支付单已经取消,记录回调记录");
|
||||
}
|
||||
|
||||
// payment支付成功, 状态非法
|
||||
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.SUCCESS.getCode())) {
|
||||
return result.setCode(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单状态非法,支付网关状态为失败,但支付单状态为已完成");
|
||||
return result.setStatus(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单状态非法,支付网关状态为失败,但支付单状态为已完成");
|
||||
}
|
||||
|
||||
// 2.通过工厂生成对应的策略组
|
||||
PayParam payParam = null;
|
||||
List<AbsPayStrategy> paymentStrategyList = PayStrategyFactory.create(payParam.getPayWays());
|
||||
if (CollectionUtil.isEmpty(paymentStrategyList)) {
|
||||
return result.setCode(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单数据非法,未找到对应的支付方式");
|
||||
return result.setStatus(PayNotifyStatusEnum.FAIL.getCode()).setMsg("支付单数据非法,未找到对应的支付方式");
|
||||
}
|
||||
// 3.初始化支付关闭的参数
|
||||
for (AbsPayStrategy paymentStrategy : paymentStrategyList) {
|
||||
@@ -156,7 +156,7 @@ public class PayCallbackService {
|
||||
// eventSender.sendPayRefund(PayEventBuilder.buildPayRefund(payOrder));
|
||||
}
|
||||
else {
|
||||
return result.setCode(PayNotifyStatusEnum.FAIL.getCode()).setMsg("回调处理过程报错");
|
||||
return result.setStatus(PayNotifyStatusEnum.FAIL.getCode()).setMsg("回调处理过程报错");
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.common.aop;
|
||||
|
||||
import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.annotation.PaymentApi;
|
||||
import cn.bootx.platform.daxpay.core.payment.common.service.PaymentSignService;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
@@ -12,7 +13,7 @@ import org.aspectj.lang.annotation.Before;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 支付签名切面, 用于对支付参数进行签名
|
||||
* 支付签名切面, 用于对支付参数进行校验和签名
|
||||
* 执行顺序: 过滤器 -> 拦截器 -> 切面 -> 方法
|
||||
* @author xxm
|
||||
* @since 2023/12/24
|
||||
@@ -21,7 +22,7 @@ import org.springframework.stereotype.Component;
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PaymentSignAop {
|
||||
public class PaymentVerifySignAop {
|
||||
private final PaymentSignService paymentSignService;
|
||||
|
||||
@Before("@annotation(paymentApi)")
|
||||
@@ -32,6 +33,9 @@ public class PaymentSignAop {
|
||||
}
|
||||
Object param = args[0];
|
||||
if (param instanceof PayCommonParam){
|
||||
// 参数校验
|
||||
ValidationUtil.validateParam(param);
|
||||
// 验签
|
||||
paymentSignService.verifySign((PayCommonParam) param);
|
||||
} else {
|
||||
throw new PayFailureException("支付参数需要继承PayCommonParam");
|
@@ -2,9 +2,9 @@ package cn.bootx.platform.daxpay.core.payment.common.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PaySignTypeEnum;
|
||||
import cn.bootx.platform.daxpay.common.context.ApiInfoLocal;
|
||||
import cn.bootx.platform.daxpay.common.context.PlatformLocal;
|
||||
import cn.bootx.platform.daxpay.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.core.system.entity.PlatformConfig;
|
||||
import cn.bootx.platform.daxpay.core.system.service.PlatformConfigService;
|
||||
import cn.bootx.platform.daxpay.core.payment.pay.service.PayAssistService;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayCommonParam;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -28,13 +28,16 @@ public class PaymentSignService {
|
||||
|
||||
private static final String FIELD_SIGN = "sign";
|
||||
|
||||
private final PlatformConfigService platformConfigService;
|
||||
private final PayAssistService payAssistService;;
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
public void verifySign(PayCommonParam param) {
|
||||
// 先触发一下平台配置上下文的初始化
|
||||
payAssistService.initPlatform();
|
||||
ApiInfoLocal apiInfo = PaymentContextLocal.get().getApiInfo();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
|
||||
// 判断当前接口是否不需要签名
|
||||
if (!apiInfo.isReqSign()){
|
||||
@@ -42,20 +45,19 @@ public class PaymentSignService {
|
||||
}
|
||||
// 参数转换为Map对象
|
||||
Map<String, String> params = param.toMap();
|
||||
PlatformConfig config = platformConfigService.getConfig();
|
||||
String signType = config.getSignType();
|
||||
String signType = platform.getSignType();
|
||||
// 生成签名前先去除sign
|
||||
params.remove(FIELD_SIGN);
|
||||
String data = PayKit.createLinkString(params);
|
||||
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
|
||||
// 签名验证
|
||||
data += "&key=" + config.getSignSecret();
|
||||
String sha256 = PayKit.hmacSha256(data, config.getSignSecret());
|
||||
data += "&key=" + platform.getSignSecret();
|
||||
String sha256 = PayKit.hmacSha256(data, platform.getSignSecret());
|
||||
if (!Objects.equals(sha256, params.get(FIELD_SIGN))){
|
||||
throw new PayFailureException("签名验证未通过");
|
||||
}
|
||||
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
|
||||
data += "&key=" + config.getSignSecret();
|
||||
data += "&key=" + platform.getSignSecret();
|
||||
String md5 = PayKit.md5(data.toUpperCase());
|
||||
String sign = StrUtil.toString(params.get(FIELD_SIGN));
|
||||
// 签名验证
|
||||
|
@@ -1,16 +1,23 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.pay.service;
|
||||
|
||||
import cn.bootx.platform.common.core.code.CommonCode;
|
||||
import cn.bootx.platform.daxpay.common.context.AsyncPayLocal;
|
||||
import cn.bootx.platform.daxpay.common.context.NoticeLocal;
|
||||
import cn.bootx.platform.daxpay.common.context.PlatformLocal;
|
||||
import cn.bootx.platform.daxpay.common.context.RequestLocal;
|
||||
import cn.bootx.platform.daxpay.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.core.system.entity.PlatformConfig;
|
||||
import cn.bootx.platform.daxpay.core.system.service.PlatformConfigService;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.daxpay.util.PayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -23,6 +30,32 @@ import java.util.Objects;
|
||||
@RequiredArgsConstructor
|
||||
public class PayAssistService {
|
||||
private final PlatformConfigService platformConfigService;
|
||||
/**
|
||||
* 初始化平台配置上下文
|
||||
*/
|
||||
public void initPlatform(){
|
||||
PlatformConfig config = platformConfigService.getConfig();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
platform.setSignType(config.getSignType());
|
||||
platform.setSignSecret(config.getSignSecret());
|
||||
platform.setNotifyUrl(config.getNotifyUrl());
|
||||
platform.setOrderTimeout(config.getOrderTimeout());
|
||||
platform.setWebsiteUrl(config.getWebsiteUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化支付相关上下文
|
||||
*/
|
||||
public void initPayContext(PayOrder order, PayParam payParam){
|
||||
// 初始化支付订单超时时间
|
||||
this.initExpiredTime(order,payParam);
|
||||
// 初始化通知相关上下文
|
||||
this.initNotice(payParam);
|
||||
// 初始化请求相关上下文
|
||||
this.initRequest(payParam);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化支付订单超时时间
|
||||
* 1. 如果支付记录为空, 超时时间读取顺序 PayParam -> 平台设置
|
||||
@@ -34,6 +67,7 @@ public class PayAssistService {
|
||||
return;
|
||||
}
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
// 支付订单是非为空
|
||||
if (Objects.nonNull(order)){
|
||||
asyncPayInfo.setExpiredTime(order.getExpiredTime());
|
||||
@@ -44,7 +78,41 @@ public class PayAssistService {
|
||||
asyncPayInfo.setExpiredTime(payParam.getExpiredTime());
|
||||
return;
|
||||
}
|
||||
PlatformConfig config = platformConfigService.getConfig();
|
||||
PayUtil.getPaymentExpiredTime(config.getOrderTimeout());
|
||||
LocalDateTime paymentExpiredTime = PayUtil.getPaymentExpiredTime(platform.getOrderTimeout());
|
||||
asyncPayInfo.setExpiredTime(paymentExpiredTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化通知相关上下文
|
||||
*/
|
||||
private void initNotice(PayParam payParam){
|
||||
NoticeLocal noticeInfo = PaymentContextLocal.get().getNoticeInfo();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
// 异步回调
|
||||
if (!payParam.isNotNotify()){
|
||||
noticeInfo.setNotifyUrl(payParam.getReturnUrl());
|
||||
if (StrUtil.isNotBlank(payParam.getNotifyUrl())){
|
||||
noticeInfo.setNotifyUrl(platform.getNotifyUrl());
|
||||
}
|
||||
}
|
||||
// 同步回调
|
||||
if (!payParam.isNotReturn()){
|
||||
noticeInfo.setReturnUrl(payParam.getReturnUrl());
|
||||
}
|
||||
// 退出回调地址
|
||||
noticeInfo.setQuitUrl(payParam.getQuitUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化支付请求相关信息
|
||||
*/
|
||||
public void initRequest(PayParam payParam){
|
||||
RequestLocal request = PaymentContextLocal.get().getRequest();
|
||||
request.setClientIp(payParam.getClientIp())
|
||||
.setExtraParam(payParam.getExtraParam())
|
||||
.setSign(payParam.getSign())
|
||||
.setVersion(payParam.getVersion())
|
||||
.setReqTime(payParam.getReqTime())
|
||||
.setReqId(MDC.get(CommonCode.TRACE_ID));
|
||||
}
|
||||
}
|
||||
|
@@ -1,16 +1,16 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.pay.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.builder.PaymentBuilder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderChannelManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderExtraManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderChannel;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrderExtra;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.payment.pay.factory.PayStrategyFactory;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
|
||||
@@ -18,8 +18,11 @@ import cn.bootx.platform.daxpay.func.AbsPayStrategy;
|
||||
import cn.bootx.platform.daxpay.func.PayStrategyConsumer;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.SimplePayParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.PayResult;
|
||||
import cn.bootx.platform.daxpay.util.PayUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -43,7 +46,7 @@ import java.util.stream.Collectors;
|
||||
@RequiredArgsConstructor
|
||||
public class PayService {
|
||||
|
||||
private final PayOrderService payOrderService;
|
||||
private final PayOrderManager payOrderManager;
|
||||
|
||||
private final PayAssistService payAssistService;;
|
||||
|
||||
@@ -51,41 +54,57 @@ public class PayService {
|
||||
|
||||
private final PayOrderChannelManager payOrderChannelManager;
|
||||
|
||||
|
||||
/**
|
||||
* 支付方法(同步/异步/组合支付) 同步支付:都只会在第一次执行中就完成支付,例如钱包、积分都是调用完就进行了扣减,完成了支付记录
|
||||
* 异步支付:例如支付宝、微信,发起支付后还需要跳转第三方平台进行支付,支付后通常需要进行回调,之后才完成支付记录
|
||||
* 组合支付:主要是混合了同步支付和异步支付,同时异步支付只能有一个,在支付时先对同步支付进行扣减,然后异步支付回调结束后完成整个支付单
|
||||
* 组合支付在非第一次支付的时候,只对新传入的异步支付PayMode进行处理,PayMode的价格使用第一次发起的价格,旧的同步支付如果传入后也不做处理,
|
||||
* Payment中PayModeList将会为 旧有的同步支付+新传入的异步支付方式(在具体支付实现中处理)
|
||||
* 支付下单接口(同步/异步/组合支付)
|
||||
* 1. 同步支付:都只会在第一次执行中就完成支付,例如钱包、储值卡都是调用完就进行了扣减,完成了支付记录
|
||||
* 2. 异步支付:例如支付宝、微信,发起支付后还需要跳转第三方平台进行支付,支付后通常需要进行回调,之后才完成支付记录
|
||||
* 3. 组合支付:主要是混合了同步支付和异步支付,同时异步支付只能有一个,在支付时先对同步支付进行扣减,然后异步支付回调结束后完成整个支付单
|
||||
* 注意:
|
||||
* 组合支付在非第一次支付的时候,只对新传入的异步支付通道进行处理,该通道的价格使用第一次发起的价格,旧的同步支付如果传入后也不做处理,
|
||||
* 支付单中支付通道列表将会为 旧有的同步支付+新传入的异步支付方式(在具体支付实现中处理)
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public PayResult pay(PayParam payParam) {
|
||||
// 检验参数
|
||||
ValidationUtil.validateParam(payParam);
|
||||
|
||||
// 异步支付方式检查
|
||||
PayUtil.validationAsyncPayMode(payParam);
|
||||
|
||||
// 获取并校验支付状态
|
||||
PayOrder payOrder = this.getAndCheckByBusinessId(payParam.getBusinessNo());
|
||||
// 获取并校验支付订单状态
|
||||
PayOrder payOrder = this.getAndCheckByBusinessNo(payParam.getBusinessNo());
|
||||
|
||||
// 初始化上下文
|
||||
payAssistService.initExpiredTime(payOrder, payParam);
|
||||
payAssistService.initPayContext(payOrder, payParam);
|
||||
|
||||
// 异步支付且非第一次支付
|
||||
if (Objects.nonNull(payOrder) && payOrder.isAsyncPayMode()) {
|
||||
return this.paySyncNotFirst(payParam, payOrder);
|
||||
} else {
|
||||
// 第一次发起支付或同步支付
|
||||
return this.payFirst(payParam, payOrder);
|
||||
return this.firstPay(payParam, payOrder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单下单, 可以视为不支持组合支付的下单接口
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public PayResult simplePay(SimplePayParam simplePayParam) {
|
||||
// 组装支付参数
|
||||
PayParam payParam = new PayParam();
|
||||
PayWayParam payWayParam = new PayWayParam();
|
||||
payWayParam.setChannel(simplePayParam.getPayChannel());
|
||||
payWayParam.setWay(simplePayParam.getPayWay());
|
||||
payWayParam.setAmount(simplePayParam.getAmount());
|
||||
payWayParam.setChannelExtra(simplePayParam.getChannelExtra());
|
||||
BeanUtil.copyProperties(simplePayParam,payWayParam, CopyOptions.create().ignoreNullValue());
|
||||
payParam.setPayWays(Collections.singletonList(payWayParam));
|
||||
// 复用支付下单接口
|
||||
return this.pay(payParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起的第一次支付请求(同步/异步)
|
||||
*/
|
||||
private PayResult payFirst(PayParam payParam, PayOrder payOrder) {
|
||||
private PayResult firstPay(PayParam payParam, PayOrder payOrder) {
|
||||
// 1. 已经发起过支付情况直接返回支付结果
|
||||
if (Objects.nonNull(payOrder)) {
|
||||
return PaymentBuilder.buildPayResultByPayOrder(payOrder);
|
||||
@@ -98,18 +117,16 @@ public class PayService {
|
||||
payOrder = this.createPayOrder(payParam);
|
||||
|
||||
// 4. 调用支付方法进行发起支付
|
||||
this.payFirstMethod(payParam, payOrder);
|
||||
this.firstPayHandler(payParam, payOrder);
|
||||
|
||||
// 5. 返回支付结果
|
||||
return PaymentBuilder.buildPayResultByPayOrder(payOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行支付方法 (第一次支付)
|
||||
* @param payParam 支付参数
|
||||
* @param payOrder 支付订单
|
||||
* 执行第一次支付的方法
|
||||
*/
|
||||
private void payFirstMethod(PayParam payParam, PayOrder payOrder) {
|
||||
private void firstPayHandler(PayParam payParam, PayOrder payOrder) {
|
||||
|
||||
// 1.获取支付方式,通过工厂生成对应的策略组
|
||||
List<AbsPayStrategy> paymentStrategyList = PayStrategyFactory.create(payParam.getPayWays());
|
||||
@@ -135,7 +152,7 @@ public class PayService {
|
||||
payOrderObj.setStatus(PayStatusEnum.SUCCESS.getCode());
|
||||
payOrderObj.setPayTime(LocalDateTime.now());
|
||||
}
|
||||
payOrderService.updateById(payOrderObj);
|
||||
payOrderManager.updateById(payOrderObj);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -144,32 +161,35 @@ public class PayService {
|
||||
*/
|
||||
private PayResult paySyncNotFirst(PayParam payParam, PayOrder payOrder) {
|
||||
|
||||
// 0. 处理支付完成情况(完成/退款)
|
||||
List<String> trades = Arrays.asList(PayStatusEnum.SUCCESS.getCode(), PayStatusEnum.CANCEL.getCode(),
|
||||
// 1. 处理支付完成情况(完成/退款)
|
||||
List<String> trades = Arrays.asList(PayStatusEnum.SUCCESS.getCode(), PayStatusEnum.CANCEL.getCode(),PayStatusEnum.CLOSE.getCode(),
|
||||
PayStatusEnum.PARTIAL_REFUND.getCode(), PayStatusEnum.REFUNDED.getCode());
|
||||
if (trades.contains(payOrder.getStatus())) {
|
||||
return PaymentBuilder.buildPayResultByPayOrder(payOrder);
|
||||
}
|
||||
|
||||
// 1.获取 异步支付 通道道,通过工厂生成对应的策略组(只包含异步支付的策略, 同步支付不再进行执行)
|
||||
// 2.获取 异步支付通道,通过工厂生成对应的策略组(只包含异步支付的策略, 同步支付相关逻辑不再进行执行)
|
||||
PayWayParam payWayParam = this.getAsyncPayParam(payParam, payOrder);
|
||||
List<AbsPayStrategy> asyncStrategyList = PayStrategyFactory.create(Collections.singletonList(payWayParam));
|
||||
|
||||
// 2.初始化支付的参数
|
||||
// 3.初始化支付的参数
|
||||
for (AbsPayStrategy paymentStrategy : asyncStrategyList) {
|
||||
paymentStrategy.initPayParam(payOrder, payParam);
|
||||
}
|
||||
// 3.支付前准备
|
||||
// 4.支付前准备
|
||||
this.doHandler(payOrder, asyncStrategyList, AbsPayStrategy::doBeforePayHandler, null);
|
||||
|
||||
// 4. 发起支付
|
||||
// 5. 发起支付
|
||||
this.doHandler(payOrder, asyncStrategyList, AbsPayStrategy::doPayHandler, (strategyList, paymentObj) -> {
|
||||
// 发起支付成功进行的执行方法
|
||||
strategyList.forEach(AbsPayStrategy::doSuccessHandler);
|
||||
payOrderService.updateById(paymentObj);
|
||||
payOrderManager.updateById(paymentObj);
|
||||
});
|
||||
|
||||
// 5. 组装返回参数
|
||||
// 6. 更新支付订单扩展参数
|
||||
updatePayOrderExtra(payParam,payOrder.getId());
|
||||
|
||||
// 7. 组装返回参数
|
||||
return PaymentBuilder.buildPayResultByPayOrder(payOrder);
|
||||
}
|
||||
|
||||
@@ -196,7 +216,7 @@ public class PayService {
|
||||
private PayWayParam getAsyncPayParam(PayParam payParam, PayOrder payOrder) {
|
||||
// 查询之前的支付方式
|
||||
String asyncPayChannel = payOrder.getAsyncPayChannel();
|
||||
PayOrderChannel payOrderChannel = payOrderChannelManager.findByOderIdAndChannel(payOrder.getId(), asyncPayChannel)
|
||||
PayOrderChannel payOrderChannel = payOrderChannelManager.findByPaymentIdAndChannel(payOrder.getId(), asyncPayChannel)
|
||||
.orElseThrow(() -> new PayFailureException("支付方式数据异常"));
|
||||
|
||||
// 新的异步支付方式
|
||||
@@ -218,7 +238,7 @@ public class PayService {
|
||||
private PayOrder createPayOrder(PayParam payParam) {
|
||||
// 构建支付订单并保存
|
||||
PayOrder payOrder = PaymentBuilder.buildPayOrder(payParam);
|
||||
payOrderService.saveOder(payOrder);
|
||||
payOrderManager.save(payOrder);
|
||||
// 构建支付订单扩展表并保存
|
||||
PayOrderExtra payOrderExtra = PaymentBuilder.buildPayOrderExtra(payParam, payOrder.getId());
|
||||
payOrderExtraManager.save(payOrderExtra);
|
||||
@@ -231,12 +251,28 @@ public class PayService {
|
||||
return payOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新支付订单扩展参数
|
||||
* @param payParam 支付参数
|
||||
* @param paymentId 支付订单id
|
||||
*/
|
||||
private void updatePayOrderExtra(PayParam payParam,Long paymentId){
|
||||
PayOrderExtra payOrderExtra = payOrderExtraManager.findById(paymentId)
|
||||
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
|
||||
payOrderExtra.setReqTime(payParam.getReqTime())
|
||||
.setSign(payParam.getSign())
|
||||
.setNotNotify(payParam.isNotNotify())
|
||||
.setNotifyUrl(payParam.getNotifyUrl())
|
||||
.setClientIp(payParam.getClientIp());
|
||||
payOrderExtraManager.updateById(payOrderExtra);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验支付状态,支付成功则返回,支付失败则抛出对应的异常
|
||||
*/
|
||||
private PayOrder getAndCheckByBusinessId(String businessId) {
|
||||
private PayOrder getAndCheckByBusinessNo(String businessNo) {
|
||||
// 根据订单查询支付记录
|
||||
PayOrder payment = payOrderService.findByBusinessId(businessId).orElse(null);
|
||||
PayOrder payment = payOrderManager.findByBusinessNo(businessNo).orElse(null);
|
||||
if (Objects.nonNull(payment)) {
|
||||
// 支付失败类型状态
|
||||
List<String> tradesStatus = Arrays.asList(PayStatusEnum.FAIL.getCode(), PayStatusEnum.CANCEL.getCode(),
|
||||
|
@@ -93,8 +93,7 @@ public class WeChatPayStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doPayHandler() {
|
||||
weChatPayService.pay(this.getPayWayParam().getAmount(), this.getOrder(), this.weChatPayParam,
|
||||
this.getPayWayParam(), this.weChatPayConfig);
|
||||
weChatPayService.pay(this.getOrder(), this.weChatPayParam, this.getPayWayParam(), this.weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,114 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.factory;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.func.AbsPayRefundStrategy;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.strategy.*;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundChannelParam;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.bootx.platform.daxpay.code.PayChannelEnum.ASYNC_TYPE_CODE;
|
||||
|
||||
/**
|
||||
* 退款策略工厂
|
||||
* @author xxm
|
||||
* @since 2023/7/4
|
||||
*/
|
||||
public class PayRefundStrategyFactory {
|
||||
|
||||
/**
|
||||
* 根据传入的支付渠道创建策略
|
||||
* @return 支付策略
|
||||
*/
|
||||
public static AbsPayRefundStrategy create(RefundChannelParam refundChannelParam) {
|
||||
|
||||
AbsPayRefundStrategy strategy = null;
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(refundChannelParam.getPayChannel());
|
||||
switch (channelEnum) {
|
||||
case ALI:
|
||||
strategy = SpringUtil.getBean(AliPayRefundStrategy.class);
|
||||
break;
|
||||
case WECHAT:
|
||||
strategy = SpringUtil.getBean(WeChatPayRefundStrategy.class);
|
||||
break;
|
||||
case UNION_PAY:
|
||||
strategy = SpringUtil.getBean(UnionPayRefundStrategy.class);
|
||||
break;
|
||||
case CASH:
|
||||
strategy = SpringUtil.getBean(CashPayRefundStrategy.class);
|
||||
break;
|
||||
case WALLET:
|
||||
strategy = SpringUtil.getBean(WalletPayRefundStrategy.class);
|
||||
break;
|
||||
case VOUCHER:
|
||||
strategy = SpringUtil.getBean(VoucherPayRefundStrategy.class);
|
||||
break;
|
||||
default:
|
||||
throw new PayUnsupportedMethodException();
|
||||
}
|
||||
strategy.setChannelParam(refundChannelParam);
|
||||
return strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的支付类型批量创建策略, 异步支付在后面
|
||||
*/
|
||||
public static List<AbsPayRefundStrategy> createDesc(List<RefundChannelParam> refundChannelParams) {
|
||||
return create(refundChannelParams, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的支付类型批量创建策略, 默认异步支付在前面
|
||||
*/
|
||||
public static List<AbsPayRefundStrategy> create(List<RefundChannelParam> refundChannelParams) {
|
||||
return create(refundChannelParams, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的支付类型批量创建策略
|
||||
* @param refundChannelParams 支付类型
|
||||
* @return 支付策略
|
||||
*/
|
||||
private static List<AbsPayRefundStrategy> create(List<RefundChannelParam> refundChannelParams, boolean description) {
|
||||
if (CollectionUtil.isEmpty(refundChannelParams)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<AbsPayRefundStrategy> list = new ArrayList<>(refundChannelParams.size());
|
||||
|
||||
// 同步支付
|
||||
val syncRefundModeParams = refundChannelParams.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(payModeParam -> !ASYNC_TYPE_CODE.contains(payModeParam.getPayChannel()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 异步支付
|
||||
val asyncRefundModeParams = refundChannelParams.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(payModeParam -> ASYNC_TYPE_CODE.contains(payModeParam.getPayChannel()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<RefundChannelParam> sortList = new ArrayList<>(refundChannelParams.size());
|
||||
|
||||
// 异步在后面
|
||||
if (description) {
|
||||
sortList.addAll(syncRefundModeParams);
|
||||
sortList.addAll(asyncRefundModeParams);
|
||||
}
|
||||
else {
|
||||
sortList.addAll(asyncRefundModeParams);
|
||||
sortList.addAll(syncRefundModeParams);
|
||||
}
|
||||
|
||||
// 此处有一个根据Type的反转排序,
|
||||
sortList.stream().filter(Objects::nonNull).forEach(payMode -> list.add(create(payMode)));
|
||||
return list;
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.func;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.common.exception.ExceptionInfo;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 抽象支付退款策略基类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/12/11
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class AbsPayRefundStrategy {
|
||||
|
||||
/** 支付对象 */
|
||||
private PayOrder order = null;
|
||||
|
||||
/** 退款参数 */
|
||||
private RefundParam refundParam = null;
|
||||
|
||||
/** 当前支付通道退款参数 退款参数中的与这个不一致, 以这个为准 */
|
||||
private RefundChannelParam channelParam = null;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
public abstract PayChannelEnum getType();
|
||||
|
||||
/**
|
||||
* 初始化支付的参数
|
||||
*/
|
||||
public void initPayParam(PayOrder payOrder, RefundParam refundParam) {
|
||||
this.order = payOrder;
|
||||
this.refundParam = refundParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款前对处理 包含必要的校验以及对Payment对象的创建和保存操作
|
||||
*/
|
||||
public void doBeforeRefundHandler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款操作
|
||||
*/
|
||||
public abstract void doRefundHandler();
|
||||
|
||||
/**
|
||||
* 退款失败的处理方式
|
||||
*/
|
||||
public void doErrorHandler(ExceptionInfo exceptionInfo) {
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.func;
|
||||
|
||||
import cn.bootx.platform.daxpay.core.order.pay.entity.PayOrder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付退款策略接口
|
||||
* @author xxm
|
||||
* @since 2023/7/5
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PayRefundStrategyConsumer<T extends List<AbsPayRefundStrategy>, S extends PayOrder> {
|
||||
|
||||
void accept(T t, S s);
|
||||
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.RefundResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -13,4 +15,14 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayRefundService {
|
||||
|
||||
/**
|
||||
* 支付退款
|
||||
*/
|
||||
public RefundResult refund(RefundParam param){
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,62 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.entity.AlipayConfig;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.service.AliPayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.service.AliPayRefundService;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.service.AlipayConfigService;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 支付宝退款
|
||||
* @author xxm
|
||||
* @since 2023/7/4
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AliPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
|
||||
private final AlipayConfigService alipayConfigService;
|
||||
private final AliPayOrderService aliPayOrderService;
|
||||
private final AliPayRefundService aliRefundService;
|
||||
/**
|
||||
* 策略标识
|
||||
*
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.ALI;
|
||||
}
|
||||
|
||||
private final PayOrderService payOrderService;
|
||||
|
||||
|
||||
/**
|
||||
* 退款前前操作
|
||||
*/
|
||||
@Override
|
||||
public void doBeforeRefundHandler() {
|
||||
AlipayConfig config = alipayConfigService.getConfig();
|
||||
alipayConfigService.initConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
aliRefundService.refund(this.getOrder(), this.getChannelParam().getAmount());
|
||||
aliPayOrderService.updatePayRefund(this.getOrder().getId(), this.getChannelParam().getAmount());
|
||||
payOrderService.updateRefundSuccess(this.getOrder(), this.getChannelParam().getAmount(), PayChannelEnum.ALI);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.channel.cash.service.CashService;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 现金支付退款
|
||||
* @author xxm
|
||||
* @since 2023/7/5
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CashPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
|
||||
private final CashService cashService;
|
||||
private final PayOrderService paymentService;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
*
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.CASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
cashService.refund(this.getOrder().getId(), this.getChannelParam().getAmount());
|
||||
paymentService.updateRefundSuccess(this.getOrder(), this.getChannelParam().getAmount(), PayChannelEnum.CASH);
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 云闪付支付退款
|
||||
* @author xxm
|
||||
* @since 2023/7/5
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UnionPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
/**
|
||||
* 策略标识
|
||||
*
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.UNION_PAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.service.VoucherPayService;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.service.VoucherPaymentService;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 储值卡支付退款
|
||||
* @author xxm
|
||||
* @since 2023/7/5
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class VoucherPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
private final VoucherPayService voucherPayService;
|
||||
private final VoucherPaymentService voucherPaymentService;
|
||||
private final PayOrderService payOrderService;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
*
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.VOUCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款前对处理
|
||||
*/
|
||||
@Override
|
||||
public void doBeforeRefundHandler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
voucherPayService.refund(this.getOrder().getId(), this.getChannelParam().getAmount());
|
||||
voucherPaymentService.updateRefund(this.getOrder().getId(), this.getChannelParam().getAmount());
|
||||
payOrderService.updateRefundSuccess(this.getOrder(), this.getChannelParam().getAmount(), PayChannelEnum.VOUCHER);
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.service.WalletPayService;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.service.WalletPaymentService;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 钱包支付退款
|
||||
* @author xxm
|
||||
* @since 2023/7/5
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class WalletPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
private final WalletPayService walletPayService;
|
||||
private final WalletPaymentService walletPaymentService;
|
||||
private final PayOrderService payOrderService;
|
||||
/**
|
||||
* 策略标识
|
||||
*
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.WALLET;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
walletPayService.refund(this.getOrder().getId(), this.getChannelParam().getAmount());
|
||||
walletPaymentService.updateRefund(this.getOrder().getId(), this.getChannelParam().getAmount());
|
||||
payOrderService.updateRefundSuccess(this.getOrder(), this.getChannelParam().getAmount(), PayChannelEnum.WALLET);
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.service.WeChatPayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.service.WechatRefundService;
|
||||
import cn.bootx.platform.daxpay.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.core.payment.refund.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 微信支付退款
|
||||
* @author xxm
|
||||
* @since 2023/7/5
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
private final WechatRefundService wechatRefundService;
|
||||
private final WeChatPayOrderService weChatPayOrderService;
|
||||
private final PayOrderService payOrderService;
|
||||
|
||||
private WeChatPayConfig weChatPayConfig;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
*
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.WECHAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款前对处理, 初始化微信支付配置
|
||||
*/
|
||||
@Override
|
||||
public void doBeforeRefundHandler() {
|
||||
this.weChatPayConfig = weChatPayConfigService.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
wechatRefundService.refund(this.getOrder(), this.getChannelParam().getAmount(), this.weChatPayConfig);
|
||||
weChatPayOrderService.updatePayRefund(this.getOrder().getId(), this.getChannelParam().getAmount());
|
||||
payOrderService.updateRefundSuccess(this.getOrder(), this.getChannelParam().getAmount(), PayChannelEnum.WECHAT);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +1,8 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.sync.strategy;
|
||||
|
||||
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.dao.AlipayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.entity.AlipayConfig;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.service.AlipayConfigService;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.service.AlipaySyncService;
|
||||
import cn.bootx.platform.daxpay.core.payment.sync.func.AbsPaySyncStrategy;
|
||||
import cn.bootx.platform.daxpay.core.payment.sync.result.PaySyncResult;
|
||||
@@ -21,7 +22,7 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
|
||||
@RequiredArgsConstructor
|
||||
public class AliPaySyncStrategy extends AbsPaySyncStrategy {
|
||||
|
||||
private final AlipayConfigManager alipayConfigManager;
|
||||
private final AlipayConfigService alipayConfigService;
|
||||
|
||||
private final AlipaySyncService alipaySyncService;
|
||||
|
||||
@@ -39,5 +40,7 @@ public class AliPaySyncStrategy extends AbsPaySyncStrategy {
|
||||
*/
|
||||
private void initAlipayConfig() {
|
||||
// 检查并获取支付宝支付配置
|
||||
AlipayConfig config = alipayConfigService.getConfig();
|
||||
alipayConfigService.initConfig(config);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.dto.channel.alipay;
|
||||
|
||||
import cn.bootx.platform.daxpay.dto.pay.order.BasePayOrderDto;
|
||||
import cn.bootx.platform.daxpay.dto.order.pay.PayOrderDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -16,7 +16,7 @@ import java.io.Serializable;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "支付宝支付记录")
|
||||
public class AliPaymentDto extends BasePayOrderDto implements Serializable {
|
||||
public class AliPaymentDto extends PayOrderDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 6883103229754466130L;
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.dto.channel.voucher;
|
||||
|
||||
import cn.bootx.platform.daxpay.dto.pay.order.BasePayOrderDto;
|
||||
import cn.bootx.platform.daxpay.dto.order.pay.PayOrderDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -14,6 +14,6 @@ import lombok.experimental.Accessors;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "储值卡支付记录")
|
||||
public class VoucherPayOrderDto extends BasePayOrderDto {
|
||||
public class VoucherPayOrderDto extends PayOrderDto {
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.dto.channel.wallet;
|
||||
|
||||
import cn.bootx.platform.daxpay.dto.pay.order.BasePayOrderDto;
|
||||
import cn.bootx.platform.daxpay.dto.order.pay.PayOrderDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -16,7 +16,7 @@ import java.io.Serializable;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "钱包支付记录")
|
||||
public class WalletPayOrderDto extends BasePayOrderDto implements Serializable {
|
||||
public class WalletPayOrderDto extends PayOrderDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8238920331255597223L;
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.dto.channel.wechat;
|
||||
|
||||
import cn.bootx.platform.daxpay.dto.pay.order.BasePayOrderDto;
|
||||
import cn.bootx.platform.daxpay.dto.order.pay.PayOrderDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -16,7 +16,7 @@ import java.io.Serializable;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "微信支付记录")
|
||||
public class WeChatPayOrderDto extends BasePayOrderDto implements Serializable {
|
||||
public class WeChatPayOrderDto extends PayOrderDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2400358210732595795L;
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package cn.bootx.platform.daxpay.dto.pay.order;
|
||||
package cn.bootx.platform.daxpay.dto.order.pay;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
@@ -18,7 +18,7 @@ import java.time.LocalDateTime;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "具体支付日志基类")
|
||||
public class BasePayOrderDto extends BaseDto {
|
||||
public class PayOrderDto extends BaseDto {
|
||||
|
||||
@Schema(description = "支付id")
|
||||
private Long paymentId;
|
@@ -0,0 +1,65 @@
|
||||
package cn.bootx.platform.daxpay.dto.order.refund;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.common.entity.OrderRefundableInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 退款记录
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/3/2
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "退款记录")
|
||||
public class PayRefundOrderDto extends BaseDto {
|
||||
|
||||
@Schema(description = "关联的业务id")
|
||||
private String businessNo;
|
||||
|
||||
@Schema(description = "付款付单号")
|
||||
private Long paymentId;
|
||||
|
||||
@Schema(description = "异步方式关联退款请求号(部分退款情况)")
|
||||
private String refundRequestNo;
|
||||
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "退款金额")
|
||||
private BigDecimal amount;
|
||||
|
||||
@Schema(description = "剩余可退")
|
||||
private BigDecimal refundableBalance;
|
||||
|
||||
@Schema(description = "退款终端ip")
|
||||
private String clientIp;
|
||||
|
||||
@Schema(description = "退款时间")
|
||||
private LocalDateTime refundTime;
|
||||
|
||||
@Schema(description = "退款信息列表")
|
||||
private List<OrderRefundableInfo> refundableInfo;
|
||||
|
||||
/**
|
||||
* @see PayStatusCode#REFUND_PROCESS_FAIL
|
||||
*/
|
||||
@Schema(description = "退款状态")
|
||||
private String refundStatus;
|
||||
|
||||
@Schema(description = "错误码")
|
||||
private String errorCode;
|
||||
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMsg;
|
||||
|
||||
}
|
@@ -104,7 +104,7 @@ public abstract class AbsPayCallbackStrategy {
|
||||
.setNotifyTime(LocalDateTime.now())
|
||||
.setPaymentId(this.getPaymentId())
|
||||
.setPayChannel(this.getPayChannel().getCode())
|
||||
.setStatus(result.getCode())
|
||||
.setPayStatus(result.getStatus())
|
||||
.setMsg(result.getMsg());
|
||||
callbackNotifyManager.save(payNotifyRecord);
|
||||
}
|
||||
|
@@ -20,9 +20,6 @@ import java.util.List;
|
||||
@Schema(title = "微信支付配置参数")
|
||||
public class WeChatPayConfigParam {
|
||||
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
cn.bootx.platform.daxpay.DaxPaySingleGatewayApp
|
||||
cn.bootx.platform.daxpay.DaxpaySingleServiceApp
|
||||
|
@@ -9,6 +9,7 @@ import com.ijpay.core.kit.PayKit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -30,8 +31,9 @@ class PaymentSignServiceTest {
|
||||
payParam.setNotReturn(true);
|
||||
payParam.setNotifyUrl("http://127.0.0.1:8080/pay/notify");
|
||||
payParam.setReturnUrl("http://127.0.0.1:8080/pay/return");
|
||||
payParam.setSignType("MD5");
|
||||
payParam.setVersion("1.0");
|
||||
// 传入的话需要传输时间戳
|
||||
payParam.setReqTime(LocalDateTime.now());
|
||||
|
||||
PayWayParam p1 = new PayWayParam();
|
||||
p1.setAmount(100);
|
||||
|
@@ -1 +1 @@
|
||||
cn.bootx.platform.daxpay.DaxPaySingleGatewayApp
|
||||
cn.bootx.platform.daxpay.DaxPaySingleAdminApp
|
||||
|
Reference in New Issue
Block a user