diff --git a/README.md b/README.md index 47ef4d1f7..f95ac8571 100644 --- a/README.md +++ b/README.md @@ -125,4 +125,4 @@ QQ扫码加入QQ交流群 ## 🍷License -Apache License Version 2.0_ +Apache License Version 2.0 diff --git a/_doc/Task.md b/_doc/Task.md new file mode 100644 index 000000000..8c01389fd --- /dev/null +++ b/_doc/Task.md @@ -0,0 +1,11 @@ +- 微信V3支付接口 +- x 拆分网关同步相关代码 +- x 记录网关同步记录 +- 重构支付消息通知结构 +- x 保存各通道的支付单 +- 钱包支持设置开通时的默认金额 +- 储值卡多卡支付和退款演示 +- x 储值卡信息调整 +- x 储值卡多卡退款到单卡, 不传卡号自动设置为默认卡 +- 储值卡批量导入 +- 储值卡支持多卡合一 diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PayController.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PayController.java index 2186b5df0..70fd402c9 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PayController.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PayController.java @@ -5,7 +5,7 @@ import cn.bootx.platform.common.core.rest.ResResult; import cn.bootx.platform.daxpay.core.pay.service.PayCancelService; import cn.bootx.platform.daxpay.core.refund.service.PayRefundService; import cn.bootx.platform.daxpay.core.pay.service.PayService; -import cn.bootx.platform.daxpay.core.pay.service.PaySyncService; +import cn.bootx.platform.daxpay.core.sync.service.PaySyncService; import cn.bootx.platform.daxpay.dto.pay.PayResult; import cn.bootx.platform.daxpay.param.pay.PayParam; import cn.bootx.platform.daxpay.param.refund.RefundParam; diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/RefundRecordController.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PayRefundRecordController.java similarity index 61% rename from dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/RefundRecordController.java rename to dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PayRefundRecordController.java index 8193f0791..a4a241b8f 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/RefundRecordController.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PayRefundRecordController.java @@ -4,8 +4,8 @@ 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.param.PageParam; -import cn.bootx.platform.daxpay.core.refund.record.service.RefundRecordService; -import cn.bootx.platform.daxpay.dto.refund.RefundRecordDto; +import cn.bootx.platform.daxpay.core.refund.record.service.PayRefundRecordService; +import cn.bootx.platform.daxpay.dto.refund.PayRefundRecordDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -23,20 +23,20 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/pay/refund") @RequiredArgsConstructor -public class RefundRecordController { +public class PayRefundRecordController { - private final RefundRecordService refundRecordService; + private final PayRefundRecordService payRefundRecordService; @Operation(summary = "分页") @GetMapping("/page") - public ResResult> page(PageParam pageParam, RefundRecordDto param) { - return Res.ok(refundRecordService.page(pageParam, param)); + public ResResult> page(PageParam pageParam, PayRefundRecordDto param) { + return Res.ok(payRefundRecordService.page(pageParam, param)); } @Operation(summary = "根据id查询") @GetMapping("/findById") - public ResResult findById(Long id) { - return Res.ok(refundRecordService.findById(id)); + public ResResult findById(Long id) { + return Res.ok(payRefundRecordService.findById(id)); } } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PaySyncRecordController.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PaySyncRecordController.java new file mode 100644 index 000000000..9593630ff --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/PaySyncRecordController.java @@ -0,0 +1,34 @@ +package cn.bootx.platform.daxpay.controller; + +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.param.PageParam; +import cn.bootx.platform.daxpay.core.sync.record.service.PaySyncRecordService; +import cn.bootx.platform.daxpay.dto.sync.PaySyncRecordDto; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "支付同步记录") +@RestController +@RequestMapping("/") +@RequiredArgsConstructor +public class PaySyncRecordController { + private final PaySyncRecordService syncRecordService; + + @Operation(summary = "分页") + @GetMapping("/page") + public ResResult> page(PageParam pageParam, PaySyncRecordDto param) { + return Res.ok(syncRecordService.page(pageParam, param)); + } + + @Operation(summary = "根据id查询") + @GetMapping("/findById") + public ResResult findById(Long id) { + return Res.ok(syncRecordService.findById(id)); + } +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/VoucherController.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/VoucherController.java index 34bd13e07..aeb652c7c 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/VoucherController.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/VoucherController.java @@ -8,12 +8,24 @@ import cn.bootx.platform.daxpay.core.channel.voucher.service.VoucherQueryService import cn.bootx.platform.daxpay.core.channel.voucher.service.VoucherService; import cn.bootx.platform.daxpay.dto.channel.voucher.VoucherDto; import cn.bootx.platform.daxpay.param.channel.voucher.VoucherGenerationParam; +import cn.bootx.platform.daxpay.param.channel.voucher.VoucherImportParam; import cn.bootx.platform.daxpay.param.channel.voucher.VoucherParam; +import cn.hutool.core.io.IoUtil; +import com.alibaba.excel.EasyExcel; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.io.InputStream; import java.util.List; /** @@ -89,4 +101,37 @@ public class VoucherController { return Res.ok(); } + @SneakyThrows + @Operation(summary = "导入已有的储值卡") + @PostMapping("/importBatch") + public ResResult importBatch(Boolean skip, MultipartFile file){ + List voucherImportParams = EasyExcel.read(file.getInputStream()) + // 设置与Excel表映射的类 + .head(VoucherImportParam.class) + // 设置sheet,默认读取第一个 + .sheet() + // 设置标题所在行数 + .headRowNumber(1) + // 异步读取 + .doReadSync(); + voucherService.importBatch(skip,voucherImportParams); + return Res.ok(); + } + + @SneakyThrows + @Operation(summary = "下载导入模板") + @GetMapping("/excelTemplate") + public ResponseEntity excelTemplate(){ + //设置header信息 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + headers.setContentDispositionFormData("attachment", + "ImportVoucher.xlsx"); + + ResourceLoader resourceLoader = new DefaultResourceLoader(); + InputStream inputStream = resourceLoader.getResource("classpath:templates//ImportVoucher.xlsx") + .getInputStream(); + + return new ResponseEntity<>(IoUtil.readBytes(inputStream),headers, HttpStatus.OK); + } } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AliPaymentService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AliPaymentService.java index 9892220e9..b9fc02088 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AliPaymentService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AliPaymentService.java @@ -3,11 +3,11 @@ package cn.bootx.platform.daxpay.core.channel.alipay.service; import cn.bootx.platform.common.core.util.BigDecimalUtil; import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; import cn.bootx.platform.daxpay.code.pay.PayStatusCode; +import cn.bootx.platform.daxpay.core.channel.alipay.dao.AliPaymentManager; +import cn.bootx.platform.daxpay.core.channel.alipay.entity.AliPayment; import cn.bootx.platform.daxpay.core.pay.local.AsyncPayInfoLocal; import cn.bootx.platform.daxpay.core.payment.dao.PaymentManager; import cn.bootx.platform.daxpay.core.payment.entity.Payment; -import cn.bootx.platform.daxpay.core.channel.alipay.dao.AliPaymentManager; -import cn.bootx.platform.daxpay.core.channel.alipay.entity.AliPayment; import cn.bootx.platform.daxpay.dto.pay.AsyncPayInfo; import cn.bootx.platform.daxpay.dto.payment.PayChannelInfo; import cn.bootx.platform.daxpay.dto.payment.RefundableInfo; @@ -25,6 +25,9 @@ import java.util.Optional; /** * 支付宝支付记录 + * 1.创建: 支付调起并支付成功后才会创建 + * 2.撤销: 关闭本地支付记录 + * 3.退款: 发起退款时记录 * * @author xxm * @since 2021/2/26 @@ -39,7 +42,7 @@ public class AliPaymentService { private final PaymentManager paymentManager; /** - * 支付调起成功 更新 payment 中 异步支付类型信息 + * 支付调起成功 更新payment中异步支付类型信息, 如果支付完成, 创建支付宝支付单 */ public void updatePaySuccess(Payment payment, PayWayParam payWayParam) { AsyncPayInfo asyncPayInfo = AsyncPayInfoLocal.get(); @@ -71,22 +74,22 @@ public class AliPaymentService { public void updateAsyncSuccess(Long id, PayWayParam payWayParam, String tradeNo) { // 更新支付记录 Payment payment = paymentManager.findById(id).orElseThrow(() -> new PayFailureException("支付记录不存在")); - + this.createAliPayment(payment,payWayParam,tradeNo); } /** - * 创建支付宝支付记录 + * 创建支付宝支付记录(支付调起成功后才会创建) */ private void createAliPayment(Payment payment, PayWayParam payWayParam, String tradeNo) { // 创建支付宝支付记录 AliPayment aliPayment = new AliPayment(); aliPayment.setTradeNo(tradeNo) - .setPaymentId(payment.getId()) - .setAmount(payWayParam.getAmount()) - .setRefundableBalance(payWayParam.getAmount()) - .setBusinessId(payment.getBusinessId()) - .setPayStatus(PayStatusCode.TRADE_SUCCESS) - .setPayTime(LocalDateTime.now()); + .setPaymentId(payment.getId()) + .setAmount(payWayParam.getAmount()) + .setRefundableBalance(payWayParam.getAmount()) + .setBusinessId(payment.getBusinessId()) + .setPayStatus(PayStatusCode.TRADE_SUCCESS) + .setPayTime(LocalDateTime.now()); aliPaymentManager.save(aliPayment); } @@ -118,5 +121,4 @@ public class AliPaymentService { aliPaymentManager.updateById(payment); }); } - } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AlipaySyncService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AlipaySyncService.java index 10170207c..25c469585 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AlipaySyncService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/alipay/service/AlipaySyncService.java @@ -2,8 +2,9 @@ package cn.bootx.platform.daxpay.core.channel.alipay.service; import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; import cn.bootx.platform.daxpay.code.paymodel.AliPayCode; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; import cn.bootx.platform.daxpay.core.payment.entity.Payment; +import cn.hutool.json.JSONUtil; import com.alipay.api.AlipayApiException; import com.alipay.api.domain.AlipayTradeQueryModel; import com.alipay.api.response.AlipayTradeQueryResponse; @@ -39,7 +40,7 @@ public class AlipaySyncService { // 查询退款参数 AlipayTradeQueryResponse response = AliPayApi.tradeQueryToResponse(queryModel); String tradeStatus = response.getTradeStatus(); - + paySyncResult.setJson(JSONUtil.toJsonStr(response)); // 支付完成 if (Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_SUCCESS) || Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_FINISHED)) { diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherPayService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherPayService.java index a56a1ffa2..38bc1adb6 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherPayService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherPayService.java @@ -164,7 +164,7 @@ public class VoucherPayService { } /** - * 直接支付 + * 直接支付 (同步支付方式下) */ @Transactional(rollbackFor = Exception.class) public List pay(BigDecimal amount, Payment payment, List vouchers) { @@ -272,9 +272,16 @@ public class VoucherPayService { .map(VoucherRecord::getCardNo) .collect(Collectors.toList()); List vouchers = voucherManager.findByCardNoList(cardNoList); + // 如果未传入卡号, 默认退到最抗用的一张卡上 + if (StrUtil.isBlank(refundVoucherNo)){ + List sort = this.sort(vouchers); + refundVoucherNo = sort.get(sort.size()-1).getCardNo(); + } + // 筛选出来要进行退款的卡 + String finalRefundVoucherNo = refundVoucherNo; Voucher voucher = vouchers.stream() - .filter(vr -> Objects.equals(vr.getCardNo(), refundVoucherNo)) + .filter(vr -> Objects.equals(vr.getCardNo(), finalRefundVoucherNo)) .findFirst() .orElseThrow(() -> new PayFailureException("退款卡号不存在")); // 将金额全部推到指定的卡上 diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherService.java index 16b33e615..ab0a3ddec 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/voucher/service/VoucherService.java @@ -1,12 +1,16 @@ package cn.bootx.platform.daxpay.core.channel.voucher.service; +import cn.bootx.platform.common.core.exception.BizException; +import cn.bootx.platform.common.core.exception.DataNotExistException; import cn.bootx.platform.daxpay.code.paymodel.VoucherCode; import cn.bootx.platform.daxpay.core.channel.voucher.dao.VoucherLogManager; import cn.bootx.platform.daxpay.core.channel.voucher.dao.VoucherManager; import cn.bootx.platform.daxpay.core.channel.voucher.entity.Voucher; import cn.bootx.platform.daxpay.core.channel.voucher.entity.VoucherLog; +import cn.bootx.platform.daxpay.param.channel.voucher.VoucherChangeParam; import cn.bootx.platform.daxpay.param.channel.voucher.VoucherGenerationParam; import cn.bootx.platform.daxpay.param.channel.voucher.VoucherImportParam; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; import lombok.RequiredArgsConstructor; @@ -68,8 +72,24 @@ public class VoucherService { /** * 批量导入 + * @param skip 是否跳过已经导入的储值卡,false时将会异常 */ - public void importBatch(VoucherImportParam param) { + public void importBatch(Boolean skip,List voucherImports) { + List cardNoList = voucherImports.stream() + .map(VoucherImportParam::getCardNo) + .distinct() + .collect(Collectors.toList()); + // 卡号不能重复 + if (voucherImports.size()!=cardNoList.size()){ + throw new BizException("卡号不能重复"); + } + // 查询库中是否已经有对应的储值卡号 + List vouchersByDB = voucherManager.findByCardNoList(cardNoList); + // 不跳过已经导入的储值卡且存在数据, 抛出异常 + if (Objects.equals(skip,true)&& CollUtil.isNotEmpty(vouchersByDB)){ + log.warn("数据库中已经存在的卡号:{}",vouchersByDB.stream().map(Voucher::getCardNo).collect(Collectors.toList())); + throw new BizException("要导入的卡号在数据中已经存在"); + } } @@ -102,10 +122,12 @@ public class VoucherService { } /** - * 更改有效期 + * 更改储值卡信息 */ - public void changeEnduring() { - + public void changeInfo(VoucherChangeParam voucherChangeParam) { + // 查询对应的卡 + Voucher voucher = voucherManager.findByCardNo(voucherChangeParam.getCardNo()) + .orElseThrow(DataNotExistException::new); } } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletConfigManager.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletConfigManager.java new file mode 100644 index 000000000..6c8ff6246 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletConfigManager.java @@ -0,0 +1,18 @@ +package cn.bootx.platform.daxpay.core.channel.wallet.dao; + +import cn.bootx.platform.common.mybatisplus.impl.BaseManager; +import cn.bootx.platform.daxpay.core.channel.wallet.entity.WalletConfig; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +/** + * 钱包配置 + * @author xxm + * @since 2023/7/14 + */ +@Slf4j +@Repository +@RequiredArgsConstructor +public class WalletConfigManager extends BaseManager { +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletConfigMapper.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletConfigMapper.java new file mode 100644 index 000000000..27ada2c28 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletConfigMapper.java @@ -0,0 +1,14 @@ +package cn.bootx.platform.daxpay.core.channel.wallet.dao; + +import cn.bootx.platform.daxpay.core.channel.wallet.entity.WalletConfig; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 钱包配置 + * @author xxm + * @since 2023/7/14 + */ +@Mapper +public interface WalletConfigMapper extends BaseMapper { +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/entity/WalletConfig.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/entity/WalletConfig.java new file mode 100644 index 000000000..830a124a6 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/entity/WalletConfig.java @@ -0,0 +1,43 @@ +package cn.bootx.platform.daxpay.core.channel.wallet.entity; + +import cn.bootx.mybatis.table.modify.annotation.DbColumn; +import cn.bootx.mybatis.table.modify.annotation.DbTable; +import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlIndex; +import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity; +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; + +/** + * 钱包配置 + * @author xxm + * @since 2023/7/14 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@DbTable(comment = "钱包配置") +@Accessors(chain = true) +@TableName("pay_wallet") +public class WalletConfig extends MpBaseEntity { + + /** 商户编码 */ + @TableField(updateStrategy = FieldStrategy.NEVER) + @DbColumn(comment = "商户编码") + private String mchCode; + + /** 商户应用编码 */ + @TableField(updateStrategy = FieldStrategy.NEVER) + @DbMySqlIndex(comment = "商户应用编码唯一索引") + @DbColumn(comment = "商户应用编码") + private String mchAppCode; + + /** 默认余额 */ + @DbColumn(comment = "默认余额") + private BigDecimal defaultBalance; + +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/service/WalletConfigService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/service/WalletConfigService.java new file mode 100644 index 000000000..c2e2ccec2 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/service/WalletConfigService.java @@ -0,0 +1,20 @@ +package cn.bootx.platform.daxpay.core.channel.wallet.service; + +import cn.bootx.platform.daxpay.core.channel.wallet.dao.WalletConfigManager; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 钱包配置 + * @author xxm + * @since 2023/7/14 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class WalletConfigService { + private final WalletConfigManager walletConfigManager; + + +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPayService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPayService.java index 1b3c15b06..e8a59e1b7 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPayService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPayService.java @@ -7,8 +7,8 @@ import cn.bootx.platform.daxpay.code.pay.PayWayEnum; import cn.bootx.platform.daxpay.code.paymodel.WeChatPayCode; import cn.bootx.platform.daxpay.code.paymodel.WeChatPayWay; import cn.bootx.platform.daxpay.core.pay.local.AsyncPayInfoLocal; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; -import cn.bootx.platform.daxpay.core.pay.service.PaySyncService; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; +import cn.bootx.platform.daxpay.core.sync.service.PaySyncService; import cn.bootx.platform.daxpay.core.payment.entity.Payment; import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig; import cn.bootx.platform.daxpay.dto.pay.AsyncPayInfo; diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaySyncService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaySyncService.java index 1b9986137..3b63fac7d 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaySyncService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaySyncService.java @@ -2,8 +2,9 @@ package cn.bootx.platform.daxpay.core.channel.wechat.service; import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; import cn.bootx.platform.daxpay.code.paymodel.WeChatPayCode; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig; +import cn.hutool.json.JSONUtil; import com.ijpay.core.enums.SignType; import com.ijpay.core.kit.WxPayKit; import com.ijpay.wxpay.WxPayApi; @@ -41,6 +42,7 @@ public class WeChatPaySyncService { try { String xmlResult = WxPayApi.orderQuery(params); Map result = WxPayKit.xmlToMap(xmlResult); + paySyncResult.setJson(JSONUtil.toJsonStr(result)); // 查询失败 if (!WxPayKit.codeIsOk(result.get(WeChatPayCode.RETURN_CODE))) { log.warn("查询微信订单失败:{}", result); diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaymentService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaymentService.java index 0ec224152..5981430d0 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaymentService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wechat/service/WeChatPaymentService.java @@ -1,6 +1,7 @@ package cn.bootx.platform.daxpay.core.channel.wechat.service; import cn.bootx.platform.common.core.exception.BizException; +import cn.bootx.platform.common.core.util.BigDecimalUtil; import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; import cn.bootx.platform.daxpay.code.pay.PayStatusCode; import cn.bootx.platform.daxpay.core.channel.wechat.dao.WeChatPaymentManager; @@ -38,7 +39,7 @@ public class WeChatPaymentService { private final WeChatPaymentManager weChatPaymentManager; /** - * 支付调起成功 更新 payment 中 异步支付类型信息 + * 支付调起成功 更新payment中异步支付类型信息, 如果支付完成, 创建微信支付单 */ public void updatePaySuccess(Payment payment, PayWayParam payWayParam) { AsyncPayInfo asyncPayInfo = AsyncPayInfoLocal.get(); @@ -74,10 +75,9 @@ public class WeChatPaymentService { } /** - * 更新支付记录成功状态, 并创建微信支付记录 + * 并创建微信支付记录 */ private void createWeChatPayment(Payment payment, PayWayParam payWayParam, String tradeNo) { - // 创建微信支付记录 WeChatPayment wechatPayment = new WeChatPayment(); wechatPayment.setTradeNo(tradeNo) @@ -105,6 +105,18 @@ public class WeChatPaymentService { * 更新退款 */ public void updatePayRefund(Long paymentId, BigDecimal amount) { + Optional weChatPayment = weChatPaymentManager.findByPaymentId(paymentId); + weChatPayment.ifPresent(payment -> { + BigDecimal refundableBalance = payment.getRefundableBalance().subtract(amount); + payment.setRefundableBalance(refundableBalance); + if (BigDecimalUtil.compareTo(refundableBalance, BigDecimal.ZERO) == 0) { + payment.setPayStatus(PayStatusCode.TRADE_REFUNDED); + } + else { + payment.setPayStatus(PayStatusCode.TRADE_REFUNDING); + } + weChatPaymentManager.updateById(payment); + }); } } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/entity/PayNotifyRecord.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/entity/PayNotifyRecord.java index a216b56cf..97530d4dc 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/entity/PayNotifyRecord.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/entity/PayNotifyRecord.java @@ -1,11 +1,10 @@ package cn.bootx.platform.daxpay.core.notify.entity; import cn.bootx.mybatis.table.modify.annotation.DbComment; -import cn.bootx.mybatis.table.modify.annotation.DbTable; import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlFieldType; import cn.bootx.mybatis.table.modify.mybatis.mysq.constants.MySqlFieldTypeEnum; import cn.bootx.platform.common.core.function.EntityBaseFunction; -import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity; +import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity; import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; import cn.bootx.platform.daxpay.code.pay.PayStatusCode; import cn.bootx.platform.daxpay.core.notify.convert.PayNotifyConvert; @@ -28,7 +27,7 @@ import java.time.LocalDateTime; //@DbTable(comment = "回调记录") @Accessors(chain = true) @TableName("pay_pay_notify_record") -public class PayNotifyRecord extends MpBaseEntity implements EntityBaseFunction { +public class PayNotifyRecord extends MpCreateEntity implements EntityBaseFunction { /** 支付记录id */ @DbComment("支付记录id") diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/service/PayNotifyRecordService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/service/PayNotifyRecordService.java index cf3778179..feb90009d 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/service/PayNotifyRecordService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/notify/service/PayNotifyRecordService.java @@ -21,7 +21,7 @@ import org.springframework.stereotype.Service; @Slf4j @Service @RequiredArgsConstructor -public class PayNotifyRecordService { +public class PayNotifyRecordService { private final PayNotifyRecordManager payNotifyRecordManager; diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/func/AbsPayStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/func/AbsPayStrategy.java index b9c26abe6..1c23d19fb 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/func/AbsPayStrategy.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/func/AbsPayStrategy.java @@ -1,9 +1,7 @@ package cn.bootx.platform.daxpay.core.pay.func; import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; -import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; import cn.bootx.platform.daxpay.core.pay.exception.ExceptionInfo; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; import cn.bootx.platform.daxpay.core.payment.entity.Payment; import cn.bootx.platform.daxpay.param.pay.PayParam; import cn.bootx.platform.daxpay.param.pay.PayWayParam; @@ -93,12 +91,4 @@ public abstract class AbsPayStrategy { */ public abstract void doCloseHandler(); - /** - * 异步支付单与支付网关进行状态比对 - * @see PaySyncStatus - */ - public PaySyncResult doSyncPayStatusHandler() { - return new PaySyncResult(); - } - } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/AliPayStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/AliPayStrategy.java index 5f1c478b0..6528917ea 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/AliPayStrategy.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/AliPayStrategy.java @@ -8,7 +8,6 @@ import cn.bootx.platform.daxpay.core.channel.alipay.entity.AlipayConfig; import cn.bootx.platform.daxpay.core.channel.alipay.service.*; import cn.bootx.platform.daxpay.core.pay.exception.ExceptionInfo; import cn.bootx.platform.daxpay.core.pay.func.AbsPayStrategy; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; import cn.bootx.platform.daxpay.exception.payment.PayAmountAbnormalException; import cn.bootx.platform.daxpay.exception.payment.PayFailureException; import cn.bootx.platform.daxpay.param.channel.alipay.AliPayParam; @@ -153,14 +152,6 @@ public class AliPayStrategy extends AbsPayStrategy { aliPaymentService.updateClose(this.getPayment().getId()); } - /** - * 异步支付单与支付网关进行状态比对 - */ - @Override - public PaySyncResult doSyncPayStatusHandler() { - this.initAlipayConfig(this.getPayParam().getMchAppCode()); - return alipaySyncService.syncPayStatus(this.getPayment()); - } /** * 初始化支付宝配置信息 diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WeChatPayStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WeChatPayStrategy.java index 438546de7..aceecc979 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WeChatPayStrategy.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WeChatPayStrategy.java @@ -11,7 +11,6 @@ import cn.bootx.platform.daxpay.core.channel.wechat.service.WeChatPaySyncService import cn.bootx.platform.daxpay.core.channel.wechat.service.WeChatPaymentService; import cn.bootx.platform.daxpay.core.pay.exception.ExceptionInfo; import cn.bootx.platform.daxpay.core.pay.func.AbsPayStrategy; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; import cn.bootx.platform.daxpay.exception.payment.PayAmountAbnormalException; import cn.bootx.platform.daxpay.exception.payment.PayFailureException; import cn.bootx.platform.daxpay.param.channel.wechat.WeChatPayParam; @@ -155,16 +154,6 @@ public class WeChatPayStrategy extends AbsPayStrategy { weChatPaymentService.updateClose(this.getPayment().getId()); } - /** - * 异步支付单与支付网关进行状态比对 - */ - @Override - public PaySyncResult doSyncPayStatusHandler() { - // 检查并获取微信支付配置 - this.initWeChatPayConfig(this.getPayParam().getMchAppCode()); - return weChatPaySyncService.syncPayStatus(this.getPayment().getId(), this.weChatPayConfig); - } - /** * 初始化微信支付 */ diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/convert/RefundConvert.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/convert/RefundConvert.java index 14d72fd71..b62f968eb 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/convert/RefundConvert.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/convert/RefundConvert.java @@ -1,7 +1,7 @@ package cn.bootx.platform.daxpay.core.refund.record.convert; -import cn.bootx.platform.daxpay.core.refund.record.entity.RefundRecord; -import cn.bootx.platform.daxpay.dto.refund.RefundRecordDto; +import cn.bootx.platform.daxpay.core.refund.record.entity.PayRefundRecord; +import cn.bootx.platform.daxpay.dto.refund.PayRefundRecordDto; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -14,6 +14,6 @@ public interface RefundConvert { RefundConvert CONVERT = Mappers.getMapper(RefundConvert.class); - RefundRecordDto convert(RefundRecord in); + PayRefundRecordDto convert(PayRefundRecord in); } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/PayRefundRecordManager.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/PayRefundRecordManager.java new file mode 100644 index 000000000..9c68bdaab --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/PayRefundRecordManager.java @@ -0,0 +1,34 @@ +package cn.bootx.platform.daxpay.core.refund.record.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.refund.record.entity.PayRefundRecord; +import cn.bootx.platform.daxpay.dto.refund.PayRefundRecordDto; +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 PayRefundRecordManager extends BaseManager { + + public Page page(PageParam pageParam, PayRefundRecordDto param) { + Page mpPage = MpUtil.getMpPage(pageParam, PayRefundRecord.class); + return lambdaQuery().orderByDesc(MpIdEntity::getId) + .like(Objects.nonNull(param.getPaymentId()), PayRefundRecord::getPaymentId, param.getPaymentId()) + .like(Objects.nonNull(param.getBusinessId()), PayRefundRecord::getBusinessId, param.getBusinessId()) + .like(Objects.nonNull(param.getTitle()), PayRefundRecord::getTitle, param.getTitle()) + .page(mpPage); + } + +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/RefundRecordMapper.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/PayRefundRecordMapper.java similarity index 58% rename from dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/RefundRecordMapper.java rename to dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/PayRefundRecordMapper.java index 55a4611e4..db718ce7c 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/RefundRecordMapper.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/PayRefundRecordMapper.java @@ -1,6 +1,6 @@ package cn.bootx.platform.daxpay.core.refund.record.dao; -import cn.bootx.platform.daxpay.core.refund.record.entity.RefundRecord; +import cn.bootx.platform.daxpay.core.refund.record.entity.PayRefundRecord; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @@ -9,6 +9,6 @@ import org.apache.ibatis.annotations.Mapper; * @since 2022/3/2 */ @Mapper -public interface RefundRecordMapper extends BaseMapper { +public interface PayRefundRecordMapper extends BaseMapper { } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/RefundRecordManager.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/RefundRecordManager.java deleted file mode 100644 index 7adaa8017..000000000 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/dao/RefundRecordManager.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.bootx.platform.daxpay.core.refund.record.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.refund.record.entity.RefundRecord; -import cn.bootx.platform.daxpay.dto.refund.RefundRecordDto; -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 RefundRecordManager extends BaseManager { - - public Page page(PageParam pageParam, RefundRecordDto param) { - Page mpPage = MpUtil.getMpPage(pageParam, RefundRecord.class); - return lambdaQuery().orderByDesc(MpIdEntity::getId) - .like(Objects.nonNull(param.getPaymentId()), RefundRecord::getPaymentId, param.getPaymentId()) - .like(Objects.nonNull(param.getBusinessId()), RefundRecord::getBusinessId, param.getBusinessId()) - .like(Objects.nonNull(param.getTitle()), RefundRecord::getTitle, param.getTitle()) - .page(mpPage); - } - -} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/entity/RefundRecord.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/entity/PayRefundRecord.java similarity index 90% rename from dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/entity/RefundRecord.java rename to dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/entity/PayRefundRecord.java index d47f4e8a4..1db4012fc 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/entity/RefundRecord.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/record/entity/PayRefundRecord.java @@ -6,7 +6,7 @@ import cn.bootx.platform.common.mybatisplus.handler.JacksonRawTypeHandler; import cn.bootx.platform.daxpay.code.pay.PayStatusCode; import cn.bootx.platform.daxpay.core.refund.record.convert.RefundConvert; import cn.bootx.platform.daxpay.dto.payment.RefundableInfo; -import cn.bootx.platform.daxpay.dto.refund.RefundRecordDto; +import cn.bootx.platform.daxpay.dto.refund.PayRefundRecordDto; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -27,7 +27,7 @@ import java.util.List; @Data @Accessors(chain = true) @TableName(value = "pay_refund_record", autoResultMap = true) -public class RefundRecord extends MpBaseEntity implements EntityBaseFunction { +public class PayRefundRecord extends MpBaseEntity implements EntityBaseFunction { /** 支付单号 */ private Long paymentId; @@ -75,7 +75,7 @@ public class RefundRecord extends MpBaseEntity implements EntityBaseFunction page(PageParam pageParam, RefundRecordDto param) { - Page page = refundRecordManager.page(pageParam, param); + public PageResult page(PageParam pageParam, PayRefundRecordDto param) { + Page page = refundRecordManager.page(pageParam, param); return MpUtil.convert2DtoPageResult(page); } /** * 根据id查询 */ - public RefundRecordDto findById(Long id) { - return refundRecordManager.findById(id).map(RefundRecord::toDto).orElseThrow(DataNotExistException::new); + public PayRefundRecordDto findById(Long id) { + return refundRecordManager.findById(id).map(PayRefundRecord::toDto).orElseThrow(DataNotExistException::new); } } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/service/PayRefundService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/service/PayRefundService.java index 6991fd441..b77f1386e 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/service/PayRefundService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/service/PayRefundService.java @@ -10,8 +10,8 @@ import cn.bootx.platform.daxpay.core.refund.factory.PayRefundStrategyFactory; import cn.bootx.platform.daxpay.core.refund.func.AbsPayRefundStrategy; import cn.bootx.platform.daxpay.core.refund.func.PayRefundStrategyConsumer; import cn.bootx.platform.daxpay.core.refund.local.AsyncRefundLocal; -import cn.bootx.platform.daxpay.core.refund.record.dao.RefundRecordManager; -import cn.bootx.platform.daxpay.core.refund.record.entity.RefundRecord; +import cn.bootx.platform.daxpay.core.refund.record.dao.PayRefundRecordManager; +import cn.bootx.platform.daxpay.core.refund.record.entity.PayRefundRecord; import cn.bootx.platform.daxpay.dto.payment.RefundableInfo; import cn.bootx.platform.daxpay.exception.payment.PayAmountAbnormalException; import cn.bootx.platform.daxpay.exception.payment.PayFailureException; @@ -54,7 +54,7 @@ public class PayRefundService { private final PaymentManager paymentManager; - private final RefundRecordManager refundRecordManager; + private final PayRefundRecordManager refundRecordManager; /** * 退款 @@ -229,7 +229,7 @@ public class PayRefundService { .collect(Collectors.toList()); HttpServletRequest request = WebServletUtil.getRequest(); String ip = ServletUtil.getClientIP(request); - RefundRecord refundRecord = new RefundRecord().setRefundRequestNo(AsyncRefundLocal.get()) + PayRefundRecord refundRecord = new PayRefundRecord().setRefundRequestNo(AsyncRefundLocal.get()) .setRefundableInfo(refundableInfos) .setAmount(amount) .setRefundableBalance(payment.getRefundableBalance()) diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/strategy/WeChatPayRefundStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/strategy/WeChatPayRefundStrategy.java index a0de464ef..57ce0bc75 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/strategy/WeChatPayRefundStrategy.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/refund/strategy/WeChatPayRefundStrategy.java @@ -2,7 +2,6 @@ package cn.bootx.platform.daxpay.core.refund.strategy; import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; import cn.bootx.platform.daxpay.core.channel.wechat.dao.WeChatPayConfigManager; -import cn.bootx.platform.daxpay.core.channel.wechat.dao.WeChatPaymentManager; import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig; import cn.bootx.platform.daxpay.core.channel.wechat.service.WeChatPayCancelService; import cn.bootx.platform.daxpay.core.channel.wechat.service.WeChatPaymentService; @@ -25,7 +24,6 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT @RequiredArgsConstructor public class WeChatPayRefundStrategy extends AbsPayRefundStrategy { - private final WeChatPaymentManager weChatPaymentManager; private final WeChatPayConfigManager weChatPayConfigManager; private final WeChatPayCancelService weChatPayCancelService; diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/factory/PaySyncStrategyFactory.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/factory/PaySyncStrategyFactory.java new file mode 100644 index 000000000..755fb48cc --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/factory/PaySyncStrategyFactory.java @@ -0,0 +1,38 @@ +package cn.bootx.platform.daxpay.core.sync.factory; + + +import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; +import cn.bootx.platform.daxpay.core.sync.func.AbsPaySyncStrategy; +import cn.bootx.platform.daxpay.core.sync.strategy.AliPaySyncStrategy; +import cn.bootx.platform.daxpay.core.sync.strategy.WeChatPaySyncStrategy; +import cn.bootx.platform.daxpay.exception.payment.PayUnsupportedMethodException; +import cn.hutool.extra.spring.SpringUtil; + +/** + * 支付同步策略工厂类 + * @author xxm + * @since 2023/7/14 + */ +public class PaySyncStrategyFactory { + /** + * 获取支付同步策略 + * @param payChannelCode + * @return + */ + public static AbsPaySyncStrategy create(String payChannelCode) { + AbsPaySyncStrategy strategy; + PayChannelEnum channelEnum = PayChannelEnum.findByCode(payChannelCode); + switch (channelEnum) { + case ALI: + strategy = SpringUtil.getBean(AliPaySyncStrategy.class); + break; + case WECHAT: + strategy = SpringUtil.getBean(WeChatPaySyncStrategy.class); + break; + default: + throw new PayUnsupportedMethodException(); + } + // noinspection ConstantConditions + return strategy; + } +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/func/AbsPaySyncStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/func/AbsPaySyncStrategy.java new file mode 100644 index 000000000..10764ecd5 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/func/AbsPaySyncStrategy.java @@ -0,0 +1,35 @@ +package cn.bootx.platform.daxpay.core.sync.func; + +import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; +import cn.bootx.platform.daxpay.core.payment.entity.Payment; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; +import lombok.Getter; +import lombok.Setter; + +/** + * 支付同步抽象类 + * @author xxm + * @since 2023/7/14 + */ +@Getter +@Setter +public abstract class AbsPaySyncStrategy { + + /** 支付对象 */ + private Payment payment = null; + + /** + * 初始化支付的参数 + */ + public void initPayParam(Payment payment) { + this.payment = payment; + } + + + /** + * 异步支付单与支付网关进行状态比对 + * @see PaySyncStatus + */ + public abstract PaySyncResult doSyncPayStatusHandler(); + +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/convert/PaySyncRecordConvert.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/convert/PaySyncRecordConvert.java new file mode 100644 index 000000000..94c96b170 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/convert/PaySyncRecordConvert.java @@ -0,0 +1,19 @@ +package cn.bootx.platform.daxpay.core.sync.record.convert; + +import cn.bootx.platform.daxpay.core.sync.record.entity.PaySyncRecord; +import cn.bootx.platform.daxpay.dto.sync.PaySyncRecordDto; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 支付同步记录同步 + * @author xxm + * @since 2023/7/14 + */ +@Mapper +public interface PaySyncRecordConvert { + PaySyncRecordConvert CONVERT = Mappers.getMapper(PaySyncRecordConvert.class); + + PaySyncRecordDto convert(PaySyncRecord in); + +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/dao/PaySyncRecordManager.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/dao/PaySyncRecordManager.java new file mode 100644 index 000000000..e6b3bc8bb --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/dao/PaySyncRecordManager.java @@ -0,0 +1,35 @@ +package cn.bootx.platform.daxpay.core.sync.record.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.sync.record.entity.PaySyncRecord; +import cn.bootx.platform.daxpay.dto.sync.PaySyncRecordDto; +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 2023/7/14 + */ +@Slf4j +@Repository +@RequiredArgsConstructor +public class PaySyncRecordManager extends BaseManager { + + public Page page(PageParam pageParam, PaySyncRecordDto param) { + Page mpPage = MpUtil.getMpPage(pageParam, PaySyncRecord.class); + return lambdaQuery().orderByDesc(MpIdEntity::getId) + .like(Objects.nonNull(param.getPaymentId()), PaySyncRecord::getPaymentId, param.getPaymentId()) + .eq(Objects.nonNull(param.getPayChannel()), PaySyncRecord::getPayChannel, param.getPayChannel()) + .eq(Objects.nonNull(param.getStatus()), PaySyncRecord::getStatus, param.getStatus()) + .page(mpPage); + } + +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/dao/PaySyncRecordMapper.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/dao/PaySyncRecordMapper.java new file mode 100644 index 000000000..60fc9f961 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/dao/PaySyncRecordMapper.java @@ -0,0 +1,14 @@ +package cn.bootx.platform.daxpay.core.sync.record.dao; + +import cn.bootx.platform.daxpay.core.sync.record.entity.PaySyncRecord; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 支付同步记录 + * @author xxm + * @since 2023/7/14 + */ +@Mapper +public interface PaySyncRecordMapper extends BaseMapper { +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/entity/PaySyncRecord.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/entity/PaySyncRecord.java new file mode 100644 index 000000000..d833a75f5 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/entity/PaySyncRecord.java @@ -0,0 +1,74 @@ +package cn.bootx.platform.daxpay.core.sync.record.entity; + +import cn.bootx.mybatis.table.modify.annotation.DbComment; +import cn.bootx.mybatis.table.modify.annotation.DbTable; +import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlFieldType; +import cn.bootx.mybatis.table.modify.mybatis.mysq.constants.MySqlFieldTypeEnum; +import cn.bootx.platform.common.core.function.EntityBaseFunction; +import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity; +import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; +import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; +import cn.bootx.platform.daxpay.core.sync.record.convert.PaySyncRecordConvert; +import cn.bootx.platform.daxpay.dto.sync.PaySyncRecordDto; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 支付同步记录 + * @author xxm + * @since 2023/7/14 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@DbTable(comment = "支付同步记录") +@Accessors(chain = true) +@TableName("pay_sync_record") +public class PaySyncRecord extends MpCreateEntity implements EntityBaseFunction { + + /** 支付记录id */ + @DbComment("支付记录id") + private Long paymentId; + + /** 商户编码 */ + @DbComment("商户编码") + private String mchCode; + + /** 商户应用编码 */ + @DbComment("商户应用编码") + private String mchAppCode; + + /** + * 支付通道 + * @see PayChannelEnum#getCode() + */ + @DbComment("支付通道") + private String payChannel; + + /** 通知消息 */ + @DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT) + @DbComment("通知消息") + private String syncInfo; + + /** + * 同步状态 + * @see PaySyncStatus#WAIT_BUYER_PAY + */ + @DbComment("同步状态") + private String status; + + /** 同步时间 */ + @DbComment("同步时间") + private LocalDateTime syncTime; + + /** + * 转换 + */ + @Override + public PaySyncRecordDto toDto() { + return PaySyncRecordConvert.CONVERT.convert(this); + } +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/service/PaySyncRecordService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/service/PaySyncRecordService.java new file mode 100644 index 000000000..5b222557a --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/record/service/PaySyncRecordService.java @@ -0,0 +1,59 @@ +package cn.bootx.platform.daxpay.core.sync.record.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.payment.entity.Payment; +import cn.bootx.platform.daxpay.core.sync.record.dao.PaySyncRecordManager; +import cn.bootx.platform.daxpay.core.sync.record.entity.PaySyncRecord; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; +import cn.bootx.platform.daxpay.dto.sync.PaySyncRecordDto; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +/** + * 支付同步记录 + * @author xxm + * @since 2023/7/14 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class PaySyncRecordService { + private final PaySyncRecordManager syncRecordManager; + + /** + * 记录同步记录 + */ + public void saveRecord(PaySyncResult paySyncResult, Payment payment){ + PaySyncRecord paySyncRecord = new PaySyncRecord() + .setPaymentId(payment.getId()) + .setMchCode(payment.getMchCode()) + .setMchAppCode(payment.getMchAppCode()) + .setPayChannel(payment.getAsyncPayChannel()) + .setSyncInfo(paySyncResult.getJson()) + .setStatus(paySyncResult.getPaySyncStatus()) + .setSyncTime(LocalDateTime.now()); + syncRecordManager.save(paySyncRecord); + } + + /** + * 分页查询 + */ + public PageResult page(PageParam pageParam, PaySyncRecordDto param) { + Page page = syncRecordManager.page(pageParam, param); + return MpUtil.convert2DtoPageResult(page); + } + + /** + * 根据id查询 + */ + public PaySyncRecordDto findById(Long id) { + return syncRecordManager.findById(id).map(PaySyncRecord::toDto).orElseThrow(DataNotExistException::new); + } +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/result/PaySyncResult.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/result/PaySyncResult.java similarity index 74% rename from dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/result/PaySyncResult.java rename to dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/result/PaySyncResult.java index fa0bd5d4a..ad282d1f2 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/result/PaySyncResult.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/result/PaySyncResult.java @@ -1,4 +1,4 @@ -package cn.bootx.platform.daxpay.core.pay.result; +package cn.bootx.platform.daxpay.core.sync.result; import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; import lombok.Data; @@ -24,7 +24,10 @@ public class PaySyncResult { */ private String paySyncStatus = NOT_SYNC; - /** 网关返回参数 */ + /** 网关返回参数(会被用到的参数) */ private Map map; + /** 网关返回对象的json字符串 */ + private String json; + } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/service/PayExpiredTimeService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/service/PayExpiredTimeService.java similarity index 55% rename from dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/service/PayExpiredTimeService.java rename to dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/service/PayExpiredTimeService.java index bda102f3d..36a614ce0 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/service/PayExpiredTimeService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/service/PayExpiredTimeService.java @@ -1,20 +1,11 @@ -package cn.bootx.platform.daxpay.core.pay.service; +package cn.bootx.platform.daxpay.core.sync.service; -import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; import cn.bootx.platform.daxpay.core.pay.builder.PayEventBuilder; -import cn.bootx.platform.daxpay.core.pay.builder.PaymentBuilder; -import cn.bootx.platform.daxpay.core.pay.factory.PayStrategyFactory; import cn.bootx.platform.daxpay.core.pay.func.AbsPayStrategy; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; import cn.bootx.platform.daxpay.core.payment.entity.Payment; import cn.bootx.platform.daxpay.core.payment.service.PaymentService; -import cn.bootx.platform.daxpay.exception.payment.PayFailureException; -import cn.bootx.platform.daxpay.exception.payment.PayUnsupportedMethodException; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; import cn.bootx.platform.daxpay.mq.PaymentEventSender; -import cn.bootx.platform.daxpay.param.pay.PayWayParam; -import cn.bootx.platform.daxpay.param.pay.PayParam; -import cn.bootx.platform.daxpay.util.PayWaylUtil; -import cn.hutool.core.collection.CollUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; @@ -49,63 +40,63 @@ public class PayExpiredTimeService { @Transactional(rollbackFor = Exception.class) public void expiredTime(Long paymentId) { - Payment payment = paymentService.findById(paymentId).orElseThrow(() -> new PayFailureException("支付单未找到")); - // 只处理支付中 - if (!Objects.equals(payment.getPayStatus(), TRADE_PROGRESS)) { - return; - } - // 获取支付网关状态 - PayParam payParam = PaymentBuilder.buildPayParamByPayment(payment); - // 1.获取支付方式,通过工厂生成对应的策略组 - List paymentStrategyList = PayStrategyFactory.create(payParam.getPayWayList()); - if (CollUtil.isEmpty(paymentStrategyList)) { - throw new PayUnsupportedMethodException(); - } - - // 2.初始化支付的参数 - for (AbsPayStrategy paymentStrategy : paymentStrategyList) { - paymentStrategy.initPayParam(payment, payParam); - } - - // 3 拿到异步支付方法, 与支付网关进行同步 - PayWayParam asyncPayMode = PayWaylUtil.getAsyncPayModeParam(payParam); - AbsPayStrategy syncPayStrategy = PayStrategyFactory.create(asyncPayMode); - syncPayStrategy.initPayParam(payment, payParam); - PaySyncResult paySyncResult = syncPayStrategy.doSyncPayStatusHandler(); - - // 4 对返回的支付网关各种状态进行处理 - String paySyncStatus = paySyncResult.getPaySyncStatus(); - switch (paySyncStatus) { - // 成功状态 - case PaySyncStatus.TRADE_SUCCESS: { - this.paySuccess(payment, syncPayStrategy, paySyncResult); - break; - } - // 待付款/ 支付中 - case PaySyncStatus.WAIT_BUYER_PAY: { - this.payCancel(payment, paymentStrategyList); - break; - } - // 超时关闭 和 网关没找到记录 - case PaySyncStatus.TRADE_CLOSED: - case PaySyncStatus.NOT_FOUND: { - this.payClose(payment, paymentStrategyList); - break; - } - // 交易退款 - case PaySyncStatus.TRADE_REFUND: { - log.info("交易退款不需要关闭: {}", payment.getId()); - break; - } - // 调用出错 进行重试 - case PaySyncStatus.FAIL: { - log.warn("支付状态同步接口调用出错"); - } - case PaySyncStatus.NOT_SYNC: - default: { - log.error("支付超时代码有问题"); - } - } +// Payment payment = paymentService.findById(paymentId).orElseThrow(() -> new PayFailureException("支付单未找到")); +// // 只处理支付中 +// if (!Objects.equals(payment.getPayStatus(), TRADE_PROGRESS)) { +// return; +// } +// // 获取支付网关状态 +// PayParam payParam = PaymentBuilder.buildPayParamByPayment(payment); +// // 1.获取支付方式,通过工厂生成对应的策略组 +// List paymentStrategyList = PayStrategyFactory.create(payParam.getPayWayList()); +// if (CollUtil.isEmpty(paymentStrategyList)) { +// throw new PayUnsupportedMethodException(); +// } +// +// // 2.初始化支付的参数 +// for (AbsPayStrategy paymentStrategy : paymentStrategyList) { +// paymentStrategy.initPayParam(payment, payParam); +// } +// +// // 3 拿到异步支付方法, 与支付网关进行同步 +// PayWayParam asyncPayMode = PayWaylUtil.getAsyncPayModeParam(payParam); +// AbsPayStrategy syncPayStrategy = PayStrategyFactory.create(asyncPayMode); +// syncPayStrategy.initPayParam(payment, payParam); +// PaySyncResult paySyncResult = syncPayStrategy.doSyncPayStatusHandler(); +// +// // 4 对返回的支付网关各种状态进行处理 +// String paySyncStatus = paySyncResult.getPaySyncStatus(); +// switch (paySyncStatus) { +// // 成功状态 +// case PaySyncStatus.TRADE_SUCCESS: { +// this.paySuccess(payment, syncPayStrategy, paySyncResult); +// break; +// } +// // 待付款/ 支付中 +// case PaySyncStatus.WAIT_BUYER_PAY: { +// this.payCancel(payment, paymentStrategyList); +// break; +// } +// // 超时关闭 和 网关没找到记录 +// case PaySyncStatus.TRADE_CLOSED: +// case PaySyncStatus.NOT_FOUND: { +// this.payClose(payment, paymentStrategyList); +// break; +// } +// // 交易退款 +// case PaySyncStatus.TRADE_REFUND: { +// log.info("交易退款不需要关闭: {}", payment.getId()); +// break; +// } +// // 调用出错 进行重试 +// case PaySyncStatus.FAIL: { +// log.warn("支付状态同步接口调用出错"); +// } +// case PaySyncStatus.NOT_SYNC: +// default: { +// log.error("支付超时代码有问题"); +// } +// } } /** diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/service/PaySyncService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/service/PaySyncService.java similarity index 85% rename from dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/service/PaySyncService.java rename to dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/service/PaySyncService.java index b746b8348..0bb478723 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/service/PaySyncService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/service/PaySyncService.java @@ -1,4 +1,4 @@ -package cn.bootx.platform.daxpay.core.pay.service; +package cn.bootx.platform.daxpay.core.sync.service; import cn.bootx.platform.common.core.exception.BizException; import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; @@ -6,14 +6,17 @@ import cn.bootx.platform.daxpay.core.pay.builder.PayEventBuilder; import cn.bootx.platform.daxpay.core.pay.builder.PaymentBuilder; import cn.bootx.platform.daxpay.core.pay.factory.PayStrategyFactory; import cn.bootx.platform.daxpay.core.pay.func.AbsPayStrategy; -import cn.bootx.platform.daxpay.core.pay.result.PaySyncResult; import cn.bootx.platform.daxpay.core.payment.entity.Payment; import cn.bootx.platform.daxpay.core.payment.service.PaymentService; +import cn.bootx.platform.daxpay.core.sync.factory.PaySyncStrategyFactory; +import cn.bootx.platform.daxpay.core.sync.func.AbsPaySyncStrategy; +import cn.bootx.platform.daxpay.core.sync.record.service.PaySyncRecordService; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; import cn.bootx.platform.daxpay.exception.payment.PayFailureException; import cn.bootx.platform.daxpay.exception.payment.PayUnsupportedMethodException; import cn.bootx.platform.daxpay.mq.PaymentEventSender; -import cn.bootx.platform.daxpay.param.pay.PayWayParam; import cn.bootx.platform.daxpay.param.pay.PayParam; +import cn.bootx.platform.daxpay.param.pay.PayWayParam; import cn.bootx.platform.daxpay.util.PayWaylUtil; import cn.hutool.core.collection.CollUtil; import lombok.RequiredArgsConstructor; @@ -39,6 +42,8 @@ public class PaySyncService { private final PaymentService paymentService; + private final PaySyncRecordService paySyncRecordService; + private final PaymentEventSender eventSender; /** @@ -67,25 +72,39 @@ public class PaySyncService { * 同步支付状态 传入 payment 对象 */ public void syncPayment(Payment payment) { + // 获取同步策略类 + AbsPaySyncStrategy syncPayStrategy = PaySyncStrategyFactory.create(payment.getAsyncPayChannel()); + syncPayStrategy.initPayParam(payment); + // 同步 + PaySyncResult paySyncResult = syncPayStrategy.doSyncPayStatusHandler(); + // 处理 + this.resultHandler(paySyncResult,payment); + // 记录 + paySyncRecordService.saveRecord(paySyncResult,payment); + } + + /** + * 对同步结果进行处理 + */ + public void resultHandler(PaySyncResult paySyncResult, Payment payment){ + String paySyncStatus = paySyncResult.getPaySyncStatus(); PayParam payParam = PaymentBuilder.buildPayParamByPayment(payment); - // 1.获取支付方式,通过工厂生成对应的策略组 + // 获取支付方式,通过工厂生成对应的策略组 List paymentStrategyList = PayStrategyFactory.create(payParam.getPayWayList()); if (CollUtil.isEmpty(paymentStrategyList)) { throw new PayUnsupportedMethodException(); } - // 2.初始化支付的参数 + // 初始化支付的参数 for (AbsPayStrategy paymentStrategy : paymentStrategyList) { paymentStrategy.initPayParam(payment, payParam); } - // 3 拿到异步支付方法, 与支付网关进行同步 + // 拿到对应的支付方式 PayWayParam asyncPayMode = PayWaylUtil.getAsyncPayModeParam(payParam); AbsPayStrategy syncPayStrategy = PayStrategyFactory.create(asyncPayMode); - syncPayStrategy.initPayParam(payment, payParam); - PaySyncResult paySyncResult = syncPayStrategy.doSyncPayStatusHandler(); - String paySyncStatus = paySyncResult.getPaySyncStatus(); + // 对同步结果处理 switch (paySyncStatus) { // 支付成功 支付宝退款时也是支付成功状态, 除非支付完成 case PaySyncStatus.TRADE_SUCCESS: { diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/strategy/AliPaySyncStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/strategy/AliPaySyncStrategy.java new file mode 100644 index 000000000..46756a3b0 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/strategy/AliPaySyncStrategy.java @@ -0,0 +1,53 @@ +package cn.bootx.platform.daxpay.core.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.sync.func.AbsPaySyncStrategy; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; +import cn.bootx.platform.daxpay.exception.payment.PayFailureException; +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/14 + */ +@Scope(SCOPE_PROTOTYPE) +@Component +@RequiredArgsConstructor +public class AliPaySyncStrategy extends AbsPaySyncStrategy { + + private final AlipayConfigManager alipayConfigManager; + + private final AlipaySyncService alipaySyncService; + + private final AlipayConfigService alipayConfigService; + + private AlipayConfig alipayConfig; + + /** + * 异步支付单与支付网关进行状态比对 + */ + @Override + public PaySyncResult doSyncPayStatusHandler() { + this.initAlipayConfig(this.getPayment().getMchAppCode()); + return alipaySyncService.syncPayStatus(this.getPayment()); + } + + /** + * 初始化支付宝配置信息 + */ + private void initAlipayConfig(String mchAppCode) { + // 检查并获取支付宝支付配置 + this.alipayConfig = alipayConfigManager.findByMchAppCode(mchAppCode) + .orElseThrow(() -> new PayFailureException("支付配置不存在")); + alipayConfigService.initApiConfig(this.alipayConfig); + } +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/strategy/WeChatPaySyncStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/strategy/WeChatPaySyncStrategy.java new file mode 100644 index 000000000..08735d733 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/sync/strategy/WeChatPaySyncStrategy.java @@ -0,0 +1,49 @@ +package cn.bootx.platform.daxpay.core.sync.strategy; + +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.channel.wechat.service.WeChatPaySyncService; +import cn.bootx.platform.daxpay.core.sync.func.AbsPaySyncStrategy; +import cn.bootx.platform.daxpay.core.sync.result.PaySyncResult; +import cn.bootx.platform.daxpay.exception.payment.PayFailureException; +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/14 + */ +@Scope(SCOPE_PROTOTYPE) +@Component +@RequiredArgsConstructor +public class WeChatPaySyncStrategy extends AbsPaySyncStrategy { + + private final WeChatPayConfigManager weChatPayConfigManager; + + private final WeChatPaySyncService weChatPaySyncService; + + private WeChatPayConfig weChatPayConfig; + + /** + * 异步支付单与支付网关进行状态比对 + */ + @Override + public PaySyncResult doSyncPayStatusHandler() { + // 检查并获取微信支付配置 + this.initWeChatPayConfig(this.getPayment().getMchAppCode()); + return weChatPaySyncService.syncPayStatus(this.getPayment().getId(), this.weChatPayConfig); + } + + /** + * 初始化微信支付 + */ + private void initWeChatPayConfig(String appCode) { + // 检查并获取微信支付配置 + this.weChatPayConfig = weChatPayConfigManager.findByMchAppCode(appCode) + .orElseThrow(() -> new PayFailureException("支付配置不存在")); + } +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/refund/RefundRecordDto.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/refund/PayRefundRecordDto.java similarity index 97% rename from dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/refund/RefundRecordDto.java rename to dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/refund/PayRefundRecordDto.java index 42d678b84..145d0c50e 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/refund/RefundRecordDto.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/refund/PayRefundRecordDto.java @@ -22,7 +22,7 @@ import java.util.List; @Data @Accessors(chain = true) @Schema(title = "退款记录") -public class RefundRecordDto extends BaseDto { +public class PayRefundRecordDto extends BaseDto { @Schema(description = "关联的业务id") private String businessId; diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/sync/PaySyncRecordDto.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/sync/PaySyncRecordDto.java new file mode 100644 index 000000000..0cac84906 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/sync/PaySyncRecordDto.java @@ -0,0 +1,61 @@ +package cn.bootx.platform.daxpay.dto.sync; + +import cn.bootx.mybatis.table.modify.annotation.DbComment; +import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlFieldType; +import cn.bootx.mybatis.table.modify.mybatis.mysq.constants.MySqlFieldTypeEnum; +import cn.bootx.platform.common.core.rest.dto.BaseDto; +import cn.bootx.platform.daxpay.code.pay.PayChannelEnum; +import cn.bootx.platform.daxpay.code.pay.PaySyncStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 支付同步记录 + * @author xxm + * @since 2023/7/14 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Accessors(chain = true) +@Schema(title = "支付同步记录") +public class PaySyncRecordDto extends BaseDto { + + /** 支付记录id */ + @DbComment("支付记录id") + private Long paymentId; + + /** 商户编码 */ + @DbComment("商户编码") + private String mchCode; + + /** 商户应用编码 */ + @DbComment("商户应用编码") + private String mchAppCode; + + /** + * 支付通道 + * @see PayChannelEnum#getCode() + */ + @DbComment("支付通道") + private String payChannel; + + /** 通知消息 */ + @DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT) + @DbComment("通知消息") + private String syncInfo; + + /** + * 同步状态 + * @see PaySyncStatus#WAIT_BUYER_PAY + */ + @DbComment("同步状态") + private String status; + + /** 同步时间 */ + @DbComment("同步时间") + private LocalDateTime syncTime; +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/mq/PaymentMessageListener.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/mq/PaymentMessageListener.java index 65452e1cb..846177d1b 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/mq/PaymentMessageListener.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/mq/PaymentMessageListener.java @@ -2,7 +2,7 @@ package cn.bootx.platform.daxpay.mq; import cn.bootx.platform.common.rabbit.conditional.ConditionalOnRabbit; import cn.bootx.platform.daxpay.code.PaymentEventCode; -import cn.bootx.platform.daxpay.core.pay.service.PayExpiredTimeService; +import cn.bootx.platform.daxpay.core.sync.service.PayExpiredTimeService; import cn.bootx.platform.daxpay.event.PayCancelEvent; import cn.bootx.platform.daxpay.event.PayCompleteEvent; import cn.bootx.platform.daxpay.event.PayRefundEvent; diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/voucher/VoucherChangeParam.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/voucher/VoucherChangeParam.java new file mode 100644 index 000000000..5e2191f8a --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/voucher/VoucherChangeParam.java @@ -0,0 +1,57 @@ +package cn.bootx.platform.daxpay.param.channel.voucher; + +import cn.bootx.platform.daxpay.code.paymodel.VoucherCode; +import cn.hutool.core.date.DatePattern; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * + * @author xxm + * @since 2023/7/13 + */ +@Data +@Accessors(chain = true) +@Schema(title = "储值卡信息更改参数") +public class VoucherChangeParam { + + @ExcelProperty("卡号") + @Schema(description = "卡号") + private String cardNo; + + @ExcelProperty("卡号") + @Schema(description = "面值") + private BigDecimal faceValue; + + @ExcelProperty("卡号") + @Schema(description = "余额") + private BigDecimal balance; + + @ExcelProperty("卡号") + @Schema(description = "是否长期有效") + private Boolean enduring; + + @ExcelProperty("开始时间") + @Schema(description = "开始时间") + @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) + private LocalDateTime startTime; + + @ExcelProperty("结束时间") + @Schema(description = "结束时间") + @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) + private LocalDateTime endTime; + + /** + * @see VoucherCode#STATUS_NORMAL + */ + @ExcelProperty("默认状态") + @Schema(description = "默认状态") + private String status; + +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/voucher/VoucherImportParam.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/voucher/VoucherImportParam.java index 9dcac1aef..ac50888b9 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/voucher/VoucherImportParam.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/voucher/VoucherImportParam.java @@ -1,16 +1,54 @@ package cn.bootx.platform.daxpay.param.channel.voucher; +import cn.bootx.platform.daxpay.code.paymodel.VoucherCode; +import cn.hutool.core.date.DatePattern; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; /** * @author xxm * @since 2022/3/14 */ @Data -@Accessors(chain = true) @Schema(title = "储值卡导入参数") public class VoucherImportParam { + @ExcelProperty("卡号") + @Schema(description = "卡号") + private String cardNo; + + @ExcelProperty("面值") + @Schema(description = "面值") + private BigDecimal faceValue; + + @ExcelProperty("余额") + @Schema(description = "余额") + private BigDecimal balance; + + @ExcelProperty("是否长期有效") + @Schema(description = "是否长期有效") + private Boolean enduring; + + @ExcelProperty("开始时间") + @Schema(description = "开始时间") + @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) + private LocalDateTime startTime; + + @ExcelProperty("结束时间") + @Schema(description = "结束时间") + @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) + private LocalDateTime endTime; + + /** + * @see VoucherCode#STATUS_NORMAL + */ + @ExcelProperty("默认状态") + @Schema(description = "默认状态") + private String status; + } diff --git a/dax-pay/src/main/resources/template/import/ImportVoucher.xlsx b/dax-pay/src/main/resources/template/import/ImportVoucher.xlsx new file mode 100644 index 000000000..2707d64f8 Binary files /dev/null and b/dax-pay/src/main/resources/template/import/ImportVoucher.xlsx differ