104 lines
4.6 KiB
Python
104 lines
4.6 KiB
Python
|
|
"""任务挂载的 MOM 出库物料 — 明细级快照
|
|||
|
|
|
|||
|
|
回答「这个任务用了哪些 MOM 出库物料」。口径已与业务确认:
|
|||
|
|
· 选择粒度 = **整张出库单**(outbound_no),该单据的明细一并带入
|
|||
|
|
—— 不存在"单里混了无关物料"的情况
|
|||
|
|
· **纯引用,不记用量**:quantity 是出库单原值,不是"本任务用了多少"
|
|||
|
|
|
|||
|
|
为什么存明细级快照,而不是只存 outbound_no 现查:
|
|||
|
|
MOM 的 trans_outbound 是**明细行**(一行 = 一条物料),物料名/规格要经
|
|||
|
|
COALESCE 三表 JOIN(stock_buy/stock_semi/stock_product → material_base)
|
|||
|
|
才能解析出来。Track 跨库无法 JOIN,若只存单号,每次展示都要打 MOM ——
|
|||
|
|
MOM 挂了就看不到已挂内容。存快照后 Track 自包含,与既有的
|
|||
|
|
product_outbounds 是同一套存档哲学。
|
|||
|
|
成本实测可忽略:517 张单平均 2.64 条明细,65% 是单条明细。
|
|||
|
|
|
|||
|
|
⚠️ mom_line_id 是**跨库逻辑外键**(指向 MOM 库 trans_outbound.id),无物理
|
|||
|
|
约束 —— 与 assignee_id 指向 MOM sys_user 是同一类做法。MOM 库若重建会让
|
|||
|
|
自增 ID 错位,所以同时冗余 outbound_no 供人工核对。
|
|||
|
|
"""
|
|||
|
|
import uuid
|
|||
|
|
from datetime import datetime
|
|||
|
|
from decimal import Decimal
|
|||
|
|
|
|||
|
|
from sqlalchemy import DateTime, ForeignKey, Numeric, String, UniqueConstraint
|
|||
|
|
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 TaskOutboundMaterial(Base):
|
|||
|
|
__tablename__ = "task_outbound_materials"
|
|||
|
|
# 防同一条出库明细被重复挂到同一任务(重复提交、前端重放、并发点击)
|
|||
|
|
__table_args__ = (
|
|||
|
|
UniqueConstraint("task_id", "mom_line_id",
|
|||
|
|
name="uq_task_outbound_materials_task_line"),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|||
|
|
|
|||
|
|
# ---- 物理外键(关联本库 tasks) ----
|
|||
|
|
task_id: Mapped[uuid.UUID] = mapped_column(
|
|||
|
|
UUID(as_uuid=True), ForeignKey("tasks.id"),
|
|||
|
|
nullable=False, index=True, comment="所属任务ID",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ---- 跨库逻辑外键(MOM 库 trans_outbound.id,无物理约束) ----
|
|||
|
|
mom_line_id: Mapped[int] = mapped_column(
|
|||
|
|
nullable=False, comment="MOM 出库明细行ID(逻辑外键→MOM trans_outbound.id)",
|
|||
|
|
)
|
|||
|
|
outbound_no: Mapped[str] = mapped_column(
|
|||
|
|
String(100), nullable=False, index=True,
|
|||
|
|
comment="MOM 出库单号(批量出库多商品共用,故本表按明细行成行)",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ---- MOM 物料/单据快照(挂载时从 MOM 拉取,之后 Track 自包含) ----
|
|||
|
|
sku: Mapped[str | None] = mapped_column(
|
|||
|
|
String(100), nullable=True, comment="物料SKU(MOM trans_outbound.sku 快照)",
|
|||
|
|
)
|
|||
|
|
material_name: Mapped[str | None] = mapped_column(
|
|||
|
|
String(255), nullable=True, comment="物料名称(经 COALESCE 三表 JOIN 解析后快照)",
|
|||
|
|
)
|
|||
|
|
spec_model: Mapped[str | None] = mapped_column(
|
|||
|
|
String(255), nullable=True, comment="规格型号快照",
|
|||
|
|
)
|
|||
|
|
quantity: Mapped[Decimal | None] = mapped_column(
|
|||
|
|
Numeric(19, 4), nullable=True,
|
|||
|
|
comment="出库数量(出库单原值,**不是**本任务用量)",
|
|||
|
|
)
|
|||
|
|
unit_price: Mapped[Decimal | None] = mapped_column(
|
|||
|
|
Numeric(19, 2), nullable=True, comment="出库单价",
|
|||
|
|
)
|
|||
|
|
outbound_type: Mapped[str | None] = mapped_column(
|
|||
|
|
String(50), nullable=True,
|
|||
|
|
comment="出库类型 SALES/USE/PRODUCTION/LOSS/REPAIR(MOM 码表未冻结,只存不判)",
|
|||
|
|
)
|
|||
|
|
consumer_name: Mapped[str | None] = mapped_column(
|
|||
|
|
String(100), nullable=True, comment="领用人/客户(MOM 侧自由填写,非可靠标识)",
|
|||
|
|
)
|
|||
|
|
operator_name: Mapped[str | None] = mapped_column(
|
|||
|
|
String(100), nullable=True, comment="MOM 侧操作员",
|
|||
|
|
)
|
|||
|
|
warehouse_location: Mapped[str | None] = mapped_column(
|
|||
|
|
String(100), nullable=True, comment="出库库位快照",
|
|||
|
|
)
|
|||
|
|
outbound_time: Mapped[datetime | None] = mapped_column(
|
|||
|
|
DateTime(timezone=True), nullable=True,
|
|||
|
|
comment="MOM 记录的出库时间(写入时已按 +08:00 补全时区)",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
added_by: Mapped[str | None] = mapped_column(
|
|||
|
|
String(64), nullable=True, comment="挂载人ID(逻辑外键→MOM sys_user)",
|
|||
|
|
)
|
|||
|
|
created_at: Mapped[datetime] = mapped_column(
|
|||
|
|
DateTime(timezone=True), default=get_beijing_time, comment="挂载时间",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ---- 关系 ----
|
|||
|
|
task: Mapped["Task"] = relationship("Task", back_populates="outbound_materials")
|
|||
|
|
|
|||
|
|
def __repr__(self) -> str:
|
|||
|
|
return f"<TaskOutboundMaterial {self.outbound_no} sku={self.sku}>"
|