refactor(gateway): CashierScene 重命名为 ClientEnv 客户端环境

将聚合扫码与收银台共用的环境识别从收银场景语义改为客户端环境,
避免与支付渠道/沙箱环境混淆。枚举 code 保持不变,同步表名/字段/i18n。
This commit is contained in:
DaxPay Dev
2026-07-14 21:17:30 +08:00
parent abe0a243ea
commit a06bef0a28
66 changed files with 443 additions and 364 deletions

View File

@@ -163,3 +163,48 @@ ALTER TABLE "public"."pay_trade" DROP COLUMN IF EXISTS "pay_body_type";
ALTER TABLE "public"."pay_trade" DROP COLUMN IF EXISTS "expired_time";
COMMENT ON COLUMN "public"."pay_trade"."relation_order_no" IS '实际上送通道的商户订单号(普通=order_no, 特殊=变形号; 回调反查权威)';
-- ClientEnv rename: cashier scene -> client_env
-- 网关订单
DO $$ BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'pay_gateway_order' AND column_name = 'scene'
) THEN
ALTER TABLE "public"."pay_gateway_order" RENAME COLUMN "scene" TO "client_env";
END IF;
END $$;
COMMENT ON COLUMN "public"."pay_gateway_order"."client_env" IS '客户端环境(ClientEnvEnum)';
-- 收银台支付项
DO $$ BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'pay_gateway_cashier_item' AND column_name = 'scene'
) THEN
ALTER TABLE "public"."pay_gateway_cashier_item" RENAME COLUMN "scene" TO "client_env";
END IF;
END $$;
COMMENT ON COLUMN "public"."pay_gateway_cashier_item"."client_env" IS '客户端环境(ClientEnvEnum)WEB 为空';
-- 聚合配置子表: 表名 + 列名
DO $$ BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_schema = 'public' AND table_name = 'pay_gateway_aggregate_scene'
) THEN
ALTER TABLE "public"."pay_gateway_aggregate_scene" RENAME TO "pay_gateway_aggregate_client_env";
END IF;
END $$;
DO $$ BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'pay_gateway_aggregate_client_env' AND column_name = 'scene'
) THEN
ALTER TABLE "public"."pay_gateway_aggregate_client_env" RENAME COLUMN "scene" TO "client_env";
END IF;
END $$;
COMMENT ON TABLE "public"."pay_gateway_aggregate_client_env" IS '网关聚合配置-客户端环境项';
COMMENT ON COLUMN "public"."pay_gateway_aggregate_client_env"."client_env" IS '客户端环境(ClientEnvEnum)';

View File

