Files
track/backend/app/models/product.py
duxingchen e0c01a562f feat(models): Task/Product 模型扩充 + 4个Alembic迁移
Task 模型:
- 新增 received_at, completed_at, reject_reason, is_rework
- 新增 TaskRecord 模型 (remark + images JSON)
- 状态常量 PENDING/WIP/COMPLETED/REJECTED/ARCHIVED
- 全部时间字段改用北京时间 (get_beijing_time)

Product 模型:
- order_id → 可选; 新增 external_serial, current_location_id
- 新增 material_name/spec_model/category/material_type 快照字段
- 新增 overall_status (备货/生产/测试/维修/在库)

迁移:
- b2c3: HEX计数器Sequence + external_serial + order_id nullable
- c3d4: material快照4列
- d4e5: overall_status
- e5f6: task_records表
2026-08-05 14:00:23 +08:00

79 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""产品模型"""
import uuid
from datetime import datetime
from sqlalchemy import String, DateTime, ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import Base
from app.core.time_utils import get_beijing_time
class Product(Base):
__tablename__ = "products"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4,
)
serial_number: Mapped[str] = mapped_column(
String(16), unique=True, index=True, nullable=False, comment="产品序列号(16位)",
)
# ---- 物理外键(关联本库 production_orders— 可选 ----
order_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("production_orders.id"), nullable=True, comment="所属订单ID(可选)",
)
# ---- 外部序列号(用户自定义,可选) ----
external_serial: Mapped[str | None] = mapped_column(
String(64), nullable=True, comment="用户自定义产品序列号(可选)",
)
# ---- 逻辑外键(关联老系统物料表,仅存储 ID无物理约束 ----
material_id: Mapped[str | None] = mapped_column(
String(64), nullable=True, comment="物料ID(逻辑外键→老系统)",
)
# ---- MOM 物料快照字段(创产品时写入,防止老系统数据变动影响标签) ----
material_name: Mapped[str | None] = mapped_column(
String(255), nullable=True, comment="物料名称快照",
)
spec_model: Mapped[str | None] = mapped_column(
String(255), nullable=True, comment="规格型号快照",
)
category: Mapped[str | None] = mapped_column(
String(255), nullable=True, comment="物料分类快照",
)
material_type: Mapped[str | None] = mapped_column(
String(100), nullable=True, comment="物料类型快照",
)
# ---- 物理外键(自引用:父产品) ----
parent_product_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("products.id"), nullable=True, comment="父产品ID",
)
# ---- 当前位置追踪逻辑外键→用户ID 或 'virtual_warehouse' ----
current_location_id: Mapped[str | None] = mapped_column(
String(64), nullable=True, comment="当前持有者ID 或 'virtual_warehouse'(仓库)",
)
status: Mapped[str] = mapped_column(
String(50), nullable=False, default="pending", comment="产品状态",
)
# 宏观流转状态 — 首次扫码时强制设定:备货/生产/测试/维修/在库
overall_status: Mapped[str | None] = mapped_column(
String(20), nullable=True, comment="宏观状态: 备货/生产/测试/维修/在库",
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=get_beijing_time, comment="创建时间",
)
# ---- 关系 ----
order: Mapped["ProductionOrder"] = relationship("ProductionOrder", lazy="selectin")
parent_product: Mapped["Product | None"] = relationship(
"Product", remote_side="Product.id", lazy="selectin",
)
def __repr__(self) -> str:
return f"<Product {self.serial_number}>"