场景描述:Java商城项目,多商户平台,支付集成的是支付宝直付通和微信平台收付通。优惠券可以根据是谁负担的成本进行划分,可以划分为平台券和商家券。如果是平台券,那用户购买商品后,平台要补给商家钱,那就要定位使用了平台券的子支付订单(合并支付的情况下),再次为该商户补贴优惠券的钱,那这又是一个关联订单。这样的话用户退款时,不仅要正常退子订单的钱退给用户,还要退关联订单的钱退给平台。如果是商家券,走正常支付流程即可,不用做额外操作。退款不会退使用过的优惠券。
针对多商户平台中平台券的处理,需在支付和退款流程中设计额外的资金补偿与回收机制。以下是实现方案:
核心流程设计
1. 支付环节
-
商家券
用户支付时直接抵扣订单金额,无需额外操作(商户自行承担成本)。 -
平台券
用户支付时抵扣订单金额后,平台需额外补偿商户优惠金额:
2. 退款环节
-
商家券
仅退还用户实际支付金额(优惠券不退)。 -
平台券
需退还两部分资金:- 用户实际支付金额 → 退还给用户
- 平台补贴金额 → 从商户回收至平台
关键实现步骤
1. 数据结构设计
// 订单表
class Order {
String orderId; // 主订单ID
BigDecimal amount; // 订单总金额
CouponType couponType;// 优惠券类型(PLATFORM/MERCHANT)
String couponId; // 优惠券ID
BigDecimal couponAmount; // 优惠券金额
BigDecimal actualPayAmount; // 用户实际支付金额
}
// 补贴订单表(平台券专属)
class SubsidyOrder {
String subsidyOrderId; // 补贴订单ID
String originalOrderId; // 关联的主订单ID
String merchantId; // 商户ID
BigDecimal amount; // 补贴金额(=优惠券金额)
PaymentChannel channel; // 支付渠道(ALIPAY/WECHAT)
}
2. 支付流程实现
// 支付成功后处理平台券补偿
public void handlePlatformCoupon(Order order) {
if (order.getCouponType() == CouponType.PLATFORM) {
// 创建补贴订单
SubsidyOrder subsidyOrder = createSubsidyOrder(
order.getId(),
order.getMerchantId(),
order.getCouponAmount()
);
// 调用支付渠道补偿商户
if (order.getChannel() == PaymentChannel.ALIPAY) {
alipayService.transferToMerchant(
subsidyOrder.getId(),
subsidyOrder.getAmount(),
order.getMerchantAccount()
);
} else if (order.getChannel() == PaymentChannel.WECHAT) {
wechatPayService.transferToMerchant(
subsidyOrder.getId(),
subsidyOrder.getAmount(),
order.getMerchantAccount()
);
}
}
}
3. 退款流程实现
public void refundOrder(Order order) {
// 1. 退用户实际支付金额
paymentService.refundOriginalOrder(order.getId(), order.getActualPayAmount());
// 2. 若含平台券,回收补贴
if (order.getCouponType() == CouponType.PLATFORM) {
SubsidyOrder subsidyOrder = subsidyOrderService.findByOrderId(order.getId());
// 从商户回收补贴金额
if (order.getChannel() == PaymentChannel.ALIPAY) {
alipayService.deductFromMerchant(
subsidyOrder.getId(),
subsidyOrder.getAmount(),
order.getMerchantAccount()
);
} else if (order.getChannel() == PaymentChannel.WECHAT) {
wechatPayService.deductFromMerchant(
subsidyOrder.getId(),
subsidyOrder.getAmount(),
order.getMerchantAccount()
);
}
// 更新补贴订单状态为已回收
subsidyOrder.markReversed();
}
}
支付渠道对接关键点
支付宝直付通
- 补贴支付
使用alipay.fund.trans.uni.transfer单笔转账到商户账户。 - 补贴回收
使用alipay.trade.order.settle发起分账扣回(需预先签约分账关系)。
微信平台收付通
- 补贴支付
调用profitsharing.addReceiver添加分账方,再通过profitsharing.orders发起分账。 - 补贴回收
使用refund接口退款时,通过refund_account参数指定REFUND_SOURCE_SUBSIDY_ACCOUNT从二级商户回收资金。
异常处理机制
- 补贴支付失败
- 记录失败状态,启动定时任务重试
- 超过3次后触发人工干预
- 补贴回收失败
- 冻结商户账户资金
- 通过消息通知商户补足余额
- 后续结算时自动抵扣
结算周期优化
- 延迟补贴回收
若实时回收失败,在商户结算周期中优先扣除待回收金额:public BigDecimal calculateSettleAmount(Merchant merchant) { BigDecimal income = merchant.getTotalIncome(); // 商户待结算收入 BigDecimal pendingRefunds = subsidyOrderService.getPendingRefunds(merchant.getId()); return income.subtract(pendingRefunds); // 实际结算金额 }
安全与合规
- 资金轨迹审计
- 为每笔补贴订单关联原支付订单号
- 保留完整的资金进出凭证(支付宝/微信交易单号)
- 商户协议约束
在商户入驻协议中明确平台券回收条款,授权平台在退款时扣回补贴。
此方案通过分离主订单与补贴订单的资金流,确保平台券的成本精准回收,同时兼容支付宝/微信双渠道的合并支付场景。