This commit is contained in:
2026-09-18 09:59:07 +08:00
parent 13a8dde0a5
commit 4f59f7bd28
45 changed files with 358 additions and 157 deletions
@@ -36,6 +36,7 @@ CREATE TABLE IF NOT EXISTS fl_ocean_booking (
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_ocean_booking_no (booking_no),
UNIQUE KEY uk_ocean_booking_bill_of_lading (bill_of_lading_no),
KEY idx_ocean_booking_customer (customer_id,status,updated_at,id),
KEY idx_ocean_booking_voyage (vessel_name,voyage_no,updated_at),
CONSTRAINT chk_ocean_booking_customer CHECK (customer_id > 0),
@@ -52,6 +53,18 @@ ALTER TABLE fl_ocean_booking
MODIFY COLUMN customer_id BIGINT UNSIGNED NULL COMMENT '可选客户ID快照',
MODIFY COLUMN customer_name VARCHAR(128) NULL COMMENT '可选客户名称快照';
SET @ocean_add_bill_unique = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE fl_ocean_booking ADD UNIQUE KEY uk_ocean_booking_bill_of_lading (bill_of_lading_no)',
'SELECT 1')
FROM information_schema.statistics
WHERE table_schema=DATABASE() AND table_name='fl_ocean_booking'
AND index_name='uk_ocean_booking_bill_of_lading'
);
PREPARE ocean_bill_unique_stmt FROM @ocean_add_bill_unique;
EXECUTE ocean_bill_unique_stmt;
DEALLOCATE PREPARE ocean_bill_unique_stmt;
-- Recreate triggers and the current two-state constraint on repeatable initialization.
DROP TRIGGER IF EXISTS trg_ocean_booking_before_update;
DROP TRIGGER IF EXISTS trg_ocean_party_before_insert;
@@ -36,7 +36,7 @@ CREATE TABLE IF NOT EXISTS fl_document_sequence (
CREATE TABLE IF NOT EXISTS fl_container_booking (
id BIGINT UNSIGNED NOT NULL COMMENT '货柜预订ID(雪花ID)',
booking_no VARCHAR(40) NOT NULL COMMENT '平台唯一货柜预订单号',
container_no VARCHAR(64) NULL COMMENT '国内唯一权威真实集装箱号;ISO 6346标准格式;订舱关联可选写入、提柜后可原子补录、预装纠错命令可修改',
container_no VARCHAR(64) NULL COMMENT '国内柜次真实集装箱号权威快照;ISO 6346标准格式;同一订舱内唯一,不同提单允许复用;订舱关联可选写入、提柜后可原子补录、预装纠错命令可修改',
cabinet_no VARCHAR(64) NOT NULL COMMENT '平台唯一内部柜号',
source_type VARCHAR(24) NOT NULL DEFAULT 'SIMULATION' COMMENT '记录来源:SIMULATION内部模拟柜、OCEAN_BOOKING订舱真实柜',
record_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '记录状态:ACTIVE可操作、MERGED已合并历史',
@@ -92,7 +92,8 @@ CREATE TABLE IF NOT EXISTS fl_container_booking (
PRIMARY KEY (id),
UNIQUE KEY uk_container_booking_no (booking_no),
UNIQUE KEY uk_container_booking_cabinet (cabinet_no),
UNIQUE KEY uk_container_booking_container_no (container_no),
UNIQUE KEY uk_container_booking_ocean_container (ocean_booking_id,container_no),
KEY idx_container_booking_container_no (container_no,updated_at,id),
KEY idx_container_booking_merge (record_status,merged_into_container_booking_id),
KEY idx_container_booking_warehouse (warehouse_id, updated_at, id),
KEY idx_container_booking_voyage (voyage_no, updated_at),
@@ -203,9 +204,17 @@ BEGIN
ALTER TABLE fl_container_booking ADD COLUMN pickup_code_updated_at DATETIME(3) NULL
COMMENT 'PU码最后填写时间' AFTER pickup_code_updated_by_name;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
IF EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='fl_container_booking' AND index_name='uk_container_booking_container_no') THEN
ALTER TABLE fl_container_booking ADD UNIQUE KEY uk_container_booking_container_no (container_no);
ALTER TABLE fl_container_booking DROP INDEX uk_container_booking_container_no;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='fl_container_booking' AND index_name='uk_container_booking_ocean_container') THEN
ALTER TABLE fl_container_booking ADD UNIQUE KEY uk_container_booking_ocean_container (ocean_booking_id,container_no);
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='fl_container_booking' AND index_name='idx_container_booking_container_no') THEN
ALTER TABLE fl_container_booking ADD KEY idx_container_booking_container_no (container_no,updated_at,id);
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='fl_container_booking' AND index_name='idx_container_booking_merge') THEN
@@ -457,7 +457,7 @@ paths:
/api/platform/v1/containers/{id}/ocean-booking-link:
post:
summary: 将内部模拟柜关联到已发布订舱需求
description: 需要 platform:firstleg:container:edit;请求指定 RELEASED oceanBookingId 和未满配 requirementId,containerNo 可空。首次关联允许 WAIT_LOADING 或已有预排货的 EDITING 模拟柜,保留原 containerBookingId/cabinetNo/loadingPlanId/items,原子写入订舱、运输和范围快照并创建 allocation;提柜后由拖车链调用柜次服务原子补录真实柜号。若关联请求已提供 containerNo,服务端仍规范化并校验 ISO 6346 结构、设备类别、校验位和全局唯一性。存在跨仓、跨渠道、柜型规格不一致、超量、重复柜号、PDA、有效装柜证据、业务单证或 LOADING/COMPLETED 等事实时拒绝。
description: 需要 platform:firstleg:container:edit;请求指定 RELEASED oceanBookingId 和未满配 requirementId,containerNo 可空。首次关联允许 WAIT_LOADING 或已有预排货的 EDITING 模拟柜,保留原 containerBookingId/cabinetNo/loadingPlanId/items,原子写入订舱、运输和范围快照并创建 allocation;提柜后由拖车链调用柜次服务原子补录真实柜号。若关联请求已提供 containerNo,服务端仍规范化并校验 ISO 6346 结构、设备类别和校验位,并保证同一订舱内唯一;不同提单允许复用同一集装箱号。存在跨仓、跨渠道、柜型规格不一致、超量、同提单重复柜号、PDA、有效装柜证据、业务单证或 LOADING/COMPLETED 等事实时拒绝。
parameters: [{$ref: '#/components/parameters/ContainerBookingId'}]
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/ContainerOceanBookingLinkRequest'}}}}
responses: {'200': {description: 关联后的同一模拟柜 containerBookingId/cabinetNo;列表仍只有这一条 ACTIVE 操作身份}}
@@ -2765,7 +2765,7 @@ components:
properties:
oceanBookingId: {type: integer, format: int64, minimum: 1, description: RELEASED订舱ID}
requirementId: {type: integer, format: int64, minimum: 1, description: 未满配的订舱柜型需求ID}
containerNo: {type: string, nullable: true, maxLength: 64, description: 可选;港口提柜后可由拖车链另行原子补录。非空时服务端移除格式空白、转大写并校验ISO 6346结构、设备类别、校验位和全局唯一性}
containerNo: {type: string, nullable: true, maxLength: 64, description: 可选;港口提柜后可由拖车链另行原子补录。非空时服务端移除格式空白、转大写并校验ISO 6346结构、设备类别、校验位和同一订舱内唯一性}
expectedVersion: {type: integer, minimum: 0}
ContainerFeeAdjustRequest:
type: object
@@ -167,7 +167,7 @@ components:
customerName: {type: string, nullable: true, description: 可选名称提示;有客户ID时由服务端校验并保存客户主数据名称,清空客户时同时置null}
channelCode: {type: string, nullable: true, description: 固定计划物流渠道组编码}
warehouseId: {type: integer, format: int64, nullable: true}
billOfLadingNo: {type: string, nullable: true}
billOfLadingNo: {type: string, nullable: true, description: 全局唯一提单号;草稿未取得时可为空}
shippingCompanyId: {type: integer, format: int64, nullable: true}
shippingCompanyName: {type: string, nullable: true}
carrierCode:
@@ -267,10 +267,11 @@ components:
carrierCodes: {type: array, items: {type: string, enum: [MATSON, SML, ZIM, COSCO, EMC, HEDE, OTHER]}}
LinkCandidate:
type: object
required: [oceanBookingId, bookingNo, requirementId, containerType, capacityCbm, maxWeightKg, requiredQuantity, allocatedQuantity, remainingQuantity, customerName, warehouseName, channelName]
required: [oceanBookingId, bookingNo, billOfLadingNo, requirementId, containerType, capacityCbm, maxWeightKg, requiredQuantity, allocatedQuantity, remainingQuantity, customerName, warehouseName, channelName]
properties:
oceanBookingId: {type: string, pattern: '^[0-9]+$'}
bookingNo: {type: string}
billOfLadingNo: {type: string, description: 已发布订舱的全局唯一提单号}
requirementId: {type: string, pattern: '^[0-9]+$'}
containerType: {type: string}
capacityCbm: {type: number}