mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-04 19:49:07 +00:00
feat 拆分网关同步相关代码/记录网关同步记录/保存各通道的支付单/储值卡多卡退款到单卡, 不传卡号自动设置为默认卡
This commit is contained in:
@@ -125,4 +125,4 @@ QQ扫码加入QQ交流群
|
||||
|
||||
## 🍷License
|
||||
|
||||
Apache License Version 2.0_
|
||||
Apache License Version 2.0
|
||||
|
11
_doc/Task.md
Normal file
11
_doc/Task.md
Normal file
@@ -0,0 +1,11 @@
|
||||
- 微信V3支付接口
|
||||
- x 拆分网关同步相关代码
|
||||
- x 记录网关同步记录
|
||||
- 重构支付消息通知结构
|
||||
- x 保存各通道的支付单
|
||||
- 钱包支持设置开通时的默认金额
|
||||
- 储值卡多卡支付和退款演示
|
||||
- x 储值卡信息调整
|
||||
- x 储值卡多卡退款到单卡, 不传卡号自动设置为默认卡
|
||||
- 储值卡批量导入
|
||||
- 储值卡支持多卡合一
|
@@ -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;
|
||||
|
@@ -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<PageResult<RefundRecordDto>> page(PageParam pageParam, RefundRecordDto param) {
|
||||
return Res.ok(refundRecordService.page(pageParam, param));
|
||||
public ResResult<PageResult<PayRefundRecordDto>> page(PageParam pageParam, PayRefundRecordDto param) {
|
||||
return Res.ok(payRefundRecordService.page(pageParam, param));
|
||||
}
|
||||
|
||||
@Operation(summary = "根据id查询")
|
||||
@GetMapping("/findById")
|
||||
public ResResult<RefundRecordDto> findById(Long id) {
|
||||
return Res.ok(refundRecordService.findById(id));
|
||||
public ResResult<PayRefundRecordDto> findById(Long id) {
|
||||
return Res.ok(payRefundRecordService.findById(id));
|
||||
}
|
||||
|
||||
}
|
@@ -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<PageResult<PaySyncRecordDto>> page(PageParam pageParam, PaySyncRecordDto param) {
|
||||
return Res.ok(syncRecordService.page(pageParam, param));
|
||||
}
|
||||
|
||||
@Operation(summary = "根据id查询")
|
||||
@GetMapping("/findById")
|
||||
public ResResult<PaySyncRecordDto> findById(Long id) {
|
||||
return Res.ok(syncRecordService.findById(id));
|
||||
}
|
||||
}
|
@@ -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<Void> importBatch(Boolean skip, MultipartFile file){
|
||||
List<VoucherImportParam> 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<byte[]> 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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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)) {
|
||||
|
@@ -164,7 +164,7 @@ public class VoucherPayService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接支付
|
||||
* 直接支付 (同步支付方式下)
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<VoucherRecord> pay(BigDecimal amount, Payment payment, List<Voucher> vouchers) {
|
||||
@@ -272,9 +272,16 @@ public class VoucherPayService {
|
||||
.map(VoucherRecord::getCardNo)
|
||||
.collect(Collectors.toList());
|
||||
List<Voucher> vouchers = voucherManager.findByCardNoList(cardNoList);
|
||||
// 如果未传入卡号, 默认退到最抗用的一张卡上
|
||||
if (StrUtil.isBlank(refundVoucherNo)){
|
||||
List<Voucher> 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("退款卡号不存在"));
|
||||
// 将金额全部推到指定的卡上
|
||||
|
@@ -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<VoucherImportParam> voucherImports) {
|
||||
List<String> cardNoList = voucherImports.stream()
|
||||
.map(VoucherImportParam::getCardNo)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
// 卡号不能重复
|
||||
if (voucherImports.size()!=cardNoList.size()){
|
||||
throw new BizException("卡号不能重复");
|
||||
}
|
||||
// 查询库中是否已经有对应的储值卡号
|
||||
List<Voucher> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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<WalletConfigMapper, WalletConfig> {
|
||||
}
|
@@ -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<WalletConfig> {
|
||||
}
|
@@ -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;
|
||||
|
||||
}
|
@@ -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;
|
||||
|
||||
|
||||
}
|
@@ -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;
|
||||
|
@@ -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<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
paySyncResult.setJson(JSONUtil.toJsonStr(result));
|
||||
// 查询失败
|
||||
if (!WxPayKit.codeIsOk(result.get(WeChatPayCode.RETURN_CODE))) {
|
||||
log.warn("查询微信订单失败:{}", result);
|
||||
|
@@ -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> 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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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<PayNotifyRecordDto> {
|
||||
public class PayNotifyRecord extends MpCreateEntity implements EntityBaseFunction<PayNotifyRecordDto> {
|
||||
|
||||
/** 支付记录id */
|
||||
@DbComment("支付记录id")
|
||||
|
@@ -21,7 +21,7 @@ import org.springframework.stereotype.Service;
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayNotifyRecordService {
|
||||
public class PayNotifyRecordService {
|
||||
|
||||
private final PayNotifyRecordManager payNotifyRecordManager;
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化支付宝配置信息
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化微信支付
|
||||
*/
|
||||
|
@@ -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);
|
||||
|
||||
}
|
||||
|
@@ -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<PayRefundRecordMapper, PayRefundRecord> {
|
||||
|
||||
public Page<PayRefundRecord> page(PageParam pageParam, PayRefundRecordDto param) {
|
||||
Page<PayRefundRecord> 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);
|
||||
}
|
||||
|
||||
}
|
@@ -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<RefundRecord> {
|
||||
public interface PayRefundRecordMapper extends BaseMapper<PayRefundRecord> {
|
||||
|
||||
}
|
@@ -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<RefundRecordMapper, RefundRecord> {
|
||||
|
||||
public Page<RefundRecord> page(PageParam pageParam, RefundRecordDto param) {
|
||||
Page<RefundRecord> 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);
|
||||
}
|
||||
|
||||
}
|
@@ -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<RefundRecordDto> {
|
||||
public class PayRefundRecord extends MpBaseEntity implements EntityBaseFunction<PayRefundRecordDto> {
|
||||
|
||||
/** 支付单号 */
|
||||
private Long paymentId;
|
||||
@@ -75,7 +75,7 @@ public class RefundRecord extends MpBaseEntity implements EntityBaseFunction<Ref
|
||||
private String errorMsg;
|
||||
|
||||
@Override
|
||||
public RefundRecordDto toDto() {
|
||||
public PayRefundRecordDto toDto() {
|
||||
return RefundConvert.CONVERT.convert(this);
|
||||
}
|
||||
|
@@ -4,9 +4,9 @@ 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.refund.record.dao.RefundRecordManager;
|
||||
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.dao.PayRefundRecordManager;
|
||||
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;
|
||||
@@ -21,23 +21,23 @@ import org.springframework.stereotype.Service;
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RefundRecordService {
|
||||
public class PayRefundRecordService {
|
||||
|
||||
private final RefundRecordManager refundRecordManager;
|
||||
private final PayRefundRecordManager refundRecordManager;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*/
|
||||
public PageResult<RefundRecordDto> page(PageParam pageParam, RefundRecordDto param) {
|
||||
Page<RefundRecord> page = refundRecordManager.page(pageParam, param);
|
||||
public PageResult<PayRefundRecordDto> page(PageParam pageParam, PayRefundRecordDto param) {
|
||||
Page<PayRefundRecord> 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);
|
||||
}
|
||||
|
||||
}
|
@@ -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())
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
|
||||
}
|
@@ -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);
|
||||
|
||||
}
|
@@ -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<PaySyncRecordMapper, PaySyncRecord> {
|
||||
|
||||
public Page<PaySyncRecord> page(PageParam pageParam, PaySyncRecordDto param) {
|
||||
Page<PaySyncRecord> 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);
|
||||
}
|
||||
|
||||
}
|
@@ -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<PaySyncRecord> {
|
||||
}
|
@@ -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<PaySyncRecordDto> {
|
||||
|
||||
/** 支付记录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);
|
||||
}
|
||||
}
|
@@ -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<PaySyncRecordDto> page(PageParam pageParam, PaySyncRecordDto param) {
|
||||
Page<PaySyncRecord> 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);
|
||||
}
|
||||
}
|
@@ -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<String, String> map;
|
||||
|
||||
/** 网关返回对象的json字符串 */
|
||||
private String json;
|
||||
|
||||
}
|
@@ -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<AbsPayStrategy> 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<AbsPayStrategy> 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("支付超时代码有问题");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
@@ -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<AbsPayStrategy> 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: {
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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("支付配置不存在"));
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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;
|
||||
}
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
}
|
@@ -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;
|
||||
|
||||
}
|
||||
|
BIN
dax-pay/src/main/resources/template/import/ImportVoucher.xlsx
Normal file
BIN
dax-pay/src/main/resources/template/import/ImportVoucher.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user