功能:新增托盘业务接口模型

This commit is contained in:
焦龙言
2026-07-24 21:07:43 +08:00
parent eab725a541
commit f747a80a2a
4 changed files with 1884 additions and 0 deletions
@@ -0,0 +1,391 @@
from datetime import datetime
from typing import Annotated, Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic.alias_generators import to_camel
PositiveId = Annotated[int, Field(gt=0)]
def _ensure_unique_ids(value: list[int]) -> list[int]:
if len(value) != len(set(value)):
raise ValueError('ID列表不能包含重复项')
return value
class StrainModel(BaseModel):
"""菌种主数据写入及展示模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
strain_id: int | None = Field(default=None, gt=0, description='菌种ID')
strain_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='菌种编码')
strain_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='菌种名称')
status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
class StrainPageQueryModel(BaseModel):
"""菌种分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
strain_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='菌种编码')
strain_name: str | None = Field(
default=None,
min_length=1,
max_length=100,
pattern=r'\S',
description='菌种名称',
)
status: Literal['0', '1'] | None = Field(default=None, description='状态')
class DeleteStrainModel(BaseModel):
"""删除菌种模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
strain_ids: list[PositiveId] = Field(min_length=1, description='需要删除的菌种ID')
_validate_unique_ids = field_validator('strain_ids')(_ensure_unique_ids)
class CustomerModel(BaseModel):
"""客户主数据写入及展示模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
customer_id: int | None = Field(default=None, gt=0, description='客户ID')
customer_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='客户编码')
customer_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='客户名称')
status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
class CustomerPageQueryModel(BaseModel):
"""客户分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
customer_code: str | None = Field(
default=None,
min_length=1,
max_length=64,
pattern=r'\S',
description='客户编码',
)
customer_name: str | None = Field(
default=None,
min_length=1,
max_length=100,
pattern=r'\S',
description='客户名称',
)
status: Literal['0', '1'] | None = Field(default=None, description='状态')
class DeleteCustomerModel(BaseModel):
"""删除客户模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
customer_ids: list[PositiveId] = Field(min_length=1, description='需要删除的客户ID')
_validate_unique_ids = field_validator('customer_ids')(_ensure_unique_ids)
class SiteModel(BaseModel):
"""客户现场主数据写入及展示模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
site_id: int | None = Field(default=None, gt=0, description='现场ID')
customer_id: int = Field(gt=0, description='客户ID')
site_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='现场编码')
site_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='现场名称')
address: str | None = Field(default=None, max_length=500, description='现场地址')
status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
class SitePageQueryModel(BaseModel):
"""客户现场分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
customer_id: int | None = Field(default=None, gt=0, description='客户ID')
site_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='现场编码')
site_name: str | None = Field(
default=None,
min_length=1,
max_length=100,
pattern=r'\S',
description='现场名称',
)
status: Literal['0', '1'] | None = Field(default=None, description='状态')
class DeleteSiteModel(BaseModel):
"""删除客户现场模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
site_ids: list[PositiveId] = Field(min_length=1, description='需要删除的现场ID')
_validate_unique_ids = field_validator('site_ids')(_ensure_unique_ids)
class LineModel(BaseModel):
"""生产线主数据写入及展示模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
line_id: int | None = Field(default=None, gt=0, description='产线ID')
site_id: int = Field(gt=0, description='现场ID')
line_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='产线编码')
line_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='产线名称')
status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
class LinePageQueryModel(BaseModel):
"""生产线分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
site_id: int | None = Field(default=None, gt=0, description='现场ID')
line_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='产线编码')
line_name: str | None = Field(
default=None,
min_length=1,
max_length=100,
pattern=r'\S',
description='产线名称',
)
status: Literal['0', '1'] | None = Field(default=None, description='状态')
class DeleteLineModel(BaseModel):
"""删除生产线模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
line_ids: list[PositiveId] = Field(min_length=1, description='需要删除的产线ID')
_validate_unique_ids = field_validator('line_ids')(_ensure_unique_ids)
class WarehouseModel(BaseModel):
"""仓库主数据写入及展示模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
warehouse_id: int | None = Field(default=None, gt=0, description='仓库ID')
warehouse_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='仓库编码')
warehouse_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='仓库名称')
address: str | None = Field(default=None, max_length=500, description='仓库地址')
status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
class WarehousePageQueryModel(BaseModel):
"""仓库分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
warehouse_code: str | None = Field(
default=None,
min_length=1,
max_length=64,
pattern=r'\S',
description='仓库编码',
)
warehouse_name: str | None = Field(
default=None,
min_length=1,
max_length=100,
pattern=r'\S',
description='仓库名称',
)
status: Literal['0', '1'] | None = Field(default=None, description='状态')
class DeleteWarehouseModel(BaseModel):
"""删除仓库模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
warehouse_ids: list[PositiveId] = Field(min_length=1, description='需要删除的仓库ID')
_validate_unique_ids = field_validator('warehouse_ids')(_ensure_unique_ids)
class PalletModel(BaseModel):
"""托盘资产展示模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
qr_token: str = Field(min_length=1, max_length=128, pattern=r'\S', description='二维码固定标识')
capacity_packages: int = Field(gt=0, description='容量包数')
asset_status: Literal['0', '1'] = Field(description='资产状态(0正常 1停用)')
remark: str | None = Field(default=None, max_length=500, description='备注')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
can_remove: bool | None = Field(default=None, description='是否允许删除')
class PalletCreateModel(BaseModel):
"""新增托盘模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
capacity_packages: int = Field(strict=True, gt=0, description='容量包数')
remark: str | None = Field(default=None, max_length=500, description='备注')
class PalletEditModel(BaseModel):
"""编辑托盘可变属性模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
pallet_id: int = Field(gt=0, description='托盘ID')
capacity_packages: int = Field(strict=True, gt=0, description='容量包数')
asset_status: Literal['0', '1'] = Field(description='资产状态(0正常 1停用)')
remark: str | None = Field(default=None, max_length=500, description='备注')
class PalletPageQueryModel(BaseModel):
"""托盘分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
asset_status: Literal['0', '1'] | None = Field(default=None, description='资产状态')
class DeletePalletModel(BaseModel):
"""删除托盘模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
pallet_ids: list[PositiveId] = Field(min_length=1, description='需要删除的托盘ID')
_validate_unique_ids = field_validator('pallet_ids')(_ensure_unique_ids)
class UserAssignModel(BaseModel):
"""用户数据范围分配模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
user_ids: list[PositiveId] = Field(min_length=1, description='用户ID列表')
_validate_unique_ids = field_validator('user_ids')(_ensure_unique_ids)
@@ -0,0 +1,463 @@
from datetime import datetime
from typing import Annotated, Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from pydantic.alias_generators import to_camel
from module_business.domain.enums import DocumentStatus, PalletFlowState, ReturnStatus
PositiveId = Annotated[int, Field(gt=0)]
NonBlankAction = Annotated[str, Field(min_length=1, max_length=64, pattern=r'\S')]
def _ensure_unique_ids(value: list[int]) -> list[int]:
if len(value) != len(set(value)):
raise ValueError('托盘ID列表不能包含重复项')
return value
class InboundCreateModel(BaseModel):
"""首次入库草稿新增模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
warehouse_id: int = Field(gt=0, description='仓库ID')
pallet_ids: list[PositiveId] = Field(min_length=1, description='托盘ID列表')
_validate_unique_ids = field_validator('pallet_ids')(_ensure_unique_ids)
class InboundUpdateModel(BaseModel):
"""首次入库草稿更新模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
inbound_id: int = Field(gt=0, description='入库单ID')
warehouse_id: int = Field(gt=0, description='仓库ID')
pallet_ids: list[PositiveId] = Field(min_length=1, description='托盘ID列表')
_validate_unique_ids = field_validator('pallet_ids')(_ensure_unique_ids)
class ConfirmCommandModel(BaseModel):
"""单据确认命令模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='确认幂等键')
class FillingCreateModel(BaseModel):
"""托盘装填命令模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
qr_token: str = Field(min_length=1, max_length=128, pattern=r'\S', description='二维码固定标识')
warehouse_id: int = Field(gt=0, description='仓库ID')
strain_id: int = Field(gt=0, description='菌种ID')
batch_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='生产批次')
package_spec: str = Field(min_length=1, max_length=64, pattern=r'\S', description='包装规格')
initial_packages: int = Field(strict=True, gt=0, description='初始包数')
idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='幂等键')
class ShipmentCreateModel(BaseModel):
"""整托发货草稿新增模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
source_warehouse_id: int = Field(gt=0, description='来源仓库ID')
target_site_id: int = Field(gt=0, description='目标现场ID')
pallet_ids: list[PositiveId] = Field(min_length=1, description='托盘ID列表')
_validate_unique_ids = field_validator('pallet_ids')(_ensure_unique_ids)
class ShipmentUpdateModel(BaseModel):
"""整托发货草稿更新模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
shipment_id: int = Field(gt=0, description='发货单ID')
source_warehouse_id: int = Field(gt=0, description='来源仓库ID')
target_site_id: int = Field(gt=0, description='目标现场ID')
pallet_ids: list[PositiveId] = Field(min_length=1, description='托盘ID列表')
_validate_unique_ids = field_validator('pallet_ids')(_ensure_unique_ids)
class UsageCreateModel(BaseModel):
"""客户现场使用命令模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
qr_token: str = Field(min_length=1, max_length=128, pattern=r'\S', description='二维码固定标识')
line_id: int = Field(gt=0, description='产线ID')
used_packages: int = Field(strict=True, gt=0, description='本次使用包数')
idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='幂等键')
class ReturnRequestModel(BaseModel):
"""托盘退回申请命令模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
source_site_id: int = Field(gt=0, description='来源现场ID')
target_warehouse_id: int = Field(gt=0, description='目标仓库ID')
pallet_ids: list[PositiveId] = Field(min_length=1, description='托盘ID列表')
idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='申请幂等键')
_validate_unique_ids = field_validator('pallet_ids')(_ensure_unique_ids)
class ReturnConfirmModel(BaseModel):
"""托盘退回确认命令模型。"""
model_config = ConfigDict(
alias_generator=to_camel,
from_attributes=True,
populate_by_name=True,
extra='forbid',
)
scanned_pallet_ids: list[PositiveId] = Field(min_length=1, description='已扫描托盘ID列表')
idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='确认幂等键')
_validate_unique_ids = field_validator('scanned_pallet_ids')(_ensure_unique_ids)
class InboundItemModel(BaseModel):
"""首次入库单托盘明细模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
inbound_item_id: int = Field(gt=0, description='入库明细ID')
inbound_id: int = Field(gt=0, description='入库单ID')
pallet_id: int = Field(gt=0, description='托盘ID')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
class InboundModel(BaseModel):
"""首次入库单展示模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
inbound_id: int = Field(gt=0, description='入库单ID')
inbound_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='入库单号')
warehouse_id: int = Field(gt=0, description='仓库ID')
status: DocumentStatus = Field(description='单据状态')
confirm_idempotency_key: str | None = Field(default=None, max_length=64, description='确认幂等键')
confirm_request_hash: str | None = Field(default=None, max_length=64, description='确认请求摘要')
confirmed_by: int | None = Field(default=None, gt=0, description='确认人ID')
confirmed_at: datetime | None = Field(default=None, description='确认时间')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
items: list[InboundItemModel] = Field(default_factory=list, description='入库托盘明细')
class FillingModel(BaseModel):
"""托盘装填记录展示模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
filling_id: int = Field(gt=0, description='装填记录ID')
filling_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='装填单号')
pallet_id: int = Field(gt=0, description='托盘ID')
warehouse_id: int = Field(gt=0, description='仓库ID')
strain_id: int = Field(gt=0, description='菌种ID')
strain_code_snapshot: str = Field(min_length=1, max_length=64, pattern=r'\S', description='菌种编码快照')
strain_name_snapshot: str = Field(min_length=1, max_length=100, pattern=r'\S', description='菌种名称快照')
batch_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='生产批次')
package_spec: str = Field(min_length=1, max_length=64, pattern=r'\S', description='包装规格')
initial_packages: int = Field(ge=0, description='初始包数')
active_slot: Literal['ACTIVE'] | None = Field(default=None, description='活动装填槽')
closed_at: datetime | None = Field(default=None, description='装填周期关闭时间')
idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='幂等键')
request_hash: str = Field(min_length=1, max_length=64, pattern=r'\S', description='请求摘要')
operator_id: int = Field(gt=0, description='操作人ID')
operated_at: datetime = Field(description='操作时间')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
class ShipmentItemModel(BaseModel):
"""整托发货明细模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
shipment_item_id: int = Field(gt=0, description='发货明细ID')
shipment_id: int = Field(gt=0, description='发货单ID')
pallet_id: int = Field(gt=0, description='托盘ID')
active_filling_id: int | None = Field(default=None, gt=0, description='确认时活动装填记录ID')
package_qty: int | None = Field(default=None, ge=0, description='确认时包数快照')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
class ShipmentModel(BaseModel):
"""整托发货单展示模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
shipment_id: int = Field(gt=0, description='发货单ID')
shipment_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='发货单号')
source_warehouse_id: int = Field(gt=0, description='来源仓库ID')
target_site_id: int = Field(gt=0, description='目标现场ID')
status: DocumentStatus = Field(description='单据状态')
confirm_idempotency_key: str | None = Field(default=None, max_length=64, description='确认幂等键')
confirm_request_hash: str | None = Field(default=None, max_length=64, description='确认请求摘要')
confirmed_by: int | None = Field(default=None, gt=0, description='确认人ID')
confirmed_at: datetime | None = Field(default=None, description='确认时间')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
items: list[ShipmentItemModel] = Field(default_factory=list, description='发货托盘明细')
class UsageModel(BaseModel):
"""客户现场使用记录展示模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
usage_id: int = Field(gt=0, description='使用记录ID')
usage_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='使用记录号')
pallet_id: int = Field(gt=0, description='托盘ID')
active_filling_id: int = Field(gt=0, description='活动装填记录ID')
site_id: int = Field(gt=0, description='现场ID')
line_id: int = Field(gt=0, description='产线ID')
used_packages: int = Field(ge=0, description='本次使用包数')
remaining_packages_after: int = Field(ge=0, description='使用后剩余包数')
idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='幂等键')
request_hash: str = Field(min_length=1, max_length=64, pattern=r'\S', description='请求摘要')
operator_id: int = Field(gt=0, description='操作人ID')
occurred_at: datetime = Field(description='发生时间')
class ReturnItemModel(BaseModel):
"""托盘退回明细模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
return_item_id: int = Field(gt=0, description='退回明细ID')
return_id: int = Field(gt=0, description='退回单ID')
pallet_id: int = Field(gt=0, description='托盘ID')
active_filling_id_snapshot: int | None = Field(default=None, gt=0, description='申请时活动装填记录快照')
remaining_packages_snapshot: int = Field(ge=0, description='申请时剩余包数快照')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
class ReturnModel(BaseModel):
"""托盘退回单展示模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
return_id: int = Field(gt=0, description='退回单ID')
return_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='退回单号')
source_site_id: int = Field(gt=0, description='来源现场ID')
target_warehouse_id: int = Field(gt=0, description='目标仓库ID')
status: ReturnStatus = Field(description='退回状态')
request_idempotency_key: str = Field(min_length=1, max_length=64, pattern=r'\S', description='申请幂等键')
request_hash: str = Field(min_length=1, max_length=64, pattern=r'\S', description='申请请求摘要')
confirm_idempotency_key: str | None = Field(default=None, max_length=64, description='确认幂等键')
confirm_request_hash: str | None = Field(default=None, max_length=64, description='确认请求摘要')
requested_by: int = Field(gt=0, description='申请人ID')
requested_at: datetime = Field(description='申请时间')
confirmed_by: int | None = Field(default=None, gt=0, description='确认人ID')
confirmed_at: datetime | None = Field(default=None, description='确认时间')
create_by: str | None = Field(default=None, max_length=64, description='创建者')
create_time: datetime | None = Field(default=None, description='创建时间')
update_by: str | None = Field(default=None, max_length=64, description='更新者')
update_time: datetime | None = Field(default=None, description='更新时间')
remark: str | None = Field(default=None, max_length=500, description='备注')
items: list[ReturnItemModel] = Field(default_factory=list, description='退回托盘明细')
class InboundPageQueryModel(BaseModel):
"""首次入库分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
inbound_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='入库单号')
warehouse_id: int | None = Field(default=None, gt=0, description='仓库ID')
status: DocumentStatus | None = Field(default=None, description='单据状态')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
class FillingPageQueryModel(BaseModel):
"""托盘装填分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
filling_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='装填单号')
warehouse_id: int | None = Field(default=None, gt=0, description='仓库ID')
strain_id: int | None = Field(default=None, gt=0, description='菌种ID')
batch_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='生产批次')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
class ShipmentPageQueryModel(BaseModel):
"""整托发货分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
shipment_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='发货单号')
source_warehouse_id: int | None = Field(default=None, gt=0, description='来源仓库ID')
target_site_id: int | None = Field(default=None, gt=0, description='目标现场ID')
status: DocumentStatus | None = Field(default=None, description='单据状态')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
class UsagePageQueryModel(BaseModel):
"""客户现场使用分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
usage_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='使用记录号')
site_id: int | None = Field(default=None, gt=0, description='现场ID')
line_id: int | None = Field(default=None, gt=0, description='产线ID')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
class ReturnPageQueryModel(BaseModel):
"""托盘退回分页查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
return_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='退回单号')
source_site_id: int | None = Field(default=None, gt=0, description='来源现场ID')
target_warehouse_id: int | None = Field(default=None, gt=0, description='目标仓库ID')
status: ReturnStatus | None = Field(default=None, description='退回状态')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
class InboundScanQueryModel(BaseModel):
"""首次入库扫码查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
warehouse_id: int = Field(gt=0, description='仓库ID')
class ShipmentScanQueryModel(BaseModel):
"""整托发货扫码查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
source_warehouse_id: int = Field(gt=0, description='来源仓库ID')
target_site_id: int = Field(gt=0, description='目标现场ID')
class ReturnScanQueryModel(BaseModel):
"""托盘退回扫码查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
mode: Literal['request', 'confirm'] = Field(description='扫码模式')
return_id: int | None = Field(default=None, gt=0, description='退回单ID')
@model_validator(mode='after')
def validate_return_id(self) -> 'ReturnScanQueryModel':
if self.mode == 'confirm' and self.return_id is None:
raise ValueError('确认退回扫码时必须提供退回单ID')
if self.mode == 'request' and self.return_id is not None:
raise ValueError('申请退回扫码时不能提供退回单ID')
return self
class BusinessOptionModel(BaseModel):
"""业务下拉选项模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
id: int = Field(gt=0, description='业务主键')
code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='业务编码')
name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='业务名称')
class PalletScanResponseModel(BaseModel):
"""业务扫码托盘响应模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
flow_state: PalletFlowState = Field(description='托盘流转状态')
warehouse_id: int | None = Field(default=None, gt=0, description='当前仓库ID')
site_id: int | None = Field(default=None, gt=0, description='当前现场ID')
current_line_id: int | None = Field(default=None, gt=0, description='当前绑定产线ID')
active_filling_id: int | None = Field(default=None, gt=0, description='当前活动装填记录ID')
strain_id: int | None = Field(default=None, gt=0, description='菌种ID')
strain_code: str | None = Field(default=None, max_length=64, description='菌种编码')
strain_name: str | None = Field(default=None, max_length=100, description='菌种名称')
batch_no: str | None = Field(default=None, max_length=64, description='生产批次')
package_spec: str | None = Field(default=None, max_length=64, description='包装规格')
capacity_packages: int = Field(gt=0, description='容量包数')
remaining_packages: int = Field(ge=0, description='当前剩余包数')
allowed_actions: list[NonBlankAction] = Field(description='当前接口允许的业务动作')
@@ -0,0 +1,245 @@
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
from pydantic.alias_generators import to_camel
from module_business.domain.enums import DocumentStatus, PalletEventType, PalletFlowState, ReturnStatus
class PalletInventoryReportQueryModel(BaseModel):
"""托盘库存报表查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
flow_state: PalletFlowState | None = Field(default=None, description='托盘流转状态')
warehouse_id: int | None = Field(default=None, gt=0, description='仓库ID')
site_id: int | None = Field(default=None, gt=0, description='现场ID')
line_id: int | None = Field(default=None, gt=0, description='产线ID')
strain_id: int | None = Field(default=None, gt=0, description='菌种ID')
batch_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='生产批次')
class PalletInventoryReportModel(BaseModel):
"""托盘库存报表行模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
flow_state: PalletFlowState = Field(description='托盘流转状态')
warehouse_id: int | None = Field(default=None, gt=0, description='当前仓库ID')
warehouse_name: str | None = Field(default=None, max_length=100, description='当前仓库名称')
site_id: int | None = Field(default=None, gt=0, description='当前现场ID')
site_name: str | None = Field(default=None, max_length=100, description='当前现场名称')
line_id: int | None = Field(default=None, gt=0, description='当前产线ID')
line_name: str | None = Field(default=None, max_length=100, description='当前产线名称')
strain_id: int | None = Field(default=None, gt=0, description='当前菌种ID')
strain_code: str | None = Field(default=None, max_length=64, description='当前菌种编码快照')
strain_name: str | None = Field(default=None, max_length=100, description='当前菌种名称快照')
batch_no: str | None = Field(default=None, max_length=64, description='当前生产批次')
initial_packages: int | None = Field(default=None, ge=0, description='初始包数')
remaining_packages: int = Field(ge=0, description='当前剩余包数')
updated_at: datetime = Field(description='库存更新时间')
class FillingReportQueryModel(BaseModel):
"""装填记录报表查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
warehouse_id: int | None = Field(default=None, gt=0, description='仓库ID')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
strain_id: int | None = Field(default=None, gt=0, description='菌种ID')
batch_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='生产批次')
class FillingReportModel(BaseModel):
"""装填记录报表行模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
filling_id: int = Field(gt=0, description='装填记录ID')
filling_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='装填单号')
operated_at: datetime = Field(description='装填时间')
warehouse_id: int = Field(gt=0, description='仓库ID')
warehouse_name: str | None = Field(default=None, max_length=100, description='仓库名称')
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
strain_id: int = Field(gt=0, description='菌种ID')
strain_code_snapshot: str = Field(min_length=1, max_length=64, pattern=r'\S', description='菌种编码快照')
strain_name_snapshot: str = Field(min_length=1, max_length=100, pattern=r'\S', description='菌种名称快照')
batch_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='生产批次')
package_spec: str = Field(min_length=1, max_length=64, pattern=r'\S', description='包装规格')
initial_packages: int = Field(ge=0, description='初始包数')
operator_id: int = Field(gt=0, description='操作人ID')
operator_name: str | None = Field(default=None, max_length=100, description='操作人名称')
class ShipmentReportQueryModel(BaseModel):
"""发货出库报表查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
shipment_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='发货单号')
source_warehouse_id: int | None = Field(default=None, gt=0, description='来源仓库ID')
target_site_id: int | None = Field(default=None, gt=0, description='目标现场ID')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
status: DocumentStatus | None = Field(default=None, description='单据状态')
class ShipmentReportModel(BaseModel):
"""发货出库报表行模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
shipment_id: int = Field(gt=0, description='发货单ID')
shipment_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='发货单号')
confirmed_at: datetime = Field(description='确认发货时间')
source_warehouse_id: int = Field(gt=0, description='来源仓库ID')
source_warehouse_name: str | None = Field(default=None, max_length=100, description='来源仓库名称')
target_site_id: int = Field(gt=0, description='目标现场ID')
target_site_name: str | None = Field(default=None, max_length=100, description='目标现场名称')
customer_id: int = Field(gt=0, description='客户ID')
customer_name: str | None = Field(default=None, max_length=100, description='客户名称')
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
active_filling_id: int | None = Field(default=None, gt=0, description='发货时活动装填记录ID')
package_qty: int = Field(ge=0, description='发货时包数快照')
class ConsumptionReportQueryModel(BaseModel):
"""产线消耗报表查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
customer_id: int | None = Field(default=None, gt=0, description='客户ID')
site_id: int | None = Field(default=None, gt=0, description='现场ID')
line_id: int | None = Field(default=None, gt=0, description='产线ID')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
strain_id: int | None = Field(default=None, gt=0, description='菌种ID')
batch_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='生产批次')
class ConsumptionReportModel(BaseModel):
"""产线消耗报表行模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
usage_id: int = Field(gt=0, description='使用记录ID')
usage_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='使用记录号')
occurred_at: datetime = Field(description='使用发生时间')
customer_id: int = Field(gt=0, description='客户ID')
customer_name: str | None = Field(default=None, max_length=100, description='客户名称')
site_id: int = Field(gt=0, description='现场ID')
site_name: str | None = Field(default=None, max_length=100, description='现场名称')
line_id: int = Field(gt=0, description='产线ID')
line_name: str | None = Field(default=None, max_length=100, description='产线名称')
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
strain_id: int = Field(gt=0, description='菌种ID')
strain_code: str | None = Field(default=None, max_length=64, description='菌种编码快照')
strain_name: str | None = Field(default=None, max_length=100, description='菌种名称快照')
batch_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='生产批次')
used_packages: int = Field(ge=0, description='本次使用包数')
remaining_packages_after: int = Field(ge=0, description='使用后剩余包数')
operator_id: int = Field(gt=0, description='操作人ID')
operator_name: str | None = Field(default=None, max_length=100, description='操作人名称')
class ReturnReportQueryModel(BaseModel):
"""退回仓库报表查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
return_no: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='退回单号')
source_site_id: int | None = Field(default=None, gt=0, description='来源现场ID')
target_warehouse_id: int | None = Field(default=None, gt=0, description='目标仓库ID')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
status: ReturnStatus | None = Field(default=None, description='退回状态')
class ReturnReportModel(BaseModel):
"""退回仓库报表行模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
return_id: int = Field(gt=0, description='退回单ID')
return_no: str = Field(min_length=1, max_length=64, pattern=r'\S', description='退回单号')
status: ReturnStatus = Field(description='退回状态')
requested_at: datetime = Field(description='申请时间')
confirmed_at: datetime | None = Field(default=None, description='确认时间')
source_site_id: int = Field(gt=0, description='来源现场ID')
source_site_name: str | None = Field(default=None, max_length=100, description='来源现场名称')
target_warehouse_id: int = Field(gt=0, description='目标仓库ID')
target_warehouse_name: str | None = Field(default=None, max_length=100, description='目标仓库名称')
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
active_filling_id_snapshot: int | None = Field(default=None, gt=0, description='活动装填记录快照')
remaining_packages_snapshot: int = Field(ge=0, description='剩余包数快照')
class PalletTraceReportQueryModel(BaseModel):
"""托盘追溯报表查询模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
page_num: int = Field(default=1, gt=0, description='当前页码')
page_size: int = Field(default=10, gt=0, description='每页记录数')
begin_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='开始时间')
end_time: str | None = Field(default=None, min_length=1, pattern=r'\S', description='结束时间')
pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
event_type: PalletEventType | None = Field(default=None, description='事件类型')
class PalletTraceReportModel(BaseModel):
"""托盘追溯报表行模型。"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
event_id: int = Field(gt=0, description='事件ID')
event_seq: int = Field(gt=0, description='托盘内事件序号')
event_type: PalletEventType = Field(description='事件类型')
source_type: str = Field(min_length=1, max_length=32, pattern=r'\S', description='来源类型')
source_id: int = Field(gt=0, description='来源记录ID')
pallet_id: int = Field(gt=0, description='托盘ID')
pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号')
before_state: PalletFlowState = Field(description='变更前状态')
after_state: PalletFlowState = Field(description='变更后状态')
before_warehouse_id: int | None = Field(default=None, gt=0, description='变更前仓库ID')
before_warehouse_name: str | None = Field(default=None, max_length=100, description='变更前仓库名称')
before_site_id: int | None = Field(default=None, gt=0, description='变更前现场ID')
before_site_name: str | None = Field(default=None, max_length=100, description='变更前现场名称')
before_line_id: int | None = Field(default=None, gt=0, description='变更前产线ID')
before_line_name: str | None = Field(default=None, max_length=100, description='变更前产线名称')
after_warehouse_id: int | None = Field(default=None, gt=0, description='变更后仓库ID')
after_warehouse_name: str | None = Field(default=None, max_length=100, description='变更后仓库名称')
after_site_id: int | None = Field(default=None, gt=0, description='变更后现场ID')
after_site_name: str | None = Field(default=None, max_length=100, description='变更后现场名称')
after_line_id: int | None = Field(default=None, gt=0, description='变更后产线ID')
after_line_name: str | None = Field(default=None, max_length=100, description='变更后产线名称')
before_remaining_packages: int = Field(ge=0, description='变更前剩余包数')
after_remaining_packages: int = Field(ge=0, description='变更后剩余包数')
operator_id: int = Field(gt=0, description='操作人ID')
operator_name: str | None = Field(default=None, max_length=100, description='操作人名称')
occurred_at: datetime = Field(description='发生时间')