refactor(tenant): 运行态/配置态拆分 IgnoreTenant,回调 path 写入 mchNo

- 新增 CallbackMchContextFilter:/unipay/callback/{mchNo}/... 解析后走正常租户过滤
- Access 引导读统一 *NotTenant;initMch 后业务读(公钥等)走租户内
- 管理端路由/凭证配置去掉滥用的 NotTenant
- 通道认证能力/授权配置补 *NotTenant 读路径;AuthStrategy 走 resolveAppNotTenant
This commit is contained in:
DaxPay Dev
2026-07-10 18:12:11 +08:00
parent 9a7fe7b2b3
commit ea9db98e13
20 changed files with 181 additions and 36 deletions

View File

@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.alipay.dao.direct;
import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectAppCapability;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -27,7 +28,7 @@ public class AlipayDirectAppCapabilityManager extends BaseManager<AlipayDirectAp
.list();
}
/// 根据通道商户号与支付能力查询单条关联(支付时调用)
/// 根据通道商户号与支付能力查询单条关联支付/回调,租户内)
public Optional<AlipayDirectAppCapability> findOne(String channelMchNo, String capability) {
return lambdaQuery()
.eq(AlipayDirectAppCapability::getChannelMchNo, channelMchNo)
@@ -35,6 +36,12 @@ public class AlipayDirectAppCapabilityManager extends BaseManager<AlipayDirectAp
.oneOpt();
}
/// 根据通道商户号与支付能力查询单条关联(认证引导,忽略租户)
@IgnoreTenant
public Optional<AlipayDirectAppCapability> findOneNotTenant(String channelMchNo, String capability) {
return findOne(channelMchNo, capability);
}
/// 根据通道商户号删除全部关联(批量保存时先清后插)
public void deleteByChannelMchNo(String channelMchNo) {
lambdaUpdate()

View File

@@ -73,7 +73,8 @@ public class AlipayDirectConfigAssembler {
return credential;
}
/// 解析支付使用的应用,优先级:能力关联 > 通道商户首个 > 商户号首个兜底
/// 解析支付使用的应用(须已装载 mchNo租户内
/// 优先级:能力关联 > 通道商户首个 > 商户号首个兜底
private AlipayDirectApp resolveApp(String mchNo, String channelMchNo, String capability) {
// 1. 能力关联解析(显式配置 > appType自动推导)
Optional<AlipayDirectApp> resolved = alipayDirectAppCapabilityService.resolveApp(channelMchNo, capability);

View File

@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.douyin.dao.direct;
import cn.daxpay.open.channel.douyin.entity.direct.DouyinDirectAppCapability;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -27,7 +28,7 @@ public class DouyinDirectAppCapabilityManager extends BaseManager<DouyinDirectAp
.list();
}
/// 根据通道商户号与支付能力查询单条关联(支付时调用)
/// 根据通道商户号与支付能力查询单条关联支付/回调,租户内)
public Optional<DouyinDirectAppCapability> findOne(String channelMchNo, String capability) {
return lambdaQuery()
.eq(DouyinDirectAppCapability::getChannelMchNo, channelMchNo)
@@ -35,6 +36,12 @@ public class DouyinDirectAppCapabilityManager extends BaseManager<DouyinDirectAp
.oneOpt();
}
/// 根据通道商户号与支付能力查询单条关联(认证引导,忽略租户)
@IgnoreTenant
public Optional<DouyinDirectAppCapability> findOneNotTenant(String channelMchNo, String capability) {
return findOne(channelMchNo, capability);
}
/// 根据通道商户号删除全部关联(批量保存时先清后插)
public void deleteByChannelMchNo(String channelMchNo) {
lambdaUpdate()

View File

@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.wechat.dao.direct;
import cn.daxpay.open.channel.wechat.entity.direct.WechatDirectAppAuthConfig;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@@ -20,6 +21,14 @@ public class WechatDirectAppAuthConfigManager extends BaseManager<WechatDirectAp
.oneOpt();
}
/// 根据应用ID查询授权认证配置运行态认证使用, 忽略租户隔离)
@IgnoreTenant
public Optional<WechatDirectAppAuthConfig> findByWechatDirectAppIdNotTenant(Long wechatDirectAppId) {
return lambdaQuery()
.eq(WechatDirectAppAuthConfig::getWechatDirectAppId, wechatDirectAppId)
.oneOpt();
}
/// 根据应用ID删除授权认证配置
public void deleteByWechatDirectAppId(Long wechatDirectAppId) {
lambdaUpdate()

View File

@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.wechat.dao.direct;
import cn.daxpay.open.channel.wechat.entity.direct.WechatDirectAppCapability;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -27,7 +28,7 @@ public class WechatDirectAppCapabilityManager extends BaseManager<WechatDirectAp
.list();
}
/// 根据通道商户号与支付能力查询单条关联(支付时调用)
/// 根据通道商户号与支付能力查询单条关联支付/回调等已装载 mchNo 后使用,租户内)
public Optional<WechatDirectAppCapability> findOne(String channelMchNo, String capability) {
return lambdaQuery()
.eq(WechatDirectAppCapability::getChannelMchNo, channelMchNo)
@@ -35,6 +36,12 @@ public class WechatDirectAppCapabilityManager extends BaseManager<WechatDirectAp
.oneOpt();
}
/// 根据通道商户号与支付能力查询单条关联(认证等无租户上下文时使用,忽略租户)
@IgnoreTenant
public Optional<WechatDirectAppCapability> findOneNotTenant(String channelMchNo, String capability) {
return findOne(channelMchNo, capability);
}
/// 根据通道商户号删除全部关联(批量保存时先清后插)
public void deleteByChannelMchNo(String channelMchNo) {
lambdaUpdate()

View File

@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.wechat.dao.isv;
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvChannelMerchant;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@@ -19,10 +20,16 @@ public class WechatIsvChannelMerchantManager extends BaseManager<WechatIsvChanne
.exists();
}
/// 根据通道商户号查询
/// 根据通道商户号查询(支付/回调,已装载 mchNo租户内
public Optional<WechatIsvChannelMerchant> findByChannelMchNo(String channelMchNo) {
return lambdaQuery()
.eq(WechatIsvChannelMerchant::getChannelMchNo, channelMchNo)
.oneOpt();
}
/// 根据通道商户号查询(认证引导,忽略租户)
@IgnoreTenant
public Optional<WechatIsvChannelMerchant> findByChannelMchNoNotTenant(String channelMchNo) {
return findByChannelMchNo(channelMchNo);
}
}

