mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-12 23:45:39 +08:00
feat: 支付产品配置表 + 后端 PayProductConfig 全套 (entity/mapper/service/controller)
This commit is contained in:
33
_config/sql/pay_product_config.sql
Normal file
33
_config/sql/pay_product_config.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
-- 支付产品配置表 产品配置状态存储
|
||||
DROP TABLE IF EXISTS pay_product_config;
|
||||
CREATE TABLE pay_product_config (
|
||||
id int8 NOT NULL,
|
||||
product varchar(32) COLLATE pg_catalog.default NOT NULL,
|
||||
channel varchar(32) COLLATE pg_catalog.default NOT NULL,
|
||||
active_env varchar(32) COLLATE pg_catalog.default DEFAULT 'prod',
|
||||
configured bool DEFAULT false,
|
||||
remark varchar(255) COLLATE pg_catalog.default,
|
||||
creator int8,
|
||||
create_time timestamptz(6),
|
||||
last_modifier int8,
|
||||
last_modified_time timestamptz(6),
|
||||
version int4 DEFAULT 0,
|
||||
deleted bool NOT NULL DEFAULT false
|
||||
);
|
||||
|
||||
COMMENT ON TABLE pay_product_config IS '支付产品配置';
|
||||
COMMENT ON COLUMN pay_product_config.id IS '主键';
|
||||
COMMENT ON COLUMN pay_product_config.product IS '产品编码';
|
||||
COMMENT ON COLUMN pay_product_config.channel IS '通道编码';
|
||||
COMMENT ON COLUMN pay_product_config.active_env IS '生效环境: prod/sandbox';
|
||||
COMMENT ON COLUMN pay_product_config.configured IS '是否已配置参数';
|
||||
COMMENT ON COLUMN pay_product_config.remark IS '备注';
|
||||
COMMENT ON COLUMN pay_product_config.creator IS '创建者ID';
|
||||
COMMENT ON COLUMN pay_product_config.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN pay_product_config.last_modifier IS '最后修改ID';
|
||||
COMMENT ON COLUMN pay_product_config.last_modified_time IS '最后修改时间';
|
||||
COMMENT ON COLUMN pay_product_config.version IS '版本号';
|
||||
COMMENT ON COLUMN pay_product_config.deleted IS '删除标志';
|
||||
|
||||
ALTER TABLE pay_product_config ADD CONSTRAINT pk_pay_product_config PRIMARY KEY (id);
|
||||
CREATE UNIQUE INDEX idx_ppc_product ON pay_product_config(product) WHERE deleted = false;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
package org.dromara.daxpay.payment.admin.controller.masterdata.product;
|
||||
|
||||
import org.dromara.daxpay.payment.pay.param.masterdata.product.PayProductConfigParam;
|
||||
import org.dromara.daxpay.payment.pay.result.masterdata.product.PayProductConfigResult;
|
||||
import org.dromara.daxpay.payment.pay.service.masterdata.product.PayProductConfigService;
|
||||
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 io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// # 支付产品配置管理
|
||||
///
|
||||
@PermCode(menuCode = "payment:product")
|
||||
@Validated
|
||||
@Tag(name = "支付产品配置管理")
|
||||
@RestController
|
||||
@RequestMapping("/admin/product-config")
|
||||
@RequiredArgsConstructor
|
||||
public class PayProductConfigController {
|
||||
|
||||
private final PayProductConfigService payProductConfigService;
|
||||
|
||||
@PermCode(code = "view", nameCn = "产品配置查看", nameEn = "Product Config View")
|
||||
@Operation(summary = "全量查询产品配置列表(卡片页使用)")
|
||||
@GetMapping("/list-all")
|
||||
public Result<List<PayProductConfigResult>> listAll() {
|
||||
return Res.ok(payProductConfigService.listAll());
|
||||
}
|
||||
|
||||
@PermCode(code = "edit", nameCn = "产品配置编辑", nameEn = "Product Config Edit")
|
||||
@Operation(summary = "切换产品生效环境")
|
||||
@PostMapping("/switch-env")
|
||||
public Result<Void> switchEnv(
|
||||
@NotBlank(message = "{validation.field.product.notBlank}") String product,
|
||||
@NotNull(message = "{validation.field.sandbox.notNull}") Boolean sandbox) {
|
||||
payProductConfigService.switchEnv(product, sandbox);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@PermCode(code = "edit", nameCn = "产品配置编辑", nameEn = "Product Config Edit")
|
||||
@Operation(summary = "保存产品配置")
|
||||
@PostMapping("/save")
|
||||
public Result<Void> save(@RequestBody @Validated PayProductConfigParam param) {
|
||||
payProductConfigService.saveOrUpdate(param);
|
||||
return Res.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.dromara.daxpay.payment.pay.convert.product;
|
||||
|
||||
import org.dromara.daxpay.payment.pay.entity.masterdata.product.PayProductConfig;
|
||||
import org.dromara.daxpay.payment.pay.result.masterdata.product.PayProductConfigResult;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/// # 支付产品配置转换
|
||||
///
|
||||
@Mapper
|
||||
public interface PayProductConfigConvert {
|
||||
|
||||
PayProductConfigConvert CONVERT = Mappers.getMapper(PayProductConfigConvert.class);
|
||||
|
||||
PayProductConfigResult toResult(PayProductConfig entity);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.dromara.daxpay.payment.pay.dao.product;
|
||||
|
||||
import org.dromara.daxpay.platform.common.mybatisplus.impl.BaseManager;
|
||||
import org.dromara.daxpay.payment.pay.entity.masterdata.product.PayProductConfig;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/// # 支付产品配置
|
||||
///
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class PayProductConfigManager extends BaseManager<PayProductConfigMapper, PayProductConfig> {
|
||||
|
||||
/// 根据产品编码查询
|
||||
public Optional<PayProductConfig> findByProduct(String product) {
|
||||
return lambdaQuery()
|
||||
.eq(PayProductConfig::getProduct, product)
|
||||
.oneOpt();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.dromara.daxpay.payment.pay.dao.product;
|
||||
|
||||
import org.dromara.daxpay.payment.pay.entity.masterdata.product.PayProductConfig;
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/// # 支付产品配置
|
||||
///
|
||||
@Mapper
|
||||
public interface PayProductConfigMapper extends MPJBaseMapper<PayProductConfig> {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.dromara.daxpay.payment.pay.entity.masterdata.product;
|
||||
|
||||
import org.dromara.daxpay.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import org.dromara.daxpay.platform.common.mybatisplus.function.ToResult;
|
||||
import org.dromara.daxpay.payment.pay.convert.product.PayProductConfigConvert;
|
||||
import org.dromara.daxpay.payment.pay.result.masterdata.product.PayProductConfigResult;
|
||||
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 = "pay_product_config", autoResultMap = true)
|
||||
public class PayProductConfig extends MpBaseEntity implements ToResult<PayProductConfigResult> {
|
||||
|
||||
/// 产品编码
|
||||
private String product;
|
||||
|
||||
/// 通道编码
|
||||
private String channel;
|
||||
|
||||
/// 生效环境: prod/sandbox
|
||||
private String activeEnv;
|
||||
|
||||
/// 是否已配置参数
|
||||
private boolean configured;
|
||||
|
||||
/// 备注
|
||||
private String remark;
|
||||
|
||||
@Override
|
||||
public PayProductConfigResult toResult() {
|
||||
return PayProductConfigConvert.CONVERT.toResult(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.dromara.daxpay.payment.pay.param.masterdata.product;
|
||||
|
||||
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 PayProductConfigParam {
|
||||
|
||||
@NotBlank(message = "{validation.field.product.notBlank}")
|
||||
@Schema(description = "产品编码")
|
||||
private String product;
|
||||
|
||||
@NotBlank(message = "{validation.field.channel.notBlank}")
|
||||
@Schema(description = "通道编码")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "生效环境: prod/sandbox")
|
||||
private String activeEnv;
|
||||
|
||||
@Schema(description = "是否已配置参数")
|
||||
private boolean configured;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.dromara.daxpay.payment.pay.result.masterdata.product;
|
||||
|
||||
import org.dromara.daxpay.platform.core.result.BaseResult;
|
||||
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 PayProductConfigResult extends BaseResult {
|
||||
|
||||
@Schema(description = "产品编码")
|
||||
private String product;
|
||||
|
||||
@Schema(description = "产品名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "通道编码")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "通道名称")
|
||||
private String channelName;
|
||||
|
||||
@Schema(description = "是否支持沙箱环境")
|
||||
private boolean sandboxSupport;
|
||||
|
||||
@Schema(description = "生效环境: prod/sandbox")
|
||||
private String activeEnv;
|
||||
|
||||
@Schema(description = "是否已配置参数")
|
||||
private boolean configured;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package org.dromara.daxpay.payment.pay.service.masterdata.product;
|
||||
|
||||
import org.dromara.daxpay.payment.common.util.PaymentStrategyFactory;
|
||||
import org.dromara.daxpay.payment.pay.dao.product.PayProductConfigManager;
|
||||
import org.dromara.daxpay.payment.pay.entity.masterdata.product.PayProductConfig;
|
||||
import org.dromara.daxpay.payment.pay.param.masterdata.product.PayProductConfigParam;
|
||||
import org.dromara.daxpay.payment.pay.result.masterdata.product.PayProductConfigResult;
|
||||
import org.dromara.daxpay.payment.pay.strategy.AbsProductStrategy;
|
||||
import org.dromara.daxpay.platform.common.i18n.util.I18nUtil;
|
||||
import org.dromara.daxpay.platform.core.enums.pay.channel.ChannelEnum;
|
||||
import org.dromara.daxpay.platform.core.enums.pay.channel.ProductEnum;
|
||||
import org.dromara.daxpay.platform.core.enums.pay.config.PayEnvEnum;
|
||||
import org.dromara.daxpay.platform.core.exception.DataNotExistException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/// # 支付产品配置服务
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayProductConfigService {
|
||||
|
||||
private final PayProductConfigManager payProductConfigManager;
|
||||
|
||||
/// 查询全部产品配置列表(卡片页使用)
|
||||
/// 融合 ProductEnum + pay_product_config 表 + 策略信息
|
||||
public List<PayProductConfigResult> listAll() {
|
||||
Map<String, PayProductConfig> configMap = payProductConfigManager.lambdaQuery().list().stream()
|
||||
.collect(Collectors.toMap(PayProductConfig::getProduct, c -> c, (a, b) -> a));
|
||||
|
||||
return Arrays.stream(ProductEnum.values())
|
||||
.map(product -> toConfigResult(product, configMap))
|
||||
.sorted(Comparator.comparing(PayProductConfigResult::getId,
|
||||
Comparator.nullsLast(Comparator.naturalOrder())))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 切换产品的生效环境
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void switchEnv(String product, boolean sandbox) {
|
||||
PayProductConfig config = payProductConfigManager.findByProduct(product)
|
||||
.orElseGet(() -> createDefaultConfig(product));
|
||||
|
||||
if (sandbox) {
|
||||
config.setActiveEnv(PayEnvEnum.SANDBOX.getCode());
|
||||
} else {
|
||||
config.setActiveEnv(PayEnvEnum.PROD.getCode());
|
||||
}
|
||||
payProductConfigManager.saveOrUpdate(config);
|
||||
}
|
||||
|
||||
/// 保存或更新配置
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveOrUpdate(PayProductConfigParam param) {
|
||||
PayProductConfig config = payProductConfigManager.findByProduct(param.getProduct())
|
||||
.orElseGet(PayProductConfig::new);
|
||||
|
||||
config.setProduct(param.getProduct());
|
||||
config.setChannel(param.getChannel());
|
||||
config.setActiveEnv(param.getActiveEnv() != null ? param.getActiveEnv() : PayEnvEnum.PROD.getCode());
|
||||
config.setConfigured(param.isConfigured());
|
||||
config.setRemark(param.getRemark());
|
||||
payProductConfigManager.saveOrUpdate(config);
|
||||
}
|
||||
|
||||
/// 更新配置状态
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void markConfigured(String product, boolean configured) {
|
||||
PayProductConfig config = payProductConfigManager.findByProduct(product)
|
||||
.orElseGet(() -> createDefaultConfig(product));
|
||||
config.setConfigured(configured);
|
||||
payProductConfigManager.saveOrUpdate(config);
|
||||
}
|
||||
|
||||
/// 枚举 + 库表 + 策略合并为配置结果
|
||||
private PayProductConfigResult toConfigResult(ProductEnum product, Map<String, PayProductConfig> configMap) {
|
||||
PayProductConfigResult result = new PayProductConfigResult()
|
||||
.setProduct(product.getCode())
|
||||
.setName(I18nUtil.getEnumName(product))
|
||||
.setChannel(product.getChannel())
|
||||
.setChannelName(I18nUtil.getEnumName(ChannelEnum.findByCode(product.getChannel())));
|
||||
|
||||
AbsProductStrategy strategy = resolveStrategy(product.getCode());
|
||||
if (strategy != null) {
|
||||
result.setSandboxSupport(strategy.isSandbox());
|
||||
}
|
||||
|
||||
PayProductConfig config = configMap.get(product.getCode());
|
||||
if (config != null) {
|
||||
result.setId(config.getId());
|
||||
result.setActiveEnv(config.getActiveEnv());
|
||||
result.setConfigured(config.isConfigured());
|
||||
} else {
|
||||
result.setActiveEnv(PayEnvEnum.PROD.getCode());
|
||||
result.setConfigured(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 创建默认配置记录
|
||||
private PayProductConfig createDefaultConfig(String product) {
|
||||
ProductEnum productEnum = ProductEnum.findByCode(product);
|
||||
if (productEnum == null) {
|
||||
throw new DataNotExistException("error.payment.product.notExist");
|
||||
}
|
||||
|
||||
PayProductConfig config = new PayProductConfig();
|
||||
config.setProduct(product);
|
||||
config.setChannel(productEnum.getChannel());
|
||||
config.setActiveEnv(PayEnvEnum.PROD.getCode());
|
||||
config.setConfigured(false);
|
||||
payProductConfigManager.save(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
private AbsProductStrategy resolveStrategy(String productCode) {
|
||||
if (!PaymentStrategyFactory.existsByProduct(productCode, AbsProductStrategy.class)) {
|
||||
return null;
|
||||
}
|
||||
return PaymentStrategyFactory.createByProduct(productCode, AbsProductStrategy.class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user