ref 流程重构

This commit is contained in:
xxm1995
2024-04-23 20:56:07 +08:00
parent a62f441195
commit 6b4ac780d3
83 changed files with 364 additions and 1535 deletions

View File

@@ -15,7 +15,6 @@ import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryServ
import cn.bootx.platform.daxpay.service.core.payment.allocation.service.AllocationService;
import cn.bootx.platform.daxpay.service.core.payment.close.service.PayCloseService;
import cn.bootx.platform.daxpay.service.core.payment.sync.service.PaySyncService;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayChannelOrderDto;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDetailDto;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderExtraDto;
@@ -42,7 +41,6 @@ import java.util.List;
public class PayOrderController {
private final PayOrderQueryService queryService;
private final PayOrderExtraService payOrderExtraService;
private final PayChannelOrderService payChannelOrderService;
private final PayCloseService PayCloseService;
private final PaySyncService paySyncService;
@@ -71,7 +69,6 @@ public class PayOrderController {
PayOrderDetailDto detailDto=new PayOrderDetailDto();
detailDto.setPayOrder(order);
detailDto.setPayOrderExtra(payOrderExtraService.findById(order.getId()).toDto());
detailDto.setPayChannelOrder(payChannelOrderService.findAllByPaymentId(orderNo));
return Res.ok(detailDto);
}
@@ -81,30 +78,19 @@ public class PayOrderController {
return Res.ok(payOrderExtraService.findById(id).toDto());
}
@Operation(summary = "查询支付订单关联支付通道订单")
@GetMapping("/listByChannel")
public ResResult<List<PayChannelOrderDto>> listByChannel(String orderNo){
return Res.ok(payChannelOrderService.findAllByPaymentId(orderNo));
}
@Operation(summary = "查询支付通道订单详情")
@GetMapping("/getChannel")
public ResResult<PayChannelOrderDto> getChannel(Long id){
return Res.ok(payChannelOrderService.findById(id));
}
@Operation(summary = "同步支付状态")
@PostMapping("/syncById")
public ResResult<SyncResult> syncById(Long id){
@PostMapping("/syncByOrderNo")
public ResResult<SyncResult> syncById(String orderNo){
PaySyncParam param = new PaySyncParam();
param.setPaymentId(id);
param.setOrderNo(orderNo);
return Res.ok(paySyncService.sync(param));
}
@Operation(summary = "关闭支付记录")
@PostMapping("/close")
public ResResult<Void> close(Long id){
public ResResult<Void> close(String orderNo){
PayCloseParam param = new PayCloseParam();
param.setPaymentId(id);
param.setOrderNo(orderNo);
PayCloseService.close(param);
return Res.ok();
}

View File

@@ -15,14 +15,14 @@ import lombok.EqualsAndHashCode;
@Schema(title = "开始分账请求参数")
public class AllocationStartParam extends PaymentCommonParam {
@Schema(description = "支付单ID")
private Long paymentId;
@Schema(description = "商户分账单号")
private String bizAllocationNo;
@Schema(description = "业务")
private String businessNo;
@Schema(description = "支付订单")
private String orderNo;
@Schema(description = "分账单号(保证唯一)")
private String allocationNo;
@Schema(description = "商户订单号")
private String bizOrderNo;
@Schema(description = "分账描述")
private String description;

View File

@@ -16,5 +16,5 @@ public class AllocationSyncParam {
private String allocationNo;
@Schema(description = "商户分账号")
private String outAllocationNo;
private String bizAllocationNo;
}

View File

@@ -19,5 +19,5 @@ public class PayCloseParam extends PaymentCommonParam {
private String orderNo;
@Schema(description = "商户订单号")
private String outTradeNo;
private String bizTradeNo;
}

View File

@@ -22,13 +22,13 @@ public class CommonResult {
private String sign;
@Schema(description = "错误码")
private String code;
private String code = "0";
@Schema(description = "错误信息")
private String msg;
@Schema(description = "响应时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime resTime;
private LocalDateTime resTime = LocalDateTime.now();
}

View File

@@ -1,44 +0,0 @@
package cn.bootx.platform.daxpay.result.order;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 支付订单通道响应参数
* @author xxm
* @since 2024/1/16
*/
@Data
@Schema(title = "支付订单通道响应参数")
public class PayChannelOrderResult {
@Schema(description = "异步支付方式")
private boolean async;
@Schema(description = "通道")
private String channel;
@Schema(description = "支付方式")
private String payWay;
/**
* 第三方支付网关生成的订单号, 用与将记录关联起来
*/
@Schema(description = "关联网关支付号")
private String gatewayOrderNo;
/**
* 支付状态
* @see PayStatusEnum
*/
@Schema(description = "支付状态")
private String status;
@Schema(description = "金额")
private Integer amount;
@Schema(description = "可退款金额")
private Integer refundableBalance;
}

View File

@@ -82,5 +82,4 @@ public class PayOrderResult extends CommonResult {
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime closeTime;
}

View File

@@ -1,50 +0,0 @@
package cn.bootx.platform.daxpay.result.order;
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
import cn.bootx.platform.daxpay.serializer.LocalDateTimeToTimestampSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* 支付退款通道明细数据
* @author xxm
* @since 2024/1/17
*/
@Data
@Accessors(chain = true)
@Schema(title = "通道退款订单")
public class RefundChannelOrderResult {
@Schema(description = "通道")
private String channel;
@Schema(description = "通道支付单id")
private Long payChannelId;
@Schema(description = "异步支付方式")
private boolean async;
@Schema(description = "订单金额")
private Integer orderAmount;
@Schema(description = "退款金额")
private Integer amount;
@Schema(description = "剩余可退余额")
private Integer refundableAmount;
/**
* @see RefundStatusEnum
*/
@Schema(description = "退款状态")
private String status;
@Schema(description = "退款完成时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime refundTime;
}

View File

@@ -9,7 +9,6 @@ import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* 退款订单数据
@@ -21,17 +20,11 @@ import java.util.List;
@Schema(title = "退款订单数据")
public class RefundOrderResult {
@Schema(description = "退款ID")
private Long refundId;
@Schema(description = "退款号")
private String refundNo;
@Schema(description = "关联支付ID")
private Long paymentId;
@Schema(description = "关联支付业务号")
private String businessNo;
@Schema(description = "商户退款订单号")
private String bizRefundNo;
@Schema(description = "标题")
private String title;
@@ -39,25 +32,14 @@ public class RefundOrderResult {
@Schema(description = "退款金额")
private BigDecimal amount;
@Schema(description = "剩余可退")
private BigDecimal refundableBalance;
/**
* 异步支付通道发给网关的退款号, 用与将记录关联起来
*/
@Schema(description = "支付网关订单号")
private String gatewayOrderNo;
@Schema(description = "退款完成时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime refundTime;
private LocalDateTime finishTime;
/**
* @see RefundStatusEnum
*/
@Schema(description = "退款状态")
private String status;
@Schema(description = "通道退款订单")
private List<RefundChannelOrderResult> channels;
}

View File

@@ -0,0 +1,19 @@
package cn.bootx.platform.daxpay.result.pay;
import cn.bootx.platform.daxpay.result.CommonResult;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 支付关闭响应参数
* @author xxm
* @since 2024/4/23
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "支付关闭响应参数")
public class PayCloseResult extends CommonResult {
}

View File

@@ -8,7 +8,7 @@ import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicLong;
/**
* 订单号审查工具类
* 各类型订单号审查工具类
* @author yxc
* @since 2024/4/15
*/
@@ -24,7 +24,7 @@ public class OrderNoGenerateUtil {
/**
* 生成支付订单号
*/
public static String trade() {
public static String pay() {
StringBuilder orderNo = new StringBuilder();
String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss"));
long id = ATOMIC_LONG.incrementAndGet();

View File

@@ -40,7 +40,7 @@ public class PaySignUtil {
}
/**
* 将参数转换为map对象. 使用ChatGPT生成, 仅局限于对请求支付相关参数进行签名
* 将参数转换为map对象. 使用ChatGPT生成, 仅局限于对支付相关参数和返回值进行签名
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@SneakyThrows

View File

@@ -12,6 +12,6 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
public class AllocationLocal {
/** 网关分账号 */
private String gatewayNo;
/** 三方系统分账号 */
private String outAllocationNo;
}

View File

@@ -23,13 +23,13 @@ public class CallbackLocal {
/** 回调参数内容 */
private Map<String, String> callbackParam = new HashMap<>();
/** 订单号, 支付/退款 */
private String orderNo;
/** 交易号 */
private String tradeNo;
/**
* 第三方支付平台订单
* 第三方支付平台交易
*/
private String outOrderNo;
private String outTradeNo;
/**
* 三方支付系统返回状态
@@ -45,7 +45,7 @@ public class CallbackLocal {
private LocalDateTime finishTime;
/** 修复号 */
private String payRepairNo;
private String repairNo;
/** 回调类型 */
private PaymentTypeEnum callbackType;

View File

@@ -23,7 +23,4 @@ public class RequestLocal {
/** 请求时间,时间戳转时间 */
private LocalDateTime reqTime;
/** 请求链路id */
private String reqId;
}

View File

@@ -1,7 +1,6 @@
package cn.bootx.platform.daxpay.service.core.channel.alipay.convert;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayRecord;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
import cn.bootx.platform.daxpay.service.dto.channel.alipay.AliPayConfigDto;
import cn.bootx.platform.daxpay.service.dto.channel.alipay.AliPayRecordDto;
@@ -20,10 +19,6 @@ public interface AlipayConvert {
AlipayConvert CONVERT = Mappers.getMapper(AlipayConvert.class);
AliPayRecordDto convert(AliPayRecord in);
GeneralReconcileRecord convertReconcileRecord(AliPayRecord in);
AliPayConfig convert(AliPayConfigParam in);
AliPayConfigDto convert(AliPayConfig in);

View File

@@ -1,45 +0,0 @@
package cn.bootx.platform.daxpay.service.core.channel.alipay.dao;
import cn.bootx.platform.common.core.rest.param.PageParam;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.common.query.generator.QueryGenerator;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayRecord;
import cn.bootx.platform.daxpay.service.param.channel.alipay.AliPayRecordQuery;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
/**
*
* @author xxm
* @since 2024/2/19
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class AliPayRecordManager extends BaseManager<AliPayRecordMapper, AliPayRecord> {
/**
* 分页
*/
public Page<AliPayRecord> page(PageParam pageParam, AliPayRecordQuery param){
Page<AliPayRecord> mpPage = MpUtil.getMpPage(pageParam, AliPayRecord.class);
QueryWrapper<AliPayRecord> generator = QueryGenerator.generator(param);
return this.page(mpPage, generator);
}
/**
* 按时间范围查询
*/
public List<AliPayRecord> findByDate(LocalDateTime startDate, LocalDateTime endDate){
return this.lambdaQuery()
.between(AliPayRecord::getGatewayTime, startDate, endDate)
.list();
}
}

View File

@@ -1,14 +0,0 @@
package cn.bootx.platform.daxpay.service.core.channel.alipay.dao;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
*
* @author xxm
* @since 2024/2/19
*/
@Mapper
public interface AliPayRecordMapper extends BaseMapper<AliPayRecord> {
}

View File

@@ -1,60 +0,0 @@
package cn.bootx.platform.daxpay.service.core.channel.alipay.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.platform.daxpay.service.code.AliPayRecordTypeEnum;
import cn.bootx.platform.daxpay.service.core.channel.alipay.convert.AlipayConvert;
import cn.bootx.platform.daxpay.service.dto.channel.alipay.AliPayRecordDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* 支付宝流水记录
* @author xxm
* @since 2024/2/19
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@DbTable(comment = "支付宝流水记录")
@TableName("pay_alipay_record")
public class AliPayRecord extends MpCreateEntity implements EntityBaseFunction<AliPayRecordDto> {
/** 标题 */
@DbColumn(comment = "标题")
private String title;
/** 金额 */
@DbColumn(comment = "金额")
private Integer amount;
/**
* 业务类型
* @see AliPayRecordTypeEnum
*/
@DbColumn(comment = "业务类型")
private String type;
/** 本地订单号 */
@DbColumn(comment = "本地订单号")
private Long orderId;
/** 网关订单号 */
@DbColumn(comment = "网关订单号")
private String gatewayOrderNo;
/** 网关完成时间 */
@DbColumn(comment = "网关完成时间")
private LocalDateTime gatewayTime;
@Override
public AliPayRecordDto toDto() {
return AlipayConvert.CONVERT.convert(this);
}
}

View File

@@ -65,7 +65,7 @@ public class AliPayAllocationService {
AlipayTradeOrderSettleResponse response = AliPayApi.tradeOrderSettleToResponse(model);
// 需要写入到分账订单中
String settleNo = response.getSettleNo();
PaymentContextLocal.get().getAllocationInfo().setGatewayNo(settleNo);
PaymentContextLocal.get().getAllocationInfo().setOutAllocationNo(settleNo);
this.verifyErrorMsg(response);
}

View File

@@ -89,9 +89,9 @@ public class AliPayCallbackService extends AbsCallbackStrategy {
CallbackLocal callback = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> callbackParam = callback.getCallbackParam();
// 网关订单号
callback.setOutOrderNo(callbackParam.get(TRADE_NO));
callback.setOutTradeNo(callbackParam.get(TRADE_NO));
// 支付订单ID
callback.setOrderNo(callbackParam.get(OUT_TRADE_NO));
callback.setTradeNo(callbackParam.get(OUT_TRADE_NO));
// 支付状态
PayStatusEnum payStatus = Objects.equals(callbackParam.get(TRADE_STATUS), NOTIFY_TRADE_SUCCESS) ? PayStatusEnum.SUCCESS : PayStatusEnum.FAIL;
callback.setOutStatus(payStatus.getCode());
@@ -117,7 +117,7 @@ public class AliPayCallbackService extends AbsCallbackStrategy {
CallbackLocal callback = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> callbackParam = callback.getCallbackParam();
// 退款订单Id
callback.setOrderNo(callbackParam.get(OUT_BIZ_NO));
callback.setTradeNo(callbackParam.get(OUT_BIZ_NO));
// 退款状态
callback.setOutStatus(callbackParam.get(TRADE_STATUS));
// 退款金额

View File

@@ -29,13 +29,13 @@ public class AliPayRefundService {
/**
* 退款, 调用支付宝退款
*/
public void refund(RefundOrder refundOrder, int amount) {
public void refund(RefundOrder refundOrder) {
RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
refundModel.setOutTradeNo(String.valueOf(refundOrder.getOrderNo()));
refundModel.setOutRequestNo(String.valueOf(refundOrder.getRefundNo()));
// 金额转换
String refundAmount = String.valueOf(amount*0.01);
String refundAmount = String.valueOf(refundOrder.getAmount()*0.01);
refundModel.setRefundAmount(refundAmount);
// 设置退款信息

View File

@@ -84,14 +84,14 @@ public class UnionPayCallbackService extends AbsCallbackStrategy {
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
// 网关订单
callbackInfo.setOutOrderNo(callbackParam.get(QUERY_ID));
// 支付订单ID
callbackInfo.setOrderId(Long.valueOf(callbackParam.get(ORDER_ID)));
// 网关支付
callbackInfo.setOutTradeNo(callbackParam.get(QUERY_ID));
// 支付
callbackInfo.setTradeNo(callbackParam.get(ORDER_ID));
// 支付结果
String resultCode = callbackParam.get(UnionPayCode.RESP_CODE);
PayStatusEnum payStatus = UnionPayCode.RESP_SUCCESS.equals(resultCode) ? PayStatusEnum.SUCCESS : PayStatusEnum.FAIL;
// 支付状态
callbackInfo.setOutStatus(payStatus.getCode());
// 支付金额
callbackInfo.setAmount(callbackParam.get(UnionPayCode.TXN_AMT));
@@ -114,13 +114,12 @@ public class UnionPayCallbackService extends AbsCallbackStrategy {
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
// 网关订单
callbackInfo.setOutOrderNo(callbackParam.get(QUERY_ID));
// 退款订单Id
callbackInfo.setOrderId(Long.valueOf(callbackParam.get(ORDER_ID)));
// 网关退款
callbackInfo.setOutTradeNo(callbackParam.get(QUERY_ID));
// 退款订单
callbackInfo.setTradeNo(callbackParam.get(ORDER_ID));
// 退款金额
callbackInfo.setAmount(callbackParam.get(TXN_AMT));
// 交易状态
String resultCode = callbackParam.get(UnionPayCode.RESP_CODE);
RefundStatusEnum refundStatus = UnionPayCode.RESP_SUCCESS.equals(resultCode) ? RefundStatusEnum.SUCCESS : RefundStatusEnum.FAIL;

View File

@@ -28,10 +28,10 @@ public class UnionPayRefundService {
/**
* 退款方法
*/
public void refund(RefundOrder refundOrder, PayOrder payOrder, int amount, UnionPayKit unionPayKit) {
public void refund(RefundOrder refundOrder, PayOrder payOrder,UnionPayKit unionPayKit) {
// 金额转换
BigDecimal refundAmount = BigDecimal.valueOf(amount * 0.01);
BigDecimal refundAmount = BigDecimal.valueOf(refundOrder.getAmount() * 0.01);
BigDecimal orderAmount = BigDecimal.valueOf(payOrder.getAmount() * 0.01);
UnionRefundOrder unionRefundOrder = new UnionRefundOrder();

View File

@@ -84,10 +84,10 @@ public class WeChatPayCallbackService extends AbsCallbackStrategy {
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
// 网关订单
callbackInfo.setOutOrderNo(callbackParam.get(TRANSACTION_ID));
// 支付订单ID
callbackInfo.setOrderId(Long.valueOf(callbackParam.get(OUT_TRADE_NO)));
// 网关支付
callbackInfo.setOutTradeNo(callbackParam.get(TRANSACTION_ID));
// 支付
callbackInfo.setTradeNo(callbackParam.get(OUT_TRADE_NO));
// 支付状态
PayStatusEnum payStatus = WxPayKit.codeIsOk(callbackParam.get(RESULT_CODE)) ? PayStatusEnum.SUCCESS : PayStatusEnum.FAIL;
callbackInfo.setOutStatus(payStatus.getCode());
@@ -119,9 +119,9 @@ public class WeChatPayCallbackService extends AbsCallbackStrategy {
callbackParam = WxPayKit.xmlToMap(decryptData);
callbackInfo.setCallbackParam(callbackParam);
// 网关订单号
callbackInfo.setOutOrderNo(callbackParam.get(CALLBACK_REFUND_ID));
callbackInfo.setOutTradeNo(callbackParam.get(CALLBACK_REFUND_ID));
// 退款订单Id
callbackInfo.setOrderId(Long.valueOf(callbackParam.get(CALLBACK_OUT_REFUND_NO)));
callbackInfo.setTradeNo(callbackParam.get(CALLBACK_OUT_REFUND_NO));
// 退款金额
callbackInfo.setAmount(callbackParam.get(CALLBACK_REFUND_FEE));

View File

@@ -36,8 +36,8 @@ public class WechatPayRefundService {
* 退款方法
* 微信需要同时传输订单金额或退款金额
*/
public void refund(RefundOrder refundOrder, int amount, WeChatPayConfig weChatPayConfig) {
String refundFee = String.valueOf(amount);
public void refund(RefundOrder refundOrder, WeChatPayConfig weChatPayConfig) {
String refundFee = String.valueOf(refundOrder.getRefundNo());
String totalFee = String.valueOf(refundOrder.getAmount());
// 设置退款信息
RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();

View File

@@ -31,6 +31,13 @@ public class AllocationOrderManager extends BaseManager<AllocationOrderMapper, A
return findByField(AllocationOrder::getAllocationNo, allocationNo);
}
/**
* 根据商户分账号查询
*/
public Optional<AllocationOrder> findByBizAllocationNo(String bizAllocationNo){
return findByField(AllocationOrder::getBizAllocationNo, bizAllocationNo);
}
/**
* 分页
*/

View File

@@ -9,8 +9,6 @@ import cn.bootx.platform.daxpay.service.core.order.allocation.convert.Allocation
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import cn.bootx.table.modify.mysql.constants.MySqlIndexType;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -19,6 +17,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* 分账订单
* @author xxm
@@ -31,25 +31,45 @@ import lombok.experimental.Accessors;
@TableName("pay_allocation_order")
public class AllocationOrder extends MpBaseEntity implements EntityBaseFunction<AllocationOrderDto> {
/**
* 分账订单号(传输给三方支付系统做关联)
*/
@DbColumn(comment = "分账订单号")
private String orderNo;
/**
* 分账单号
*/
@DbMySqlIndex(comment = "分账单号索引", type = MySqlIndexType.UNIQUE)
@DbColumn(comment = "分账单号")
private String allocationNo;
/**
* 商户分账单号
*/
@DbColumn(comment = "商户分账单号")
private String bizAllocationNo;
/**
* 支付订单ID
* 三方系统分账单号
*/
@DbColumn(comment = "网关分账单号")
private String outAllocationNo;
/** 支付订单ID */
@DbColumn(comment = "支付订单ID")
private Long paymentId;
private Long orderId;
/**
* 支付订单号
*/
@DbColumn(comment = "支付订单号")
private String orderNo;
/**
* 商户支付订单号
*/
@DbColumn(comment = "商户支付订单号")
private String bizOrderNo;
/**
* 三方系统支付订单号
*/
@DbColumn(comment = "网关支付订单号")
private String outOrderNo;
/**
* 支付订单标题
@@ -57,17 +77,6 @@ public class AllocationOrder extends MpBaseEntity implements EntityBaseFunction<
@Schema(description = "支付订单标题")
private String title;
/**
* 网关支付订单号
*/
@DbColumn(comment = "网关支付订单号")
private String gatewayPayOrderNo;
/**
* 网关分账单号
*/
@DbColumn(comment = "网关分账单号")
private String gatewayAllocationNo;
/**
* 所属通道
@@ -103,12 +112,23 @@ public class AllocationOrder extends MpBaseEntity implements EntityBaseFunction<
private String result;
/**
* 错误原因
* 错误
*/
@DbColumn(comment = "错误码")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String errorCode;
/**
* 错误信息
*/
@DbColumn(comment = "错误原因")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String errorMsg;
/** 分账完成时间 */
@DbColumn(comment = "分账完成时间")
private LocalDateTime finishTime;
/**
* 转换
*/

View File

@@ -22,9 +22,9 @@ import cn.bootx.platform.daxpay.service.dto.allocation.AllocationGroupReceiverRe
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDetailDto;
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDto;
import cn.bootx.platform.daxpay.service.param.order.AllocationOrderQuery;
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -96,12 +96,6 @@ public class AllocationOrderService {
public OrderAndDetail createAndUpdate(AllocationStartParam param, PayOrder payOrder, int orderAmount, List<AllocationGroupReceiverResult> receiversByGroups){
long orderId = IdUtil.getSnowflakeNextId();
// 请求号不存在使用订单ID
String allocationNo = param.getAllocationNo();
if (StrUtil.isBlank(allocationNo)){
allocationNo = String.valueOf(orderId);
}
// 订单明细
List<AllocationOrderDetail> details = receiversByGroups.stream()
.map(o -> {
@@ -126,12 +120,14 @@ public class AllocationOrderService {
.reduce(0, Integer::sum);
// 分账订单
AllocationOrder allocationOrder = new AllocationOrder()
.setPaymentId(payOrder.getId())
.setOrderId(payOrder.getId())
.setOrderNo(payOrder.getOrderNo())
.setBizOrderNo(payOrder.getBizOrderNo())
.setOutOrderNo(payOrder.getOutOrderNo())
.setTitle(payOrder.getTitle())
.setAllocationNo(allocationNo)
.setChannel(payOrder.getAsyncChannel())
.setGatewayPayOrderNo(payOrder.getGatewayOrderNo())
.setOrderNo(String.valueOf(orderId))
.setAllocationNo(OrderNoGenerateUtil.allocation())
.setBizAllocationNo(param.getBizAllocationNo())
.setChannel(payOrder.getChannel())
.setDescription(param.getDescription())
.setStatus(AllocationOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
.setAmount(sumAmount);

View File

@@ -3,15 +3,12 @@ package cn.bootx.platform.daxpay.service.core.order.pay.builder;
import cn.bootx.platform.daxpay.code.PayOrderAllocationStatusEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.param.payment.pay.PayParam;
import cn.bootx.platform.daxpay.result.pay.PayResult;
import cn.bootx.platform.daxpay.service.common.context.NoticeLocal;
import cn.bootx.platform.daxpay.service.common.context.PayLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.experimental.UtilityClass;
@@ -37,7 +34,7 @@ public class PayBuilder {
// 构建支付订单对象
PayOrder payOrder = new PayOrder()
.setBizOrderNo(payParam.getBizOrderNo())
.setOrderNo(OrderNoGenerateUtil.trade())
.setOrderNo(OrderNoGenerateUtil.pay())
.setTitle(payParam.getTitle())
.setDescription(payParam.getDescription())
.setStatus(PayStatusEnum.PROGRESS.getCode())
@@ -76,24 +73,4 @@ public class PayBuilder {
return payOrderExtra;
}
/**
* 根据支付订单构建支付结果
* @param payOrder 支付订单
* @return PayResult 支付结果
*/
public PayResult buildResultByPayOrder(PayOrder payOrder) {
PayResult payResult;
payResult = new PayResult();
payResult.setBizOrderNo(payOrder.getBizOrderNo());
payResult.setOrderNo(payOrder.getOrderNo());
payResult.setStatus(payOrder.getStatus());
// 设置支付参数
PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo();;
if (StrUtil.isNotBlank(asyncPayInfo.getPayBody())) {
payResult.setPayBody(asyncPayInfo.getPayBody());
}
return payResult;
}
}

View File

@@ -1,10 +1,7 @@
package cn.bootx.platform.daxpay.service.core.order.pay.convert;
import cn.bootx.platform.daxpay.result.order.PayChannelOrderResult;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayChannelOrderDto;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderExtraDto;
import org.mapstruct.Mapper;
@@ -23,7 +20,4 @@ public interface PayOrderConvert {
PayOrderDto convert(PayOrder in);
PayChannelOrderDto convert(PayChannelOrder in);
PayChannelOrderResult convertResult(PayChannelOrder in);
}

View File

@@ -1,58 +0,0 @@
package cn.bootx.platform.daxpay.service.core.order.pay.dao;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 支付订单关联支付时通道信息
* @author xxm
* @since 2023/12/20
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class PayChannelOrderManager extends BaseManager<PayChannelOrderMapper, PayChannelOrder> {
/**
* 根据订单查找
*/
public List<PayChannelOrder> findAllByPaymentId(String orderNo){
return findAllByField(PayChannelOrder::getPaymentId,orderNo);
}
/**
* 根据订单id和支付通道查询
*/
public Optional<PayChannelOrder> findByPaymentIdAndChannel(Long paymentId, String channel) {
return lambdaQuery()
.eq(PayChannelOrder::getPaymentId,paymentId)
.eq(PayChannelOrder::getChannel,channel)
.oneOpt();
}
/**
* 根据订单id和支付通道查询
*/
public Optional<PayChannelOrder> findByAsyncChannel(Long paymentId) {
return lambdaQuery()
.eq(PayChannelOrder::getPaymentId,paymentId)
.eq(PayChannelOrder::isAsync,true)
.oneOpt();
}
/**
* 根据订单id删除异步支付记录
*/
public void deleteByPaymentIdAndAsync(String orderNo){
lambdaUpdate()
.eq(PayChannelOrder::getPaymentId,orderNo)
.eq(PayChannelOrder::isAsync,true)
.remove();
}
}

View File

@@ -1,14 +0,0 @@
package cn.bootx.platform.daxpay.service.core.order.pay.dao;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 通道支付订单
* @author xxm
* @since 2023/12/20
*/
@Mapper
public interface PayChannelOrderMapper extends BaseMapper<PayChannelOrder> {
}

View File

@@ -1,81 +0,0 @@
package cn.bootx.platform.daxpay.service.core.order.pay.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
import cn.bootx.platform.daxpay.param.channel.WeChatPayParam;
import cn.bootx.platform.daxpay.service.core.order.pay.convert.PayOrderConvert;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayChannelOrderDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
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.time.LocalDateTime;
/**
* 关联支付订单支付时通道信息
* @author xxm
* @since 2023/12/18
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@DbTable(comment = "支付订单关联支付时通道信息")
@TableName("pay_channel_order")
@Deprecated
public class PayChannelOrder extends MpCreateEntity implements EntityBaseFunction<PayChannelOrderDto> {
@DbColumn(comment = "支付id")
private String paymentId;
@DbColumn(comment = "异步支付方式")
private boolean async;
@DbColumn(comment = "通道")
private String channel;
@DbColumn(comment = "支付方式")
private String payWay;
@DbColumn(comment = "金额")
private Integer amount;
@DbColumn(comment = "可退款金额")
private Integer refundableBalance;
/**
* 支付状态
* @see PayStatusEnum
*/
@DbColumn(comment = "支付状态")
private String status;
@DbColumn(comment = "支付完成时间")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime payTime;
/**
* @see AliPayParam
* @see WeChatPayParam
* @see WalletPayParam
*/
@DbColumn(comment = "附加支付参数")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String channelExtra;
/**
* 转换
*/
@Override
public PayChannelOrderDto toDto() {
return PayOrderConvert.CONVERT.convert(this);
}
}

View File

@@ -8,7 +8,6 @@ import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.payment.pay.QueryPayParam;
import cn.bootx.platform.daxpay.result.order.PayOrderResult;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderExtraManager;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
@@ -36,7 +35,6 @@ import java.util.Optional;
public class PayOrderQueryService {
private final PayOrderManager payOrderManager;
private final PayOrderExtraManager payOrderExtraManager;
private final PayChannelOrderManager payChannelOrderManager;
/**
* 分页
@@ -67,6 +65,21 @@ public class PayOrderQueryService {
return payOrderManager.findByBizOrderNo(bizOrderNo);
}
/**
* 根据订单号或商户订单号查询
*/
public Optional<PayOrder> findByBizOrOrderNo(String orderNo, String bizOrderNo) {
if (Objects.nonNull(orderNo)){
return this.findByOrderNo(orderNo);
}
if (Objects.nonNull(bizOrderNo)){
return this.findByBizOrderNo(bizOrderNo);
}
return Optional.empty();
}
/**
* 查询支付记录
*/

View File

@@ -1,8 +1,5 @@
package cn.bootx.platform.daxpay.service.core.order.refund.convert;
import cn.bootx.platform.daxpay.result.order.RefundChannelOrderResult;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundChannelOrderDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@@ -15,9 +12,4 @@ import org.mapstruct.factory.Mappers;
public interface RefundOrderChannelConvert {
RefundOrderChannelConvert CONVERT = Mappers.getMapper(RefundOrderChannelConvert.class);
RefundChannelOrderDto convert(RefundChannelOrder in);
RefundChannelOrderResult convertResult(RefundChannelOrder in);
}

View File

@@ -1,39 +0,0 @@
package cn.bootx.platform.daxpay.service.core.order.refund.dao;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 通道退款订单
* @author xxm
* @since 2024/1/17
*/
@Slf4j
@Repository
@RequiredArgsConstructor
@Deprecated
public class RefundChannelOrderManager extends BaseManager<RefundChannelOrderMapper, RefundChannelOrder> {
/**
* 根据退款单ID查找
*/
public List<RefundChannelOrder> findAllByRefundId(Long paymentId){
return findAllByField(RefundChannelOrder::getRefundId,paymentId);
}
/**
* 根据退款单ID和退款通道查询
*/
public Optional<RefundChannelOrder> findByRefundIdAndChannel(Long refundId, String channel) {
return lambdaQuery()
.eq(RefundChannelOrder::getRefundId,refundId)
.eq(RefundChannelOrder::getChannel,channel)
.oneOpt();
}
}

View File

@@ -1,15 +0,0 @@
package cn.bootx.platform.daxpay.service.core.order.refund.dao;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
*
* @author xxm
* @since 2024/1/17
*/
@Mapper
@Deprecated
public interface RefundChannelOrderMapper extends BaseMapper<RefundChannelOrder> {
}

View File

@@ -1,71 +0,0 @@
package cn.bootx.platform.daxpay.service.core.order.refund.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
import cn.bootx.platform.daxpay.service.core.order.refund.convert.RefundOrderChannelConvert;
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundChannelOrderDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
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.time.LocalDateTime;
/**
* 支付退款订单关联通道信息
* @author xxm
* @since 2024/1/17
*/
@EqualsAndHashCode(callSuper = true)
@Data
@DbTable(comment = "支付退款通道订单")
@Accessors(chain = true)
@Deprecated
@TableName("pay_refund_channel_order")
public class RefundChannelOrder extends MpCreateEntity implements EntityBaseFunction<RefundChannelOrderDto> {
@DbColumn(comment = "关联退款id")
private Long refundId;
@DbColumn(comment = "通道支付单id")
private Long payChannelId;
@DbColumn(comment = "通道")
private String channel;
@DbColumn(comment = "异步支付方式")
private boolean async;
@DbColumn(comment = "订单金额")
private Integer orderAmount;
@DbColumn(comment = "退款金额")
private Integer amount;
@DbColumn(comment = "剩余可退余额")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private Integer refundableAmount;
/**
* 退款状态
* @see RefundStatusEnum
*/
@DbColumn(comment = "退款状态")
private String status;
@DbColumn(comment = "退款完成时间")
private LocalDateTime refundTime;
/**
* 转换
*/
@Override
public RefundChannelOrderDto toDto() {
return RefundOrderChannelConvert.CONVERT.convert(this);
}
}

View File

@@ -9,20 +9,15 @@ import cn.bootx.platform.common.spring.util.WebServletUtil;
import cn.bootx.platform.daxpay.code.PaymentApiCode;
import cn.bootx.platform.daxpay.param.payment.refund.QueryRefundParam;
import cn.bootx.platform.daxpay.param.payment.refund.RefundParam;
import cn.bootx.platform.daxpay.result.order.RefundChannelOrderResult;
import cn.bootx.platform.daxpay.result.order.RefundOrderResult;
import cn.bootx.platform.daxpay.service.core.order.refund.convert.RefundOrderChannelConvert;
import cn.bootx.platform.daxpay.service.core.order.refund.convert.RefundOrderConvert;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundChannelOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import cn.bootx.platform.daxpay.service.core.payment.common.service.PaymentAssistService;
import cn.bootx.platform.daxpay.service.core.payment.refund.service.RefundService;
import cn.bootx.platform.daxpay.service.core.system.config.dao.PayApiConfigManager;
import cn.bootx.platform.daxpay.service.core.system.config.entity.PayApiConfig;
import cn.bootx.platform.daxpay.service.core.system.config.service.PayApiConfigService;
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundChannelOrderDto;
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderDto;
import cn.bootx.platform.daxpay.service.param.order.PayOrderRefundParam;
import cn.bootx.platform.daxpay.service.param.order.RefundOrderQuery;
@@ -34,10 +29,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 退款
@@ -73,25 +66,6 @@ public class RefundOrderService {
.orElseThrow(() -> new DataNotExistException("退款订单不存在"));
}
/**
* 通道退款订单列表查询
*/
public List<RefundChannelOrderDto> listByChannel(Long refundId){
List<RefundChannelOrder> refundOrderChannels = refundOrderChannelManager.findAllByRefundId(refundId);
return refundOrderChannels.stream()
.map(RefundOrderChannelConvert.CONVERT::convert)
.collect(Collectors.toList());
}
/**
* 查询通道退款订单详情
*/
public RefundChannelOrderDto findChannelById(Long id) {
return refundOrderChannelManager.findById(id)
.map(RefundChannelOrder::toDto)
.orElseThrow(() -> new DataNotExistException("通道退款订单不存在"));
}
/**
* 查询退款订单
*/
@@ -111,16 +85,8 @@ public class RefundOrderService {
refundOrder = refundOrderManager.findByRefundNo(param.getRefundNo())
.orElseThrow(() -> new DataNotExistException("未查询到支付订单"));
}
// 查询退款明细
List<RefundChannelOrder> refundOrderChannels = refundOrderChannelManager.findAllByRefundId(refundOrder.getId());
List<RefundChannelOrderResult> channels = refundOrderChannels.stream()
.map(RefundOrderChannelConvert.CONVERT::convertResult)
.collect(Collectors.toList());
RefundOrderResult refundOrderResult = RefundOrderConvert.CONVERT.convertResult(refundOrder);
refundOrderResult.setRefundId(refundOrder.getId());
refundOrderResult.setChannels(channels);
return refundOrderResult;
return RefundOrderConvert.CONVERT.convertResult(refundOrder);
}
/**
@@ -133,11 +99,10 @@ public class RefundOrderService {
.orElse("未知");
RefundParam refundParam = new RefundParam();
refundParam.setPaymentId(param.getPaymentId());
refundParam.setOrderNo(param.getOrderNo());
refundParam.setReason(param.getReason());
refundParam.setReqTime(LocalDateTime.now());
refundParam.setClientIp(ip);
refundParam.setRefundAll(true);
// 手动初始化上下文
paymentAssistService.initContext(refundParam);
// 初始化接口信息为统一退款

View File

@@ -18,10 +18,9 @@ import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationO
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrderDetail;
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.OrderAndDetail;
import cn.bootx.platform.daxpay.service.core.order.allocation.service.AllocationOrderService;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
import cn.bootx.platform.daxpay.service.core.payment.allocation.dao.AllocationGroupManager;
import cn.bootx.platform.daxpay.service.core.payment.allocation.entity.AllocationGroup;
import cn.bootx.platform.daxpay.service.core.payment.allocation.factory.AllocationFactory;
@@ -50,8 +49,6 @@ public class AllocationService {
private final PayOrderManager payOrderManager;
private final PayChannelOrderManager payChannelOrderManager;
private final AllocationGroupManager groupManager;
private final AllocationOrderManager allocationOrderManager;
@@ -61,33 +58,28 @@ public class AllocationService {
private final AllocationOrderService allocationOrderService;
private final AllocationOrderDetailManager allocationOrderDetailManager;
private final PayOrderQueryService payOrderQueryService;
/**
* 开启分账, 使用分账组进行分账
*/
public AllocationResult allocation(AllocationStartParam param) {
PayOrder payOrder = this.getAndCheckPayOrder(param);
// 查询待分账的通道支付订单
PayChannelOrder channelOrder = payChannelOrderManager.findByAsyncChannel(payOrder.getId())
.orElseThrow(() -> new DataNotExistException("未查询到支付通道订单"));
// 查询分账组 未传输使用默认该通道默认分账组
AllocationGroup allocationGroup;
if (Objects.nonNull(param.getAllocationGroupId())) {
allocationGroup = groupManager.findById(param.getAllocationGroupId()).orElseThrow(() -> new DataNotExistException("未查询到分账组"));
} else {
allocationGroup = groupManager.findDefaultGroup(payOrder.getAsyncChannel()).orElseThrow(() -> new DataNotExistException("未查询到默认分账组"));
allocationGroup = groupManager.findDefaultGroup(payOrder.getChannel()).orElseThrow(() -> new DataNotExistException("未查询到默认分账组"));
}
List<AllocationGroupReceiverResult> receiversByGroups = allocationGroupService.findReceiversByGroups(allocationGroup.getId());
// 创建分账单和明细并保存, 同时更新支付订单状态 使用事务
OrderAndDetail orderAndDetail = allocationOrderService.createAndUpdate(param ,payOrder, channelOrder.getAmount(), receiversByGroups);
OrderAndDetail orderAndDetail = allocationOrderService.createAndUpdate(param ,payOrder, payOrder.getAmount(), receiversByGroups);
// 创建分账策略并初始化
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(payOrder.getAsyncChannel());
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(payOrder.getChannel());
AllocationOrder order = orderAndDetail.getOrder();
List<AllocationOrderDetail> details = orderAndDetail.getDetails();
allocationStrategy.initParam(order, details);
@@ -108,8 +100,8 @@ public class AllocationService {
// 网关分账号
String gatewayNo = PaymentContextLocal.get()
.getAllocationInfo()
.getGatewayNo();
order.setGatewayAllocationNo(gatewayNo);
.getOutAllocationNo();
order.setOutAllocationNo(gatewayNo);
allocationOrderManager.updateById(order);
return new AllocationResult().setOrderId(order.getId())
@@ -204,8 +196,8 @@ public class AllocationService {
public void sync(AllocationSyncParam param) {
// 获取分账订单
AllocationOrder allocationOrder = null;
if (Objects.nonNull(param.getAllocationId())){
allocationOrder = allocationOrderManager.findById(param.getAllocationId())
if (Objects.nonNull(param.getAllocationNo())){
allocationOrder = allocationOrderManager.findById(param.getBizAllocationNo())
.orElseThrow(() -> new DataNotExistException("分账单不存在"));
}
if (Objects.isNull(allocationOrder)){
@@ -273,15 +265,8 @@ public class AllocationService {
*/
private PayOrder getAndCheckPayOrder(AllocationStartParam param) {
// 查询支付单
PayOrder payOrder = null;
if (Objects.nonNull(param.getPaymentId())){
payOrder = payOrderManager.findById(param.getPaymentId())
.orElseThrow(() -> new DataNotExistException("未查询到支付订单"));
}
if (StrUtil.isNotBlank(param.getBusinessNo())){
payOrder = payOrderManager.findByBusinessNo(param.getBusinessNo())
.orElseThrow(() -> new DataNotExistException("未查询到支付订单"));
}
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getOrderNo(), param.getBizOrderNo())
.orElseThrow(() -> new DataNotExistException("支付单不存在"));
// 判断订单是否可以分账
if (!payOrder.isAllocation()){
throw new PayFailureException("该订单不允许分账");

View File

@@ -42,22 +42,22 @@ public class PayCallbackService {
public void payCallback() {
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
// 加锁
LockInfo lock = lockTemplate.lock("callback:payment:" + callbackInfo.getOrderId(),10000, 200);
LockInfo lock = lockTemplate.lock("callback:payment:" + callbackInfo.getTradeNo(),10000, 200);
if (Objects.isNull(lock)){
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.IGNORE).setMsg("回调正在处理中,忽略本次回调请求");
log.warn("订单号: {} 回调正在处理中,忽略本次回调请求", callbackInfo.getOrderId());
log.warn("订单号: {} 回调正在处理中,忽略本次回调请求", callbackInfo.getTradeNo());
return;
}
try {
// 获取支付单
PayOrder payOrder = payOrderQueryService.findById(callbackInfo.getOrderId()).orElse(null);
PayOrder payOrder = payOrderQueryService.findByOrderNo(callbackInfo.getTradeNo()).orElse(null);
// 本地支付单不存在,记录回调记录, TODO 需要补单或进行退款
if (Objects.isNull(payOrder)) {
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.NOT_FOUND).setMsg("支付单不存在,记录回调记录");
return;
}
// 设置订单关联网关订单号
payOrder.setGatewayOrderNo(callbackInfo.getOutOrderNo());
payOrder.setOutOrderNo(callbackInfo.getOutTradeNo());
// 成功状态
if (Objects.equals(PayCallbackStatusEnum.SUCCESS.getCode(), callbackInfo.getOutStatus())) {
@@ -97,7 +97,7 @@ public class PayCallbackService {
PaymentContextLocal.get().getRepairInfo().setFinishTime(callbackInfo.getFinishTime());
// 执行支付完成修复逻辑
PayRepairResult repair = payRepairService.repair(payOrder, PayRepairWayEnum.PAY_SUCCESS);
callbackInfo.setPayRepairNo(repair.getRepairNo());
callbackInfo.setRepairNo(repair.getRepairNo());
}
/**
@@ -117,7 +117,7 @@ public class PayCallbackService {
}
// 执行支付关闭修复逻辑
PayRepairResult repair = payRepairService.repair(payOrder, PayRepairWayEnum.CLOSE_LOCAL);
callbackInfo.setPayRepairNo(repair.getRepairNo());
callbackInfo.setRepairNo(repair.getRepairNo());
}
}

View File

@@ -39,15 +39,15 @@ public class RefundCallbackService {
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
// 加锁
LockInfo lock = lockTemplate.lock("callback:refund:" + callbackInfo.getOrderId(),10000, 200);
LockInfo lock = lockTemplate.lock("callback:refund:" + callbackInfo.getTradeNo(),10000, 200);
if (Objects.isNull(lock)){
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.IGNORE).setMsg("回调正在处理中,忽略本次回调请求");
log.warn("订单号: {} 回调正在处理中,忽略本次回调请求", callbackInfo.getOrderId());
log.warn("订单号: {} 回调正在处理中,忽略本次回调请求", callbackInfo.getTradeNo());
return;
}
try {
// 获取退款单
RefundOrder refundOrder = refundOrderManager.findById(callbackInfo.getOrderId()).orElse(null);
RefundOrder refundOrder = refundOrderManager.findByRefundNo(callbackInfo.getTradeNo()).orElse(null);
// 退款单不存在,记录回调记录
if (Objects.isNull(refundOrder)) {
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.NOT_FOUND).setMsg("退款单不存在,记录回调记录");
@@ -63,10 +63,10 @@ public class RefundCallbackService {
if (Objects.equals(RefundStatusEnum.SUCCESS.getCode(), callbackInfo.getOutStatus())) {
PaymentContextLocal.get().getRepairInfo().setFinishTime(callbackInfo.getFinishTime());
RefundRepairResult repair = reflectionService.repair(refundOrder, RefundRepairWayEnum.REFUND_SUCCESS);
callbackInfo.setPayRepairNo(repair.getRepairNo());
callbackInfo.setRepairNo(repair.getRepairNo());
} else {
RefundRepairResult repair = reflectionService.repair(refundOrder, RefundRepairWayEnum.REFUND_FAIL);
callbackInfo.setPayRepairNo(repair.getRepairNo());
callbackInfo.setRepairNo(repair.getRepairNo());
}
} finally {

View File

@@ -2,20 +2,12 @@ package cn.bootx.platform.daxpay.service.core.payment.close.factory;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
import cn.bootx.platform.daxpay.service.core.payment.close.strategy.*;
import cn.bootx.platform.daxpay.service.core.payment.close.strategy.AliPayCloseStrategy;
import cn.bootx.platform.daxpay.service.core.payment.close.strategy.UnionPayCloseStrategy;
import cn.bootx.platform.daxpay.service.core.payment.close.strategy.WeChatPayCloseStrategy;
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
import lombok.val;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.bootx.platform.daxpay.code.PayChannelEnum.ASYNC_TYPE_CODE;
/**
* 支付关闭策略工厂
@@ -29,8 +21,8 @@ public class PayCloseStrategyFactory {
* 根据传入的支付通道创建策略
* @return 支付策略
*/
public static AbsPayCloseStrategy create(PayChannelEnum channelEnum) {
public static AbsPayCloseStrategy create(String channel) {
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
AbsPayCloseStrategy strategy;
switch (channelEnum) {
case ALI:
@@ -50,59 +42,4 @@ public class PayCloseStrategyFactory {
}
return strategy;
}
/**
* 根据传入的支付类型批量创建策略, 异步支付在后面
*/
public static List<AbsPayCloseStrategy> createAsyncLast(List<String> channelCodes) {
return create(channelCodes, true);
}
/**
* 根据传入的支付类型批量创建策略, 异步支付在前面
*/
public static List<AbsPayCloseStrategy> createAsyncFront(List<String> channelCodes) {
return create(channelCodes, false);
}
/**
* 根据传入的支付类型批量创建策略
* @param asyncSort 是否异步支付在后面
* @return 支付策略
*/
private static List<AbsPayCloseStrategy> create(List<String> channelCodes, boolean asyncSort) {
if (CollectionUtil.isEmpty(channelCodes)) {
return Collections.emptyList();
}
// 同步支付
val syncChannels = channelCodes.stream()
.filter(code -> !ASYNC_TYPE_CODE.contains(code))
.map(PayChannelEnum::findByCode)
.collect(Collectors.toList());
// 异步支付
val asyncChannels = channelCodes.stream()
.filter(ASYNC_TYPE_CODE::contains)
.map(PayChannelEnum::findByCode)
.collect(Collectors.toList());
List<PayChannelEnum> sortList = new ArrayList<>(channelCodes.size());
// 异步在后面
if (asyncSort) {
sortList.addAll(syncChannels);
sortList.addAll(asyncChannels);
}
else {
sortList.addAll(asyncChannels);
sortList.addAll(syncChannels);
}
// 此处有一个根据Type的反转排序
return sortList.stream()
.filter(Objects::nonNull)
.map(PayCloseStrategyFactory::create)
.collect(Collectors.toList());
}
}

View File

@@ -1,14 +1,13 @@
package cn.bootx.platform.daxpay.service.core.payment.close.service;
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.common.core.function.CollectorsFunction;
import cn.bootx.platform.daxpay.code.PaySignTypeEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
import cn.bootx.platform.daxpay.param.payment.pay.PayCloseParam;
import cn.bootx.platform.daxpay.result.pay.PayCloseResult;
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
@@ -17,7 +16,7 @@ import cn.bootx.platform.daxpay.service.core.payment.notice.service.ClientNotice
import cn.bootx.platform.daxpay.service.core.record.close.entity.PayCloseRecord;
import cn.bootx.platform.daxpay.service.core.record.close.service.PayCloseRecordService;
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
import cn.hutool.core.collection.CollectionUtil;
import cn.bootx.platform.daxpay.util.PaySignUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
@@ -26,11 +25,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 支付关闭和撤销服务
@@ -41,7 +36,6 @@ import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class PayCloseService {
private final PayChannelOrderManager payChannelOrderManager;
private final PayOrderService payOrderService;
private final PayOrderQueryService payOrderQueryService;
private final PayCloseRecordService payCloseRecordService;
@@ -53,22 +47,15 @@ public class PayCloseService {
* 关闭支付
*/
@Transactional(rollbackFor = Exception.class)
public void close(PayCloseParam param){
PayOrder payOrder = null;
if (Objects.nonNull(param.getPaymentId())){
payOrder = payOrderQueryService.findById(param.getPaymentId())
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
}
if (Objects.isNull(payOrder)){
payOrder = payOrderQueryService.findByBizOrderNo(param.getBusinessNo())
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
}
public PayCloseResult close(PayCloseParam param){
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getOrderNo(), param.getBizTradeNo())
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
LockInfo lock = lockTemplate.lock("payment:close:" + payOrder.getId(),10000, 50);
if (Objects.isNull(lock)){
throw new RepetitiveOperationException("支付订单已在关闭中,请勿重复发起");
}
try {
this.close(payOrder);
return this.close(payOrder);
} finally {
lockTemplate.releaseLock(lock);
}
@@ -77,69 +64,42 @@ public class PayCloseService {
/**
* 关闭支付记录
*/
private void close(PayOrder payOrder) {
List<PayChannelOrder> payChannelOrders;
private PayCloseResult close(PayOrder payOrder) {
try {
// 状态检查, 只有支付中可以进行取消支付
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())) {
throw new PayFailureException("订单不是支付中, 无法进行关闭订单");
}
// 0.基础数据准备
Map<String, PayChannelOrder> orderChannelMap = payChannelOrderManager.findAllByPaymentId(payOrder.getOrderNo())
.stream()
.collect(Collectors.toMap(PayChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
// 1.获取支付方式, 通过工厂生成对应的策略
List<String> channels = orderChannelMap.values()
.stream()
.map(PayChannelOrder::getChannel)
.collect(Collectors.toList());
List<AbsPayCloseStrategy> payCloseStrategies = PayCloseStrategyFactory.createAsyncLast(channels);
if (CollectionUtil.isEmpty(payCloseStrategies)) {
throw new PayUnsupportedMethodException();
}
// 2.初始化关闭支付的参数
for (AbsPayCloseStrategy strategy : payCloseStrategies) {
strategy.initCloseParam(payOrder, orderChannelMap.get(strategy.getChannel()
.getCode()));
}
// 3.关闭前准备
payCloseStrategies.forEach(AbsPayCloseStrategy::doBeforeCloseHandler);
// 4.执行关闭策略
payCloseStrategies.forEach(AbsPayCloseStrategy::doCloseHandler);
// 5.关闭成功后处理
payCloseStrategies.forEach(AbsPayCloseStrategy::doSuccessHandler);
// 6.更新支付通道订单的状态
payChannelOrders = payCloseStrategies.stream()
.map(AbsPayCloseStrategy::getChannelOrder)
.collect(Collectors.toList());
payChannelOrderManager.updateAllById(payChannelOrders);
} catch (PayFailureException e) {
AbsPayCloseStrategy strategy = PayCloseStrategyFactory.create(payOrder.getChannel());
// 设置支付订单
strategy.setOrder(payOrder);
// 关闭前准备
strategy.doBeforeCloseHandler();
// 执行关闭策略
strategy.doCloseHandler();
this.successHandler(payOrder);
// 返回结果
return this.sign(new PayCloseResult());
} catch (Exception e) {
// 记录关闭失败的记录
this.saveRecord(payOrder, false, e.getMessage());
throw e;
PayCloseResult payCloseResult = new PayCloseResult();
payCloseResult.setCode("1").setMsg(e.getMessage());
return this.sign(payCloseResult);
}
// 关闭成功后处理
this.successHandler(payOrder, payChannelOrders);
}
/**
* 成功后处理方法
*/
private void successHandler(PayOrder payOrder, List<PayChannelOrder> payChannelOrders){
private void successHandler(PayOrder payOrder){
// 关闭订单
payOrder.setStatus(PayStatusEnum.CLOSE.getCode())
.setCloseTime(LocalDateTime.now());
payOrderService.updateById(payOrder);
// 发送通知
clientsService.registerPayNotice(payOrder,null, payChannelOrders);
clientsService.registerPayNotice(payOrder,null);
this.saveRecord(payOrder,true,null);
}
@@ -150,18 +110,30 @@ public class PayCloseService {
String clientIp = PaymentContextLocal.get()
.getRequestInfo()
.getClientIp();
String reqId = PaymentContextLocal.get()
.getRequestInfo()
.getReqId();
PayCloseRecord record = new PayCloseRecord()
.setPaymentId(payOrder.getId())
.setBusinessNo(payOrder.getBusinessNo())
.setAsyncChannel(payOrder.getAsyncChannel())
.setOrderNo(payOrder.getOrderNo())
.setBizOrderNo(payOrder.getOutOrderNo())
.setChannel(payOrder.getChannel())
.setClosed(closed)
.setErrorMsg(errMsg)
.setClientIp(clientIp)
.setReqId(reqId);
.setClientIp(clientIp);
payCloseRecordService.saveRecord(record);
}
/**
* 对返回结果进行签名
*/
private PayCloseResult sign(PayCloseResult result){
PlatformLocal platformInfo = PaymentContextLocal.get()
.getPlatformInfo();
String signType = platformInfo.getSignType();
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
result.setSign(PaySignUtil.hmacSha256Sign(result, platformInfo.getSignSecret()));
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
result.setSign(PaySignUtil.md5Sign(result, platformInfo.getSignSecret()));
} else {
throw new PayFailureException("未获取到签名方式,请检查");
}
return result;
}
}

View File

@@ -1,56 +0,0 @@
package cn.bootx.platform.daxpay.service.core.payment.close.strategy;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.Wallet;
import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayService;
import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletQueryService;
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
/**
* 钱包支付关闭策略
* @author xxm
* @since 2023/12/30
*/
@Slf4j
@Scope(SCOPE_PROTOTYPE)
@Service
@RequiredArgsConstructor
public class WalletPayCloseStrategy extends AbsPayCloseStrategy {
private final WalletPayService walletPayService;
private final WalletQueryService walletQueryService;
private Wallet wallet;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WALLET;
}
/**
* 关闭前的处理方式
*/
@Override
public void doBeforeCloseHandler() {
// 从通道扩展参数中取出钱包参数
String channelExtra = this.getChannelOrder().getChannelExtra();
WalletPayParam walletPayParam = JSONUtil.toBean(channelExtra, WalletPayParam.class);
this.wallet = walletQueryService.getWallet(walletPayParam);
}
/**
* 关闭操作
*/
@Override
public void doCloseHandler() {
walletPayService.close(this.getOrder(),this.wallet);
}
}

View File

@@ -1,15 +1,13 @@
package cn.bootx.platform.daxpay.service.core.payment.common.service;
import cn.bootx.platform.common.core.code.CommonCode;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
import cn.bootx.platform.daxpay.service.common.context.RequestLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.system.config.entity.PlatformConfig;
import cn.bootx.platform.daxpay.service.core.system.config.service.PlatformConfigService;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
/**
@@ -53,7 +51,6 @@ public class PaymentAssistService {
RequestLocal request = PaymentContextLocal.get().getRequestInfo();
request.setClientIp(paymentCommonParam.getClientIp())
.setSign(paymentCommonParam.getSign())
.setReqTime(paymentCommonParam.getReqTime())
.setReqId(MDC.get(CommonCode.TRACE_ID));
.setReqTime(paymentCommonParam.getReqTime());
}
}

View File

@@ -9,7 +9,6 @@ import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.List;
/**
*
@@ -21,27 +20,21 @@ import java.util.List;
@Schema(title = "退款通知消息")
public class RefundNoticeResult {
@Schema(description = "退款ID")
private Long refundId;
@Schema(description = "退款号")
private String refundNo;
@Schema(description = "是否含有异步通道")
private boolean asyncPay;
@Schema(description = "商户退款号")
private String bizRefundNo;
/**
* @see PayChannelEnum#ASYNC_TYPE_CODE
* @see PayChannelEnum
*/
@Schema(description = "异步通道")
private String asyncChannel;
private String channel;
@Schema(description = "退款金额")
private Integer amount;
@Schema(description = "退款通道信息")
private List<RefundChannelResult> refundChannels;
/**
* @see RefundStatusEnum
*/

View File

@@ -5,11 +5,9 @@ import cn.bootx.platform.daxpay.code.PaySignTypeEnum;
import cn.bootx.platform.daxpay.service.code.ClientNoticeTypeEnum;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrderExtra;
import cn.bootx.platform.daxpay.service.core.payment.notice.result.PayNoticeResult;
import cn.bootx.platform.daxpay.service.core.payment.notice.result.RefundChannelResult;
import cn.bootx.platform.daxpay.service.core.payment.notice.result.RefundNoticeResult;
import cn.bootx.platform.daxpay.service.core.system.config.entity.PlatformConfig;
import cn.bootx.platform.daxpay.service.core.system.config.service.PlatformConfigService;
@@ -19,9 +17,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 客户系统消息通知任务支撑服务
@@ -76,27 +72,23 @@ public class ClientNoticeAssistService {
*/
public ClientNoticeTask buildRefundTask(RefundOrder order, RefundOrderExtra orderExtra){
// 创建退款通知内容
RefundNoticeResult payNoticeResult = new RefundNoticeResult()
.setRefundId(order.getId())
.setAsyncPay(order.isAsyncPay())
.setAsyncChannel(order.getAsyncChannel())
.setRefundNo(order.getRefundNo())
.setChannel(order.getChannel())
.setAmount(order.getAmount())
.setRefundTime(order.getRefundTime())
.setCreateTime(order.getCreateTime())
.setStatus(order.getStatus())
.setAttach(orderExtra.getAttach())
.setRefundChannels(channels);
.setAttach(orderExtra.getAttach());
PlatformConfig config = configService.getConfig();
// 是否需要签名
if (orderExtra.isNoticeSign()){
// 签名
if (Objects.equals(config.getSignType(), PaySignTypeEnum.MD5.getCode())){
payNoticeResult.setSign(PaySignUtil.md5Sign(payNoticeResult,config.getSignSecret()));
} else {
payNoticeResult.setSign(PaySignUtil.hmacSha256Sign(payNoticeResult,config.getSignSecret()));
}
// 签名
if (Objects.equals(config.getSignType(), PaySignTypeEnum.MD5.getCode())){
payNoticeResult.setSign(PaySignUtil.md5Sign(payNoticeResult,config.getSignSecret()));
} else if (Objects.equals(config.getSignType(), PaySignTypeEnum.HMAC_SHA256.getCode())) {
payNoticeResult.setSign(PaySignUtil.hmacSha256Sign(payNoticeResult,config.getSignSecret()));
} else {
}
return new ClientNoticeTask()
.setUrl(orderExtra.getNotifyUrl())

View File

@@ -36,8 +36,8 @@ public class PayReturnService {
*/
public String alipay(AliPayReturnParam param){
PayOrderExtra payOrderExtra = payOrderExtraManager.findById(param.getOut_trade_no()).orElse(null);
PayOrder prOrder = payOrderQueryService.findById(param.getOut_trade_no()).orElse(null);
if (Objects.isNull(payOrderExtra) || Objects.isNull(prOrder)){
PayOrder payOrder = payOrderQueryService.findById(param.getOut_trade_no()).orElse(null);
if (Objects.isNull(payOrderExtra) || Objects.isNull(payOrder)){
return StrUtil.format("{}/result/error?msg={}", properties.getFrontH5Url(), URLEncodeUtil.encode("支付订单有问题,请排查"));
}
@@ -47,7 +47,7 @@ public class PayReturnService {
returnUrl = platformConfigService.getConfig().getReturnUrl();
}
if (StrUtil.isNotBlank(returnUrl)){
return StrUtil.format("{}?paymentId={}&businessNo={}", payOrderExtra.getReturnUrl(),prOrder.getId(),prOrder.getBusinessNo());
return StrUtil.format("{}?orderNo={}&bizOrderNo={}", payOrderExtra.getReturnUrl(),payOrder.getOrderNo(),payOrder.getBizOrderNo());
}
// 跳转到默认页
return StrUtil.format("{}/result/success?msg={}", properties.getFrontH5Url(), URLEncodeUtil.encode("支付成功..."));
@@ -72,7 +72,7 @@ public class PayReturnService {
returnUrl = platformConfigService.getConfig().getReturnUrl();
}
if (StrUtil.isNotBlank(returnUrl)){
return StrUtil.format("{}?paymentId={}&businessNo={}", payOrderExtra.getReturnUrl(),prOrder.getId(),prOrder.getBusinessNo());
return StrUtil.format("{}?orderNo={}&bizOrderNo={}", payOrderExtra.getReturnUrl(),prOrder.getOrderNo(), prOrder.getBizOrderNo());
}
// 跳转到默认页
return StrUtil.format("{}/result/success?msg={}", properties.getFrontH5Url(), URLEncodeUtil.encode("支付成功..."));

View File

@@ -3,8 +3,10 @@ package cn.bootx.platform.daxpay.service.core.payment.pay.service;
import cn.bootx.platform.common.core.util.CollUtil;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PaySignTypeEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.payment.pay.PayParam;
import cn.bootx.platform.daxpay.result.pay.PayResult;
import cn.bootx.platform.daxpay.service.common.context.ApiInfoLocal;
import cn.bootx.platform.daxpay.service.common.context.NoticeLocal;
import cn.bootx.platform.daxpay.service.common.context.PayLocal;
@@ -17,6 +19,7 @@ import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.core.payment.sync.service.PaySyncService;
import cn.bootx.platform.daxpay.util.PaySignUtil;
import cn.bootx.platform.daxpay.util.PayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
@@ -227,4 +230,37 @@ public class PayAssistService {
throw new PayFailureException("支付金额超过限额");
}
}
/**
* 根据支付订单构建支付结果
* @param payOrder 支付订单
* @return PayResult 支付结果
*/
public PayResult buildResult(PayOrder payOrder) {
PayResult payResult;
payResult = new PayResult();
payResult.setBizOrderNo(payOrder.getBizOrderNo());
payResult.setOrderNo(payOrder.getOrderNo());
payResult.setStatus(payOrder.getStatus());
// 设置支付参数
PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo();;
if (StrUtil.isNotBlank(asyncPayInfo.getPayBody())) {
payResult.setPayBody(asyncPayInfo.getPayBody());
}
// 进行签名
PlatformLocal platformInfo = PaymentContextLocal.get()
.getPlatformInfo();
String signType = platformInfo.getSignType();
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
payResult.setSign(PaySignUtil.hmacSha256Sign(payResult, platformInfo.getSignSecret()));
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
payResult.setSign(PaySignUtil.md5Sign(payResult, platformInfo.getSignSecret()));
} else {
throw new PayFailureException("未获取到签名方式,请检查");
}
return payResult;
}
}

View File

@@ -5,7 +5,6 @@ import cn.bootx.platform.daxpay.param.payment.pay.PayParam;
import cn.bootx.platform.daxpay.result.pay.PayResult;
import cn.bootx.platform.daxpay.service.common.context.PayLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.builder.PayBuilder;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderExtraManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
@@ -132,7 +131,7 @@ public class PayService {
if (Objects.equals(payOrder.getStatus(), SUCCESS.getCode())){
clientNoticeService.registerPayNotice(payOrder, payInfo.getPayOrderExtra());
}
return PayBuilder.buildResultByPayOrder(payOrder);
return payAssistService.buildResult(payOrder);
}
/**
@@ -185,6 +184,6 @@ public class PayService {
// 查询通道订单
clientNoticeService.registerPayNotice(payOrder, payOrderExtra);
}
return PayBuilder.buildResultByPayOrder(payOrder);
return payAssistService.buildResult(payOrder);
}
}

View File

@@ -3,10 +3,7 @@ package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.service.core.channel.alipay.convert.AlipayConvert;
import cn.bootx.platform.daxpay.service.core.channel.alipay.dao.AliPayRecordManager;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayRecord;
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayReconcileService;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
@@ -23,7 +20,6 @@ import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
@@ -40,8 +36,6 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
private final AliPayReconcileService reconcileService;
private final AliPayRecordManager recordManager;
private final AliPayConfigService configService;
private final DaxPaySequenceHandler daxPaySequenceHandler;
@@ -108,7 +102,6 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
LocalDateTime localDateTime = LocalDateTimeUtil.date2DateTime(this.getRecordOrder().getDate());
LocalDateTime start = LocalDateTimeUtil.beginOfDay(localDateTime);
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
List<AliPayRecord> records = recordManager.findByDate(start, end);
return records.stream().map(AlipayConvert.CONVERT::convertReconcileRecord).collect(Collectors.toList());
return null;
}
}

View File

@@ -3,7 +3,6 @@ package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.service.core.channel.union.convert.UnionPayConvert;
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayConfigService;
import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayReconcileService;
@@ -24,7 +23,6 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
@@ -99,8 +97,7 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
LocalDateTime localDateTime = LocalDateTimeUtil.date2DateTime(this.getRecordOrder().getDate());
LocalDateTime start = LocalDateTimeUtil.beginOfDay(localDateTime);
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
List<UnionPayRecord> records = recordManager.findByDate(start, end);
return records.stream().map(UnionPayConvert.CONVERT::convertReconcileRecord).collect(Collectors.toList());
return null;
}
/**

View File

@@ -106,8 +106,7 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
LocalDateTime localDateTime = LocalDateTimeUtil.date2DateTime(this.getRecordOrder().getDate());
LocalDateTime start = LocalDateTimeUtil.beginOfDay(localDateTime);
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
List<WeChatPayRecord> records = recordManager.findByDate(start, end);
return records.stream().map(WeChatConvert.CONVERT::convertReconcileRecord).collect(Collectors.toList());
return null;
}
}

View File

@@ -1,22 +1,23 @@
package cn.bootx.platform.daxpay.service.core.payment.refund.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.daxpay.code.PaySignTypeEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.payment.refund.RefundParam;
import cn.bootx.platform.daxpay.result.pay.RefundResult;
import cn.bootx.platform.daxpay.service.common.context.ApiInfoLocal;
import cn.bootx.platform.daxpay.service.common.context.NoticeLocal;
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
import cn.bootx.platform.daxpay.service.common.context.RefundLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderExtraManager;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrderExtra;
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
import cn.bootx.platform.daxpay.util.PaySignUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -40,8 +41,6 @@ import static cn.bootx.platform.daxpay.code.RefundStatusEnum.SUCCESS;
@Service
@RequiredArgsConstructor
public class RefundAssistService {
private final PayOrderQueryService payOrderQueryService;
private final RefundOrderManager refundOrderManager;
private final RefundOrderExtraManager refundOrderExtraManager;
@@ -55,7 +54,7 @@ public class RefundAssistService {
}
/**
* 初始化通知相关上下文
* 初始化退款通知相关上下文
*/
private void initNotice(RefundParam param) {
NoticeLocal noticeInfo = PaymentContextLocal.get().getNoticeInfo();
@@ -76,39 +75,6 @@ public class RefundAssistService {
}
}
/**
* 根据退款参数获取退款订单
*/
public RefundOrder getRefundOrder(RefundParam param){
// 查询退款单
RefundOrder refundOrder = null;
if (Objects.nonNull(param.getrefun())){
refundOrder = refundOrderManager.findById(param.getRefundNo())
.orElseThrow(() -> new DataNotExistException("未查询到支付订单"));
}
if (Objects.isNull(refundOrder)){
refundOrder = refundOrderManager.findByRefundNo(param.getRefundNo())
.orElseThrow(() -> new DataNotExistException("未查询到支付订单"));
}
return refundOrder;
}
/**
* 根据退款参数获取支付订单
*/
public PayOrder getPayOrder(RefundParam param){
PayOrder payOrder = null;
if (Objects.nonNull(param.getOrderNo())){
payOrder = payOrderQueryService.findByOrderNo(param.getOrderNo())
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
}
if (Objects.isNull(payOrder)){
payOrder = payOrderQueryService.findByBizOrderNo(param.getBizOrderNo())
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
}
return payOrder;
}
/**
* 检查并处理退款参数
*/
@@ -173,6 +139,7 @@ public class RefundAssistService {
.setRefundNo(asyncRefundInfo.getOutRefundNo());
// 退款成功更新退款时间
if (Objects.equals(refundOrder.getStatus(), SUCCESS.getCode())){
// TODO 读取网关返回的退款时间
refundOrder.setRefundTime(LocalDateTime.now());
}
refundOrderManager.updateById(refundOrder);
@@ -186,9 +153,33 @@ public class RefundAssistService {
RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
refundOrder.setErrorCode(refundInfo.getErrorCode());
refundOrder.setErrorMsg(refundInfo.getErrorMsg());
// 退款失败不保存剩余可退余额, 否则数据看起开会产生困惑
refundOrder.setRefundableBalance(null);
refundOrderManager.updateById(refundOrder);
}
/**
* 根据退款订单信息构建出返回结果
*/
public RefundResult buildResult(RefundOrder refundOrder){
PlatformLocal platformInfo = PaymentContextLocal.get()
.getPlatformInfo();
RefundResult refundResult = new RefundResult();
refundResult.setRefundNo(refundOrder.getRefundNo())
.setBizRefundNo(refundOrder.getBizRefundNo());
refundResult.setCode(refundOrder.getStatus())
.setMsg(refundOrder.getErrorMsg())
.setCode(refundOrder.getErrorCode());
// 进行签名
String signType = platformInfo.getSignType();
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
refundResult.setSign(PaySignUtil.hmacSha256Sign(refundOrder, platformInfo.getSignSecret()));
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
refundResult.setSign(PaySignUtil.md5Sign(refundOrder, platformInfo.getSignSecret()));
} else {
throw new PayFailureException("未获取到签名方式,请检查");
}
return refundResult;
}
}

View File

@@ -2,7 +2,6 @@ package cn.bootx.platform.daxpay.service.core.payment.refund.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.common.core.function.CollectorsFunction;
import cn.bootx.platform.common.core.util.ValidationUtil;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
@@ -11,11 +10,10 @@ import cn.bootx.platform.daxpay.param.payment.refund.RefundParam;
import cn.bootx.platform.daxpay.result.pay.RefundResult;
import cn.bootx.platform.daxpay.service.common.context.RefundLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import cn.bootx.platform.daxpay.service.core.payment.notice.service.ClientNoticeService;
import cn.bootx.platform.daxpay.service.core.payment.refund.factory.RefundStrategyFactory;
@@ -28,9 +26,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* 支付退款服务
@@ -50,6 +49,8 @@ public class RefundService {
private final RefundOrderManager refundOrderManager;
private final PayOrderQueryService payOrderQueryService;
private final LockTemplate lockTemplate;
/**
@@ -70,7 +71,7 @@ public class RefundService {
// 判断是否是首次发起退款
Optional<RefundOrder> refund = refundOrderManager.findByBizRefundNo(param.getBizRefundNo());
if (refund.isPresent()){
return this.repeatRefund(param,refund.get());
return this.repeatRefund(refund.get());
} else {
return this.firstRefund(param);
}
@@ -85,7 +86,8 @@ public class RefundService {
public RefundResult firstRefund(RefundParam param){
// 获取支付订单
PayOrder payOrder = refundAssistService.getPayOrder(param);
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getOrderNo(), param.getBizOrderNo())
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
// 检查退款参数
refundAssistService.checkAndParam(param, payOrder);
@@ -97,10 +99,8 @@ public class RefundService {
refundStrategy.setPayOrder(payOrder);
// 进行退款前预处理
refundStrategy.doBeforeRefundHandler();
// 退款操作的预处理, 使用独立的新事物进行发起, 返回创建成功的退款订单, 成功后才可以进行下一阶段的操作
RefundOrder refundOrder = SpringUtil.getBean(this.getClass()).preRefundMethod(param, payOrder);
try {
// 3.2 执行退款策略
refundStrategy.doRefundHandler();
@@ -112,9 +112,7 @@ public class RefundService {
refundAssistService.updateOrderByError(refundOrder);
}
SpringUtil.getBean(this.getClass()).successHandler(refundOrder, payOrder);
return new RefundResult()
.setBizRefundNo(refundOrder.getBizRefundNo())
.setRefundNo(refundOrder.getRefundNo());
return refundAssistService.buildResult(refundOrder);
}
/**
@@ -137,37 +135,33 @@ public class RefundService {
* 1. 查出相关退款订单
* 2. 构建退款策略, 发起退款
*/
public RefundResult repeatRefund(RefundParam param, RefundOrder refundOrder){
public RefundResult repeatRefund(RefundOrder refundOrder){
// 退款失败才可以重新发起退款, 重新发起退款
if (!Objects.equals(refundOrder.getStatus(), RefundStatusEnum.FAIL.getCode())){
throw new PayFailureException("只有失败状态的才可以重新发起退款");
}
// 获取支付订单
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(refundOrder.getOrderNo(), refundOrder.getBizOrderNo())
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(refundOrder.getRefundNo());
// 设置退款订单对象
refundStrategy.setRefundOrder(refundOrder);
// 退款前准备操作
refundStrategy.doBeforeRefundHandler();
try {
// 3.1 退款前准备操作
refundStrategy.forEach(AbsRefundStrategy::doBeforeRefundHandler);
// 3.2 执行退款策略
refundStrategy.forEach(AbsRefundStrategy::doRefundHandler);
// 3.3 执行退款发起成功后操作
refundStrategy.forEach(AbsRefundStrategy::doSuccessHandler);
// 4.进行成功处理, 分别处理退款订单, 通道退款订单, 支付订单
List<RefundChannelOrder> refundChannelOrders = refundStrategy.stream()
.map(AbsRefundStrategy::getRefundChannelOrder)
.collect(Collectors.toList());
this.successHandler(refundOrder, refundChannelOrders, payOrder);
// 执行退款策略
refundStrategy.doRefundHandler();
}
catch (Exception e) {
// 5. 失败处理, 所有记录都会回滚, 可以调用退款重试
// 失败处理, 所有记录都会回滚, 可以调用退款重试
PaymentContextLocal.get().getRefundInfo().setStatus(RefundStatusEnum.FAIL);
// 记录退款失败的记录
refundAssistService.updateOrderByError(refundOrder);
}
// 退款发起成功处理
SpringUtil.getBean(this.getClass()).successHandler(refundOrder, payOrder);
return refundAssistService.buildResult(refundOrder);
}
/**

View File

@@ -48,6 +48,6 @@ public class AliRefundStrategy extends AbsRefundStrategy {
*/
@Override
public void doRefundHandler() {
aliRefundService.refund(this.getRefundOrder(), this.getRefundParam().getAmount());
aliRefundService.refund(this.getRefundOrder());
}
}

View File

@@ -53,6 +53,6 @@ public class UnionRefundStrategy extends AbsRefundStrategy {
@Override
public void doRefundHandler() {
UnionPayKit unionPayKit = unionPayConfigService.initPayService(unionPayConfig);
unionPayRefundService.refund(this.getRefundOrder(), this.getPayOrder(), this.getRefundParam().getAmount(), unionPayKit);
unionPayRefundService.refund(this.getRefundOrder(), this.getPayOrder(), unionPayKit);
}
}

View File

@@ -56,6 +56,6 @@ public class WalletRefundStrategy extends AbsRefundStrategy {
@Override
public void doRefundHandler() {
// 不包含异步支付, 则只在支付订单中进行扣减, 等待异步退款完成, 再进行退款
walletPayService.refund(this.wallet, this.getRefundParam().getAmount());
walletPayService.refund(this.wallet, this.getRefundOrder().getAmount());
}
}

View File

@@ -51,7 +51,7 @@ public class WeChatRefundStrategy extends AbsRefundStrategy {
*/
@Override
public void doRefundHandler() {
wechatPayRefundService.refund(this.getRefundOrder(), this.getRefundParam().getAmount(), this.weChatPayConfig);
wechatPayRefundService.refund(this.getRefundOrder(), this.weChatPayConfig);
}
}

View File

@@ -1,13 +1,10 @@
package cn.bootx.platform.daxpay.service.core.payment.repair.service;
import cn.bootx.platform.common.core.function.CollectorsFunction;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.service.code.PayRepairWayEnum;
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.core.payment.notice.service.ClientNoticeService;
@@ -26,7 +23,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -43,8 +39,6 @@ public class PayRepairService {
private final ClientNoticeService clientNoticeService;
private final PayChannelOrderManager channelOrderManager;
private final PayRepairRecordService recordService;
private final LockTemplate lockTemplate;

View File

@@ -7,14 +7,10 @@ import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
import cn.bootx.platform.daxpay.service.code.RefundRepairWayEnum;
import cn.bootx.platform.daxpay.service.common.context.RepairLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundChannelOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import cn.bootx.platform.daxpay.service.core.payment.notice.service.ClientNoticeService;
import cn.bootx.platform.daxpay.service.core.payment.repair.factory.RefundRepairStrategyFactory;
@@ -50,8 +46,6 @@ public class RefundRepairService {
private final ClientNoticeService clientNoticeService;
private final PayChannelOrderManager payChannelOrderManager;
private final RefundOrderManager refundOrderManager;
private final PayRepairRecordService recordService;

View File

@@ -7,8 +7,6 @@ import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.Wallet;
import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayService;
import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletQueryService;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import cn.bootx.platform.daxpay.service.func.AbsRefundRepairStrategy;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;

View File

@@ -29,13 +29,13 @@ import lombok.experimental.Accessors;
@TableName("pay_callback_record")
public class PayCallbackRecord extends MpCreateEntity implements EntityBaseFunction<PayCallbackRecordDto> {
/** 本地订单id */
@DbColumn(comment = "本地订单id")
private Long orderId;
/** 本地交易号 */
@DbColumn(comment = "本地交易号")
private String tradeNo;
/** 支付网关订单号 */
/** 三方支付交易号 */
@DbColumn(comment = "支付网关订单号")
private String gatewayOrderNo;
private String outOrderNo;
/**
* 支付通道
@@ -63,9 +63,14 @@ public class PayCallbackRecord extends MpCreateEntity implements EntityBaseFunct
private String status;
/** 修复号 */
@Schema(description = "修复号")
private String repairOrderNo;
/** 错误码 */
@DbColumn(comment = "错误码")
private String errorCode;
/** 提示信息 */
@DbColumn(comment = "提示信息")
private String msg;

View File

@@ -24,20 +24,20 @@ import lombok.experimental.Accessors;
@TableName("pay_close_record")
public class PayCloseRecord extends MpCreateEntity implements EntityBaseFunction<PayCloseRecordDto> {
/** 支付记录id */
@DbColumn(comment = "支付记录id")
private Long paymentId;
/** 订单号 */
@DbColumn(comment = "订单号")
private String orderNo;
/** 业务号 */
@DbColumn(comment = "业务")
private String businessNo;
/** 商户订单号 */
@DbColumn(comment = "商户订单")
private String bizOrderNo;
/**
* 关闭的异步支付通道, 可以为空
* @see PayChannelEnum#getCode()
* 关闭的支付通道
* @see PayChannelEnum
*/
@DbColumn(comment = "关闭的异步支付通道")
private String asyncChannel;
private String channel;
/**
* 是否关闭成功
@@ -45,6 +45,9 @@ public class PayCloseRecord extends MpCreateEntity implements EntityBaseFunction
@DbColumn(comment = "是否关闭成功")
private boolean closed;
@DbColumn(comment = "错误码")
private String code;
@DbColumn(comment = "错误消息")
private String errorMsg;
@@ -52,10 +55,6 @@ public class PayCloseRecord extends MpCreateEntity implements EntityBaseFunction
@DbColumn(comment = "客户端IP")
private String clientIp;
/** 请求链路ID */
@DbColumn(comment = "请求链路ID")
private String reqId;
/**
* 转换
*/

View File

@@ -1,55 +0,0 @@
package cn.bootx.platform.daxpay.service.dto.order.pay;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
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 2024/1/9
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "支付订单关联通道信息")
public class PayChannelOrderDto extends BaseDto {
@Schema(description = "支付id")
private String paymentId;
@Schema(description = "异步支付方式")
private boolean async;
@Schema(description = "通道")
private String channel;
@Schema(description = "支付方式")
private String payWay;
/**
* 异步支付通道发给网关的退款号, 用与将记录关联起来
*/
@Schema(description = "关联网关支付号")
private String gatewayOrderNo;
@Schema(description = "金额")
private Integer amount;
@Schema(description = "可退款金额")
private Integer refundableBalance;
/**
* 支付状态
* @see PayStatusEnum
*/
@Schema(description = "支付状态")
private String status;
@Schema(description = "支付时间")
private LocalDateTime payTime;
}

View File

@@ -8,5 +8,4 @@ import java.util.List;
public class PayOrderDetailDto {
private PayOrderDto payOrder;
private PayOrderExtraDto payOrderExtra;
private List<PayChannelOrderDto> payChannelOrder;
}

View File

@@ -107,10 +107,10 @@ public abstract class AbsCallbackStrategy implements PayStrategy {
PayCallbackRecord payNotifyRecord = new PayCallbackRecord()
.setChannel(this.getChannel().getCode())
.setNotifyInfo(JSONUtil.toJsonStr(callbackInfo.getCallbackParam()))
.setOrderId(callbackInfo.getOrderId())
.setGatewayOrderNo(callbackInfo.getOutOrderNo())
.setOrderId(callbackInfo.getTradeNo())
.setGatewayOrderNo(callbackInfo.getOutTradeNo())
.setCallbackType(callbackInfo.getCallbackType().getCode())
.setRepairOrderNo(callbackInfo.getPayRepairNo())
.setRepairOrderNo(callbackInfo.getRepairNo())
.setStatus(callbackInfo.getCallbackStatus().getCode())
.setMsg(callbackInfo.getMsg());
callbackRecordService.save(payNotifyRecord);

View File

@@ -1,7 +1,5 @@
package cn.bootx.platform.daxpay.service.func;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import lombok.Getter;
import lombok.Setter;
@@ -18,13 +16,6 @@ public abstract class AbsPayCloseStrategy implements PayStrategy{
/** 支付订单 */
private PayOrder order = null;
/** 支付通道订单 */
private PayChannelOrder channelOrder = null;
public void initCloseParam(PayOrder order, PayChannelOrder channelOrder){
this.order = order;
this.channelOrder = channelOrder;
}
/**
* 关闭前的处理方式
@@ -36,11 +27,4 @@ public abstract class AbsPayCloseStrategy implements PayStrategy{
*/
public abstract void doCloseHandler();
/**
* 关闭成功的处理方式
*/
public void doSuccessHandler() {
// 更新通道支付订单的状态为关闭
this.getChannelOrder().setStatus(PayStatusEnum.CLOSE.getCode());
}
}

View File

@@ -2,9 +2,7 @@ package cn.bootx.platform.daxpay.service.func;
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import lombok.Getter;

View File

@@ -1,6 +1,5 @@
package cn.bootx.platform.daxpay.service.func;
import cn.bootx.platform.daxpay.param.payment.refund.RefundParam;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import lombok.Getter;
@@ -22,9 +21,6 @@ public abstract class AbsRefundStrategy implements PayStrategy{
/** 退款订单 */
private RefundOrder refundOrder = null;
/** 退款参数 */
private RefundParam refundParam;
/**
* 退款前对处理, 主要进行配置的加载和检查

View File

@@ -17,7 +17,7 @@ public class PayOrderRefundParam {
/** 支付订单号 */
@Schema(description = "支付订单号")
private Long orderNo;
private String orderNo;
/**
* 支付通道