View File

@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.wechat.dao.isv;
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvMchAppAuthConfig;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@@ -20,6 +21,14 @@ public class WechatIsvMchAppAuthConfigManager extends BaseManager<WechatIsvMchAp
.oneOpt();
}
/// 根据应用ID查询授权认证配置运行态认证使用, 忽略租户隔离)
@IgnoreTenant
public Optional<WechatIsvMchAppAuthConfig> findByWechatIsvMchAppIdNotTenant(Long wechatIsvMchAppId) {
return lambdaQuery()
.eq(WechatIsvMchAppAuthConfig::getWechatIsvMchAppId, wechatIsvMchAppId)
.oneOpt();
}
/// 根据应用ID删除授权认证配置
public void deleteByWechatIsvMchAppId(Long wechatIsvMchAppId) {
lambdaUpdate()

View File

@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.wechat.dao.isv;
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvMchAppCapability;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -27,7 +28,7 @@ public class WechatIsvMchAppCapabilityManager extends BaseManager<WechatIsvMchAp
.list();
}
/// 根据通道商户号与支付能力查询单条关联(支付时调用)
/// 根据通道商户号与支付能力查询单条关联支付/回调,租户内)
public Optional<WechatIsvMchAppCapability> findOne(String channelMchNo, String capability) {
return lambdaQuery()
.eq(WechatIsvMchAppCapability::getChannelMchNo, channelMchNo)
@@ -35,6 +36,12 @@ public class WechatIsvMchAppCapabilityManager extends BaseManager<WechatIsvMchAp
.oneOpt();
}
/// 根据通道商户号与支付能力查询单条关联(认证引导,忽略租户)
@IgnoreTenant
public Optional<WechatIsvMchAppCapability> findOneNotTenant(String channelMchNo, String capability) {
return findOne(channelMchNo, capability);
}
/// 根据通道商户号删除全部关联(批量保存时先清后插)
public void deleteByChannelMchNo(String channelMchNo) {
lambdaUpdate()

View File

@@ -60,7 +60,7 @@ public class WechatDirectConfigAssembler {
return credential;
}
/// 解析支付使用的应用
/// 解析支付使用的应用(须已装载 mchNo租户内
///
/// 优先级(委托 [WechatDirectAppCapabilityService.resolveApp]):
/// 能力关联(显式配置 > appType自动推导) > 通道商户首个应用

View File

@@ -50,10 +50,11 @@ public class WechatIsvConfigAssembler {
// 服务商密钥(全局唯一, 含 sp_mchid 与证书; 缺失或关键字段为空时 fail-fast)
WechatIsvKeyConfig keyConfig = wechatIsvKeyConfigService.getByProductForPay(ProductEnum.WECHAT_ISV.getCode());
// 特约商户绑定(取 sub_mchid)
// 支付/回调须已装载 mchNo通道商户走租户内查询
WechatIsvChannelMerchant channelMerchant = wechatIsvChannelMerchantManager.findByChannelMchNo(channelMchNo)
// 微信: 通道商户配置不存在
.orElseThrow(() -> new DataNotExistException("error.payment.channel.channelMerchantNotExist"));
// 服务商应用(取 sp_appid, 必须存在)
// 服务商应用为平台级(非 MchBaseEntity),无租户过滤
WechatIsvApp isvApp = wechatIsvAppCapabilityService.resolveApp(capability)
// 微信: 服务商应用不存在
.orElseThrow(() -> new DataNotExistException("error.channel.wechat.appNotFound"));

View File

@@ -96,7 +96,7 @@ public class WechatDirectAuthStrategy extends AbsChannelAuthStrategy {
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"error.channel.wechat.opAppIdNotFound", opAppId));
}
return wechatDirectAppCapabilityService.resolveApp(channelMchNo, capability)
return wechatDirectAppCapabilityService.resolveAppNotTenant(channelMchNo, capability)
// 微信: 直连商户应用不存在
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"error.channel.wechat.mchAppNotFound"));

