diff --git a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/entity/direct/AlipayDirectChannelMerchant.java b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/entity/direct/AlipayDirectChannelMerchant.java index ce0a90181..348f8fde7 100644 --- a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/entity/direct/AlipayDirectChannelMerchant.java +++ b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/entity/direct/AlipayDirectChannelMerchant.java @@ -29,6 +29,9 @@ public class AlipayDirectChannelMerchant extends MchBaseEntity implements ToResu /// 支付宝商家唯一识别码(2088开头的16位数字) private String alipayUserId; + /// 是否沙箱环境商户 + private boolean sandbox; + /// 转换 @Override public AlipayDirectChannelMerchantResult toResult() { diff --git a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/direct/AlipayDirectConfigAssembler.java b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/direct/AlipayDirectConfigAssembler.java index ec69791fc..b68427af3 100644 --- a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/direct/AlipayDirectConfigAssembler.java +++ b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/direct/AlipayDirectConfigAssembler.java @@ -1,12 +1,16 @@ package cn.daxpay.open.channel.alipay.service.direct; import cn.daxpay.open.channel.alipay.dao.direct.AlipayDirectAppManager; +import cn.daxpay.open.channel.alipay.dao.direct.AlipayDirectChannelMerchantManager; import cn.daxpay.open.channel.alipay.client.credential.AlipaySdkCredential; import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectApp; import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectAppKeyConfig; +import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectChannelMerchant; import cn.daxpay.open.payment.masterdata.constants.product.dao.PayProductConfigManager; +import cn.daxpay.open.platform.core.code.CommonErrorCode; import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum; import cn.daxpay.open.platform.core.enums.pay.config.PayEnvEnum; +import cn.daxpay.open.platform.core.exception.BizInfoException; import cn.daxpay.open.platform.core.exception.DataNotExistException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -28,6 +32,7 @@ import java.util.Optional; public class AlipayDirectConfigAssembler { private final AlipayDirectAppManager alipayDirectAppManager; + private final AlipayDirectChannelMerchantManager alipayDirectChannelMerchantManager; private final AlipayDirectAppKeyConfigService alipayDirectAppKeyConfigService; private final AlipayDirectAppCapabilityService alipayDirectAppCapabilityService; private final PayProductConfigManager payProductConfigManager; @@ -45,6 +50,14 @@ public class AlipayDirectConfigAssembler { boolean sandbox = payProductConfigManager.findByProduct(ProductEnum.ALIPAY.getCode()) .map(c -> PayEnvEnum.SANDBOX.getCode().equals(c.getActiveEnv())) .orElse(false); + // 环境一致性校验: 通道商户绑定的沙箱标记需与产品当前生效环境一致 + AlipayDirectChannelMerchant channelMerchant = alipayDirectChannelMerchantManager.lambdaQuery() + .eq(AlipayDirectChannelMerchant::getChannelMchNo, channelMchNo) + .oneOpt() + .orElseThrow(() -> new DataNotExistException("error.payment.channel.channelMerchantNotExist")); + if (channelMerchant.isSandbox() != sandbox) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.envMismatch"); + } AlipayDirectAppKeyConfig keyConfig = alipayDirectAppKeyConfigService.findByAlipayDirectAppId(app.getId(), sandbox); var credential = new AlipaySdkCredential(); diff --git a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/entity/isv/FuyouIsvChannelMerchant.java b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/entity/isv/FuyouIsvChannelMerchant.java index 4e9359262..e489d8668 100644 --- a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/entity/isv/FuyouIsvChannelMerchant.java +++ b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/entity/isv/FuyouIsvChannelMerchant.java @@ -27,6 +27,9 @@ public class FuyouIsvChannelMerchant extends MchBaseEntity implements ToResult new DataNotExistException("error.payment.channel.channelMerchantNotExist")); + // 环境一致性校验 + if (channelMerchant.isSandbox() != sandbox) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.envMismatch"); + } FuyouSdkCredential credential = new FuyouSdkCredential(); // 服务商身份与密钥 diff --git a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/entity/isv/HkrtIsvChannelMerchant.java b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/entity/isv/HkrtIsvChannelMerchant.java index 3b3780c50..b2f0e5367 100644 --- a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/entity/isv/HkrtIsvChannelMerchant.java +++ b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/entity/isv/HkrtIsvChannelMerchant.java @@ -27,6 +27,9 @@ public class HkrtIsvChannelMerchant extends MchBaseEntity implements ToResult new DataNotExistException("error.payment.channel.channelMerchantNotExist")); + // 环境一致性校验 + if (channelMerchant.isSandbox() != sandbox) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.envMismatch"); + } HkrtSdkCredential credential = new HkrtSdkCredential(); // 服务商身份与密钥 diff --git a/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/entity/isv/HmpayIsvChannelMerchant.java b/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/entity/isv/HmpayIsvChannelMerchant.java index fe11c1909..5b53021f3 100644 --- a/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/entity/isv/HmpayIsvChannelMerchant.java +++ b/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/entity/isv/HmpayIsvChannelMerchant.java @@ -27,6 +27,9 @@ public class HmpayIsvChannelMerchant extends MchBaseEntity implements ToResult new DataNotExistException("payment.error.channel.channelMerchantNotExist")); + // 环境一致性校验 + if (channelMerchant.isSandbox() != sandbox) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.envMismatch"); + } + HmpaySdkCredential credential = new HmpaySdkCredential(); // 服务商身份与密钥 credential.setSandAppId(keyConfig.getSandAppId()); diff --git a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/entity/isv/LakalaIsvChannelMerchant.java b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/entity/isv/LakalaIsvChannelMerchant.java index 5b68babbb..62eb2b84f 100644 --- a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/entity/isv/LakalaIsvChannelMerchant.java +++ b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/entity/isv/LakalaIsvChannelMerchant.java @@ -27,6 +27,9 @@ public class LakalaIsvChannelMerchant extends MchBaseEntity implements ToResult< /// @see cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum private String product; + /// 是否沙箱环境商户 + private boolean sandbox; + /// 拉卡拉商户编号(merchantNo) private String lakalaMchNo; diff --git a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/isv/LakalaIsvConfigAssembler.java b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/isv/LakalaIsvConfigAssembler.java index ac4a26429..b54a0a226 100644 --- a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/isv/LakalaIsvConfigAssembler.java +++ b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/isv/LakalaIsvConfigAssembler.java @@ -55,6 +55,10 @@ public class LakalaIsvConfigAssembler { LakalaIsvChannelMerchant channelMerchant = lakalaIsvChannelMerchantManager.findByChannelMchNo(channelMchNo) // 拉卡拉: 通道商户配置不存在 .orElseThrow(() -> new DataNotExistException("error.payment.channel.channelMerchantNotExist")); + // 环境一致性校验 + if (channelMerchant.isSandbox() != sandbox) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.envMismatch"); + } LakalaSdkCredential credential = new LakalaSdkCredential(); // 服务商身份与密钥 diff --git a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/entity/isv/LeshuaIsvChannelMerchant.java b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/entity/isv/LeshuaIsvChannelMerchant.java index f2e7b841f..abaecba5d 100644 --- a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/entity/isv/LeshuaIsvChannelMerchant.java +++ b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/entity/isv/LeshuaIsvChannelMerchant.java @@ -27,6 +27,9 @@ public class LeshuaIsvChannelMerchant extends MchBaseEntity implements ToResult< /// @see cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum private String product; + /// 是否沙箱环境商户 + private boolean sandbox; + /// 乐刷商户编号(merchant_id) private String lsMchNo; diff --git a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/service/isv/LeshuaIsvConfigAssembler.java b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/service/isv/LeshuaIsvConfigAssembler.java index 690c62d28..817f0f26f 100644 --- a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/service/isv/LeshuaIsvConfigAssembler.java +++ b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/service/isv/LeshuaIsvConfigAssembler.java @@ -6,8 +6,10 @@ import cn.daxpay.open.channel.leshua.entity.isv.LeshuaIsvChannelMerchant; import cn.daxpay.open.channel.leshua.entity.isv.LeshuaIsvKeyConfig; import cn.daxpay.open.payment.masterdata.constants.product.dao.PayProductConfigManager; import cn.daxpay.open.payment.masterdata.constants.product.entity.PayProductConfig; +import cn.daxpay.open.platform.core.code.CommonErrorCode; import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum; import cn.daxpay.open.platform.core.enums.pay.config.PayEnvEnum; +import cn.daxpay.open.platform.core.exception.BizInfoException; import cn.daxpay.open.platform.core.exception.DataNotExistException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -47,6 +49,14 @@ public class LeshuaIsvConfigAssembler { .orElse(false); // 服务商密钥(按生效环境取对应环境密钥, 含 lsMchNo + tradeKey + signType) LeshuaIsvKeyConfig keyConfig = leshuaIsvKeyConfigService.getByProductForPay(ProductEnum.LESHUA_PAY.getCode(), sandbox); + // 通道商户绑定(校验环境一致性) + LeshuaIsvChannelMerchant channelMerchant = leshuaIsvChannelMerchantManager.findByChannelMchNo(channelMchNo) + // 乐刷: 通道商户配置不存在 + .orElseThrow(() -> new DataNotExistException("error.payment.channel.channelMerchantNotExist")); + // 环境一致性校验 + if (channelMerchant.isSandbox() != sandbox) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.envMismatch"); + } LeshuaSdkCredential credential = new LeshuaSdkCredential(); credential.setLsMchNo(keyConfig.getLsMchNo()); diff --git a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/entity/isv/VbillIsvChannelMerchant.java b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/entity/isv/VbillIsvChannelMerchant.java index 63282604a..91533e487 100644 --- a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/entity/isv/VbillIsvChannelMerchant.java +++ b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/entity/isv/VbillIsvChannelMerchant.java @@ -27,6 +27,9 @@ public class VbillIsvChannelMerchant extends MchBaseEntity implements ToResult new DataNotExistException("error.payment.channel.channelMerchantNotExist")); + // 环境一致性校验 + if (channelMerchant.isSandbox() != sandbox) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.envMismatch"); + } + VbillSdkCredential credential = new VbillSdkCredential(); // 服务商身份与密钥 credential.setOrgId(keyConfig.getOrgId()); diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/channel/entity/mch/ChannelMerchant.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/channel/entity/mch/ChannelMerchant.java index d7074cdd2..83e2e8dda 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/channel/entity/mch/ChannelMerchant.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/channel/entity/mch/ChannelMerchant.java @@ -43,6 +43,9 @@ public class ChannelMerchant extends MchBaseEntity implements ToResult results) { if (results.isEmpty()) { return; @@ -111,20 +110,15 @@ public class ChannelMerchantService { if (products.isEmpty()) { return; } - // 生效环境 - Map envMap = payProductConfigManager.lambdaQuery() - .in(PayProductConfig::getProduct, products) - .list() - .stream() - .collect(Collectors.toMap(PayProductConfig::getProduct, PayProductConfig::getActiveEnv, (a, b) -> a)); - // 沙箱支持标志 + // 沙箱支持标志(来自支付产品表, 决定前端是否显示环境标签) Map sandboxMap = payProductManager.lambdaQuery() .in(PayProduct::getCode, products) .list() .stream() .collect(Collectors.toMap(PayProduct::getCode, p -> Boolean.TRUE.equals(p.getSandbox()), (a, b) -> a)); results.forEach(r -> { - r.setActiveEnv(envMap.get(r.getProduct())); + // activeEnv 从商户自身的 sandbox 字段推导 + r.setActiveEnv(r.isSandbox() ? PayEnvEnum.SANDBOX.getCode() : PayEnvEnum.PROD.getCode()); r.setSandboxSupport(sandboxMap.getOrDefault(r.getProduct(), false)); }); } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/masterdata/constants/product/service/PayProductConfigService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/masterdata/constants/product/service/PayProductConfigService.java index 6ef56747f..7d6693a07 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/masterdata/constants/product/service/PayProductConfigService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/masterdata/constants/product/service/PayProductConfigService.java @@ -7,12 +7,17 @@ import cn.daxpay.open.payment.masterdata.constants.product.entity.PayProductConf import cn.daxpay.open.payment.masterdata.constants.product.param.PayProductConfigParam; import cn.daxpay.open.payment.masterdata.constants.product.result.PayProductConfigResult; import cn.daxpay.open.payment.core.strategy.product.AbsProductStrategy; +import cn.daxpay.open.platform.common.config.properties.PlatformConfigProperties; 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.ChannelEnum; import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum; import cn.daxpay.open.platform.core.enums.pay.config.PayEnvEnum; +import cn.daxpay.open.platform.core.exception.BizInfoException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,6 +36,8 @@ public class PayProductConfigService { private final PayProductService payProductService; + private final PlatformConfigProperties platformConfigProperties; + /// 查询全部产品配置列表(卡片页使用) /// 融合 PayProduct + pay_md_product_config 表 + 策略信息 public List listAll() { @@ -46,6 +53,11 @@ public class PayProductConfigService { /// 切换产品的生效环境 @Transactional(rollbackFor = Exception.class) public void switchEnv(String product, boolean sandbox) { + // 全局沙箱开关校验 + if (sandbox && !platformConfigProperties.isSandboxEnabled()) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.env.sandboxDisabled"); + } + PayProductConfig config = payProductConfigManager.findByProduct(product) .orElseGet(() -> createDefaultConfig(product)); @@ -60,6 +72,12 @@ public class PayProductConfigService { /// 保存或更新配置 @Transactional(rollbackFor = Exception.class) public void saveOrUpdate(PayProductConfigParam param) { + // 全局沙箱开关校验 + if (PayEnvEnum.SANDBOX.getCode().equals(param.getActiveEnv()) + && !platformConfigProperties.isSandboxEnabled()) { + throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.env.sandboxDisabled"); + } + PayProductConfig config = payProductConfigManager.findByProduct(param.getProduct()) .orElseGet(PayProductConfig::new); @@ -71,6 +89,25 @@ public class PayProductConfigService { payProductConfigManager.saveOrUpdate(config); } + /// 应用启动后检查: 沙箱被全局禁用时, 将所有 activeEnv=sandbox 的产品强制重置为 prod + @EventListener(ApplicationReadyEvent.class) + @Transactional(rollbackFor = Exception.class) + public void checkSandboxOnStartup() { + if (platformConfigProperties.isSandboxEnabled()) { + return; + } + List sandboxConfigs = payProductConfigManager.lambdaQuery() + .eq(PayProductConfig::getActiveEnv, PayEnvEnum.SANDBOX.getCode()) + .list(); + for (PayProductConfig config : sandboxConfigs) { + config.setActiveEnv(PayEnvEnum.PROD.getCode()); + payProductConfigManager.updateById(config); + } + if (!sandboxConfigs.isEmpty()) { + log.info("沙箱环境已禁用(daxpay.pay.env.sandbox-enabled=false), {} 个产品从 sandbox 重置为 prod", sandboxConfigs.size()); + } + } + /// PayProduct + 库表 + 策略合并为配置结果 private PayProductConfigResult toConfigResult(PayProduct payProduct, Map configMap) { var result = new PayProductConfigResult() diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/unipay/param/trade/pay/NormalPayParam.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/unipay/param/trade/pay/NormalPayParam.java index 85317480a..189a00acf 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/unipay/param/trade/pay/NormalPayParam.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/unipay/param/trade/pay/NormalPayParam.java @@ -74,6 +74,11 @@ public class NormalPayParam extends MerchantPaymentCommonParam { @Schema(description = "用户标识OpenId") private String openId; + /// 指定支付/认证使用的应用AppId, 优先级高于配置自动解析, 必须在系统中预先配置过 + @Size(max = 128, message = "{validation.field.opAppId.size}") + @Schema(description = "指定应用AppId") + private String opAppId; + /// 付款码(被扫支付必填) @Size(max = 128, message = "{validation.field.authCode.size}") @Schema(description = "付款码") diff --git a/daxpay-platform/daxpay-platform-common/common-config/src/main/java/cn/daxpay/open/platform/common/config/properties/PlatformConfigProperties.java b/daxpay-platform/daxpay-platform-common/common-config/src/main/java/cn/daxpay/open/platform/common/config/properties/PlatformConfigProperties.java index 1ad05e38b..810eabeee 100644 --- a/daxpay-platform/daxpay-platform-common/common-config/src/main/java/cn/daxpay/open/platform/common/config/properties/PlatformConfigProperties.java +++ b/daxpay-platform/daxpay-platform-common/common-config/src/main/java/cn/daxpay/open/platform/common/config/properties/PlatformConfigProperties.java @@ -30,6 +30,9 @@ public class PlatformConfigProperties { @Valid private Encrypt encrypt = new Encrypt(); + /// 沙箱环境全局开关(关闭后不可切换到沙箱, 已在沙箱的产品启动时自动重置为生产) + private boolean sandboxEnabled = true; + /// # 平台公私钥配置 /// @Slf4j diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/wx_verify_owner_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/wx_verify_owner_type.json new file mode 100644 index 000000000..0b148ee22 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/wx_verify_owner_type.json @@ -0,0 +1,4 @@ +{ + "official_account": "Official Account", + "miniprogram": "Mini Program" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/error/channel.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/error/channel.json new file mode 100644 index 000000000..2d8a8a12c --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/error/channel.json @@ -0,0 +1,3 @@ +{ + "envMismatch": "Channel merchant environment does not match the product's active environment" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/pay/env.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/pay/env.json new file mode 100644 index 000000000..f1b205500 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/pay/env.json @@ -0,0 +1,3 @@ +{ + "sandboxDisabled": "Sandbox environment is disabled by system" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/wx_verify_owner_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/wx_verify_owner_type.json new file mode 100644 index 000000000..bc94ce47c --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/wx_verify_owner_type.json @@ -0,0 +1,4 @@ +{ + "official_account": "公众号", + "miniprogram": "小程序" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/error/channel.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/error/channel.json new file mode 100644 index 000000000..c4f2a4204 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/error/channel.json @@ -0,0 +1,3 @@ +{ + "envMismatch": "通道商户环境与支付产品当前生效环境不一致" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/pay/env.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/pay/env.json new file mode 100644 index 000000000..a051d4803 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/pay/env.json @@ -0,0 +1,3 @@ +{ + "sandboxDisabled": "沙箱环境已被系统关闭,无法切换" +} diff --git a/daxpay-platform/daxpay-platform-service/service-notify/src/main/java/cn/daxpay/open/platform/notify/service/notice/NotifySseService.java b/daxpay-platform/daxpay-platform-service/service-notify/src/main/java/cn/daxpay/open/platform/notify/service/notice/NotifySseService.java index aeb1c3f92..d9e15d826 100644 --- a/daxpay-platform/daxpay-platform-service/service-notify/src/main/java/cn/daxpay/open/platform/notify/service/notice/NotifySseService.java +++ b/daxpay-platform/daxpay-platform-service/service-notify/src/main/java/cn/daxpay/open/platform/notify/service/notice/NotifySseService.java @@ -66,7 +66,7 @@ public class NotifySseService { if (emitters.isEmpty()) { return; } - emitters.forEach((userId, set) -> sendAll(set, payload)); + emitters.forEach((_, set) -> sendAll(set, payload)); } /// 推送给指定用户(个人消息场景) diff --git a/daxpay-start/src/main/resources/application-dev.yml b/daxpay-start/src/main/resources/application-dev.yml index 5b29d4faa..6c563b259 100644 --- a/daxpay-start/src/main/resources/application-dev.yml +++ b/daxpay-start/src/main/resources/application-dev.yml @@ -109,7 +109,7 @@ daxpay: # 查询模式: VECTOR_INDEX(推荐) 或 CACHE search-type: VECTOR_INDEX config: - # 证书配置0 + # 平台公私钥(证书)配置, 用于接口请求/回调的 RSA 签名与验签 key-config: # 私钥配置 private-key: '-----BEGIN PRIVATE KEY----- @@ -150,11 +150,22 @@ daxpay: qEYdxyjbqztxm0SmYwl885mcGPBNPTt9ApoRWR3CGRfE8pcQieuB0YdsdSh9+ZSa IwIDAQAB -----END PUBLIC KEY-----' + # 数据加密配置(数据库敏感字段透明加解密, AES-256-GCM, 由 MyBatis-Plus TypeHandler 自动处理) encrypt: + # 是否启用数据加密; 启用后敏感字段写入自动加密、读取自动解密 + # 注意: 启用并写入加密数据后不要关闭, 否则历史密文读取时不再解密(以密文原文返回) enable: true + # 密钥列表(支持密钥轮换, 列表内版本号不可重复) + # 第一个为当前密钥(用于加密新数据), 其余为历史密钥(仅用于解密旧数据) + # 密文格式: v{版本号}:{base64(IV + AES-GCM 密文)}, 解密时按版本前缀匹配对应密钥 keys: + # 32 位 AES 密钥(必须正好 32 个字符); 轮换时生成新密钥置于列表首位并使用更大的版本号 - key: z0Vd8jDKB80pA6OOptGLO+qDVvWboEko + # 密钥版本号(整数, 列表内唯一) version: 1 + # 沙箱环境全局开关: false=生产模式(本机开发默认), true=沙箱模式 + # 关闭后不可切换到沙箱; 若启动时已有产品处于沙箱, 将自动重置为生产环境 + sandbox-enabled: false # 通道适配子应用配置 # 按支付通道拆分的独立部署子服务, 主服务通过 HTTP 调用对应子服务完成通道对接。 # 拆分目的: 通道 SDK 依赖隔离(避免冲突) + 独立升级 + 弹性伸缩 diff --git a/pom.xml b/pom.xml index 8157c380b..fa0f74725 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,8 @@ 3.3.7 4.8.4.B 0.24.0 + + 4.40.272.ALL