Files
track/backend/app/models/task.py
duxingchen 817be6b036 feat(models): 扩充 Task 和 Product 数据库模型
Task 模型新增:
- received_at: DateTime (操作员确认接收时间)
- completed_at: DateTime (任务完工转交时间)
- reject_reason: String(500) (驳回原因)
- is_rework: Boolean (是否为返工任务,默认 False)
- 状态常量: PENDING/WIP/COMPLETED/REJECTED/ARCHIVED
- 默认状态由 'pending' 升为大写 'PENDING'

Product 模型新增:
- current_location_id: String(64) (当前持有者ID 或 'virtual_warehouse')
2026-08-04 17:03:23 +08:00

83 lines
3.1 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, timezone
from sqlalchemy import String, DateTime, Boolean, ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import Base
# 任务状态常量
TASK_STATUS_PENDING = "PENDING" # 待接收
TASK_STATUS_WIP = "WIP" # 进行中
TASK_STATUS_COMPLETED = "COMPLETED" # 已完成
TASK_STATUS_REJECTED = "REJECTED" # 已驳回
TASK_STATUS_ARCHIVED = "ARCHIVED" # 已入库
class Task(Base):
__tablename__ = "tasks"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4,
)
# ---- 物理外键(关联本库 products ----
product_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("products.id"), nullable=False, comment="所属产品ID",
)
# ---- 物理外键(自引用:无限嵌套父子任务 / 裂变分支) ----
parent_task_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("tasks.id"), nullable=True, index=True, comment="父任务ID(用于任务裂变树)",
)
task_name: Mapped[str] = mapped_column(
String(200), nullable=False, comment="任务名称",
)
# ---- 逻辑外键(关联老系统用户表,仅存储 ID无物理约束 ----
assignee_id: Mapped[str | None] = mapped_column(
String(64), nullable=True, comment="负责人ID(逻辑外键→老系统)",
)
status: Mapped[str] = mapped_column(
String(50), nullable=False, default=TASK_STATUS_PENDING,
comment="任务状态: PENDING(待接收) | WIP(进行中) | COMPLETED(已完成) | REJECTED(已驳回) | ARCHIVED(已入库)",
)
notify_parent_on_complete: Mapped[bool] = mapped_column(
Boolean, default=False, comment="完成后是否通知父任务",
)
# ---- 时间追踪 ----
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), comment="创建时间",
)
received_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True, comment="操作员确认接收时间",
)
completed_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True, comment="任务完工转交时间",
)
# ---- 驳回/返工 ----
reject_reason: Mapped[str | None] = mapped_column(
String(500), nullable=True, comment="驳回原因",
)
is_rework: Mapped[bool] = mapped_column(
Boolean, default=False, comment="是否为返工任务",
)
# ---- 关系 ----
product: Mapped["Product"] = relationship("Product", lazy="selectin")
parent_task: Mapped["Task | None"] = relationship(
"Task", remote_side="Task.id", back_populates="child_tasks", lazy="selectin",
)
child_tasks: Mapped[list["Task"]] = relationship(
"Task", back_populates="parent_task", lazy="selectin",
)
def __repr__(self) -> str:
return f"<Task {self.task_name}>"