View File

@@ -127,7 +127,7 @@ public class WechatIsvAuthStrategy extends AbsChannelAuthStrategy {
return new ResolvedAuthApp(app.getWxAppId(), cfg.getAppSecret());
}
// SUB_APP: 子商户应用(仅显式配置, 未配置返回empty)
WechatIsvMchApp app = wechatIsvMchAppCapabilityService.resolveApp(channelMchNo, capability)
WechatIsvMchApp app = wechatIsvMchAppCapabilityService.resolveAppNotTenant(channelMchNo, capability)
// 微信: 服务商通道商户应用不存在
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"error.channel.wechat.mchAppNotFound"));

View File

@@ -0,0 +1,67 @@
package cn.daxpay.open.payment.common.runtime;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/// # 通道回调商户上下文过滤器
///
/// 所有通道回调路径约定为 `/unipay/callback/{mchNo}/{appId}/...`。
/// 在 [PaymentContextFilter] 开启作用域后,从 path 解析 mchNo 写入 [PaymentContext]
/// 使回调链路在验签/查单/组装凭证时走**正常租户过滤**,无需再依赖 `@IgnoreTenant`。
///
/// 须晚于 [PaymentContextFilter]open 之后)执行。
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class CallbackMchContextFilter extends OncePerRequestFilter implements Ordered {
/// 匹配 .../unipay/callback/{mchNo}/...
private static final Pattern CALLBACK_MCH_PATH =
Pattern.compile(".*/unipay/callback/([^/]+)/.*");
private final PaymentContext paymentContext;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (paymentContext.isOpen()) {
String mchNo = extractMchNo(request.getRequestURI());
if (StrUtil.isNotBlank(mchNo)) {
paymentContext.setMchNo(mchNo);
}
}
filterChain.doFilter(request, response);
}
/// 从回调 URI 解析商户号;非回调路径返回 null
private static String extractMchNo(String requestUri) {
if (StrUtil.isBlank(requestUri)) {
return null;
}
Matcher matcher = CALLBACK_MCH_PATH.matcher(requestUri);
if (!matcher.matches()) {
return null;
}
return matcher.group(1);
}
@Override
public int getOrder() {
// PaymentContextFilter = HIGHEST_PRECEDENCE + 100
return Ordered.HIGHEST_PRECEDENCE + 101;
}
}

