2026-08-08 13:32:20 +08:00
SET NAMES utf8mb4 ;
USE baiyue_firstleg ;
CREATE TABLE IF NOT EXISTS fl_ocean_booking (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '海运订舱ID' ,
booking_no VARCHAR ( 40 ) NOT NULL COMMENT '平台海运订舱编号' ,
2026-08-15 09:47:17 +08:00
status VARCHAR ( 24 ) NOT NULL DEFAULT 'DRAFT' COMMENT '订舱状态:DRAFT仅限创建事务内部、CONFIRMED已确认、RELEASED已放舱、CHANGE_PENDING船期待变更、CANCELLED已取消' ,
2026-08-14 19:59:26 +08:00
customer_id BIGINT UNSIGNED NULL COMMENT '可选客户ID快照' ,
customer_name VARCHAR ( 128 ) NULL COMMENT '可选客户名称快照' ,
2026-08-12 17:29:30 +08:00
channel_code VARCHAR ( 64 ) NOT NULL COMMENT '订舱渠道编码快照' ,
channel_name VARCHAR ( 128 ) NOT NULL COMMENT '订舱渠道名称快照' ,
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '国内中转仓ID快照' ,
warehouse_name VARCHAR ( 128 ) NOT NULL COMMENT '国内中转仓名称快照' ,
2026-08-11 18:06:26 +08:00
bill_of_lading_no VARCHAR ( 128 ) NULL COMMENT '提单号' ,
shipping_company_id BIGINT UNSIGNED NULL COMMENT '船公司逻辑ID快照' ,
shipping_company_name VARCHAR ( 128 ) NULL COMMENT '船公司名称快照' ,
booking_agent_id BIGINT UNSIGNED NULL COMMENT '订舱代理逻辑ID快照' ,
booking_agent_name VARCHAR ( 128 ) NULL COMMENT '订舱代理名称快照' ,
vessel_name VARCHAR ( 128 ) NULL COMMENT '当前确认船名快照' ,
voyage_no VARCHAR ( 64 ) NULL COMMENT '当前确认航次号快照' ,
departure_port_code VARCHAR ( 32 ) NULL COMMENT '起运港编码快照' ,
departure_port_name VARCHAR ( 128 ) NULL COMMENT '起运港名称快照' ,
destination_port_code VARCHAR ( 32 ) NULL COMMENT '目的港编码快照' ,
destination_port_name VARCHAR ( 128 ) NULL COMMENT '目的港名称快照' ,
place_of_delivery VARCHAR ( 128 ) NULL COMMENT '最终交货地快照' ,
2026-08-14 19:59:26 +08:00
service_term VARCHAR ( 32 ) NOT NULL COMMENT '运输服务条款快照' ,
freight_term VARCHAR ( 32 ) NOT NULL COMMENT '海运费支付条款快照' ,
2026-08-11 18:06:26 +08:00
estimated_sailing_at DATETIME ( 3 ) NULL COMMENT '当前确认预计开船时间' ,
estimated_arrival_at DATETIME ( 3 ) NULL COMMENT '当前确认预计到港时间' ,
pending_vessel_name VARCHAR ( 128 ) NULL COMMENT '待确认变更船名' ,
pending_voyage_no VARCHAR ( 64 ) NULL COMMENT '待确认变更航次号' ,
pending_estimated_sailing_at DATETIME ( 3 ) NULL COMMENT '待确认变更预计开船时间' ,
pending_estimated_arrival_at DATETIME ( 3 ) NULL COMMENT '待确认变更预计到港时间' ,
change_reason VARCHAR ( 1000 ) NULL COMMENT '船期变更原因' ,
cancellation_reason VARCHAR ( 1000 ) NULL COMMENT '取消订舱原因' ,
remark VARCHAR ( 1000 ) NULL COMMENT '平台内部备注' ,
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建操作人ID' ,
created_by_name VARCHAR ( 64 ) NULL COMMENT '创建操作人姓名快照' ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) COMMENT '订舱记录创建时间' ,
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改操作人ID' ,
updated_by_name VARCHAR ( 64 ) NULL COMMENT '最后修改操作人姓名快照' ,
updated_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) ON UPDATE CURRENT_TIMESTAMP ( 3 ) COMMENT '订舱记录最后更新时间' ,
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号' ,
2026-08-08 13:32:20 +08:00
PRIMARY KEY ( id ),
UNIQUE KEY uk_ocean_booking_no ( booking_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 ),
CONSTRAINT chk_ocean_booking_status CHECK ( status IN
2026-08-15 09:47:17 +08:00
( 'DRAFT' , 'CONFIRMED' , 'RELEASED' , 'CHANGE_PENDING' , 'CANCELLED' )),
2026-08-08 13:32:20 +08:00
CONSTRAINT chk_ocean_booking_schedule CHECK
( estimated_sailing_at IS NULL OR estimated_arrival_at IS NULL OR estimated_arrival_at >= estimated_sailing_at ),
CONSTRAINT chk_ocean_booking_pending_schedule CHECK
( pending_estimated_sailing_at IS NULL OR pending_estimated_arrival_at IS NULL
OR pending_estimated_arrival_at >= pending_estimated_sailing_at )
) ENGINE = InnoDB COMMENT = '独立海运订舱聚合;柜次仍由fl_container_booking承载' ;
2026-08-14 22:03:21 +08:00
-- CREATE TABLE IF NOT EXISTS does not reconcile a database initialized before customer became optional.
ALTER TABLE fl_ocean_booking
MODIFY COLUMN customer_id BIGINT UNSIGNED NULL COMMENT '可选客户ID快照' ,
MODIFY COLUMN customer_name VARCHAR ( 128 ) NULL COMMENT '可选客户名称快照' ;
2026-08-15 10:27:15 +08:00
-- Reconcile databases created before the direct-CONFIRMED contract. This is
-- intentionally fail-closed: no legacy row is promoted and no transport term
-- is guessed. Referenced legacy aggregates must be archived/deleted by the
-- owning module first, then this block can be rerun safely.
DROP TRIGGER IF EXISTS trg_ocean_booking_before_update ;
DROP TRIGGER IF EXISTS trg_ocean_party_before_insert ;
DROP TRIGGER IF EXISTS trg_ocean_party_before_update ;
DROP TRIGGER IF EXISTS trg_ocean_party_before_delete ;
DROP TRIGGER IF EXISTS trg_ocean_requirement_before_insert ;
DROP TRIGGER IF EXISTS trg_ocean_requirement_before_update ;
DROP TRIGGER IF EXISTS trg_ocean_requirement_before_delete ;
DROP TRIGGER IF EXISTS trg_ocean_history_before_delete ;
DELIMITER $$
DROP PROCEDURE IF EXISTS reconcile_ocean_booking_legacy$$
CREATE PROCEDURE reconcile_ocean_booking_legacy ()
BEGIN
DECLARE v_blank_terms INT DEFAULT 0 ;
DECLARE v_legacy INT DEFAULT 0 ;
DECLARE v_external INT DEFAULT 0 ;
DECLARE v_sql TEXT ;
SELECT COUNT ( * ) INTO v_blank_terms
FROM fl_ocean_booking
WHERE NULLIF ( TRIM ( service_term ), '' ) IS NULL
OR NULLIF ( TRIM ( freight_term ), '' ) IS NULL ;
IF v_blank_terms > 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '订舱结构收敛暂停:存在 service_term/freight_term 为空的真实行,请按原始业务资料补齐后重跑,禁止猜值' ;
END IF ;
SELECT COUNT ( * ) INTO v_legacy
FROM fl_ocean_booking
WHERE status IN ( 'DRAFT' , 'SUBMITTED' , 'FAILED' );
IF v_legacy > 0 THEN
-- Tables from later phase blocks may not exist on a module-only run. Use
-- dynamic SQL so a clean initialization remains repeatable.
IF EXISTS ( SELECT 1 FROM information_schema . tables
WHERE table_schema = DATABASE () AND table_name = 'fl_port_schedule' ) THEN
SET @ ocean_legacy_external : = 0 ;
SET v_sql = 'SELECT COUNT(*) INTO @ocean_legacy_external FROM fl_port_schedule p JOIN fl_ocean_booking b ON b.id=p.ocean_booking_id WHERE b.status IN (''DRAFT'',''SUBMITTED'',''FAILED'')' ;
PREPARE stmt FROM v_sql ; EXECUTE stmt ; DEALLOCATE PREPARE stmt ;
SET v_external = v_external + COALESCE ( @ ocean_legacy_external , 0 );
END IF ;
IF EXISTS ( SELECT 1 FROM information_schema . tables
WHERE table_schema = DATABASE () AND table_name = 'fl_carrier_schedule_query' ) THEN
SET @ ocean_legacy_external : = 0 ;
SET v_sql = 'SELECT COUNT(*) INTO @ocean_legacy_external FROM fl_carrier_schedule_query q JOIN fl_ocean_booking b ON b.id=q.ocean_booking_id WHERE b.status IN (''DRAFT'',''SUBMITTED'',''FAILED'')' ;
PREPARE stmt FROM v_sql ; EXECUTE stmt ; DEALLOCATE PREPARE stmt ;
SET v_external = v_external + COALESCE ( @ ocean_legacy_external , 0 );
END IF ;
IF v_external > 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '订舱结构收敛暂停:旧订舱仍被港务船期/船司查询引用,请先按子表历史->主表归档顺序清理引用后重跑;不会伪造 CONFIRMED' ;
END IF ;
DELETE FROM fl_ocean_booking_party
WHERE ocean_booking_id IN ( SELECT id FROM fl_ocean_booking WHERE status IN ( 'DRAFT' , 'SUBMITTED' , 'FAILED' ));
DELETE FROM fl_ocean_booking_container_allocation
WHERE ocean_booking_id IN ( SELECT id FROM fl_ocean_booking WHERE status IN ( 'DRAFT' , 'SUBMITTED' , 'FAILED' ));
DELETE FROM fl_ocean_booking_container_requirement
WHERE ocean_booking_id IN ( SELECT id FROM fl_ocean_booking WHERE status IN ( 'DRAFT' , 'SUBMITTED' , 'FAILED' ));
DELETE FROM fl_ocean_booking_operation
WHERE ocean_booking_id IN ( SELECT id FROM fl_ocean_booking WHERE status IN ( 'DRAFT' , 'SUBMITTED' , 'FAILED' ));
DELETE FROM fl_ocean_booking_status_history
WHERE ocean_booking_id IN ( SELECT id FROM fl_ocean_booking WHERE status IN ( 'DRAFT' , 'SUBMITTED' , 'FAILED' ));
DELETE FROM fl_ocean_booking
WHERE status IN ( 'DRAFT' , 'SUBMITTED' , 'FAILED' );
END IF ;
END $$
CALL reconcile_ocean_booking_legacy () $$
DROP PROCEDURE reconcile_ocean_booking_legacy$$
DELIMITER ;
-- Existing CHECK constraints are not reconciled by CREATE TABLE IF NOT EXISTS.
SET @ ocean_drop_status_check = (
SELECT IF ( COUNT ( * ) > 0 ,
'ALTER TABLE fl_ocean_booking DROP CHECK chk_ocean_booking_status' ,
'SELECT 1' )
FROM information_schema . table_constraints
WHERE table_schema = DATABASE () AND table_name = 'fl_ocean_booking'
AND constraint_name = 'chk_ocean_booking_status'
);
PREPARE ocean_drop_status_stmt FROM @ ocean_drop_status_check ;
EXECUTE ocean_drop_status_stmt ;
DEALLOCATE PREPARE ocean_drop_status_stmt ;
ALTER TABLE fl_ocean_booking
MODIFY COLUMN service_term VARCHAR ( 32 ) NOT NULL COMMENT '运输服务条款快照' ,
MODIFY COLUMN freight_term VARCHAR ( 32 ) NOT NULL COMMENT '海运费支付条款快照' ,
ADD CONSTRAINT chk_ocean_booking_status CHECK
( status IN ( 'DRAFT' , 'CONFIRMED' , 'RELEASED' , 'CHANGE_PENDING' , 'CANCELLED' ));
SET @ ocean_drop_failure_reason = (
SELECT IF ( COUNT ( * ) > 0 ,
'ALTER TABLE fl_ocean_booking DROP COLUMN failure_reason' ,
'SELECT 1' )
FROM information_schema . columns
WHERE table_schema = DATABASE () AND table_name = 'fl_ocean_booking'
AND column_name = 'failure_reason'
);
PREPARE ocean_drop_failure_stmt FROM @ ocean_drop_failure_reason ;
EXECUTE ocean_drop_failure_stmt ;
DEALLOCATE PREPARE ocean_drop_failure_stmt ;
2026-08-08 13:32:20 +08:00
CREATE TABLE IF NOT EXISTS fl_ocean_booking_party (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '订舱提单关系方ID' ,
ocean_booking_id BIGINT UNSIGNED NOT NULL COMMENT '所属海运订舱ID' ,
party_type VARCHAR ( 24 ) NOT NULL COMMENT '关系方类型:SHIPPER发货人、CONSIGNEE收货人、NOTIFY_PARTY通知人' ,
party_name VARCHAR ( 255 ) NOT NULL COMMENT '关系方名称快照' ,
address VARCHAR ( 1000 ) NULL COMMENT '关系方地址快照' ,
contact_name VARCHAR ( 128 ) NULL COMMENT '关系方联系人快照' ,
contact_phone VARCHAR ( 64 ) NULL COMMENT '关系方联系电话快照' ,
2026-08-08 13:32:20 +08:00
PRIMARY KEY ( id ),
UNIQUE KEY uk_ocean_booking_party ( ocean_booking_id , party_type ),
CONSTRAINT fk_ocean_booking_party FOREIGN KEY ( ocean_booking_id ) REFERENCES fl_ocean_booking ( id ),
CONSTRAINT chk_ocean_booking_party_type CHECK ( party_type IN ( 'SHIPPER' , 'CONSIGNEE' , 'NOTIFY_PARTY' ))
) ENGINE = InnoDB COMMENT = '订舱提单关系方快照' ;
CREATE TABLE IF NOT EXISTS fl_ocean_booking_container_requirement (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '订舱箱型需求ID' ,
ocean_booking_id BIGINT UNSIGNED NOT NULL COMMENT '所属海运订舱ID' ,
container_type VARCHAR ( 32 ) NOT NULL COMMENT '所需集装箱尺寸类型编码' ,
container_kind VARCHAR ( 32 ) NOT NULL COMMENT '所需集装箱箱种编码' ,
2026-08-12 17:29:30 +08:00
capacity_cbm DECIMAL ( 18 , 4 ) NOT NULL COMMENT '该需求柜型可用容量快照m3' ,
max_weight_kg DECIMAL ( 18 , 3 ) NOT NULL COMMENT '该需求柜型最大承重快照kg' ,
2026-08-11 18:06:26 +08:00
quantity INT UNSIGNED NOT NULL COMMENT '该箱型箱种所需柜数' ,
sort_no INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '订舱需求展示顺序' ,
2026-08-08 13:32:20 +08:00
PRIMARY KEY ( id ),
KEY idx_ocean_requirement_booking ( ocean_booking_id , sort_no , id ),
CONSTRAINT fk_ocean_requirement_booking FOREIGN KEY ( ocean_booking_id ) REFERENCES fl_ocean_booking ( id ),
CONSTRAINT chk_ocean_requirement_quantity CHECK ( quantity > 0 )
) ENGINE = InnoDB COMMENT = '订舱箱型箱种及数量需求' ;
CREATE TABLE IF NOT EXISTS fl_ocean_booking_container_allocation (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '订舱柜次分配关系ID' ,
ocean_booking_id BIGINT UNSIGNED NOT NULL COMMENT '所属海运订舱ID' ,
requirement_id BIGINT UNSIGNED NOT NULL COMMENT '对应订舱箱型需求ID' ,
2026-08-08 13:32:20 +08:00
container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '明确引用现有柜次ID' ,
2026-08-11 18:06:26 +08:00
allocated_by BIGINT UNSIGNED NOT NULL COMMENT '分配操作人ID' ,
allocated_by_name VARCHAR ( 64 ) NULL COMMENT '分配操作人姓名快照' ,
allocated_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) COMMENT '柜次分配时间' ,
2026-08-08 13:32:20 +08:00
PRIMARY KEY ( id ),
UNIQUE KEY uk_ocean_allocation_container ( container_booking_id ),
KEY idx_ocean_allocation_booking ( ocean_booking_id , requirement_id , allocated_at ),
CONSTRAINT fk_ocean_allocation_booking FOREIGN KEY ( ocean_booking_id ) REFERENCES fl_ocean_booking ( id ),
CONSTRAINT fk_ocean_allocation_requirement FOREIGN KEY ( requirement_id )
REFERENCES fl_ocean_booking_container_requirement ( id ),
CONSTRAINT fk_ocean_allocation_container FOREIGN KEY ( container_booking_id ) REFERENCES fl_container_booking ( id )
) ENGINE = InnoDB COMMENT = '订舱需求与现有柜次的唯一分配关系' ;
CREATE TABLE IF NOT EXISTS fl_ocean_booking_status_history (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '订舱状态历史ID' ,
ocean_booking_id BIGINT UNSIGNED NOT NULL COMMENT '所属海运订舱ID' ,
from_status VARCHAR ( 24 ) NULL COMMENT '变更前订舱状态;创建时为空' ,
to_status VARCHAR ( 24 ) NOT NULL COMMENT '变更后订舱状态' ,
action VARCHAR ( 40 ) NOT NULL COMMENT '触发状态变更的业务动作' ,
reason VARCHAR ( 1000 ) NULL COMMENT '状态变更原因' ,
before_snapshot JSON NULL COMMENT '状态变更前订舱数据快照;创建时为空' ,
after_snapshot JSON NOT NULL COMMENT '状态变更后订舱数据快照' ,
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID' ,
operator_name VARCHAR ( 64 ) NULL COMMENT '操作人姓名快照' ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) COMMENT '状态历史创建时间' ,
2026-08-08 13:32:20 +08:00
PRIMARY KEY ( id ),
KEY idx_ocean_history_booking ( ocean_booking_id , created_at , id ),
CONSTRAINT fk_ocean_history_booking FOREIGN KEY ( ocean_booking_id ) REFERENCES fl_ocean_booking ( id )
) ENGINE = InnoDB COMMENT = '海运订舱不可变状态历史' ;
CREATE TABLE IF NOT EXISTS fl_ocean_booking_operation (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '订舱写操作幂等记录ID' ,
ocean_booking_id BIGINT UNSIGNED NULL COMMENT '关联海运订舱ID;创建请求完成前允许为空' ,
operator_id BIGINT UNSIGNED NOT NULL COMMENT '发起写操作的平台操作人ID' ,
operation VARCHAR ( 40 ) NOT NULL COMMENT '幂等写操作类型' ,
idempotency_key VARCHAR ( 128 ) NOT NULL COMMENT '客户端写操作幂等键' ,
request_hash CHAR ( 64 ) NOT NULL COMMENT '规范化请求内容SHA-256摘要;用于识别同键不同请求' ,
status VARCHAR ( 16 ) NOT NULL DEFAULT 'PROCESSING' COMMENT '处理状态:PROCESSING处理中、SUCCESS成功' ,
result_json JSON NULL COMMENT '成功结果JSON快照;供幂等重放返回' ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) COMMENT '幂等记录创建时间' ,
completed_at DATETIME ( 3 ) NULL COMMENT '写操作成功完成时间' ,
2026-08-08 13:32:20 +08:00
PRIMARY KEY ( id ),
UNIQUE KEY uk_ocean_operation ( operator_id , operation , idempotency_key ),
KEY idx_ocean_operation_booking ( ocean_booking_id , created_at ),
CONSTRAINT fk_ocean_operation_booking FOREIGN KEY ( ocean_booking_id ) REFERENCES fl_ocean_booking ( id ),
CONSTRAINT chk_ocean_operation_status CHECK ( status IN ( 'PROCESSING' , 'SUCCESS' ))
) ENGINE = InnoDB COMMENT = '海运订舱写操作幂等与请求哈希' ;
DROP TRIGGER IF EXISTS trg_ocean_booking_before_update ;
DELIMITER $$
CREATE TRIGGER trg_ocean_booking_before_update BEFORE UPDATE ON fl_ocean_booking FOR EACH ROW
BEGIN
IF OLD . status IN ( 'RELEASED' , 'CANCELLED' ) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已放舱或已取消订舱不可修改' ;
END IF ;
IF OLD . status <> NEW . status AND NOT (
2026-08-15 09:47:17 +08:00
( OLD . status = 'DRAFT' AND NEW . status = 'CONFIRMED' )
2026-08-08 13:32:20 +08:00
OR ( OLD . status = 'CONFIRMED' AND NEW . status IN ( 'RELEASED' , 'CHANGE_PENDING' , 'CANCELLED' ))
2026-08-15 09:47:17 +08:00
OR ( OLD . status = 'CHANGE_PENDING' AND NEW . status IN ( 'CONFIRMED' , 'CANCELLED' ))) THEN
2026-08-08 13:32:20 +08:00
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '海运订舱状态迁移非法' ;
END IF ;
END $$
DELIMITER ;
DROP TRIGGER IF EXISTS trg_ocean_party_before_insert ;
DROP TRIGGER IF EXISTS trg_ocean_party_before_update ;
DROP TRIGGER IF EXISTS trg_ocean_party_before_delete ;
DELIMITER $$
CREATE TRIGGER trg_ocean_party_before_insert BEFORE INSERT ON fl_ocean_booking_party FOR EACH ROW
BEGIN IF ( SELECT status FROM fl_ocean_booking WHERE id = NEW . ocean_booking_id ) <> 'DRAFT' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅草稿可维护订舱方' ; END IF ; END $$
CREATE TRIGGER trg_ocean_party_before_update BEFORE UPDATE ON fl_ocean_booking_party FOR EACH ROW
BEGIN IF ( SELECT status FROM fl_ocean_booking WHERE id = OLD . ocean_booking_id ) <> 'DRAFT' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅草稿可维护订舱方' ; END IF ; END $$
CREATE TRIGGER trg_ocean_party_before_delete BEFORE DELETE ON fl_ocean_booking_party FOR EACH ROW
BEGIN IF ( SELECT status FROM fl_ocean_booking WHERE id = OLD . ocean_booking_id ) <> 'DRAFT' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅草稿可维护订舱方' ; END IF ; END $$
DELIMITER ;
DROP TRIGGER IF EXISTS trg_ocean_requirement_before_insert ;
DROP TRIGGER IF EXISTS trg_ocean_requirement_before_update ;
DROP TRIGGER IF EXISTS trg_ocean_requirement_before_delete ;
DELIMITER $$
CREATE TRIGGER trg_ocean_requirement_before_insert BEFORE INSERT ON fl_ocean_booking_container_requirement FOR EACH ROW
BEGIN IF ( SELECT status FROM fl_ocean_booking WHERE id = NEW . ocean_booking_id ) <> 'DRAFT' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅草稿可维护箱型需求' ; END IF ; END $$
CREATE TRIGGER trg_ocean_requirement_before_update BEFORE UPDATE ON fl_ocean_booking_container_requirement FOR EACH ROW
BEGIN IF ( SELECT status FROM fl_ocean_booking WHERE id = OLD . ocean_booking_id ) <> 'DRAFT' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅草稿可维护箱型需求' ; END IF ; END $$
CREATE TRIGGER trg_ocean_requirement_before_delete BEFORE DELETE ON fl_ocean_booking_container_requirement FOR EACH ROW
BEGIN IF ( SELECT status FROM fl_ocean_booking WHERE id = OLD . ocean_booking_id ) <> 'DRAFT' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅草稿可维护箱型需求' ; END IF ; END $$
DELIMITER ;
DROP TRIGGER IF EXISTS trg_ocean_allocation_before_insert ;
DELIMITER $$
CREATE TRIGGER trg_ocean_allocation_before_insert BEFORE INSERT ON fl_ocean_booking_container_allocation FOR EACH ROW
BEGIN
IF ( SELECT ocean_booking_id FROM fl_ocean_booking_container_requirement WHERE id = NEW . requirement_id ) <> NEW . ocean_booking_id THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '箱型需求不属于当前订舱' ;
END IF ;
IF ( SELECT status FROM fl_ocean_booking WHERE id = NEW . ocean_booking_id ) NOT IN
2026-08-17 13:24:48 +08:00
( 'CONFIRMED' , 'RELEASED' ) THEN
2026-08-08 13:32:20 +08:00
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '当前订舱状态不可分配柜次' ;
END IF ;
END $$
DELIMITER ;
DROP TRIGGER IF EXISTS trg_ocean_history_before_update ;
DROP TRIGGER IF EXISTS trg_ocean_history_before_delete ;
DELIMITER $$
CREATE TRIGGER trg_ocean_history_before_update BEFORE UPDATE ON fl_ocean_booking_status_history FOR EACH ROW
BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '订舱状态历史不可修改' ; END $$
CREATE TRIGGER trg_ocean_history_before_delete BEFORE DELETE ON fl_ocean_booking_status_history FOR EACH ROW
BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '订舱状态历史不可删除' ; END $$
DELIMITER ;
USE baiyue_iam ;
2026-08-08 14:19:45 +08:00
DROP PROCEDURE IF EXISTS assert_ocean_booking_permission_ids_available ;
DELIMITER $$
CREATE PROCEDURE assert_ocean_booking_permission_ids_available ()
BEGIN
IF EXISTS (
SELECT 1 FROM iam_permission
WHERE ( id BETWEEN 5102140 AND 5102149
AND permission_code <> CASE id
WHEN 5102140 THEN 'platform:firstleg:ocean-booking:list'
2026-08-13 12:54:34 +08:00
WHEN 5102141 THEN 'platform:firstleg:ocean-booking:list'
2026-08-08 14:19:45 +08:00
WHEN 5102142 THEN 'platform:firstleg:ocean-booking:create'
WHEN 5102146 THEN 'platform:firstleg:ocean-booking:release'
WHEN 5102147 THEN 'platform:firstleg:ocean-booking:cancel'
WHEN 5102148 THEN 'platform:firstleg:ocean-booking:change'
WHEN 5102149 THEN 'platform:firstleg:ocean-booking:allocate'
END )
OR ( permission_code LIKE 'platform:firstleg:ocean-booking:%'
AND ( tenant_id <> 0 OR app_code <> 'PLATFORM' OR id NOT BETWEEN 5102140 AND 5102149 ))
) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '三期订舱权限迁移失败:5102140-5102149 ID 或权限码被其他语义占用' ;
END IF ;
END $$
DELIMITER ;
CALL assert_ocean_booking_permission_ids_available ();
DROP PROCEDURE IF EXISTS assert_ocean_booking_permission_ids_available ;
2026-08-08 13:32:20 +08:00
INSERT INTO iam_permission
( id , tenant_id , app_code , permission_type , parent_id , permission_code , permission_name ,
route_path , http_method , sort_no , status , built_in , deleted )
VALUES
( 5102140 , 0 , 'PLATFORM' , 'MENU' , 5102000 , 'platform:firstleg:ocean-booking:list' , '订舱管理' , '/first-leg/ocean-bookings' , 'GET' , 80 , 'ACTIVE' , 1 , 0 ),
( 5102142 , 0 , 'PLATFORM' , 'BUTTON' , 5102140 , 'platform:firstleg:ocean-booking:create' , '创建订舱' , NULL , 'POST' , 20 , 'ACTIVE' , 1 , 0 ),
( 5102146 , 0 , 'PLATFORM' , 'BUTTON' , 5102140 , 'platform:firstleg:ocean-booking:release' , '确认放舱' , NULL , 'POST' , 60 , 'ACTIVE' , 1 , 0 ),
( 5102147 , 0 , 'PLATFORM' , 'BUTTON' , 5102140 , 'platform:firstleg:ocean-booking:cancel' , '取消订舱' , NULL , 'POST' , 70 , 'ACTIVE' , 1 , 0 ),
( 5102148 , 0 , 'PLATFORM' , 'BUTTON' , 5102140 , 'platform:firstleg:ocean-booking:change' , '变更船期' , NULL , 'POST' , 80 , 'ACTIVE' , 1 , 0 ),
( 5102149 , 0 , 'PLATFORM' , 'BUTTON' , 5102140 , 'platform:firstleg:ocean-booking:allocate' , '分配柜次' , NULL , 'POST' , 90 , 'ACTIVE' , 1 , 0 )
2026-08-08 14:19:45 +08:00
ON DUPLICATE KEY UPDATE tenant_id = 0 , app_code = 'PLATFORM' , permission_type = VALUES ( permission_type ),
permission_code = VALUES ( permission_code ), permission_name = VALUES ( permission_name ), parent_id = VALUES ( parent_id ),
2026-08-08 13:32:20 +08:00
route_path = VALUES ( route_path ), http_method = VALUES ( http_method ), sort_no = VALUES ( sort_no ), status = 'ACTIVE' , built_in = 1 , deleted = 0 ;
INSERT IGNORE INTO iam_role_permission ( role_id , permission_id , tenant_id )
SELECT role . id , permission . id , 0 FROM iam_role role JOIN iam_permission permission
ON permission . tenant_id = 0 AND permission . permission_code LIKE 'platform:firstleg:ocean-booking:%'
WHERE role . tenant_id = 0 AND role . role_code IN ( 'PLATFORM_ADMIN' , 'ORDER_OPERATOR' );
2026-08-13 12:22:31 +08:00
DELETE rp FROM iam_role_permission rp JOIN iam_permission p ON p . tenant_id = rp . tenant_id AND p . id = rp . permission_id
2026-08-13 12:54:34 +08:00
WHERE p . id = 5102141 ;
UPDATE iam_permission SET status = 'INACTIVE' , deleted = 1 WHERE id = 5102141 ;
2026-08-15 09:47:17 +08:00
DELETE rp FROM iam_role_permission rp WHERE rp . permission_id IN ( 5102143 , 5102144 , 5102145 );
DELETE FROM iam_permission WHERE id IN ( 5102143 , 5102144 , 5102145 );
2026-08-13 12:22:31 +08:00
2026-08-08 13:32:20 +08:00
USE baiyue_firstleg ;