mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-08 22:25:32 +08:00
refactor(tenant): 运行态/配置态拆分 IgnoreTenant,回调 path 写入 mchNo
- 新增 CallbackMchContextFilter:/unipay/callback/{mchNo}/... 解析后走正常租户过滤
- Access 引导读统一 *NotTenant;initMch 后业务读(公钥等)走租户内
- 管理端路由/凭证配置去掉滥用的 NotTenant
- 通道认证能力/授权配置补 *NotTenant 读路径;AuthStrategy 走 resolveAppNotTenant
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -60,7 +60,7 @@ public class WechatDirectConfigAssembler {
|
||||
return credential;
|
||||
}
|
||||
|
||||
/// 解析支付使用的应用
|
||||
/// 解析支付使用的应用(须已装载 mchNo,租户内)
|
||||
///
|
||||
/// 优先级(委托 [WechatDirectAppCapabilityService.resolveApp]):
|
||||
/// 能力关联(显式配置 > appType自动推导) > 通道商户首个应用
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ import static java.util.Optional.ofNullable;
|
||||
/// - `initMch`:商户身份进上下文(所有交易场景必调)
|
||||
/// - `resolveApp`:应用解析(推导默认/校验启用),仅需要应用归属时调,返回应用信息供调用方显式 setAppId
|
||||
///
|
||||
/// 引导阶段通过 [MerchantAccessQueryService] 的 `*NotTenant` 读路径装载身份;
|
||||
/// **initMch 成功之后**业务链路应走正常租户过滤,勿再散落 `@IgnoreTenant`。
|
||||
/// appId 不进线程上下文:它是可空、可推导的业务属性,由调用方按需显式赋值到实体。
|
||||
@Slf4j
|
||||
@Service
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user