- businesses 五项汇总冗余列服务层事务内维护;毛利润不落库(派生值,M3 台账固化) - 行级 product_category 折算锚点(#14);回款 settlement_status 预置为 M3 防重锚点 - 评级等级种子四条(迁移+init-dev 双写);编号前缀常量 YW/SH/HK - 双轨 SQL 同步(V4/V5 重导,schema_sync+test_models 164 例全绿) Co-Authored-By: Claude Code <noreply@anthropic.com>
116 lines
4.3 KiB
Python
116 lines
4.3 KiB
Python
"""发货模型:发货单与发货产品明细。
|
||
|
||
- ship_date 是**回款天数计算基准日**(对照表 #1:发货日首日计第 1 天),
|
||
回款指定本发货单后由 formula.payment_days 派生回款天数,不在本表落库
|
||
- 运费仅记录展示,不计入毛利润口径(对照表 #2)
|
||
- total_amount 为明细行汇总冗余,服务层事务内维护
|
||
"""
|
||
|
||
from datetime import date
|
||
from decimal import Decimal
|
||
|
||
from sqlalchemy import Date, ForeignKey, Index, Numeric, String
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.models.base import (
|
||
BIGINT_UNSIGNED,
|
||
Base,
|
||
TimestampMixin,
|
||
TPlusSyncMixin,
|
||
mysql_table_args,
|
||
)
|
||
|
||
|
||
class Shipment(Base, TimestampMixin, TPlusSyncMixin):
|
||
"""发货单表(需求 2.2.2):每笔发货对应一个业务,支持分批发货。"""
|
||
|
||
__tablename__ = "shipments"
|
||
__table_args__ = mysql_table_args(
|
||
"发货单表(发货日为回款天数基准日,发货日首日计第 1 天)",
|
||
Index("idx_shipments_business_id", "business_id"),
|
||
Index("idx_shipments_ship_date", "ship_date"),
|
||
)
|
||
|
||
id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||
)
|
||
shipment_no: Mapped[str] = mapped_column(
|
||
String(32),
|
||
nullable=False,
|
||
unique=True,
|
||
comment="发货单号,自动生成 SH{YYYYMMDD}-{4位当日序号}(内部追溯用)",
|
||
)
|
||
business_id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED,
|
||
ForeignKey("businesses.id", ondelete="RESTRICT"),
|
||
nullable=False,
|
||
comment="业务ID(businesses.id;终态业务禁止新发货)",
|
||
)
|
||
ship_date: Mapped[date] = mapped_column(
|
||
Date, nullable=False, comment="发货日期(回款天数基准日,发货日首日=第 1 天)"
|
||
)
|
||
freight_amount: Mapped[Decimal] = mapped_column(
|
||
Numeric(14, 2),
|
||
nullable=False,
|
||
server_default="0",
|
||
comment="运费金额(仅记录展示;不计入毛利润口径,对照表 #2)",
|
||
)
|
||
total_amount: Mapped[Decimal] = mapped_column(
|
||
Numeric(14, 2),
|
||
nullable=False,
|
||
server_default="0",
|
||
comment="发货总金额(明细行汇总冗余,服务层事务内维护,禁手工直改)",
|
||
)
|
||
remark: Mapped[str | None] = mapped_column(String(255), comment="备注")
|
||
|
||
|
||
class ShipmentItem(Base, TimestampMixin):
|
||
"""发货产品明细表(需求 2.2.2):记录发货的产品名称、规格、数量等。
|
||
|
||
价格口径两可(T+ 供价或人工录入,待 IT 确认):sale_price 可空人工补,
|
||
amount 由服务层按 数量×单价 计算固化。
|
||
"""
|
||
|
||
__tablename__ = "shipment_items"
|
||
__table_args__ = mysql_table_args(
|
||
"发货产品明细表",
|
||
Index("idx_shipment_items_shipment_id", "shipment_id"),
|
||
Index("idx_shipment_items_product_id", "product_id"),
|
||
)
|
||
|
||
id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||
)
|
||
shipment_id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED,
|
||
ForeignKey("shipments.id", ondelete="RESTRICT"),
|
||
nullable=False,
|
||
comment="发货单ID(shipments.id)",
|
||
)
|
||
product_id: Mapped[int | None] = mapped_column(
|
||
BIGINT_UNSIGNED,
|
||
ForeignKey("products.id", ondelete="RESTRICT"),
|
||
comment="产品ID(products.id;NULL=自由录入)",
|
||
)
|
||
product_name: Mapped[str] = mapped_column(
|
||
String(128), nullable=False, comment="产品名称(引用产品时冗余固化)"
|
||
)
|
||
spec_model: Mapped[str] = mapped_column(
|
||
String(128),
|
||
nullable=False,
|
||
server_default="''",
|
||
comment="规格型号(冗余固化;空串对齐 products 组合唯一键口径)",
|
||
)
|
||
unit: Mapped[str | None] = mapped_column(String(16), comment="计量单位")
|
||
quantity: Mapped[Decimal] = mapped_column(
|
||
Numeric(14, 2), nullable=False, comment="发货数量(>0)"
|
||
)
|
||
sale_price: Mapped[Decimal | None] = mapped_column(
|
||
Numeric(14, 4), comment="发货单价(元;T+ 同步或人工,口径待 IT 确认)"
|
||
)
|
||
amount: Mapped[Decimal] = mapped_column(
|
||
Numeric(14, 2),
|
||
nullable=False,
|
||
comment="行金额 = 数量×单价(服务层计算固化,不信任前端传值)",
|
||
)
|