2026-05-30 06:57:21 +08:00
|
|
|
|
"""业务核心 ORM 模型。
|
|
|
|
|
|
|
|
|
|
|
|
定义订单管理系统的所有业务数据表,包括客户、产品、供应商、
|
|
|
|
|
|
订单、物流、提醒、文件附件、定价规则等。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
2026-05-26 15:24:41 +08:00
|
|
|
|
from sqlalchemy import Boolean, Date, DateTime, ForeignKey, Integer, Numeric, String, Text, func
|
2026-05-14 10:15:51 +08:00
|
|
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
from backend.app.db import Base
|
|
|
|
|
|
from backend.app.models.base import AuditMixin, TimestampMixin
|
2026-05-14 10:15:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
class Customer(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""客户表(customer)。
|
|
|
|
|
|
|
|
|
|
|
|
存储客户基本信息、结算方式、所属业务员、信用额度等。
|
|
|
|
|
|
支持软删除(AuditMixin.deleted)。
|
|
|
|
|
|
被调用方: customer_repository、customer_service、order_service
|
|
|
|
|
|
"""
|
2026-05-14 13:51:06 +08:00
|
|
|
|
__tablename__ = "customer"
|
2026-05-14 10:15:51 +08:00
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
customer_name: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
mobile: Mapped[str] = mapped_column(String(32), index=True)
|
|
|
|
|
|
address: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
settlement_type: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
settlement_days: Mapped[int] = mapped_column(default=0)
|
|
|
|
|
|
customer_type: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
2026-05-26 15:24:41 +08:00
|
|
|
|
price_tier: Mapped[str | None] = mapped_column(String(32), nullable=True, default="default")
|
2026-05-14 13:51:06 +08:00
|
|
|
|
salesman_id: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
credit_limit: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
2026-05-14 10:15:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
class ProductCategory(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""产品分类表(product_category)。
|
|
|
|
|
|
|
|
|
|
|
|
管理产品的一级分类,如"铝板"、"钢材"等。
|
|
|
|
|
|
category_code 唯一标识,sort_no 控制前端排序。
|
|
|
|
|
|
"""
|
2026-05-14 13:51:06 +08:00
|
|
|
|
__tablename__ = "product_category"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
category_name: Mapped[str] = mapped_column(String(64))
|
|
|
|
|
|
category_code: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
|
|
|
|
|
sort_no: Mapped[int] = mapped_column(default=0)
|
|
|
|
|
|
status: Mapped[int] = mapped_column(default=1)
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Product(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""产品表(product)。
|
|
|
|
|
|
|
|
|
|
|
|
存储产品名称、规格、单位、成本价、售价等信息。
|
|
|
|
|
|
category_id 关联 product_category 表,is_default 标记默认规格。
|
|
|
|
|
|
被调用方: product_repository、product_service、pricing_engine
|
|
|
|
|
|
"""
|
2026-05-14 10:15:51 +08:00
|
|
|
|
__tablename__ = "product"
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
product_name: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
specification: Mapped[str] = mapped_column(String(64), default="")
|
|
|
|
|
|
unit: Mapped[str] = mapped_column(String(32), default="")
|
|
|
|
|
|
category: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
category_id: Mapped[int | None] = mapped_column(ForeignKey("product_category.id"), nullable=True)
|
|
|
|
|
|
cost_price: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
sale_price: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
2026-05-26 15:24:41 +08:00
|
|
|
|
pricing_type: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
pricing_unit: Mapped[str | None] = mapped_column(String(16), nullable=True, default="㎡")
|
|
|
|
|
|
thickness: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
weight_gsm: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
|
|
|
|
default_width_m: Mapped[float | None] = mapped_column(Numeric(10, 4), nullable=True)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
status: Mapped[int] = mapped_column(default=1)
|
2026-05-21 14:59:38 +08:00
|
|
|
|
is_default: Mapped[int] = mapped_column(default=0)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Supplier(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""供应商表(supplier)。
|
|
|
|
|
|
|
|
|
|
|
|
存储供应商/工厂基本信息,supplier_type 区分"factory"等类型。
|
|
|
|
|
|
template_type 用于生成发厂文本时选择对应的模板。
|
|
|
|
|
|
"""
|
2026-05-14 13:51:06 +08:00
|
|
|
|
__tablename__ = "supplier"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
supplier_name: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
supplier_type: Mapped[str] = mapped_column(String(32), default="factory")
|
|
|
|
|
|
contact_name: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
contact_mobile: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
address: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
template_type: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
status: Mapped[int] = mapped_column(default=1)
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SalesOrder(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""销售订单主表(sales_order)。
|
|
|
|
|
|
|
|
|
|
|
|
订单全流程的核心表,包含客户信息快照、金额汇总、状态流转、
|
|
|
|
|
|
取消审批、发厂确认等字段。order_status 驱动整个业务流程。
|
|
|
|
|
|
状态流转: draft → pending_approve → approved → pending_factory → ...
|
|
|
|
|
|
被调用方: order_repository、order_service、reminder_service
|
|
|
|
|
|
"""
|
2026-05-14 10:15:51 +08:00
|
|
|
|
__tablename__ = "sales_order"
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
order_no: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
|
|
|
|
|
customer_id: Mapped[int | None] = mapped_column(ForeignKey("customer.id"), nullable=True)
|
|
|
|
|
|
customer_name: Mapped[str] = mapped_column(String(64))
|
|
|
|
|
|
customer_mobile: Mapped[str] = mapped_column(String(32))
|
|
|
|
|
|
customer_address: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
salesman_id: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
order_status: Mapped[str] = mapped_column(String(32), index=True, default="draft")
|
|
|
|
|
|
order_source: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
delivery_type: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
factory_id: Mapped[int | None] = mapped_column(ForeignKey("supplier.id"), nullable=True)
|
|
|
|
|
|
sale_price_total: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
cost_price_total: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
rebate_total: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
freight_total: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
tax_total: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
other_fee_total: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
profit_total: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
profit_rate: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
commission_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
cancel_requested_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
cancel_requested_at: Mapped[DateTime | None] = mapped_column(DateTime, nullable=True)
|
|
|
|
|
|
cancel_reason: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
cancel_opinion: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
cancel_previous_status: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
supplier_text_confirmed_at: Mapped[DateTime | None] = mapped_column(DateTime, nullable=True)
|
|
|
|
|
|
supplier_text_confirmed_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SalesOrderItem(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""订单明细行表(sales_order_item)。
|
|
|
|
|
|
|
|
|
|
|
|
每个订单包含多条明细,记录产品、数量、单价、面积、附加费用等。
|
|
|
|
|
|
pricing_type 区分按面积/按重量等计价方式。
|
|
|
|
|
|
被调用方: order_repository、order_service
|
|
|
|
|
|
"""
|
2026-05-14 10:15:51 +08:00
|
|
|
|
__tablename__ = "sales_order_item"
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
order_id: Mapped[int] = mapped_column(ForeignKey("sales_order.id"), index=True)
|
|
|
|
|
|
product_id: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
product_name: Mapped[str] = mapped_column(String(64))
|
|
|
|
|
|
specification: Mapped[str] = mapped_column(String(64), default="")
|
|
|
|
|
|
unit: Mapped[str] = mapped_column(String(32), default="")
|
|
|
|
|
|
quantity: Mapped[float] = mapped_column(Numeric(18, 4), default=0)
|
|
|
|
|
|
sale_price: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
cost_price: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
rebate_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
freight_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
tax_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
other_fee_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
2026-05-26 15:24:41 +08:00
|
|
|
|
pricing_type: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
length_m: Mapped[float | None] = mapped_column(Numeric(10, 4), nullable=True)
|
|
|
|
|
|
width_m: Mapped[float | None] = mapped_column(Numeric(10, 4), nullable=True)
|
|
|
|
|
|
area_sqm: Mapped[float | None] = mapped_column(Numeric(18, 4), nullable=True)
|
|
|
|
|
|
surcharge_detail: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
processing_detail: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
supplier_id: Mapped[int | None] = mapped_column(ForeignKey("supplier.id"), nullable=True)
|
|
|
|
|
|
supplier_model: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
price_tier: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-14 13:57:32 +08:00
|
|
|
|
class SalesOrderApproveLog(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""订单审批日志表(sales_order_approve_log)。
|
|
|
|
|
|
|
|
|
|
|
|
记录每次审批操作的结果(通过/驳回)、审批前后状态、审批意见。
|
|
|
|
|
|
approve_type 区分"order"(订单审批)和"cancel_order"(取消审批)。
|
|
|
|
|
|
被调用方: order_service
|
|
|
|
|
|
"""
|
2026-05-14 13:57:32 +08:00
|
|
|
|
__tablename__ = "sales_order_approve_log"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
order_id: Mapped[int] = mapped_column(ForeignKey("sales_order.id"), index=True)
|
|
|
|
|
|
approve_type: Mapped[str] = mapped_column(String(32), default="order")
|
|
|
|
|
|
approve_result: Mapped[str] = mapped_column(String(32))
|
|
|
|
|
|
before_status: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
after_status: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
approve_opinion: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
operator_id: Mapped[int | None] = mapped_column(nullable=True)
|
2026-05-19 17:30:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OrderSupplierTextLog(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""发厂文本日志表(order_supplier_text_log)。
|
|
|
|
|
|
|
|
|
|
|
|
记录为供应商生成的发厂文本内容及确认状态。
|
|
|
|
|
|
confirmed 标记工厂是否已确认文本内容。
|
|
|
|
|
|
被调用方: order_service
|
|
|
|
|
|
"""
|
2026-05-19 17:30:35 +08:00
|
|
|
|
__tablename__ = "order_supplier_text_log"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
order_id: Mapped[int] = mapped_column(ForeignKey("sales_order.id"), index=True)
|
|
|
|
|
|
supplier_id: Mapped[int] = mapped_column(ForeignKey("supplier.id"), index=True)
|
|
|
|
|
|
template_type: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
text_content: Mapped[str] = mapped_column(Text)
|
|
|
|
|
|
confirmed: Mapped[int] = mapped_column(default=0)
|
|
|
|
|
|
confirmed_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
confirmed_at: Mapped[DateTime | None] = mapped_column(DateTime, nullable=True)
|
|
|
|
|
|
created_by: Mapped[int | None] = mapped_column(nullable=True)
|
2026-05-14 13:57:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
class LogisticsTask(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""物流任务表(logistics_task)。
|
|
|
|
|
|
|
|
|
|
|
|
记录每个订单的物流配送任务,包含取货/送货地址、司机、
|
|
|
|
|
|
快递单号、任务状态等。status: pending → accepted → picked_up → delivered。
|
|
|
|
|
|
被调用方: logistics_repository、logistics_service、reminder_service
|
|
|
|
|
|
"""
|
2026-05-14 13:51:06 +08:00
|
|
|
|
__tablename__ = "logistics_task"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
2026-06-07 16:00:02 +08:00
|
|
|
|
task_no: Mapped[str | None] = mapped_column(String(64), nullable=True, unique=True)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
order_id: Mapped[int] = mapped_column(ForeignKey("sales_order.id"), index=True)
|
|
|
|
|
|
driver_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
factory_id: Mapped[int | None] = mapped_column(ForeignKey("supplier.id"), nullable=True)
|
|
|
|
|
|
pickup_address: Mapped[str] = mapped_column(String(255))
|
|
|
|
|
|
delivery_address: Mapped[str] = mapped_column(String(255))
|
|
|
|
|
|
pickup_content: Mapped[str] = mapped_column(String(255))
|
|
|
|
|
|
quantity: Mapped[float] = mapped_column(Numeric(18, 4), default=0)
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(32), default="pending")
|
2026-05-27 14:43:54 +08:00
|
|
|
|
tracking_number: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
express_company: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
created_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
canceled_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
cancel_reason: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
2026-05-15 11:10:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-05-15 11:31:55 +08:00
|
|
|
|
class LogisticsTrace(Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""物流轨迹表(logistics_trace)。
|
|
|
|
|
|
|
|
|
|
|
|
记录物流节点的时间、描述、类型、数据来源平台。
|
|
|
|
|
|
支持从快递100等第三方平台同步轨迹数据。
|
|
|
|
|
|
"""
|
2026-05-15 11:31:55 +08:00
|
|
|
|
__tablename__ = "logistics_trace"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
order_id: Mapped[int] = mapped_column(ForeignKey("sales_order.id"), index=True)
|
|
|
|
|
|
task_id: Mapped[int | None] = mapped_column(ForeignKey("logistics_task.id"), nullable=True, index=True)
|
|
|
|
|
|
node_time: Mapped[DateTime] = mapped_column(DateTime)
|
|
|
|
|
|
node_desc: Mapped[str] = mapped_column(String(500))
|
|
|
|
|
|
node_type: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
source_platform: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-15 11:10:44 +08:00
|
|
|
|
class FileAttachment(Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""文件附件表(file_attachment)。
|
|
|
|
|
|
|
|
|
|
|
|
通用文件关联表,通过 biz_type + biz_id 关联任意业务对象。
|
|
|
|
|
|
存储文件 URL、类型、大小、阿里云 OSS 存储信息等。
|
|
|
|
|
|
被调用方: file_repository、file_service
|
|
|
|
|
|
"""
|
2026-05-15 11:10:44 +08:00
|
|
|
|
__tablename__ = "file_attachment"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
biz_type: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
biz_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
file_name: Mapped[str] = mapped_column(String(255))
|
|
|
|
|
|
file_url: Mapped[str] = mapped_column(String(1000))
|
|
|
|
|
|
file_type: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
file_size: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
created_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|
|
|
|
|
|
storage_provider: Mapped[str | None] = mapped_column(String(32), nullable=True, default="aliyun_oss")
|
|
|
|
|
|
bucket_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
|
|
|
|
object_key: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
|
|
|
|
|
content_type: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
|
|
|
|
file_ext: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
file_category: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
2026-05-15 11:24:15 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CustomerArrears(Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""客户欠款表(customer_arrears)。
|
|
|
|
|
|
|
|
|
|
|
|
记录客户未结清的欠款信息,包括欠款金额、账期起始日、到期日。
|
|
|
|
|
|
status: pending → overdue,超期后触发提醒。
|
|
|
|
|
|
被调用方: reminder_repository、reminder_service
|
|
|
|
|
|
"""
|
2026-05-15 11:24:15 +08:00
|
|
|
|
__tablename__ = "customer_arrears"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
customer_id: Mapped[int] = mapped_column(ForeignKey("customer.id"), index=True)
|
|
|
|
|
|
order_id: Mapped[int] = mapped_column(ForeignKey("sales_order.id"), index=True)
|
|
|
|
|
|
arrears_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
settlement_start_date: Mapped[Date | None] = mapped_column(Date, nullable=True)
|
|
|
|
|
|
due_date: Mapped[Date | None] = mapped_column(Date, nullable=True)
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(32), default="pending")
|
|
|
|
|
|
reminded_at: Mapped[DateTime | None] = mapped_column(DateTime, nullable=True)
|
|
|
|
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SystemReminder(Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""系统提醒表(system_reminder)。
|
|
|
|
|
|
|
|
|
|
|
|
存储系统自动生成的提醒消息,如物流超时、欠款逾期、沉默客户等。
|
|
|
|
|
|
reminder_type 区分提醒类型,receiver_user_id 指定接收人。
|
|
|
|
|
|
status: pending → read。
|
|
|
|
|
|
被调用方: reminder_repository、reminder_service
|
|
|
|
|
|
"""
|
2026-05-15 11:24:15 +08:00
|
|
|
|
__tablename__ = "system_reminder"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
reminder_type: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
biz_type: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
biz_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
receiver_user_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
reminder_title: Mapped[str] = mapped_column(String(255))
|
|
|
|
|
|
reminder_content: Mapped[str] = mapped_column(String(2000))
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(32), default="pending")
|
|
|
|
|
|
sent_at: Mapped[DateTime | None] = mapped_column(DateTime, nullable=True)
|
|
|
|
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|
2026-05-15 11:47:29 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AIRecognitionLog(Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""AI 识别日志表(ai_recognition_log)。
|
|
|
|
|
|
|
|
|
|
|
|
记录 AI 图片识别的原始结果、置信度、人工修正结果。
|
|
|
|
|
|
用于 AI 识别功能的结果追踪和模型优化。
|
|
|
|
|
|
被调用方: ai_repository、ai_service
|
|
|
|
|
|
"""
|
2026-05-15 11:47:29 +08:00
|
|
|
|
__tablename__ = "ai_recognition_log"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
biz_type: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
biz_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
image_url: Mapped[str] = mapped_column(String(1000))
|
|
|
|
|
|
raw_result: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
confidence: Mapped[float | None] = mapped_column(Numeric(10, 4), nullable=True)
|
|
|
|
|
|
corrected_result: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
created_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|
2026-05-26 15:24:41 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProductPricingRule(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""产品定价规则表(product_pricing_rule)。
|
|
|
|
|
|
|
|
|
|
|
|
定义每个产品的计价方式(按面积/按重量)、基准单价、
|
|
|
|
|
|
计算公式、附加费用等。被 pricing_engine 在创建订单时调用。
|
|
|
|
|
|
"""
|
2026-05-26 15:24:41 +08:00
|
|
|
|
__tablename__ = "product_pricing_rule"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
product_id: Mapped[int] = mapped_column(unique=True, index=True)
|
|
|
|
|
|
product_name: Mapped[str] = mapped_column(String(128))
|
|
|
|
|
|
pricing_type: Mapped[str] = mapped_column(String(32), default="area")
|
|
|
|
|
|
base_unit_price: Mapped[float] = mapped_column(Numeric(18, 4), default=0)
|
|
|
|
|
|
pricing_unit: Mapped[str] = mapped_column(String(16), default="㎡")
|
|
|
|
|
|
pricing_inputs: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
formula_expr: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
formula_constants: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
surcharge_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
formula_note: Mapped[str | None] = mapped_column(Text, nullable=True)
|
2026-05-30 11:15:55 +08:00
|
|
|
|
tax_rate: Mapped[float] = mapped_column(Numeric(5, 2), default=0)
|
|
|
|
|
|
tax_inclusive: Mapped[int] = mapped_column(default=0)
|
2026-05-26 15:24:41 +08:00
|
|
|
|
status: Mapped[int] = mapped_column(default=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SupplierProductCost(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""供应商产品成本表(supplier_product_cost)。
|
|
|
|
|
|
|
|
|
|
|
|
记录每个供应商对每个产品的成本价格,支持按厚度、克重等维度定价。
|
|
|
|
|
|
is_primary 标记主供应商。被 pricing_engine 在计算订单成本时调用。
|
|
|
|
|
|
"""
|
2026-05-26 15:24:41 +08:00
|
|
|
|
__tablename__ = "supplier_product_cost"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
product_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
supplier_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
supplier_model: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
our_model: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
thickness: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
weight_gsm: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
|
|
|
|
base_fabric_weight: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
|
|
|
|
cost_price: Mapped[float] = mapped_column(Numeric(18, 4))
|
|
|
|
|
|
cost_unit: Mapped[str] = mapped_column(String(16), default="㎡")
|
|
|
|
|
|
is_primary: Mapped[int] = mapped_column(default=0)
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
status: Mapped[int] = mapped_column(default=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProductPriceTier(TimestampMixin, AuditMixin, Base):
|
2026-05-30 06:57:21 +08:00
|
|
|
|
"""产品价格层级表(product_price_tier)。
|
|
|
|
|
|
|
|
|
|
|
|
定义产品的多级价格体系(如普通客户价、VIP客户价)。
|
|
|
|
|
|
tier_code 区分层级,前端根据客户的价格层级选择对应售价。
|
|
|
|
|
|
"""
|
2026-05-26 15:24:41 +08:00
|
|
|
|
__tablename__ = "product_price_tier"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
product_id: Mapped[int] = mapped_column(index=True)
|
|
|
|
|
|
tier_code: Mapped[str] = mapped_column(String(32))
|
|
|
|
|
|
tier_name: Mapped[str] = mapped_column(String(64))
|
|
|
|
|
|
price: Mapped[float] = mapped_column(Numeric(18, 4))
|
|
|
|
|
|
price_unit: Mapped[str] = mapped_column(String(16), default="㎡")
|
|
|
|
|
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
|
|
status: Mapped[int] = mapped_column(default=1)
|
2026-06-05 22:26:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-06-07 14:03:36 +08:00
|
|
|
|
class LogisticsWaybill(TimestampMixin, AuditMixin, Base):
|
|
|
|
|
|
"""物流运单号表(logistics_waybill)。
|
|
|
|
|
|
|
|
|
|
|
|
记录一个物流任务关联的多个运单号(一票货分多件场景)。
|
|
|
|
|
|
通过 task_id 关联 logistics_task,order_id 冗余关联 sales_order。
|
|
|
|
|
|
被调用方: logistics_repository、logistics_service
|
|
|
|
|
|
"""
|
|
|
|
|
|
__tablename__ = "logistics_waybill"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
task_id: Mapped[int] = mapped_column(ForeignKey("logistics_task.id"), index=True)
|
|
|
|
|
|
order_id: Mapped[int] = mapped_column(ForeignKey("sales_order.id"), index=True)
|
|
|
|
|
|
tracking_number: Mapped[str] = mapped_column(String(64), index=True)
|
|
|
|
|
|
express_company: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
|
|
|
|
express_name: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
image_url: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
|
|
|
|
|
ocr_raw: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(32), default="pending")
|
|
|
|
|
|
created_by: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-05 22:26:08 +08:00
|
|
|
|
class PerformanceStatCache(Base):
|
|
|
|
|
|
"""业绩统计缓存表(performance_stat_cache)。
|
|
|
|
|
|
|
|
|
|
|
|
存储业绩统计结果缓存,避免重复查询数据库。
|
|
|
|
|
|
created_at 超过 24 小时视为过期。
|
|
|
|
|
|
"""
|
|
|
|
|
|
__tablename__ = "performance_stat_cache"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
|
|
stat_type: Mapped[str] = mapped_column(String(16), index=True)
|
|
|
|
|
|
stat_period: Mapped[str] = mapped_column(String(32), index=True)
|
|
|
|
|
|
category_id: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
|
|
order_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
|
|
order_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
commission_amount: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
|
|
|
|
|
total_profit: Mapped[float] = mapped_column(Numeric(18, 2), default=0)
|
2026-06-14 16:20:04 +08:00
|
|
|
|
category_amounts_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
2026-06-05 22:26:08 +08:00
|
|
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|