mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-12 15:35:38 +08:00
feat(code-pay): method 判定 needOpenId,DIRECT 按能力反推 method
This commit is contained in:
@@ -3,10 +3,12 @@ package cn.daxpay.open.payment.admin.controller.merchant.gateway;
|
||||
import cn.daxpay.open.payment.merchant.param.gateway.GatewayCodeConfigParam;
|
||||
import cn.daxpay.open.payment.merchant.result.gateway.GatewayCodeConfigResult;
|
||||
import cn.daxpay.open.payment.merchant.service.gateway.GatewayCodeConfigService;
|
||||
import cn.daxpay.open.payment.route.service.support.PayRouteStrategyCapabilitySupport;
|
||||
import cn.daxpay.open.platform.core.annotation.PermCode;
|
||||
import cn.daxpay.open.platform.core.code.PermCodes;
|
||||
import cn.daxpay.open.platform.core.rest.Res;
|
||||
import cn.daxpay.open.platform.core.rest.result.Result;
|
||||
import cn.daxpay.open.platform.core.rest.dto.LabelValue;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@@ -14,6 +16,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// # 码牌支付策略配置(管理)
|
||||
@PermCode(menuCode = PermCodes.Merchant.GatewayCode.MENU)
|
||||
@Validated
|
||||
@@ -24,6 +28,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
public class GatewayCodeConfigAdminController {
|
||||
|
||||
private final GatewayCodeConfigService gatewayCodeConfigService;
|
||||
private final PayRouteStrategyCapabilitySupport payRouteStrategyCapabilitySupport;
|
||||
|
||||
@PermCode(code = PermCodes.Action.VIEW)
|
||||
@Operation(summary = "按应用查询码牌支付配置")
|
||||
@@ -40,4 +45,23 @@ public class GatewayCodeConfigAdminController {
|
||||
gatewayCodeConfigService.saveOrUpdate(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
/// DIRECT 模式: 按商户+支付渠道列通道商户(不绑死默认 JSAPI method)
|
||||
@PermCode(code = PermCodes.Action.VIEW)
|
||||
@Operation(summary = "直接指定-通道商户候选")
|
||||
@GetMapping("/direct-channel-mch-candidates")
|
||||
public Result<List<LabelValue>> listDirectChannelMchCandidates(
|
||||
@NotBlank(message = "{validation.field.mchNo.notBlank}") String mchNo,
|
||||
@NotBlank(message = "{validation.field.provider.notBlank}") String provider) {
|
||||
return Res.ok(payRouteStrategyCapabilitySupport.listDirectChannelMchCandidates(mchNo, provider));
|
||||
}
|
||||
|
||||
/// DIRECT 模式: 按通道商户列全部已挂载支付能力(不按默认 method 过滤,便于选 H5/主扫等)
|
||||
@PermCode(code = PermCodes.Action.VIEW)
|
||||
@Operation(summary = "直接指定-支付能力候选")
|
||||
@GetMapping("/direct-capability-candidates")
|
||||
public Result<List<LabelValue>> listDirectCapabilityCandidates(
|
||||
@NotBlank(message = "{validation.field.channelMchNo.notBlank}") String channelMchNo) {
|
||||
return Res.ok(payRouteStrategyCapabilitySupport.listDirectCapabilityCandidates(channelMchNo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.daxpay.open.payment.common.util;
|
||||
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/// # 支付方式是否需要买家 openId / userId
|
||||
///
|
||||
/// 供码牌 H5 OAuth 门控、聚合 meta、下单前校验共用。
|
||||
/// 与交互形态绑定(JSAPI/小程序需用户标识;H5/主扫等一般不需要),**不**挂产品/Gateway 策略。
|
||||
///
|
||||
/// 换票时序:授权回跳页立即 code→openId,支付只传 openId,禁止支付时再换 code。
|
||||
public final class PayMethodOpenIdSupport {
|
||||
|
||||
/// 需要买家标识的支付方式(与聚合历史白名单一致)
|
||||
private static final Set<String> METHODS_NEED_OPEN_ID = Set.of(
|
||||
PayMethodEnum.WECHAT_JSAPI.getCode(),
|
||||
PayMethodEnum.WECHAT_MINI.getCode(),
|
||||
PayMethodEnum.ALIPAY_JSAPI.getCode(),
|
||||
PayMethodEnum.UNION_JSAPI.getCode(),
|
||||
PayMethodEnum.DOUYIN_JSAPI.getCode()
|
||||
);
|
||||
|
||||
private PayMethodOpenIdSupport() {
|
||||
}
|
||||
|
||||
/// 该支付方式下单前是否需要 openId/userId
|
||||
///
|
||||
/// @param methodCode 支付方式编码,空则 false
|
||||
public static boolean needsOpenId(String methodCode) {
|
||||
if (StrUtil.isBlank(methodCode)) {
|
||||
return false;
|
||||
}
|
||||
if (METHODS_NEED_OPEN_ID.contains(methodCode)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
PayMethodEnum method = PayMethodEnum.findByCode(methodCode);
|
||||
return switch (method) {
|
||||
case WECHAT_JSAPI, WECHAT_MINI, ALIPAY_JSAPI, UNION_JSAPI, DOUYIN_JSAPI -> true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
catch (Exception e) {
|
||||
// 未知扩展 method: 含 jsapi/mini 视作需要
|
||||
String lower = methodCode.toLowerCase();
|
||||
return lower.contains("jsapi") || lower.contains("mini");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,10 @@ import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateConfig;
|
||||
import cn.daxpay.open.payment.merchant.enums.AggregateConfigLevelEnum;
|
||||
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
|
||||
import cn.daxpay.open.payment.merchant.enums.ClientRuntimeEnum;
|
||||
import cn.daxpay.open.payment.route.service.runtime.PayRouteService;
|
||||
import cn.daxpay.open.platform.common.i18n.util.I18nUtil;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -19,6 +22,7 @@ import org.springframework.stereotype.Service;
|
||||
/// 读应用级**聚合**扫码配置(AUTO/METHOD/DIRECT), 输出 method / channelMchNo / capability。
|
||||
/// 仅供 [cn.daxpay.open.payment.trade.runtime.service.pay.gateway.AggregatePayService] 使用。
|
||||
/// 码牌支付请使用 [CodePayResolveService], 不再读本服务。
|
||||
/// DIRECT: 与路由直接指定对齐——method 空时由 channelMch+capability 反推。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -26,6 +30,7 @@ public class ClientEnvPayResolveService {
|
||||
|
||||
private final GatewayAggregateConfigManager configManager;
|
||||
private final GatewayAggregateClientEnvManager clientEnvManager;
|
||||
private final PayRouteService payRouteService;
|
||||
|
||||
/// 解析结果
|
||||
public record Resolved(String method, String channelMchNo, String capability) {}
|
||||
@@ -55,13 +60,27 @@ public class ClientEnvPayResolveService {
|
||||
}
|
||||
case DIRECT -> {
|
||||
GatewayAggregateClientEnv envConfig = requireEnvConfig(config, clientEnv);
|
||||
if (StrUtil.isBlank(envConfig.getChannelMchNo())) {
|
||||
if (StrUtil.isBlank(envConfig.getChannelMchNo()) || StrUtil.isBlank(envConfig.getCapability())) {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"pay.error.gateway.clientEnvNotConfigured");
|
||||
}
|
||||
String method = StrUtil.isNotBlank(envConfig.getMethod())
|
||||
? ClientEnvEnum.adaptMethodForRuntime(envConfig.getMethod(), rt)
|
||||
: clientEnv.defaultMethodCode(rt);
|
||||
String method;
|
||||
if (StrUtil.isNotBlank(envConfig.getMethod())) {
|
||||
method = ClientEnvEnum.adaptMethodForRuntime(envConfig.getMethod(), rt);
|
||||
}
|
||||
else {
|
||||
// 与码牌/路由 DIRECT 一致:按能力反推,禁止静默默认 JSAPI
|
||||
String inferred = payRouteService.inferMethodForCapability(
|
||||
envConfig.getChannelMchNo(), envConfig.getCapability());
|
||||
if (StrUtil.isBlank(inferred)) {
|
||||
PayCapabilityEnum capEnum = PayCapabilityEnum.findByCode(envConfig.getCapability());
|
||||
String capLabel = capEnum != null ? I18nUtil.getEnumName(capEnum) : envConfig.getCapability();
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"pay.route.error.directCapabilityChannelMchMismatch",
|
||||
capLabel, envConfig.getChannelMchNo());
|
||||
}
|
||||
method = ClientEnvEnum.adaptMethodForRuntime(inferred, rt);
|
||||
}
|
||||
yield new Resolved(method, envConfig.getChannelMchNo(), envConfig.getCapability());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,7 +7,10 @@ import cn.daxpay.open.payment.merchant.entity.gateway.GatewayCodeConfig;
|
||||
import cn.daxpay.open.payment.merchant.enums.AggregateConfigLevelEnum;
|
||||
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
|
||||
import cn.daxpay.open.payment.merchant.enums.CodePayFormEnum;
|
||||
import cn.daxpay.open.payment.route.service.runtime.PayRouteService;
|
||||
import cn.daxpay.open.platform.common.i18n.util.I18nUtil;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -18,6 +21,7 @@ import org.springframework.stereotype.Service;
|
||||
///
|
||||
/// 仅读 [GatewayCodeConfig] 系列表; **不回落**聚合配置。
|
||||
/// METHOD/DIRECT 使用子表配置字面值, **不做** jsapi→mini 隐式升级。
|
||||
/// DIRECT: 与路由直接指定对齐——method 空时由 channelMch+capability 反推,禁止静默默认 JSAPI。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -25,6 +29,7 @@ public class CodePayResolveService {
|
||||
|
||||
private final GatewayCodeConfigManager configManager;
|
||||
private final GatewayCodeClientEnvManager clientEnvManager;
|
||||
private final PayRouteService payRouteService;
|
||||
|
||||
/// 解析结果
|
||||
public record Resolved(String method, String channelMchNo, String capability) {}
|
||||
@@ -49,18 +54,33 @@ public class CodePayResolveService {
|
||||
}
|
||||
case DIRECT -> {
|
||||
GatewayCodeClientEnv envConfig = requireEnvConfig(config, clientEnv, form);
|
||||
if (StrUtil.isBlank(envConfig.getChannelMchNo())) {
|
||||
if (StrUtil.isBlank(envConfig.getChannelMchNo()) || StrUtil.isBlank(envConfig.getCapability())) {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"pay.error.gateway.codeClientEnvNotConfigured");
|
||||
}
|
||||
String method = StrUtil.isNotBlank(envConfig.getMethod())
|
||||
? envConfig.getMethod()
|
||||
: form.defaultMethodCode(clientEnv);
|
||||
String method = resolveDirectMethod(
|
||||
envConfig.getMethod(), envConfig.getChannelMchNo(), envConfig.getCapability());
|
||||
yield new Resolved(method, envConfig.getChannelMchNo(), envConfig.getCapability());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// DIRECT: 优先用已配 method;否则按通道商户+能力反推(与 [PayRouteService#inferMethodForCapability] 一致)
|
||||
private String resolveDirectMethod(String configuredMethod, String channelMchNo, String capability) {
|
||||
if (StrUtil.isNotBlank(configuredMethod)) {
|
||||
return configuredMethod;
|
||||
}
|
||||
String inferred = payRouteService.inferMethodForCapability(channelMchNo, capability);
|
||||
if (StrUtil.isBlank(inferred)) {
|
||||
PayCapabilityEnum capEnum = PayCapabilityEnum.findByCode(capability);
|
||||
String capLabel = capEnum != null ? I18nUtil.getEnumName(capEnum) : capability;
|
||||
// 支付能力与通道商户不匹配(无法反推 method)
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"pay.route.error.directCapabilityChannelMchMismatch", capLabel, channelMchNo);
|
||||
}
|
||||
return inferred;
|
||||
}
|
||||
|
||||
private GatewayCodeClientEnv requireEnvConfig(
|
||||
GatewayCodeConfig config, ClientEnvEnum clientEnv, CodePayFormEnum payForm) {
|
||||
GatewayCodeClientEnv envConfig = clientEnvManager.findByConfigIdAndClientEnvAndPayForm(
|
||||
|
||||
@@ -112,8 +112,10 @@ public class PayRouteService {
|
||||
}
|
||||
|
||||
/// 直接指定: 由(通道商户, 支付能力)反推支付方式编码(策略 Map + DB 启用, 无则 null)
|
||||
/// 查询次数与迁前一致:1 次通道商户 + 能力挂载/主数据检查
|
||||
private String inferMethodForCapability(String channelMchNo, String capabilityCode) {
|
||||
///
|
||||
/// 供码牌/聚合 DIRECT 解析与路由直接指定共用,避免两处默认 method 语义漂移。
|
||||
/// 查询次数:1 次通道商户 + 能力挂载/主数据检查
|
||||
public String inferMethodForCapability(String channelMchNo, String capabilityCode) {
|
||||
String product = channelMerchantManager.findProductByChannelMchNo(channelMchNo);
|
||||
if (StrUtil.isBlank(product) || !PaymentStrategyFactory.existsByProduct(product, AbsProductStrategy.class)) {
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.daxpay.open.payment.trade.runtime.service.pay.gateway;
|
||||
|
||||
import cn.daxpay.open.payment.common.util.PayMethodOpenIdSupport;
|
||||
import cn.daxpay.open.payment.merchant.dao.gateway.GatewayAggregateConfigManager;
|
||||
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateConfig;
|
||||
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
|
||||
@@ -12,7 +13,6 @@ import cn.daxpay.open.payment.unipay.result.gateway.AggregatePayMetaResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayResult;
|
||||
import cn.daxpay.open.platform.common.spring.util.WebServletUtil;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/// # 聚合扫码支付服务
|
||||
///
|
||||
@@ -30,15 +29,6 @@ import java.util.Set;
|
||||
@RequiredArgsConstructor
|
||||
public class AggregatePayService {
|
||||
|
||||
/// 需要买家标识(openId/userId)的支付方式
|
||||
private static final Set<String> METHODS_NEED_OPEN_ID = Set.of(
|
||||
PayMethodEnum.WECHAT_JSAPI.getCode(),
|
||||
PayMethodEnum.WECHAT_MINI.getCode(),
|
||||
PayMethodEnum.ALIPAY_JSAPI.getCode(),
|
||||
PayMethodEnum.UNION_JSAPI.getCode(),
|
||||
PayMethodEnum.DOUYIN_JSAPI.getCode()
|
||||
);
|
||||
|
||||
private final GatewayPayAssistService gatewayPayAssistService;
|
||||
private final ClientEnvPayResolveService clientEnvPayResolveService;
|
||||
private final GatewayPayHandleService gatewayPayHandleService;
|
||||
@@ -60,7 +50,8 @@ public class AggregatePayService {
|
||||
|
||||
return new AggregatePayMetaResult()
|
||||
.setAutoLaunch(Boolean.TRUE.equals(config.getAutoLaunch()))
|
||||
.setNeedOpenId(METHODS_NEED_OPEN_ID.contains(resolved.method()));
|
||||
// 与码牌同源: 按 method 判定是否需 OAuth 取 openId
|
||||
.setNeedOpenId(PayMethodOpenIdSupport.needsOpenId(resolved.method()));
|
||||
}
|
||||
|
||||
/// 聚合扫码发起支付
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.daxpay.open.payment.unipay.client.service;
|
||||
|
||||
import cn.daxpay.open.payment.auth.ChannelAuthFacade;
|
||||
import cn.daxpay.open.payment.common.context.MerchantContextLoader;
|
||||
import cn.daxpay.open.payment.common.util.PayMethodOpenIdSupport;
|
||||
import cn.daxpay.open.payment.device.enums.QrCodeAmountTypeEnum;
|
||||
import cn.daxpay.open.payment.device.enums.QrCodeStatusEnum;
|
||||
import cn.daxpay.open.payment.device.qrcode.dao.DeviceQrCodeManager;
|
||||
@@ -22,12 +23,12 @@ import cn.daxpay.open.payment.unipay.param.assist.GenerateAuthUrlParam;
|
||||
import cn.daxpay.open.payment.unipay.param.device.CodePayAuthUrlParam;
|
||||
import cn.daxpay.open.payment.unipay.param.device.CodePayParam;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayParam;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.TerminalInfo;
|
||||
import cn.daxpay.open.payment.unipay.result.assist.AuthUrlResult;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayResult;
|
||||
import cn.daxpay.open.platform.common.spring.util.WebServletUtil;
|
||||
import cn.daxpay.open.platform.core.code.CommonCode;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.trade.TradeSourceEnum;
|
||||
import cn.daxpay.open.platform.core.enums.unipay.ChannelAuthTypeEnum;
|
||||
@@ -80,11 +81,12 @@ public class CodePayAssistService {
|
||||
if (StrUtil.isNotBlank(clientEnv)) {
|
||||
try {
|
||||
String method = this.resolveMethod(entity, clientEnv);
|
||||
result.setNeedOpenId(this.needOpenId(method));
|
||||
// 严格按 method 判定;非 JSAPI/MINI 不强制 OAuth
|
||||
result.setNeedOpenId(PayMethodOpenIdSupport.needsOpenId(method));
|
||||
} catch (Exception e) {
|
||||
// 策略未配置等: 默认 JSAPI 路径需要 openId, 避免前端跳过授权
|
||||
// 策略未配置等: 不误强制授权(false);支付时会因策略失败再报错
|
||||
log.warn("码牌 needOpenId 解析失败 code={} clientEnv={}: {}", code, clientEnv, e.getMessage());
|
||||
result.setNeedOpenId(true);
|
||||
result.setNeedOpenId(false);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -107,6 +109,10 @@ public class CodePayAssistService {
|
||||
validateRuntimeMatchesPayForm(param.getRuntime(), payForm);
|
||||
|
||||
var resolved = codePayResolveService.resolveRequired(mchApp.getAppId(), clientEnv, payForm);
|
||||
// JSAPI/MINI 必须已在授权回跳页换好 openId,支付只带 openId、禁止支付时再换 code
|
||||
if (PayMethodOpenIdSupport.needsOpenId(resolved.method()) && StrUtil.isBlank(param.getOpenId())) {
|
||||
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.openIdRequired");
|
||||
}
|
||||
|
||||
String codeName = StrUtil.blankToDefault(entity.getName(), entity.getCode());
|
||||
String amountYuan = String.format("%.2f", amount / 100.0);
|
||||
@@ -125,11 +131,18 @@ public class CodePayAssistService {
|
||||
payParam.setOpenId(param.getOpenId());
|
||||
payParam.setClientIp(StrUtil.blankToDefault(param.getClientIp(), WebServletUtil.getClientIp()));
|
||||
payParam.setSource(TradeSourceEnum.CASHIER_CODE.getCode());
|
||||
// 门店: 码牌显式 storeNo 优先; 空则由下单侧 resolve 默认门店, 仍注入 terminal 便于统一路径
|
||||
// 此处只传码牌上的显式值(可空), NormalPayAssistService 再 resolveStoreNo
|
||||
TerminalInfo terminal = new TerminalInfo();
|
||||
terminal.setStoreNo(entity.getStoreNo());
|
||||
payParam.setTerminal(terminal);
|
||||
|
||||
return normalPayService.pay(payParam);
|
||||
}
|
||||
|
||||
/// 生成码牌 OAuth 授权链接(公开, 按码牌解析商户/策略/路由)
|
||||
///
|
||||
/// 仅 needOpenId 的 method 应调用;回跳落地页立即 code→openId,非支付时再换。
|
||||
public AuthUrlResult generateAuthUrl(CodePayAuthUrlParam param) {
|
||||
DeviceQrCode entity = this.loadEnabledAssigned(param.getCode());
|
||||
merchantContextLoader.initMch(entity.getMchNo());
|
||||
@@ -141,6 +154,10 @@ public class CodePayAssistService {
|
||||
}
|
||||
CodePayFormEnum payForm = CodePayFormEnum.fromProgramType(entity.getProgramType());
|
||||
var resolved = codePayResolveService.resolveRequired(mchApp.getAppId(), clientEnv, payForm);
|
||||
if (!PayMethodOpenIdSupport.needsOpenId(resolved.method())) {
|
||||
// 当前支付方式无需授权(H5/主扫等)
|
||||
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.authNotRequired");
|
||||
}
|
||||
|
||||
// 跟随支付同路径路由, 拿到 product/channelMchNo/capability 供通道认证
|
||||
NormalPayParam routeParam = new NormalPayParam();
|
||||
@@ -243,23 +260,6 @@ public class CodePayAssistService {
|
||||
return codePayResolveService.resolveRequired(mchApp.getAppId(), clientEnv, payForm).method();
|
||||
}
|
||||
|
||||
/// method 是否需要用户标识(JSAPI/小程序类)
|
||||
private boolean needOpenId(String methodCode) {
|
||||
if (StrUtil.isBlank(methodCode)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
PayMethodEnum method = PayMethodEnum.findByCode(methodCode);
|
||||
return switch (method) {
|
||||
case WECHAT_JSAPI, WECHAT_MINI, ALIPAY_JSAPI, UNION_JSAPI, DOUYIN_JSAPI -> true;
|
||||
default -> false;
|
||||
};
|
||||
} catch (Exception e) {
|
||||
// 未知 method: 含 jsapi/mini 视作需要
|
||||
return methodCode.contains("jsapi") || methodCode.contains("mini");
|
||||
}
|
||||
}
|
||||
|
||||
/// 分端页 returnPath: /h/wechat|{alipay}/:code?authed=1
|
||||
private String buildReturnPath(ClientEnvEnum clientEnv, String code) {
|
||||
String segment = switch (clientEnv) {
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "Please select QR code boards",
|
||||
"clientEnvNotSupport": "Current client environment does not support code-plate pay. Please scan with WeChat/Alipay etc.",
|
||||
"amountRequired": "Please enter the payment amount",
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}"
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}",
|
||||
"openIdRequired": "This payment method requires user authorization. Please complete authorization first",
|
||||
"authNotRequired": "This payment method does not require authorization",
|
||||
"storeBindMchInconsistent": "Selected QR code boards must belong to the same merchant when binding a store"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "Please select QR code boards",
|
||||
"clientEnvNotSupport": "Current client environment does not support code-plate pay. Please scan with WeChat/Alipay etc.",
|
||||
"amountRequired": "Please enter the payment amount",
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}"
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}",
|
||||
"openIdRequired": "Metode pembayaran ini memerlukan otorisasi pengguna. Selesaikan otorisasi terlebih dahulu",
|
||||
"authNotRequired": "Metode pembayaran ini tidak memerlukan otorisasi",
|
||||
"storeBindMchInconsistent": "Saat mengikat toko secara batch, pilih papan kode dari merchant yang sama"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "QRコードボードを選択してください",
|
||||
"clientEnvNotSupport": "現在の環境ではコードプレート決済に対応していません。WeChat/Alipayなどでスキャンしてください",
|
||||
"amountRequired": "支払金額を入力してください",
|
||||
"programTypeNotFound": "対応するコード牌プログラム種別が見つかりません: {0}"
|
||||
"programTypeNotFound": "対応するコード牌プログラム種別が見つかりません: {0}",
|
||||
"openIdRequired": "この支払い方法ではユーザー認可が必要です。先に認可を完了してください",
|
||||
"authNotRequired": "この支払い方法では認可は不要です",
|
||||
"storeBindMchInconsistent": "店舗を一括バインドする場合、同一加盟店のコード札を選択してください"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "QR 코드 보드를 선택하세요",
|
||||
"clientEnvNotSupport": "현재 환경에서는 코드플레이트 결제를 지원하지 않습니다. WeChat/Alipay 등으로 스캔하세요",
|
||||
"amountRequired": "결제 금액을 입력하세요",
|
||||
"programTypeNotFound": "일치하는 코드 프로그램 유형을 찾을 수 없습니다: {0}"
|
||||
"programTypeNotFound": "일치하는 코드 프로그램 유형을 찾을 수 없습니다: {0}",
|
||||
"openIdRequired": "현재 결제 방식은 사용자 승인이 필요합니다. 먼저 승인을 완료해 주세요",
|
||||
"authNotRequired": "현재 결제 방식은 승인이 필요하지 않습니다",
|
||||
"storeBindMchInconsistent": "매장 일괄 바인딩 시 동일 가맹점의 코드판을 선택해야 합니다"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "Please select QR code boards",
|
||||
"clientEnvNotSupport": "Current client environment does not support code-plate pay. Please scan with WeChat/Alipay etc.",
|
||||
"amountRequired": "Please enter the payment amount",
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}"
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}",
|
||||
"openIdRequired": "This payment method requires user authorization. Please complete authorization first",
|
||||
"authNotRequired": "This payment method does not require authorization",
|
||||
"storeBindMchInconsistent": "Apabila mengikat kedai secara kelompok, pilih papan kod di bawah peniaga yang sama"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "Please select QR code boards",
|
||||
"clientEnvNotSupport": "Current client environment does not support code-plate pay. Please scan with WeChat/Alipay etc.",
|
||||
"amountRequired": "Please enter the payment amount",
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}"
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}",
|
||||
"openIdRequired": "This payment method requires user authorization. Please complete authorization first",
|
||||
"authNotRequired": "This payment method does not require authorization",
|
||||
"storeBindMchInconsistent": "เมื่อผูกสาขาแบบชุดต้องเลือกป้ายรหัสภายใต้ร้านค้าเดียวกัน"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "Please select QR code boards",
|
||||
"clientEnvNotSupport": "Current client environment does not support code-plate pay. Please scan with WeChat/Alipay etc.",
|
||||
"amountRequired": "Please enter the payment amount",
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}"
|
||||
"programTypeNotFound": "No matching QR code program type found: {0}",
|
||||
"openIdRequired": "This payment method requires user authorization. Please complete authorization first",
|
||||
"authNotRequired": "This payment method does not require authorization",
|
||||
"storeBindMchInconsistent": "Khi gán cửa hàng hàng loạt, phải chọn mã thuộc cùng một thương nhân"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "请选择码牌",
|
||||
"clientEnvNotSupport": "当前打开环境不支持码牌支付, 请使用微信/支付宝等扫码",
|
||||
"amountRequired": "请输入支付金额",
|
||||
"programTypeNotFound": "未找到对应的码牌程序类型: {0}"
|
||||
"programTypeNotFound": "未找到对应的码牌程序类型: {0}",
|
||||
"openIdRequired": "当前支付方式需要用户授权,请先完成授权后重试",
|
||||
"authNotRequired": "当前支付方式无需授权",
|
||||
"storeBindMchInconsistent": "批量绑定门店时须选择同一商户下的码牌"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "請選擇碼牌",
|
||||
"clientEnvNotSupport": "目前開啟環境不支援碼牌支付,請使用微信/支付寶等掃碼",
|
||||
"amountRequired": "請輸入支付金額",
|
||||
"programTypeNotFound": "未找到對應的碼牌程式類型: {0}"
|
||||
"openIdRequired": "目前支付方式需要使用者授權,請先完成授權後重試",
|
||||
"authNotRequired": "目前支付方式無需授權",
|
||||
"programTypeNotFound": "未找到對應的碼牌程式類型: {0}",
|
||||
"storeBindMchInconsistent": "批量綁定門店時須選擇同一商戶下的碼牌"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
"idsEmpty": "請選擇碼牌",
|
||||
"clientEnvNotSupport": "目前開啟環境不支援碼牌支付,請使用微信/支付寶等掃碼",
|
||||
"amountRequired": "請輸入支付金額",
|
||||
"programTypeNotFound": "未找到對應的碼牌程式類型: {0}"
|
||||
"programTypeNotFound": "未找到對應的碼牌程式類型: {0}",
|
||||
"openIdRequired": "目前支付方式需要使用者授權,請先完成授權後重試",
|
||||
"authNotRequired": "目前支付方式無需授權",
|
||||
"storeBindMchInconsistent": "批量綁定門店時須選擇同一商戶下的碼牌"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user