@@ -36,8 +36,8 @@ public class GatewayCashierConfigAdminController {
public Result<List<GatewayCashierItemResult>> list(
@NotBlank(message = "{validation.field.appId.notBlank}") String appId,
@NotBlank(message = "{validation.field.cashierType.notBlank}") String cashierType,
String scene) {
return Res.ok(gatewayCashierConfigService.list(appId, cashierType, scene));
String clientEnv) {
return Res.ok(gatewayCashierConfigService.list(appId, cashierType, clientEnv));
}
@PermCode(code = PermCodes.Action.VIEW)

View File

@@ -1,7 +1,7 @@
package cn.daxpay.open.payment.admin.service.merchant.gateway;
import cn.daxpay.open.payment.merchant.enums.CashierItemResolveModeEnum;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import cn.daxpay.open.payment.merchant.enums.GatewayCashierTypeEnum;
import cn.daxpay.open.payment.merchant.dao.gateway.GatewayCashierItemManager;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayCashierItem;
@@ -22,7 +22,7 @@ import java.util.Objects;
/// # 网关收银台配置服务
///
/// 管理应用级收银台支付项: H5 按终端 scene 分桶, WEB 扁平列表;
/// 管理应用级收银台支付项: H5 按客户端环境 clientEnv 分桶, WEB 扁平列表;
/// 每项支持 method / direct 两种支付解析模式。
@Slf4j
@Service
@@ -31,11 +31,11 @@ public class GatewayCashierConfigService {
private final GatewayCashierItemManager itemManager;
/// 按应用 + 收银台类型 + 场景列出支付项
public List<GatewayCashierItemResult> list(String appId, String cashierType, String scene) {
/// 按应用 + 收银台类型 + 客户端环境列出支付项
public List<GatewayCashierItemResult> list(String appId, String cashierType, String clientEnv) {
GatewayCashierTypeEnum typeEnum = GatewayCashierTypeEnum.findByCode(cashierType);
String normalizedScene = normalizeSceneForQuery(typeEnum, scene);
return itemManager.listByAppAndBucket(appId, typeEnum.getCode(), normalizedScene).stream()
String normalizedClientEnv = normalizeClientEnvForQuery(typeEnum, clientEnv);
return itemManager.listByAppAndBucket(appId, typeEnum.getCode(), normalizedClientEnv).stream()
.map(this::toResult)
.toList();
}
@@ -80,18 +80,18 @@ public class GatewayCashierConfigService {
.orElseThrow(() -> new DataNotExistException("pay.error.gateway.cashierItemNotFound"));
}
/// 规范化 scene 查询参数
private String normalizeSceneForQuery(GatewayCashierTypeEnum typeEnum, String scene) {
/// 规范化 clientEnv 查询参数
private String normalizeClientEnvForQuery(GatewayCashierTypeEnum typeEnum, String clientEnv) {
if (typeEnum == GatewayCashierTypeEnum.WEB) {
return null;
}
if (StrUtil.isBlank(scene)) {
if (StrUtil.isBlank(clientEnv)) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.cashierSceneRequired");
"pay.error.gateway.clientEnvRequired");
}
// 校验 scene 合法
CashierSceneEnum.findByCode(scene);
return scene;
// 校验 clientEnv 合法
ClientEnvEnum.findByCode(clientEnv);
return clientEnv;
}
/// 校验并规范化写入字段
@@ -99,16 +99,16 @@ public class GatewayCashierConfigService {
GatewayCashierTypeEnum typeEnum = GatewayCashierTypeEnum.findByCode(param.getCashierType());
CashierItemResolveModeEnum resolveMode = CashierItemResolveModeEnum.findByCode(param.getResolveMode());
String scene = param.getScene();
String clientEnv = param.getClientEnv();
if (typeEnum == GatewayCashierTypeEnum.WEB) {
// WEB 固定无 scene
scene = null;
// WEB 固定无 clientEnv
clientEnv = null;
} else {
if (StrUtil.isBlank(scene)) {
if (StrUtil.isBlank(clientEnv)) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.cashierSceneRequired");
"pay.error.gateway.clientEnvRequired");
}
CashierSceneEnum.findByCode(scene);
ClientEnvEnum.findByCode(clientEnv);
}
String method = StrUtil.trimToNull(param.getMethod());
@@ -146,7 +146,7 @@ public class GatewayCashierConfigService {
Integer sortNo = param.getSortNo() != null ? param.getSortNo() : 0;
String icon = StrUtil.trimToNull(param.getIcon());
return new NormalizedItem(typeEnum.getCode(), scene, name, icon, recommend, sortNo,
return new NormalizedItem(typeEnum.getCode(), clientEnv, name, icon, recommend, sortNo,
resolveMode.getCode(), method, channelMchNo, capability);
}
@@ -156,7 +156,7 @@ public class GatewayCashierConfigService {
entity.setAppId(appId);
}
entity.setCashierType(n.cashierType());
entity.setScene(n.scene());
entity.setClientEnv(n.clientEnv());
entity.setName(n.name());
entity.setIcon(n.icon());
entity.setRecommend(n.recommend());
@@ -175,7 +175,7 @@ public class GatewayCashierConfigService {
private record NormalizedItem(
String cashierType,
String scene,
String clientEnv,
String name,
String icon,
Boolean recommend,

View File

@@ -0,0 +1,36 @@
package cn.daxpay.open.payment.merchant.dao.gateway;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateClientEnv;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import org.springframework.stereotype.Repository;
import java.util.List;
/// # 网关聚合扫码客户端环境配置 Manager
///
/// 管理客户端环境子表的查询与批量替换(先删后插)。
@Repository
public class GatewayAggregateClientEnvManager extends BaseManager<GatewayAggregateClientEnvMapper, GatewayAggregateClientEnv> {
/// 按聚合配置主表 ID 查询全部客户端环境配置
public List<GatewayAggregateClientEnv> findByConfigId(Long configId) {
return lambdaQuery()
.eq(GatewayAggregateClientEnv::getConfigId, configId)
.list();
}
/// 按聚合配置主表 ID 删除全部客户端环境配置
public void deleteByConfigId(Long configId) {
lambdaUpdate()
.eq(GatewayAggregateClientEnv::getConfigId, configId)
.remove();
}
/// 按聚合配置主表 ID + 客户端环境编码查询单条
public GatewayAggregateClientEnv findByConfigIdAndClientEnv(Long configId, String clientEnv) {
return lambdaQuery()
.eq(GatewayAggregateClientEnv::getConfigId, configId)
.eq(GatewayAggregateClientEnv::getClientEnv, clientEnv)
.one();
}
}

View File

@@ -1,10 +1,10 @@
package cn.daxpay.open.payment.merchant.dao.gateway;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateScene;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateClientEnv;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
/// # 网关聚合扫码场景配置 Mapper
/// # 网关聚合扫码客户端环境配置 Mapper
@Mapper
public interface GatewayAggregateSceneMapper extends MPJBaseMapper<GatewayAggregateScene> {
public interface GatewayAggregateClientEnvMapper extends MPJBaseMapper<GatewayAggregateClientEnv> {
}

View File

@@ -1,36 +0,0 @@
package cn.daxpay.open.payment.merchant.dao.gateway;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateScene;
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
import org.springframework.stereotype.Repository;
import java.util.List;
/// # 网关聚合扫码场景配置 Manager
///
/// 管理场景子表的查询与批量替换(先删后插)。
@Repository
public class GatewayAggregateSceneManager extends BaseManager<GatewayAggregateSceneMapper, GatewayAggregateScene> {
/// 按聚合配置主表 ID 查询全部场景配置
public List<GatewayAggregateScene> findByConfigId(Long configId) {
return lambdaQuery()
.eq(GatewayAggregateScene::getConfigId, configId)
.list();
}
/// 按聚合配置主表 ID 删除全部场景配置
public void deleteByConfigId(Long configId) {
lambdaUpdate()
.eq(GatewayAggregateScene::getConfigId, configId)
.remove();
}
/// 按聚合配置主表 ID + 场景编码查询单条
public GatewayAggregateScene findByConfigIdAndScene(Long configId, String scene) {
return lambdaQuery()
.eq(GatewayAggregateScene::getConfigId, configId)
.eq(GatewayAggregateScene::getScene, scene)
.one();
}
}

View File

@@ -11,15 +11,15 @@ import java.util.List;
@Repository
public class GatewayCashierItemManager extends BaseManager<GatewayCashierItemMapper, GatewayCashierItem> {
/// 按应用 + 收银台类型 + 场景查询, 按 sort_no 升序
/// 按应用 + 收银台类型 + 客户端环境查询, 按 sort_no 升序
///
/// WEB 的 scene 传 null, 条件为 scene is null。
public List<GatewayCashierItem> listByAppAndBucket(String appId, String cashierType, String scene) {
/// WEB 的 clientEnv 传 null, 条件为 client_env is null。
public List<GatewayCashierItem> listByAppAndBucket(String appId, String cashierType, String clientEnv) {
return lambdaQuery()
.eq(GatewayCashierItem::getAppId, appId)
.eq(GatewayCashierItem::getCashierType, cashierType)
.eq(StrUtil.isNotBlank(scene), GatewayCashierItem::getScene, scene)
.isNull(StrUtil.isBlank(scene), GatewayCashierItem::getScene)
.eq(StrUtil.isNotBlank(clientEnv), GatewayCashierItem::getClientEnv, clientEnv)
.isNull(StrUtil.isBlank(clientEnv), GatewayCashierItem::getClientEnv)
.orderByAsc(GatewayCashierItem::getSortNo)
.orderByAsc(GatewayCashierItem::getId)
.list();

View File

@@ -1,6 +1,6 @@
package cn.daxpay.open.payment.merchant.entity.gateway;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import cn.daxpay.open.platform.common.mybatisplus.base.MpBaseEntity;
import cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum;
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
@@ -9,24 +9,24 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/// # 网关聚合扫码场景配置(子表)
/// # 网关聚合扫码客户端环境配置(子表)
///
/// 每个聚合配置主表对应多条场景配置(微信/支付宝/云闪付/抖音)
/// 每个聚合配置主表对应多条客户端环境配置(微信/支付宝/云闪付/抖音)
/// - METHOD 模式: method
/// - DIRECT 模式: channelMchNo + capability
/// - AUTO 模式: 子表可为空
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("pay_gateway_aggregate_scene")
public class GatewayAggregateScene extends MpBaseEntity {
@TableName("pay_gateway_aggregate_client_env")
public class GatewayAggregateClientEnv extends MpBaseEntity {
/// 聚合配置主表ID
private Long configId;
/// 场景编码: wechat_pay/alipay/union_pay/douyin
/// @see CashierSceneEnum
private String scene;
/// 客户端环境编码: wechat_pay/alipay/union_pay/douyin
/// @see ClientEnvEnum
private String clientEnv;
/// 支付方式(METHOD 模式填)
/// @see PayMethodEnum

View File

@@ -11,10 +11,10 @@ import lombok.experimental.Accessors;
/// # 网关聚合扫码配置(应用级)
///
/// 按配置深度(level)控制场景解析支付方式的自由度, 场景明细存储在 [GatewayAggregateScene] 子表。
/// 按配置深度(level)控制客户端环境解析支付方式的自由度, 明细存储在 [GatewayAggregateClientEnv] 子表。
/// - AUTO: 子表无需配置, 系统按扫码环境推导支付方式
/// - METHOD: 子表每场景配置支付方式(method)
/// - DIRECT: 子表每场景配置通道商户号(channelMchNo)+支付能力(capability)
/// - METHOD: 子表每客户端环境配置支付方式(method)
/// - DIRECT: 子表每客户端环境配置通道商户号(channelMchNo)+支付能力(capability)
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)

View File

@@ -2,7 +2,7 @@ package cn.daxpay.open.payment.merchant.entity.gateway;
import cn.daxpay.open.payment.common.entity.MchBaseEntity;
import cn.daxpay.open.payment.merchant.enums.CashierItemResolveModeEnum;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import cn.daxpay.open.payment.merchant.enums.GatewayCashierTypeEnum;
import cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum;
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
@@ -15,9 +15,9 @@ import lombok.experimental.Accessors;
/// # 网关收银台支付项配置(应用级)
///
/// 一张表按 cashier_type + scene 分桶:
/// - H5: scene 必填(browser/wechat_pay/alipay/union_pay/douyin), 每终端一套支付项
/// - WEB: scene 为空, 一套扁平支付项
/// 一张表按 cashier_type + client_env 分桶:
/// - H5: clientEnv 必填(browser/wechat_pay/alipay/union_pay/douyin), 每终端一套支付项
/// - WEB: clientEnv 为空, 一套扁平支付项
/// 支付解析按项 resolve_mode:
/// - METHOD: 填 method
/// - DIRECT: 填 channelMchNo + capability
@@ -35,9 +35,9 @@ public class GatewayCashierItem extends MchBaseEntity {
/// @see GatewayCashierTypeEnum
private String cashierType;
/// H5 终端场景; WEB 为空
/// @see CashierSceneEnum
private String scene;
/// 客户端环境UA/宿主识别;聚合扫码与收银台 H5 共用;非支付渠道、非沙箱环境);WEB 为空
/// @see ClientEnvEnum
private String clientEnv;
/// 前台展示名称
private String name;

View File

@@ -7,14 +7,16 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/// # 收银场景(环境识别)
/// # 客户端环境(UA/宿主识别)
///
/// 字典: cashier_scene
/// 聚合扫码使用微信/支付宝/云闪付/抖音
/// 字典: client_env
/// 聚合扫码与收银台 H5 共用
/// 聚合使用微信/支付宝/云闪付/抖音
/// 收银台 H5 额外支持 browser(普通浏览器), 聚合配置不使用 browser
/// 非支付渠道(PayProvider/Channel)非沙箱环境(PayEnv)
@Getter
@RequiredArgsConstructor
public enum CashierSceneEnum implements I18nSupport {
public enum ClientEnvEnum implements I18nSupport {
/// 普通浏览器环境(仅收银台 H5 配置使用)
BROWSER("browser"),
@@ -32,13 +34,13 @@ public enum CashierSceneEnum implements I18nSupport {
@Override
public String getI18nPrefix() {
return "enum.cashier_scene";
return "enum.client_env";
}
public static CashierSceneEnum findByCode(String code) {
public static ClientEnvEnum findByCode(String code) {
return Arrays.stream(values())
.filter(e -> e.getCode().equals(code))
.findFirst()
.orElseThrow(() -> new DataNotExistException("error.common.cashierSceneNotExist", code));
.orElseThrow(() -> new DataNotExistException("error.common.clientEnvNotExist", code));
}
}

View File

@@ -15,9 +15,9 @@ import java.util.Arrays;
@RequiredArgsConstructor
public enum GatewayCashierTypeEnum implements I18nSupport {
/// H5 收银台(按终端 scene 再分桶)
/// H5 收银台(按客户端环境 clientEnv 再分桶)
H5("h5"),
/// WEB/PC 收银台(扁平列表, scene 为空)
/// WEB/PC 收银台(扁平列表, clientEnv 为空)
WEB("web"),
;

View File

@@ -4,15 +4,15 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Size;
import lombok.Data;
/// # 网关聚合扫码场景配置参数(子表)
/// # 网关聚合扫码客户端环境配置参数(子表)
@Data
@Schema(title = "网关聚合扫码场景配置参数")
public class GatewayAggregateSceneParam {
@Schema(title = "网关聚合扫码客户端环境配置参数")
public class GatewayAggregateClientEnvParam {
/// @see cn.daxpay.open.payment.merchant.enums.CashierSceneEnum
@Schema(description = "场景编码: wechat_pay/alipay/union_pay/douyin")
@Size(max = 32, message = "{validation.field.scene.size}")
private String scene;
/// @see cn.daxpay.open.payment.merchant.enums.ClientEnvEnum
@Schema(description = "客户端环境编码: wechat_pay/alipay/union_pay/douyin")
@Size(max = 32, message = "{validation.field.clientEnv.size}")
private String clientEnv;
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum
@Schema(description = "支付方式(METHOD 模式填)")

View File

@@ -11,10 +11,10 @@ import java.util.List;
/// # 网关聚合扫码配置参数
///
/// level 控制场景子表的填充要求:
/// - AUTO: scenes 可为空
/// - METHOD: 每场景填 method
/// - DIRECT: 每场景填 channelMchNo + capability
/// level 控制客户端环境子表的填充要求:
/// - AUTO: clientEnvs 可为空
/// - METHOD: 每环境填 method
/// - DIRECT: 每环境填 channelMchNo + capability
@Data
@Schema(title = "网关聚合扫码配置参数")
public class GatewayAggregateConfigParam {
@@ -39,6 +39,6 @@ public class GatewayAggregateConfigParam {
private Boolean autoLaunch;
@Valid
@Schema(description = "场景配置列表")
private List<GatewayAggregateSceneParam> scenes;
@Schema(description = "客户端环境配置列表")
private List<GatewayAggregateClientEnvParam> clientEnvs;
}

View File

@@ -1,7 +1,7 @@
package cn.daxpay.open.payment.merchant.param.gateway;
import cn.daxpay.open.payment.merchant.enums.CashierItemResolveModeEnum;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import cn.daxpay.open.payment.merchant.enums.GatewayCashierTypeEnum;
import cn.daxpay.open.platform.core.validation.ValidationGroup;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -35,10 +35,10 @@ public class GatewayCashierItemParam {
@Size(max = 16, message = "{validation.field.cashierType.size}")
private String cashierType;
/// @see CashierSceneEnum
@Schema(description = "H5终端场景; WEB为空")
@Size(max = 32, message = "{validation.field.scene.size}")
private String scene;
/// @see ClientEnvEnum
@Schema(description = "H5客户端环境; WEB为空")
@Size(max = 32, message = "{validation.field.clientEnv.size}")
private String clientEnv;
@Schema(description = "前台展示名称")
@NotBlank(message = "{validation.field.name.notBlank}")

View File

@@ -4,15 +4,15 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/// # 网关聚合扫码场景配置结果(子表)
/// # 网关聚合扫码客户端环境配置结果(子表)
@Data
@Accessors(chain = true)
@Schema(title = "网关聚合扫码场景配置结果")
public class GatewayAggregateSceneResult {
@Schema(title = "网关聚合扫码客户端环境配置结果")
public class GatewayAggregateClientEnvResult {
/// @see cn.daxpay.open.payment.merchant.enums.CashierSceneEnum
@Schema(description = "场景编码: wechat_pay/alipay/union_pay/douyin")
private String scene;
/// @see cn.daxpay.open.payment.merchant.enums.ClientEnvEnum
@Schema(description = "客户端环境编码: wechat_pay/alipay/union_pay/douyin")
private String clientEnv;
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum
@Schema(description = "支付方式(METHOD 模式)")

View File

@@ -28,6 +28,6 @@ public class GatewayAggregateConfigResult {
@Schema(description = "是否自动拉起支付")
private Boolean autoLaunch;
@Schema(description = "场景配置列表")
private List<GatewayAggregateSceneResult> scenes;
@Schema(description = "客户端环境配置列表")
private List<GatewayAggregateClientEnvResult> clientEnvs;
}

View File

@@ -22,8 +22,8 @@ public class GatewayCashierItemResult {
@Schema(description = "收银台类型: h5/web")
private String cashierType;
@Schema(description = "H5终端场景; WEB为空")
private String scene;
@Schema(description = "H5客户端环境; WEB为空")
private String clientEnv;
@Schema(description = "前台展示名称")
private String name;

View File

@@ -0,0 +1,35 @@
package cn.daxpay.open.payment.merchant.service.gateway;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import cn.daxpay.open.platform.core.code.CommonErrorCode;
import cn.daxpay.open.platform.core.exception.BizInfoException;
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
import lombok.experimental.UtilityClass;
import java.util.Map;
/// # 聚合扫码客户端环境默认支付方式推导器(L1 自动模式)
///
/// L1 AUTO 模式下, 系统按扫码环境自动推导支付方式, 无需商户手动配置。
/// 推导规则: 原生 APP 环境一律使用 JSAPI 支付方式。
@UtilityClass
public class ClientEnvMethodDefaultResolver {
/// 客户端环境 → 默认支付方式映射
private static final Map<ClientEnvEnum, PayMethodEnum> DEFAULT_METHODS = Map.of(
ClientEnvEnum.WECHAT_PAY, PayMethodEnum.WECHAT_JSAPI,
ClientEnvEnum.ALIPAY, PayMethodEnum.ALIPAY_JSAPI,
ClientEnvEnum.UNION_PAY, PayMethodEnum.UNION_JSAPI,
ClientEnvEnum.DOUYIN, PayMethodEnum.DOUYIN_JSAPI
);
/// 按客户端环境推导默认支付方式编码
public static String resolve(ClientEnvEnum clientEnv) {
PayMethodEnum method = DEFAULT_METHODS.get(clientEnv);
if (method == null) {
// 不支持的客户端环境
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.gateway.clientEnvNotSupport");
}
return method.getCode();
}
}

View File

@@ -2,13 +2,13 @@ package cn.daxpay.open.payment.merchant.service.gateway;
import cn.daxpay.open.payment.merchant.enums.AggregateConfigLevelEnum;
import cn.daxpay.open.payment.merchant.dao.gateway.GatewayAggregateConfigManager;
import cn.daxpay.open.payment.merchant.dao.gateway.GatewayAggregateSceneManager;
import cn.daxpay.open.payment.merchant.dao.gateway.GatewayAggregateClientEnvManager;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateConfig;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateScene;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateClientEnv;
import cn.daxpay.open.payment.merchant.param.gateway.GatewayAggregateConfigParam;
import cn.daxpay.open.payment.merchant.param.gateway.GatewayAggregateSceneParam;
import cn.daxpay.open.payment.merchant.param.gateway.GatewayAggregateClientEnvParam;
import cn.daxpay.open.payment.merchant.result.gateway.GatewayAggregateConfigResult;
import cn.daxpay.open.payment.merchant.result.gateway.GatewayAggregateSceneResult;
import cn.daxpay.open.payment.merchant.result.gateway.GatewayAggregateClientEnvResult;
import cn.daxpay.open.platform.core.code.CommonErrorCode;
import cn.daxpay.open.platform.core.exception.BizInfoException;
import cn.hutool.core.bean.BeanUtil;
@@ -24,25 +24,25 @@ import java.util.List;
/// # 网关聚合扫码配置服务
///
/// 管理聚合扫码配置的主表(配置深度)与场景子表(每场景支付方式/通道),
/// 按 level 校验场景子表填充完整性。
/// 管理聚合扫码配置的主表(配置深度)与客户端环境子表(每环境支付方式/通道),
/// 按 level 校验客户端环境子表填充完整性。
@Slf4j
@Service
@RequiredArgsConstructor
public class GatewayAggregateConfigService {
private final GatewayAggregateConfigManager configManager;
private final GatewayAggregateSceneManager sceneManager;
private final GatewayAggregateClientEnvManager clientEnvManager;
/// 按应用查询, 不存在返回空对象(含 level 默认 AUTO)
public GatewayAggregateConfigResult findByAppId(String appId) {
return configManager.findByAppId(appId)
.map(this::toResultWithScenes)
.map(this::toResultWithClientEnvs)
.orElseGet(() -> new GatewayAggregateConfigResult()
.setAppId(appId)
.setLevel(AggregateConfigLevelEnum.AUTO.getCode())
.setAutoLaunch(false)
.setScenes(List.of()));
.setClientEnvs(List.of()));
}
/// 支付时必须已配置
@@ -56,7 +56,7 @@ public class GatewayAggregateConfigService {
@Transactional(rollbackFor = Exception.class)
public void saveOrUpdate(GatewayAggregateConfigParam param) {
AggregateConfigLevelEnum level = AggregateConfigLevelEnum.findByCode(param.getLevel());
validateScenes(level, param.getScenes());
validateClientEnvs(level, param.getClientEnvs());
// 主表保存或更新
GatewayAggregateConfig config = configManager.findByAppId(param.getAppId())
@@ -73,67 +73,67 @@ public class GatewayAggregateConfigService {
configManager.saveOrUpdate(config);
// 子表替换: 先删后插
sceneManager.deleteByConfigId(config.getId());
if (CollUtil.isNotEmpty(param.getScenes())) {
List<GatewayAggregateScene> scenes = new ArrayList<>();
for (GatewayAggregateSceneParam sceneParam : param.getScenes()) {
GatewayAggregateScene scene = new GatewayAggregateScene()
clientEnvManager.deleteByConfigId(config.getId());
if (CollUtil.isNotEmpty(param.getClientEnvs())) {
List<GatewayAggregateClientEnv> clientEnvs = new ArrayList<>();
for (GatewayAggregateClientEnvParam envParam : param.getClientEnvs()) {
GatewayAggregateClientEnv env = new GatewayAggregateClientEnv()
.setConfigId(config.getId())
.setScene(sceneParam.getScene())
.setMethod(sceneParam.getMethod())
.setChannelMchNo(sceneParam.getChannelMchNo())
.setCapability(sceneParam.getCapability());
scenes.add(scene);
.setClientEnv(envParam.getClientEnv())
.setMethod(envParam.getMethod())
.setChannelMchNo(envParam.getChannelMchNo())
.setCapability(envParam.getCapability());
clientEnvs.add(env);
}
sceneManager.saveAll(scenes);
clientEnvManager.saveAll(clientEnvs);
}
}
/// 按 level 校验场景子表填充完整性
private void validateScenes(AggregateConfigLevelEnum level, List<GatewayAggregateSceneParam> scenes) {
/// 按 level 校验客户端环境子表填充完整性
private void validateClientEnvs(AggregateConfigLevelEnum level, List<GatewayAggregateClientEnvParam> clientEnvs) {
if (level == AggregateConfigLevelEnum.AUTO) {
// AUTO 模式不校验子表
return;
}
if (CollUtil.isEmpty(scenes)) {
if (CollUtil.isEmpty(clientEnvs)) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.aggregateScenesRequired");
"pay.error.gateway.aggregateClientEnvsRequired");
}
for (GatewayAggregateSceneParam scene : scenes) {
if (StrUtil.isBlank(scene.getScene())) {
for (GatewayAggregateClientEnvParam env : clientEnvs) {
if (StrUtil.isBlank(env.getClientEnv())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.aggregateSceneBlank");
"pay.error.gateway.aggregateClientEnvBlank");
}
if (level == AggregateConfigLevelEnum.METHOD && StrUtil.isBlank(scene.getMethod())) {
if (level == AggregateConfigLevelEnum.METHOD && StrUtil.isBlank(env.getMethod())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.aggregateSceneMethodRequired");
"pay.error.gateway.aggregateClientEnvMethodRequired");
}
if (level == AggregateConfigLevelEnum.DIRECT) {
if (StrUtil.isBlank(scene.getChannelMchNo())) {
if (StrUtil.isBlank(env.getChannelMchNo())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.aggregateSceneChannelMchRequired");
"pay.error.gateway.aggregateClientEnvChannelMchRequired");
}
if (StrUtil.isBlank(scene.getCapability())) {
if (StrUtil.isBlank(env.getCapability())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.aggregateSceneCapabilityRequired");
"pay.error.gateway.aggregateClientEnvCapabilityRequired");
}
}
}
}
/// 组装主表 + 场景子表为 Result
private GatewayAggregateConfigResult toResultWithScenes(GatewayAggregateConfig entity) {
/// 组装主表 + 客户端环境子表为 Result
private GatewayAggregateConfigResult toResultWithClientEnvs(GatewayAggregateConfig entity) {
GatewayAggregateConfigResult result = new GatewayAggregateConfigResult();
BeanUtil.copyProperties(entity, result);
List<GatewayAggregateScene> scenes = sceneManager.findByConfigId(entity.getId());
List<GatewayAggregateSceneResult> sceneResults = scenes.stream()
.map(s -> new GatewayAggregateSceneResult()
.setScene(s.getScene())
List<GatewayAggregateClientEnv> clientEnvs = clientEnvManager.findByConfigId(entity.getId());
List<GatewayAggregateClientEnvResult> envResults = clientEnvs.stream()
.map(s -> new GatewayAggregateClientEnvResult()
.setClientEnv(s.getClientEnv())
.setMethod(s.getMethod())
.setChannelMchNo(s.getChannelMchNo())
.setCapability(s.getCapability()))
.toList();
result.setScenes(sceneResults);
result.setClientEnvs(envResults);
return result;
}
}

View File

@@ -1,35 +0,0 @@
package cn.daxpay.open.payment.merchant.service.gateway;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.platform.core.code.CommonErrorCode;
import cn.daxpay.open.platform.core.exception.BizInfoException;
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
import lombok.experimental.UtilityClass;
import java.util.Map;
/// # 聚合扫码场景默认支付方式推导器(L1 自动模式)
///
/// L1 AUTO 模式下, 系统按扫码环境自动推导支付方式, 无需商户手动配置。
/// 推导规则: 原生 APP 环境一律使用 JSAPI 支付方式。
@UtilityClass
public class SceneMethodDefaultResolver {
/// 场景 → 默认支付方式映射
private static final Map<CashierSceneEnum, PayMethodEnum> DEFAULT_METHODS = Map.of(
CashierSceneEnum.WECHAT_PAY, PayMethodEnum.WECHAT_JSAPI,
CashierSceneEnum.ALIPAY, PayMethodEnum.ALIPAY_JSAPI,
CashierSceneEnum.UNION_PAY, PayMethodEnum.UNION_JSAPI,
CashierSceneEnum.DOUYIN, PayMethodEnum.DOUYIN_JSAPI
);
/// 按场景推导默认支付方式编码
public static String resolve(CashierSceneEnum scene) {
PayMethodEnum method = DEFAULT_METHODS.get(scene);
if (method == null) {
// 不支持的收银场景
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.gateway.sceneNotSupport");
}
return method.getCode();
}
}

View File

@@ -1,12 +1,14 @@
package cn.daxpay.open.payment.trade.order.entity;
import cn.daxpay.open.payment.common.entity.MchBaseEntity;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import cn.daxpay.open.payment.trade.enums.GatewayOrderStatusEnum;
import cn.daxpay.open.payment.trade.enums.GatewayPayTypeEnum;
import cn.daxpay.open.payment.unipay.param.trade.pay.GoodsDetail;
import cn.daxpay.open.platform.core.enums.pay.channel.CurrencyEnum;
import cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum;
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
import cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum;
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
@@ -61,7 +63,7 @@ public class GatewayPayOrder extends MchBaseEntity {
/// 商户附加参数(回调原样返回)
private String attach;
/// 业务单过期时间(超时关单权威,不落 pay_trade
/// 业务单过期时间
private OffsetDateTime expiredTime;
// ===== 金额(冗余,方便查询;预下单即确定,支付前可无 Trade=====
@@ -96,9 +98,9 @@ public class GatewayPayOrder extends MchBaseEntity {
/// 微信 openidjsapi/app/miniapp
private String openid;
/// 收银场景(环境识别,支付时回填;与聚合/收银台配置共用同一字典)
/// @see CashierSceneEnum
private String scene;
/// 客户端环境UA/宿主识别,支付时回填;与聚合/收银台配置共用同一字典;非支付渠道、非沙箱环境
/// @see ClientEnvEnum
private String clientEnv;
/// 最后发起设备mobile/pc支付时回填与 H5 端 window.__DEVICE__ 一致)
private String device;
@@ -117,7 +119,7 @@ public class GatewayPayOrder extends MchBaseEntity {
private String channelMchNo;
/// 支付能力编码(路由回填)
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum
/// @see PayCapabilityEnum
private String capability;
/// 通道应用 AppId本笔交易实际使用的微信/通道侧 AppId 快照;解析后写入,关退同步复用)
@@ -126,7 +128,7 @@ public class GatewayPayOrder extends MchBaseEntity {
// ===== 通道回执(支付成功/同步后写入)=====
/// 支付渠道(微信/支付宝/银联等,三方通道透传时填)
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum
/// @see PayProviderEnum
private String provider;
/// 付款用户标识(支付宝 user_id、微信 openid 等,非通道 AppId

View File

@@ -12,7 +12,7 @@ import java.time.OffsetDateTime;
///
/// 列表场景仅填充容器(GatewayPayOrder)字段;
/// 详情场景额外填充资金凭证(PayTrade)字段: tradeNo / outOrderNo / fundStatus 等。
/// 字段契约与 [NormalPayOrderResult] 对齐, 另含网关独有 gatewayType / scene / device。
/// 字段契约与 [NormalPayOrderResult] 对齐, 另含网关独有 gatewayType / clientEnv / device。
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@@ -77,9 +77,9 @@ public class GatewayPayOrderResult extends BaseResult {
@Schema(description = "限制支付类型")
private String limitPay;
/// @see cn.daxpay.open.payment.merchant.enums.CashierSceneEnum
@Schema(description = "收银场景(环境识别)")
private String scene;
/// @see cn.daxpay.open.payment.merchant.enums.ClientEnvEnum
@Schema(description = "客户端环境(UA/宿主识别)")
private String clientEnv;
@Schema(description = "设备(mobile/pc)")
private String device;

View File

@@ -1,6 +1,6 @@
package cn.daxpay.open.payment.unipay.gateway.param;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
@@ -16,12 +16,12 @@ public class AggregateQrPayParam {
@Size(max = 64, message = "{validation.field.orderNo.size}")
private String orderNo;
/// 收银场景(环境识别,与聚合/收银台配置共用 [CashierSceneEnum]
/// @see CashierSceneEnum
@Schema(description = "收银场景(CashierSceneEnum: wechat_pay/alipay/union_pay/douyin/browser)")
@NotBlank(message = "{validation.field.scene.notBlank}")
@Size(max = 32, message = "{validation.field.scene.size}")
private String scene;
/// 客户端环境UA/宿主识别,与聚合/收银台配置共用 [ClientEnvEnum]
/// @see ClientEnvEnum
@Schema(description = "客户端环境(ClientEnvEnum: wechat_pay/alipay/union_pay/douyin/browser)")
@NotBlank(message = "{validation.field.clientEnv.notBlank}")
@Size(max = 32, message = "{validation.field.clientEnv.size}")
private String clientEnv;
@Schema(description = "OpenId(微信 JSAPI 等)")
@Size(max = 128, message = "{validation.field.openId.size}")

View File

@@ -1,14 +1,14 @@
package cn.daxpay.open.payment.unipay.gateway.service;
import cn.daxpay.open.payment.merchant.enums.AggregateConfigLevelEnum;
import cn.daxpay.open.payment.merchant.enums.CashierSceneEnum;
import cn.daxpay.open.payment.merchant.enums.ClientEnvEnum;
import cn.daxpay.open.payment.trade.enums.GatewayPayTypeEnum;
import cn.daxpay.open.payment.trade.order.entity.GatewayPayOrder;
import cn.daxpay.open.payment.merchant.dao.gateway.GatewayAggregateSceneManager;
import cn.daxpay.open.payment.merchant.dao.gateway.GatewayAggregateClientEnvManager;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateConfig;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateScene;
import cn.daxpay.open.payment.merchant.entity.gateway.GatewayAggregateClientEnv;
import cn.daxpay.open.payment.merchant.service.gateway.GatewayAggregateConfigService;
import cn.daxpay.open.payment.merchant.service.gateway.SceneMethodDefaultResolver;
import cn.daxpay.open.payment.merchant.service.gateway.ClientEnvMethodDefaultResolver;
import cn.daxpay.open.payment.unipay.gateway.param.AggregateQrPayParam;
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayResult;
import cn.daxpay.open.platform.common.spring.util.WebServletUtil;
@@ -24,9 +24,9 @@ import java.util.Objects;
/// # 网关聚合扫码支付服务
///
/// 按应用聚合配置的深度(level)解析支付方式:
/// - AUTO: 系统按扫码环境推导 method, 走路由基础/场景模式
/// - METHOD: 每场景配置的 method, 走路由场景模式
/// - DIRECT: 每场景配置的 channelMchNo+capability, 走路由直定模式
/// - AUTO: 系统按扫码客户端环境推导 method, 走路由基础/场景模式
/// - METHOD: 每客户端环境配置的 method, 走路由场景模式
/// - DIRECT: 每客户端环境配置的 channelMchNo+capability, 走路由直定模式
@Slf4j
@Service
@RequiredArgsConstructor
@@ -34,7 +34,7 @@ public class GatewayAggregatePayService {
private final GatewayPayAssistService gatewayPayAssistService;
private final GatewayAggregateConfigService gatewayAggregateConfigService;
private final GatewayAggregateSceneManager gatewayAggregateSceneManager;
private final GatewayAggregateClientEnvManager gatewayAggregateClientEnvManager;
private final GatewayPayHandleService gatewayPayHandleService;
/// 聚合扫码发起支付
@@ -43,7 +43,7 @@ public class GatewayAggregatePayService {
if (!Objects.equals(order.getGatewayType(), GatewayPayTypeEnum.AGGREGATE.getCode())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.gateway.typeMismatch");
}
CashierSceneEnum scene = CashierSceneEnum.findByCode(param.getScene());
ClientEnvEnum clientEnv = ClientEnvEnum.findByCode(param.getClientEnv());
GatewayAggregateConfig config = gatewayAggregateConfigService.getRequiredByAppId(order.getAppId());
AggregateConfigLevelEnum level = AggregateConfigLevelEnum.findByCode(config.getLevel());
@@ -54,41 +54,41 @@ public class GatewayAggregatePayService {
switch (level) {
case AUTO -> {
// L1: 系统按场景推导支付方式, channelMchNo 为空走路由
method = SceneMethodDefaultResolver.resolve(scene);
// L1: 系统按客户端环境推导支付方式, channelMchNo 为空走路由
method = ClientEnvMethodDefaultResolver.resolve(clientEnv);
}
case METHOD -> {
// L2: 每场景配置支付方式, channelMchNo 为空走路由
GatewayAggregateScene sceneConfig = gatewayAggregateSceneManager
.findByConfigIdAndScene(config.getId(), scene.getCode());
if (sceneConfig == null || StrUtil.isBlank(sceneConfig.getMethod())) {
// L2: 每客户端环境配置支付方式, channelMchNo 为空走路由
GatewayAggregateClientEnv envConfig = gatewayAggregateClientEnvManager
.findByConfigIdAndClientEnv(config.getId(), clientEnv.getCode());
if (envConfig == null || StrUtil.isBlank(envConfig.getMethod())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.sceneNotConfigured");
"pay.error.gateway.clientEnvNotConfigured");
}
method = sceneConfig.getMethod();
method = envConfig.getMethod();
}
case DIRECT -> {
// L3: 直接指定通道商户号+能力, 走路由直定模式
GatewayAggregateScene sceneConfig = gatewayAggregateSceneManager
.findByConfigIdAndScene(config.getId(), scene.getCode());
if (sceneConfig == null || StrUtil.isBlank(sceneConfig.getChannelMchNo())) {
GatewayAggregateClientEnv envConfig = gatewayAggregateClientEnvManager
.findByConfigIdAndClientEnv(config.getId(), clientEnv.getCode());
if (envConfig == null || StrUtil.isBlank(envConfig.getChannelMchNo())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.sceneNotConfigured");
"pay.error.gateway.clientEnvNotConfigured");
}
channelMchNo = sceneConfig.getChannelMchNo();
capability = sceneConfig.getCapability();
// method: 优先用配置值, 未配则按场景推导(直定模式可由通道商户+能力反推)
method = StrUtil.isNotBlank(sceneConfig.getMethod())
? sceneConfig.getMethod()
: SceneMethodDefaultResolver.resolve(scene);
channelMchNo = envConfig.getChannelMchNo();
capability = envConfig.getCapability();
// method: 优先用配置值, 未配则按客户端环境推导(直定模式可由通道商户+能力反推)
method = StrUtil.isNotBlank(envConfig.getMethod())
? envConfig.getMethod()
: ClientEnvMethodDefaultResolver.resolve(clientEnv);
}
default -> throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
"pay.error.gateway.sceneNotSupport");
"pay.error.gateway.clientEnvNotSupport");
}
String clientIp = StrUtil.blankToDefault(param.getClientIp(), WebServletUtil.getClientIp());
// product 传 null: AUTO/METHOD 由路由解析, DIRECT 由 channelMchNo 派生
return gatewayPayHandleService.handle(order, null, method, channelMchNo, capability,
param.getOpenId(), scene.getCode(), param.getDevice(), clientIp);
param.getOpenId(), clientEnv.getCode(), param.getDevice(), clientIp);
}
}

View File

@@ -56,7 +56,7 @@ public class GatewayPayHandleService {
/// @param capability 支付能力(DIRECT 模式必填)
public NormalPayResult handle(GatewayPayOrder order, String product, String method,
String channelMchNo, String capability,
String openId, String scene, String device, String clientIp) {
String openId, String clientEnv, String device, String clientIp) {
LockInfo lock = lockTemplate.lock("payment:gateway:pay:" + order.getOrderNo(), 10000, 200);
if (Objects.isNull(lock)) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.pay.processing");
@@ -104,10 +104,10 @@ public class GatewayPayHandleService {
// 建 Trade(若无) + 回填容器
if (existing == null) {
existing = SpringUtil.getBean(this.getClass())
.createTrade(order, payParam, scene, device);
.createTrade(order, payParam, clientEnv, device);
} else {
// 回填路由结果到容器
this.fillRouteOnOrder(order, payParam, scene, device);
this.fillRouteOnOrder(order, payParam, clientEnv, device);
gatewayPayOrderManager.updateById(order);
}
context.setTrade(existing);
@@ -130,7 +130,7 @@ public class GatewayPayHandleService {
/// 创建资金凭证并更新容器为 paying
@Transactional(rollbackFor = Exception.class)
public PayTrade createTrade(GatewayPayOrder order, NormalPayParam payParam, String scene, String device) {
public PayTrade createTrade(GatewayPayOrder order, NormalPayParam payParam, String clientEnv, String device) {
var productEnum = ProductEnum.findByCode(payParam.getProduct());
String channel = productEnum.getChannel();
@@ -150,7 +150,7 @@ public class GatewayPayHandleService {
trade.setSource(TradeSourceEnum.AGGRESS_PAY.getCode());
payTradeManager.save(trade);
this.fillRouteOnOrder(order, payParam, scene, device);
this.fillRouteOnOrder(order, payParam, clientEnv, device);
order.setStatus(GatewayOrderStatusEnum.PAYING.getCode());
order.setChannel(channel);
order.setMethod(payParam.getMethod());
@@ -178,13 +178,13 @@ public class GatewayPayHandleService {
return this.buildResult(latest, trade);
}
private void fillRouteOnOrder(GatewayPayOrder order, NormalPayParam payParam, String scene, String device) {
private void fillRouteOnOrder(GatewayPayOrder order, NormalPayParam payParam, String clientEnv, String device) {
order.setChannelMchNo(payParam.getChannelMchNo());
order.setCapability(payParam.getCapability());
// doBeforePay 后 payParam.channelAppId 为实际解析值
order.setChannelAppId(payParam.getChannelAppId());
if (StrUtil.isNotBlank(scene)) {
order.setScene(scene);
if (StrUtil.isNotBlank(clientEnv)) {
order.setClientEnv(clientEnv);
}
if (StrUtil.isNotBlank(device)) {
order.setDevice(device);

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "Backend base URL (backendBaseUrl) is not configured, cannot generate callback URL",
"requestContextMissing": "Cannot obtain request context",
"gatewayUrlNotConfigured": "Payment gateway base URL (paymentGatewayBaseUrl) is not configured, cannot generate auth callback URL",
"cashierSceneNotExist": "Cashier scene not found: {0}",
"clientEnvNotExist": "Client environment not found: {0}",
"gatewayPayTypeNotExist": "Gateway pay type not found: {0}",
"aggregateConfigLevelNotExist": "Aggregate config level not found: {0}",
"gatewayCashierTypeNotExist": "Gateway cashier type not found: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "Cashier payment is not available yet",
"typeMismatch": "Gateway order type mismatch",
"sceneNotSupport": "Unsupported cashier scene",
"sceneNotConfigured": "Payment method not configured for this scene",
"clientEnvNotSupport": "Unsupported client environment",
"clientEnvNotConfigured": "Payment method not configured for this client environment",
"aggregateConfigMissing": "Aggregate QR pay config missing for app",
"aggregateScenesRequired": "Scene config required for this config level",
"aggregateSceneBlank": "Scene code must not be blank",
"aggregateSceneMethodRequired": "Payment method required for each scene in METHOD level",
"aggregateSceneChannelMchRequired": "Channel merchant required for each scene in DIRECT level",
"aggregateSceneCapabilityRequired": "Capability required for each scene in DIRECT level",
"aggregateClientEnvsRequired": "Client environment config required for this config level",
"aggregateClientEnvBlank": "Client environment code must not be blank",
"aggregateClientEnvMethodRequired": "Payment method required for each client environment in METHOD level",
"aggregateClientEnvChannelMchRequired": "Channel merchant required for each client environment in DIRECT level",
"aggregateClientEnvCapabilityRequired": "Capability required for each client environment in DIRECT level",
"channelLocked": "Payment method locked for this order",
"cashierSceneRequired": "H5 cashier requires a terminal scene",
"clientEnvRequired": "H5 cashier requires a client environment",
"cashierItemNotFound": "Cashier payment item not found",
"cashierItemAppIdImmutable": "Cashier item appId cannot be changed",
"cashierItemMethodRequired": "Payment method is required in METHOD mode",

View File

@@ -537,9 +537,12 @@
"oldPassword": {
"notBlank": "Old password cannot be blank"
},
"clientEnv": {
"notBlank": "Client environment must not be blank",
"size": "Client environment code must not exceed 32 characters"
},
"scene": {
"notNull": "Message scene cannot be blank",
"size": "Scene code cannot exceed 32 characters"
"notNull": "Message scene must not be null"
},
"demoContent": {
"notBlank": "Message content cannot be blank"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "URL dasar backend (backendBaseUrl) tidak dikonfigurasi, tidak dapat menghasilkan URL panggilan balik",
"requestContextMissing": "Tidak dapat memperoleh konteks permintaan",
"gatewayUrlNotConfigured": "URL dasar gateway pembayaran (pembayaranGatewayBaseUrl) tidak dikonfigurasi, tidak dapat menghasilkan URL panggilan balik autentikasi",
"cashierSceneNotExist": "Adegan kasir tidak ditemukan: {0}",
"clientEnvNotExist": "Lingkungan klien tidak ditemukan: {0}",
"gatewayPayTypeNotExist": "Jenis pembayaran gerbang tidak ditemukan: {0}",
"aggregateConfigLevelNotExist": "Tingkat konfigurasi agregat tidak ditemukan: {0}",
"gatewayCashierTypeNotExist": "Jenis kasir gerbang tidak ditemukan: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "Pembayaran kasir belum tersedia",
"typeMismatch": "Jenis pesanan gateway tidak cocok",
"sceneNotSupport": "Adegan kasir tidak didukung",
"sceneNotConfigured": "Metode pembayaran tidak dikonfigurasi untuk adegan ini",
"clientEnvNotSupport": "Unsupported client environment",
"clientEnvNotConfigured": "Payment method not configured for this client environment",
"aggregateConfigMissing": "Konfigurasi pembayaran QR agregat tidak ada untuk aplikasi",
"aggregateScenesRequired": "Konfigurasi adegan diperlukan untuk tingkat konfigurasi ini",
"aggregateSceneBlank": "Kode adegan wajib diisi",
"aggregateSceneMethodRequired": "Metode pembayaran diperlukan untuk setiap adegan di level METODE",
"aggregateSceneChannelMchRequired": "Pedagang saluran diperlukan untuk setiap adegan di level LANGSUNG",
"aggregateSceneCapabilityRequired": "Kemampuan diperlukan untuk setiap adegan di level LANGSUNG",
"aggregateClientEnvsRequired": "Client environment config required for this config level",
"aggregateClientEnvBlank": "Client environment code must not be blank",
"aggregateClientEnvMethodRequired": "Payment method required for each client environment in METHOD level",
"aggregateClientEnvChannelMchRequired": "Channel merchant required for each client environment in DIRECT level",
"aggregateClientEnvCapabilityRequired": "Capability required for each client environment in DIRECT level",
"channelLocked": "Metode pembayaran dikunci untuk pesanan ini",
"cashierSceneRequired": "Kasir H5 membutuhkan adegan terminal",
"clientEnvRequired": "H5 cashier requires a client environment",
"cashierItemNotFound": "Item pembayaran kasir tidak ditemukan",
"cashierItemAppIdImmutable": "AppId item kasir tidak dapat diubah",
"cashierItemMethodRequired": "Metode pembayaran diperlukan dalam mode METODE",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "Kata sandi lama tidak boleh kosong"
},
"clientEnv": {
"notBlank": "Lingkungan klien tidak boleh kosong",
"size": "Kode lingkungan klien tidak boleh lebih dari 32 karakter"
},
"scene": {
"notNull": "Adegan pesan tidak boleh kosong",
"size": "Kode adegan tidak boleh melebihi 32 karakter"
"notNull": "Adegan pesan tidak boleh kosong"
},
"demoContent": {
"notBlank": "Isi pesan tidak boleh kosong"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "バックエンド ベース URL (backendBaseUrl) が構成されていないため、コールバック URL を生成できません",
"requestContextMissing": "リクエストコンテキストを取得できません",
"gatewayUrlNotConfigured": "支払いゲートウェイのベース URL (paymentGatewayBaseUrl) が構成されていないため、認証コールバック URL を生成できません",
"cashierSceneNotExist": "レジ係のシーンが見つかりません: {0}",
"clientEnvNotExist": "クライアント環境が見つかりません: {0}",
"gatewayPayTypeNotExist": "ゲートウェイの支払いタイプが見つかりません: {0}",
"aggregateConfigLevelNotExist": "集約構成レベルが見つかりません: {0}",
"gatewayCashierTypeNotExist": "ゲートウェイ レジ係のタイプが見つかりません: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "レジでの支払いはまだ利用できません",
"typeMismatch": "ゲートウェイ注文タイプの不一致",
"sceneNotSupport": "サポートされていないレジのシーン",
"sceneNotConfigured": "このシーンには支払い方法が設定されていません",
"clientEnvNotSupport": "サポートされていないクライアント環境",
"clientEnvNotConfigured": "このクライアント環境には支払い方法が設定されていません",
"aggregateConfigMissing": "アプリの集約 QR Pay 構成がありません",
"aggregateScenesRequired": "この構成レベルに必要なシーン構成",
"aggregateSceneBlank": "シーンコードを空白にすることはできません",
"aggregateSceneMethodRequired": "METHODレベルのシーンごとに必要な支払い方法",
"aggregateSceneChannelMchRequired": "DIRECTレベルの各シーンに必要なチャネルマーチャント",
"aggregateSceneCapabilityRequired": "DIRECTレベルの各シーンに必要な能力",
"aggregateClientEnvsRequired": "この構成レベルではクライアント環境設定が必要です",
"aggregateClientEnvBlank": "クライアント環境コードを空白にすることはできません",
"aggregateClientEnvMethodRequired": "METHOD レベルの各クライアント環境で支払い方法が必要です",
"aggregateClientEnvChannelMchRequired": "DIRECT レベルの各クライアント環境でチャネルマーチャントが必要です",
"aggregateClientEnvCapabilityRequired": "DIRECT レベルの各クライアント環境で能力が必要です",
"channelLocked": "この注文では支払い方法がロックされています",
"cashierSceneRequired": "H5 レジにはターミナル シーンが必要です",
"clientEnvRequired": "H5 レジにはクライアント環境が必要です",
"cashierItemNotFound": "レジの支払い項目が見つかりません",
"cashierItemAppIdImmutable": "レジアイテムの appId は変更できません",
"cashierItemMethodRequired": "METHODモードでは支払い方法が必要です",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "古いパスワードを空白にすることはできません"
},
"clientEnv": {
"notBlank": "クライアント環境を空にすることはできません",
"size": "クライアント環境コードは32文字以内である必要があります"
},
"scene": {
"notNull": "メッセージシーンを空にすることはできません",
"size": "シーンコードは32文字を超えることはできません"
"notNull": "メッセージシーンを空にすることはできません"
},
"demoContent": {
"notBlank": "メッセージの内容を空白にすることはできません"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "백엔드 기본 URL(backendBaseUrl)이 구성되지 않아 콜백 URL을 생성할 수 없습니다.",
"requestContextMissing": "요청 컨텍스트를 얻을 수 없습니다.",
"gatewayUrlNotConfigured": "결제 게이트웨이 기본 URL(payGatewayBaseUrl)이 구성되지 않았으며 인증 콜백 URL을 생성할 수 없습니다.",
"cashierSceneNotExist": "계산원 장면을 찾을 수 없습니다: {0}",
"clientEnvNotExist": "클라이언트 환경을 찾을 수 없습니다: {0}",
"gatewayPayTypeNotExist": "게이트웨이 지불 유형을 찾을 수 없습니다: {0}",
"aggregateConfigLevelNotExist": "집계 구성 수준을 찾을 수 없습니다: {0}",
"gatewayCashierTypeNotExist": "게이트웨이 계산원 유형을 찾을 수 없습니다: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "아직 캐셔 결제를 사용할 수 없습니다.",
"typeMismatch": "게이트웨이 주문 유형 불일치",
"sceneNotSupport": "지원되지 않는 계산원 장면",
"sceneNotConfigured": "이 장면에는 결제 수단이 구성되지 않았습니다.",
"clientEnvNotSupport": "지원되지 않는 클라이언트 환경",
"clientEnvNotConfigured": "이 클라이언트 환경에는 결제 수단이 구성되지 않았습니다",
"aggregateConfigMissing": "앱에 대한 집계 QR 지불 구성이 누락되었습니다.",
"aggregateScenesRequired": "이 구성 수준에 필요한 장면 구성",
"aggregateSceneBlank": "장면 코드는 비워둘 수 없습니다.",
"aggregateSceneMethodRequired": "METHOD 레벨의 각 장면에 필요한 결제 수단",
"aggregateSceneChannelMchRequired": "DIRECT 레벨의 각 장면에 필요한 채널 상인",
"aggregateSceneCapabilityRequired": "DIRECT 레벨의 각 장면에 필요한 기능",
"aggregateClientEnvsRequired": "이 구성 수준에는 클라이언트 환경 구성이 필요합니다",
"aggregateClientEnvBlank": "클라이언트 환경 코드는 비워둘 수 없습니다",
"aggregateClientEnvMethodRequired": "METHOD 레벨의 각 클라이언트 환경에 결제 수단이 필요합니다",
"aggregateClientEnvChannelMchRequired": "DIRECT 레벨의 각 클라이언트 환경에 채널 상인이 필요합니다",
"aggregateClientEnvCapabilityRequired": "DIRECT 레벨의 각 클라이언트 환경에 기능이 필요합니다",
"channelLocked": "이 주문에 대한 결제 수단이 잠겼습니다.",
"cashierSceneRequired": "H5 계산원은 터미널 장면이 필요합니다",
"clientEnvRequired": "H5 계산원에는 클라이언트 환경이 필요합니다",
"cashierItemNotFound": "계산원 결제 항목을 찾을 수 없습니다.",
"cashierItemAppIdImmutable": "계산원 항목 appId를 변경할 수 없습니다.",
"cashierItemMethodRequired": "METHOD 모드에는 결제 수단이 필요합니다.",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "이전 비밀번호는 비워둘 수 없습니다."
},
"clientEnv": {
"notBlank": "클라이언트 환경은 비워둘 수 없습니다",
"size": "클라이언트 환경 코드는 32자를 초과할 수 없습니다"
},
"scene": {
"notNull": "메시지 장면은 비워둘 수 없습니다.",
"size": "장면 코드는 32자를 초과할 수 없습니다."
"notNull": "메시지 장면은 비워둘 수 없습니다"
},
"demoContent": {
"notBlank": "메시지 내용은 비워둘 수 없습니다."

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "URL asas backend (backendBaseUrl) tidak dikonfigurasikan, tidak boleh menjana URL panggil balik",
"requestContextMissing": "Tidak boleh mendapatkan konteks permintaan",
"gatewayUrlNotConfigured": "URL asas get laluan pembayaran (paymentGatewayBaseUrl) tidak dikonfigurasikan, tidak boleh menjana URL panggil balik pengesahan",
"cashierSceneNotExist": "Adegan juruwang tidak ditemui: {0}",
"clientEnvNotExist": "Persekitaran klien tidak ditemui: {0}",
"gatewayPayTypeNotExist": "Jenis pembayaran gerbang tidak ditemui: {0}",
"aggregateConfigLevelNotExist": "Tahap konfigurasi agregat tidak ditemui: {0}",
"gatewayCashierTypeNotExist": "Jenis juruwang pintu masuk tidak ditemui: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "Bayaran juruwang belum tersedia",
"typeMismatch": "Jenis pesanan gerbang tidak padan",
"sceneNotSupport": "Adegan juruwang yang tidak disokong",
"sceneNotConfigured": "Kaedah pembayaran tidak dikonfigurasikan untuk adegan ini",
"clientEnvNotSupport": "Unsupported client environment",
"clientEnvNotConfigured": "Payment method not configured for this client environment",
"aggregateConfigMissing": "Konfigurasi pembayaran QR agregat tiada untuk apl",
"aggregateScenesRequired": "Konfigurasi adegan diperlukan untuk tahap konfigurasi ini",
"aggregateSceneBlank": "Kod adegan tidak boleh kosong",
"aggregateSceneMethodRequired": "Kaedah pembayaran diperlukan untuk setiap adegan dalam tahap METHOD",
"aggregateSceneChannelMchRequired": "Pedagang saluran diperlukan untuk setiap adegan dalam tahap LANGSUNG",
"aggregateSceneCapabilityRequired": "Keupayaan diperlukan untuk setiap adegan dalam tahap LANGSUNG",
"aggregateClientEnvsRequired": "Client environment config required for this config level",
"aggregateClientEnvBlank": "Client environment code must not be blank",
"aggregateClientEnvMethodRequired": "Payment method required for each client environment in METHOD level",
"aggregateClientEnvChannelMchRequired": "Channel merchant required for each client environment in DIRECT level",
"aggregateClientEnvCapabilityRequired": "Capability required for each client environment in DIRECT level",
"channelLocked": "Kaedah pembayaran dikunci untuk pesanan ini",
"cashierSceneRequired": "Juruwang H5 memerlukan adegan terminal",
"clientEnvRequired": "H5 cashier requires a client environment",
"cashierItemNotFound": "Item pembayaran juruwang tidak ditemui",
"cashierItemAppIdImmutable": "AppId item juruwang tidak boleh ditukar",
"cashierItemMethodRequired": "Kaedah pembayaran diperlukan dalam mod METHOD",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "Kata laluan lama tidak boleh kosong"
},
"clientEnv": {
"notBlank": "Persekitaran klien tidak boleh kosong",
"size": "Kod persekitaran klien tidak boleh melebihi 32 aksara"
},
"scene": {
"notNull": "Adegan mesej tidak boleh kosong",
"size": "Kod adegan tidak boleh melebihi 32 aksara"
"notNull": "Adegan mesej tidak boleh kosong"
},
"demoContent": {
"notBlank": "Kandungan mesej tidak boleh kosong"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "ไม่ได้กำหนดค่า URL ฐานแบ็กเอนด์ (backendBaseUrl) ไม่สามารถสร้าง URL เรียกกลับได้",
"requestContextMissing": "ไม่สามารถรับบริบทคำขอได้",
"gatewayUrlNotConfigured": "ไม่ได้กำหนดค่า URL ฐานเกตเวย์การชำระเงิน (PaymentGatewayBaseUrl) ไม่สามารถสร้าง URL เรียกกลับการรับรองความถูกต้องได้",
"cashierSceneNotExist": "ไม่พบฉากแคชเชียร์: {0}",
"clientEnvNotExist": "ไม่พบสภาพแวดล้อมไคลเอนต์: {0}",
"gatewayPayTypeNotExist": "ไม่พบประเภทการชำระเงินของเกตเวย์: {0}",
"aggregateConfigLevelNotExist": "ไม่พบระดับการกำหนดค่ารวม: {0}",
"gatewayCashierTypeNotExist": "ไม่พบประเภทแคชเชียร์ของเกตเวย์: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "ยังไม่มีการชำระเงินผ่านแคชเชียร์",
"typeMismatch": "ประเภทคำสั่งเกตเวย์ไม่ตรงกัน",
"sceneNotSupport": "ฉากแคชเชียร์ที่ไม่รองรับ",
"sceneNotConfigured": "ไม่ได้กำหนดค่าวิธีการชำระเงินสำหรับฉากนี้",
"clientEnvNotSupport": "Unsupported client environment",
"clientEnvNotConfigured": "Payment method not configured for this client environment",
"aggregateConfigMissing": "การกำหนดค่าการจ่าย QR รวมหายไปสำหรับแอป",
"aggregateScenesRequired": "ต้องมีการกำหนดค่าฉากสำหรับระดับการกำหนดค่านี้",
"aggregateSceneBlank": "รหัสฉากต้องไม่เว้นว่าง",
"aggregateSceneMethodRequired": "วิธีการชำระเงินที่จำเป็นสำหรับแต่ละฉากในระดับวิธี",
"aggregateSceneChannelMchRequired": "ผู้ค้าช่องทางที่จำเป็นสำหรับแต่ละฉากในระดับโดยตรง",
"aggregateSceneCapabilityRequired": "ความสามารถที่จำเป็นสำหรับแต่ละฉากในระดับ DIRECT",
"aggregateClientEnvsRequired": "Client environment config required for this config level",
"aggregateClientEnvBlank": "Client environment code must not be blank",
"aggregateClientEnvMethodRequired": "Payment method required for each client environment in METHOD level",
"aggregateClientEnvChannelMchRequired": "Channel merchant required for each client environment in DIRECT level",
"aggregateClientEnvCapabilityRequired": "Capability required for each client environment in DIRECT level",
"channelLocked": "วิธีการชำระเงินถูกล็อคสำหรับคำสั่งซื้อนี้",
"cashierSceneRequired": "แคชเชียร์ H5 ต้องใช้ฉากเทอร์มินัล",
"clientEnvRequired": "H5 cashier requires a client environment",
"cashierItemNotFound": "ไม่พบรายการชำระเงินของแคชเชียร์",
"cashierItemAppIdImmutable": "ไม่สามารถเปลี่ยนรหัสแอปรายการแคชเชียร์ได้",
"cashierItemMethodRequired": "ต้องระบุวิธีการชำระเงินในโหมดวิธี",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "รหัสผ่านเก่าไม่สามารถเว้นว่างได้"
},
"clientEnv": {
"notBlank": "สภาพแวดล้อมไคลเอนต์ต้องไม่ว่าง",
"size": "รหัสสภาพแวดล้อมไคลเอนต์ต้องไม่เกิน 32 ตัวอักษร"
},
"scene": {
"notNull": "ฉากข้อความต้องไม่เว้นว่าง",
"size": "โค้ดฉากต้องมีความยาวไม่เกิน 32 อักขระ"
"notNull": "ฉากข้อความต้องไม่ว่าง"
},
"demoContent": {
"notBlank": "เนื้อหาข้อความต้องไม่เว้นว่าง"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "URL cơ sở phụ trợ (backendBaseUrl) chưa được định cấu hình, không thể tạo URL gọi lại",
"requestContextMissing": "Không thể lấy được ngữ cảnh yêu cầu",
"gatewayUrlNotConfigured": "URL cơ sở của cổng thanh toán (PaymentGatewayBaseUrl) chưa được định cấu hình, không thể tạo URL gọi lại xác thực",
"cashierSceneNotExist": "Không tìm thấy cảnh thu ngân: {0}",
"clientEnvNotExist": "Không tìm thấy môi trường máy khách: {0}",
"gatewayPayTypeNotExist": "Không tìm thấy loại thanh toán qua cổng: {0}",
"aggregateConfigLevelNotExist": "Không tìm thấy cấp cấu hình tổng hợp: {0}",
"gatewayCashierTypeNotExist": "Không tìm thấy loại cổng thu ngân: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "Thanh toán bằng tiền mặt vẫn chưa có sẵn",
"typeMismatch": "Loại thứ tự cổng không khớp",
"sceneNotSupport": "Cảnh thu ngân không được hỗ trợ",
"sceneNotConfigured": "Phương thức thanh toán chưa được định cấu hình cho cảnh này",
"clientEnvNotSupport": "Unsupported client environment",
"clientEnvNotConfigured": "Payment method not configured for this client environment",
"aggregateConfigMissing": "Thiếu cấu hình thanh toán QR tổng hợp cho ứng dụng",
"aggregateScenesRequired": "Cần có cấu hình cảnh cho cấp cấu hình này",
"aggregateSceneBlank": "Mã cảnh không được để trống",
"aggregateSceneMethodRequired": "Cần có phương thức thanh toán cho từng cảnh ở cấp PHƯƠNG PHÁP",
"aggregateSceneChannelMchRequired": "Cần có người bán kênh cho mỗi cảnh ở cấp độ TRỰC TIẾP",
"aggregateSceneCapabilityRequired": "Khả năng cần thiết cho từng cảnh ở cấp độ TRỰC TIẾP",
"aggregateClientEnvsRequired": "Client environment config required for this config level",
"aggregateClientEnvBlank": "Client environment code must not be blank",
"aggregateClientEnvMethodRequired": "Payment method required for each client environment in METHOD level",
"aggregateClientEnvChannelMchRequired": "Channel merchant required for each client environment in DIRECT level",
"aggregateClientEnvCapabilityRequired": "Capability required for each client environment in DIRECT level",
"channelLocked": "Phương thức thanh toán bị khóa cho đơn hàng này",
"cashierSceneRequired": "Nhân viên thu ngân H5 yêu cầu cảnh cuối",
"clientEnvRequired": "H5 cashier requires a client environment",
"cashierItemNotFound": "Không tìm thấy mục thanh toán thu ngân",
"cashierItemAppIdImmutable": "Id ứng dụng của mặt hàng thu ngân không thể thay đổi",
"cashierItemMethodRequired": "Phương thức thanh toán là bắt buộc trong chế độ METHOD",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "Mật khẩu cũ không được để trống"
},
"clientEnv": {
"notBlank": "Môi trường máy khách không được để trống",
"size": "Mã môi trường máy khách không được vượt quá 32 ký tự"
},
"scene": {
"notNull": "Cảnh tin nhắn không được để trống",
"size": "Mã cảnh không được vượt quá 32 ký tự"
"notNull": "Cảnh tin nhắn không được để trống"
},
"demoContent": {
"notBlank": "Nội dung tin nhắn không được để trống"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "平台后端访问地址(backendBaseUrl)未配置, 无法生成回调地址",
"requestContextMissing": "无法获取请求上下文",
"gatewayUrlNotConfigured": "支付网关前端地址(paymentGatewayBaseUrl)未配置, 无法生成认证回调地址",
"cashierSceneNotExist": "收银场景不存在: {0}",
"clientEnvNotExist": "客户端环境不存在: {0}",
"gatewayPayTypeNotExist": "网关支付类型不存在: {0}",
"aggregateConfigLevelNotExist": "聚合扫码配置深度不存在: {0}",
"gatewayCashierTypeNotExist": "收银台类型不存在: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "收银台支付尚未开放",
"typeMismatch": "网关订单类型不匹配",
"sceneNotSupport": "不支持的收银场景",
"sceneNotConfigured": "该场景未配置支付方式",
"clientEnvNotSupport": "不支持的客户端环境",
"clientEnvNotConfigured": "该客户端环境未配置支付方式",
"aggregateConfigMissing": "应用未配置聚合扫码支付",
"aggregateScenesRequired": "当前配置深度下场景配置不能为空",
"aggregateSceneBlank": "场景编码不能为空",
"aggregateSceneMethodRequired": "指定支付方式时,每个打开环境的支付方式必填",
"aggregateSceneChannelMchRequired": "指定通道商户时,每个打开环境的通道商户号必填",
"aggregateSceneCapabilityRequired": "指定通道商户时,每个打开环境的支付能力必填",
"aggregateClientEnvsRequired": "当前配置深度下客户端环境配置不能为空",
"aggregateClientEnvBlank": "客户端环境编码不能为空",
"aggregateClientEnvMethodRequired": "指定支付方式时,每个打开环境的支付方式必填",
"aggregateClientEnvChannelMchRequired": "指定通道商户时,每个打开环境的通道商户号必填",
"aggregateClientEnvCapabilityRequired": "指定通道商户时,每个打开环境的支付能力必填",
"channelLocked": "订单已锁定支付方式,请勿切换",
"cashierSceneRequired": "H5收银台必须指定终端场景",
"clientEnvRequired": "H5收银台必须指定客户端环境",
"cashierItemNotFound": "收银台支付项不存在",
"cashierItemAppIdImmutable": "收银台支付项应用号不可修改",
"cashierItemMethodRequired": "指定支付方式时支付方式必填",

View File

@@ -540,9 +540,12 @@
"oldPassword": {
"notBlank": "旧密码不能为空"
},
"clientEnv": {
"notBlank": "客户端环境不能为空",
"size": "客户端环境编码不可超过32位"
},
"scene": {
"notNull": "消息场景不能为空",
"size": "场景编码不可超过32位"
"notNull": "消息场景不能为空"
},
"demoContent": {
"notBlank": "消息内容不能为空"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "平台後端訪問地址(backendBaseUrl)未配置, 無法生成回調地址",
"requestContextMissing": "無法獲取請求上下文",
"gatewayUrlNotConfigured": "支付網關前端地址(paymentGatewayBaseUrl)未配置, 無法生成認證回調地址",
"cashierSceneNotExist": "收銀場景不存在: {0}",
"clientEnvNotExist": "用戶端環境不存在: {0}",
"gatewayPayTypeNotExist": "網關支付類型不存在: {0}",
"aggregateConfigLevelNotExist": "聚合掃碼配置深度不存在: {0}",
"gatewayCashierTypeNotExist": "收銀台類型不存在: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "收銀台支付尚未開放",
"typeMismatch": "網關訂單類型不匹配",
"sceneNotSupport": "不支持的收銀場景",
"sceneNotConfigured": "該場景未配置支付方式",
"clientEnvNotSupport": "不支持的用戶端環境",
"clientEnvNotConfigured": "該用戶端環境未配置支付方式",
"aggregateConfigMissing": "應用未配置聚合掃碼支付",
"aggregateScenesRequired": "當前配置深度下場景配置不能為空",
"aggregateSceneBlank": "場景編碼不能為空",
"aggregateSceneMethodRequired": "指定支付方式時,每個打開環境的支付方式必填",
"aggregateSceneChannelMchRequired": "指定通道商時,每個打開環境的通道商號必填",
"aggregateSceneCapabilityRequired": "指定通道商時,每個打開環境的支付能力必填",
"aggregateClientEnvsRequired": "當前配置深度下用戶端環境配置不能為空",
"aggregateClientEnvBlank": "用戶端環境編碼不能為空",
"aggregateClientEnvMethodRequired": "指定支付方式時,每個打開環境的支付方式必填",
"aggregateClientEnvChannelMchRequired": "指定通道商時,每個打開環境的通道商號必填",
"aggregateClientEnvCapabilityRequired": "指定通道商時,每個打開環境的支付能力必填",
"channelLocked": "訂單已鎖定支付方式,請勿切換",
"cashierSceneRequired": "H5收銀台必須指定終端場景",
"clientEnvRequired": "H5收銀台必須指定用戶端環境",
"cashierItemNotFound": "收銀台支付項不存在",
"cashierItemAppIdImmutable": "收銀台支付項應用號不可修改",
"cashierItemMethodRequired": "指定支付方式時支付方式必填",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "舊密碼不能為空"
},
"clientEnv": {
"notBlank": "用戶端環境不能為空",
"size": "用戶端環境編碼不可超過32位"
},
"scene": {
"notNull": "息場景不能為空",
"size": "場景編碼不可超過32位"
"notNull": "息場景不能為空"
},
"demoContent": {
"notBlank": "消息內容不能為空"

View File

@@ -32,7 +32,7 @@
"backendBaseUrlNotConfigured": "平臺後端訪問地址(backendBaseUrl)未配置, 無法生成回撥地址",
"requestContextMissing": "無法獲取請求上下文",
"gatewayUrlNotConfigured": "支付閘道器前端地址(paymentGatewayBaseUrl)未配置, 無法生成認證回撥地址",
"cashierSceneNotExist": "收銀場景不存在: {0}",
"clientEnvNotExist": "用戶端環境不存在: {0}",
"gatewayPayTypeNotExist": "閘道器支付型別不存在: {0}",
"aggregateConfigLevelNotExist": "聚合掃碼配置深度不存在: {0}",
"gatewayCashierTypeNotExist": "收銀臺型別不存在: {0}",

View File

@@ -45,16 +45,16 @@
"gateway": {
"cashierNotReady": "收銀臺支付尚未開放",
"typeMismatch": "閘道器訂單型別不匹配",
"sceneNotSupport": "不支援的收銀場景",
"sceneNotConfigured": "該場景未配置支付方式",
"clientEnvNotSupport": "不支援的用戶端環境",
"clientEnvNotConfigured": "該用戶端環境未配置支付方式",
"aggregateConfigMissing": "應用未配置聚合掃碼支付",
"aggregateScenesRequired": "當前配置深度下場景配置不能為空",
"aggregateSceneBlank": "場景編碼不能為空",
"aggregateSceneMethodRequired": "指定支付方式時,每個開啟環境的支付方式必填",
"aggregateSceneChannelMchRequired": "指定通道商戶時,每個開啟環境的通道商戶號必填",
"aggregateSceneCapabilityRequired": "指定通道商戶時,每個開啟環境的支付能力必填",
"aggregateClientEnvsRequired": "當前配置深度下用戶端環境配置不能為空",
"aggregateClientEnvBlank": "用戶端環境編碼不能為空",
"aggregateClientEnvMethodRequired": "指定支付方式時,每個開啟環境的支付方式必填",
"aggregateClientEnvChannelMchRequired": "指定通道商戶時,每個開啟環境的通道商戶號必填",
"aggregateClientEnvCapabilityRequired": "指定通道商戶時,每個開啟環境的支付能力必填",
"channelLocked": "訂單已鎖定支付方式,請勿切換",
"cashierSceneRequired": "H5收銀必須指定終端場景",
"clientEnvRequired": "H5收銀必須指定用戶端環境",
"cashierItemNotFound": "收銀臺支付項不存在",
"cashierItemAppIdImmutable": "收銀臺支付項應用號不可修改",
"cashierItemMethodRequired": "指定支付方式時支付方式必填",

View File

@@ -533,9 +533,12 @@
"oldPassword": {
"notBlank": "舊密碼不能為空"
},
"clientEnv": {
"notBlank": "用戶端環境不能為空",
"size": "用戶端環境編碼不可超過32位"
},
"scene": {
"notNull": "訊息場景不能為空",
"size": "場景編碼不可超過32位"
"notNull": "訊息場景不能為空"
},
"demoContent": {
"notBlank": "訊息內容不能為空"