From c4adba57db3f19fda88e66afee353913d7769a6e Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 15 Aug 2026 11:12:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/sql/头程数据库统一增量-MySQL8.sql | 27 +++++++++++++++++-- .../entity/CustomsSubmissionBatchEntity.java | 1 + .../customs/service/CustomsService.java | 1 + .../baiyue/firstleg/dto/ContainerDtos.java | 1 + .../entity/ContainerBookingEntity.java | 1 + .../mapper/ContainerBookingMapper.java | 3 ++- .../firstleg/service/ContainerService.java | 4 +++ .../resources/db/phase3-customs-schema.sql | 1 + .../db/phase3-smart-loading-schema.sql | 3 ++- .../main/resources/openapi/customs-v1.yaml | 24 ++++++++++++++++- .../main/resources/openapi/firstleg-v1.yaml | 6 +++-- .../customs/service/CustomsServiceTest.java | 2 ++ .../Phase3FinalUnifiedSqlContractTest.java | 3 +++ .../service/ContainerServiceTest.java | 6 ++++- order/AGENTS.md | 2 +- .../baiyue/order/client/PartnerClient.java | 16 ----------- .../com/baiyue/order/dto/OrderRequests.java | 3 ++- .../src/main/resources/openapi/order-v1.yaml | 3 ++- .../client/WarehouseFeignContractTest.java | 1 - .../OrderApplicationServiceStateTest.java | 4 +-- .../service/OrderMasterDataGuardTest.java | 2 +- .../WarehouseSchemaContractTest.java | 13 ++++++++- 22 files changed, 95 insertions(+), 32 deletions(-) delete mode 100644 order/src/main/java/com/baiyue/order/client/PartnerClient.java diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index b41c4b217..10bcefcfe 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -4788,7 +4788,8 @@ CREATE TABLE IF NOT EXISTS fl_container_booking ( destination_warehouse_name VARCHAR(128) NULL COMMENT '目的仓名称快照', capacity_cbm DECIMAL(18,4) NULL COMMENT '货柜容量m3', max_weight_kg DECIMAL(18,3) NULL COMMENT '货柜最大承重kg', - terminal_trucking_company VARCHAR(128) NULL COMMENT '码头拖车公司', + terminal_trucking_company_id BIGINT UNSIGNED NULL COMMENT '码头拖车Supplier逻辑ID快照;历史数据无法推导时为空', + terminal_trucking_company VARCHAR(128) NULL COMMENT '码头拖车公司名称快照', loading_at DATETIME(3) NULL COMMENT '计划或实际装柜时间', estimated_sailing_at DATETIME(3) NULL COMMENT '预计开船时间', actual_sailing_at DATETIME(3) NULL COMMENT '实际开船时间', @@ -9507,7 +9508,7 @@ CREATE TABLE IF NOT EXISTS fl_customs_supplement_request ( CREATE TABLE IF NOT EXISTS fl_customs_submission_batch ( id BIGINT UNSIGNED NOT NULL COMMENT '报关代理提交批次逻辑ID', customs_case_id BIGINT UNSIGNED NOT NULL COMMENT '所属报关协同单ID', batch_no VARCHAR(40) NOT NULL COMMENT '全局唯一代理提交批次号', - batch_version INT UNSIGNED NOT NULL COMMENT '同一报关协同单内的提交批次版本序号', customs_agent_name VARCHAR(128) NOT NULL COMMENT '本批次接收报关资料的报关代理名称快照', external_reference VARCHAR(128) NULL COMMENT '报关代理或外部系统返回的业务参考号', + batch_version INT UNSIGNED NOT NULL COMMENT '同一报关协同单内的提交批次版本序号', customs_agent_id BIGINT UNSIGNED NULL COMMENT '本批次报关代理Supplier逻辑ID快照;历史数据无法推导时为空', customs_agent_name VARCHAR(128) NOT NULL COMMENT '本批次接收报关资料的报关代理名称快照', external_reference VARCHAR(128) NULL COMMENT '报关代理或外部系统返回的业务参考号', file_snapshot_json JSON NOT NULL COMMENT '提交时冻结的已审核资料数组;元素包含documentId、fileId、itemCode、documentVersion和fileHash', status VARCHAR(16) NOT NULL DEFAULT 'SUBMITTED' COMMENT '代理提交状态:SUBMITTED已提交、ACKNOWLEDGED代理已确认、REJECTED代理已拒绝、COMPLETED代理处理完成', note VARCHAR(500) NULL COMMENT '提交报关代理时的平台备注', submitted_by BIGINT UNSIGNED NOT NULL COMMENT '提交报关代理的平台操作人ID', submitted_by_name VARCHAR(64) NULL COMMENT '提交时的平台操作人名称快照', submitted_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '提交报关代理时间', PRIMARY KEY (id), @@ -9516,6 +9517,26 @@ CREATE TABLE IF NOT EXISTS fl_customs_submission_batch ( CONSTRAINT chk_customs_batch_status CHECK (status IN ('SUBMITTED','ACKNOWLEDGED','REJECTED','COMPLETED')) ) ENGINE=InnoDB COMMENT='报关代理提交批次及冻结文件版本'; +-- 供应商引用快照收敛:历史名称无法反推Supplier ID,保留为空;新写入由Firstleg服务校验并持久化。 +DROP PROCEDURE IF EXISTS phase3_supplier_snapshot_add_columns; +DELIMITER $$ +CREATE PROCEDURE phase3_supplier_snapshot_add_columns() +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='fl_container_booking') + AND NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='fl_container_booking' AND column_name='terminal_trucking_company_id') THEN + ALTER TABLE fl_container_booking + ADD COLUMN terminal_trucking_company_id BIGINT UNSIGNED NULL COMMENT '码头拖车Supplier逻辑ID快照;历史数据无法推导时为空' AFTER max_weight_kg; + END IF; + IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='fl_customs_submission_batch') + AND NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='fl_customs_submission_batch' AND column_name='customs_agent_id') THEN + ALTER TABLE fl_customs_submission_batch + ADD COLUMN customs_agent_id BIGINT UNSIGNED NULL COMMENT '本批次报关代理Supplier逻辑ID快照;历史数据无法推导时为空' AFTER batch_version; + END IF; +END$$ +DELIMITER ; +CALL phase3_supplier_snapshot_add_columns(); +DROP PROCEDURE phase3_supplier_snapshot_add_columns; + CREATE TABLE IF NOT EXISTS fl_customs_receipt ( id BIGINT UNSIGNED NOT NULL COMMENT '报关回执文件版本逻辑ID', customs_case_id BIGINT UNSIGNED NOT NULL COMMENT '所属报关协同单ID', submission_batch_id BIGINT UNSIGNED NOT NULL COMMENT '产生本回执的报关代理提交批次ID', receipt_type VARCHAR(16) NOT NULL COMMENT '回执类型:RECEIVED已收件、DECLARED已申报、REJECTED已拒绝、INSPECTION查验通知、RELEASED放行回执、OTHER其他回执', file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务回执文件逻辑ID;跨库不建立外键', receipt_version INT UNSIGNED NOT NULL COMMENT '同一提交批次和回执类型下的版本序号', @@ -11998,6 +12019,7 @@ CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'max_weight CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'shipping_company_id', '船司ID快照'); CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'shipping_company_name', '船司名称快照'); CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'terminal_trucking_company', '码头拖车公司'); +CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'terminal_trucking_company_id', '码头拖车Supplier逻辑ID快照;历史数据无法推导时为空'); CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'updated_at', '货柜资料最后更新时间'); CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'updated_by', '最后修改人ID'); CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'updated_by_name', '最后修改人名称快照'); @@ -12167,6 +12189,7 @@ CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'visibility', CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'batch_no', '全局唯一代理提交批次号'); CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'batch_version', '同一报关协同单内的提交批次版本序号'); CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'customs_agent_name', '本批次接收报关资料的报关代理名称快照'); +CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'customs_agent_id', '本批次报关代理Supplier逻辑ID快照;历史数据无法推导时为空'); CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'customs_case_id', '所属报关协同单ID'); CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'external_reference', '报关代理或外部系统返回的业务参考号'); CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'file_snapshot_json', '提交时冻结的已审核资料数组;元素包含documentId、fileId、itemCode、documentVersion和fileHash'); diff --git a/firstleg/src/main/java/com/baiyue/firstleg/customs/entity/CustomsSubmissionBatchEntity.java b/firstleg/src/main/java/com/baiyue/firstleg/customs/entity/CustomsSubmissionBatchEntity.java index 537f12c9b..d68fa1c84 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/customs/entity/CustomsSubmissionBatchEntity.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/customs/entity/CustomsSubmissionBatchEntity.java @@ -11,6 +11,7 @@ public class CustomsSubmissionBatchEntity { private Long customsCaseId; private String batchNo; private Integer batchVersion; + private Long customsAgentId; private String customsAgentName; private String externalReference; private String fileSnapshotJson; diff --git a/firstleg/src/main/java/com/baiyue/firstleg/customs/service/CustomsService.java b/firstleg/src/main/java/com/baiyue/firstleg/customs/service/CustomsService.java index faafbf7c4..d13bae634 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/customs/service/CustomsService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/customs/service/CustomsService.java @@ -181,6 +181,7 @@ public class CustomsService { batch.setId(IdWorker.getId()); batch.setCustomsCaseId(caseId); batch.setBatchVersion(repository.batches(caseId).size() + 1); batch.setBatchNo("CB" + batch.getId()); var customsAgent = suppliers.customs(request.customsAgentId(), request.customsAgentName()); + batch.setCustomsAgentId(customsAgent == null ? null : customsAgent.supplierId()); batch.setCustomsAgentName(customsAgent == null ? null : customsAgent.name()); batch.setExternalReference(trim(request.externalReference())); batch.setFileSnapshotJson(json(current.stream() .map(v -> Map.of("documentId", v.getId(), "fileId", v.getFileId(), "itemCode", v.getChecklistItemCode(), diff --git a/firstleg/src/main/java/com/baiyue/firstleg/dto/ContainerDtos.java b/firstleg/src/main/java/com/baiyue/firstleg/dto/ContainerDtos.java index c0eef66de..c6f7e4164 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/dto/ContainerDtos.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/dto/ContainerDtos.java @@ -64,6 +64,7 @@ public final class ContainerDtos { @Size(max = 128) String destinationWarehouseName, @DecimalMin(value = "0", inclusive = false) BigDecimal capacityCbm, @DecimalMin(value = "0", inclusive = false) BigDecimal maxWeightKg, + @Positive Long terminalTruckingCompanyId, @Size(max = 128) String terminalTruckingCompany, LocalDateTime loadingAt, LocalDateTime estimatedSailingAt, diff --git a/firstleg/src/main/java/com/baiyue/firstleg/entity/ContainerBookingEntity.java b/firstleg/src/main/java/com/baiyue/firstleg/entity/ContainerBookingEntity.java index 48f09634e..64e0bc571 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/entity/ContainerBookingEntity.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/entity/ContainerBookingEntity.java @@ -42,6 +42,7 @@ public class ContainerBookingEntity { private String destinationWarehouseName; private BigDecimal capacityCbm; private BigDecimal maxWeightKg; + private Long terminalTruckingCompanyId; private String terminalTruckingCompany; private LocalDateTime loadingAt; private LocalDateTime estimatedSailingAt; diff --git a/firstleg/src/main/java/com/baiyue/firstleg/mapper/ContainerBookingMapper.java b/firstleg/src/main/java/com/baiyue/firstleg/mapper/ContainerBookingMapper.java index 880b0d95e..b2ca7fdb4 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/mapper/ContainerBookingMapper.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/mapper/ContainerBookingMapper.java @@ -85,7 +85,8 @@ public interface ContainerBookingMapper extends BaseMapper activeWarehouse(invocation.getArgument(2, Long.class), "DOMESTIC", "上海中转仓")); + when(suppliers.trucking(202L, "拖车公司A")) + .thenReturn(new WarehouseSupplierClient.Snapshot(202L, "拖车公司A", "TRUCKING", null, "ACTIVE")); } @Test @@ -320,7 +324,7 @@ class ContainerServiceTest { private static SaveRequest request(String cabinetNo) { return new SaveRequest("MSCU1234567", cabinetNo, 101L, "上海仓", "BOL-001", "柏悦轮", "V001", "40HQ", 201L, "船司A", "CNSHA", "上海港", "USLAX", "洛杉矶港", - "ONT8", "ONT8", new BigDecimal("68.0000"), new BigDecimal("26000.000"), "拖车公司A", + "ONT8", "ONT8", new BigDecimal("68.0000"), new BigDecimal("26000.000"), 202L, "拖车公司A", LocalDateTime.of(2026, 8, 10, 8, 0), LocalDateTime.of(2026, 8, 12, 8, 0), null, LocalDateTime.of(2026, 8, 25, 8, 0), null, LocalDateTime.of(2026, 8, 27, 8, 0), null); diff --git a/order/AGENTS.md b/order/AGENTS.md index d2430c64c..b5a0535ac 100644 --- a/order/AGENTS.md +++ b/order/AGENTS.md @@ -4,7 +4,7 @@ - 负责头程订单主数据、货物明细、快照、状态编排、幂等、Outbox 和内部货物查询。 - 订单交易状态归本模块;履约/入库状态归 `firstleg/`,仓储资源归 `warehouse/`,不得跨库读取。 -- `tenant_id` 是客户隔离键;`customer_id` 是业务客户/往来单位快照,不能替代前者。 +- `tenant_id` 是客户隔离键;`customer_id` 是客户/企业账号 ID,商户下单时固定来自认证上下文,不得指向 Warehouse 往来单位。发货单位、收货单位只保存为订单 Party 引用与业务快照。 ## 模块入口 diff --git a/order/src/main/java/com/baiyue/order/client/PartnerClient.java b/order/src/main/java/com/baiyue/order/client/PartnerClient.java deleted file mode 100644 index 85fbae56e..000000000 --- a/order/src/main/java/com/baiyue/order/client/PartnerClient.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baiyue.order.client; - -import com.baiyue.common.core.api.ApiResponse; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.*; -import java.util.List; - -@FeignClient(name="warehouse-service", contextId="warehousePartnerClient", - url="${baiyue.clients.warehouse.url:}", path="/internal/warehouse-partners") -public interface PartnerClient { - @GetMapping("/{tenantId}/{id}/active") - ApiResponse active(@RequestHeader("X-Internal-Service-Token") String token, - @PathVariable("tenantId") long tenantId, @PathVariable("id") long id); - record Partner(Long id, Long tenantId, String partnerName, String status, - String partnerType, List types) { } -} diff --git a/order/src/main/java/com/baiyue/order/dto/OrderRequests.java b/order/src/main/java/com/baiyue/order/dto/OrderRequests.java index 42cce323b..f8e9cd2b3 100644 --- a/order/src/main/java/com/baiyue/order/dto/OrderRequests.java +++ b/order/src/main/java/com/baiyue/order/dto/OrderRequests.java @@ -28,7 +28,8 @@ public final class OrderRequests { @Schema(name = "FirstLegOrderSaveRequest", description = "First-leg order create or update request / 头程订单新增或更新请求") public record SaveRequest( - @Schema(description = "Customer ID / 客户 ID", example = "30001") Long customerId, + @Schema(description = "Deprecated and ignored. Customer ID is always taken from authenticated enterprise context / 已废弃并忽略,客户 ID 固定取认证企业上下文", deprecated = true) + Long customerId, @Schema(description = "Customer name / 客户名称", example = "Shenzhen Example Trading Co., Ltd. / 深圳示例贸易有限公司", maxLength = 128, requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank @Size(max = 128) String customerName, @Schema(description = "Transport mode / 运输方式", example = "SEA", allowableValues = {"SEA", "AIR", "RAIL", "TRUCK"}, requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/order/src/main/resources/openapi/order-v1.yaml b/order/src/main/resources/openapi/order-v1.yaml index d07b022f4..65ea14255 100644 --- a/order/src/main/resources/openapi/order-v1.yaml +++ b/order/src/main/resources/openapi/order-v1.yaml @@ -590,7 +590,8 @@ components: items: {$ref: '#/components/schemas/FirstLegOrderCargo'} description: >- 订单保存请求中的完整字段以服务端 FirstLegOrderSaveRequest 为准;pricingTaxMode - 是新建和编辑订单的必填报价维度;历史存量订单的响应字段仍允许为空。 + 是新建和编辑订单的必填报价维度;customerId 不接受客户端指定,服务端始终使用认证企业 ID; + 发货单位和收货单位仅通过 sender/receiver 保存业务快照。历史存量订单的响应字段仍允许为空。 FirstLegBatchDraftItem: type: object required: [clientRowId, draft] diff --git a/order/src/test/java/com/baiyue/order/client/WarehouseFeignContractTest.java b/order/src/test/java/com/baiyue/order/client/WarehouseFeignContractTest.java index 012df84dc..45ab0e4a5 100644 --- a/order/src/test/java/com/baiyue/order/client/WarehouseFeignContractTest.java +++ b/order/src/test/java/com/baiyue/order/client/WarehouseFeignContractTest.java @@ -12,7 +12,6 @@ import static org.assertj.core.api.Assertions.assertThat; class WarehouseFeignContractTest { @Test void clientsUseNacosServiceNameAndInternalPathsByDefault() throws Exception { assertClient(WarehouseClient.class, "/internal/warehouses"); - assertClient(PartnerClient.class, "/internal/warehouse-partners"); } private void assertClient(Class type, String expectedPath) throws Exception { diff --git a/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java b/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java index f3b7d2825..3f170257a 100644 --- a/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java +++ b/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java @@ -363,7 +363,7 @@ class OrderApplicationServiceStateTest { } @Test - void publicDestinationCanBeSavedWithoutPartnerSenderOrReceiver() { + void publicDestinationUsesAuthenticatedEnterpriseAsCustomerWithoutPartySnapshots() { OrderRepository repository = mock(OrderRepository.class); OrderEligibilityGuard eligibility = mock(OrderEligibilityGuard.class); OrderMasterDataGuard masterData = mock(OrderMasterDataGuard.class); @@ -374,7 +374,7 @@ class OrderApplicationServiceStateTest { service(repository, eligibility, masterData) .createDraft(20002L, 2L, request, "public-destination-no-parties"); - verify(repository).insertOrder(argThat(order -> order.getCustomerId() == null + verify(repository).insertOrder(argThat(order -> Long.valueOf(20002L).equals(order.getCustomerId()) && "当前企业".equals(order.getCustomerName()))); verify(repository, never()).insertParty(any()); } diff --git a/order/src/test/java/com/baiyue/order/service/OrderMasterDataGuardTest.java b/order/src/test/java/com/baiyue/order/service/OrderMasterDataGuardTest.java index afdbe3649..9b3fb236a 100644 --- a/order/src/test/java/com/baiyue/order/service/OrderMasterDataGuardTest.java +++ b/order/src/test/java/com/baiyue/order/service/OrderMasterDataGuardTest.java @@ -75,7 +75,7 @@ class OrderMasterDataGuardTest { "CN", null, "深圳", null, "地址", null); var cargo = new OrderRequests.Cargo("货物", null, "CARTON", 1, BigDecimal.ONE, BigDecimal.ONE, null, null, null, null, null, false, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null); + null, null, null, null, null, null, null, null, null, null, null); return new OrderRequests.SaveRequest(null, "当前企业", "SEA", null, "CN", destinationWarehouseId, "目的仓", null, null, party, party, List.of(cargo), "PICKUP", receivingWarehouseId, "收货仓", "CH", "渠道", null, null, "BUY_DECLARATION", null, "LCL", false, diff --git a/warehouse/src/test/java/com/baiyue/warehouse/repository/WarehouseSchemaContractTest.java b/warehouse/src/test/java/com/baiyue/warehouse/repository/WarehouseSchemaContractTest.java index c319729b3..a3cda47ea 100644 --- a/warehouse/src/test/java/com/baiyue/warehouse/repository/WarehouseSchemaContractTest.java +++ b/warehouse/src/test/java/com/baiyue/warehouse/repository/WarehouseSchemaContractTest.java @@ -28,7 +28,10 @@ class WarehouseSchemaContractTest { "contact_phone", "contact_email", "country_code", "province", "city", "district", "address_line", "postal_code", "status", "remark"); assertThat(sql).contains("CREATE TABLE IF NOT EXISTS wh_partner_type") - .contains("idx_wh_partner_type_scope"); + .contains("idx_wh_partner_type_scope") + .contains("chk_wh_partner_type CHECK (partner_type IN ('CUSTOMER','CARRIER','SHIPPER','CONSIGNEE'))") + .contains("chk_wh_partner_type_value CHECK (partner_type IN ('CUSTOMER','CARRIER','SHIPPER','CONSIGNEE'))") + .doesNotContain("CUSTOMS_BROKER", "SUPPLIER或BOTH"); assertBaseColumns(sql); } @@ -138,6 +141,14 @@ class WarehouseSchemaContractTest { .contains("库位活动预占或占用唯一约束不完整"); } + @Test + void unifiedSqlUsesOnlyNonSupplierPartnerTypes() throws IOException { + String unified = Files.readString(Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql")); + assertThat(tableDefinition(unified, "wh_partner")) + .contains("chk_wh_partner_type CHECK (partner_type IN ('CUSTOMER','CARRIER','SHIPPER','CONSIGNEE'))") + .doesNotContain("CUSTOMS_BROKER", "SUPPLIER或BOTH"); + } + private static String read(String file) throws IOException { return Files.readString(Path.of("src/main/resources/db", file)); }