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
@@ -0,0 +1,174 @@
SET NAMES utf8mb4;
USE baiyue_firstleg;
CREATE TABLE IF NOT EXISTS fl_customs_container (
id BIGINT UNSIGNED NOT NULL,
loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '已完成装柜计划ID;报关柜级聚合唯一键',
container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '物理货柜ID',
status VARCHAR(40) NOT NULL COMMENT 'WAITING_CUSTOMER_DOCUMENTS、READY_TO_START、DECLARING、COMPLETED',
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 COMMENT '客户隔离键;只允许关联同客户退税票',
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 COMMENT 'UPLOAD、REPLACE、SCOPE_CHANGE、DELETE',
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 COMMENT '一份冻结客户资料严格对应一份完成文件逻辑根',
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='整柜报关写命令幂等事实';
USE baiyue_iam;
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) VALUES
(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 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),status='ACTIVE',deleted=0;
INSERT IGNORE INTO iam_role_permission(role_id,permission_id,tenant_id)
SELECT r.id,p.id,0 FROM iam_role r JOIN iam_permission p ON p.tenant_id=0 AND p.app_code='PLATFORM'
AND p.permission_code IN('platform:firstleg:customs:list','platform:firstleg:customs:manage')
WHERE r.tenant_id=0 AND r.role_code IN('PLATFORM_ADMIN','ORDER_OPERATOR');