数据:增加测试批次模型与迁移契约

This commit is contained in:
焦龙言
2026-09-22 14:37:31 +08:00
parent 40c56c6b33
commit 17bfa2c5fe
12 changed files with 1278 additions and 32 deletions
@@ -28,3 +28,14 @@ class PalletEventType(str, Enum):
USAGE_RECORDED = 'USAGE_RECORDED' USAGE_RECORDED = 'USAGE_RECORDED'
RETURN_REQUESTED = 'RETURN_REQUESTED' RETURN_REQUESTED = 'RETURN_REQUESTED'
RETURN_CONFIRMED = 'RETURN_CONFIRMED' RETURN_CONFIRMED = 'RETURN_CONFIRMED'
class TestBatchStatus(str, Enum):
ACTIVE = 'ACTIVE'
CLOSED = 'CLOSED'
PURGED = 'PURGED'
class TestBatchPreviewAction(str, Enum):
ADOPT = 'ADOPT'
PURGE = 'PURGE'
@@ -27,6 +27,13 @@ class BizStrain(Base):
) )
strain_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='菌种ID') strain_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='菌种ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
strain_code = Column(String(64), nullable=False, unique=True, comment='菌种编码') strain_code = Column(String(64), nullable=False, unique=True, comment='菌种编码')
strain_name = Column(String(100), nullable=False, comment='菌种名称') strain_name = Column(String(100), nullable=False, comment='菌种名称')
status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)') status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)')
@@ -52,6 +59,13 @@ class BizWarehouse(Base):
) )
warehouse_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='仓库ID') warehouse_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='仓库ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
warehouse_code = Column(String(64), nullable=False, unique=True, comment='仓库编码') warehouse_code = Column(String(64), nullable=False, unique=True, comment='仓库编码')
warehouse_name = Column(String(100), nullable=False, comment='仓库名称') warehouse_name = Column(String(100), nullable=False, comment='仓库名称')
address = Column(String(500), nullable=True, comment='仓库地址') address = Column(String(500), nullable=True, comment='仓库地址')
@@ -78,6 +92,13 @@ class BizCustomer(Base):
) )
customer_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='客户ID') customer_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='客户ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
customer_code = Column(String(64), nullable=False, unique=True, comment='客户编码') customer_code = Column(String(64), nullable=False, unique=True, comment='客户编码')
customer_name = Column(String(100), nullable=False, comment='客户名称') customer_name = Column(String(100), nullable=False, comment='客户名称')
status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)') status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)')
@@ -104,6 +125,13 @@ class BizCustomerSite(Base):
) )
site_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='现场ID') site_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='现场ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
customer_id = Column( customer_id = Column(
BigInteger, BigInteger,
ForeignKey('biz_customer.customer_id'), ForeignKey('biz_customer.customer_id'),
@@ -137,6 +165,13 @@ class BizProductionLine(Base):
) )
line_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='产线ID') line_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='产线ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
site_id = Column( site_id = Column(
BigInteger, BigInteger,
ForeignKey('biz_customer_site.site_id'), ForeignKey('biz_customer_site.site_id'),
@@ -169,6 +204,13 @@ class BizPallet(Base):
) )
pallet_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='托盘ID') pallet_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='托盘ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
pallet_code = Column(String(64), nullable=False, unique=True, comment='托盘编号') pallet_code = Column(String(64), nullable=False, unique=True, comment='托盘编号')
qr_token = Column(String(128), nullable=False, unique=True, comment='二维码固定标识') qr_token = Column(String(128), nullable=False, unique=True, comment='二维码固定标识')
capacity_packages = Column(Integer, nullable=False, comment='容量包数') capacity_packages = Column(Integer, nullable=False, comment='容量包数')
@@ -22,6 +22,13 @@ class BizInboundOrder(Base):
) )
inbound_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='入库单ID') inbound_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='入库单ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
inbound_no = Column(String(64), nullable=False, unique=True, comment='入库单号') inbound_no = Column(String(64), nullable=False, unique=True, comment='入库单号')
warehouse_id = Column( warehouse_id = Column(
BigInteger, BigInteger,
@@ -62,6 +69,13 @@ class BizInboundItem(Base):
autoincrement=True, autoincrement=True,
comment='入库明细ID', comment='入库明细ID',
) )
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
inbound_id = Column( inbound_id = Column(
BigInteger, BigInteger,
ForeignKey('biz_inbound_order.inbound_id'), ForeignKey('biz_inbound_order.inbound_id'),
@@ -93,6 +107,13 @@ class BizFillingRecord(Base):
) )
filling_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='装填记录ID') filling_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='装填记录ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
filling_no = Column(String(64), nullable=False, unique=True, comment='装填单号') filling_no = Column(String(64), nullable=False, unique=True, comment='装填单号')
pallet_id = Column(BigInteger, ForeignKey('biz_pallet.pallet_id'), nullable=False, comment='托盘ID') pallet_id = Column(BigInteger, ForeignKey('biz_pallet.pallet_id'), nullable=False, comment='托盘ID')
warehouse_id = Column( warehouse_id = Column(
@@ -141,6 +162,13 @@ class BizShipmentOrder(Base):
) )
shipment_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='发货单ID') shipment_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='发货单ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
shipment_no = Column(String(64), nullable=False, unique=True, comment='发货单号') shipment_no = Column(String(64), nullable=False, unique=True, comment='发货单号')
source_warehouse_id = Column( source_warehouse_id = Column(
BigInteger, BigInteger,
@@ -191,6 +219,13 @@ class BizShipmentItem(Base):
autoincrement=True, autoincrement=True,
comment='发货明细ID', comment='发货明细ID',
) )
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
shipment_id = Column( shipment_id = Column(
BigInteger, BigInteger,
ForeignKey('biz_shipment_order.shipment_id'), ForeignKey('biz_shipment_order.shipment_id'),
@@ -224,6 +259,13 @@ class BizUsageRecord(Base):
) )
usage_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='使用记录ID') usage_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='使用记录ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
usage_no = Column(String(64), nullable=False, unique=True, comment='使用记录号') usage_no = Column(String(64), nullable=False, unique=True, comment='使用记录号')
pallet_id = Column(BigInteger, ForeignKey('biz_pallet.pallet_id'), nullable=False, comment='托盘ID') pallet_id = Column(BigInteger, ForeignKey('biz_pallet.pallet_id'), nullable=False, comment='托盘ID')
active_filling_id = Column( active_filling_id = Column(
@@ -264,6 +306,13 @@ class BizReturnOrder(Base):
) )
return_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='退回单ID') return_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='退回单ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
return_no = Column(String(64), nullable=False, unique=True, comment='退回单号') return_no = Column(String(64), nullable=False, unique=True, comment='退回单号')
source_site_id = Column( source_site_id = Column(
BigInteger, BigInteger,
@@ -318,6 +367,13 @@ class BizReturnItem(Base):
autoincrement=True, autoincrement=True,
comment='退回明细ID', comment='退回明细ID',
) )
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
return_id = Column( return_id = Column(
BigInteger, BigInteger,
ForeignKey('biz_return_order.return_id'), ForeignKey('biz_return_order.return_id'),
@@ -363,6 +419,13 @@ class BizPalletInventory(Base):
autoincrement=False, autoincrement=False,
comment='托盘ID', comment='托盘ID',
) )
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
active_filling_id = Column( active_filling_id = Column(
BigInteger, BigInteger,
ForeignKey('biz_filling_record.filling_id'), ForeignKey('biz_filling_record.filling_id'),
@@ -415,6 +478,13 @@ class BizPalletEvent(Base):
) )
event_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='事件ID') event_id = Column(BigInteger, primary_key=True, nullable=False, autoincrement=True, comment='事件ID')
test_batch_id = Column(
BigInteger,
ForeignKey('biz_test_batch.batch_id'),
nullable=True,
index=True,
comment='测试数据批次ID;NULL表示正式数据',
)
pallet_id = Column(BigInteger, ForeignKey('biz_pallet.pallet_id'), nullable=False, comment='托盘ID') pallet_id = Column(BigInteger, ForeignKey('biz_pallet.pallet_id'), nullable=False, comment='托盘ID')
event_seq = Column(Integer, nullable=False, comment='托盘内事件序号') event_seq = Column(Integer, nullable=False, comment='托盘内事件序号')
event_type = Column(String(32), nullable=False, comment='事件类型') event_type = Column(String(32), nullable=False, comment='事件类型')
@@ -0,0 +1,49 @@
from datetime import datetime
from sqlalchemy import CHAR, BigInteger, CheckConstraint, Column, DateTime, ForeignKey, String, Text
from config.database import Base
class BizTestBatch(Base):
"""测试数据批次。"""
__tablename__ = 'biz_test_batch'
__table_args__ = (
CheckConstraint("status IN ('ACTIVE', 'CLOSED', 'PURGED')", name='ck_biz_test_batch_status'),
CheckConstraint(
"preview_action IS NULL OR preview_action IN ('ADOPT', 'PURGE')",
name='ck_biz_test_batch_preview_action',
),
{'comment': '测试数据批次'},
)
batch_id = Column(BigInteger, primary_key=True, autoincrement=True)
batch_code = Column(String(64), nullable=False, unique=True)
batch_name = Column(String(100), nullable=False)
status = Column(String(16), nullable=False, server_default='ACTIVE')
create_by = Column(String(64), nullable=False, server_default='')
create_time = Column(DateTime, nullable=False, default=datetime.now)
update_by = Column(String(64), nullable=False, server_default='')
update_time = Column(DateTime, nullable=False, default=datetime.now)
closed_by = Column(BigInteger, ForeignKey('sys_user.user_id'), nullable=True)
closed_at = Column(DateTime, nullable=True)
purged_by = Column(BigInteger, ForeignKey('sys_user.user_id'), nullable=True)
purged_at = Column(DateTime, nullable=True)
purge_summary = Column(Text, nullable=True)
preview_action = Column(String(16), nullable=True)
preview_token_hash = Column(CHAR(64), nullable=True)
preview_scope_hash = Column(CHAR(64), nullable=True)
preview_expires_at = Column(DateTime, nullable=True)
remark = Column(String(500), nullable=True)
class BizTestBatchUser(Base):
"""测试数据批次与用户关联。"""
__tablename__ = 'biz_test_batch_user'
batch_id = Column(BigInteger, ForeignKey('biz_test_batch.batch_id'), primary_key=True)
user_id = Column(BigInteger, ForeignKey('sys_user.user_id'), primary_key=True)
create_by = Column(String(64), nullable=False, server_default='')
create_time = Column(DateTime, nullable=False, default=datetime.now)
@@ -0,0 +1,116 @@
from datetime import datetime
from typing import Annotated, Literal
from pydantic import BaseModel, ConfigDict, Field
from pydantic.alias_generators import to_camel
from module_business.domain.enums import TestBatchStatus
PositiveId = Annotated[int, Field(gt=0)]
class TestBatchApiModel(BaseModel):
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
class TestBatchCreateModel(TestBatchApiModel):
batch_name: str = Field(min_length=1, max_length=100)
remark: str | None = Field(default=None, max_length=500)
class TestBatchEditModel(TestBatchApiModel):
remark: str | None = Field(default=None, max_length=500)
class TestBatchUserAssignModel(TestBatchApiModel):
user_ids: list[PositiveId]
class TestBatchModel(TestBatchApiModel):
batch_id: PositiveId
batch_code: str
batch_name: str
status: TestBatchStatus
remark: str | None = None
create_by: str
create_time: datetime
update_by: str
update_time: datetime
closed_by: int | None = None
closed_at: datetime | None = None
purged_by: int | None = None
purged_at: datetime | None = None
purge_summary: dict[str, int] | None = None
class TestBatchOptionModel(TestBatchApiModel):
batch_id: PositiveId
batch_code: str
batch_name: str
status: TestBatchStatus
class BatchImpactModel(TestBatchApiModel):
table_name: str
label: str
count: int = Field(ge=0)
keys: list[str]
class TestBatchDetailModel(TestBatchModel):
user_ids: list[int]
data_summary: list[BatchImpactModel]
class TestBatchPreviewModel(TestBatchApiModel):
batch_id: PositiveId
batch_name: str
preview_token: str
expires_at: datetime
total_count: int = Field(ge=0)
impacts: list[BatchImpactModel]
class PurgePreviewModel(TestBatchPreviewModel):
online_purge_allowed: bool
online_purge_limit: int = Field(ge=0)
blocking_reason: str | None = None
AdoptionRootType = Literal[
'strain',
'customer',
'site',
'line',
'warehouse',
'pallet',
'inbound',
'filling',
'shipment',
'usage',
'return',
]
class AdoptionRootModel(TestBatchApiModel):
resource_type: AdoptionRootType
resource_ids: list[PositiveId] = Field(min_length=1)
class AdoptionPreviewRequestModel(TestBatchApiModel):
roots: list[AdoptionRootModel] = Field(min_length=1)
class AdoptionExecuteRequestModel(AdoptionPreviewRequestModel):
batch_name: str = Field(min_length=1, max_length=100)
preview_token: str = Field(min_length=32, max_length=128)
class PurgeExecuteRequestModel(TestBatchApiModel):
batch_name: str = Field(min_length=1, max_length=100)
preview_token: str = Field(min_length=32, max_length=128)
@@ -0,0 +1,137 @@
-- 测试数据批次隔离:MySQL 增量补丁
-- 本补丁仅增加可空归属字段,不回填既有数据。
CREATE TABLE biz_test_batch (
batch_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '测试数据批次ID',
batch_code VARCHAR(64) NOT NULL COMMENT '批次编码',
batch_name VARCHAR(100) NOT NULL COMMENT '批次名称',
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '批次状态',
create_by VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者',
update_time DATETIME NOT NULL COMMENT '更新时间',
closed_by BIGINT NULL COMMENT '关闭人ID',
closed_at DATETIME NULL COMMENT '关闭时间',
purged_by BIGINT NULL COMMENT '清理人ID',
purged_at DATETIME NULL COMMENT '清理时间',
purge_summary TEXT NULL COMMENT '清理摘要JSON',
preview_action VARCHAR(16) NULL COMMENT '预览动作',
preview_token_hash CHAR(64) NULL COMMENT '预览令牌摘要',
preview_scope_hash CHAR(64) NULL COMMENT '预览范围摘要',
preview_expires_at DATETIME NULL COMMENT '预览过期时间',
remark VARCHAR(500) NULL COMMENT '备注',
PRIMARY KEY (batch_id),
CONSTRAINT uq_biz_test_batch_code UNIQUE (batch_code),
CONSTRAINT ck_biz_test_batch_status CHECK (status IN ('ACTIVE', 'CLOSED', 'PURGED')),
CONSTRAINT ck_biz_test_batch_preview_action CHECK (
preview_action IS NULL OR preview_action IN ('ADOPT', 'PURGE')
),
CONSTRAINT fk_biz_test_batch_closed_by FOREIGN KEY (closed_by) REFERENCES sys_user (user_id),
CONSTRAINT fk_biz_test_batch_purged_by FOREIGN KEY (purged_by) REFERENCES sys_user (user_id)
) ENGINE=InnoDB COMMENT='测试数据批次';
CREATE TABLE biz_test_batch_user (
batch_id BIGINT NOT NULL COMMENT '测试数据批次ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
create_by VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者',
create_time DATETIME NOT NULL COMMENT '创建时间',
PRIMARY KEY (batch_id, user_id),
CONSTRAINT fk_biz_test_batch_user_batch FOREIGN KEY (batch_id) REFERENCES biz_test_batch (batch_id),
CONSTRAINT fk_biz_test_batch_user_user FOREIGN KEY (user_id) REFERENCES sys_user (user_id)
) ENGINE=InnoDB COMMENT='测试数据批次与用户关联';
ALTER TABLE biz_strain
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_strain_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_strain_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_customer
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_customer_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_customer_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_customer_site
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_customer_site_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_customer_site_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_production_line
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_production_line_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_production_line_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_warehouse
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_warehouse_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_warehouse_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_pallet
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_pallet_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_pallet_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_inbound_order
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_inbound_order_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_inbound_order_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_inbound_item
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_inbound_item_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_inbound_item_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_filling_record
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_filling_record_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_filling_record_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_shipment_order
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_shipment_order_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_shipment_order_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_shipment_item
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_shipment_item_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_shipment_item_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_usage_record
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_usage_record_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_usage_record_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_return_order
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_return_order_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_return_order_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_return_item
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_return_item_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_return_item_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_pallet_inventory
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_pallet_inventory_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_pallet_inventory_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_pallet_event
ADD COLUMN test_batch_id BIGINT NULL COMMENT '测试数据批次ID;NULL表示正式数据',
ADD INDEX idx_biz_pallet_event_test_batch_id (test_batch_id),
ADD CONSTRAINT fk_biz_pallet_event_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
@@ -0,0 +1,139 @@
-- 测试数据批次隔离:PostgreSQL 增量补丁
-- 本补丁仅增加可空归属字段,不回填既有数据。
CREATE TABLE biz_test_batch (
batch_id BIGSERIAL NOT NULL,
batch_code VARCHAR(64) NOT NULL,
batch_name VARCHAR(100) NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
create_by VARCHAR(64) NOT NULL DEFAULT '',
create_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
update_by VARCHAR(64) NOT NULL DEFAULT '',
update_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
closed_by BIGINT NULL,
closed_at TIMESTAMP WITHOUT TIME ZONE NULL,
purged_by BIGINT NULL,
purged_at TIMESTAMP WITHOUT TIME ZONE NULL,
purge_summary TEXT NULL,
preview_action VARCHAR(16) NULL,
preview_token_hash CHAR(64) NULL,
preview_scope_hash CHAR(64) NULL,
preview_expires_at TIMESTAMP WITHOUT TIME ZONE NULL,
remark VARCHAR(500) NULL,
PRIMARY KEY (batch_id),
CONSTRAINT uq_biz_test_batch_code UNIQUE (batch_code),
CONSTRAINT ck_biz_test_batch_status CHECK (status IN ('ACTIVE', 'CLOSED', 'PURGED')),
CONSTRAINT ck_biz_test_batch_preview_action CHECK (
preview_action IS NULL OR preview_action IN ('ADOPT', 'PURGE')
),
CONSTRAINT fk_biz_test_batch_closed_by FOREIGN KEY (closed_by) REFERENCES sys_user (user_id),
CONSTRAINT fk_biz_test_batch_purged_by FOREIGN KEY (purged_by) REFERENCES sys_user (user_id)
);
COMMENT ON TABLE biz_test_batch IS '测试数据批次';
CREATE TABLE biz_test_batch_user (
batch_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
create_by VARCHAR(64) NOT NULL DEFAULT '',
create_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
PRIMARY KEY (batch_id, user_id),
CONSTRAINT fk_biz_test_batch_user_batch FOREIGN KEY (batch_id) REFERENCES biz_test_batch (batch_id),
CONSTRAINT fk_biz_test_batch_user_user FOREIGN KEY (user_id) REFERENCES sys_user (user_id)
);
COMMENT ON TABLE biz_test_batch_user IS '测试数据批次与用户关联';
ALTER TABLE biz_strain ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_strain.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_strain_test_batch_id ON biz_strain (test_batch_id);
ALTER TABLE biz_strain ADD CONSTRAINT fk_biz_strain_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_customer ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_customer.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_customer_test_batch_id ON biz_customer (test_batch_id);
ALTER TABLE biz_customer ADD CONSTRAINT fk_biz_customer_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_customer_site ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_customer_site.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_customer_site_test_batch_id ON biz_customer_site (test_batch_id);
ALTER TABLE biz_customer_site ADD CONSTRAINT fk_biz_customer_site_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_production_line ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_production_line.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_production_line_test_batch_id ON biz_production_line (test_batch_id);
ALTER TABLE biz_production_line ADD CONSTRAINT fk_biz_production_line_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_warehouse ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_warehouse.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_warehouse_test_batch_id ON biz_warehouse (test_batch_id);
ALTER TABLE biz_warehouse ADD CONSTRAINT fk_biz_warehouse_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_pallet ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_pallet.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_pallet_test_batch_id ON biz_pallet (test_batch_id);
ALTER TABLE biz_pallet ADD CONSTRAINT fk_biz_pallet_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_inbound_order ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_inbound_order.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_inbound_order_test_batch_id ON biz_inbound_order (test_batch_id);
ALTER TABLE biz_inbound_order ADD CONSTRAINT fk_biz_inbound_order_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_inbound_item ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_inbound_item.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_inbound_item_test_batch_id ON biz_inbound_item (test_batch_id);
ALTER TABLE biz_inbound_item ADD CONSTRAINT fk_biz_inbound_item_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_filling_record ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_filling_record.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_filling_record_test_batch_id ON biz_filling_record (test_batch_id);
ALTER TABLE biz_filling_record ADD CONSTRAINT fk_biz_filling_record_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_shipment_order ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_shipment_order.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_shipment_order_test_batch_id ON biz_shipment_order (test_batch_id);
ALTER TABLE biz_shipment_order ADD CONSTRAINT fk_biz_shipment_order_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_shipment_item ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_shipment_item.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_shipment_item_test_batch_id ON biz_shipment_item (test_batch_id);
ALTER TABLE biz_shipment_item ADD CONSTRAINT fk_biz_shipment_item_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_usage_record ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_usage_record.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_usage_record_test_batch_id ON biz_usage_record (test_batch_id);
ALTER TABLE biz_usage_record ADD CONSTRAINT fk_biz_usage_record_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_return_order ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_return_order.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_return_order_test_batch_id ON biz_return_order (test_batch_id);
ALTER TABLE biz_return_order ADD CONSTRAINT fk_biz_return_order_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_return_item ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_return_item.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_return_item_test_batch_id ON biz_return_item (test_batch_id);
ALTER TABLE biz_return_item ADD CONSTRAINT fk_biz_return_item_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_pallet_inventory ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_pallet_inventory.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_pallet_inventory_test_batch_id ON biz_pallet_inventory (test_batch_id);
ALTER TABLE biz_pallet_inventory ADD CONSTRAINT fk_biz_pallet_inventory_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
ALTER TABLE biz_pallet_event ADD COLUMN test_batch_id BIGINT NULL;
COMMENT ON COLUMN biz_pallet_event.test_batch_id IS '测试数据批次ID;NULL表示正式数据';
CREATE INDEX idx_biz_pallet_event_test_batch_id ON biz_pallet_event (test_batch_id);
ALTER TABLE biz_pallet_event ADD CONSTRAINT fk_biz_pallet_event_test_batch_id
FOREIGN KEY (test_batch_id) REFERENCES biz_test_batch (batch_id);
@@ -19,6 +19,8 @@ drop table if exists biz_customer_site;
drop table if exists biz_customer; drop table if exists biz_customer;
drop table if exists biz_warehouse; drop table if exists biz_warehouse;
drop table if exists biz_strain; drop table if exists biz_strain;
drop table if exists biz_test_batch_user;
drop table if exists biz_test_batch;
-- ---------------------------- -- ----------------------------
-- 1、部门表 -- 1、部门表
@@ -1076,8 +1078,48 @@ $$ IMMUTABLE STRICT LANGUAGE PLPGSQL;
-- ---------------------------- -- ----------------------------
-- 20、托盘流转业务表 -- 20、托盘流转业务表
-- ---------------------------- -- ----------------------------
create table biz_test_batch (
batch_id bigserial not null,
batch_code varchar(64) not null,
batch_name varchar(100) not null,
status varchar(16) not null default 'ACTIVE',
create_by varchar(64) not null default '',
create_time timestamp without time zone not null,
update_by varchar(64) not null default '',
update_time timestamp without time zone not null,
closed_by bigint,
closed_at timestamp without time zone,
purged_by bigint,
purged_at timestamp without time zone,
purge_summary text,
preview_action varchar(16),
preview_token_hash char(64),
preview_scope_hash char(64),
preview_expires_at timestamp without time zone,
remark varchar(500),
primary key (batch_id),
constraint uq_biz_test_batch_code unique (batch_code),
constraint ck_biz_test_batch_status check (status in ('ACTIVE', 'CLOSED', 'PURGED')),
constraint ck_biz_test_batch_preview_action check (preview_action is null or preview_action in ('ADOPT', 'PURGE')),
constraint fk_biz_test_batch_closed_by foreign key (closed_by) references sys_user(user_id),
constraint fk_biz_test_batch_purged_by foreign key (purged_by) references sys_user(user_id)
);
comment on table biz_test_batch is '测试数据批次';
create table biz_test_batch_user (
batch_id bigint not null,
user_id bigint not null,
create_by varchar(64) not null default '',
create_time timestamp without time zone not null,
primary key (batch_id, user_id),
constraint fk_biz_test_batch_user_batch foreign key (batch_id) references biz_test_batch(batch_id),
constraint fk_biz_test_batch_user_user foreign key (user_id) references sys_user(user_id)
);
comment on table biz_test_batch_user is '测试数据批次与用户关联';
create table biz_strain ( create table biz_strain (
strain_id bigserial not null, strain_id bigserial not null,
test_batch_id bigint null,
strain_code varchar(64) not null, strain_code varchar(64) not null,
strain_name varchar(100) not null, strain_name varchar(100) not null,
status char(1) not null default '0', status char(1) not null default '0',
@@ -1088,11 +1130,13 @@ create table biz_strain (
remark varchar(500) default null, remark varchar(500) default null,
primary key (strain_id), primary key (strain_id),
constraint uq_biz_strain_code unique (strain_code), constraint uq_biz_strain_code unique (strain_code),
constraint fk_biz_strain_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id),
constraint ck_biz_strain_status check (status in ('0', '1')) constraint ck_biz_strain_status check (status in ('0', '1'))
); );
create table biz_warehouse ( create table biz_warehouse (
warehouse_id bigserial not null, warehouse_id bigserial not null,
test_batch_id bigint null,
warehouse_code varchar(64) not null, warehouse_code varchar(64) not null,
warehouse_name varchar(100) not null, warehouse_name varchar(100) not null,
address varchar(500), address varchar(500),
@@ -1104,11 +1148,13 @@ create table biz_warehouse (
remark varchar(500) default null, remark varchar(500) default null,
primary key (warehouse_id), primary key (warehouse_id),
constraint uq_biz_warehouse_code unique (warehouse_code), constraint uq_biz_warehouse_code unique (warehouse_code),
constraint fk_biz_warehouse_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id),
constraint ck_biz_warehouse_status check (status in ('0', '1')) constraint ck_biz_warehouse_status check (status in ('0', '1'))
); );
create table biz_customer ( create table biz_customer (
customer_id bigserial not null, customer_id bigserial not null,
test_batch_id bigint null,
customer_code varchar(64) not null, customer_code varchar(64) not null,
customer_name varchar(100) not null, customer_name varchar(100) not null,
status char(1) not null default '0', status char(1) not null default '0',
@@ -1119,11 +1165,13 @@ create table biz_customer (
remark varchar(500) default null, remark varchar(500) default null,
primary key (customer_id), primary key (customer_id),
constraint uq_biz_customer_code unique (customer_code), constraint uq_biz_customer_code unique (customer_code),
constraint fk_biz_customer_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id),
constraint ck_biz_customer_status check (status in ('0', '1')) constraint ck_biz_customer_status check (status in ('0', '1'))
); );
create table biz_customer_site ( create table biz_customer_site (
site_id bigserial not null, site_id bigserial not null,
test_batch_id bigint null,
customer_id bigint not null, customer_id bigint not null,
site_code varchar(64) not null, site_code varchar(64) not null,
site_name varchar(100) not null, site_name varchar(100) not null,
@@ -1136,12 +1184,14 @@ create table biz_customer_site (
remark varchar(500) default null, remark varchar(500) default null,
primary key (site_id), primary key (site_id),
constraint uq_biz_customer_site_customer_code unique (customer_id, site_code), constraint uq_biz_customer_site_customer_code unique (customer_id, site_code),
constraint fk_biz_customer_site_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id),
constraint ck_biz_customer_site_status check (status in ('0', '1')), constraint ck_biz_customer_site_status check (status in ('0', '1')),
constraint fk_biz_customer_site_customer foreign key (customer_id) references biz_customer(customer_id) constraint fk_biz_customer_site_customer foreign key (customer_id) references biz_customer(customer_id)
); );
create table biz_production_line ( create table biz_production_line (
line_id bigserial not null, line_id bigserial not null,
test_batch_id bigint null,
site_id bigint not null, site_id bigint not null,
line_code varchar(64) not null, line_code varchar(64) not null,
line_name varchar(100) not null, line_name varchar(100) not null,
@@ -1153,12 +1203,14 @@ create table biz_production_line (
remark varchar(500) default null, remark varchar(500) default null,
primary key (line_id), primary key (line_id),
constraint uq_biz_production_line_site_code unique (site_id, line_code), constraint uq_biz_production_line_site_code unique (site_id, line_code),
constraint fk_biz_production_line_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id),
constraint ck_biz_production_line_status check (status in ('0', '1')), constraint ck_biz_production_line_status check (status in ('0', '1')),
constraint fk_biz_production_line_site foreign key (site_id) references biz_customer_site(site_id) constraint fk_biz_production_line_site foreign key (site_id) references biz_customer_site(site_id)
); );
create table biz_pallet ( create table biz_pallet (
pallet_id bigserial not null, pallet_id bigserial not null,
test_batch_id bigint null,
pallet_code varchar(64) not null, pallet_code varchar(64) not null,
qr_token varchar(128) not null, qr_token varchar(128) not null,
capacity_packages integer not null, capacity_packages integer not null,
@@ -1171,6 +1223,7 @@ create table biz_pallet (
primary key (pallet_id), primary key (pallet_id),
constraint uq_biz_pallet_code unique (pallet_code), constraint uq_biz_pallet_code unique (pallet_code),
constraint uq_biz_pallet_qr_token unique (qr_token), constraint uq_biz_pallet_qr_token unique (qr_token),
constraint fk_biz_pallet_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id),
constraint ck_biz_pallet_capacity_packages check (capacity_packages > 0), constraint ck_biz_pallet_capacity_packages check (capacity_packages > 0),
constraint ck_biz_pallet_asset_status check (asset_status in ('0', '1')) constraint ck_biz_pallet_asset_status check (asset_status in ('0', '1'))
); );
@@ -1197,6 +1250,7 @@ create table biz_user_site (
create table biz_inbound_order ( create table biz_inbound_order (
inbound_id bigserial not null, inbound_id bigserial not null,
test_batch_id bigint null,
inbound_no varchar(64) not null, inbound_no varchar(64) not null,
warehouse_id bigint not null, warehouse_id bigint not null,
status varchar(32) not null default 'DRAFT', status varchar(32) not null default 'DRAFT',
@@ -1213,12 +1267,14 @@ create table biz_inbound_order (
constraint uq_biz_inbound_order_no unique (inbound_no), constraint uq_biz_inbound_order_no unique (inbound_no),
constraint uq_biz_inbound_order_warehouse_confirm_idempotency unique (warehouse_id, confirm_idempotency_key), constraint uq_biz_inbound_order_warehouse_confirm_idempotency unique (warehouse_id, confirm_idempotency_key),
constraint ck_biz_inbound_order_status check (status in ('DRAFT', 'CONFIRMED')), constraint ck_biz_inbound_order_status check (status in ('DRAFT', 'CONFIRMED')),
constraint fk_biz_inbound_order_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id),
constraint fk_biz_inbound_order_warehouse foreign key (warehouse_id) references biz_warehouse(warehouse_id), constraint fk_biz_inbound_order_warehouse foreign key (warehouse_id) references biz_warehouse(warehouse_id),
constraint fk_biz_inbound_order_confirmer foreign key (confirmed_by) references sys_user(user_id) constraint fk_biz_inbound_order_confirmer foreign key (confirmed_by) references sys_user(user_id)
); );
create table biz_inbound_item ( create table biz_inbound_item (
inbound_item_id bigserial not null, inbound_item_id bigserial not null,
test_batch_id bigint null,
inbound_id bigint not null, inbound_id bigint not null,
pallet_id bigint not null, pallet_id bigint not null,
create_by varchar(64) default '', create_by varchar(64) default '',
@@ -1226,11 +1282,13 @@ create table biz_inbound_item (
primary key (inbound_item_id), primary key (inbound_item_id),
constraint uq_biz_inbound_item_order_pallet unique (inbound_id, pallet_id), constraint uq_biz_inbound_item_order_pallet unique (inbound_id, pallet_id),
constraint fk_biz_inbound_item_order foreign key (inbound_id) references biz_inbound_order(inbound_id), constraint fk_biz_inbound_item_order foreign key (inbound_id) references biz_inbound_order(inbound_id),
constraint fk_biz_inbound_item_pallet foreign key (pallet_id) references biz_pallet(pallet_id) constraint fk_biz_inbound_item_pallet foreign key (pallet_id) references biz_pallet(pallet_id),
constraint fk_biz_inbound_item_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_filling_record ( create table biz_filling_record (
filling_id bigserial not null, filling_id bigserial not null,
test_batch_id bigint null,
filling_no varchar(64) not null, filling_no varchar(64) not null,
pallet_id bigint not null, pallet_id bigint not null,
warehouse_id bigint not null, warehouse_id bigint not null,
@@ -1260,11 +1318,13 @@ create table biz_filling_record (
constraint fk_biz_filling_record_pallet foreign key (pallet_id) references biz_pallet(pallet_id), constraint fk_biz_filling_record_pallet foreign key (pallet_id) references biz_pallet(pallet_id),
constraint fk_biz_filling_record_warehouse foreign key (warehouse_id) references biz_warehouse(warehouse_id), constraint fk_biz_filling_record_warehouse foreign key (warehouse_id) references biz_warehouse(warehouse_id),
constraint fk_biz_filling_record_strain foreign key (strain_id) references biz_strain(strain_id), constraint fk_biz_filling_record_strain foreign key (strain_id) references biz_strain(strain_id),
constraint fk_biz_filling_record_operator foreign key (operator_id) references sys_user(user_id) constraint fk_biz_filling_record_operator foreign key (operator_id) references sys_user(user_id),
constraint fk_biz_filling_record_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_shipment_order ( create table biz_shipment_order (
shipment_id bigserial not null, shipment_id bigserial not null,
test_batch_id bigint null,
shipment_no varchar(64) not null, shipment_no varchar(64) not null,
source_warehouse_id bigint not null, source_warehouse_id bigint not null,
target_site_id bigint not null, target_site_id bigint not null,
@@ -1284,11 +1344,13 @@ create table biz_shipment_order (
constraint ck_biz_shipment_order_status check (status in ('DRAFT', 'CONFIRMED')), constraint ck_biz_shipment_order_status check (status in ('DRAFT', 'CONFIRMED')),
constraint fk_biz_shipment_order_warehouse foreign key (source_warehouse_id) references biz_warehouse(warehouse_id), constraint fk_biz_shipment_order_warehouse foreign key (source_warehouse_id) references biz_warehouse(warehouse_id),
constraint fk_biz_shipment_order_site foreign key (target_site_id) references biz_customer_site(site_id), constraint fk_biz_shipment_order_site foreign key (target_site_id) references biz_customer_site(site_id),
constraint fk_biz_shipment_order_confirmer foreign key (confirmed_by) references sys_user(user_id) constraint fk_biz_shipment_order_confirmer foreign key (confirmed_by) references sys_user(user_id),
constraint fk_biz_shipment_order_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_shipment_item ( create table biz_shipment_item (
shipment_item_id bigserial not null, shipment_item_id bigserial not null,
test_batch_id bigint null,
shipment_id bigint not null, shipment_id bigint not null,
pallet_id bigint not null, pallet_id bigint not null,
active_filling_id bigint, active_filling_id bigint,
@@ -1300,11 +1362,13 @@ create table biz_shipment_item (
constraint ck_biz_shipment_item_package_qty check (package_qty is null or package_qty > 0), constraint ck_biz_shipment_item_package_qty check (package_qty is null or package_qty > 0),
constraint fk_biz_shipment_item_order foreign key (shipment_id) references biz_shipment_order(shipment_id), constraint fk_biz_shipment_item_order foreign key (shipment_id) references biz_shipment_order(shipment_id),
constraint fk_biz_shipment_item_pallet foreign key (pallet_id) references biz_pallet(pallet_id), constraint fk_biz_shipment_item_pallet foreign key (pallet_id) references biz_pallet(pallet_id),
constraint fk_biz_shipment_item_filling foreign key (active_filling_id) references biz_filling_record(filling_id) constraint fk_biz_shipment_item_filling foreign key (active_filling_id) references biz_filling_record(filling_id),
constraint fk_biz_shipment_item_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_usage_record ( create table biz_usage_record (
usage_id bigserial not null, usage_id bigserial not null,
test_batch_id bigint null,
usage_no varchar(64) not null, usage_no varchar(64) not null,
pallet_id bigint not null, pallet_id bigint not null,
active_filling_id bigint not null, active_filling_id bigint not null,
@@ -1325,11 +1389,13 @@ create table biz_usage_record (
constraint fk_biz_usage_record_filling foreign key (active_filling_id) references biz_filling_record(filling_id), constraint fk_biz_usage_record_filling foreign key (active_filling_id) references biz_filling_record(filling_id),
constraint fk_biz_usage_record_site foreign key (site_id) references biz_customer_site(site_id), constraint fk_biz_usage_record_site foreign key (site_id) references biz_customer_site(site_id),
constraint fk_biz_usage_record_line foreign key (line_id) references biz_production_line(line_id), constraint fk_biz_usage_record_line foreign key (line_id) references biz_production_line(line_id),
constraint fk_biz_usage_record_operator foreign key (operator_id) references sys_user(user_id) constraint fk_biz_usage_record_operator foreign key (operator_id) references sys_user(user_id),
constraint fk_biz_usage_record_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_return_order ( create table biz_return_order (
return_id bigserial not null, return_id bigserial not null,
test_batch_id bigint null,
return_no varchar(64) not null, return_no varchar(64) not null,
source_site_id bigint not null, source_site_id bigint not null,
target_warehouse_id bigint not null, target_warehouse_id bigint not null,
@@ -1355,11 +1421,13 @@ create table biz_return_order (
constraint fk_biz_return_order_site foreign key (source_site_id) references biz_customer_site(site_id), constraint fk_biz_return_order_site foreign key (source_site_id) references biz_customer_site(site_id),
constraint fk_biz_return_order_warehouse foreign key (target_warehouse_id) references biz_warehouse(warehouse_id), constraint fk_biz_return_order_warehouse foreign key (target_warehouse_id) references biz_warehouse(warehouse_id),
constraint fk_biz_return_order_requester foreign key (requested_by) references sys_user(user_id), constraint fk_biz_return_order_requester foreign key (requested_by) references sys_user(user_id),
constraint fk_biz_return_order_confirmer foreign key (confirmed_by) references sys_user(user_id) constraint fk_biz_return_order_confirmer foreign key (confirmed_by) references sys_user(user_id),
constraint fk_biz_return_order_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_return_item ( create table biz_return_item (
return_item_id bigserial not null, return_item_id bigserial not null,
test_batch_id bigint null,
return_id bigint not null, return_id bigint not null,
pallet_id bigint not null, pallet_id bigint not null,
active_filling_id_snapshot bigint, active_filling_id_snapshot bigint,
@@ -1371,11 +1439,13 @@ create table biz_return_item (
constraint ck_biz_return_item_remaining_packages_snapshot check (remaining_packages_snapshot >= 0), constraint ck_biz_return_item_remaining_packages_snapshot check (remaining_packages_snapshot >= 0),
constraint fk_biz_return_item_order foreign key (return_id) references biz_return_order(return_id), constraint fk_biz_return_item_order foreign key (return_id) references biz_return_order(return_id),
constraint fk_biz_return_item_pallet foreign key (pallet_id) references biz_pallet(pallet_id), constraint fk_biz_return_item_pallet foreign key (pallet_id) references biz_pallet(pallet_id),
constraint fk_biz_return_item_filling foreign key (active_filling_id_snapshot) references biz_filling_record(filling_id) constraint fk_biz_return_item_filling foreign key (active_filling_id_snapshot) references biz_filling_record(filling_id),
constraint fk_biz_return_item_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_pallet_event ( create table biz_pallet_event (
event_id bigserial not null, event_id bigserial not null,
test_batch_id bigint null,
pallet_id bigint not null, pallet_id bigint not null,
event_seq integer not null, event_seq integer not null,
event_type varchar(32) not null, event_type varchar(32) not null,
@@ -1411,11 +1481,13 @@ create table biz_pallet_event (
constraint fk_biz_pallet_event_after_warehouse foreign key (after_warehouse_id) references biz_warehouse(warehouse_id), constraint fk_biz_pallet_event_after_warehouse foreign key (after_warehouse_id) references biz_warehouse(warehouse_id),
constraint fk_biz_pallet_event_after_site foreign key (after_site_id) references biz_customer_site(site_id), constraint fk_biz_pallet_event_after_site foreign key (after_site_id) references biz_customer_site(site_id),
constraint fk_biz_pallet_event_after_line foreign key (after_line_id) references biz_production_line(line_id), constraint fk_biz_pallet_event_after_line foreign key (after_line_id) references biz_production_line(line_id),
constraint fk_biz_pallet_event_operator foreign key (operator_id) references sys_user(user_id) constraint fk_biz_pallet_event_operator foreign key (operator_id) references sys_user(user_id),
constraint fk_biz_pallet_event_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
create table biz_pallet_inventory ( create table biz_pallet_inventory (
pallet_id bigint not null, pallet_id bigint not null,
test_batch_id bigint null,
active_filling_id bigint, active_filling_id bigint,
warehouse_id bigint, warehouse_id bigint,
site_id bigint, site_id bigint,
@@ -1442,9 +1514,43 @@ create table biz_pallet_inventory (
constraint fk_biz_pallet_inventory_warehouse foreign key (warehouse_id) references biz_warehouse(warehouse_id), constraint fk_biz_pallet_inventory_warehouse foreign key (warehouse_id) references biz_warehouse(warehouse_id),
constraint fk_biz_pallet_inventory_site foreign key (site_id) references biz_customer_site(site_id), constraint fk_biz_pallet_inventory_site foreign key (site_id) references biz_customer_site(site_id),
constraint fk_biz_pallet_inventory_line foreign key (current_line_id) references biz_production_line(line_id), constraint fk_biz_pallet_inventory_line foreign key (current_line_id) references biz_production_line(line_id),
constraint fk_biz_pallet_inventory_event foreign key (last_event_id) references biz_pallet_event(event_id) constraint fk_biz_pallet_inventory_event foreign key (last_event_id) references biz_pallet_event(event_id),
constraint fk_biz_pallet_inventory_test_batch_id foreign key (test_batch_id) references biz_test_batch(batch_id)
); );
comment on column biz_strain.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_strain_test_batch_id on biz_strain (test_batch_id);
comment on column biz_customer.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_customer_test_batch_id on biz_customer (test_batch_id);
comment on column biz_customer_site.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_customer_site_test_batch_id on biz_customer_site (test_batch_id);
comment on column biz_production_line.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_production_line_test_batch_id on biz_production_line (test_batch_id);
comment on column biz_warehouse.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_warehouse_test_batch_id on biz_warehouse (test_batch_id);
comment on column biz_pallet.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_pallet_test_batch_id on biz_pallet (test_batch_id);
comment on column biz_inbound_order.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_inbound_order_test_batch_id on biz_inbound_order (test_batch_id);
comment on column biz_inbound_item.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_inbound_item_test_batch_id on biz_inbound_item (test_batch_id);
comment on column biz_filling_record.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_filling_record_test_batch_id on biz_filling_record (test_batch_id);
comment on column biz_shipment_order.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_shipment_order_test_batch_id on biz_shipment_order (test_batch_id);
comment on column biz_shipment_item.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_shipment_item_test_batch_id on biz_shipment_item (test_batch_id);
comment on column biz_usage_record.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_usage_record_test_batch_id on biz_usage_record (test_batch_id);
comment on column biz_return_order.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_return_order_test_batch_id on biz_return_order (test_batch_id);
comment on column biz_return_item.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_return_item_test_batch_id on biz_return_item (test_batch_id);
comment on column biz_pallet_inventory.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_pallet_inventory_test_batch_id on biz_pallet_inventory (test_batch_id);
comment on column biz_pallet_event.test_batch_id is '测试数据批次ID;NULL表示正式数据';
create index idx_biz_pallet_event_test_batch_id on biz_pallet_event (test_batch_id);
-- ---------------------------- -- ----------------------------
-- 初始化-托盘业务一级菜单和权限 -- 初始化-托盘业务一级菜单和权限
-- ---------------------------- -- ----------------------------
@@ -19,6 +19,8 @@ drop table if exists biz_customer_site;
drop table if exists biz_customer; drop table if exists biz_customer;
drop table if exists biz_warehouse; drop table if exists biz_warehouse;
drop table if exists biz_strain; drop table if exists biz_strain;
drop table if exists biz_test_batch_user;
drop table if exists biz_test_batch;
-- ---------------------------- -- ----------------------------
-- 1、部门表 -- 1、部门表
@@ -811,9 +813,49 @@ create table gen_table_column (
-- ---------------------------- -- ----------------------------
-- 20、托盘业务表(按依赖创建) -- 20、托盘业务表(按依赖创建)
-- ---------------------------- -- ----------------------------
-- 测试数据批次
create table biz_test_batch (
batch_id bigint(20) not null auto_increment comment '测试数据批次ID',
batch_code varchar(64) not null comment '批次编码',
batch_name varchar(100) not null comment '批次名称',
status varchar(16) not null default 'ACTIVE' comment '批次状态',
create_by varchar(64) not null default '' comment '创建者',
create_time datetime not null comment '创建时间',
update_by varchar(64) not null default '' comment '更新者',
update_time datetime not null comment '更新时间',
closed_by bigint(20) comment '关闭人ID',
closed_at datetime comment '关闭时间',
purged_by bigint(20) comment '清理人ID',
purged_at datetime comment '清理时间',
purge_summary text comment '清理摘要JSON',
preview_action varchar(16) comment '预览动作',
preview_token_hash char(64) comment '预览令牌摘要',
preview_scope_hash char(64) comment '预览范围摘要',
preview_expires_at datetime comment '预览过期时间',
remark varchar(500) comment '备注',
primary key (batch_id),
constraint uq_biz_test_batch_code unique (batch_code),
constraint ck_biz_test_batch_status check (status in ('ACTIVE', 'CLOSED', 'PURGED')),
constraint ck_biz_test_batch_preview_action check (preview_action is null or preview_action in ('ADOPT', 'PURGE')),
constraint fk_biz_test_batch_closed_by foreign key (closed_by) references sys_user (user_id),
constraint fk_biz_test_batch_purged_by foreign key (purged_by) references sys_user (user_id)
) engine=innodb comment = '测试数据批次';
-- 测试数据批次与用户关联
create table biz_test_batch_user (
batch_id bigint(20) not null comment '测试数据批次ID',
user_id bigint(20) not null comment '用户ID',
create_by varchar(64) not null default '' comment '创建者',
create_time datetime not null comment '创建时间',
primary key (batch_id, user_id),
constraint fk_biz_test_batch_user_batch foreign key (batch_id) references biz_test_batch (batch_id),
constraint fk_biz_test_batch_user_user foreign key (user_id) references sys_user (user_id)
) engine=innodb comment = '测试数据批次与用户关联';
-- 菌种主数据表 -- 菌种主数据表
create table biz_strain ( create table biz_strain (
strain_id bigint(20) not null auto_increment comment '菌种ID', strain_id bigint(20) not null auto_increment comment '菌种ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
strain_code varchar(64) not null comment '菌种编码', strain_code varchar(64) not null comment '菌种编码',
strain_name varchar(100) not null comment '菌种名称', strain_name varchar(100) not null comment '菌种名称',
status char(1) not null default '0' comment '状态(0正常 1停用)', status char(1) not null default '0' comment '状态(0正常 1停用)',
@@ -823,13 +865,16 @@ create table biz_strain (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (strain_id), primary key (strain_id),
key idx_biz_strain_test_batch_id (test_batch_id),
constraint uq_biz_strain_code unique (strain_code), constraint uq_biz_strain_code unique (strain_code),
constraint fk_biz_strain_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_strain_status check (status in ('0', '1')) constraint ck_biz_strain_status check (status in ('0', '1'))
) engine=innodb comment = '菌种主数据表'; ) engine=innodb comment = '菌种主数据表';
-- 仓库主数据表 -- 仓库主数据表
create table biz_warehouse ( create table biz_warehouse (
warehouse_id bigint(20) not null auto_increment comment '仓库ID', warehouse_id bigint(20) not null auto_increment comment '仓库ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
warehouse_code varchar(64) not null comment '仓库编码', warehouse_code varchar(64) not null comment '仓库编码',
warehouse_name varchar(100) not null comment '仓库名称', warehouse_name varchar(100) not null comment '仓库名称',
address varchar(500) comment '仓库地址', address varchar(500) comment '仓库地址',
@@ -840,13 +885,16 @@ create table biz_warehouse (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (warehouse_id), primary key (warehouse_id),
key idx_biz_warehouse_test_batch_id (test_batch_id),
constraint uq_biz_warehouse_code unique (warehouse_code), constraint uq_biz_warehouse_code unique (warehouse_code),
constraint fk_biz_warehouse_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_warehouse_status check (status in ('0', '1')) constraint ck_biz_warehouse_status check (status in ('0', '1'))
) engine=innodb comment = '仓库主数据表'; ) engine=innodb comment = '仓库主数据表';
-- 客户主数据表 -- 客户主数据表
create table biz_customer ( create table biz_customer (
customer_id bigint(20) not null auto_increment comment '客户ID', customer_id bigint(20) not null auto_increment comment '客户ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
customer_code varchar(64) not null comment '客户编码', customer_code varchar(64) not null comment '客户编码',
customer_name varchar(100) not null comment '客户名称', customer_name varchar(100) not null comment '客户名称',
status char(1) not null default '0' comment '状态(0正常 1停用)', status char(1) not null default '0' comment '状态(0正常 1停用)',
@@ -856,13 +904,16 @@ create table biz_customer (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (customer_id), primary key (customer_id),
key idx_biz_customer_test_batch_id (test_batch_id),
constraint uq_biz_customer_code unique (customer_code), constraint uq_biz_customer_code unique (customer_code),
constraint fk_biz_customer_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_customer_status check (status in ('0', '1')) constraint ck_biz_customer_status check (status in ('0', '1'))
) engine=innodb comment = '客户主数据表'; ) engine=innodb comment = '客户主数据表';
-- 客户现场主数据表 -- 客户现场主数据表
create table biz_customer_site ( create table biz_customer_site (
site_id bigint(20) not null auto_increment comment '现场ID', site_id bigint(20) not null auto_increment comment '现场ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
customer_id bigint(20) not null comment '客户ID', customer_id bigint(20) not null comment '客户ID',
site_code varchar(64) not null comment '现场编码', site_code varchar(64) not null comment '现场编码',
site_name varchar(100) not null comment '现场名称', site_name varchar(100) not null comment '现场名称',
@@ -874,7 +925,9 @@ create table biz_customer_site (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (site_id), primary key (site_id),
key idx_biz_customer_site_test_batch_id (test_batch_id),
constraint uq_biz_customer_site_customer_code unique (customer_id, site_code), constraint uq_biz_customer_site_customer_code unique (customer_id, site_code),
constraint fk_biz_customer_site_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint fk_biz_customer_site_customer foreign key (customer_id) references biz_customer (customer_id), constraint fk_biz_customer_site_customer foreign key (customer_id) references biz_customer (customer_id),
constraint ck_biz_customer_site_status check (status in ('0', '1')) constraint ck_biz_customer_site_status check (status in ('0', '1'))
) engine=innodb comment = '客户现场主数据表'; ) engine=innodb comment = '客户现场主数据表';
@@ -882,6 +935,7 @@ create table biz_customer_site (
-- 客户现场产线主数据表 -- 客户现场产线主数据表
create table biz_production_line ( create table biz_production_line (
line_id bigint(20) not null auto_increment comment '产线ID', line_id bigint(20) not null auto_increment comment '产线ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
site_id bigint(20) not null comment '现场ID', site_id bigint(20) not null comment '现场ID',
line_code varchar(64) not null comment '产线编码', line_code varchar(64) not null comment '产线编码',
line_name varchar(100) not null comment '产线名称', line_name varchar(100) not null comment '产线名称',
@@ -892,7 +946,9 @@ create table biz_production_line (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (line_id), primary key (line_id),
key idx_biz_production_line_test_batch_id (test_batch_id),
constraint uq_biz_production_line_site_code unique (site_id, line_code), constraint uq_biz_production_line_site_code unique (site_id, line_code),
constraint fk_biz_production_line_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint fk_biz_production_line_site foreign key (site_id) references biz_customer_site (site_id), constraint fk_biz_production_line_site foreign key (site_id) references biz_customer_site (site_id),
constraint ck_biz_production_line_status check (status in ('0', '1')) constraint ck_biz_production_line_status check (status in ('0', '1'))
) engine=innodb comment = '客户现场产线主数据表'; ) engine=innodb comment = '客户现场产线主数据表';
@@ -900,6 +956,7 @@ create table biz_production_line (
-- 托盘资产主数据表 -- 托盘资产主数据表
create table biz_pallet ( create table biz_pallet (
pallet_id bigint(20) not null auto_increment comment '托盘ID', pallet_id bigint(20) not null auto_increment comment '托盘ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
pallet_code varchar(64) not null comment '托盘编号', pallet_code varchar(64) not null comment '托盘编号',
qr_token varchar(128) not null comment '二维码固定标识', qr_token varchar(128) not null comment '二维码固定标识',
capacity_packages int not null comment '容量包数', capacity_packages int not null comment '容量包数',
@@ -910,8 +967,10 @@ create table biz_pallet (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (pallet_id), primary key (pallet_id),
key idx_biz_pallet_test_batch_id (test_batch_id),
constraint uq_biz_pallet_code unique (pallet_code), constraint uq_biz_pallet_code unique (pallet_code),
constraint uq_biz_pallet_qr_token unique (qr_token), constraint uq_biz_pallet_qr_token unique (qr_token),
constraint fk_biz_pallet_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_pallet_capacity_packages check (capacity_packages > 0), constraint ck_biz_pallet_capacity_packages check (capacity_packages > 0),
constraint ck_biz_pallet_asset_status check (asset_status in ('0', '1')) constraint ck_biz_pallet_asset_status check (asset_status in ('0', '1'))
) engine=innodb comment = '托盘资产主数据表'; ) engine=innodb comment = '托盘资产主数据表';
@@ -941,6 +1000,7 @@ create table biz_user_site (
-- 首次入库单 -- 首次入库单
create table biz_inbound_order ( create table biz_inbound_order (
inbound_id bigint(20) not null auto_increment comment '入库单ID', inbound_id bigint(20) not null auto_increment comment '入库单ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
inbound_no varchar(64) not null comment '入库单号', inbound_no varchar(64) not null comment '入库单号',
warehouse_id bigint(20) not null comment '仓库ID', warehouse_id bigint(20) not null comment '仓库ID',
status varchar(32) not null default 'DRAFT' comment '单据状态', status varchar(32) not null default 'DRAFT' comment '单据状态',
@@ -954,29 +1014,35 @@ create table biz_inbound_order (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (inbound_id), primary key (inbound_id),
key idx_biz_inbound_order_test_batch_id (test_batch_id),
constraint uq_biz_inbound_order_no unique (inbound_no), constraint uq_biz_inbound_order_no unique (inbound_no),
constraint uq_biz_inbound_order_warehouse_confirm_idempotency unique (warehouse_id, confirm_idempotency_key), constraint uq_biz_inbound_order_warehouse_confirm_idempotency unique (warehouse_id, confirm_idempotency_key),
constraint fk_biz_inbound_order_warehouse foreign key (warehouse_id) references biz_warehouse (warehouse_id), constraint fk_biz_inbound_order_warehouse foreign key (warehouse_id) references biz_warehouse (warehouse_id),
constraint fk_biz_inbound_order_confirmed_by foreign key (confirmed_by) references sys_user (user_id), constraint fk_biz_inbound_order_confirmed_by foreign key (confirmed_by) references sys_user (user_id),
constraint fk_biz_inbound_order_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_inbound_order_status check (status in ('DRAFT', 'CONFIRMED')) constraint ck_biz_inbound_order_status check (status in ('DRAFT', 'CONFIRMED'))
) engine=innodb comment = '首次入库单'; ) engine=innodb comment = '首次入库单';
-- 首次入库单托盘明细 -- 首次入库单托盘明细
create table biz_inbound_item ( create table biz_inbound_item (
inbound_item_id bigint(20) not null auto_increment comment '入库明细ID', inbound_item_id bigint(20) not null auto_increment comment '入库明细ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
inbound_id bigint(20) not null comment '入库单ID', inbound_id bigint(20) not null comment '入库单ID',
pallet_id bigint(20) not null comment '托盘ID', pallet_id bigint(20) not null comment '托盘ID',
create_by varchar(64) default '' comment '创建者', create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间', create_time datetime comment '创建时间',
primary key (inbound_item_id), primary key (inbound_item_id),
key idx_biz_inbound_item_test_batch_id (test_batch_id),
constraint uq_biz_inbound_item_order_pallet unique (inbound_id, pallet_id), constraint uq_biz_inbound_item_order_pallet unique (inbound_id, pallet_id),
constraint fk_biz_inbound_item_order foreign key (inbound_id) references biz_inbound_order (inbound_id), constraint fk_biz_inbound_item_order foreign key (inbound_id) references biz_inbound_order (inbound_id),
constraint fk_biz_inbound_item_pallet foreign key (pallet_id) references biz_pallet (pallet_id) constraint fk_biz_inbound_item_pallet foreign key (pallet_id) references biz_pallet (pallet_id),
constraint fk_biz_inbound_item_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id)
) engine=innodb comment = '首次入库单托盘明细'; ) engine=innodb comment = '首次入库单托盘明细';
-- 托盘装填记录 -- 托盘装填记录
create table biz_filling_record ( create table biz_filling_record (
filling_id bigint(20) not null auto_increment comment '装填记录ID', filling_id bigint(20) not null auto_increment comment '装填记录ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
filling_no varchar(64) not null comment '装填单号', filling_no varchar(64) not null comment '装填单号',
pallet_id bigint(20) not null comment '托盘ID', pallet_id bigint(20) not null comment '托盘ID',
warehouse_id bigint(20) not null comment '仓库ID', warehouse_id bigint(20) not null comment '仓库ID',
@@ -998,6 +1064,7 @@ create table biz_filling_record (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (filling_id), primary key (filling_id),
key idx_biz_filling_record_test_batch_id (test_batch_id),
constraint uq_biz_filling_record_no unique (filling_no), constraint uq_biz_filling_record_no unique (filling_no),
constraint uq_biz_filling_record_warehouse_idempotency unique (warehouse_id, idempotency_key), constraint uq_biz_filling_record_warehouse_idempotency unique (warehouse_id, idempotency_key),
constraint uq_biz_filling_record_pallet_active_slot unique (pallet_id, active_slot), constraint uq_biz_filling_record_pallet_active_slot unique (pallet_id, active_slot),
@@ -1005,6 +1072,7 @@ create table biz_filling_record (
constraint fk_biz_filling_record_warehouse foreign key (warehouse_id) references biz_warehouse (warehouse_id), constraint fk_biz_filling_record_warehouse foreign key (warehouse_id) references biz_warehouse (warehouse_id),
constraint fk_biz_filling_record_strain foreign key (strain_id) references biz_strain (strain_id), constraint fk_biz_filling_record_strain foreign key (strain_id) references biz_strain (strain_id),
constraint fk_biz_filling_record_operator foreign key (operator_id) references sys_user (user_id), constraint fk_biz_filling_record_operator foreign key (operator_id) references sys_user (user_id),
constraint fk_biz_filling_record_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_filling_record_initial_packages check (initial_packages > 0), constraint ck_biz_filling_record_initial_packages check (initial_packages > 0),
constraint ck_biz_filling_record_active_slot check (active_slot is null or active_slot = 'ACTIVE') constraint ck_biz_filling_record_active_slot check (active_slot is null or active_slot = 'ACTIVE')
) engine=innodb comment = '托盘装填记录'; ) engine=innodb comment = '托盘装填记录';
@@ -1012,6 +1080,7 @@ create table biz_filling_record (
-- 整托发货单 -- 整托发货单
create table biz_shipment_order ( create table biz_shipment_order (
shipment_id bigint(20) not null auto_increment comment '发货单ID', shipment_id bigint(20) not null auto_increment comment '发货单ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
shipment_no varchar(64) not null comment '发货单号', shipment_no varchar(64) not null comment '发货单号',
source_warehouse_id bigint(20) not null comment '来源仓库ID', source_warehouse_id bigint(20) not null comment '来源仓库ID',
target_site_id bigint(20) not null comment '目标现场ID', target_site_id bigint(20) not null comment '目标现场ID',
@@ -1026,17 +1095,20 @@ create table biz_shipment_order (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (shipment_id), primary key (shipment_id),
key idx_biz_shipment_order_test_batch_id (test_batch_id),
constraint uq_biz_shipment_order_no unique (shipment_no), constraint uq_biz_shipment_order_no unique (shipment_no),
constraint uq_biz_shipment_order_route_confirm_idempotency unique (source_warehouse_id, target_site_id, confirm_idempotency_key), constraint uq_biz_shipment_order_route_confirm_idempotency unique (source_warehouse_id, target_site_id, confirm_idempotency_key),
constraint fk_biz_shipment_order_warehouse foreign key (source_warehouse_id) references biz_warehouse (warehouse_id), constraint fk_biz_shipment_order_warehouse foreign key (source_warehouse_id) references biz_warehouse (warehouse_id),
constraint fk_biz_shipment_order_site foreign key (target_site_id) references biz_customer_site (site_id), constraint fk_biz_shipment_order_site foreign key (target_site_id) references biz_customer_site (site_id),
constraint fk_biz_shipment_order_confirmed_by foreign key (confirmed_by) references sys_user (user_id), constraint fk_biz_shipment_order_confirmed_by foreign key (confirmed_by) references sys_user (user_id),
constraint fk_biz_shipment_order_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_shipment_order_status check (status in ('DRAFT', 'CONFIRMED')) constraint ck_biz_shipment_order_status check (status in ('DRAFT', 'CONFIRMED'))
) engine=innodb comment = '整托发货单'; ) engine=innodb comment = '整托发货单';
-- 整托发货明细 -- 整托发货明细
create table biz_shipment_item ( create table biz_shipment_item (
shipment_item_id bigint(20) not null auto_increment comment '发货明细ID', shipment_item_id bigint(20) not null auto_increment comment '发货明细ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
shipment_id bigint(20) not null comment '发货单ID', shipment_id bigint(20) not null comment '发货单ID',
pallet_id bigint(20) not null comment '托盘ID', pallet_id bigint(20) not null comment '托盘ID',
active_filling_id bigint(20) comment '确认时活动装填记录ID', active_filling_id bigint(20) comment '确认时活动装填记录ID',
@@ -1044,16 +1116,19 @@ create table biz_shipment_item (
create_by varchar(64) default '' comment '创建者', create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间', create_time datetime comment '创建时间',
primary key (shipment_item_id), primary key (shipment_item_id),
key idx_biz_shipment_item_test_batch_id (test_batch_id),
constraint uq_biz_shipment_item_order_pallet unique (shipment_id, pallet_id), constraint uq_biz_shipment_item_order_pallet unique (shipment_id, pallet_id),
constraint fk_biz_shipment_item_order foreign key (shipment_id) references biz_shipment_order (shipment_id), constraint fk_biz_shipment_item_order foreign key (shipment_id) references biz_shipment_order (shipment_id),
constraint fk_biz_shipment_item_pallet foreign key (pallet_id) references biz_pallet (pallet_id), constraint fk_biz_shipment_item_pallet foreign key (pallet_id) references biz_pallet (pallet_id),
constraint fk_biz_shipment_item_filling foreign key (active_filling_id) references biz_filling_record (filling_id), constraint fk_biz_shipment_item_filling foreign key (active_filling_id) references biz_filling_record (filling_id),
constraint fk_biz_shipment_item_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_shipment_item_package_qty check (package_qty is null or package_qty > 0) constraint ck_biz_shipment_item_package_qty check (package_qty is null or package_qty > 0)
) engine=innodb comment = '整托发货明细'; ) engine=innodb comment = '整托发货明细';
-- 客户现场使用事实记录 -- 客户现场使用事实记录
create table biz_usage_record ( create table biz_usage_record (
usage_id bigint(20) not null auto_increment comment '使用记录ID', usage_id bigint(20) not null auto_increment comment '使用记录ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
usage_no varchar(64) not null comment '使用记录号', usage_no varchar(64) not null comment '使用记录号',
pallet_id bigint(20) not null comment '托盘ID', pallet_id bigint(20) not null comment '托盘ID',
active_filling_id bigint(20) not null comment '活动装填记录ID', active_filling_id bigint(20) not null comment '活动装填记录ID',
@@ -1066,6 +1141,7 @@ create table biz_usage_record (
operator_id bigint(20) not null comment '操作人ID', operator_id bigint(20) not null comment '操作人ID',
occurred_at datetime not null comment '发生时间', occurred_at datetime not null comment '发生时间',
primary key (usage_id), primary key (usage_id),
key idx_biz_usage_record_test_batch_id (test_batch_id),
constraint uq_biz_usage_record_no unique (usage_no), constraint uq_biz_usage_record_no unique (usage_no),
constraint uq_biz_usage_record_site_idempotency unique (site_id, idempotency_key), constraint uq_biz_usage_record_site_idempotency unique (site_id, idempotency_key),
constraint fk_biz_usage_record_pallet foreign key (pallet_id) references biz_pallet (pallet_id), constraint fk_biz_usage_record_pallet foreign key (pallet_id) references biz_pallet (pallet_id),
@@ -1073,6 +1149,7 @@ create table biz_usage_record (
constraint fk_biz_usage_record_site foreign key (site_id) references biz_customer_site (site_id), constraint fk_biz_usage_record_site foreign key (site_id) references biz_customer_site (site_id),
constraint fk_biz_usage_record_line foreign key (line_id) references biz_production_line (line_id), constraint fk_biz_usage_record_line foreign key (line_id) references biz_production_line (line_id),
constraint fk_biz_usage_record_operator foreign key (operator_id) references sys_user (user_id), constraint fk_biz_usage_record_operator foreign key (operator_id) references sys_user (user_id),
constraint fk_biz_usage_record_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_usage_record_used_packages check (used_packages > 0), constraint ck_biz_usage_record_used_packages check (used_packages > 0),
constraint ck_biz_usage_record_remaining_packages_after check (remaining_packages_after >= 0) constraint ck_biz_usage_record_remaining_packages_after check (remaining_packages_after >= 0)
) engine=innodb comment = '客户现场使用事实记录'; ) engine=innodb comment = '客户现场使用事实记录';
@@ -1080,6 +1157,7 @@ create table biz_usage_record (
-- 托盘退回单 -- 托盘退回单
create table biz_return_order ( create table biz_return_order (
return_id bigint(20) not null auto_increment comment '退回单ID', return_id bigint(20) not null auto_increment comment '退回单ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
return_no varchar(64) not null comment '退回单号', return_no varchar(64) not null comment '退回单号',
source_site_id bigint(20) not null comment '来源现场ID', source_site_id bigint(20) not null comment '来源现场ID',
target_warehouse_id bigint(20) not null comment '目标仓库ID', target_warehouse_id bigint(20) not null comment '目标仓库ID',
@@ -1098,6 +1176,7 @@ create table biz_return_order (
update_time datetime comment '更新时间', update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注', remark varchar(500) default null comment '备注',
primary key (return_id), primary key (return_id),
key idx_biz_return_order_test_batch_id (test_batch_id),
constraint uq_biz_return_order_no unique (return_no), constraint uq_biz_return_order_no unique (return_no),
constraint uq_biz_return_order_route_request_idempotency unique (source_site_id, target_warehouse_id, request_idempotency_key), constraint uq_biz_return_order_route_request_idempotency unique (source_site_id, target_warehouse_id, request_idempotency_key),
constraint uq_biz_return_order_route_confirm_idempotency unique (source_site_id, target_warehouse_id, confirm_idempotency_key), constraint uq_biz_return_order_route_confirm_idempotency unique (source_site_id, target_warehouse_id, confirm_idempotency_key),
@@ -1105,12 +1184,14 @@ create table biz_return_order (
constraint fk_biz_return_order_warehouse foreign key (target_warehouse_id) references biz_warehouse (warehouse_id), constraint fk_biz_return_order_warehouse foreign key (target_warehouse_id) references biz_warehouse (warehouse_id),
constraint fk_biz_return_order_requested_by foreign key (requested_by) references sys_user (user_id), constraint fk_biz_return_order_requested_by foreign key (requested_by) references sys_user (user_id),
constraint fk_biz_return_order_confirmed_by foreign key (confirmed_by) references sys_user (user_id), constraint fk_biz_return_order_confirmed_by foreign key (confirmed_by) references sys_user (user_id),
constraint fk_biz_return_order_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_return_order_status check (status in ('REQUESTED', 'CONFIRMED')) constraint ck_biz_return_order_status check (status in ('REQUESTED', 'CONFIRMED'))
) engine=innodb comment = '托盘退回单'; ) engine=innodb comment = '托盘退回单';
-- 托盘退回明细 -- 托盘退回明细
create table biz_return_item ( create table biz_return_item (
return_item_id bigint(20) not null auto_increment comment '退回明细ID', return_item_id bigint(20) not null auto_increment comment '退回明细ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
return_id bigint(20) not null comment '退回单ID', return_id bigint(20) not null comment '退回单ID',
pallet_id bigint(20) not null comment '托盘ID', pallet_id bigint(20) not null comment '托盘ID',
active_filling_id_snapshot bigint(20) comment '申请时活动装填记录快照', active_filling_id_snapshot bigint(20) comment '申请时活动装填记录快照',
@@ -1118,16 +1199,19 @@ create table biz_return_item (
create_by varchar(64) default '' comment '创建者', create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间', create_time datetime comment '创建时间',
primary key (return_item_id), primary key (return_item_id),
key idx_biz_return_item_test_batch_id (test_batch_id),
constraint uq_biz_return_item_order_pallet unique (return_id, pallet_id), constraint uq_biz_return_item_order_pallet unique (return_id, pallet_id),
constraint fk_biz_return_item_order foreign key (return_id) references biz_return_order (return_id), constraint fk_biz_return_item_order foreign key (return_id) references biz_return_order (return_id),
constraint fk_biz_return_item_pallet foreign key (pallet_id) references biz_pallet (pallet_id), constraint fk_biz_return_item_pallet foreign key (pallet_id) references biz_pallet (pallet_id),
constraint fk_biz_return_item_filling foreign key (active_filling_id_snapshot) references biz_filling_record (filling_id), constraint fk_biz_return_item_filling foreign key (active_filling_id_snapshot) references biz_filling_record (filling_id),
constraint fk_biz_return_item_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_return_item_remaining_packages_snapshot check (remaining_packages_snapshot >= 0) constraint ck_biz_return_item_remaining_packages_snapshot check (remaining_packages_snapshot >= 0)
) engine=innodb comment = '托盘退回明细'; ) engine=innodb comment = '托盘退回明细';
-- 托盘只追加流转事件;必须先于库存快照创建 -- 托盘只追加流转事件;必须先于库存快照创建
create table biz_pallet_event ( create table biz_pallet_event (
event_id bigint(20) not null auto_increment comment '事件ID', event_id bigint(20) not null auto_increment comment '事件ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
pallet_id bigint(20) not null comment '托盘ID', pallet_id bigint(20) not null comment '托盘ID',
event_seq int not null comment '托盘内事件序号', event_seq int not null comment '托盘内事件序号',
event_type varchar(32) not null comment '事件类型', event_type varchar(32) not null comment '事件类型',
@@ -1148,6 +1232,7 @@ create table biz_pallet_event (
idempotency_key varchar(64) not null comment '幂等键', idempotency_key varchar(64) not null comment '幂等键',
request_hash varchar(64) not null comment '请求摘要', request_hash varchar(64) not null comment '请求摘要',
primary key (event_id), primary key (event_id),
key idx_biz_pallet_event_test_batch_id (test_batch_id),
constraint uq_biz_pallet_event_pallet_seq unique (pallet_id, event_seq), constraint uq_biz_pallet_event_pallet_seq unique (pallet_id, event_seq),
constraint uq_biz_pallet_event_pallet_idempotency unique (pallet_id, idempotency_key), constraint uq_biz_pallet_event_pallet_idempotency unique (pallet_id, idempotency_key),
constraint fk_biz_pallet_event_pallet foreign key (pallet_id) references biz_pallet (pallet_id), constraint fk_biz_pallet_event_pallet foreign key (pallet_id) references biz_pallet (pallet_id),
@@ -1158,6 +1243,7 @@ create table biz_pallet_event (
constraint fk_biz_pallet_event_after_site foreign key (after_site_id) references biz_customer_site (site_id), constraint fk_biz_pallet_event_after_site foreign key (after_site_id) references biz_customer_site (site_id),
constraint fk_biz_pallet_event_after_line foreign key (after_line_id) references biz_production_line (line_id), constraint fk_biz_pallet_event_after_line foreign key (after_line_id) references biz_production_line (line_id),
constraint fk_biz_pallet_event_operator foreign key (operator_id) references sys_user (user_id), constraint fk_biz_pallet_event_operator foreign key (operator_id) references sys_user (user_id),
constraint fk_biz_pallet_event_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_pallet_event_event_type check ( constraint ck_biz_pallet_event_event_type check (
event_type in ( event_type in (
'INBOUND_CONFIRMED', 'INBOUND_CONFIRMED',
@@ -1173,6 +1259,7 @@ create table biz_pallet_event (
-- 托盘当前库存、位置和流转状态 -- 托盘当前库存、位置和流转状态
create table biz_pallet_inventory ( create table biz_pallet_inventory (
pallet_id bigint(20) not null comment '托盘ID', pallet_id bigint(20) not null comment '托盘ID',
test_batch_id bigint(20) null comment '测试数据批次ID;NULL表示正式数据',
active_filling_id bigint(20) comment '当前活动装填记录ID', active_filling_id bigint(20) comment '当前活动装填记录ID',
warehouse_id bigint(20) comment '当前仓库ID', warehouse_id bigint(20) comment '当前仓库ID',
site_id bigint(20) comment '当前现场ID', site_id bigint(20) comment '当前现场ID',
@@ -1183,12 +1270,14 @@ create table biz_pallet_inventory (
version int not null default 0 comment '并发版本号', version int not null default 0 comment '并发版本号',
updated_at datetime not null comment '更新时间', updated_at datetime not null comment '更新时间',
primary key (pallet_id), primary key (pallet_id),
key idx_biz_pallet_inventory_test_batch_id (test_batch_id),
constraint fk_biz_pallet_inventory_pallet foreign key (pallet_id) references biz_pallet (pallet_id), constraint fk_biz_pallet_inventory_pallet foreign key (pallet_id) references biz_pallet (pallet_id),
constraint fk_biz_pallet_inventory_filling foreign key (active_filling_id) references biz_filling_record (filling_id), constraint fk_biz_pallet_inventory_filling foreign key (active_filling_id) references biz_filling_record (filling_id),
constraint fk_biz_pallet_inventory_warehouse foreign key (warehouse_id) references biz_warehouse (warehouse_id), constraint fk_biz_pallet_inventory_warehouse foreign key (warehouse_id) references biz_warehouse (warehouse_id),
constraint fk_biz_pallet_inventory_site foreign key (site_id) references biz_customer_site (site_id), constraint fk_biz_pallet_inventory_site foreign key (site_id) references biz_customer_site (site_id),
constraint fk_biz_pallet_inventory_line foreign key (current_line_id) references biz_production_line (line_id), constraint fk_biz_pallet_inventory_line foreign key (current_line_id) references biz_production_line (line_id),
constraint fk_biz_pallet_inventory_event foreign key (last_event_id) references biz_pallet_event (event_id), constraint fk_biz_pallet_inventory_event foreign key (last_event_id) references biz_pallet_event (event_id),
constraint fk_biz_pallet_inventory_test_batch_id foreign key (test_batch_id) references biz_test_batch (batch_id),
constraint ck_biz_pallet_inventory_flow_state check ( constraint ck_biz_pallet_inventory_flow_state check (
flow_state in ( flow_state in (
'UNSTOCKED', 'UNSTOCKED',
@@ -1,11 +1,32 @@
import unittest import unittest
from sqlalchemy import CHAR, BigInteger, CheckConstraint, DateTime, Integer, String, Table, UniqueConstraint from sqlalchemy import CHAR, BigInteger, CheckConstraint, DateTime, Integer, String, Table, Text, UniqueConstraint
from sqlalchemy.dialects import mysql, postgresql from sqlalchemy.dialects import mysql, postgresql
from sqlalchemy.schema import CreateColumn from sqlalchemy.schema import CreateColumn, CreateTable
from config.database import Base from config.database import Base
from module_business.entity.do import master_do, operation_do from module_admin.entity.do import user_do
from module_business.entity.do import master_do, operation_do, test_batch_do
EXPECTED_TEST_BATCH_TABLES = {'biz_test_batch', 'biz_test_batch_user'}
TEST_BATCH_OWNED_TABLES = {
'biz_strain',
'biz_customer',
'biz_customer_site',
'biz_production_line',
'biz_warehouse',
'biz_pallet',
'biz_inbound_order',
'biz_inbound_item',
'biz_filling_record',
'biz_shipment_order',
'biz_shipment_item',
'biz_usage_record',
'biz_return_order',
'biz_return_item',
'biz_pallet_inventory',
'biz_pallet_event',
}
EXPECTED_COLUMNS = { EXPECTED_COLUMNS = {
'biz_strain': { 'biz_strain': {
@@ -892,6 +913,136 @@ EXPECTED_UNIQUE_SETS = {
}, },
} }
for table_name in TEST_BATCH_OWNED_TABLES:
EXPECTED_COLUMNS[table_name].add('test_batch_id')
EXPECTED_COLUMN_TYPES[table_name]['test_batch_id'] = (BigInteger, None)
EXPECTED_NULLABILITY[table_name]['test_batch_id'] = True
EXPECTED_FOREIGN_KEYS[table_name].add(('test_batch_id', 'biz_test_batch.batch_id'))
EXPECTED_COLUMNS.update(
{
'biz_test_batch': {
'batch_id',
'batch_code',
'batch_name',
'status',
'create_by',
'create_time',
'update_by',
'update_time',
'closed_by',
'closed_at',
'purged_by',
'purged_at',
'purge_summary',
'preview_action',
'preview_token_hash',
'preview_scope_hash',
'preview_expires_at',
'remark',
},
'biz_test_batch_user': {'batch_id', 'user_id', 'create_by', 'create_time'},
}
)
EXPECTED_COLUMN_TYPES.update(
{
'biz_test_batch': {
'batch_id': (BigInteger, None),
'batch_code': (String, 64),
'batch_name': (String, 100),
'status': (String, 16),
'create_by': (String, 64),
'create_time': (DateTime, None),
'update_by': (String, 64),
'update_time': (DateTime, None),
'closed_by': (BigInteger, None),
'closed_at': (DateTime, None),
'purged_by': (BigInteger, None),
'purged_at': (DateTime, None),
'purge_summary': (Text, None),
'preview_action': (String, 16),
'preview_token_hash': (CHAR, 64),
'preview_scope_hash': (CHAR, 64),
'preview_expires_at': (DateTime, None),
'remark': (String, 500),
},
'biz_test_batch_user': {
'batch_id': (BigInteger, None),
'user_id': (BigInteger, None),
'create_by': (String, 64),
'create_time': (DateTime, None),
},
}
)
EXPECTED_NULLABILITY.update(
{
'biz_test_batch': {
'batch_id': False,
'batch_code': False,
'batch_name': False,
'status': False,
'create_by': False,
'create_time': False,
'update_by': False,
'update_time': False,
'closed_by': True,
'closed_at': True,
'purged_by': True,
'purged_at': True,
'purge_summary': True,
'preview_action': True,
'preview_token_hash': True,
'preview_scope_hash': True,
'preview_expires_at': True,
'remark': True,
},
'biz_test_batch_user': {
'batch_id': False,
'user_id': False,
'create_by': False,
'create_time': False,
},
}
)
EXPECTED_CALLABLE_DATETIME_DEFAULTS.update(
{
('biz_test_batch', 'create_time'),
('biz_test_batch', 'update_time'),
('biz_test_batch_user', 'create_time'),
}
)
EXPECTED_EMPTY_AUDIT_SERVER_DEFAULTS.update(
{
('biz_test_batch', 'create_by'),
('biz_test_batch', 'update_by'),
('biz_test_batch_user', 'create_by'),
}
)
EXPECTED_PRIMARY_KEYS.update(
{
'biz_test_batch': ('batch_id',),
'biz_test_batch_user': ('batch_id', 'user_id'),
}
)
EXPECTED_FOREIGN_KEYS.update(
{
'biz_test_batch': {
('closed_by', 'sys_user.user_id'),
('purged_by', 'sys_user.user_id'),
},
'biz_test_batch_user': {
('batch_id', 'biz_test_batch.batch_id'),
('user_id', 'sys_user.user_id'),
},
}
)
EXPECTED_UNIQUE_SETS.update(
{
'biz_test_batch': {frozenset({'batch_code'})},
'biz_test_batch_user': set(),
}
)
def _unique_column_sets(table: Table) -> set[frozenset[str]]: def _unique_column_sets(table: Table) -> set[frozenset[str]]:
return { return {
@@ -910,6 +1061,16 @@ def _normalized_check_sql(table: Table) -> dict[str, str]:
class BusinessModelContractTest(unittest.TestCase): class BusinessModelContractTest(unittest.TestCase):
def test_batch_related_tables_compile_for_mysql_and_postgresql(self) -> None:
self.assertIs(Base.metadata.tables['sys_user'], user_do.SysUser.__table__)
batch_tables = EXPECTED_TEST_BATCH_TABLES | TEST_BATCH_OWNED_TABLES
self.assertEqual(18, len(batch_tables))
for table_name in batch_tables:
for dialect_name, dialect in (('mysql', mysql.dialect()), ('postgresql', postgresql.dialect())):
with self.subTest(table_name=table_name, dialect=dialect_name):
compiled = str(CreateTable(Base.metadata.tables[table_name]).compile(dialect=dialect))
self.assertIn(table_name, compiled)
def test_exact_business_tables_are_registered(self) -> None: def test_exact_business_tables_are_registered(self) -> None:
expected = { expected = {
'biz_strain', 'biz_strain',
@@ -930,7 +1091,7 @@ class BusinessModelContractTest(unittest.TestCase):
'biz_return_item', 'biz_return_item',
'biz_pallet_inventory', 'biz_pallet_inventory',
'biz_pallet_event', 'biz_pallet_event',
} } | EXPECTED_TEST_BATCH_TABLES
actual = {name for name in Base.metadata.tables if name.startswith('biz_')} actual = {name for name in Base.metadata.tables if name.startswith('biz_')}
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@@ -954,6 +1115,8 @@ class BusinessModelContractTest(unittest.TestCase):
operation_do.BizReturnItem: 'biz_return_item', operation_do.BizReturnItem: 'biz_return_item',
operation_do.BizPalletInventory: 'biz_pallet_inventory', operation_do.BizPalletInventory: 'biz_pallet_inventory',
operation_do.BizPalletEvent: 'biz_pallet_event', operation_do.BizPalletEvent: 'biz_pallet_event',
test_batch_do.BizTestBatch: 'biz_test_batch',
test_batch_do.BizTestBatchUser: 'biz_test_batch_user',
} }
self.assertEqual(set(EXPECTED_COLUMNS), set(models.values())) self.assertEqual(set(EXPECTED_COLUMNS), set(models.values()))
for model, table_name in models.items(): for model, table_name in models.items():
@@ -1032,6 +1195,7 @@ class BusinessModelContractTest(unittest.TestCase):
_, separator, compiled_default = compiled_column.partition(' DEFAULT ') _, separator, compiled_default = compiled_column.partition(' DEFAULT ')
if separator: if separator:
compiled_default = compiled_default.split(' COMMENT ', maxsplit=1)[0].strip() compiled_default = compiled_default.split(' COMMENT ', maxsplit=1)[0].strip()
compiled_default = compiled_default.removesuffix(' NOT NULL')
if compiled_default != "''": if compiled_default != "''":
violations.append((dialect_name, table_name, column_name, compiled_default)) violations.append((dialect_name, table_name, column_name, compiled_default))
self.assertEqual([], violations) self.assertEqual([], violations)
@@ -1058,6 +1222,26 @@ class BusinessModelContractTest(unittest.TestCase):
with self.subTest(table_name=table_name): with self.subTest(table_name=table_name):
self.assertEqual(expected_unique_sets, _unique_column_sets(Base.metadata.tables[table_name])) self.assertEqual(expected_unique_sets, _unique_column_sets(Base.metadata.tables[table_name]))
def test_all_owned_models_have_nullable_indexed_batch_fk(self) -> None:
for table_name in TEST_BATCH_OWNED_TABLES:
table = Base.metadata.tables[table_name]
column = table.c.test_batch_id
self.assertTrue(column.nullable, table_name)
self.assertTrue(column.index, table_name)
fk = next(iter(column.foreign_keys))
self.assertEqual('biz_test_batch.batch_id', fk.target_fullname)
self.assertIsNone(fk.ondelete)
def test_test_batch_model_defaults_and_comments_match_contract(self) -> None:
table = Base.metadata.tables['biz_test_batch']
self.assertEqual('测试数据批次', table.comment)
self.assertEqual('ACTIVE', str(table.c.status.server_default.arg))
for table_name in TEST_BATCH_OWNED_TABLES:
self.assertEqual(
'测试数据批次ID;NULL表示正式数据',
Base.metadata.tables[table_name].c.test_batch_id.comment,
)
def test_pallet_identifiers_are_unique(self) -> None: def test_pallet_identifiers_are_unique(self) -> None:
table = Base.metadata.tables['biz_pallet'] table = Base.metadata.tables['biz_pallet']
unique_columns = {column.name for column in table.columns if column.unique} unique_columns = {column.name for column in table.columns if column.unique}
@@ -1065,6 +1249,10 @@ class BusinessModelContractTest(unittest.TestCase):
def test_checks_lock_quantities_states_active_slot_and_location(self) -> None: def test_checks_lock_quantities_states_active_slot_and_location(self) -> None:
expected_checks = { expected_checks = {
'biz_test_batch': {
'ck_biz_test_batch_status': "statusIN('ACTIVE','CLOSED','PURGED')",
'ck_biz_test_batch_preview_action': "preview_actionISNULLORpreview_actionIN('ADOPT','PURGE')",
},
'biz_strain': {'ck_biz_strain_status': "statusIN('0','1')"}, 'biz_strain': {'ck_biz_strain_status': "statusIN('0','1')"},
'biz_warehouse': {'ck_biz_warehouse_status': "statusIN('0','1')"}, 'biz_warehouse': {'ck_biz_warehouse_status': "statusIN('0','1')"},
'biz_customer': {'ck_biz_customer_status': "statusIN('0','1')"}, 'biz_customer': {'ck_biz_customer_status': "statusIN('0','1')"},
@@ -9,11 +9,33 @@ INITIALIZERS = ('shierfeng-fastapi.sql', 'shierfeng-fastapi-pg.sql')
PATCH_PATH = SQL_ROOT / 'patches/20260724_pallet_workflow_mysql.sql' PATCH_PATH = SQL_ROOT / 'patches/20260724_pallet_workflow_mysql.sql'
MENU_PROMOTION_PATCH_PATH = SQL_ROOT / 'patches/20260727_promote_business_menus_mysql.sql' MENU_PROMOTION_PATCH_PATH = SQL_ROOT / 'patches/20260727_promote_business_menus_mysql.sql'
BUSINESS_MENU_ICON_PATCH_PATH = SQL_ROOT / 'patches/20260728_add_business_menu_icons_mysql.sql' BUSINESS_MENU_ICON_PATCH_PATH = SQL_ROOT / 'patches/20260728_add_business_menu_icons_mysql.sql'
TEST_BATCH_MYSQL_PATCH_PATH = SQL_ROOT / 'patches/20260922_test_data_batch_mysql.sql'
TEST_BATCH_PG_PATCH_PATH = SQL_ROOT / 'patches/20260922_test_data_batch_pg.sql'
SYS_MENU_VALUE_COUNT = 20 SYS_MENU_VALUE_COUNT = 20
SYS_MENU_PERMS_INDEX = 13 SYS_MENU_PERMS_INDEX = 13
SYS_MENU_ICON_INDEX = 14 SYS_MENU_ICON_INDEX = 14
REMOVED_AI_DICT_CODES = set(range(33, 70)) REMOVED_AI_DICT_CODES = set(range(33, 70))
EXPECTED_TEST_BATCH_TABLES = {'biz_test_batch', 'biz_test_batch_user'}
TEST_BATCH_OWNED_TABLES = {
'biz_strain',
'biz_customer',
'biz_customer_site',
'biz_production_line',
'biz_warehouse',
'biz_pallet',
'biz_inbound_order',
'biz_inbound_item',
'biz_filling_record',
'biz_shipment_order',
'biz_shipment_item',
'biz_usage_record',
'biz_return_order',
'biz_return_item',
'biz_pallet_inventory',
'biz_pallet_event',
}
EXPECTED_TABLES = { EXPECTED_TABLES = {
'biz_strain', 'biz_strain',
'biz_warehouse', 'biz_warehouse',
@@ -346,6 +368,83 @@ EXPECTED_CHECKS = {
}, },
} }
LEGACY_EXPECTED_TABLES = set(EXPECTED_TABLES)
LEGACY_EXPECTED_COLUMNS = {table: set(columns) for table, columns in EXPECTED_COLUMNS.items()}
LEGACY_EXPECTED_PRIMARY_KEYS = dict(EXPECTED_PRIMARY_KEYS)
LEGACY_EXPECTED_UNIQUE_KEYS = {table: set(keys) for table, keys in EXPECTED_UNIQUE_KEYS.items()}
LEGACY_EXPECTED_FOREIGN_KEYS = {table: set(keys) for table, keys in EXPECTED_FOREIGN_KEYS.items()}
LEGACY_EXPECTED_CHECKS = {table: set(checks) for table, checks in EXPECTED_CHECKS.items()}
EXPECTED_TABLES |= EXPECTED_TEST_BATCH_TABLES
for table_name in TEST_BATCH_OWNED_TABLES:
EXPECTED_COLUMNS[table_name].add('test_batch_id')
EXPECTED_FOREIGN_KEYS[table_name].add(('test_batch_id', 'biz_test_batch.batch_id'))
EXPECTED_COLUMNS.update(
{
'biz_test_batch': {
'batch_id',
'batch_code',
'batch_name',
'status',
'create_by',
'create_time',
'update_by',
'update_time',
'closed_by',
'closed_at',
'purged_by',
'purged_at',
'purge_summary',
'preview_action',
'preview_token_hash',
'preview_scope_hash',
'preview_expires_at',
'remark',
},
'biz_test_batch_user': {'batch_id', 'user_id', 'create_by', 'create_time'},
}
)
EXPECTED_DATETIME_COLUMNS.update(
{
'biz_test_batch': {'create_time', 'update_time', 'closed_at', 'purged_at', 'preview_expires_at'},
'biz_test_batch_user': {'create_time'},
}
)
EXPECTED_PRIMARY_KEYS.update(
{
'biz_test_batch': ('batch_id',),
'biz_test_batch_user': ('batch_id', 'user_id'),
}
)
EXPECTED_UNIQUE_KEYS.update(
{
'biz_test_batch': {('batch_code',)},
'biz_test_batch_user': set(),
}
)
EXPECTED_FOREIGN_KEYS.update(
{
'biz_test_batch': {
('closed_by', 'sys_user.user_id'),
('purged_by', 'sys_user.user_id'),
},
'biz_test_batch_user': {
('batch_id', 'biz_test_batch.batch_id'),
('user_id', 'sys_user.user_id'),
},
}
)
EXPECTED_CHECKS.update(
{
'biz_test_batch': {
"statusin('active','closed','purged')",
"preview_actionisnullorpreview_actionin('adopt','purge')",
},
'biz_test_batch_user': set(),
}
)
EXPECTED_PAGES = { EXPECTED_PAGES = {
502: ('菌种资料', 121, 1, 'strain', 'master/strain/index', 'master:strain:list'), 502: ('菌种资料', 121, 1, 'strain', 'master/strain/index', 'master:strain:list'),
503: ('客户资料', 121, 2, 'customer', 'master/customer/index', 'master:customer:list'), 503: ('客户资料', 121, 2, 'customer', 'master/customer/index', 'master:customer:list'),
@@ -873,6 +972,74 @@ def _is_postgres_naive_timestamp_with_default_precision(definition: str) -> bool
) )
def _assert_test_batch_sql_contract(
test_case: unittest.TestCase,
sql: str,
*,
dialect: str,
is_patch: bool,
) -> None:
clean_sql = _strip_sql_comments(sql).replace('`', '')
normalized = re.sub(r'\s+', ' ', clean_sql).strip().lower()
tables = _create_table_bodies(sql)
test_case.assertNotRegex(normalized, r'\bon\s+delete\s+cascade\b')
if is_patch:
test_case.assertNotRegex(normalized, r'\bupdate\b')
for table_name in EXPECTED_TEST_BATCH_TABLES:
test_case.assertIn(table_name, tables)
columns, primary_key, unique_keys, foreign_keys, checks = _table_contract(tables[table_name])
test_case.assertEqual(EXPECTED_COLUMNS[table_name], columns, table_name)
test_case.assertEqual(EXPECTED_PRIMARY_KEYS[table_name], primary_key, table_name)
test_case.assertEqual(EXPECTED_UNIQUE_KEYS[table_name], unique_keys, table_name)
test_case.assertEqual(EXPECTED_FOREIGN_KEYS[table_name], foreign_keys, table_name)
test_case.assertEqual(EXPECTED_CHECKS[table_name], checks, table_name)
create_batch = normalized.index('create table biz_test_batch (')
create_batch_user = normalized.index('create table biz_test_batch_user (')
owned_marker = 'alter table' if is_patch else 'create table'
first_owned = min(normalized.index(f'{owned_marker} {table_name} ') for table_name in TEST_BATCH_OWNED_TABLES)
test_case.assertLess(create_batch, create_batch_user)
test_case.assertLess(create_batch_user, first_owned)
for table_name in TEST_BATCH_OWNED_TABLES:
with test_case.subTest(dialect=dialect, patch=is_patch, table=table_name):
if is_patch:
test_case.assertRegex(
normalized,
rf'\balter table {table_name}\s+add column test_batch_id bigint null\b',
)
else:
definitions = _column_definitions(tables[table_name])
test_case.assertIn('test_batch_id', definitions)
test_case.assertRegex(definitions['test_batch_id'], r'\bbigint\b')
test_case.assertNotRegex(definitions['test_batch_id'], r'\bnot\s+null\b')
index_name = f'idx_{table_name}_test_batch_id'
if dialect == 'mysql':
index_pattern = rf'\b(?:add\s+)?(?:index|key)\s+{index_name}\s*\(\s*test_batch_id\s*\)'
test_case.assertRegex(normalized, index_pattern)
test_case.assertIn("comment '测试数据批次id;null表示正式数据'", normalized)
else:
index_pattern = (
rf'\bcreate\s+index\s+{index_name}\s+on\s+{table_name}\s*\(\s*test_batch_id\s*\)'
)
test_case.assertRegex(normalized, index_pattern)
test_case.assertRegex(
normalized,
rf"comment\s+on\s+column\s+{table_name}\.test_batch_id\s+is\s+"
r"'测试数据批次id;null表示正式数据'",
)
constraint_name = f'fk_{table_name}_test_batch_id'
test_case.assertRegex(
normalized,
rf'\bconstraint\s+{constraint_name}\s+foreign\s+key\s*\(\s*test_batch_id\s*\)\s*'
r'references\s+biz_test_batch\s*\(\s*batch_id\s*\)',
)
def _menu_rows(sql: str, menu_ids: set[int]) -> dict[int, list]: def _menu_rows(sql: str, menu_ids: set[int]) -> dict[int, list]:
rows = _insert_rows(sql, 'sys_menu') rows = _insert_rows(sql, 'sys_menu')
selected = [row for row in rows if row and str(row[0]).isdigit() and int(row[0]) in menu_ids] selected = [row for row in rows if row and str(row[0]).isdigit() and int(row[0]) in menu_ids]
@@ -1064,9 +1231,7 @@ def _assert_business_menu_icon_guard_primary_key(test_case: unittest.TestCase, s
def _assert_business_menu_icon_guard_structure(test_case: unittest.TestCase, sql: str) -> tuple[str, str]: def _assert_business_menu_icon_guard_structure(test_case: unittest.TestCase, sql: str) -> tuple[str, str]:
normalized = [_normalized_sql_statement(statement) for statement in _sql_statements(sql)] normalized = [_normalized_sql_statement(statement) for statement in _sql_statements(sql)]
guards = [ guards = [statement for statement in normalized if statement.startswith('insert into business_menu_icon_guard ')]
statement for statement in normalized if statement.startswith('insert into business_menu_icon_guard ')
]
test_case.assertEqual(2, len(guards)) test_case.assertEqual(2, len(guards))
pre_guard, post_guard = guards pre_guard, post_guard = guards
identity_fields = ( identity_fields = (
@@ -1128,6 +1293,23 @@ def _assert_business_menu_icon_guard_structure(test_case: unittest.TestCase, sql
class SqlContractTest(unittest.TestCase): class SqlContractTest(unittest.TestCase):
def test_test_batch_initializers_and_patches_match_contract(self) -> None:
scripts = (
(SQL_ROOT / 'shierfeng-fastapi.sql', 'mysql', False),
(SQL_ROOT / 'shierfeng-fastapi-pg.sql', 'postgresql', False),
(TEST_BATCH_MYSQL_PATCH_PATH, 'mysql', True),
(TEST_BATCH_PG_PATCH_PATH, 'postgresql', True),
)
for path, dialect, is_patch in scripts:
with self.subTest(path=path.name):
self.assertTrue(path.is_file(), f'missing SQL: {path}')
_assert_test_batch_sql_contract(
self,
path.read_text(encoding='utf-8'),
dialect=dialect,
is_patch=is_patch,
)
def test_initializers_define_exact_business_table_set(self) -> None: def test_initializers_define_exact_business_table_set(self) -> None:
for filename in INITIALIZERS: for filename in INITIALIZERS:
with self.subTest(filename=filename): with self.subTest(filename=filename):
@@ -1149,7 +1331,7 @@ class SqlContractTest(unittest.TestCase):
self.assertEqual(EXPECTED_CHECKS[table], checks) self.assertEqual(EXPECTED_CHECKS[table], checks)
def test_postgres_business_datetimes_preserve_default_microsecond_precision(self) -> None: def test_postgres_business_datetimes_preserve_default_microsecond_precision(self) -> None:
self.assertEqual(34, sum(len(columns) for columns in EXPECTED_DATETIME_COLUMNS.values())) self.assertEqual(40, sum(len(columns) for columns in EXPECTED_DATETIME_COLUMNS.values()))
tables = _create_table_bodies((SQL_ROOT / 'shierfeng-fastapi-pg.sql').read_text(encoding='utf-8')) tables = _create_table_bodies((SQL_ROOT / 'shierfeng-fastapi-pg.sql').read_text(encoding='utf-8'))
invalid_columns = [] invalid_columns = []
for table, expected_columns in EXPECTED_DATETIME_COLUMNS.items(): for table, expected_columns in EXPECTED_DATETIME_COLUMNS.items():
@@ -1290,9 +1472,7 @@ class SqlContractTest(unittest.TestCase):
self.assertEqual(1, normalized.count('start transaction')) self.assertEqual(1, normalized.count('start transaction'))
self.assertEqual(1, normalized.count('commit')) self.assertEqual(1, normalized.count('commit'))
transaction_body = normalized[start_index + 1 : commit_index] transaction_body = normalized[start_index + 1 : commit_index]
lock_statement = ( lock_statement = 'select menu_id from sys_menu where menu_id in (121, 122, 123) order by menu_id for update'
'select menu_id from sys_menu where menu_id in (121, 122, 123) order by menu_id for update'
)
expected_update = ( expected_update = (
"update sys_menu set icon = case menu_id when 121 then 'documentation' when 122 then 'build' " "update sys_menu set icon = case menu_id when 121 then 'documentation' when 122 then 'build' "
"when 123 then 'chart' else icon end where menu_id in (121, 122, 123)" "when 123 then 'chart' else icon end where menu_id in (121, 122, 123)"
@@ -1476,6 +1656,8 @@ class SqlContractTest(unittest.TestCase):
'biz_customer', 'biz_customer',
'biz_warehouse', 'biz_warehouse',
'biz_strain', 'biz_strain',
'biz_test_batch_user',
'biz_test_batch',
) )
for filename in INITIALIZERS: for filename in INITIALIZERS:
with self.subTest(filename=filename): with self.subTest(filename=filename):
@@ -1777,15 +1959,15 @@ class SqlContractTest(unittest.TestCase):
self.assertLess(lower.index('ddl'), lower.index('dml')) self.assertLess(lower.index('ddl'), lower.index('dml'))
self.assertEqual(18, len(re.findall(r'create\s+table\s+if\s+not\s+exists\s+`?biz_', lower))) self.assertEqual(18, len(re.findall(r'create\s+table\s+if\s+not\s+exists\s+`?biz_', lower)))
tables = _create_table_bodies(raw) tables = _create_table_bodies(raw)
self.assertEqual(EXPECTED_TABLES, {table for table in tables if table.startswith('biz_')}) self.assertEqual(LEGACY_EXPECTED_TABLES, {table for table in tables if table.startswith('biz_')})
for table in EXPECTED_TABLES: for table in LEGACY_EXPECTED_TABLES:
with self.subTest(table=table): with self.subTest(table=table):
columns, primary_key, unique_keys, foreign_keys, checks = _table_contract(tables[table]) columns, primary_key, unique_keys, foreign_keys, checks = _table_contract(tables[table])
self.assertEqual(EXPECTED_COLUMNS[table], columns) self.assertEqual(LEGACY_EXPECTED_COLUMNS[table], columns)
self.assertEqual(EXPECTED_PRIMARY_KEYS[table], primary_key) self.assertEqual(LEGACY_EXPECTED_PRIMARY_KEYS[table], primary_key)
self.assertEqual(EXPECTED_UNIQUE_KEYS[table], unique_keys) self.assertEqual(LEGACY_EXPECTED_UNIQUE_KEYS[table], unique_keys)
self.assertEqual(EXPECTED_FOREIGN_KEYS[table], foreign_keys) self.assertEqual(LEGACY_EXPECTED_FOREIGN_KEYS[table], foreign_keys)
self.assertEqual(EXPECTED_CHECKS[table], checks) self.assertEqual(LEGACY_EXPECTED_CHECKS[table], checks)
_assert_business_menu_fields(self, raw, LEGACY_PATCH_BUSINESS_MENU_FIELDS) _assert_business_menu_fields(self, raw, LEGACY_PATCH_BUSINESS_MENU_FIELDS)
_assert_business_permission_inventory(self, raw) _assert_business_permission_inventory(self, raw)
patch_rows = _business_menu_rows(raw) patch_rows = _business_menu_rows(raw)
@@ -1793,9 +1975,7 @@ class SqlContractTest(unittest.TestCase):
compared_indexes = (0, 1, *range(4, 15)) compared_indexes = (0, 1, *range(4, 15))
expected_legacy_rows = { expected_legacy_rows = {
menu_id: tuple( menu_id: tuple(
'#' '#' if index == SYS_MENU_ICON_INDEX and menu_id in EXPECTED_BUSINESS_ROOT_ICONS else row[index]
if index == SYS_MENU_ICON_INDEX and menu_id in EXPECTED_BUSINESS_ROOT_ICONS
else row[index]
for index in compared_indexes for index in compared_indexes
) )
for menu_id, row in mysql_rows.items() for menu_id, row in mysql_rows.items()
@@ -1,4 +1,5 @@
import unittest import unittest
from datetime import datetime
from pydantic import ValidationError from pydantic import ValidationError
from pydantic.alias_generators import to_camel from pydantic.alias_generators import to_camel
@@ -69,6 +70,21 @@ from module_business.entity.vo.report_vo import (
ShipmentReportModel, ShipmentReportModel,
ShipmentReportQueryModel, ShipmentReportQueryModel,
) )
from module_business.entity.vo.test_batch_vo import (
AdoptionExecuteRequestModel,
AdoptionPreviewRequestModel,
AdoptionRootModel,
BatchImpactModel,
PurgeExecuteRequestModel,
PurgePreviewModel,
TestBatchCreateModel,
TestBatchDetailModel,
TestBatchEditModel,
TestBatchModel,
TestBatchOptionModel,
TestBatchPreviewModel,
TestBatchUserAssignModel,
)
MASTER_MODEL_FIELDS = { MASTER_MODEL_FIELDS = {
StrainModel: { StrainModel: {
@@ -549,6 +565,71 @@ REPORT_MODEL_FIELDS = {
}, },
} }
TEST_BATCH_MODEL_FIELDS = {
TestBatchCreateModel: {'batch_name', 'remark'},
TestBatchEditModel: {'remark'},
TestBatchUserAssignModel: {'user_ids'},
TestBatchModel: {
'batch_id',
'batch_code',
'batch_name',
'status',
'remark',
'create_by',
'create_time',
'update_by',
'update_time',
'closed_by',
'closed_at',
'purged_by',
'purged_at',
'purge_summary',
},
TestBatchOptionModel: {'batch_id', 'batch_code', 'batch_name', 'status'},
BatchImpactModel: {'table_name', 'label', 'count', 'keys'},
TestBatchDetailModel: {
'batch_id',
'batch_code',
'batch_name',
'status',
'remark',
'create_by',
'create_time',
'update_by',
'update_time',
'closed_by',
'closed_at',
'purged_by',
'purged_at',
'purge_summary',
'user_ids',
'data_summary',
},
TestBatchPreviewModel: {
'batch_id',
'batch_name',
'preview_token',
'expires_at',
'total_count',
'impacts',
},
PurgePreviewModel: {
'batch_id',
'batch_name',
'preview_token',
'expires_at',
'total_count',
'impacts',
'online_purge_allowed',
'online_purge_limit',
'blocking_reason',
},
AdoptionRootModel: {'resource_type', 'resource_ids'},
AdoptionPreviewRequestModel: {'roots'},
AdoptionExecuteRequestModel: {'roots', 'batch_name', 'preview_token'},
PurgeExecuteRequestModel: {'batch_name', 'preview_token'},
}
WRITE_MODELS = ( WRITE_MODELS = (
StrainModel, StrainModel,
DeleteStrainModel, DeleteStrainModel,
@@ -761,7 +842,7 @@ PACKAGE_MODEL_PAYLOADS = {
class BusinessVoContractTest(unittest.TestCase): class BusinessVoContractTest(unittest.TestCase):
def test_all_models_have_exact_fields_and_camel_case_aliases(self) -> None: def test_all_models_have_exact_fields_and_camel_case_aliases(self) -> None:
expected_models = MASTER_MODEL_FIELDS | OPERATION_MODEL_FIELDS | REPORT_MODEL_FIELDS expected_models = MASTER_MODEL_FIELDS | OPERATION_MODEL_FIELDS | REPORT_MODEL_FIELDS | TEST_BATCH_MODEL_FIELDS
for model_class, expected_fields in expected_models.items(): for model_class, expected_fields in expected_models.items():
with self.subTest(model=model_class.__name__): with self.subTest(model=model_class.__name__):
@@ -777,6 +858,44 @@ class BusinessVoContractTest(unittest.TestCase):
with self.subTest(model=model_class.__name__): with self.subTest(model=model_class.__name__):
self.assertEqual('forbid', model_class.model_config.get('extra')) self.assertEqual('forbid', model_class.model_config.get('extra'))
def test_all_test_batch_models_forbid_extra_fields(self) -> None:
for model_class in TEST_BATCH_MODEL_FIELDS:
with self.subTest(model=model_class.__name__):
self.assertEqual('forbid', model_class.model_config.get('extra'))
def test_test_batch_models_accept_snake_case_and_camel_case(self) -> None:
camel_case = TestBatchCreateModel(batchName='验收批次', remark='camel')
snake_case = TestBatchCreateModel(batch_name='验收批次', remark='snake')
self.assertEqual('验收批次', camel_case.batch_name)
self.assertEqual('验收批次', snake_case.batch_name)
def test_test_batch_edit_forbids_immutable_fields(self) -> None:
for field_name, value in (('batchName', '新名称'), ('status', 'CLOSED')):
with self.subTest(field=field_name), self.assertRaises(ValidationError):
TestBatchEditModel.model_validate({'remark': None, field_name: value})
def test_test_batch_positive_ids_and_non_empty_roots_are_validated(self) -> None:
with self.assertRaises(ValidationError):
TestBatchUserAssignModel(userIds=[0])
with self.assertRaises(ValidationError):
AdoptionRootModel(resourceType='strain', resourceIds=[])
with self.assertRaises(ValidationError):
AdoptionPreviewRequestModel(roots=[])
def test_test_batch_status_rejects_unknown_value(self) -> None:
with self.assertRaises(ValidationError) as context:
TestBatchModel(
batchId=1,
batchCode='TB-1',
batchName='验收批次',
status='UNKNOWN',
createBy='admin',
createTime=datetime(2026, 9, 22),
updateBy='admin',
updateTime=datetime(2026, 9, 22),
)
self.assertIn(('status',), {tuple(error['loc']) for error in context.exception.errors()})
def test_page_queries_have_positive_defaults(self) -> None: def test_page_queries_have_positive_defaults(self) -> None:
for model_class in PAGE_QUERY_MODELS: for model_class in PAGE_QUERY_MODELS:
with self.subTest(model=model_class.__name__): with self.subTest(model=model_class.__name__):