View File

@@ -27,6 +27,8 @@ import static java.util.Optional.ofNullable;
/// - `initMch`:商户身份进上下文(所有交易场景必调)
/// - `resolveApp`:应用解析(推导默认/校验启用),仅需要应用归属时调,返回应用信息供调用方显式 setAppId
///
/// 引导阶段通过 [MerchantAccessQueryService] 的 `*NotTenant` 读路径装载身份;
/// **initMch 成功之后**业务链路应走正常租户过滤,勿再散落 `@IgnoreTenant`。
/// appId 不进线程上下文:它是可空、可推导的业务属性,由调用方按需显式赋值到实体。
@Slf4j
@Service

View File

@@ -25,18 +25,30 @@ import java.util.Optional;
@RequiredArgsConstructor
public class MchAppInfoManager extends BaseManager<MchAppInfoMapper, MchAppInfo> {
/// 根据应用AppId查询, 商户端使用会过滤租户
/// 根据应用AppId查询(配置态,租户内)
public Optional<MchAppInfo> findByAppId(String appId) {
return this.findByField(MchAppInfo::getAppId, appId);
}
/// 按应用号加载商户应用,不存在则抛配置异常(配置态,租户内;运营端 ignoreTable
public MchAppInfo requireByAppId(String appId) {
return findByAppId(appId)
// 商户: 未找到指定应用的配置
.orElseThrow(() -> new ConfigNotExistException("error.payment.merchant.specifiedAppConfigNotFound"));
}
/// 按应用号解析商户号(配置态,租户内)
public String requireMchNoByAppId(String appId) {
return requireByAppId(appId).getMchNo();
}
/// 根据应用AppId查询 忽略租户拦截
/// 根据应用AppId查询(运行态引导,忽略租户
@IgnoreTenant
public Optional<MchAppInfo> findByAppIdNotTenant(String appId) {
return this.findByField(MchAppInfo::getAppId, appId);
}
/// 按应用号加载商户应用,不存在则抛配置异常(忽略租户)
/// 按应用号加载商户应用(运行态引导,忽略租户)
@IgnoreTenant
public MchAppInfo requireByAppIdNotTenant(String appId) {
return findByAppIdNotTenant(appId)
@@ -44,7 +56,7 @@ public class MchAppInfoManager extends BaseManager<MchAppInfoMapper, MchAppInfo>
.orElseThrow(() -> new ConfigNotExistException("error.payment.merchant.specifiedAppConfigNotFound"));
}
/// 按应用号解析商户号(忽略租户)
/// 按应用号解析商户号(运行态引导,忽略租户)
@IgnoreTenant
public String requireMchNoByAppIdNotTenant(String appId) {
return requireByAppIdNotTenant(appId).getMchNo();

View File

@@ -1,6 +1,5 @@
package cn.daxpay.open.payment.merchant.service.config;
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
import cn.daxpay.open.platform.core.exception.DataNotExistException;
import cn.daxpay.open.platform.common.config.properties.PlatformConfigProperties;
import cn.daxpay.open.platform.core.util.RsaSignUtil;
@@ -15,8 +14,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/// # 商户API配置服务
/// # 商户API配置服务(配置态)
///
/// 管理端/商户端凭证查询与更新。须在已有租户上下文(登录 Filter / 运营端 ignoreTable下调用。
/// 网关验签取公钥请走 [cn.daxpay.open.payment.merchant.service.query.MerchantAccessQueryService]。
@Slf4j
@Service
@RequiredArgsConstructor
@@ -25,8 +26,7 @@ public class MerchantCredentialService {
private final MerchantInfoManager merchantInfoManager;
private final PlatformConfigProperties platformConfigProperties;
/// 根据商户号查询
@IgnoreTenant
/// 根据商户号查询(配置态,租户内;运营端由 ignoreTable 放开)
public MerchantCredentialResult findByMchNo(String mchNo) {
String publicKey = platformConfigProperties.getKeyConfig().getPublicKey();
var credentialOptional = credentialManager.findByMchNo(mchNo);

View File

@@ -3,38 +3,42 @@ package cn.daxpay.open.payment.merchant.service.query;
import cn.daxpay.open.payment.merchant.dto.MchAppInfoAccessInfo;
import cn.daxpay.open.payment.merchant.dto.MerchantAccessInfo;
import cn.daxpay.open.payment.merchant.dao.appinfo.MchAppInfoManager;
import cn.daxpay.open.payment.merchant.dao.config.MerchantCredentialManager;
import cn.daxpay.open.payment.merchant.dao.info.MerchantInfoManager;
import cn.daxpay.open.payment.merchant.entity.appinfo.MchAppInfo;
import cn.daxpay.open.payment.merchant.entity.config.MerchantCredential;
import cn.daxpay.open.payment.merchant.entity.info.MerchantInfo;
import cn.daxpay.open.payment.merchant.service.config.MerchantCredentialService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/// # 商户接入信息查询服务
/// # 商户接入信息查询服务(运行态 Access
///
/// 供支付总线层查询商户/应用接入信息,返回精简 DTO,不暴露 JPA 实体
/// 供支付总线层在**商户上下文尚未装载**时查询商户/应用接入信息返回精简 DTO。
/// 引导类读路径统一走 `*NotTenant``initMch` 之后的业务读(如公钥验签)走租户内查询。
///
/// 配置态 CRUD 请使用各业务 Service勿在此扩展管理端能力。
@Service
@RequiredArgsConstructor
public class MerchantAccessQueryService {
private final MerchantInfoManager merchantInfoManager;
private final MchAppInfoManager mchAppInfoManager;
private final MerchantCredentialService merchantCredentialService;
private final MerchantCredentialManager merchantCredentialManager;
/// 根据商户号查询商户接入信息
/// 根据商户号查询商户接入信息(引导用,忽略租户)
public MerchantAccessInfo getMerchantByMchNo(String mchNo) {
return merchantInfoManager.findByMchNo(mchNo)
return merchantInfoManager.findByMchNoNotTenant(mchNo)
.map(this::toMerchantAccessInfo)
.orElse(null);
}
/// 根据商户号查询默认应用
/// 根据商户号查询默认应用(引导用,忽略租户)
public MchAppInfoAccessInfo getDefaultAppByMchNo(String mchNo) {
return mchAppInfoManager.findDefaultByMchNoNotTenant(mchNo)
.map(this::toMchAppInfoAccessInfo)
.orElse(null);
}
/// 根据应用号查询应用
/// 根据应用号查询应用(引导用,忽略租户)
public MchAppInfoAccessInfo getAppByAppId(String appId) {
return mchAppInfoManager.findByAppIdNotTenant(appId)
.map(this::toMchAppInfoAccessInfo)
@@ -42,8 +46,12 @@ public class MerchantAccessQueryService {
}
/// 根据商户号查询商户公钥
///
/// 调用方须已完成 `initMch`(或回调 Filter 已写入 mchNo走**租户内**查询。
public String findMerchantPublicKey(String mchNo) {
return merchantCredentialService.findByMchNo(mchNo).getPublicKey();
return merchantCredentialManager.findByMchNo(mchNo)
.map(MerchantCredential::getPublicKey)
.orElse(null);
}
private MerchantAccessInfo toMerchantAccessInfo(MerchantInfo merchantInfo) {

View File

@@ -41,7 +41,7 @@ public class PayRouteBasicConfigService {
/// 查询基础模式面板数据(已保存通道商户号 + 各渠道可选通道商户列表)
public List<PayRouteBasicConfigResult> listBasicByAppId(String appId) {
String mchNo = mchAppInfoManager.requireMchNoByAppIdNotTenant(appId);
String mchNo = mchAppInfoManager.requireMchNoByAppId(appId);
PayRouteStrategy strategy = requireStrategy(appId);
Map<String, String> mchMap = basicConfigManager.findByStrategyId(strategy.getId()).stream()
.filter(config -> StrUtil.isNotBlank(config.getProvider()))
@@ -55,7 +55,7 @@ public class PayRouteBasicConfigService {
/// 批量保存基础模式配置(先删后插)
@Transactional(rollbackFor = Exception.class)
public void saveBasicBatch(PayRouteBasicConfigBatchParam param) {
String mchNo = mchAppInfoManager.requireMchNoByAppIdNotTenant(param.getAppId());
String mchNo = mchAppInfoManager.requireMchNoByAppId(param.getAppId());
PayRouteStrategy strategy = requireStrategy(param.getAppId());
basicConfigManager.deleteByStrategyId(strategy.getId());
for (PayRouteBasicConfigItem item : param.getItems()) {

View File

@@ -39,7 +39,8 @@ public class PayRouteConfigService {
/// 按应用号获取路由策略,不存在则创建默认基础模式策略
@Transactional(rollbackFor = Exception.class)
public PayRouteStrategyResult getOrInitByAppId(String appId) {
mchAppInfoManager.requireByAppIdNotTenant(appId);
// 配置态:运营端 ignoreTable / 租户内查应用
mchAppInfoManager.requireByAppId(appId);
return strategyManager.findByAppId(appId)
.map(PayRouteStrategy::toResult)
.orElseGet(() -> createDefaultStrategy(appId));
@@ -49,7 +50,7 @@ public class PayRouteConfigService {
private PayRouteStrategyResult createDefaultStrategy(String appId) {
PayRouteStrategy strategy = new PayRouteStrategy();
strategy.setAppId(appId);
strategy.setMchNo(mchAppInfoManager.requireMchNoByAppIdNotTenant(appId));
strategy.setMchNo(mchAppInfoManager.requireMchNoByAppId(appId));
strategy.setMode(PayRouteModeEnum.BASIC.getCode());
strategyManager.save(strategy);
return strategy.toResult();
@@ -58,7 +59,7 @@ public class PayRouteConfigService {
/// 更新应用路由策略(模式、支付渠道、启用状态、名称)
@Transactional(rollbackFor = Exception.class)
public PayRouteStrategyResult updateStrategy(PayRouteStrategyParam param) {
mchAppInfoManager.requireByAppIdNotTenant(param.getAppId());
mchAppInfoManager.requireByAppId(param.getAppId());
PayRouteStrategy strategy = strategyManager.findByAppId(param.getAppId())
.orElseThrow(() -> new DataNotExistException("pay.route.error.routeStrategyNotExist"));
PayRouteStrategyConvert.CONVERT.copy(param, strategy);

View File

@@ -59,7 +59,7 @@ public class PayRouteSceneConfigService {
/// 批量保存场景模式配置全量覆盖method 唯一、通道商户/能力校验)
@Transactional(rollbackFor = Exception.class)
public void saveSceneBatch(PayRouteSceneConfigBatchParam param) {
String mchNo = mchAppInfoManager.requireMchNoByAppIdNotTenant(param.getAppId());
String mchNo = mchAppInfoManager.requireMchNoByAppId(param.getAppId());
PayRouteStrategy strategy = requireStrategy(param.getAppId());
validateSceneConfigUnique(param.getItems());
validateSceneChannelMchCapabilityPairing(param.getItems());
@@ -114,13 +114,13 @@ public class PayRouteSceneConfigService {
/// 通道路由白名单目录下全部 (provider,method) 的通道商户候选(批量)
public Map<String, List<LabelValue>> listSceneChannelMchCandidatesBatch(String appId) {
String mchNo = mchAppInfoManager.requireMchNoByAppIdNotTenant(appId);
String mchNo = mchAppInfoManager.requireMchNoByAppId(appId);
return payRouteStrategyCapabilitySupport.listSceneChannelMchCandidatesBatch(mchNo);
}
/// 按目录项+通道商户批量返回支付能力候选
public Map<String, List<LabelValue>> listSceneCapabilityCandidatesBatch(PayRouteSceneCapabilityBatchParam param) {
mchAppInfoManager.requireMchNoByAppIdNotTenant(param.getAppId());
mchAppInfoManager.requireMchNoByAppId(param.getAppId());
return payRouteStrategyCapabilitySupport.listSceneCapabilityCandidatesBatch(param.getItems());
}
@@ -129,7 +129,7 @@ public class PayRouteSceneConfigService {
if (StrUtil.isBlank(method) || !payProviderMethodService.contains(provider, method)) {
return List.of();
}
String mchNo = mchAppInfoManager.requireMchNoByAppIdNotTenant(appId);
String mchNo = mchAppInfoManager.requireMchNoByAppId(appId);
return payRouteStrategyCapabilitySupport.listSceneChannelMchCandidates(mchNo, provider, method);
}