mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 14:56:06 +08:00
feat(payment): 统一支付新增退款/退款查询/退款同步接口
- UniTradeController 增 POST /refund 退款发起 - UniQueryController 增 POST /refund-order 退款订单查询 - UniSyncController 增 POST /refund 退款订单同步 - 新增 RefundParam/RefundOrderQueryParam/RefundSyncParam 与对应 Result - 新增 RefundOrderService/RefundOrderQueryService/RefundOrderSyncService + UnipayRefundOrderConvert - RefundOrderManager 增 findByBizRefundNo(单参/含appId) 支持统一接口主路径查询
This commit is contained in:
@@ -23,6 +23,21 @@ public class RefundOrderManager extends BaseManager<RefundOrderMapper, RefundOrd
|
||||
return findByField(RefundOrder::getRefundNo, refundNo);
|
||||
}
|
||||
|
||||
/// 根据商户退款号查询(按商户号自动租户隔离)
|
||||
public Optional<RefundOrder> findByBizRefundNo(String bizRefundNo) {
|
||||
return lambdaQuery()
|
||||
.eq(RefundOrder::getBizRefundNo, bizRefundNo)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据商户退款号和应用号查询(统一接口主路径, 避免同商户多应用串单)
|
||||
public Optional<RefundOrder> findByBizRefundNo(String bizRefundNo, String appId) {
|
||||
return lambdaQuery()
|
||||
.eq(RefundOrder::getBizRefundNo, bizRefundNo)
|
||||
.eq(RefundOrder::getAppId, appId)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据实际上送串查询(回调容错: 特殊通道仅回传变形号)
|
||||
public Optional<RefundOrder> findByRelationOrderNo(String relationOrderNo) {
|
||||
return findByField(RefundOrder::getRelationOrderNo, relationOrderNo);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.daxpay.open.payment.unipay.param.trade.refund;
|
||||
|
||||
import cn.daxpay.open.payment.unipay.param.MerchantPaymentCommonParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/// # 退款单查询参数
|
||||
///
|
||||
/// 平台退款号与商户退款号至少传一个, 优先使用平台退款号。
|
||||
/// 仅查询本地退款单, 不调用通道; 需要实时通道状态请走退款同步接口。
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Schema(title = "退款单查询参数")
|
||||
public class RefundOrderQueryParam extends MerchantPaymentCommonParam {
|
||||
|
||||
/// 平台退款号
|
||||
@Schema(description = "平台退款号")
|
||||
@Size(max = 100, message = "{validation.field.refundNo.size}")
|
||||
private String refundNo;
|
||||
|
||||
/// 商户退款号
|
||||
@Schema(description = "商户退款号")
|
||||
@Size(max = 100, message = "{validation.field.bizRefundNo.size}")
|
||||
private String bizRefundNo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package cn.daxpay.open.payment.unipay.param.trade.refund;
|
||||
|
||||
import cn.daxpay.open.payment.unipay.param.MerchantPaymentCommonParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/// # 统一退款发起参数
|
||||
///
|
||||
/// 从已支付订单发起退款, 支持部分退款。
|
||||
/// 原支付单定位: tradeNo(资金交易号) 与 bizOrderNo(商户业务单号) 至少传一个, 优先使用 tradeNo。
|
||||
/// 与内部编排参数 [cn.daxpay.open.payment.trade.runtime.param.RefundParam] 同名但职责不同:
|
||||
/// 本类是对外签名 DTO(含 mchNo/appId/sign), Controller 层负责转换。
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Schema(title = "统一退款参数")
|
||||
public class RefundParam extends MerchantPaymentCommonParam {
|
||||
|
||||
/// 原支付资金交易号(平台 tradeNo)
|
||||
@Schema(description = "原支付资金交易号")
|
||||
@Size(max = 100, message = "{validation.field.tradeNo.size}")
|
||||
private String tradeNo;
|
||||
|
||||
/// 原支付商户业务订单号
|
||||
@Schema(description = "原支付商户业务订单号")
|
||||
@Size(max = 100, message = "{validation.field.bizOrderNo.size}")
|
||||
private String bizOrderNo;
|
||||
|
||||
/// 退款金额(单位: 分, 最小货币单位)
|
||||
@Schema(description = "退款金额(分)")
|
||||
@NotNull(message = "{validation.field.amount.notNull}")
|
||||
@Positive(message = "{validation.field.amount.positive}")
|
||||
@Min(value = 1, message = "{validation.field.amount.min}")
|
||||
private Long amount;
|
||||
|
||||
/// 退款原因
|
||||
@Schema(description = "退款原因")
|
||||
@Size(max = 50, message = "{validation.field.reason.size}")
|
||||
private String reason;
|
||||
|
||||
/// 商户退款号(可选, 不传则由系统生成)
|
||||
@Schema(description = "商户退款号")
|
||||
@Size(max = 100, message = "{validation.field.bizRefundNo.size}")
|
||||
private String bizRefundNo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.daxpay.open.payment.unipay.param.trade.refund;
|
||||
|
||||
import cn.daxpay.open.payment.unipay.param.MerchantPaymentCommonParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/// # 退款状态同步参数
|
||||
///
|
||||
/// 主动查询通道网关方退款终态并回写本地退款单。
|
||||
/// 平台退款号与商户退款号至少传一个, 优先使用平台退款号。
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Schema(title = "退款状态同步参数")
|
||||
public class RefundSyncParam extends MerchantPaymentCommonParam {
|
||||
|
||||
/// 平台退款号
|
||||
@Schema(description = "平台退款号")
|
||||
@Size(max = 100, message = "{validation.field.refundNo.size}")
|
||||
private String refundNo;
|
||||
|
||||
/// 商户退款号
|
||||
@Schema(description = "商户退款号")
|
||||
@Size(max = 100, message = "{validation.field.bizRefundNo.size}")
|
||||
private String bizRefundNo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package cn.daxpay.open.payment.unipay.result.trade.refund;
|
||||
|
||||
import cn.daxpay.open.payment.trade.enums.RefundOrderStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/// # 退款订单(统一查询)
|
||||
///
|
||||
/// 对外查询结果(精简), 不复用管理端 [cn.daxpay.open.payment.trade.order.result.RefundOrderResult]
|
||||
/// (后者含 mchName 翻译、channelMchNo 等内部字段, 不宜对商户暴露)。
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "退款订单")
|
||||
public class RefundOrderResult {
|
||||
|
||||
/// 平台退款号
|
||||
@Schema(description = "平台退款号")
|
||||
private String refundNo;
|
||||
|
||||
/// 商户退款号
|
||||
@Schema(description = "商户退款号")
|
||||
private String bizRefundNo;
|
||||
|
||||
/// 原支付资金交易号
|
||||
@Schema(description = "原支付资金交易号")
|
||||
private String tradeNo;
|
||||
|
||||
/// 原支付商户业务订单号
|
||||
@Schema(description = "原支付商户业务订单号")
|
||||
private String bizOrderNo;
|
||||
|
||||
/// 通道退款流水号
|
||||
@Schema(description = "通道退款流水号")
|
||||
private String outRefundNo;
|
||||
|
||||
/// 退款金额(分)
|
||||
@Schema(description = "退款金额(分)")
|
||||
private Long amount;
|
||||
|
||||
/// 订单总金额(分)
|
||||
@Schema(description = "订单总金额(分)")
|
||||
private Long orderAmount;
|
||||
|
||||
/// 退款状态
|
||||
/// @see RefundOrderStatusEnum
|
||||
@Schema(description = "退款状态")
|
||||
private String status;
|
||||
|
||||
/// 退款原因
|
||||
@Schema(description = "退款原因")
|
||||
private String reason;
|
||||
|
||||
/// 退款完成时间(UTC)
|
||||
@Schema(description = "退款完成时间(UTC)")
|
||||
private OffsetDateTime finishTime;
|
||||
|
||||
/// 错误信息
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMsg;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.daxpay.open.payment.unipay.result.trade.refund;
|
||||
|
||||
import cn.daxpay.open.payment.trade.enums.RefundOrderStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/// # 统一退款响应参数
|
||||
///
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "统一退款响应参数")
|
||||
public class RefundResult {
|
||||
|
||||
/// 平台退款号
|
||||
@Schema(description = "平台退款号")
|
||||
private String refundNo;
|
||||
|
||||
/// 商户退款号
|
||||
@Schema(description = "商户退款号")
|
||||
private String bizRefundNo;
|
||||
|
||||
/// 退款状态
|
||||
/// @see RefundOrderStatusEnum
|
||||
@Schema(description = "退款状态")
|
||||
private String status;
|
||||
|
||||
/// 错误信息(失败时返回)
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMsg;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.daxpay.open.payment.unipay.result.trade.refund;
|
||||
|
||||
import cn.daxpay.open.payment.trade.enums.RefundOrderStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/// # 退款同步结果
|
||||
///
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "退款同步结果")
|
||||
public class RefundSyncResult {
|
||||
|
||||
/// 同步后的退款订单状态
|
||||
/// @see RefundOrderStatusEnum
|
||||
@Schema(description = "同步后退款状态")
|
||||
private String orderStatus;
|
||||
|
||||
/// 是否触发了调整(本地状态因本次同步发生了变更)
|
||||
@Schema(description = "是否触发了调整")
|
||||
private boolean adjust;
|
||||
|
||||
}
|
||||
@@ -2,12 +2,15 @@ package cn.daxpay.open.payment.unipay.trade.controller;
|
||||
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreAuth;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayQueryParam;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.refund.RefundOrderQueryParam;
|
||||
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayOrderResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundOrderResult;
|
||||
import cn.daxpay.open.payment.common.util.DaxRes;
|
||||
import cn.daxpay.open.payment.unipay.aop.PaymentVerify;
|
||||
import cn.daxpay.open.payment.unipay.trade.service.NormalPayOrderQueryService;
|
||||
import cn.daxpay.open.payment.unipay.trade.service.RefundOrderQueryService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -27,6 +30,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class UniQueryController {
|
||||
|
||||
private final NormalPayOrderQueryService normalPayOrderQueryService;
|
||||
private final RefundOrderQueryService refundOrderQueryService;
|
||||
|
||||
@Operation(summary = "支付订单查询接口")
|
||||
@PostMapping("/pay-order")
|
||||
@@ -34,4 +38,10 @@ public class UniQueryController {
|
||||
return DaxRes.ok(normalPayOrderQueryService.queryPayOrder(param));
|
||||
}
|
||||
|
||||
@Operation(summary = "退款订单查询接口")
|
||||
@PostMapping("/refund-order")
|
||||
public DaxResult<RefundOrderResult> queryRefundOrder(@RequestBody RefundOrderQueryParam param){
|
||||
return DaxRes.ok(refundOrderQueryService.queryRefundOrder(param));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@ package cn.daxpay.open.payment.unipay.trade.controller;
|
||||
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreAuth;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPaySyncParam;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.refund.RefundSyncParam;
|
||||
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPaySyncResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundSyncResult;
|
||||
import cn.daxpay.open.payment.common.util.DaxRes;
|
||||
import cn.daxpay.open.payment.unipay.aop.PaymentVerify;
|
||||
import cn.daxpay.open.payment.trade.runtime.service.sync.PaySyncService;
|
||||
import cn.daxpay.open.payment.unipay.trade.service.RefundOrderSyncService;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -28,6 +31,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class UniSyncController {
|
||||
|
||||
private final PaySyncService paySyncService;
|
||||
private final RefundOrderSyncService refundOrderSyncService;
|
||||
|
||||
@Operation(summary = "支付订单同步接口")
|
||||
@PostMapping("/pay")
|
||||
@@ -35,4 +39,10 @@ public class UniSyncController {
|
||||
return DaxRes.ok(paySyncService.sync(param));
|
||||
}
|
||||
|
||||
@Operation(summary = "退款订单同步接口")
|
||||
@PostMapping("/refund")
|
||||
public DaxResult<RefundSyncResult> refund(@RequestBody RefundSyncParam param){
|
||||
return DaxRes.ok(refundOrderSyncService.sync(param));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,12 +3,15 @@ package cn.daxpay.open.payment.unipay.trade.controller;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreAuth;
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import cn.daxpay.open.payment.common.util.DaxRes;
|
||||
import cn.daxpay.open.payment.unipay.aop.PaymentVerify;
|
||||
import cn.daxpay.open.payment.trade.runtime.service.close.PayCloseService;
|
||||
import cn.daxpay.open.payment.trade.runtime.service.pay.normal.NormalPayService;
|
||||
import cn.daxpay.open.payment.unipay.aop.PaymentVerify;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayCloseParam;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayParam;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.refund.RefundParam;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundResult;
|
||||
import cn.daxpay.open.payment.unipay.trade.service.RefundOrderService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -28,6 +31,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class UniTradeController {
|
||||
private final NormalPayService normalPayService;
|
||||
private final PayCloseService payCloseService;
|
||||
private final RefundOrderService refundOrderService;
|
||||
|
||||
@Operation(summary = "支付接口")
|
||||
@PostMapping("/pay")
|
||||
@@ -42,4 +46,10 @@ public class UniTradeController {
|
||||
return DaxRes.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "退款接口")
|
||||
@PostMapping("/refund")
|
||||
public DaxResult<RefundResult> refund(@RequestBody RefundParam param){
|
||||
return DaxRes.ok(refundOrderService.refund(param));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.daxpay.open.payment.unipay.trade.convert;
|
||||
|
||||
import cn.daxpay.open.payment.trade.order.entity.RefundOrder;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.refund.RefundParam;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundOrderResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundResult;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/// # 退款转换器(对外)
|
||||
///
|
||||
/// 汇聚退款场景的对外映射:
|
||||
/// - 退款单实体 → 对外查询结果 [RefundOrderResult] (内部字段 mchNo/channelMchNo 等自动忽略)
|
||||
/// - 退款单实体 → 发起响应 [RefundResult] (仅退款号/状态等对外字段)
|
||||
/// - 对外签名入参 [RefundParam] → 内部编排参数 (丢弃 mchNo/appId/sign 等签名字段)
|
||||
@Mapper
|
||||
public interface UnipayRefundOrderConvert {
|
||||
|
||||
UnipayRefundOrderConvert CONVERT = Mappers.getMapper(UnipayRefundOrderConvert.class);
|
||||
|
||||
/// 退款单实体 → 对外查询结果(同名映射)
|
||||
RefundOrderResult toResult(RefundOrder order);
|
||||
|
||||
/// 退款单实体 → 发起响应(同名映射)
|
||||
RefundResult toRefundResult(RefundOrder order);
|
||||
|
||||
/// 对外签名入参 → 内部编排参数(同名字段映射, 签名/商户字段无目标自动丢弃)
|
||||
cn.daxpay.open.payment.trade.runtime.param.RefundParam toRuntime(RefundParam param);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.daxpay.open.payment.unipay.trade.service;
|
||||
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.DataNotExistException;
|
||||
import cn.daxpay.open.payment.trade.order.dao.RefundOrderManager;
|
||||
import cn.daxpay.open.payment.trade.order.entity.RefundOrder;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.refund.RefundOrderQueryParam;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundOrderResult;
|
||||
import cn.daxpay.open.payment.unipay.trade.convert.UnipayRefundOrderConvert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 退款订单查询服务(对外)
|
||||
///
|
||||
/// 纯查本地退款单, 不调用通道; 需要实时通道状态请走退款同步接口。
|
||||
/// 支持按平台退款号(refundNo)或商户退款号(bizRefundNo)查询, 优先使用平台退款号。
|
||||
/// 按商户退款号查询时绑定 appId, 避免同商户多应用串单。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RefundOrderQueryService {
|
||||
|
||||
private final RefundOrderManager refundOrderManager;
|
||||
|
||||
/// 查询退款订单
|
||||
public RefundOrderResult queryRefundOrder(RefundOrderQueryParam param) {
|
||||
// 校验参数, 平台退款号和商户退款号不能都为空
|
||||
if (StrUtil.isBlank(param.getRefundNo()) && StrUtil.isBlank(param.getBizRefundNo())) {
|
||||
// 退款: 退款号不能都为空(复用统一接口层通用单号校验 key)
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.orderNoRequired");
|
||||
}
|
||||
|
||||
RefundOrder order;
|
||||
// 优先按平台退款号查询
|
||||
if (StrUtil.isNotBlank(param.getRefundNo())) {
|
||||
order = refundOrderManager.findByRefundNo(param.getRefundNo())
|
||||
// 退款: 退款订单不存在
|
||||
.orElseThrow(() -> new DataNotExistException("pay.error.refund.orderNotFound"));
|
||||
} else {
|
||||
// 按商户退款号 + 应用号查询(避免串单)
|
||||
order = refundOrderManager.findByBizRefundNo(param.getBizRefundNo(), param.getAppId())
|
||||
.orElseThrow(() -> new DataNotExistException("pay.error.refund.orderNotFound"));
|
||||
}
|
||||
return UnipayRefundOrderConvert.CONVERT.toResult(order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.daxpay.open.payment.unipay.trade.service;
|
||||
|
||||
import cn.daxpay.open.payment.trade.order.entity.RefundOrder;
|
||||
import cn.daxpay.open.payment.trade.runtime.service.refund.RefundService;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.refund.RefundParam;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundResult;
|
||||
import cn.daxpay.open.payment.unipay.trade.convert.UnipayRefundOrderConvert;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 退款发起服务(对外)
|
||||
///
|
||||
/// 对外统一退款的编排入口: 对外签名入参 → 内部编排参数, 委托核心 [RefundService] 建单调通道,
|
||||
/// 再将退款单实体映射为对外响应 [RefundResult]。
|
||||
/// 核心层只认内部 [cn.daxpay.open.payment.trade.runtime.param.RefundParam], 对外签名字段(mchNo/appId/sign)在此剥离。
|
||||
/// 与退款查询/同步的 [RefundOrderQueryService] / [RefundOrderSyncService] 并列。
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RefundOrderService {
|
||||
|
||||
private final RefundService refundService;
|
||||
|
||||
/// 发起退款
|
||||
public RefundResult refund(RefundParam param) {
|
||||
RefundOrder refundOrder = refundService.refund(UnipayRefundOrderConvert.CONVERT.toRuntime(param));
|
||||
return UnipayRefundOrderConvert.CONVERT.toRefundResult(refundOrder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package cn.daxpay.open.payment.unipay.trade.service;
|
||||
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.DataNotExistException;
|
||||
import cn.daxpay.open.payment.trade.order.dao.RefundOrderManager;
|
||||
import cn.daxpay.open.payment.trade.order.entity.RefundOrder;
|
||||
import cn.daxpay.open.payment.trade.runtime.service.refund.RefundSyncService;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.refund.RefundSyncParam;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.refund.RefundSyncResult;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/// # 退款订单同步服务(对外)
|
||||
///
|
||||
/// 对外统一入口: 按平台退款号或商户退款号定位退款单, 委托 [RefundSyncService] 查询通道终态回写。
|
||||
/// adjust 标记: 同步前后本地状态发生变化即为 true, 让商户感知本次同步是否触发了状态调整。
|
||||
/// 与支付同步 [cn.daxpay.open.payment.trade.runtime.service.sync.PaySyncService] 的 adjust 语义对齐。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RefundOrderSyncService {
|
||||
|
||||
private final RefundOrderManager refundOrderManager;
|
||||
private final RefundSyncService refundSyncService;
|
||||
|
||||
/// 退款同步
|
||||
public RefundSyncResult sync(RefundSyncParam param) {
|
||||
// 校验参数, 平台退款号和商户退款号不能都为空
|
||||
if (StrUtil.isBlank(param.getRefundNo()) && StrUtil.isBlank(param.getBizRefundNo())) {
|
||||
// 退款: 退款号不能都为空(复用统一接口层通用单号校验 key)
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.orderNoRequired");
|
||||
}
|
||||
|
||||
// 按号定位退款单(优先平台退款号)
|
||||
RefundOrder refundOrder;
|
||||
if (StrUtil.isNotBlank(param.getRefundNo())) {
|
||||
refundOrder = refundOrderManager.findByRefundNo(param.getRefundNo())
|
||||
.orElseThrow(() -> new DataNotExistException("pay.error.refund.orderNotFound"));
|
||||
} else {
|
||||
refundOrder = refundOrderManager.findByBizRefundNo(param.getBizRefundNo(), param.getAppId())
|
||||
.orElseThrow(() -> new DataNotExistException("pay.error.refund.orderNotFound"));
|
||||
}
|
||||
|
||||
// 记录同步前状态, 同步后比较得出是否调整
|
||||
String statusBefore = refundOrder.getStatus();
|
||||
RefundOrder synced = refundSyncService.sync(refundOrder);
|
||||
String statusAfter = synced.getStatus();
|
||||
boolean adjust = !Objects.equals(statusBefore, statusAfter);
|
||||
|
||||
return new RefundSyncResult()
|
||||
.setOrderStatus(statusAfter)
|
||||
.setAdjust(adjust);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user