优化
This commit is contained in:
@@ -24,13 +24,13 @@ public final class MasterDataQueries {
|
||||
@Schema(description = "编码、名称、联系人或联系电话关键字", example = "示例客户")
|
||||
@Size(max = 128) String keyword,
|
||||
@Schema(description = "往来单位类型", allowableValues = {
|
||||
"CUSTOMER", "SUPPLIER", "BOTH", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE"})
|
||||
@Pattern(regexp = "^(CUSTOMER|SUPPLIER|BOTH|CARRIER|CUSTOMS_BROKER|SHIPPER|CONSIGNEE)$") String type,
|
||||
"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE"})
|
||||
@Pattern(regexp = "^(CUSTOMER|CARRIER|SHIPPER|CONSIGNEE)$") String type,
|
||||
@Schema(description = "状态", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
@Pattern(regexp = "^(ACTIVE|INACTIVE)$") String status,
|
||||
@Schema(description = "往来单位类型集合(可重复传参)", allowableValues = {
|
||||
"CUSTOMER", "SUPPLIER", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE"})
|
||||
@Size(max = 6) List<@Pattern(regexp = "^(CUSTOMER|SUPPLIER|CARRIER|CUSTOMS_BROKER|SHIPPER|CONSIGNEE)$") String> types
|
||||
"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE"})
|
||||
@Size(max = 4) List<@Pattern(regexp = "^(CUSTOMER|CARRIER|SHIPPER|CONSIGNEE)$") String> types
|
||||
) {
|
||||
public PartnerPageQuery {
|
||||
if (page == 0) {
|
||||
@@ -69,8 +69,8 @@ public final class MasterDataQueries {
|
||||
@NotBlank @Size(max = 50) String partnerCode,
|
||||
@Schema(description = "往来单位名称", example = "深圳示例贸易有限公司")
|
||||
@NotBlank @Size(max = 128) String partnerName,
|
||||
@Schema(description = "兼容旧客户端的单值类型", allowableValues = {"CUSTOMER", "SUPPLIER", "BOTH", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE"})
|
||||
@Pattern(regexp = "^(CUSTOMER|SUPPLIER|BOTH|CARRIER|CUSTOMS_BROKER|SHIPPER|CONSIGNEE)$") String partnerType,
|
||||
@Schema(description = "单值单位类型", allowableValues = {"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE"})
|
||||
@Pattern(regexp = "^(CUSTOMER|CARRIER|SHIPPER|CONSIGNEE)$") String partnerType,
|
||||
@Schema(description = "联系人", example = "张三")
|
||||
@NotBlank @Size(max = 64) String contactName,
|
||||
@Schema(description = "联系电话", example = "13800138000")
|
||||
@@ -91,8 +91,8 @@ public final class MasterDataQueries {
|
||||
@Size(max = 20) String postalCode,
|
||||
@Schema(description = "状态", allowableValues = {"ACTIVE", "INACTIVE"})
|
||||
@NotBlank @Pattern(regexp = "^(ACTIVE|INACTIVE)$") String status,
|
||||
@Schema(description = "单位类型集合", allowableValues = {"CUSTOMER", "SUPPLIER", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE"})
|
||||
@Size(max = 6) List<@Pattern(regexp = "^(CUSTOMER|SUPPLIER|CARRIER|CUSTOMS_BROKER|SHIPPER|CONSIGNEE)$") String> types,
|
||||
@Schema(description = "单位类型集合", allowableValues = {"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE"})
|
||||
@Size(max = 4) List<@Pattern(regexp = "^(CUSTOMER|CARRIER|SHIPPER|CONSIGNEE)$") String> types,
|
||||
@Schema(description = "备注") @Size(max = 500) String remark
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ public class PartnerEntity extends BaseEntity {
|
||||
private String partnerCode;
|
||||
@Schema(description = "往来单位名称", example = "深圳示例贸易有限公司")
|
||||
private String partnerName;
|
||||
@Schema(description = "类型", example = "CUSTOMER", allowableValues = {"CUSTOMER", "SUPPLIER", "BOTH"})
|
||||
@Schema(description = "类型", example = "CUSTOMER", allowableValues = {"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE"})
|
||||
private String partnerType;
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "单位类型集合", allowableValues = {"CUSTOMER", "SUPPLIER", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE"})
|
||||
@Schema(description = "单位类型集合", allowableValues = {"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE"})
|
||||
private List<String> types;
|
||||
@Schema(description = "联系人")
|
||||
private String contactName;
|
||||
|
||||
@@ -37,30 +37,12 @@ public interface PartnerMapper extends BaseMapper<PartnerEntity> {
|
||||
<if test="tenantId != null">
|
||||
AND p.tenant_id = #{tenantId}
|
||||
</if>
|
||||
<choose>
|
||||
<when test="type == 'BOTH'">
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM wh_partner_type customer_type
|
||||
WHERE customer_type.partner_id = p.id
|
||||
AND customer_type.partner_type = 'CUSTOMER'
|
||||
AND customer_type.tenant_id = p.tenant_id
|
||||
)
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM wh_partner_type supplier_type
|
||||
WHERE supplier_type.partner_id = p.id
|
||||
AND supplier_type.partner_type = 'SUPPLIER'
|
||||
AND supplier_type.tenant_id = p.tenant_id
|
||||
)
|
||||
</when>
|
||||
<otherwise>
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM wh_partner_type pt
|
||||
WHERE pt.partner_id = p.id
|
||||
AND pt.partner_type = #{type}
|
||||
AND pt.tenant_id = p.tenant_id
|
||||
)
|
||||
</otherwise>
|
||||
</choose>
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM wh_partner_type pt
|
||||
WHERE pt.partner_id = p.id
|
||||
AND pt.partner_type = #{type}
|
||||
AND pt.tenant_id = p.tenant_id
|
||||
)
|
||||
<if test="status != null and status != ''">
|
||||
AND p.status = #{status}
|
||||
</if>
|
||||
|
||||
@@ -141,7 +141,6 @@ public class PartnerRepository {
|
||||
private record PartnerKey(Long tenantId, Long partnerId) { }
|
||||
|
||||
private static List<String> legacyTypes(String type) {
|
||||
if ("BOTH".equals(type)) return List.of("CUSTOMER", "SUPPLIER");
|
||||
return StringUtils.hasText(type) ? List.of(type) : List.of();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class PartnerImportService {
|
||||
private static final int MAX_ROWS = 1000;
|
||||
private static final String TEMPLATE_VERSION = "1";
|
||||
private static final Set<String> ALLOWED_TYPES = Set.of(
|
||||
"CUSTOMER", "SUPPLIER", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE");
|
||||
"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE");
|
||||
private static final Pattern EMAIL = Pattern.compile("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$");
|
||||
private static final String[] HEADERS = {
|
||||
"单位编码*", "单位名称*", "单位类型*", "联系人*", "联系电话*", "联系邮箱",
|
||||
@@ -53,7 +53,7 @@ public class PartnerImportService {
|
||||
Row instruction = sheet.createRow(1);
|
||||
instruction.createCell(0).setCellValue("说明");
|
||||
instruction.createCell(1).setCellValue(
|
||||
"仅新增;类型可用中文逗号或英文逗号分隔:CUSTOMER、SUPPLIER、CARRIER、CUSTOMS_BROKER、SHIPPER、CONSIGNEE;状态为 ACTIVE 或 INACTIVE");
|
||||
"仅新增;类型可用中文逗号或英文逗号分隔:CUSTOMER、CARRIER、SHIPPER、CONSIGNEE;供应商与报关代理请在供应商中心维护;状态为 ACTIVE 或 INACTIVE");
|
||||
Row header = sheet.createRow(2);
|
||||
for (int i = 0; i < HEADERS.length; i++) {
|
||||
header.createCell(i).setCellValue(HEADERS[i]);
|
||||
@@ -162,7 +162,7 @@ public class PartnerImportService {
|
||||
entity.setPartnerCode(row.code);
|
||||
entity.setPartnerName(row.name);
|
||||
entity.setTypes(row.types);
|
||||
entity.setPartnerType(row.types.contains("CUSTOMER") && row.types.contains("SUPPLIER") ? "BOTH" : row.types.get(0));
|
||||
entity.setPartnerType(row.types.get(0));
|
||||
entity.setContactName(row.contactName);
|
||||
entity.setContactPhone(row.contactPhone);
|
||||
entity.setContactEmail(nullable(row.email));
|
||||
|
||||
+5
-6
@@ -23,7 +23,7 @@ import java.util.Locale;
|
||||
public class PlatformPartnerQueryService {
|
||||
private static final long PUBLIC_TENANT_ID = 0L;
|
||||
private static final Set<String> ALLOWED_QUERY_TYPES = Set.of(
|
||||
"CUSTOMER", "SUPPLIER", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE", "BOTH");
|
||||
"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE");
|
||||
@Resource
|
||||
private PartnerRepository repository;
|
||||
|
||||
@@ -143,18 +143,17 @@ public class PlatformPartnerQueryService {
|
||||
if (requested != null) requested.forEach(type -> {
|
||||
if (type != null && !type.isBlank()) normalized.add(type);
|
||||
});
|
||||
if (normalized.isEmpty() && "BOTH".equals(legacyType)) {
|
||||
normalized.add("CUSTOMER");
|
||||
normalized.add("SUPPLIER");
|
||||
} else if (normalized.isEmpty() && legacyType != null && !legacyType.isBlank()) {
|
||||
if (normalized.isEmpty() && legacyType != null && !legacyType.isBlank()) {
|
||||
normalized.add(legacyType);
|
||||
}
|
||||
if (normalized.isEmpty()) throw new BizException(ResultCode.BAD_REQUEST, "请至少选择一个单位类型");
|
||||
if (normalized.stream().anyMatch(type -> !ALLOWED_QUERY_TYPES.contains(type))) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "往来单位仅支持 CUSTOMER、CARRIER、SHIPPER、CONSIGNEE");
|
||||
}
|
||||
return List.copyOf(normalized);
|
||||
}
|
||||
|
||||
private static String legacyType(List<String> types) {
|
||||
if (types.contains("CUSTOMER") && types.contains("SUPPLIER")) return "BOTH";
|
||||
return types.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS wh_partner (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '往来单位ID(雪花ID)', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '平台公共往来单位固定使用 tenant_id=0',
|
||||
data_scope_id BIGINT UNSIGNED NOT NULL COMMENT '所属业务数据范围',
|
||||
partner_code VARCHAR(50) NOT NULL COMMENT '平台内唯一往来单位编码', partner_name VARCHAR(128) NOT NULL COMMENT '往来单位名称',
|
||||
partner_type VARCHAR(20) NOT NULL COMMENT 'CUSTOMER、SUPPLIER或BOTH',
|
||||
partner_type VARCHAR(20) NOT NULL COMMENT '往来单位类型:CUSTOMER、CARRIER、SHIPPER或CONSIGNEE',
|
||||
contact_name VARCHAR(64) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(32) NOT NULL COMMENT '联系电话',
|
||||
contact_email VARCHAR(128) NULL COMMENT '联系邮箱', country_code CHAR(2) NOT NULL COMMENT '国家二字码',
|
||||
province VARCHAR(64) NULL COMMENT '省或州', city VARCHAR(64) NOT NULL COMMENT '城市', district VARCHAR(64) NULL COMMENT '区县',
|
||||
@@ -15,13 +15,15 @@ CREATE TABLE IF NOT EXISTS wh_partner (
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记:0未删除、1已删除', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_wh_partner_tenant_code(tenant_id,partner_code,deleted),
|
||||
KEY idx_wh_partner_tenant_status(tenant_id,status,deleted)
|
||||
KEY idx_wh_partner_tenant_status(tenant_id,status,deleted),
|
||||
CONSTRAINT chk_wh_partner_type CHECK (partner_type IN ('CUSTOMER','CARRIER','SHIPPER','CONSIGNEE'))
|
||||
) ENGINE=InnoDB COMMENT='平台统一维护、供全部客户共享的往来单位主数据';
|
||||
CREATE TABLE IF NOT EXISTS wh_partner_type (
|
||||
partner_id BIGINT UNSIGNED NOT NULL COMMENT '往来单位ID', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '平台公共往来单位固定使用 tenant_id=0',
|
||||
data_scope_id BIGINT UNSIGNED NOT NULL COMMENT '所属业务数据范围,平台公共数据为0', partner_type VARCHAR(32) NOT NULL COMMENT '稳定业务类型:CUSTOMER客户、SHIPPER发货方等',
|
||||
PRIMARY KEY(partner_id,partner_type),
|
||||
KEY idx_wh_partner_type_scope(tenant_id,data_scope_id,partner_type,partner_id)
|
||||
KEY idx_wh_partner_type_scope(tenant_id,data_scope_id,partner_type,partner_id),
|
||||
CONSTRAINT chk_wh_partner_type_value CHECK (partner_type IN ('CUSTOMER','CARRIER','SHIPPER','CONSIGNEE'))
|
||||
) ENGINE=InnoDB COMMENT='平台共享往来单位稳定业务类型';
|
||||
INSERT INTO wh_partner(id,tenant_id,data_scope_id,partner_code,partner_name,partner_type,contact_name,contact_phone,contact_email,country_code,province,city,district,address_line,postal_code,status)
|
||||
VALUES(191000000000000001,0,0,'CUS-001','深圳示例贸易有限公司','CUSTOMER','张三','13800138000','contact@example.com','CN','广东省','深圳市','宝安区','航城街道示例路1号','518000','ACTIVE')
|
||||
|
||||
+7
-1
@@ -25,12 +25,18 @@ class PlatformMasterDataControllerContractTest {
|
||||
try (var factory = Validation.buildDefaultValidatorFactory()) {
|
||||
var validator = factory.getValidator();
|
||||
for (String type : java.util.List.of(
|
||||
"CUSTOMER", "SUPPLIER", "BOTH", "CARRIER", "CUSTOMS_BROKER", "SHIPPER", "CONSIGNEE")) {
|
||||
"CUSTOMER", "CARRIER", "SHIPPER", "CONSIGNEE")) {
|
||||
var query = new com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery(
|
||||
1, 20, null, type, null, null);
|
||||
assertThat(validator.validate(query)).isEmpty();
|
||||
}
|
||||
|
||||
for (String removed : java.util.List.of("SUPPLIER", "CUSTOMS_BROKER", "BOTH")) {
|
||||
var query = new com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery(
|
||||
1, 20, null, removed, null, null);
|
||||
assertThat(validator.validate(query)).isNotEmpty();
|
||||
}
|
||||
|
||||
var invalid = new com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery(
|
||||
1, 20, null, "UNKNOWN", null, null);
|
||||
assertThat(validator.validate(invalid))
|
||||
|
||||
@@ -8,18 +8,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PartnerMapperContractTest {
|
||||
@Test
|
||||
void bothTypeRequiresCustomerAndSupplierAssociations() throws Exception {
|
||||
void typeFilterUsesOnlyStablePartnerTypeAssociation() throws Exception {
|
||||
Select select = PartnerMapper.class.getDeclaredMethod("selectPartnerPageByType",
|
||||
Page.class, Long.class, String.class, String.class, String.class)
|
||||
.getAnnotation(Select.class);
|
||||
String sql = String.join("\n", select.value());
|
||||
|
||||
assertThat(sql)
|
||||
.contains("<when test=\"type == 'BOTH'\">")
|
||||
.contains("customer_type.partner_type = 'CUSTOMER'")
|
||||
.contains("supplier_type.partner_type = 'SUPPLIER'")
|
||||
.contains("<otherwise>")
|
||||
.contains("pt.partner_type = #{type}");
|
||||
assertThat(sql).contains("pt.partner_type = #{type}")
|
||||
.doesNotContain("type == 'BOTH'", "supplier_type.partner_type = 'SUPPLIER'");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -89,7 +89,7 @@ class PartnerRepositoryTest {
|
||||
PartnerEntity customerA = new PartnerEntity();
|
||||
customerA.setId(7L); customerA.setTenantId(10001L); customerA.setPartnerType("CUSTOMER");
|
||||
PartnerEntity customerB = new PartnerEntity();
|
||||
customerB.setId(7L); customerB.setTenantId(10002L); customerB.setPartnerType("SUPPLIER");
|
||||
customerB.setId(7L); customerB.setTenantId(10002L); customerB.setPartnerType("SHIPPER");
|
||||
Page<PartnerEntity> source = new Page<>(1, 20);
|
||||
source.setRecords(List.of(customerA, customerB));
|
||||
source.setTotal(2);
|
||||
@@ -98,14 +98,14 @@ class PartnerRepositoryTest {
|
||||
PartnerTypeEntity typeA = new PartnerTypeEntity();
|
||||
typeA.setTenantId(10001L); typeA.setPartnerId(7L); typeA.setPartnerType("CUSTOMER");
|
||||
PartnerTypeEntity typeB = new PartnerTypeEntity();
|
||||
typeB.setTenantId(10002L); typeB.setPartnerId(7L); typeB.setPartnerType("SUPPLIER");
|
||||
typeB.setTenantId(10002L); typeB.setPartnerId(7L); typeB.setPartnerType("SHIPPER");
|
||||
when(mapper.selectTypes(List.of(10001L, 10002L), List.of(7L, 7L)))
|
||||
.thenReturn(List.of(typeA, typeB));
|
||||
|
||||
repository.page(null, new PartnerPageQuery(1, 20, null, null, null, null));
|
||||
|
||||
assertThat(customerA.getTypes()).containsExactly("CUSTOMER");
|
||||
assertThat(customerB.getTypes()).containsExactly("SUPPLIER");
|
||||
assertThat(customerB.getTypes()).containsExactly("SHIPPER");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user