refactor: 微信通道按 ISV/直连拆分重构,调整支付宝通道商户

- 微信:新增 WechatDirectChannelMerchant / WechatIsvChannelMerchant 直连与服务商通道商户,目录按 direct/isv 重组,枚举移至 code 包
This commit is contained in:
DaxPay Dev
2026-06-14 21:48:28 +08:00
parent bd52f5df50
commit 4319fedece
73 changed files with 888 additions and 192 deletions

View File

@@ -0,0 +1,235 @@
-- =====================================================================
-- 微信服务商相关表 (DROP + CREATE 重建)
-- 对应实体:
-- org.dromara.daxpay.channel.wechat.entity.app.WechatIsvApp
-- org.dromara.daxpay.channel.wechat.entity.config.WechatIsvKeyConfig
-- org.dromara.daxpay.channel.wechat.entity.config.WechatIsvAppAuthConfig
-- org.dromara.daxpay.channel.wechat.entity.mch.WechatIsvChannelMerchant
-- 执行方式: 手动执行(业务表 DDL 不入库, 由开发者按需在数据库执行)
-- 注意: 加密字段(DataEncryptTypeHandler)在数据库层均为普通 text, 加解密在应用层完成
-- =====================================================================
-- =========================
-- 1. 微信服务商应用 wechat_isv_app
-- =========================
DROP TABLE IF EXISTS "public"."wechat_isv_app";
CREATE TABLE "public"."wechat_isv_app" (
"id" int8 NOT NULL,
"app_name" varchar(64),
"app_type" varchar(32),
"wx_app_id" varchar(64),
"creator" int8,
"create_time" timestamptz(6),
"last_modifier" int8,
"last_modified_time" timestamptz(6),
"version" int4 DEFAULT 0 NOT NULL,
"deleted" bool DEFAULT false NOT NULL
);
COMMENT ON TABLE "public"."wechat_isv_app" IS '微信服务商应用';
COMMENT ON COLUMN "public"."wechat_isv_app"."id" IS '主键';
COMMENT ON COLUMN "public"."wechat_isv_app"."app_name" IS '应用名称';
COMMENT ON COLUMN "public"."wechat_isv_app"."app_type" IS '应用类型';
COMMENT ON COLUMN "public"."wechat_isv_app"."wx_app_id" IS '微信应用AppId';
COMMENT ON COLUMN "public"."wechat_isv_app"."creator" IS '创建人';
COMMENT ON COLUMN "public"."wechat_isv_app"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."wechat_isv_app"."last_modifier" IS '最后修改人';
COMMENT ON COLUMN "public"."wechat_isv_app"."last_modified_time" IS '最后修改时间';
COMMENT ON COLUMN "public"."wechat_isv_app"."version" IS '乐观锁版本号';
COMMENT ON COLUMN "public"."wechat_isv_app"."deleted" IS '逻辑删除标志';
ALTER TABLE "public"."wechat_isv_app"
ADD CONSTRAINT "pk_wechat_isv_app" PRIMARY KEY ("id");
CREATE UNIQUE INDEX IF NOT EXISTS "uk_wechat_isv_app_wx_app_id"
ON "public"."wechat_isv_app" ("wx_app_id")
WHERE "deleted" = false;
-- =========================
-- 2. 微信服务商密钥配置 wechat_isv_key_config
-- =========================
DROP TABLE IF EXISTS "public"."wechat_isv_key_config";
CREATE TABLE "public"."wechat_isv_key_config" (
"id" int8 NOT NULL,
"product" varchar(32),
"wx_mch_id" varchar(32),
"api_key_v3" text,
"public_key" text,
"public_key_id" varchar(64),
"private_key" text,
"private_cert" text,
"cert_serial_no" varchar(128),
"creator" int8,
"create_time" timestamptz(6),
"last_modifier" int8,
"last_modified_time" timestamptz(6),
"version" int4 DEFAULT 0 NOT NULL,
"deleted" bool DEFAULT false NOT NULL
);
COMMENT ON TABLE "public"."wechat_isv_key_config" IS '微信服务商密钥配置';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."id" IS '主键';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."product" IS '产品编码';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."wx_mch_id" IS '微信服务商商户号';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."api_key_v3" IS 'APIv3密钥(加密存储)';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."public_key" IS '支付公钥(加密存储)';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."public_key_id" IS '支付公钥ID';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."private_key" IS 'apiclient_key证书(加密存储)';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."private_cert" IS 'apiclient_cert证书(加密存储)';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."cert_serial_no" IS '证书序列号';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."creator" IS '创建人';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."last_modifier" IS '最后修改人';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."last_modified_time" IS '最后修改时间';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."version" IS '乐观锁版本号';
COMMENT ON COLUMN "public"."wechat_isv_key_config"."deleted" IS '逻辑删除标志';
ALTER TABLE "public"."wechat_isv_key_config"
ADD CONSTRAINT "pk_wechat_isv_key_config" PRIMARY KEY ("id");
-- 密钥配置按产品全局唯一(平台为唯一服务商)
CREATE UNIQUE INDEX IF NOT EXISTS "uk_wechat_isv_key_config_product"
ON "public"."wechat_isv_key_config" ("product")
WHERE "deleted" = false;
-- =========================
-- 3. 微信服务商应用授权认证配置 wechat_isv_app_auth_config
-- =========================
DROP TABLE IF EXISTS "public"."wechat_isv_app_auth_config";
CREATE TABLE "public"."wechat_isv_app_auth_config" (
"id" int8 NOT NULL,
"app_id" int8,
"app_secret" text,
"auth_callback_url" varchar(255),
"creator" int8,
"create_time" timestamptz(6),
"last_modifier" int8,
"last_modified_time" timestamptz(6),
"version" int4 DEFAULT 0 NOT NULL,
"deleted" bool DEFAULT false NOT NULL
);
COMMENT ON TABLE "public"."wechat_isv_app_auth_config" IS '微信服务商应用授权认证配置';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."id" IS '主键';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."app_id" IS '微信服务商应用ID(指向 wechat_isv_app.id)';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."app_secret" IS '应用密钥(加密存储)';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."auth_callback_url" IS '授权回调地址';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."creator" IS '创建人';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."last_modifier" IS '最后修改人';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."last_modified_time" IS '最后修改时间';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."version" IS '乐观锁版本号';
COMMENT ON COLUMN "public"."wechat_isv_app_auth_config"."deleted" IS '逻辑删除标志';
ALTER TABLE "public"."wechat_isv_app_auth_config"
ADD CONSTRAINT "pk_wechat_isv_app_auth_config" PRIMARY KEY ("id");
-- 一个应用只有一条授权认证配置
CREATE UNIQUE INDEX IF NOT EXISTS "uk_wechat_isv_app_auth_config_app_id"
ON "public"."wechat_isv_app_auth_config" ("app_id")
WHERE "deleted" = false;
-- =========================
-- 4. 微信服务商通道商户绑定 mch_wechat_isv_channel_merchant
-- 微信特约商户关联到服务商本身(服务商密钥全局唯一), 不挂靠具体服务商应用
-- =========================
DROP TABLE IF EXISTS "public"."mch_wechat_isv_channel_merchant";
CREATE TABLE "public"."mch_wechat_isv_channel_merchant" (
"id" int8 NOT NULL,
"mch_no" varchar(32) NOT NULL,
"channel_mch_no" varchar(64) NOT NULL,
"product" varchar(32) NOT NULL,
"sub_mch_id" varchar(64) NOT NULL,
"creator" int8,
"create_time" timestamptz(6),
"last_modifier" int8,
"last_modified_time" timestamptz(6),
"version" int4 DEFAULT 0 NOT NULL,
"deleted" bool DEFAULT false NOT NULL
);
COMMENT ON TABLE "public"."mch_wechat_isv_channel_merchant" IS '微信服务商通道商户绑定';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."id" IS '主键';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."mch_no" IS '商户号';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."channel_mch_no" IS '通道商户号(WISV+雪花)';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."product" IS '所属支付产品';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."sub_mch_id" IS '微信特约商户号/二级商户号(V3 sub_mchid)';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."creator" IS '创建人';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."last_modifier" IS '最后修改人';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."last_modified_time" IS '最后修改时间';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."version" IS '乐观锁版本号';
COMMENT ON COLUMN "public"."mch_wechat_isv_channel_merchant"."deleted" IS '逻辑删除标志';
ALTER TABLE "public"."mch_wechat_isv_channel_merchant"
ADD CONSTRAINT "pk_mch_wechat_isv_channel_merchant" PRIMARY KEY ("id");
-- 唯一索引: 同一商户下特约商户号不重复(逻辑删除场景排除已删除记录)
CREATE UNIQUE INDEX IF NOT EXISTS "uk_wechat_isv_cm_mchno_submch"
ON "public"."mch_wechat_isv_channel_merchant" ("mch_no", "sub_mch_id")
WHERE "deleted" = false;
-- 普通索引: 按通道商户号查询
CREATE INDEX IF NOT EXISTS "idx_wechat_isv_cm_channel_mch_no"
ON "public"."mch_wechat_isv_channel_merchant" ("channel_mch_no");
-- 普通索引: 按商户号查询
CREATE INDEX IF NOT EXISTS "idx_wechat_isv_cm_mch_no"
ON "public"."mch_wechat_isv_channel_merchant" ("mch_no");
-- =========================
-- 5. 微信直连通道商户绑定 mch_wechat_direct_channel_merchant
-- 一个微信商户号(wxMchId)对应一个 channelMchNo, 商户的多个应用共享此绑定
-- =========================
DROP TABLE IF EXISTS "public"."mch_wechat_direct_channel_merchant";
CREATE TABLE "public"."mch_wechat_direct_channel_merchant" (
"id" int8 NOT NULL,
"mch_no" varchar(32) NOT NULL,
"channel_mch_no" varchar(64) NOT NULL,
"product" varchar(32) NOT NULL,
"wx_mch_id" varchar(32) NOT NULL,
"creator" int8,
"create_time" timestamptz(6),
"last_modifier" int8,
"last_modified_time" timestamptz(6),
"version" int4 DEFAULT 0 NOT NULL,
"deleted" bool DEFAULT false NOT NULL
);
COMMENT ON TABLE "public"."mch_wechat_direct_channel_merchant" IS '微信直连通道商户绑定';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."id" IS '主键';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."mch_no" IS '商户号';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."channel_mch_no" IS '通道商户号(系统生成雪花号)';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."product" IS '所属支付产品';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."wx_mch_id" IS '微信直连商户号';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."creator" IS '创建人';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."last_modifier" IS '最后修改人';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."last_modified_time" IS '最后修改时间';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."version" IS '乐观锁版本号';
COMMENT ON COLUMN "public"."mch_wechat_direct_channel_merchant"."deleted" IS '逻辑删除标志';
ALTER TABLE "public"."mch_wechat_direct_channel_merchant"
ADD CONSTRAINT "pk_mch_wechat_direct_channel_merchant" PRIMARY KEY ("id");
-- 唯一索引: 同一商户下微信商户号不重复(逻辑删除场景排除已删除记录)
CREATE UNIQUE INDEX IF NOT EXISTS "uk_wechat_direct_cm_mchno_wxmchid"
ON "public"."mch_wechat_direct_channel_merchant" ("mch_no", "wx_mch_id")
WHERE "deleted" = false;
-- 普通索引: 按通道商户号查询
CREATE INDEX IF NOT EXISTS "idx_wechat_direct_cm_channel_mch_no"
ON "public"."mch_wechat_direct_channel_merchant" ("channel_mch_no");
-- 普通索引: 按商户号查询
CREATE INDEX IF NOT EXISTS "idx_wechat_direct_cm_mch_no"
ON "public"."mch_wechat_direct_channel_merchant" ("mch_no");

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.direct;
import org.dromara.daxpay.channel.alipay.entity.direct.AlipayDirectAppAuthConfig;
import org.dromara.daxpay.channel.alipay.param.direct.AlipayDirectAppAuthConfigParam;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.direct;
import org.dromara.daxpay.channel.alipay.entity.direct.AlipayDirectApp;
import org.dromara.daxpay.channel.alipay.param.direct.AlipayDirectAppParam;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.direct;
import org.dromara.daxpay.channel.alipay.entity.direct.AlipayDirectAppKeyConfig;
import org.dromara.daxpay.channel.alipay.param.direct.AlipayDirectAppKeyConfigParam;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.direct;
import org.dromara.daxpay.channel.alipay.entity.direct.AlipayDirectChannelMerchant;
import org.dromara.daxpay.channel.alipay.result.direct.AlipayDirectChannelMerchantResult;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.isv;
import org.dromara.daxpay.channel.alipay.entity.isv.AlipayIsvAppAuthConfig;
import org.dromara.daxpay.channel.alipay.param.isv.AlipayIsvAppAuthConfigParam;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.isv;
import org.dromara.daxpay.channel.alipay.entity.isv.AlipayIsvApp;
import org.dromara.daxpay.channel.alipay.param.isv.AlipayIsvAppParam;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.isv;
import org.dromara.daxpay.channel.alipay.entity.isv.AlipayIsvAppKeyConfig;
import org.dromara.daxpay.channel.alipay.param.isv.AlipayIsvAppKeyConfigParam;

