feat(firstleg): implement container customs workflow

This commit is contained in:
2026-08-28 16:48:50 +08:00
parent bb9673358d
commit 0ea4aeecc9
92 changed files with 3165 additions and 2754 deletions
+99 -291
View File
@@ -5114,7 +5114,7 @@ CREATE TABLE IF NOT EXISTS fl_loading_plan_item (
CREATE TABLE IF NOT EXISTS fl_container_document (
id BIGINT UNSIGNED NOT NULL COMMENT '货柜文件关联ID(雪花ID)',
container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '货柜预订ID',
document_type VARCHAR(32) NOT NULL COMMENT '文件类型:DESTINATION_CLEARANCE目的港清关、CUSTOMS_DECLARATION出口报关、DELIVERY_ORDER提货单、PICKUP_ORDER取货单',
document_type VARCHAR(32) NOT NULL COMMENT '文件类型:DESTINATION_CLEARANCE目的港清关、DELIVERY_ORDER提货单、PICKUP_ORDER取货单',
file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务文件ID,不建立跨库外键',
file_name VARCHAR(255) NOT NULL COMMENT '文件名称快照',
file_hash VARCHAR(64) NULL COMMENT 'File服务SHA-256快照',
@@ -5134,7 +5134,7 @@ CREATE TABLE IF NOT EXISTS fl_container_document (
CONSTRAINT fk_container_document_booking FOREIGN KEY (container_booking_id)
REFERENCES fl_container_booking (id),
CONSTRAINT chk_container_document_type
CHECK (document_type IN ('DESTINATION_CLEARANCE', 'CUSTOMS_DECLARATION', 'DELIVERY_ORDER', 'PICKUP_ORDER'))
CHECK (document_type IN ('DESTINATION_CLEARANCE', 'DELIVERY_ORDER', 'PICKUP_ORDER'))
) ENGINE=InnoDB COMMENT='平台货柜清关、DO与PU文件关联';
CREATE TABLE IF NOT EXISTS fl_loading_plan_history (
@@ -5906,7 +5906,7 @@ BEGIN
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan
WHERE container_booking_id = NEW.container_booking_id;
IF current_plan_status = 'COMPLETED'
AND NEW.document_type NOT IN ('DESTINATION_CLEARANCE', 'CUSTOMS_DECLARATION', 'DELIVERY_ORDER', 'PICKUP_ORDER') THEN
AND NEW.document_type NOT IN ('DESTINATION_CLEARANCE', 'DELIVERY_ORDER', 'PICKUP_ORDER') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后货柜文件不可新增';
END IF;
END$$
@@ -5922,7 +5922,7 @@ BEGIN
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan
WHERE container_booking_id = OLD.container_booking_id;
IF current_plan_status = 'COMPLETED'
AND OLD.document_type NOT IN ('DESTINATION_CLEARANCE', 'CUSTOMS_DECLARATION', 'DELIVERY_ORDER', 'PICKUP_ORDER') THEN
AND OLD.document_type NOT IN ('DESTINATION_CLEARANCE', 'DELIVERY_ORDER', 'PICKUP_ORDER') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后货柜文件不可修改';
END IF;
END$$
@@ -9777,173 +9777,25 @@ WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR')
USE baiyue_firstleg;
-- Phase 3 customs document, supplementation, broker submission and receipt lifecycle.
USE baiyue_firstleg;
CREATE TABLE IF NOT EXISTS fl_customs_checklist_version (
id BIGINT UNSIGNED NOT NULL COMMENT '报关资料清单版本逻辑ID', checklist_code VARCHAR(40) NOT NULL COMMENT '报关资料清单编码;同一清单的多个版本共用', version_no VARCHAR(32) NOT NULL COMMENT '清单业务版本号',
country_code VARCHAR(32) NOT NULL COMMENT '清单适用的目的国家或地区编码', channel_code VARCHAR(40) NOT NULL COMMENT '清单适用的运输渠道编码', cargo_type VARCHAR(40) NOT NULL COMMENT '清单适用的货物类型编码',
items_json JSON NOT NULL COMMENT '不可变清单项目数组;元素包含code项目编码、name项目名称和required是否必填', status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '清单版本状态:ACTIVE启用、RETIRED停用', 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 '清单版本创建时间', PRIMARY KEY (id),
UNIQUE KEY uk_customs_checklist_version (checklist_code,version_no),
KEY idx_customs_checklist_match (country_code,channel_code,cargo_type,status),
CONSTRAINT chk_customs_checklist_status CHECK (status IN ('ACTIVE','RETIRED'))
) ENGINE=InnoDB COMMENT='三期报关资料清单不可变版本';
CREATE TABLE IF NOT EXISTS fl_customs_case (
id BIGINT UNSIGNED NOT NULL COMMENT '报关协同单逻辑ID', customs_no VARCHAR(40) NOT NULL COMMENT '全局唯一报关协同单号', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
order_id BIGINT UNSIGNED NOT NULL COMMENT 'Order服务订单逻辑ID;跨库不建立外键', inbound_id BIGINT UNSIGNED NOT NULL COMMENT 'Firstleg入库单逻辑ID',
container_booking_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '关联柜次逻辑ID;0表示创建时尚未关联柜次', checklist_version_id BIGINT UNSIGNED NOT NULL COMMENT '本单冻结使用的报关资料清单版本ID',
checklist_code VARCHAR(40) NOT NULL COMMENT '创建协同单时的清单编码快照;源清单变化不回写', checklist_version_no VARCHAR(32) NOT NULL COMMENT '创建协同单时的清单版本号快照;源清单变化不回写',
status VARCHAR(32) NOT NULL DEFAULT 'DOCUMENTS_PENDING' COMMENT '协同状态:DOCUMENTS_PENDING待补资料、REVIEWING审核中、SUPPLEMENT_REQUIRED需补件、READY_TO_SUBMIT待提交代理、RECEIPT_PENDING待回执、RECEIPT_AVAILABLE已有回执、CLEARANCE_COMPLETED已放行、CANCELLED已取消', remark VARCHAR(500) 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 '乐观锁版本号;每次状态变更递增', PRIMARY KEY (id), UNIQUE KEY uk_customs_no (customs_no),
UNIQUE KEY uk_customs_case_scope (tenant_id,order_id,inbound_id,container_booking_id),
KEY idx_customs_case_status (status,updated_at), KEY idx_customs_case_container (container_booking_id),
CONSTRAINT fk_customs_case_checklist FOREIGN KEY (checklist_version_id) REFERENCES fl_customs_checklist_version(id),
CONSTRAINT chk_customs_case_status CHECK (status IN ('DOCUMENTS_PENDING','REVIEWING','SUPPLEMENT_REQUIRED','READY_TO_SUBMIT','RECEIPT_PENDING','RECEIPT_AVAILABLE','CLEARANCE_COMPLETED','CANCELLED'))
) ENGINE=InnoDB COMMENT='三期订单报关协同聚合';
CREATE TABLE IF NOT EXISTS fl_customs_document (
id BIGINT UNSIGNED NOT NULL COMMENT '报关资料文件版本逻辑ID', customs_case_id BIGINT UNSIGNED NOT NULL COMMENT '所属报关协同单ID', checklist_item_code VARCHAR(40) NOT NULL COMMENT '对应冻结清单中的资料项目编码',
file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务文件逻辑ID;跨库不建立外键', document_version INT UNSIGNED NOT NULL COMMENT '同一协同单和清单项目下的文件版本序号', replaces_document_id BIGINT UNSIGNED NULL COMMENT '被本版本替换的上一资料版本ID;首个版本为空',
file_name VARCHAR(255) NOT NULL COMMENT '上传或引用时的文件名称快照', file_hash CHAR(64) NOT NULL COMMENT '文件内容SHA-256摘要;用于版本审计和幂等校验', status VARCHAR(16) NOT NULL DEFAULT 'UPLOADED' COMMENT '资料状态:UPLOADED待审核、APPROVED审核通过、RETURNED已退回、SUPERSEDED已被替换、FROZEN已随代理提交批次冻结',
visibility VARCHAR(16) NOT NULL DEFAULT 'CUSTOMER' COMMENT '资料可见范围:PLATFORM仅平台可见、CUSTOMER客户可见', uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传或引用资料的操作人ID',
uploaded_by_type VARCHAR(16) NOT NULL COMMENT '上传主体类型:PLATFORM平台操作人、MERCHANT客户操作人', uploaded_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '资料上传或引用时间',
reviewed_by BIGINT UNSIGNED NULL COMMENT '审核资料的平台操作人ID;未审核时为空', reviewed_by_name VARCHAR(64) NULL COMMENT '审核时的平台操作人名称快照', reviewed_at DATETIME(3) NULL COMMENT '资料审核时间',
review_reason VARCHAR(500) NULL COMMENT '审核退回原因或审核备注', PRIMARY KEY (id),
UNIQUE KEY uk_customs_document_version (customs_case_id,checklist_item_code,document_version),
UNIQUE KEY uk_customs_document_file (customs_case_id,file_id), KEY idx_customs_document_case (customs_case_id,status),
CONSTRAINT fk_customs_document_case FOREIGN KEY (customs_case_id) REFERENCES fl_customs_case(id),
CONSTRAINT chk_customs_document_status CHECK (status IN ('UPLOADED','APPROVED','RETURNED','SUPERSEDED','FROZEN')),
CONSTRAINT chk_customs_document_actor CHECK (uploaded_by_type IN ('PLATFORM','MERCHANT')),
CONSTRAINT chk_customs_document_visibility CHECK (visibility IN ('PLATFORM','CUSTOMER'))
) ENGINE=InnoDB COMMENT='报关客户文件版本引用';
CREATE TABLE IF NOT EXISTS fl_customs_supplement_request (
id BIGINT UNSIGNED NOT NULL COMMENT '报关补件请求逻辑ID', customs_case_id BIGINT UNSIGNED NOT NULL COMMENT '所属报关协同单ID', source_document_id BIGINT UNSIGNED NOT NULL COMMENT '触发本次补件的被退回资料版本ID',
resolved_document_id BIGINT UNSIGNED NULL COMMENT '解决本次补件的新资料版本ID;未解决时为空', checklist_item_code VARCHAR(40) NOT NULL COMMENT '需要补充的报关资料项目编码', reason VARCHAR(500) NOT NULL COMMENT '平台审核人员填写的补件原因',
due_at DATETIME(3) NULL COMMENT '期望完成补件时间;未设置时为空', status VARCHAR(16) NOT NULL DEFAULT 'OPEN' COMMENT '补件状态:OPEN待补件、RESOLVED已由新资料解决、CANCELLED已取消', requested_by BIGINT UNSIGNED NOT NULL COMMENT '发起补件的平台操作人ID',
requested_by_name VARCHAR(64) NULL COMMENT '发起补件时的平台操作人名称快照', requested_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '补件请求发起时间',
resolved_by BIGINT UNSIGNED NULL COMMENT '提交解决资料的操作人ID;未解决时为空', resolved_at DATETIME(3) NULL COMMENT '补件请求解决时间', PRIMARY KEY (id),
KEY idx_customs_supplement_case (customs_case_id,status,due_at),
CONSTRAINT fk_customs_supplement_case FOREIGN KEY (customs_case_id) REFERENCES fl_customs_case(id),
CONSTRAINT chk_customs_supplement_status CHECK (status IN ('OPEN','RESOLVED','CANCELLED'))
) ENGINE=InnoDB COMMENT='报关补件请求';
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_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),
UNIQUE KEY uk_customs_batch_no (batch_no), UNIQUE KEY uk_customs_batch_version (customs_case_id,batch_version),
CONSTRAINT fk_customs_batch_case FOREIGN KEY (customs_case_id) REFERENCES fl_customs_case(id),
CONSTRAINT chk_customs_batch_status CHECK (status IN ('SUBMITTED','ACKNOWLEDGED','REJECTED','COMPLETED'))
) ENGINE=InnoDB COMMENT='报关代理提交批次及冻结文件版本';
-- 历史代理名称无法安全反推Supplier ID,旧行保持NULL;新写入由服务端校验并持久化。
DROP PROCEDURE IF EXISTS phase3_customs_supplier_snapshot_add_column;
DELIMITER $$
CREATE PROCEDURE phase3_customs_supplier_snapshot_add_column()
BEGIN
IF 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_customs_supplier_snapshot_add_column();
DROP PROCEDURE phase3_customs_supplier_snapshot_add_column;
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 '同一提交批次和回执类型下的版本序号',
replaces_receipt_id BIGINT UNSIGNED NULL COMMENT '被本版本替换的上一回执版本ID;首个版本为空', file_name VARCHAR(255) NOT NULL COMMENT '上传或引用时的回执文件名称快照', file_hash CHAR(64) NOT NULL COMMENT '回执文件内容SHA-256摘要;用于版本审计和幂等校验',
visibility VARCHAR(16) NOT NULL DEFAULT 'PLATFORM' COMMENT '回执可见范围:PLATFORM仅平台可见、CUSTOMER客户可查询下载', note VARCHAR(500) NULL COMMENT '回执业务备注', uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传或引用回执的平台操作人ID',
uploaded_by_name VARCHAR(64) NULL COMMENT '上传回执时的平台操作人名称快照', uploaded_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '回执上传或引用时间', PRIMARY KEY (id),
UNIQUE KEY uk_customs_receipt_version (submission_batch_id,receipt_type,receipt_version),
UNIQUE KEY uk_customs_receipt_file (submission_batch_id,file_id),
KEY idx_customs_receipt_case (customs_case_id,visibility,uploaded_at),
CONSTRAINT fk_customs_receipt_case FOREIGN KEY (customs_case_id) REFERENCES fl_customs_case(id),
CONSTRAINT fk_customs_receipt_batch FOREIGN KEY (submission_batch_id) REFERENCES fl_customs_submission_batch(id),
CONSTRAINT chk_customs_receipt_type CHECK (receipt_type IN ('RECEIVED','DECLARED','REJECTED','INSPECTION','RELEASED','OTHER')),
CONSTRAINT chk_customs_receipt_visibility CHECK (visibility IN ('PLATFORM','CUSTOMER'))
) ENGINE=InnoDB COMMENT='报关代理回执版本与客户可见范围';
CREATE TABLE IF NOT EXISTS fl_customs_history (
id BIGINT UNSIGNED NOT NULL COMMENT '报关协同历史逻辑ID', customs_case_id BIGINT UNSIGNED NOT NULL COMMENT '所属报关协同单ID', action VARCHAR(40) NOT NULL COMMENT '业务动作编码,如CREATE、UPLOAD_DOCUMENT、REPLACE_DOCUMENT、REVIEW_DOCUMENT_APPROVE、REVIEW_DOCUMENT_RETURN、SUBMIT_AGENT_BATCH或UPLOAD_RECEIPT',
from_status VARCHAR(32) NULL COMMENT '动作发生前的协同状态;创建动作时为空', to_status VARCHAR(32) NULL COMMENT '动作完成后的协同状态', resource_type VARCHAR(32) NOT NULL COMMENT '动作关联资源类型:CASE协同单、DOCUMENT资料、SUBMISSION_BATCH提交批次或RECEIPT回执',
resource_id BIGINT UNSIGNED NOT NULL COMMENT '动作关联资源逻辑ID', note VARCHAR(500) NULL COMMENT '动作原因、资料项目编码或业务备注快照', operator_id BIGINT UNSIGNED NOT NULL COMMENT '执行业务动作的操作人ID',
operator_name VARCHAR(64) NULL COMMENT '执行动作时的操作人名称快照', operator_type VARCHAR(16) NOT NULL COMMENT '操作主体类型:PLATFORM平台操作人、MERCHANT客户操作人',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '历史记录创建时间', PRIMARY KEY (id),
KEY idx_customs_history_case (customs_case_id,created_at,id),
CONSTRAINT fk_customs_history_case FOREIGN KEY (customs_case_id) REFERENCES fl_customs_case(id),
CONSTRAINT chk_customs_history_actor CHECK (operator_type IN ('PLATFORM','MERCHANT'))
) ENGINE=InnoDB COMMENT='报关协同稳定历史';
CREATE TABLE IF NOT EXISTS fl_customs_operation (
id BIGINT UNSIGNED NOT NULL COMMENT '报关写命令幂等记录逻辑ID', operator_id BIGINT UNSIGNED NOT NULL COMMENT '发起写命令的操作人ID;与动作和幂等键共同限定重放范围', action VARCHAR(64) 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_type VARCHAR(24) NULL COMMENT '成功结果资源类型:CHECKLIST、CASE、DOCUMENT、BATCH或RECEIPT', result_id BIGINT UNSIGNED NULL COMMENT '成功结果资源逻辑ID;处理中为空',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '幂等记录创建时间', completed_at DATETIME(3) NULL COMMENT '写命令成功完成时间;处理中为空', PRIMARY KEY (id),
UNIQUE KEY uk_customs_operation (operator_id,action,idempotency_key),
CONSTRAINT chk_customs_operation_status CHECK (status IN ('PROCESSING','SUCCESS'))
) ENGINE=InnoDB COMMENT='报关协同命令幂等记录';
-- Latest container customs permissions; old case/review/receipt actions are removed.
USE baiyue_iam;
DROP PROCEDURE IF EXISTS assert_phase3_customs_permission_ids;
DELIMITER $$
CREATE PROCEDURE assert_phase3_customs_permission_ids()
BEGIN
IF EXISTS (
SELECT 1 FROM iam_permission
WHERE (id BETWEEN 5102170 AND 5102175
AND permission_code <> CASE id
WHEN 5102170 THEN 'platform:firstleg:customs:list'
WHEN 5102171 THEN 'platform:firstleg:customs:view'
WHEN 5102172 THEN 'platform:firstleg:customs:manage'
WHEN 5102173 THEN 'platform:firstleg:customs:review'
WHEN 5102174 THEN 'platform:firstleg:customs:submit'
WHEN 5102175 THEN 'platform:firstleg:customs:receipt'
END)
OR (permission_code LIKE 'platform:firstleg:customs:%'
AND (tenant_id <> 0 OR app_code <> 'PLATFORM' OR id NOT BETWEEN 5102170 AND 5102175))
) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '三期报关权限迁移失败:5102170-5102175 ID 或权限码被其他语义占用';
END IF;
END$$
DELIMITER ;
CALL assert_phase3_customs_permission_ids();
DROP PROCEDURE IF EXISTS assert_phase3_customs_permission_ids;
DELETE rp FROM iam_role_permission rp WHERE rp.permission_id IN (5102171,5102173,5102174,5102175);
DELETE FROM iam_permission WHERE id IN (5102171,5102173,5102174,5102175)
AND permission_code IN ('platform:firstleg:customs:view','platform:firstleg:customs:review','platform:firstleg:customs:submit','platform:firstleg:customs:receipt');
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)
(id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name,route_path,http_method,sort_no,status,built_in,deleted)
VALUES
(5102170,0,'PLATFORM','MENU',5102000,'platform:firstleg:customs:list','报关协同','/first-leg/customs','GET',100,'ACTIVE',1,0),
(5102171,0,'PLATFORM','BUTTON',5102170,'platform:firstleg:customs:view','查看报关协同',NULL,'GET',10,'ACTIVE',1,0),
(5102172,0,'PLATFORM','BUTTON',5102170,'platform:firstleg:customs:manage','维护报关资料',NULL,'POST',20,'ACTIVE',1,0),
(5102173,0,'PLATFORM','BUTTON',5102170,'platform:firstleg:customs:review','审核退回报关资料',NULL,'POST',30,'ACTIVE',1,0),
(5102174,0,'PLATFORM','BUTTON',5102170,'platform:firstleg:customs:submit','提交报关代理',NULL,'POST',40,'ACTIVE',1,0),
(5102175,0,'PLATFORM','BUTTON',5102170,'platform:firstleg:customs:receipt','维护报关回执',NULL,'POST',50,'ACTIVE',1,0)
(5102170,0,'PLATFORM','MENU',5102000,'platform:firstleg:customs:list','整柜报关','/first-leg/customs','GET',100,'ACTIVE',1,0),
(5102172,0,'PLATFORM','BUTTON',5102170,'platform:firstleg:customs:manage','维护整柜报关',NULL,'POST',20,'ACTIVE',1,0)
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),
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.app_code='PLATFORM'
AND permission.permission_code LIKE 'platform:firstleg:customs:%'
AND permission.permission_code IN ('platform:firstleg:customs:list','platform:firstleg:customs:manage')
WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR');
USE baiyue_firstleg;
-- Phase 3 loading evidence hardening for existing databases. Evidence is append-only:
-- multiple active/void records of the same type are allowed; voiding is an audit action.
USE baiyue_firstleg;
@@ -10140,11 +9992,12 @@ BEGIN
IF (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema='baiyue_firstleg' AND table_name IN (
'fl_outbound_dispatch','fl_outbound_dispatch_history','fl_outbound_dispatch_operation',
'fl_customs_checklist_version','fl_customs_case','fl_customs_document','fl_customs_supplement_request',
'fl_customs_submission_batch','fl_customs_receipt','fl_customs_history','fl_customs_operation',
'fl_customs_container','fl_customs_customer_document','fl_customs_customer_document_inbound',
'fl_customs_customer_document_version','fl_customs_frozen_document_inbound',
'fl_customs_completion_document','fl_customs_completion_document_version','fl_customs_container_history','fl_customs_command',
'fl_port_schedule','fl_port_schedule_history','fl_port_schedule_operation',
'fl_preload_loading_plan_link','fl_loading_pick_assignment','fl_loading_pick_review',
'fl_loading_pick_operation')) <> 18 THEN
'fl_loading_pick_operation')) <> 19 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='统一迁移失败:三期出仓、报关或船期表未完整创建';
END IF;
IF (SELECT COUNT(*) FROM information_schema.columns
@@ -10173,8 +10026,8 @@ BEGIN
WHERE table_schema='baiyue_firstleg' AND table_name='fl_outbound_dispatch'
AND index_name='uk_outbound_dispatch_owner' AND non_unique=0) <> 3
OR (SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_customs_case'
AND index_name='uk_customs_case_scope' AND non_unique=0) <> 4
WHERE table_schema='baiyue_firstleg' AND table_name='fl_customs_container'
AND index_name='uk_customs_container_plan' AND non_unique=0) <> 1
OR (SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_port_schedule'
AND index_name='uk_port_schedule_source' AND non_unique=0) <> 3 THEN
@@ -10182,9 +10035,9 @@ BEGIN
END IF;
IF (SELECT COUNT(*) FROM information_schema.referential_constraints
WHERE constraint_schema='baiyue_firstleg' AND constraint_name IN (
'fk_outbound_dispatch_inbound','fk_outbound_dispatch_container','fk_customs_case_checklist',
'fk_customs_document_case','fk_customs_supplement_case','fk_customs_batch_case',
'fk_customs_receipt_case','fk_customs_receipt_batch','fk_customs_history_case',
'fk_outbound_dispatch_inbound','fk_outbound_dispatch_container','fk_customs_customer_document_container',
'fk_customs_document_inbound_document','fk_customs_customer_document_version','fk_customs_frozen_document',
'fk_customs_completion_source','fk_customs_completion_version','fk_customs_container_history',
'fk_port_schedule_booking','fk_port_schedule_container','fk_port_schedule_history',
'fk_port_schedule_operation','fk_preload_loading_inbound','fk_preload_loading_preload',
'fk_preload_loading_plan','fk_loading_pick_assignment_task','fk_loading_pick_review_task',
@@ -10202,7 +10055,7 @@ BEGIN
IF (SELECT COUNT(*) FROM baiyue_iam.iam_permission WHERE tenant_id=0 AND app_code='PLATFORM'
AND id BETWEEN 5102160 AND 5102164 AND permission_code LIKE 'platform:firstleg:outbound-dispatch:%') <> 5
OR (SELECT COUNT(*) FROM baiyue_iam.iam_permission WHERE tenant_id=0 AND app_code='PLATFORM'
AND id BETWEEN 5102170 AND 5102175 AND permission_code LIKE 'platform:firstleg:customs:%') <> 6
AND id IN (5102170,5102172) AND permission_code LIKE 'platform:firstleg:customs:%') <> 2
OR (SELECT COUNT(*) FROM baiyue_iam.iam_permission WHERE tenant_id=0 AND app_code='PLATFORM'
AND id BETWEEN 5102180 AND 5102183 AND permission_code LIKE 'platform:firstleg:port-schedule:%') <> 3 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='统一迁移失败:三期出仓、报关或船期权限未完整写入';
@@ -10219,7 +10072,7 @@ BEGIN
AND (p.permission_code LIKE 'platform:firstleg:outbound-dispatch:%'
OR p.permission_code LIKE 'platform:firstleg:customs:%'
OR p.permission_code LIKE 'platform:firstleg:port-schedule:%'
OR p.permission_code LIKE 'platform:firstleg:pda:%')) <> 36 THEN
OR p.permission_code LIKE 'platform:firstleg:pda:%')) <> 28 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='统一迁移失败:三期出仓、报关或船期角色授权未完整写入';
END IF;
END$$
@@ -12229,14 +12082,6 @@ CALL queue_table_comment('baiyue_firstleg', 'fl_container_document', '平台货
CALL queue_table_comment('baiyue_firstleg', 'fl_container_fee_detail', '柜次级人工应收应付费用来源;审核通过且参与结算后同步Finance');
CALL queue_table_comment('baiyue_firstleg', 'fl_customer_charge_rule', '客户头程计费规则版本');
CALL queue_table_comment('baiyue_firstleg', 'fl_customer_dimension_config', '客户固定四箱规尺寸配置');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_case', '三期订单报关协同聚合');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_checklist_version', '三期报关资料清单不可变版本');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_document', '报关客户文件版本引用');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_history', '报关协同稳定历史');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_operation', '报关协同命令幂等记录');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_receipt', '报关代理回执版本与客户可见范围');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_submission_batch', '报关代理提交批次及冻结文件版本');
CALL queue_table_comment('baiyue_firstleg', 'fl_customs_supplement_request', '报关补件请求');
CALL queue_table_comment('baiyue_firstleg', 'fl_fee_item', '平台公共费用项目主数据');
CALL queue_table_comment('baiyue_firstleg', 'fl_fulfillment_task', '头程履约任务表:接收订单事件后形成独立履约任务,管理指派、执行和完成状态');
CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_carton_label', '首次打印前冻结的实际箱号与订单货物明细映射');
@@ -12950,7 +12795,7 @@ CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'warehouse_
CALL queue_column_comment('baiyue_firstleg', 'fl_container_booking', 'warehouse_name', '装柜仓库名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_container_document', 'container_booking_id', '货柜预订ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_container_document', 'created_at', '创建时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_container_document', 'document_type', '文件类型:DESTINATION_CLEARANCE目的港清关、CUSTOMS_DECLARATION出口报关、DELIVERY_ORDER提货单、PICKUP_ORDER取货单');
CALL queue_column_comment('baiyue_firstleg', 'fl_container_document', 'document_type', '文件类型:DESTINATION_CLEARANCE目的港清关、DELIVERY_ORDER提货单、PICKUP_ORDER取货单');
CALL queue_column_comment('baiyue_firstleg', 'fl_container_document', 'file_id', 'File服务文件ID,不建立跨库外键');
CALL queue_column_comment('baiyue_firstleg', 'fl_container_document', 'file_name', '文件名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_container_document', 'file_url', '文件访问地址快照');
@@ -13024,114 +12869,6 @@ CALL queue_column_comment('baiyue_firstleg', 'fl_customer_dimension_config', 'te
CALL queue_column_comment('baiyue_firstleg', 'fl_customer_dimension_config', 'updated_at', '更新时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customer_dimension_config', 'updated_by', '最后修改人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customer_dimension_config', 'version', '乐观锁版本号');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'checklist_code', '创建协同单时的清单编码快照;源清单变化不回写');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'checklist_version_id', '本单冻结使用的报关资料清单版本ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'checklist_version_no', '创建协同单时的清单版本号快照;源清单变化不回写');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'container_booking_id', '关联柜次逻辑ID;0表示创建时尚未关联柜次');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'created_at', '协同单创建时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'created_by', '创建协同单的平台操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'created_by_name', '创建协同单时的平台操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'customs_no', '全局唯一报关协同单号');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'id', '报关协同单逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'inbound_id', 'Firstleg入库单逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'order_id', 'Order服务订单逻辑ID;跨库不建立外键');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'remark', '报关协同单内部业务备注');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'status', '协同状态:DOCUMENTS_PENDING待补资料、REVIEWING审核中、SUPPLEMENT_REQUIRED需补件、READY_TO_SUBMIT待提交代理、RECEIPT_PENDING待回执、RECEIPT_AVAILABLE已有回执、CLEARANCE_COMPLETED已放行、CANCELLED已取消');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'tenant_id', '客户ID和数据隔离键');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'updated_at', '协同单最后修改时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'updated_by', '最后修改协同单的平台操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'updated_by_name', '最后修改时的平台操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_case', 'version', '乐观锁版本号;每次状态变更递增');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'cargo_type', '清单适用的货物类型编码');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'channel_code', '清单适用的运输渠道编码');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'checklist_code', '报关资料清单编码;同一清单的多个版本共用');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'country_code', '清单适用的目的国家或地区编码');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'created_at', '清单版本创建时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'created_by', '创建清单版本的平台操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'created_by_name', '创建清单版本时的平台操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'id', '报关资料清单版本逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'items_json', '不可变清单项目数组;元素包含code项目编码、name项目名称和required是否必填');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'status', '清单版本状态:ACTIVE启用、RETIRED停用');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_checklist_version', 'version_no', '清单业务版本号');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'checklist_item_code', '对应冻结清单中的资料项目编码');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'customs_case_id', '所属报关协同单ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'document_version', '同一协同单和清单项目下的文件版本序号');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'file_hash', '文件内容SHA-256摘要;用于版本审计和幂等校验');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'file_id', 'File服务文件逻辑ID;跨库不建立外键');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'file_name', '上传或引用时的文件名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'id', '报关资料文件版本逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'replaces_document_id', '被本版本替换的上一资料版本ID;首个版本为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'review_reason', '审核退回原因或审核备注');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'reviewed_at', '资料审核时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'reviewed_by', '审核资料的平台操作人ID;未审核时为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'reviewed_by_name', '审核时的平台操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'status', '资料状态:UPLOADED待审核、APPROVED审核通过、RETURNED已退回、SUPERSEDED已被替换、FROZEN已随代理提交批次冻结');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'uploaded_at', '资料上传或引用时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'uploaded_by', '上传或引用资料的操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'uploaded_by_type', '上传主体类型:PLATFORM平台操作人、MERCHANT客户操作人');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_document', 'visibility', '资料可见范围:PLATFORM仅平台可见、CUSTOMER客户可见');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'action', '业务动作编码,如CREATE、UPLOAD_DOCUMENT、REPLACE_DOCUMENT、REVIEW_DOCUMENT_APPROVE、REVIEW_DOCUMENT_RETURN、SUBMIT_AGENT_BATCH或UPLOAD_RECEIPT');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'created_at', '历史记录创建时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'customs_case_id', '所属报关协同单ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'from_status', '动作发生前的协同状态;创建动作时为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'id', '报关协同历史逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'note', '动作原因、资料项目编码或业务备注快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'operator_id', '执行业务动作的操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'operator_name', '执行动作时的操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'operator_type', '操作主体类型:PLATFORM平台操作人、MERCHANT客户操作人');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'resource_id', '动作关联资源逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'resource_type', '动作关联资源类型:CASE协同单、DOCUMENT资料、SUBMISSION_BATCH提交批次或RECEIPT回执');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_history', 'to_status', '动作完成后的协同状态');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'action', '幂等业务动作编码,包含平台或客户动作及资料、审核、提交、回执类型');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'completed_at', '写命令成功完成时间;处理中为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'created_at', '幂等记录创建时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'id', '报关写命令幂等记录逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'idempotency_key', '客户端提供的幂等键');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'operator_id', '发起写命令的操作人ID;与动作和幂等键共同限定重放范围');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'request_hash', '规范化完整请求内容的SHA-256摘要;同键不同请求时拒绝');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'result_id', '成功结果资源逻辑ID;处理中为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'result_type', '成功结果资源类型:CHECKLIST、CASE、DOCUMENT、BATCH或RECEIPT');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_operation', 'status', '幂等处理状态:PROCESSING处理中、SUCCESS处理成功');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'customs_case_id', '所属报关协同单ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'file_hash', '回执文件内容SHA-256摘要;用于版本审计和幂等校验');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'file_id', 'File服务回执文件逻辑ID;跨库不建立外键');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'file_name', '上传或引用时的回执文件名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'id', '报关回执文件版本逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'note', '回执业务备注');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'receipt_type', '回执类型:RECEIVED已收件、DECLARED已申报、REJECTED已拒绝、INSPECTION查验通知、RELEASED放行回执、OTHER其他回执');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'receipt_version', '同一提交批次和回执类型下的版本序号');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'replaces_receipt_id', '被本版本替换的上一回执版本ID;首个版本为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'submission_batch_id', '产生本回执的报关代理提交批次ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'uploaded_at', '回执上传或引用时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'uploaded_by', '上传或引用回执的平台操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'uploaded_by_name', '上传回执时的平台操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_receipt', 'visibility', '回执可见范围:PLATFORM仅平台可见、CUSTOMER客户可查询下载');
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');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'id', '报关代理提交批次逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'note', '提交报关代理时的平台备注');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'status', '代理提交状态:SUBMITTED已提交、ACKNOWLEDGED代理已确认、REJECTED代理已拒绝、COMPLETED代理处理完成');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'submitted_at', '提交报关代理时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'submitted_by', '提交报关代理的平台操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_submission_batch', 'submitted_by_name', '提交时的平台操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'checklist_item_code', '需要补充的报关资料项目编码');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'customs_case_id', '所属报关协同单ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'due_at', '期望完成补件时间;未设置时为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'id', '报关补件请求逻辑ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'reason', '平台审核人员填写的补件原因');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'requested_at', '补件请求发起时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'requested_by', '发起补件的平台操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'requested_by_name', '发起补件时的平台操作人名称快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'resolved_at', '补件请求解决时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'resolved_by', '提交解决资料的操作人ID;未解决时为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'resolved_document_id', '解决本次补件的新资料版本ID;未解决时为空');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'source_document_id', '触发本次补件的被退回资料版本ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_customs_supplement_request', 'status', '补件状态:OPEN待补件、RESOLVED已由新资料解决、CANCELLED已取消');
CALL queue_column_comment('baiyue_firstleg', 'fl_fee_item', 'allocation_fee', '平摊费用是否参与');
CALL queue_column_comment('baiyue_firstleg', 'fl_fee_item', 'category', '费用分类');
CALL queue_column_comment('baiyue_firstleg', 'fl_fee_item', 'created_at', '创建时间');
@@ -15821,7 +15558,7 @@ BEGIN
END IF;
END$$
DELIMITER ;
-- 货柜清关与装柜清单报关采用同一份轻量文件事实,不再要求独立报关 case 状态机。
-- 货柜目的港清关与DO/PU采用轻量文件事实;出口报关由customs-v1整柜聚合唯一承载。
USE baiyue_firstleg;
DROP PROCEDURE IF EXISTS phase3_simple_customs_add_column;
DELIMITER $$
@@ -15848,7 +15585,7 @@ SET @ddl = IF(@has_simple_customs_check=0, 'SELECT 1',
'ALTER TABLE fl_container_document DROP CHECK chk_container_document_type');
PREPARE statement FROM @ddl; EXECUTE statement; DEALLOCATE PREPARE statement;
ALTER TABLE fl_container_document ADD CONSTRAINT chk_container_document_type
CHECK (document_type IN ('DESTINATION_CLEARANCE','CUSTOMS_DECLARATION','DELIVERY_ORDER','PICKUP_ORDER'));
CHECK (document_type IN ('DESTINATION_CLEARANCE','DELIVERY_ORDER','PICKUP_ORDER'));
DROP TRIGGER IF EXISTS trg_container_document_before_insert;
DELIMITER $$
@@ -15856,7 +15593,7 @@ CREATE TRIGGER trg_container_document_before_insert BEFORE INSERT ON fl_containe
BEGIN
DECLARE current_plan_status VARCHAR(24);
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan WHERE container_booking_id=NEW.container_booking_id;
IF current_plan_status='COMPLETED' AND NEW.document_type NOT IN ('DESTINATION_CLEARANCE','CUSTOMS_DECLARATION','DELIVERY_ORDER','PICKUP_ORDER') THEN
IF current_plan_status='COMPLETED' AND NEW.document_type NOT IN ('DESTINATION_CLEARANCE','DELIVERY_ORDER','PICKUP_ORDER') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='装柜完成后货柜物流文件不可新增';
END IF;
END$$
@@ -15867,7 +15604,7 @@ CREATE TRIGGER trg_container_document_before_update BEFORE UPDATE ON fl_containe
BEGIN
DECLARE current_plan_status VARCHAR(24);
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan WHERE container_booking_id=OLD.container_booking_id;
IF current_plan_status='COMPLETED' AND OLD.document_type NOT IN ('DESTINATION_CLEARANCE','CUSTOMS_DECLARATION','DELIVERY_ORDER','PICKUP_ORDER') THEN
IF current_plan_status='COMPLETED' AND OLD.document_type NOT IN ('DESTINATION_CLEARANCE','DELIVERY_ORDER','PICKUP_ORDER') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='装柜完成后货柜物流文件不可修改';
END IF;
END$$
@@ -16603,6 +16340,77 @@ BEGIN
END$$
DELIMITER ;
-- 最新整柜报关基线:装柜完成后收集退税资料,按柜冻结、回传并自动收敛离仓。
USE baiyue_firstleg;
CREATE TABLE IF NOT EXISTS fl_customs_container(
id BIGINT UNSIGNED NOT NULL,loading_plan_id BIGINT UNSIGNED NOT NULL,container_booking_id BIGINT UNSIGNED NOT NULL,
status VARCHAR(40) NOT NULL,started_by BIGINT UNSIGNED NULL,started_by_name VARCHAR(64) NULL,started_at DATETIME(3) NULL,
completed_by BIGINT UNSIGNED NULL,completed_by_name VARCHAR(64) NULL,completed_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
version INT UNSIGNED NOT NULL DEFAULT 0,PRIMARY KEY(id),UNIQUE KEY uk_customs_container_plan(loading_plan_id),
UNIQUE KEY uk_customs_container_booking(container_booking_id),KEY idx_customs_container_status(status,updated_at),
CONSTRAINT chk_customs_container_status CHECK(status IN('WAITING_CUSTOMER_DOCUMENTS','READY_TO_START','DECLARING','COMPLETED'))
)ENGINE=InnoDB COMMENT='装柜完成后的整柜出口报关聚合';
CREATE TABLE IF NOT EXISTS fl_customs_customer_document(
id BIGINT UNSIGNED NOT NULL,customs_container_id BIGINT UNSIGNED NOT NULL,tenant_id BIGINT UNSIGNED NOT NULL,
file_id BIGINT UNSIGNED NOT NULL,file_name VARCHAR(255) NOT NULL,file_hash CHAR(64) NOT NULL,content_type VARCHAR(128) NULL,
size_bytes BIGINT UNSIGNED NOT NULL,status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',uploaded_by BIGINT UNSIGNED NOT NULL,
uploaded_at DATETIME(3) NOT NULL,frozen_version INT UNSIGNED NULL,frozen_at DATETIME(3) NULL,deleted_by BIGINT UNSIGNED NULL,
deleted_at DATETIME(3) NULL,version INT UNSIGNED NOT NULL DEFAULT 1,created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),PRIMARY KEY(id),
KEY idx_customs_customer_document_container(customs_container_id,status,tenant_id),
CONSTRAINT fk_customs_customer_document_container FOREIGN KEY(customs_container_id) REFERENCES fl_customs_container(id),
CONSTRAINT chk_customs_customer_document_status CHECK(status IN('ACTIVE','DELETED')),
CONSTRAINT chk_customs_customer_document_freeze CHECK((frozen_at IS NULL AND frozen_version IS NULL)OR(frozen_at IS NOT NULL AND frozen_version IS NOT NULL))
)ENGINE=InnoDB COMMENT='客户整份退税报送资料逻辑根';
CREATE TABLE IF NOT EXISTS fl_customs_customer_document_inbound(
document_id BIGINT UNSIGNED NOT NULL,inbound_id BIGINT UNSIGNED NOT NULL,tenant_id BIGINT UNSIGNED NOT NULL,
order_id BIGINT UNSIGNED NOT NULL,inbound_code VARCHAR(40) NOT NULL,created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY(document_id,inbound_id),KEY idx_customs_document_inbound(inbound_id,tenant_id),
CONSTRAINT fk_customs_document_inbound_document FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id)
)ENGINE=InnoDB COMMENT='客户报送资料与当前柜退税入仓码多对多关系';
CREATE TABLE IF NOT EXISTS fl_customs_customer_document_version(
id BIGINT UNSIGNED NOT NULL,document_id BIGINT UNSIGNED NOT NULL,document_version INT UNSIGNED NOT NULL,file_id BIGINT UNSIGNED NOT NULL,
file_name VARCHAR(255) NOT NULL,file_hash CHAR(64) NOT NULL,content_type VARCHAR(128) NULL,size_bytes BIGINT UNSIGNED NOT NULL,
scope_snapshot_json JSON NOT NULL,action VARCHAR(24) NOT NULL,operator_id BIGINT UNSIGNED NOT NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),PRIMARY KEY(id),UNIQUE KEY uk_customs_customer_document_version(document_id,document_version),
CONSTRAINT fk_customs_customer_document_version FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id),
CONSTRAINT chk_customs_customer_document_version_action CHECK(action IN('UPLOAD','REPLACE','SCOPE_CHANGE','DELETE'))
)ENGINE=InnoDB COMMENT='客户报送资料文件与覆盖范围不可变版本';
CREATE TABLE IF NOT EXISTS fl_customs_frozen_document_inbound(
document_id BIGINT UNSIGNED NOT NULL,inbound_id BIGINT UNSIGNED NOT NULL,tenant_id BIGINT UNSIGNED NOT NULL,
order_id BIGINT UNSIGNED NOT NULL,inbound_code VARCHAR(40) NOT NULL,created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY(document_id,inbound_id),CONSTRAINT fk_customs_frozen_document FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id)
)ENGINE=InnoDB COMMENT='开始报关时冻结的客户资料覆盖范围';
CREATE TABLE IF NOT EXISTS fl_customs_completion_document(
id BIGINT UNSIGNED NOT NULL,source_document_id BIGINT UNSIGNED NOT NULL,file_id BIGINT UNSIGNED NOT NULL,
file_name VARCHAR(255) NOT NULL,file_hash CHAR(64) NOT NULL,content_type VARCHAR(128) NULL,size_bytes BIGINT UNSIGNED NOT NULL,
uploaded_by BIGINT UNSIGNED NOT NULL,uploaded_by_name VARCHAR(64) NULL,uploaded_at DATETIME(3) NOT NULL,version INT UNSIGNED NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id),UNIQUE KEY uk_customs_completion_source(source_document_id),
CONSTRAINT fk_customs_completion_source FOREIGN KEY(source_document_id) REFERENCES fl_customs_customer_document(id)
)ENGINE=InnoDB COMMENT='报关完成文件当前版本';
CREATE TABLE IF NOT EXISTS fl_customs_completion_document_version(
id BIGINT UNSIGNED NOT NULL,completion_document_id BIGINT UNSIGNED NOT NULL,document_version INT UNSIGNED NOT NULL,
file_id BIGINT UNSIGNED NOT NULL,file_name VARCHAR(255) NOT NULL,file_hash CHAR(64) NOT NULL,content_type VARCHAR(128) NULL,
size_bytes BIGINT UNSIGNED NOT NULL,operator_id BIGINT UNSIGNED NOT NULL,operator_name VARCHAR(64) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),PRIMARY KEY(id),
UNIQUE KEY uk_customs_completion_version(completion_document_id,document_version),
CONSTRAINT fk_customs_completion_version FOREIGN KEY(completion_document_id) REFERENCES fl_customs_completion_document(id)
)ENGINE=InnoDB COMMENT='报关完成文件不可变覆盖版本';
CREATE TABLE IF NOT EXISTS fl_customs_container_history(
id BIGINT UNSIGNED NOT NULL,customs_container_id BIGINT UNSIGNED NOT NULL,action VARCHAR(40) NOT NULL,
from_status VARCHAR(40) NULL,to_status VARCHAR(40) NULL,remark VARCHAR(500) NULL,operator_id BIGINT UNSIGNED NOT NULL,
operator_name VARCHAR(64) NULL,created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),PRIMARY KEY(id),
KEY idx_customs_container_history(customs_container_id,created_at,id),
CONSTRAINT fk_customs_container_history FOREIGN KEY(customs_container_id) REFERENCES fl_customs_container(id)
)ENGINE=InnoDB COMMENT='整柜报关状态与系统触发历史';
CREATE TABLE IF NOT EXISTS fl_customs_command(
id BIGINT UNSIGNED NOT NULL,actor_id BIGINT UNSIGNED NOT NULL,action VARCHAR(80) NOT NULL,idempotency_key VARCHAR(128) NOT NULL,
request_hash CHAR(64) NOT NULL,status VARCHAR(16) NOT NULL,result_id BIGINT UNSIGNED NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),completed_at DATETIME(3) NULL,PRIMARY KEY(id),
UNIQUE KEY uk_customs_command(actor_id,action,idempotency_key),CONSTRAINT chk_customs_command_status CHECK(status IN('PROCESSING','SUCCESS'))
)ENGINE=InnoDB COMMENT='整柜报关写命令幂等事实';
CALL baiyue_firstleg.assert_unified_final_schema();
DROP PROCEDURE IF EXISTS baiyue_firstleg.assert_unified_final_schema;
SELECT 'PASS' AS migration_status,