From e09137247daa5430d2757813bc79ddc08daca2ed Mon Sep 17 00:00:00 2001 From: dzc <2388224167@qq.com> Date: Fri, 28 Aug 2026 20:48:15 +0800 Subject: [PATCH] 11 --- .../pay/wechat/ThirdAppPlusPayDto.java | 11 ++++-- .../pay/ThirdAggregatePayCreateContext.java | 5 ++- .../service/ThirdMchFzRelationService.java | 2 +- .../ThirdAggregateAliPayServiceImpl.java | 27 +++++++------- .../ThirdAggregateOrderPayServiceImpl.java | 5 ++- .../ThirdAppPlusAliPayServiceImpl.java | 34 +++++++++--------- .../impl/appplus/ThirdAppPlusServiceImpl.java | 5 ++- .../pay/ThirdMchFzRelationServiceImpl.java | 6 ++-- .../impl/pay/ThirdPayOrderServiceImpl.java | 23 ++++++------ .../ThirdAggregateAliPayServiceImplTest.java | 7 +++- .../ThirdAppPlusAliPayServiceImplTest.java | 35 +++++++++++++++---- ...irdAppPlusServiceImplOrderCodePayTest.java | 30 +++++++++++++--- .../ThirdMchFzRelationServiceImplTest.java | 8 ++--- 13 files changed, 131 insertions(+), 67 deletions(-) diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdAppPlusPayDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdAppPlusPayDto.java index 6c074dc17..9047ae877 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdAppPlusPayDto.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/appplus/pay/wechat/ThirdAppPlusPayDto.java @@ -4,20 +4,25 @@ import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderBizTypeEnum; import lombok.Data; /** - * app支付参数 + * 第三方渠道支付创建参数,仅由服务端支付编排层构造并传给具体渠道实现。 */ @Data public class ThirdAppPlusPayDto { + /** + * 收款商户主键,来源于服务端已校验的业务订单或商户资料。 + */ private Long mchId; /** - * 支付创建前由服务端解析的已绑定平台分佣关系主键;客户端不得提交或覆盖。 + * 支付创建前由服务端解析的平台分佣关系主键;客户端不得提交或覆盖。 + * 为空只表示本单关闭分账,不代表支付宝直付通可以省略 {@link #subMchid}。 */ private Long fzRelationId; /** - * 子商户id + * 订单创建时由服务端从默认关系复制的渠道二级商户标识。 + * 支付宝直付通无论是否分账都必须携带,客户端不得提交或覆盖。 */ private String subMchid; diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/model/pay/ThirdAggregatePayCreateContext.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/model/pay/ThirdAggregatePayCreateContext.java index 87f7767a8..03247a301 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/model/pay/ThirdAggregatePayCreateContext.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/model/pay/ThirdAggregatePayCreateContext.java @@ -38,7 +38,10 @@ public class ThirdAggregatePayCreateContext { */ private Long mchId; - /** 创建子订单时固定的平台分佣关系主键;由服务端在平台选择后填充。 */ + /** + * 创建子订单时固定的平台分佣关系主键,由服务端在平台选择后填充。 + * 为空只表示本单关闭分账,支付宝直付通仍必须从订单级渠道快照读取 smid/ip_role_id。 + */ private Long fzRelationId; /** diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMchFzRelationService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMchFzRelationService.java index 214f939fb..8c4619038 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMchFzRelationService.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdMchFzRelationService.java @@ -32,7 +32,7 @@ public interface ThirdMchFzRelationService { /** * 删除关系;已绑定关系只标记为历史关系,删除默认关系后允许当前支付配置暂时没有默认关系。 - * 支付宝在没有默认关系时按普通支付处理;微信服务商支付仍需默认关系提供子商户路由。 + * 支付宝直付通和微信服务商支付都需要默认关系提供二级商户路由,缺失期间新支付将被拒绝。 * 历史订单继续使用原关系快照完成退款或退分账。 * * @param ids 关系主键列表 diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateAliPayServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateAliPayServiceImpl.java index c24397af1..f59434dc6 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateAliPayServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateAliPayServiceImpl.java @@ -156,11 +156,10 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ model.setProductCode(PRODUCT_CODE); model.setTimeExpire(LocalDateTimeUtil.format(context.getExpireTime(), DatePattern.NORM_DATETIME_PATTERN)); boolean enableFz = context.getFzRelationId() != null; - if (enableFz) { - SubMerchant subMerchant = new SubMerchant(); - subMerchant.setMerchantId(aliPaySetting.getSubMchid()); - model.setSubMerchant(subMerchant); - } + // fzRelationId 只控制平台抽佣,直付通无论是否分账都必须携带二级商户标识。 + SubMerchant subMerchant = new SubMerchant(); + subMerchant.setMerchantId(aliPaySetting.getSubMchid()); + model.setSubMerchant(subMerchant); if (StrUtil.isNotBlank(identity.getOpenId())) { model.setBuyerOpenId(identity.getOpenId()); } else { @@ -171,7 +170,7 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ AppPlusPayConfig.AliPayConfig aliPayConfig = appPlusPayConfig.getAliPayConfig(); request.setNotifyUrl(aliPayConfig.getBaseCallbackUrl() + aliPayConfig.getPayCallbackUrl()); request.setBizModel(model); - // 普通支付不携带关系专属授权;直付通仅在配置了代调用授权时发送 token。 + // 关闭分账不携带平台抽佣专属授权;开启分账且配置了代调用授权时才发送 token。 if (enableFz && StrUtil.isNotBlank(aliPaySetting.getAppAuthToken())) { request.putOtherTextParam(APP_AUTH_TOKEN_PARAM, aliPaySetting.getAppAuthToken()); } @@ -317,20 +316,20 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ } /** - * 校验商户支付宝配置并解析可选 app_auth_token;普通支付允许配置 JSON 为空。 + * 校验订单创建时生成的支付宝渠道快照并解析可选 app_auth_token。 * * @param paySetting 当前商户启用的支付宝支付配置 - * @return 支付宝配置;无关系配置时返回空对象 + * @return 包含必填 smid/ip_role_id 的支付宝订单级渠道配置 */ private MchPaySettingEntity.AliPaySetting parseAliPaySetting(MchPaySettingVo paySetting) { - if (paySetting == null) { - throw new RuntimeException("商户支付宝支付配置不存在"); - } - if (StrUtil.isBlank(paySetting.getSettingJson())) { - return new MchPaySettingEntity.AliPaySetting(); + if (paySetting == null || StrUtil.isBlank(paySetting.getSettingJson())) { + throw new RuntimeException("商户支付宝支付配置不完整"); } MchPaySettingEntity.AliPaySetting setting = JSONUtil.toBean(paySetting.getSettingJson(), MchPaySettingEntity.AliPaySetting.class); - return setting == null ? new MchPaySettingEntity.AliPaySetting() : setting; + if (setting == null || StrUtil.isBlank(setting.getSubMchid())) { + throw new RuntimeException("商户支付宝直付通二级商户标识未配置"); + } + return setting; } /** 聚合支付底层再次校验分佣关系,防止绕过编排层直接创建无关系直付通订单。 */ diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateOrderPayServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateOrderPayServiceImpl.java index faa7cbcc5..f6557662c 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateOrderPayServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAggregateOrderPayServiceImpl.java @@ -1208,7 +1208,7 @@ public class ThirdAggregateOrderPayServiceImpl implements ThirdAggregateOrderPay * 聚合支付选定平台后解析可选默认关系,并生成只属于当前子订单的渠道配置快照。 * *
默认关系始终提供渠道商户路由;只有关系明确开启分账时才写入分账关系主键。 - * 未配置默认关系时支付宝按普通支付创建子订单。
+ * 支付宝直付通没有默认关系时无法取得可信 smid/ip_role_id,必须拒绝创建子订单。 * * @param setting 已确认启用的支付配置 * @param context 聚合子订单创建上下文 @@ -1218,6 +1218,9 @@ public class ThirdAggregateOrderPayServiceImpl implements ThirdAggregateOrderPay ThirdMchFzRelationEntity relation = mchFzRelationService.findBoundDefault(setting); if (relation == null) { context.setFzRelationId(null); + if (ObjectUtil.equals(setting.getPlatformType(), AppPlusPlatformPayType.ALI_PAY.getType())) { + throw new IllegalStateException("商户未配置支付宝直付通二级商户关系"); + } return setting; } context.setFzRelationId(YesNoEnum.NO.getCode().equals(relation.getEnableFz()) ? null : relation.getId()); diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusAliPayServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusAliPayServiceImpl.java index d1ef3531f..8899c5704 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusAliPayServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusAliPayServiceImpl.java @@ -352,11 +352,10 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService model.setSubject(ORDER_CODE_SUBJECT); model.setProductCode(ORDER_CODE_PRODUCT_CODE); model.setTimeExpire(LocalDateTimeUtil.format(expireTime, DatePattern.NORM_DATETIME_PATTERN)); - if (enableFz) { - SubMerchant subMerchant = new SubMerchant(); - subMerchant.setMerchantId(aliPaySetting.getSubMchid()); - model.setSubMerchant(subMerchant); - } + // fzRelationId 只控制平台抽佣,直付通无论是否分账都必须携带二级商户标识。 + SubMerchant subMerchant = new SubMerchant(); + subMerchant.setMerchantId(aliPaySetting.getSubMchid()); + model.setSubMerchant(subMerchant); payOrder.setPayRep(JSONUtil.toJsonStr(model)); request.setBizModel(model); @@ -422,8 +421,8 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService /** * 创建支付宝 App 支付订单。 * - *只有订单携带已绑定默认关系时才创建直付通请求;没有关系时按平台普通支付创建, - * 不发送二级商户、延迟结算或商户授权参数。
+ *{@code fzRelationId} 只控制平台抽佣;直付通路由始终使用订单级关系快照中的 + * smid/ip_role_id,关闭分账也不得降级为不携带二级商户标识的普通支付。
* * @param dto 已由编排层校验的支付参数,金额单位为人民币分 * @param setting 当前商户启用的支付宝支付配置或关系快照 @@ -485,7 +484,7 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService model.setSubMerchant(subMerchant); SettleInfo directPaySettleInfo = new SettleInfo(); directPaySettleInfo.setSettlePeriodTime("1d"); - // 直付通延迟结算必须填写默认结算明细,普通支付不能携带该参数。 + // 直付通延迟结算必须填写默认结算明细,关闭平台抽佣不改变直付通结算模型。 ArrayList默认关系始终提供渠道商户路由;只有关系明确开启分账时才把关系主键传给渠道服务。 - * 未配置默认关系时不携带渠道关系参数,支付宝按普通支付处理。
+ * 支付宝直付通没有默认关系时无法取得可信 smid/ip_role_id,必须拒绝下单。 * * @param paySetting 已由商户服务确认启用的支付配置 * @param payDto 即将提交渠道服务的内部支付参数 @@ -760,6 +760,9 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService { if (relation == null) { payDto.setFzRelationId(null); payDto.setSubMchid(null); + if (ObjectUtil.equals(paySetting.getPlatformType(), AppPlusPlatformPayType.ALI_PAY.getType())) { + throw new IllegalStateException("商户未配置支付宝直付通二级商户关系"); + } return paySetting; } payDto.setFzRelationId(YesNoEnum.NO.getCode().equals(relation.getEnableFz()) ? null : relation.getId()); diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdMchFzRelationServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdMchFzRelationServiceImpl.java index 99265488d..ccd73ee95 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdMchFzRelationServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdMchFzRelationServiceImpl.java @@ -473,7 +473,7 @@ public class ThirdMchFzRelationServiceImpl implements ThirdMchFzRelationService * 删除关系;已绑定关系保留为历史事实,只移出默认候选,避免历史订单无法退分账。 * *删除默认关系不再强制寻找替代关系。删除后当前支付配置可以暂时没有默认关系, - * 支付宝新订单按普通支付处理;微信服务商支付仍需配置一条提供子商户路由的默认关系。 + * 但支付宝直付通和微信服务商支付都将在新下单时因缺少二级商户路由而拒付。 * 历史订单继续按原关系快照退款和退分账。
* * @param ids 关系主键 @@ -590,7 +590,7 @@ public class ThirdMchFzRelationServiceImpl implements ThirdMchFzRelationService } /** - * 查询支付配置当前可选的默认渠道关系;没有默认关系表示按渠道允许的普通支付处理。 + * 查询支付配置当前可选的默认渠道关系;没有默认关系时由具体渠道决定是否拒绝支付。 * * @param setting 商户支付配置 * @return 默认关系;关闭分账时不要求绑定,未配置默认关系时返回 {@code null} @@ -653,7 +653,7 @@ public class ThirdMchFzRelationServiceImpl implements ThirdMchFzRelationService snapshot.setSettingJson(JSONUtil.toJsonStr(channel)); } else if (ALIPAY_TYPE.equals(setting.getPlatformType())) { MchPaySettingEntity.AliPaySetting channel = new MchPaySettingEntity.AliPaySetting(); - // 关闭分账的支付宝关系只承担本地配置归属,不得把直付通商户或授权参数带入普通支付。 + // 关闭分账仍是直付通交易,smid 必须保留;仅平台抽佣专属的账号和授权令牌不再复制。 if (isProfitSharingEnabled(relation)) { channel.setAccountKey(relation.getAccountKey()); channel.setAppAuthToken(relation.getAppAuthToken()); diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdPayOrderServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdPayOrderServiceImpl.java index 48ba69e52..c7cf8db0a 100755 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdPayOrderServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/pay/ThirdPayOrderServiceImpl.java @@ -18,14 +18,13 @@ import com.bsd.pjcloud.thirdparty.constant.miniplatform.AppPlusPlatformTypeEnum; import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderBizTypeEnum; import com.bsd.pjcloud.thirdparty.dto.pay.ThirdPayOrderDto; import com.bsd.pjcloud.thirdparty.entity.pay.ThirdFzOrderEntity; -import com.bsd.pjcloud.thirdparty.entity.pay.ThirdMchFzRelationEntity; import com.bsd.pjcloud.thirdparty.entity.pay.ThirdPayOrderEntity; import com.bsd.pjcloud.thirdparty.mapper.pay.ThirdPayOrderMapper; import com.bsd.pjcloud.thirdparty.mapper.pay.ThirdPaymentTaskMapper; import com.bsd.pjcloud.thirdparty.service.ThirdFzOrderService; -import com.bsd.pjcloud.thirdparty.service.ThirdMchFzRelationService; import com.bsd.pjcloud.thirdparty.service.ThirdPayOrderService; import com.bsd.pjcloud.thirdparty.vo.pay.ThirdPayOrderVo; +import com.bsd.pjcloud.wallet.api.entity.mch.MchPaySettingEntity; import com.bsd.pjcloud.wallet.api.feign.RemoteMchService; import com.bsd.pjcloud.wallet.api.vo.MchManageVo; import lombok.RequiredArgsConstructor; @@ -67,10 +66,6 @@ public class ThirdPayOrderServiceImpl extends ServiceImpl