This commit is contained in:
2026-09-11 11:51:26 +08:00
parent d60689ce02
commit d2cff49b9e
45 changed files with 569 additions and 66 deletions
@@ -110,7 +110,7 @@ public final class TenantDtos {
@Schema(description = "Review type / 审核类型", example = "REGISTER") String reviewType,
@Schema(description = "Review status / 审核状态", example = "PENDING") String status,
@Schema(description = "Customer name / 客户名称", example = "深圳虫虫出海科技有限公司") String tenantName,
@Schema(description = "Customer code / 客户编号", example = "TEN190000000000000002") String tenantCode,
@Schema(description = "Customer code / 五位客户编号", example = "00001") String tenantCode,
@Schema(description = "Primary contact / 联系人", example = "张三") String contactName,
@Schema(description = "Contact phone / 联系电话", example = "13800138000") String contactPhone,
@Schema(description = "Contact email / 联系邮箱", example = "ops@example.com") String contactEmail,
@@ -0,0 +1,51 @@
package com.baiyue.iam.repository;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import jakarta.annotation.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Locale;
/** 在客户创建事务内串行分配固定五位客户编号。 */
@Repository
public class CustomerCodeRepository {
private static final String SEQUENCE_KEY = "CUSTOMER_CODE";
private static final long MAX_CUSTOMER_CODE = 99_999L;
@Resource
private JdbcTemplate jdbc;
@Transactional(propagation = Propagation.MANDATORY)
public String nextCode() {
jdbc.update("INSERT IGNORE INTO iam_number_sequence(sequence_key,next_value) VALUES (?,1)",
SEQUENCE_KEY);
Long value = jdbc.queryForObject(
"SELECT next_value FROM iam_number_sequence WHERE sequence_key=? FOR UPDATE",
Long.class, SEQUENCE_KEY);
if (value == null) {
throw new BizException(ResultCode.INTERNAL_ERROR, "客户编号序列状态异常");
}
String code = format(value);
int updated = jdbc.update(
"UPDATE iam_number_sequence SET next_value=next_value+1 WHERE sequence_key=? AND next_value=?",
SEQUENCE_KEY, value);
if (updated != 1) {
throw new BizException(ResultCode.CONFLICT, "客户编号分配冲突,请重试");
}
return code;
}
static String format(long value) {
if (value < 1) {
throw new BizException(ResultCode.INTERNAL_ERROR, "客户编号序列状态异常");
}
if (value > MAX_CUSTOMER_CODE) {
throw new BizException(ResultCode.CONFLICT, "五位客户编号已用完");
}
return String.format(Locale.ROOT, "%05d", value);
}
}
@@ -20,6 +20,7 @@ import com.baiyue.iam.mapper.IamTenantMapper;
import com.baiyue.iam.mapper.IamTenantQualificationMapper;
import com.baiyue.iam.mapper.IamTenantReviewMapper;
import com.baiyue.iam.mapper.IamUserMapper;
import com.baiyue.iam.repository.CustomerCodeRepository;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import jakarta.annotation.Resource;
@@ -43,6 +44,7 @@ public class MerchantOnboardingService {
@Resource private CustomerDimensionRuleInitializationService dimensionRuleInitialization;
@Resource private OverseasStorageFeeInitializationService overseasStorageFeeInitialization;
@Resource private SecurityEventOutboxService securityEvents;
@Resource private CustomerCodeRepository customerCodes;
@Transactional
public MerchantRegistrationResponse register(MerchantRegistrationRequest request) {
@@ -66,7 +68,7 @@ public class MerchantOnboardingService {
IamTenant tenant = new IamTenant();
tenant.setId(tenantId);
tenant.setTenantCode("TEN" + tenantId);
tenant.setTenantCode(customerCodes.nextCode());
tenant.setTenantName(request.companyName());
tenant.setTenantType("MERCHANT");
tenant.setStatus("PROFILE_REQUIRED");
@@ -11,6 +11,7 @@ import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.entity.IamTenantQualification;
import com.baiyue.iam.entity.IamTenantReview;
import com.baiyue.iam.repository.TenantRepository;
import com.baiyue.iam.repository.CustomerCodeRepository;
import com.baiyue.iam.repository.ProfileResourceRepository;
import com.baiyue.iam.client.AuthAccountClient;
import com.baiyue.iam.repository.MemberRepository;
@@ -56,6 +57,8 @@ public class TenantService {
@Resource
private TenantRepository repository;
@Resource
private CustomerCodeRepository customerCodes;
@Resource
private ProfileResourceRepository profileRepository;
@Resource
private AuthAccountClient authClient;
@@ -165,7 +168,7 @@ public class TenantService {
ensureAdministratorPhoneAvailable(contactPhone);
IamTenant tenant = new IamTenant();
tenant.setId(IdWorker.getId());
tenant.setTenantCode("TEN" + tenant.getId());
tenant.setTenantCode(customerCodes.nextCode());
tenant.setTenantName(request.tenantName());
tenant.setTenantType("MERCHANT");
tenant.setStatus("PROFILE_REQUIRED");
+10 -1
View File
@@ -7,7 +7,7 @@ USE baiyue_iam;
CREATE TABLE IF NOT EXISTS iam_tenant (
id BIGINT NOT NULL COMMENT '客户主档ID(雪花ID);0保留为平台技术作用域',
tenant_code VARCHAR(64) NOT NULL COMMENT '全局唯一客户编码',
tenant_code VARCHAR(8) NOT NULL COMMENT '客户编号:企业客户固定五位数字,平台技术主体为PLATFORM',
tenant_name VARCHAR(128) NOT NULL COMMENT '客户企业名称',
tenant_type VARCHAR(20) NOT NULL DEFAULT 'MERCHANT' COMMENT '主体类型:MERCHANT企业客户',
status VARCHAR(20) NOT NULL DEFAULT 'PROFILE_REQUIRED' COMMENT '客户状态:PROFILE_REQUIRED待完善资料、PENDING待审核、ACTIVE正常、REJECTED已驳回、DISABLED已停用、ARCHIVED已归档',
@@ -43,6 +43,15 @@ CREATE TABLE IF NOT EXISTS iam_tenant (
KEY idx_iam_tenant_status (status, created_at)
) ENGINE=InnoDB COMMENT='客户企业主档表:保存企业资料、审核结果和启停状态;ID同时作为客户数据隔离键';
CREATE TABLE IF NOT EXISTS iam_number_sequence (
sequence_key VARCHAR(64) NOT NULL COMMENT '业务编号类型',
next_value BIGINT UNSIGNED NOT NULL COMMENT '下一待分配数字',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
PRIMARY KEY (sequence_key)
) ENGINE=InnoDB COMMENT='IAM业务编号序列表';
INSERT IGNORE INTO iam_number_sequence(sequence_key, next_value) VALUES ('CUSTOMER_CODE', 1);
CREATE TABLE IF NOT EXISTS iam_customer_dimension_initialization_task (
tenant_id BIGINT NOT NULL COMMENT '客户ID及任务聚合ID',
operator_id BIGINT NOT NULL COMMENT '触发初始化的操作人ID;系统补偿为0',
+3 -3
View File
@@ -1113,7 +1113,7 @@ components:
reviewType: {type: string, example: REGISTER}
status: {type: string, enum: [PENDING]}
tenantName: {type: string, description: 客户名称}
tenantCode: {type: string, description: 客户编号}
tenantCode: {type: string, pattern: '^\d{5}$', example: '00001', description: 五位客户编号}
contactName: {type: string, description: 联系人}
contactPhone: {type: string, nullable: true, description: 联系电话}
contactEmail: {type: string, format: email, nullable: true, description: 联系邮箱}
@@ -1199,7 +1199,7 @@ components:
required: [id, tenantCode, tenantName, status, dimensionInitializationStatus, servicePackage]
properties:
id: {type: string, pattern: '^\d+$', example: '190000000000000001'}
tenantCode: {type: string}
tenantCode: {type: string, pattern: '^\d{5}$', example: '00001'}
tenantName: {type: string}
status: {type: string, enum: [PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED, DISABLED, ARCHIVED]}
dimensionInitializationStatus: {type: string, enum: [PENDING, READY, FAILED], description: 客户默认尺寸初始化状态;未 READY 时依赖该配置的业务失败关闭}
@@ -1237,7 +1237,7 @@ components:
required: [id, tenantCode, tenantName, status]
properties:
id: {type: string, pattern: '^\d+$'}
tenantCode: {type: string}
tenantCode: {type: string, pattern: '^\d{5}$', example: '00001'}
tenantName: {type: string}
status: {type: string, enum: [ACTIVE, DISABLED]}
contactName: {type: string, nullable: true}