SET NAMES utf8mb4; USE baiyue_firstleg; CREATE TABLE IF NOT EXISTS fl_customs_checklist_version ( id BIGINT UNSIGNED NOT NULL, checklist_code VARCHAR(40) NOT NULL, version_no VARCHAR(32) NOT NULL, country_code VARCHAR(32) NOT NULL, channel_code VARCHAR(40) NOT NULL, cargo_type VARCHAR(40) NOT NULL, items_json JSON NOT NULL, status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', created_by BIGINT UNSIGNED NOT NULL, created_by_name VARCHAR(64) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), 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, customs_no VARCHAR(40) NOT NULL, tenant_id BIGINT UNSIGNED NOT NULL, order_id BIGINT UNSIGNED NOT NULL, inbound_id BIGINT UNSIGNED NOT NULL, container_booking_id BIGINT UNSIGNED NOT NULL DEFAULT 0, checklist_version_id BIGINT UNSIGNED NOT NULL, checklist_code VARCHAR(40) NOT NULL, checklist_version_no VARCHAR(32) NOT NULL, status VARCHAR(32) NOT NULL DEFAULT 'DOCUMENTS_PENDING', remark VARCHAR(500) NULL, created_by BIGINT UNSIGNED NOT NULL, created_by_name VARCHAR(64) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_by BIGINT UNSIGNED NOT NULL, updated_by_name VARCHAR(64) NULL, 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_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, customs_case_id BIGINT UNSIGNED NOT NULL, checklist_item_code VARCHAR(40) NOT NULL, file_id BIGINT UNSIGNED NOT NULL, document_version INT UNSIGNED NOT NULL, replaces_document_id BIGINT UNSIGNED NULL, file_name VARCHAR(255) NOT NULL, file_hash CHAR(64) NOT NULL, status VARCHAR(16) NOT NULL DEFAULT 'UPLOADED', visibility VARCHAR(16) NOT NULL DEFAULT 'CUSTOMER', uploaded_by BIGINT UNSIGNED NOT NULL, uploaded_by_type VARCHAR(16) NOT NULL, uploaded_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), reviewed_by BIGINT UNSIGNED NULL, reviewed_by_name VARCHAR(64) NULL, reviewed_at DATETIME(3) NULL, review_reason VARCHAR(500) NULL, 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, customs_case_id BIGINT UNSIGNED NOT NULL, source_document_id BIGINT UNSIGNED NOT NULL, resolved_document_id BIGINT UNSIGNED NULL, checklist_item_code VARCHAR(40) NOT NULL, reason VARCHAR(500) NOT NULL, due_at DATETIME(3) NULL, status VARCHAR(16) NOT NULL DEFAULT 'OPEN', requested_by BIGINT UNSIGNED NOT NULL, requested_by_name VARCHAR(64) NULL, requested_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), resolved_by BIGINT UNSIGNED NULL, resolved_at DATETIME(3) NULL, 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, customs_case_id BIGINT UNSIGNED NOT NULL, batch_no VARCHAR(40) NOT NULL, batch_version INT UNSIGNED NOT NULL, customs_agent_name VARCHAR(128) NOT NULL, external_reference VARCHAR(128) NULL, file_snapshot_json JSON NOT NULL, status VARCHAR(16) NOT NULL DEFAULT 'SUBMITTED', note VARCHAR(500) NULL, submitted_by BIGINT UNSIGNED NOT NULL, submitted_by_name VARCHAR(64) NULL, submitted_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), 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='报关代理提交批次及冻结文件版本'; CREATE TABLE IF NOT EXISTS fl_customs_receipt ( id BIGINT UNSIGNED NOT NULL, customs_case_id BIGINT UNSIGNED NOT NULL, submission_batch_id BIGINT UNSIGNED NOT NULL, receipt_type VARCHAR(16) NOT NULL, file_id BIGINT UNSIGNED NOT NULL, receipt_version INT UNSIGNED NOT NULL, replaces_receipt_id BIGINT UNSIGNED NULL, file_name VARCHAR(255) NOT NULL, file_hash CHAR(64) NOT NULL, visibility VARCHAR(16) NOT NULL DEFAULT 'PLATFORM', note VARCHAR(500) NULL, uploaded_by BIGINT UNSIGNED NOT NULL, uploaded_by_name VARCHAR(64) NULL, uploaded_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), 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, customs_case_id BIGINT UNSIGNED NOT NULL, action VARCHAR(40) NOT NULL, from_status VARCHAR(32) NULL, to_status VARCHAR(32) NULL, resource_type VARCHAR(32) NOT NULL, resource_id BIGINT UNSIGNED NOT NULL, note VARCHAR(500) NULL, operator_id BIGINT UNSIGNED NOT NULL, operator_name VARCHAR(64) NULL, operator_type VARCHAR(16) NOT NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), 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, operator_id BIGINT UNSIGNED NOT NULL, action VARCHAR(64) NOT NULL, idempotency_key VARCHAR(128) NOT NULL, request_hash CHAR(64) NOT NULL, status VARCHAR(16) NOT NULL DEFAULT 'PROCESSING', result_type VARCHAR(24) 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_operation (operator_id, action, idempotency_key), CONSTRAINT chk_customs_operation_status CHECK (status IN ('PROCESSING','SUCCESS')) ) ENGINE=InnoDB COMMENT='报关协同命令幂等记录'; 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; 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), (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) 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:%' WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR'); USE baiyue_firstleg;