View File

@@ -1,9 +1,8 @@
package org.dromara.daxpay.channel.alipay.convert;
package org.dromara.daxpay.channel.alipay.convert.isv;
import org.dromara.daxpay.channel.alipay.entity.isv.AlipayIsvChannelMerchant;
import org.dromara.daxpay.channel.alipay.result.isv.AlipayIsvChannelMerchantResult;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/// # 支付宝服务商通道商户绑定转换
@@ -13,7 +12,5 @@ public interface AlipayIsvChannelMerchantConvert {
AlipayIsvChannelMerchantConvert CONVERT = Mappers.getMapper(AlipayIsvChannelMerchantConvert.class);
/// 实体 appId(Long) 映射到结果 isvAppId(Long), 避免与父类 MchTradeBaseResult.appId(String) 冲突
@Mapping(source = "appId", target = "isvAppId")
AlipayIsvChannelMerchantResult toResult(AlipayIsvChannelMerchant entity);
}

View File

@@ -10,9 +10,9 @@ import org.springframework.stereotype.Repository;
public class AlipayIsvChannelMerchantManager extends BaseManager<AlipayIsvChannelMerchantMapper, AlipayIsvChannelMerchant> {
/// 校验同一服务商应用下是否已绑定该子商户
public boolean existsByAppIdAndAlipayUserId(Long appId, String alipayUserId) {
public boolean existsByIsvAppIdAndAlipayUserId(Long isvAppId, String alipayUserId) {
return lambdaQuery()
.eq(AlipayIsvChannelMerchant::getAppId, appId)
.eq(AlipayIsvChannelMerchant::getIsvAppId, isvAppId)
.eq(AlipayIsvChannelMerchant::getAlipayUserId, alipayUserId)
.exists();
}

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.direct;
import org.dromara.daxpay.channel.alipay.convert.AlipayDirectAppConvert;
import org.dromara.daxpay.channel.alipay.convert.direct.AlipayDirectAppConvert;
import org.dromara.daxpay.channel.alipay.result.direct.AlipayDirectAppResult;
import org.dromara.daxpay.payment.common.entity.merchant.MchBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.direct;
import org.dromara.daxpay.channel.alipay.convert.AlipayDirectAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.direct.AlipayDirectAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.result.direct.AlipayDirectAppAuthConfigResult;
import org.dromara.daxpay.payment.common.entity.merchant.MchBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.direct;
import org.dromara.daxpay.channel.alipay.convert.AlipayDirectAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.direct.AlipayDirectAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.result.direct.AlipayDirectAppKeyConfigResult;
import org.dromara.daxpay.payment.common.entity.merchant.MchBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.direct;
import org.dromara.daxpay.channel.alipay.convert.AlipayDirectChannelMerchantConvert;
import org.dromara.daxpay.channel.alipay.convert.direct.AlipayDirectChannelMerchantConvert;
import org.dromara.daxpay.channel.alipay.result.direct.AlipayDirectChannelMerchantResult;
import org.dromara.daxpay.payment.common.entity.merchant.MchBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.isv;
import org.dromara.daxpay.channel.alipay.convert.AlipayIsvAppConvert;
import org.dromara.daxpay.channel.alipay.convert.isv.AlipayIsvAppConvert;
import org.dromara.daxpay.channel.alipay.result.isv.AlipayIsvAppResult;
import org.dromara.daxpay.platform.common.mybatisplus.base.MpBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.isv;
import org.dromara.daxpay.channel.alipay.convert.AlipayIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.isv.AlipayIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.result.isv.AlipayIsvAppAuthConfigResult;
import org.dromara.daxpay.platform.common.mybatisplus.base.MpBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.isv;
import org.dromara.daxpay.channel.alipay.convert.AlipayIsvAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.isv.AlipayIsvAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.result.isv.AlipayIsvAppKeyConfigResult;
import org.dromara.daxpay.platform.common.mybatisplus.base.MpBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.entity.isv;
import org.dromara.daxpay.channel.alipay.convert.AlipayIsvChannelMerchantConvert;
import org.dromara.daxpay.channel.alipay.convert.isv.AlipayIsvChannelMerchantConvert;
import org.dromara.daxpay.channel.alipay.result.isv.AlipayIsvChannelMerchantResult;
import org.dromara.daxpay.payment.common.entity.merchant.MchBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;
@@ -28,7 +28,7 @@ public class AlipayIsvChannelMerchant extends MchBaseEntity implements ToResult<
private String product;
/// 关联服务商应用ID(系统主键, 指向 alipay_isv_app.id)
private Long appId;
private Long isvAppId;
/// 子商户支付宝识别码(2088开头的16位数字)
private String alipayUserId;

View File

@@ -31,7 +31,7 @@ public class AlipayIsvChannelMerchantCreateParam {
/// 服务商应用ID(系统主键, 指向 alipay_isv_app.id)
@Schema(description = "服务商应用ID")
@NotNull(message = "{validation.field.appId.notNull}")
private Long appId;
private Long isvAppId;
/// 子商户支付宝用户ID(2088开头)
@Schema(description = "子商户支付宝用户ID(2088开头)")

View File

@@ -22,7 +22,6 @@ public class AlipayIsvChannelMerchantResult extends MchTradeBaseResult {
@Schema(description = "所属支付产品")
private String product;
/// 注意: 此处用 isvAppId(Long) 而非 appId, 避免与父类 MchTradeBaseResult.appId(String) 字段冲突
@Schema(description = "关联服务商应用ID(系统主键)")
private Long isvAppId;

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.alipay.service.direct;
import org.dromara.daxpay.channel.alipay.code.AlipayCode;
import org.dromara.daxpay.channel.alipay.convert.AlipayDirectAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.direct.AlipayDirectAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.dao.direct.AlipayDirectAppManager;
import org.dromara.daxpay.channel.alipay.dao.direct.AlipayDirectAppAuthConfigManager;
import org.dromara.daxpay.channel.alipay.entity.direct.AlipayDirectApp;

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.alipay.service.direct;
import org.dromara.daxpay.channel.alipay.code.AlipayCode;
import org.dromara.daxpay.channel.alipay.convert.AlipayDirectAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.direct.AlipayDirectAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.dao.direct.AlipayDirectAppManager;
import org.dromara.daxpay.channel.alipay.dao.direct.AlipayDirectAppKeyConfigManager;
import org.dromara.daxpay.channel.alipay.entity.direct.AlipayDirectApp;
@@ -54,7 +54,7 @@ public class AlipayDirectAppKeyConfigService {
if (existing.isPresent()) {
AlipayDirectAppKeyConfig config = existing.get();
config.setAuthType(param.getAuthType());
this.mergeSensitiveFields(config, param);
AlipayDirectAppKeyConfigConvert.CONVERT.copy(param, config);
alipayDirectAppKeyConfigManager.updateById(config);
return;
}
@@ -71,28 +71,6 @@ public class AlipayDirectAppKeyConfigService {
alipayDirectAppKeyConfigManager.deleteByAppId(appId);
}
/// 合并敏感字段,空值表示不更新
private void mergeSensitiveFields(AlipayDirectAppKeyConfig config, AlipayDirectAppKeyConfigParam param) {
if (StrUtil.isNotBlank(param.getAlipayPublicKey())) {
config.setAlipayPublicKey(param.getAlipayPublicKey());
}
if (StrUtil.isNotBlank(param.getPrivateKey())) {
config.setPrivateKey(param.getPrivateKey());
}
if (StrUtil.isNotBlank(param.getAppCert())) {
config.setAppCert(param.getAppCert());
}
if (StrUtil.isNotBlank(param.getAlipayCert())) {
config.setAlipayCert(param.getAlipayCert());
}
if (StrUtil.isNotBlank(param.getAlipayRootCert())) {
config.setAlipayRootCert(param.getAlipayRootCert());
}
if (StrUtil.isNotBlank(param.getSecretKey())) {
config.setSecretKey(param.getSecretKey());
}
}
/// 新增时的条件校验
private void validateForCreate(AlipayDirectAppKeyConfigParam param) {
if (StrUtil.isBlank(param.getPrivateKey())) {

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.service.direct;
import org.dromara.daxpay.channel.alipay.convert.AlipayDirectAppConvert;
import org.dromara.daxpay.channel.alipay.convert.direct.AlipayDirectAppConvert;
import org.dromara.daxpay.channel.alipay.dao.direct.AlipayDirectAppManager;
import org.dromara.daxpay.channel.alipay.entity.direct.AlipayDirectApp;
import org.dromara.daxpay.channel.alipay.param.direct.AlipayDirectAppParam;

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.alipay.service.isv;
import org.dromara.daxpay.channel.alipay.code.AlipayCode;
import org.dromara.daxpay.channel.alipay.convert.AlipayIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.isv.AlipayIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.alipay.dao.isv.AlipayIsvAppManager;
import org.dromara.daxpay.channel.alipay.dao.isv.AlipayIsvAppAuthConfigManager;
import org.dromara.daxpay.channel.alipay.entity.isv.AlipayIsvAppAuthConfig;

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.alipay.service.isv;
import org.dromara.daxpay.channel.alipay.code.AlipayCode;
import org.dromara.daxpay.channel.alipay.convert.AlipayIsvAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.convert.isv.AlipayIsvAppKeyConfigConvert;
import org.dromara.daxpay.channel.alipay.dao.isv.AlipayIsvAppManager;
import org.dromara.daxpay.channel.alipay.dao.isv.AlipayIsvAppKeyConfigManager;
import org.dromara.daxpay.channel.alipay.entity.isv.AlipayIsvAppKeyConfig;
@@ -48,7 +48,7 @@ public class AlipayIsvAppKeyConfigService {
if (existing.isPresent()) {
AlipayIsvAppKeyConfig config = existing.get();
config.setAuthType(param.getAuthType());
this.mergeSensitiveFields(config, param);
AlipayIsvAppKeyConfigConvert.CONVERT.copy(param, config);
alipayIsvAppKeyConfigManager.updateById(config);
return;
}
@@ -63,28 +63,6 @@ public class AlipayIsvAppKeyConfigService {
alipayIsvAppKeyConfigManager.deleteByAppId(appId);
}
/// 合并敏感字段,空值表示不更新
private void mergeSensitiveFields(AlipayIsvAppKeyConfig config, AlipayIsvAppKeyConfigParam param) {
if (StrUtil.isNotBlank(param.getAlipayPublicKey())) {
config.setAlipayPublicKey(param.getAlipayPublicKey());
}
if (StrUtil.isNotBlank(param.getPrivateKey())) {
config.setPrivateKey(param.getPrivateKey());
}
if (StrUtil.isNotBlank(param.getAppCert())) {
config.setAppCert(param.getAppCert());
}
if (StrUtil.isNotBlank(param.getAlipayCert())) {
config.setAlipayCert(param.getAlipayCert());
}
if (StrUtil.isNotBlank(param.getAlipayRootCert())) {
config.setAlipayRootCert(param.getAlipayRootCert());
}
if (StrUtil.isNotBlank(param.getSecretKey())) {
config.setSecretKey(param.getSecretKey());
}
}
/// 新增时的条件校验
private void validateForCreate(AlipayIsvAppKeyConfigParam param) {
if (StrUtil.isBlank(param.getPrivateKey())) {

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.alipay.service.isv;
import org.dromara.daxpay.channel.alipay.convert.AlipayIsvAppConvert;
import org.dromara.daxpay.channel.alipay.convert.isv.AlipayIsvAppConvert;
import org.dromara.daxpay.channel.alipay.dao.isv.AlipayIsvAppManager;
import org.dromara.daxpay.channel.alipay.entity.isv.AlipayIsvApp;
import org.dromara.daxpay.channel.alipay.param.isv.AlipayIsvAppParam;

View File

@@ -34,12 +34,12 @@ public class AlipayIsvChannelMerchantService {
/// 创建支付宝服务商通道商户
@Transactional(rollbackFor = Exception.class)
public void create(AlipayIsvChannelMerchantCreateParam param) {
// 校验服务商应用存在(用 appId 系统主键查询)
AlipayIsvApp isvApp = alipayIsvAppManager.findById(param.getAppId())
// 校验服务商应用存在(用 isvAppId 系统主键查询)
AlipayIsvApp isvApp = alipayIsvAppManager.findById(param.getIsvAppId())
.orElseThrow(() -> new DataNotExistException("error.channel.alipay.appNotFound"));
// 校验同一应用下子商户号不重复
if (alipayIsvChannelMerchantManager.existsByAppIdAndAlipayUserId(
param.getAppId(), param.getAlipayUserId())) {
if (alipayIsvChannelMerchantManager.existsByIsvAppIdAndAlipayUserId(
param.getIsvAppId(), param.getAlipayUserId())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.alipay.subMerchantDuplicate");
}
// 生成通道商户号:前缀 AISV + 雪花ID(无分隔符, 符合 TradeNoGenerateUtil 约定)
@@ -58,7 +58,7 @@ public class AlipayIsvChannelMerchantService {
entity.setMchNo(param.getMchNo());
entity.setChannelMchNo(channelMchNo);
entity.setProduct(param.getProduct());
entity.setAppId(isvApp.getId());
entity.setIsvAppId(isvApp.getId());
entity.setAlipayUserId(param.getAlipayUserId());
entity.setAppAuthToken(param.getAppAuthToken());
alipayIsvChannelMerchantManager.save(entity);

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.enums;
package org.dromara.daxpay.channel.wechat.code;
import org.dromara.daxpay.platform.core.i18n.I18nSupport;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.enums;
package org.dromara.daxpay.channel.wechat.code;
import org.dromara.daxpay.platform.core.i18n.I18nSupport;
import lombok.Getter;

View File

@@ -0,0 +1,47 @@
package org.dromara.daxpay.channel.wechat.controller.direct;
import org.dromara.daxpay.platform.core.annotation.PermCode;
import org.dromara.daxpay.platform.core.rest.Res;
import org.dromara.daxpay.platform.core.rest.result.Result;
import org.dromara.daxpay.channel.wechat.param.direct.WechatDirectChannelMerchantCreateParam;
import org.dromara.daxpay.channel.wechat.result.direct.WechatDirectChannelMerchantResult;
import org.dromara.daxpay.channel.wechat.service.direct.WechatDirectChannelMerchantService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/// # 微信直连通道商户管理
///
@PermCode(menuCode = "payment:merchant:channelMerchant")
@Validated
@Tag(name = "微信直连通道商户管理")
@RestController
@RequestMapping("/admin/wechat/direct-channel-merchant")
@RequiredArgsConstructor
public class WechatDirectChannelMerchantController {
private final WechatDirectChannelMerchantService wechatDirectChannelMerchantService;
@PermCode(code = "view", nameCn = "商户通道商户查看", nameEn = "Merchant Channel Merchant View")
@Operation(summary = "根据通道商户号查询微信直连通道商户配置")
@GetMapping("/find-by-channel-mch-no")
public Result<WechatDirectChannelMerchantResult> findByChannelMchNo(
@NotBlank(message = "{validation.field.channelMerchantNo.notBlank}") String channelMchNo) {
return Res.ok(wechatDirectChannelMerchantService.findByChannelMchNo(channelMchNo));
}
@PermCode(code = "add", nameCn = "商户通道商户新增", nameEn = "Merchant Channel Merchant Add")
@Operation(summary = "创建微信直连通道商户")
@PostMapping("/create")
public Result<Void> create(@RequestBody @Validated WechatDirectChannelMerchantCreateParam param) {
wechatDirectChannelMerchantService.create(param);
return Res.ok();
}
}

View File

@@ -1,16 +1,16 @@
package org.dromara.daxpay.channel.wechat.controller.app;
package org.dromara.daxpay.channel.wechat.controller.isv;
import org.dromara.daxpay.platform.core.annotation.PermCode;
import org.dromara.daxpay.platform.core.rest.Res;
import org.dromara.daxpay.platform.core.rest.result.Result;
import org.dromara.daxpay.platform.core.util.ValidationUtil;
import org.dromara.daxpay.platform.core.validation.ValidationGroup;
import org.dromara.daxpay.channel.wechat.param.app.WechatIsvAppParam;
import org.dromara.daxpay.channel.wechat.param.config.WechatIsvAppAuthConfigParam;
import org.dromara.daxpay.channel.wechat.result.app.WechatIsvAppResult;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvAppAuthConfigResult;
import org.dromara.daxpay.channel.wechat.service.app.WechatIsvAppService;
import org.dromara.daxpay.channel.wechat.service.config.WechatIsvAppAuthConfigService;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvAppParam;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvAppAuthConfigParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppResult;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppAuthConfigResult;
import org.dromara.daxpay.channel.wechat.service.isv.WechatIsvAppService;
import org.dromara.daxpay.channel.wechat.service.isv.WechatIsvAppAuthConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;

View File

@@ -0,0 +1,47 @@
package org.dromara.daxpay.channel.wechat.controller.isv;
import org.dromara.daxpay.platform.core.annotation.PermCode;
import org.dromara.daxpay.platform.core.rest.Res;
import org.dromara.daxpay.platform.core.rest.result.Result;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvChannelMerchantCreateParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvChannelMerchantResult;
import org.dromara.daxpay.channel.wechat.service.isv.WechatIsvChannelMerchantService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/// # 微信服务商通道商户管理
///
@PermCode(menuCode = "payment:merchant:channelMerchant")
@Validated
@Tag(name = "微信服务商通道商户管理")
@RestController
@RequestMapping("/admin/wechat/isv-channel-merchant")
@RequiredArgsConstructor
public class WechatIsvChannelMerchantController {
private final WechatIsvChannelMerchantService wechatIsvChannelMerchantService;
@PermCode(code = "view", nameCn = "商户通道商户查看", nameEn = "Merchant Channel Merchant View")
@Operation(summary = "根据通道商户号查询微信服务商通道商户配置")
@GetMapping("/find-by-channel-mch-no")
public Result<WechatIsvChannelMerchantResult> findByChannelMchNo(
@NotBlank(message = "{validation.field.channelMerchantNo.notBlank}") String channelMchNo) {
return Res.ok(wechatIsvChannelMerchantService.findByChannelMchNo(channelMchNo));
}
@PermCode(code = "add", nameCn = "商户通道商户新增", nameEn = "Merchant Channel Merchant Add")
@Operation(summary = "创建微信服务商通道商户")
@PostMapping("/create")
public Result<Void> create(@RequestBody @Validated WechatIsvChannelMerchantCreateParam param) {
wechatIsvChannelMerchantService.create(param);
return Res.ok();
}
}

View File

@@ -1,11 +1,11 @@
package org.dromara.daxpay.channel.wechat.controller.config;
package org.dromara.daxpay.channel.wechat.controller.isv;
import org.dromara.daxpay.platform.core.annotation.PermCode;
import org.dromara.daxpay.platform.core.rest.Res;
import org.dromara.daxpay.platform.core.rest.result.Result;
import org.dromara.daxpay.channel.wechat.param.config.WechatIsvKeyConfigParam;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvKeyConfigResult;
import org.dromara.daxpay.channel.wechat.service.config.WechatIsvKeyConfigService;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvKeyConfigParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvKeyConfigResult;
import org.dromara.daxpay.channel.wechat.service.isv.WechatIsvKeyConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;

View File

@@ -0,0 +1,16 @@
package org.dromara.daxpay.channel.wechat.convert.direct;
import org.dromara.daxpay.channel.wechat.entity.direct.WechatDirectChannelMerchant;
import org.dromara.daxpay.channel.wechat.result.direct.WechatDirectChannelMerchantResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/// # 微信直连通道商户绑定转换
///
@Mapper
public interface WechatDirectChannelMerchantConvert {
WechatDirectChannelMerchantConvert CONVERT = Mappers.getMapper(WechatDirectChannelMerchantConvert.class);
WechatDirectChannelMerchantResult toResult(WechatDirectChannelMerchant entity);
}

View File

@@ -1,8 +1,8 @@
package org.dromara.daxpay.channel.wechat.convert;
package org.dromara.daxpay.channel.wechat.convert.isv;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvAppAuthConfig;
import org.dromara.daxpay.channel.wechat.param.config.WechatIsvAppAuthConfigParam;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvAppAuthConfigResult;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvAppAuthConfig;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvAppAuthConfigParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppAuthConfigResult;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;

View File

@@ -1,8 +1,8 @@
package org.dromara.daxpay.channel.wechat.convert;
package org.dromara.daxpay.channel.wechat.convert.isv;
import org.dromara.daxpay.channel.wechat.entity.app.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.param.app.WechatIsvAppParam;
import org.dromara.daxpay.channel.wechat.result.app.WechatIsvAppResult;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvAppParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppResult;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;

View File

@@ -0,0 +1,16 @@
package org.dromara.daxpay.channel.wechat.convert.isv;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvChannelMerchant;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvChannelMerchantResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/// # 微信服务商通道商户绑定转换
///
@Mapper
public interface WechatIsvChannelMerchantConvert {
WechatIsvChannelMerchantConvert CONVERT = Mappers.getMapper(WechatIsvChannelMerchantConvert.class);
WechatIsvChannelMerchantResult toResult(WechatIsvChannelMerchant entity);
}

View File

@@ -1,8 +1,8 @@
package org.dromara.daxpay.channel.wechat.convert;
package org.dromara.daxpay.channel.wechat.convert.isv;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvKeyConfig;
import org.dromara.daxpay.channel.wechat.param.config.WechatIsvKeyConfigParam;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvKeyConfigResult;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvKeyConfig;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvKeyConfigParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvKeyConfigResult;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;

View File

@@ -0,0 +1,19 @@
package org.dromara.daxpay.channel.wechat.dao.direct;
import org.dromara.daxpay.channel.wechat.entity.direct.WechatDirectChannelMerchant;
import org.dromara.daxpay.platform.common.mybatisplus.impl.BaseManager;
import org.springframework.stereotype.Repository;
/// # 微信直连通道商户绑定
///
@Repository
public class WechatDirectChannelMerchantManager extends BaseManager<WechatDirectChannelMerchantMapper, WechatDirectChannelMerchant> {
/// 校验同一商户下微信直连商户号不重复
public boolean existsByMchNoAndWxMchId(String mchNo, String wxMchId) {
return lambdaQuery()
.eq(WechatDirectChannelMerchant::getMchNo, mchNo)
.eq(WechatDirectChannelMerchant::getWxMchId, wxMchId)
.exists();
}
}

View File

@@ -0,0 +1,13 @@
package org.dromara.daxpay.channel.wechat.dao.direct;
import org.dromara.daxpay.channel.wechat.entity.direct.WechatDirectChannelMerchant;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
/// # 微信直连通道商户绑定
///
/// 微信直连通道商户 MyBatis-Plus Mapper继承 MPJBaseMapper 支持多表联查。
///
@Mapper
public interface WechatDirectChannelMerchantMapper extends MPJBaseMapper<WechatDirectChannelMerchant> {
}

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.wechat.dao.config;
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.platform.common.mybatisplus.impl.BaseManager;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvAppAuthConfig;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvAppAuthConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.wechat.dao.config;
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvAppAuthConfig;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvAppAuthConfig;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.wechat.dao.app;
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.platform.common.mybatisplus.impl.BaseManager;
import org.dromara.daxpay.channel.wechat.entity.app.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvApp;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.wechat.dao.app;
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.channel.wechat.entity.app.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvApp;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;

View File

@@ -0,0 +1,19 @@
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvChannelMerchant;
import org.dromara.daxpay.platform.common.mybatisplus.impl.BaseManager;
import org.springframework.stereotype.Repository;
/// # 微信服务商通道商户绑定
///
@Repository
public class WechatIsvChannelMerchantManager extends BaseManager<WechatIsvChannelMerchantMapper, WechatIsvChannelMerchant> {
/// 校验同一商户下特约商户号不重复
public boolean existsByMchNoAndSubMchId(String mchNo, String subMchId) {
return lambdaQuery()
.eq(WechatIsvChannelMerchant::getMchNo, mchNo)
.eq(WechatIsvChannelMerchant::getSubMchId, subMchId)
.exists();
}
}

View File

@@ -0,0 +1,13 @@
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvChannelMerchant;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
/// # 微信服务商通道商户绑定
///
/// 微信服务商通道商户 MyBatis-Plus Mapper继承 MPJBaseMapper 支持多表联查。
///
@Mapper
public interface WechatIsvChannelMerchantMapper extends MPJBaseMapper<WechatIsvChannelMerchant> {
}

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.wechat.dao.config;
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.platform.common.mybatisplus.impl.BaseManager;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvKeyConfig;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvKeyConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

View File

@@ -1,6 +1,6 @@
package org.dromara.daxpay.channel.wechat.dao.config;
package org.dromara.daxpay.channel.wechat.dao.isv;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvKeyConfig;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvKeyConfig;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;

View File

@@ -0,0 +1,37 @@
package org.dromara.daxpay.channel.wechat.entity.direct;
import org.dromara.daxpay.channel.wechat.convert.direct.WechatDirectChannelMerchantConvert;
import org.dromara.daxpay.channel.wechat.result.direct.WechatDirectChannelMerchantResult;
import org.dromara.daxpay.payment.common.entity.merchant.MchBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/// # 微信直连通道商户绑定
///
/// 一个微信商户号(wxMchId)对应一个 channelMchNo, 商户的多个应用共享此绑定。
///
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@TableName(value = "mch_wechat_direct_channel_merchant", autoResultMap = true)
public class WechatDirectChannelMerchant extends MchBaseEntity implements ToResult<WechatDirectChannelMerchantResult> {
/// 通道商户号(系统生成雪花号)
private String channelMchNo;
/// 所属支付产品
/// @see org.dromara.daxpay.platform.core.enums.pay.channel.ProductEnum
private String product;
/// 微信直连商户号
private String wxMchId;
/// 转换
@Override
public WechatDirectChannelMerchantResult toResult() {
return WechatDirectChannelMerchantConvert.CONVERT.toResult(this);
}
}

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.wechat.entity.app;
package org.dromara.daxpay.channel.wechat.entity.isv;
import org.dromara.daxpay.channel.wechat.convert.WechatIsvAppConvert;
import org.dromara.daxpay.channel.wechat.result.app.WechatIsvAppResult;
import org.dromara.daxpay.channel.wechat.convert.isv.WechatIsvAppConvert;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppResult;
import org.dromara.daxpay.platform.common.mybatisplus.base.MpBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;
import com.baomidou.mybatisplus.annotation.FieldStrategy;

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.wechat.entity.config;
package org.dromara.daxpay.channel.wechat.entity.isv;
import org.dromara.daxpay.channel.wechat.convert.WechatIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvAppAuthConfigResult;
import org.dromara.daxpay.channel.wechat.convert.isv.WechatIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppAuthConfigResult;
import org.dromara.daxpay.platform.common.mybatisplus.base.MpBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;
import org.dromara.daxpay.platform.common.mybatisplus.handler.encrypt.DataEncryptTypeHandler;

View File

@@ -0,0 +1,38 @@
package org.dromara.daxpay.channel.wechat.entity.isv;
import org.dromara.daxpay.channel.wechat.convert.isv.WechatIsvChannelMerchantConvert;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvChannelMerchantResult;
import org.dromara.daxpay.payment.common.entity.merchant.MchBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/// # 微信服务商通道商户绑定
///
/// 微信特约商户关联到服务商本身(服务商密钥全局唯一), 不挂靠具体服务商应用,
/// 因此本表不保存应用关联字段。同一商户下特约商户号不重复。
///
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@TableName(value = "mch_wechat_isv_channel_merchant", autoResultMap = true)
public class WechatIsvChannelMerchant extends MchBaseEntity implements ToResult<WechatIsvChannelMerchantResult> {
/// 通道商户号(WISV+雪花)
private String channelMchNo;
/// 所属支付产品
/// @see org.dromara.daxpay.platform.core.enums.pay.channel.ProductEnum
private String product;
/// 微信特约商户号/二级商户号(V3 服务商支付 sub_mchid)
private String subMchId;
/// 转换
@Override
public WechatIsvChannelMerchantResult toResult() {
return WechatIsvChannelMerchantConvert.CONVERT.toResult(this);
}
}

View File

@@ -1,7 +1,7 @@
package org.dromara.daxpay.channel.wechat.entity.config;
package org.dromara.daxpay.channel.wechat.entity.isv;
import org.dromara.daxpay.channel.wechat.convert.WechatIsvKeyConfigConvert;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvKeyConfigResult;
import org.dromara.daxpay.channel.wechat.convert.isv.WechatIsvKeyConfigConvert;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvKeyConfigResult;
import org.dromara.daxpay.platform.common.mybatisplus.base.MpBaseEntity;
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;
import org.dromara.daxpay.platform.common.mybatisplus.handler.encrypt.DataEncryptTypeHandler;

View File

@@ -0,0 +1,34 @@
package org.dromara.daxpay.channel.wechat.param.direct;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.experimental.Accessors;
/// # 微信直连通道商户创建参数
///
@Data
@Accessors(chain = true)
@Schema(title = "微信直连通道商户创建参数")
public class WechatDirectChannelMerchantCreateParam {
/// 商户号
@Schema(description = "商户号")
@NotBlank(message = "{validation.field.mchNo.notBlank}")
private String mchNo;
/// 通道商户名称
@Schema(description = "通道商户名称")
@NotBlank(message = "{validation.field.channelMerchantName.notBlank}")
private String channelMerchantName;
/// 所属支付产品
@Schema(description = "所属支付产品")
@NotBlank(message = "{validation.field.product.notBlank}")
private String product;
/// 微信直连商户号
@Schema(description = "微信直连商户号")
@NotBlank(message = "{validation.field.wxMchId.notBlank}")
private String wxMchId;
}

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.param.config;
package org.dromara.daxpay.channel.wechat.param.isv;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.param.app;
package org.dromara.daxpay.channel.wechat.param.isv;
import org.dromara.daxpay.platform.core.validation.ValidationGroup;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -0,0 +1,34 @@
package org.dromara.daxpay.channel.wechat.param.isv;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.experimental.Accessors;
/// # 微信服务商通道商户创建参数
///
@Data
@Accessors(chain = true)
@Schema(title = "微信服务商通道商户创建参数")
public class WechatIsvChannelMerchantCreateParam {
/// 商户号
@Schema(description = "商户号")
@NotBlank(message = "{validation.field.mchNo.notBlank}")
private String mchNo;
/// 通道商户名称
@Schema(description = "通道商户名称")
@NotBlank(message = "{validation.field.channelMerchantName.notBlank}")
private String channelMerchantName;
/// 所属支付产品
@Schema(description = "所属支付产品")
@NotBlank(message = "{validation.field.product.notBlank}")
private String product;
/// 微信特约商户号/二级商户号
@Schema(description = "微信特约商户号/二级商户号")
@NotBlank(message = "{validation.field.subMchId.notBlank}")
private String subMchId;
}

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.param.config;
package org.dromara.daxpay.channel.wechat.param.isv;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;

View File

@@ -0,0 +1,27 @@
package org.dromara.daxpay.channel.wechat.result.direct;
import org.dromara.daxpay.payment.common.result.MchTradeBaseResult;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/// # 微信直连通道商户绑定结果
///
/// 微信直连通道商户绑定关系的返回结果对象,包含通道商户号、所属产品和微信直连商户号等信息。
///
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "微信直连通道商户绑定结果")
public class WechatDirectChannelMerchantResult extends MchTradeBaseResult {
@Schema(description = "通道商户号")
private String channelMchNo;
@Schema(description = "所属支付产品")
private String product;
@Schema(description = "微信直连商户号")
private String wxMchId;
}

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.result.config;
package org.dromara.daxpay.channel.wechat.result.isv;
import org.dromara.daxpay.platform.common.json.sensitive.SensitiveInfo;
import org.dromara.daxpay.platform.core.result.BaseResult;

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.result.app;
package org.dromara.daxpay.channel.wechat.result.isv;
import org.dromara.daxpay.platform.core.result.BaseResult;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -0,0 +1,27 @@
package org.dromara.daxpay.channel.wechat.result.isv;
import org.dromara.daxpay.payment.common.result.MchTradeBaseResult;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/// # 微信服务商通道商户绑定结果
///
/// 微信服务商通道商户绑定关系的返回结果对象,包含通道商户号、所属产品和特约商户号等信息。
///
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "微信服务商通道商户绑定结果")
public class WechatIsvChannelMerchantResult extends MchTradeBaseResult {
@Schema(description = "通道商户号")
private String channelMchNo;
@Schema(description = "所属支付产品")
private String product;
@Schema(description = "微信特约商户号/二级商户号")
private String subMchId;
}

View File

@@ -1,4 +1,4 @@
package org.dromara.daxpay.channel.wechat.result.config;
package org.dromara.daxpay.channel.wechat.result.isv;
import org.dromara.daxpay.platform.common.json.sensitive.SensitiveInfo;
import org.dromara.daxpay.platform.core.result.BaseResult;

View File

@@ -0,0 +1,67 @@
package org.dromara.daxpay.channel.wechat.service.direct;
import org.dromara.daxpay.channel.wechat.dao.direct.WechatDirectChannelMerchantManager;
import org.dromara.daxpay.channel.wechat.entity.direct.WechatDirectChannelMerchant;
import org.dromara.daxpay.channel.wechat.param.direct.WechatDirectChannelMerchantCreateParam;
import org.dromara.daxpay.channel.wechat.result.direct.WechatDirectChannelMerchantResult;
import org.dromara.daxpay.payment.channel.dao.mch.ChannelMerchantManager;
import org.dromara.daxpay.payment.channel.entity.mch.ChannelMerchant;
import org.dromara.daxpay.platform.core.code.CommonErrorCode;
import org.dromara.daxpay.platform.core.enums.channel.ChannelMerchantSourceEnum;
import org.dromara.daxpay.platform.core.exception.BizInfoException;
import org.dromara.daxpay.platform.core.exception.DataNotExistException;
import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/// # 微信直连通道商户管理
///
/// 一个微信商户号(wxMchId)对应一个 channelMchNo, 商户的多个应用共享此绑定。
///
@Slf4j
@Service
@RequiredArgsConstructor
public class WechatDirectChannelMerchantService {
private final ChannelMerchantManager channelMerchantManager;
private final WechatDirectChannelMerchantManager wechatDirectChannelMerchantManager;
/// 创建微信直连通道商户
@Transactional(rollbackFor = Exception.class)
public void create(WechatDirectChannelMerchantCreateParam param) {
// 校验同一商户下微信商户号不重复
if (wechatDirectChannelMerchantManager.existsByMchNoAndWxMchId(
param.getMchNo(), param.getWxMchId())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.wechat.directMchDuplicate");
}
// 生成通道商户号(雪花号, 不再使用 wxMchId)
String channelMchNo = String.valueOf(IdUtil.getSnowflakeNextId());
// 写通用通道商户主表
ChannelMerchant channelMerchant = new ChannelMerchant();
channelMerchant.setMchNo(param.getMchNo());
channelMerchant.setChannelMchNo(channelMchNo);
channelMerchant.setChannelMerchantName(param.getChannelMerchantName());
channelMerchant.setProduct(param.getProduct());
channelMerchant.setSource(ChannelMerchantSourceEnum.MANUAL.getCode());
channelMerchant.setEnable(true);
channelMerchantManager.save(channelMerchant);
// 写直连绑定表(wxMchId 作为业务字段, 不参与关联)
WechatDirectChannelMerchant entity = new WechatDirectChannelMerchant();
entity.setMchNo(param.getMchNo());
entity.setChannelMchNo(channelMchNo);
entity.setProduct(param.getProduct());
entity.setWxMchId(param.getWxMchId());
wechatDirectChannelMerchantManager.save(entity);
}
/// 根据通道商户号查询直连通道商户配置
public WechatDirectChannelMerchantResult findByChannelMchNo(String channelMchNo) {
return wechatDirectChannelMerchantManager.lambdaQuery()
.eq(WechatDirectChannelMerchant::getChannelMchNo, channelMchNo)
.oneOpt()
.map(WechatDirectChannelMerchant::toResult)
.orElseThrow(() -> new DataNotExistException("error.payment.channel.channelMerchantNotExist"));
}
}

View File

@@ -1,13 +1,13 @@
package org.dromara.daxpay.channel.wechat.service.config;
package org.dromara.daxpay.channel.wechat.service.isv;
import org.dromara.daxpay.channel.wechat.convert.WechatIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.wechat.dao.app.WechatIsvAppManager;
import org.dromara.daxpay.channel.wechat.dao.config.WechatIsvAppAuthConfigManager;
import org.dromara.daxpay.channel.wechat.entity.app.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvAppAuthConfig;
import org.dromara.daxpay.channel.wechat.enums.WechatIsvAppTypeEnum;
import org.dromara.daxpay.channel.wechat.param.config.WechatIsvAppAuthConfigParam;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvAppAuthConfigResult;
import org.dromara.daxpay.channel.wechat.convert.isv.WechatIsvAppAuthConfigConvert;
import org.dromara.daxpay.channel.wechat.dao.isv.WechatIsvAppManager;
import org.dromara.daxpay.channel.wechat.dao.isv.WechatIsvAppAuthConfigManager;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvAppAuthConfig;
import org.dromara.daxpay.channel.wechat.code.WechatIsvAppTypeEnum;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvAppAuthConfigParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppAuthConfigResult;
import org.dromara.daxpay.platform.core.code.CommonErrorCode;
import org.dromara.daxpay.platform.core.exception.BizInfoException;
import org.dromara.daxpay.platform.core.exception.DataNotExistException;
@@ -50,9 +50,8 @@ public class WechatIsvAppAuthConfigService {
Optional<WechatIsvAppAuthConfig> existing = wechatIsvAppAuthConfigManager.findByAppId(param.getAppId());
if (existing.isPresent()) {
WechatIsvAppAuthConfig config = existing.get();
if (StrUtil.isNotBlank(param.getAppSecret())) {
config.setAppSecret(param.getAppSecret());
} else if (StrUtil.isBlank(config.getAppSecret())) {
WechatIsvAppAuthConfigConvert.CONVERT.copy(param, config);
if (StrUtil.isBlank(config.getAppSecret())) {
// 所有应用类型均须配置 AppSecret
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.wechat.appSecretRequired");
}

View File

@@ -1,12 +1,12 @@
package org.dromara.daxpay.channel.wechat.service.app;
package org.dromara.daxpay.channel.wechat.service.isv;
import org.dromara.daxpay.channel.wechat.convert.WechatIsvAppConvert;
import org.dromara.daxpay.channel.wechat.dao.app.WechatIsvAppManager;
import org.dromara.daxpay.channel.wechat.entity.app.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.enums.WechatIsvAppTypeEnum;
import org.dromara.daxpay.channel.wechat.param.app.WechatIsvAppParam;
import org.dromara.daxpay.channel.wechat.result.app.WechatIsvAppResult;
import org.dromara.daxpay.channel.wechat.service.config.WechatIsvAppAuthConfigService;
import org.dromara.daxpay.channel.wechat.convert.isv.WechatIsvAppConvert;
import org.dromara.daxpay.channel.wechat.dao.isv.WechatIsvAppManager;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvApp;
import org.dromara.daxpay.channel.wechat.code.WechatIsvAppTypeEnum;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvAppParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvAppResult;
import org.dromara.daxpay.channel.wechat.service.isv.WechatIsvAppAuthConfigService;
import org.dromara.daxpay.platform.common.mybatisplus.util.MpUtil;
import org.dromara.daxpay.platform.core.code.CommonErrorCode;
import org.dromara.daxpay.platform.core.exception.BizInfoException;

View File

@@ -0,0 +1,68 @@
package org.dromara.daxpay.channel.wechat.service.isv;
import org.dromara.daxpay.channel.wechat.dao.isv.WechatIsvChannelMerchantManager;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvChannelMerchant;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvChannelMerchantCreateParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvChannelMerchantResult;
import org.dromara.daxpay.payment.channel.dao.mch.ChannelMerchantManager;
import org.dromara.daxpay.payment.channel.entity.mch.ChannelMerchant;
import org.dromara.daxpay.platform.core.code.CommonErrorCode;
import org.dromara.daxpay.platform.core.enums.channel.ChannelMerchantSourceEnum;
import org.dromara.daxpay.platform.core.exception.BizInfoException;
import org.dromara.daxpay.platform.core.exception.DataNotExistException;
import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/// # 微信服务商通道商户管理
///
/// 微信特约商户关联到服务商本身(服务商密钥全局唯一), 不挂靠具体服务商应用。
/// 一个商户下同一特约商户号(subMchId)只允许绑定一次。
///
@Slf4j
@Service
@RequiredArgsConstructor
public class WechatIsvChannelMerchantService {
private final ChannelMerchantManager channelMerchantManager;
private final WechatIsvChannelMerchantManager wechatIsvChannelMerchantManager;
/// 创建微信服务商通道商户
@Transactional(rollbackFor = Exception.class)
public void create(WechatIsvChannelMerchantCreateParam param) {
// 校验同一商户下特约商户号不重复
if (wechatIsvChannelMerchantManager.existsByMchNoAndSubMchId(
param.getMchNo(), param.getSubMchId())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "error.channel.wechat.subMerchantDuplicate");
}
// 生成通道商户号:前缀 WISV + 雪花ID(无分隔符, 符合 TradeNoGenerateUtil 约定)
String channelMchNo = "WISV" + IdUtil.getSnowflakeNextId();
// 写通用通道商户主表
ChannelMerchant channelMerchant = new ChannelMerchant();
channelMerchant.setMchNo(param.getMchNo());
channelMerchant.setChannelMchNo(channelMchNo);
channelMerchant.setChannelMerchantName(param.getChannelMerchantName());
channelMerchant.setProduct(param.getProduct());
channelMerchant.setSource(ChannelMerchantSourceEnum.MANUAL.getCode());
channelMerchant.setEnable(true);
channelMerchantManager.save(channelMerchant);
// 写服务商绑定表
WechatIsvChannelMerchant entity = new WechatIsvChannelMerchant();
entity.setMchNo(param.getMchNo());
entity.setChannelMchNo(channelMchNo);
entity.setProduct(param.getProduct());
entity.setSubMchId(param.getSubMchId());
wechatIsvChannelMerchantManager.save(entity);
}
/// 根据通道商户号查询服务商通道商户配置
public WechatIsvChannelMerchantResult findByChannelMchNo(String channelMchNo) {
return wechatIsvChannelMerchantManager.lambdaQuery()
.eq(WechatIsvChannelMerchant::getChannelMchNo, channelMchNo)
.oneOpt()
.map(WechatIsvChannelMerchant::toResult)
.orElseThrow(() -> new DataNotExistException("error.payment.channel.channelMerchantNotExist"));
}
}

View File

@@ -1,10 +1,10 @@
package org.dromara.daxpay.channel.wechat.service.config;
package org.dromara.daxpay.channel.wechat.service.isv;
import org.dromara.daxpay.channel.wechat.convert.WechatIsvKeyConfigConvert;
import org.dromara.daxpay.channel.wechat.dao.config.WechatIsvKeyConfigManager;
import org.dromara.daxpay.channel.wechat.entity.config.WechatIsvKeyConfig;
import org.dromara.daxpay.channel.wechat.param.config.WechatIsvKeyConfigParam;
import org.dromara.daxpay.channel.wechat.result.config.WechatIsvKeyConfigResult;
import org.dromara.daxpay.channel.wechat.convert.isv.WechatIsvKeyConfigConvert;
import org.dromara.daxpay.channel.wechat.dao.isv.WechatIsvKeyConfigManager;
import org.dromara.daxpay.channel.wechat.entity.isv.WechatIsvKeyConfig;
import org.dromara.daxpay.channel.wechat.param.isv.WechatIsvKeyConfigParam;
import org.dromara.daxpay.channel.wechat.result.isv.WechatIsvKeyConfigResult;
import org.dromara.daxpay.platform.core.code.CommonErrorCode;
import org.dromara.daxpay.platform.core.exception.BizInfoException;
import cn.hutool.core.util.StrUtil;
@@ -40,24 +40,7 @@ public class WechatIsvKeyConfigService {
if (existing.isPresent()) {
config = existing.get();
config.setWxMchId(param.getWxMchId());
if (StrUtil.isNotBlank(param.getApiKeyV3())) {
config.setApiKeyV3(param.getApiKeyV3());
}
if (StrUtil.isNotBlank(param.getPublicKey())) {
config.setPublicKey(param.getPublicKey());
}
if (StrUtil.isNotBlank(param.getPublicKeyId())) {
config.setPublicKeyId(param.getPublicKeyId());
}
if (StrUtil.isNotBlank(param.getPrivateKey())) {
config.setPrivateKey(param.getPrivateKey());
}
if (StrUtil.isNotBlank(param.getPrivateCert())) {
config.setPrivateCert(param.getPrivateCert());
}
if (StrUtil.isNotBlank(param.getCertSerialNo())) {
config.setCertSerialNo(param.getCertSerialNo());
}
WechatIsvKeyConfigConvert.CONVERT.copy(param, config);
wechatIsvKeyConfigManager.updateById(config);
} else {
this.validateForCreate(param);

View File

@@ -5,6 +5,8 @@ import org.dromara.daxpay.payment.merchant.param.config.MerchantCredentialParam;
import org.dromara.daxpay.payment.merchant.result.config.MerchantCredentialResult;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;
import org.mapstruct.BeanMapping;
import org.mapstruct.factory.Mappers;
/// # 商户API配置转换
@@ -17,5 +19,6 @@ public interface MerchantCredentialConvert {
MerchantCredentialResult toResult(MerchantCredential entity);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void copy(MerchantCredentialParam param, @MappingTarget MerchantCredential entity);
}

View File

@@ -2,7 +2,13 @@ package org.dromara.daxpay.payment.merchant.convert.route.strategy;
import org.dromara.daxpay.payment.merchant.entity.route.strategy.PayRouteStrategy;
import org.dromara.daxpay.payment.merchant.result.route.strategy.PayRouteStrategyResult;
import org.dromara.daxpay.payment.merchant.entity.route.strategy.PayRouteStrategy;
import org.dromara.daxpay.payment.merchant.param.route.strategy.PayRouteStrategyParam;
import org.dromara.daxpay.payment.merchant.result.route.strategy.PayRouteStrategyResult;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;
import org.mapstruct.factory.Mappers;
/// # 支付通道路由策略转换
@@ -13,4 +19,7 @@ public interface PayRouteStrategyConvert {
PayRouteStrategyConvert CONVERT = Mappers.getMapper(PayRouteStrategyConvert.class);
PayRouteStrategyResult toResult(PayRouteStrategy entity);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void copy(PayRouteStrategyParam param, @MappingTarget PayRouteStrategy entity);
}

View File

@@ -1,6 +1,7 @@
package org.dromara.daxpay.payment.merchant.service.route.facade;
import org.dromara.daxpay.payment.merchant.dao.appinfo.MchAppInfoManager;
import org.dromara.daxpay.payment.merchant.convert.route.strategy.PayRouteStrategyConvert;
import org.dromara.daxpay.payment.merchant.dao.route.strategy.PayRouteStrategyManager;
import org.dromara.daxpay.payment.merchant.entity.route.strategy.PayRouteStrategy;
import org.dromara.daxpay.payment.merchant.param.route.basic.PayRouteBasicConfigBatchParam;
@@ -15,7 +16,6 @@ import org.dromara.daxpay.payment.merchant.service.route.basic.PayRouteBasicConf
import org.dromara.daxpay.payment.merchant.service.route.scene.PayRouteSceneConfigService;
import org.dromara.daxpay.platform.core.enums.pay.route.PayRouteModeEnum;
import org.dromara.daxpay.platform.core.exception.DataNotExistException;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -62,18 +62,7 @@ public class PayRouteConfigService {
mchAppInfoManager.requireByAppIdNotTenant(param.getAppId());
PayRouteStrategy strategy = strategyManager.findByAppId(param.getAppId())
.orElseThrow(() -> new DataNotExistException("pay.route.error.routeStrategyNotExist"));
if (StrUtil.isNotBlank(param.getMode())) {
strategy.setMode(param.getMode());
}
if (param.getEnable() != null) {
strategy.setEnable(param.getEnable());
}
if (StrUtil.isNotBlank(param.getName())) {
strategy.setName(param.getName());
}
if (StrUtil.isNotBlank(param.getProvider())) {
strategy.setProvider(param.getProvider());
}
PayRouteStrategyConvert.CONVERT.copy(param, strategy);
strategyManager.updateById(strategy);
return strategy.toResult();
}

View File

@@ -39,5 +39,7 @@
"appTypeInvalid": "Invalid WeChat application type",
"appSecretRequired": "App secret is required",
"publicKeyRequired": "Payment public key is required",
"privateCertRequired": "API certificate is required"
"privateCertRequired": "API certificate is required",
"subMerchantDuplicate": "This sub-merchant already exists under the WeChat application",
"directMchDuplicate": "The WeChat merchant already exists under this merchant"
}

View File

@@ -39,5 +39,7 @@
"appTypeInvalid": "微信应用类型无效",
"appSecretRequired": "应用密钥不可为空",
"publicKeyRequired": "支付公钥未配置",
"privateCertRequired": "API证书未配置"
"privateCertRequired": "API证书未配置",
"subMerchantDuplicate": "该微信应用下已存在此特约商户号",
"directMchDuplicate": "同一商户下该微信商户已存在"
}