按 2026-11-02 需求补齐计划交付后端能力: - 角色授权:权限目录化,接口统一准入校验,未登记默认拒绝; 管理员判断改为按数据库角色重新判定,防止权限码持有者绕过 - 系统监控:单进程采集资源、请求与异常指标,分钟级聚合, 阈值配置化;敏感配置增加 repr 保护,Redis 密码 URL 转义 - 试用期计提:按回款日判定并写入快照,年度结清与调整单联动; 人员模型补试用期、离职日期与工资版本历史字段 - 计提模板:公式骨架受控,页面维护名称与参数绑定 - T+ 采集:自动化配置表与进度查询 内置角色禁停用保护对齐模块注释;核算规则版本提为常量并 补充批量核算失败堆栈日志。 影响范围:后端全部模块、数据库迁移 V22-V28 验证:uv run ruff check 通过;922 个单元测试全部通过; 集成测试因本机 MySQL 数据卷被其他容器锁定暂未运行
61 lines
2.6 KiB
Python
61 lines
2.6 KiB
Python
"""产品模型:产品主数据。
|
||
|
||
产品类别(product_category)是**折算阈值的行级锚点**:混合业务按产品逐条
|
||
计算(对照表 #14),阈值本身由 M1 参数 `product.threshold` 按 PRODUCT_CATEGORY
|
||
维度承担(#28「全部阈值统一在系统设置维护」),本表不建阈值列 —— 两处维护
|
||
必然漂移。类别值域与 M1 参数维度共用 PRODUCT_CATEGORIES 常量。
|
||
"""
|
||
|
||
from decimal import Decimal
|
||
|
||
from sqlalchemy import JSON, Numeric, String, UniqueConstraint
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.models.base import (
|
||
BIGINT_UNSIGNED,
|
||
TINYINT_TYPE,
|
||
Base,
|
||
TimestampMixin,
|
||
TPlusSyncMixin,
|
||
mysql_table_args,
|
||
)
|
||
|
||
|
||
class Product(Base, TimestampMixin, TPlusSyncMixin):
|
||
"""产品表(需求 2.1.2)。停用(status=0)为主,不物理删除。"""
|
||
|
||
__tablename__ = "products"
|
||
__table_args__ = mysql_table_args(
|
||
"产品表(类别锚定折算阈值参数;T+同步不覆盖产品类别)",
|
||
UniqueConstraint("product_name", "spec_model", name="uk_products_name_spec"),
|
||
)
|
||
|
||
id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||
)
|
||
product_name: Mapped[str] = mapped_column(String(128), nullable=False, comment="产品名称")
|
||
spec_model: Mapped[str] = mapped_column(
|
||
String(128),
|
||
nullable=False,
|
||
server_default="''",
|
||
comment="规格型号(空串而非 NULL:参与组合唯一键,MySQL 组合索引对 NULL 不去重)",
|
||
)
|
||
unit: Mapped[str | None] = mapped_column(String(16), comment="计量单位")
|
||
stock_quantity: Mapped[Decimal | None] = mapped_column(
|
||
Numeric(14, 2), comment="数量(T+ 同步原样存储,语义待 IT 确认)"
|
||
)
|
||
sale_price: Mapped[Decimal | None] = mapped_column(
|
||
Numeric(14, 4), comment="销售单价(元,T+ 同步)"
|
||
)
|
||
product_category: Mapped[str] = mapped_column(
|
||
String(32),
|
||
nullable=False,
|
||
comment="产品类别:municipal_water市政水利 rail_transit轨道交通(决定折算阈值 30%/20%;T+同步不覆盖)",
|
||
)
|
||
status: Mapped[int] = mapped_column(
|
||
TINYINT_TYPE, nullable=False, server_default="1", comment="状态:1启用 0停用"
|
||
)
|
||
remark: Mapped[str | None] = mapped_column(String(255), comment="备注")
|
||
source_trade_json: Mapped[dict | None] = mapped_column(JSON, comment="最近有效发货数量、含税成交价及源单据快照")
|
||
quantity_price_manual: Mapped[int] = mapped_column(TINYINT_TYPE, nullable=False, server_default="0", comment="数量单价人工保护:1人工维护 0随源更新")
|