feat(system): 新增岗位角色与计提参数四表及 V3 迁移
- business_roles/param_definitions/param_change_batches/param_values 四表 + 种子(3 内置岗位/16 参数定义/19 版本条目/初始批次 P20260101-00) - 双轨迁移:Alembic bfbda9c3191d + db/migration/V3 导出 + init-dev.sql 同步(schema_sync 校验通过) - 参数值以 Fraction 可解析字符串存储(4/360 禁 0.011111);企业户 2‰→3‰ 双种子支持按到账日回溯 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
c7212cd93f
commit
bc019cadf5
8 files changed
+1375
-1
No files matched your search
@@ -10,15 +10,21 @@
|
||||
"""
|
||||
|
||||
from app.models.base import Base, TimestampMixin
|
||||
from app.models.business_role import BusinessRole
|
||||
from app.models.login_log import LoginLog
|
||||
from app.models.operation_log import OperationLog
|
||||
from app.models.param import ParamChangeBatch, ParamDefinition, ParamValue
|
||||
from app.models.role import Permission, Role, RolePermission
|
||||
from app.models.user import User, UserRole
|
||||
|
||||
__all__ = [
|
||||
"Base",
|
||||
"BusinessRole",
|
||||
"LoginLog",
|
||||
"OperationLog",
|
||||
"ParamChangeBatch",
|
||||
"ParamDefinition",
|
||||
"ParamValue",
|
||||
"Permission",
|
||||
"Role",
|
||||
"RolePermission",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
"""业务岗位角色模型。
|
||||
|
||||
与系统登录角色(`roles`,权限维度)严格区分:本表是**业务岗位**维度,
|
||||
决定人员适用的计提公式模板与参数。需求 #28 要求岗位角色可增删、
|
||||
新增岗位时在系统设置中绑定公式与参数(无需改代码),故模板编码
|
||||
存于本表、公式实现留在代码内注册表(一期不引入规则引擎)。
|
||||
"""
|
||||
|
||||
from sqlalchemy import Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import BIGINT_UNSIGNED, TINYINT_TYPE, Base, TimestampMixin, mysql_table_args
|
||||
|
||||
|
||||
class BusinessRole(Base, TimestampMixin):
|
||||
"""业务岗位角色表。内置三个岗位(营销员/营销经理/信息员)随迁移初始化。"""
|
||||
|
||||
__tablename__ = "business_roles"
|
||||
__table_args__ = mysql_table_args("业务岗位角色表(与登录角色roles区分,决定计提公式与参数)")
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||||
)
|
||||
role_code: Mapped[str] = mapped_column(
|
||||
String(32),
|
||||
nullable=False,
|
||||
unique=True,
|
||||
comment="岗位编码:salesperson营销员 sales_manager营销经理 info_officer信息员,创建后不可修改",
|
||||
)
|
||||
role_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="岗位名称")
|
||||
calc_template: Mapped[str] = mapped_column(
|
||||
String(32), nullable=False, comment="计提公式模板编码(以代码内模板注册表为准)"
|
||||
)
|
||||
description: Mapped[str | None] = mapped_column(String(255), comment="岗位说明")
|
||||
sort_order: Mapped[int] = mapped_column(
|
||||
Integer, nullable=False, server_default="0", comment="显示排序"
|
||||
)
|
||||
status: Mapped[int] = mapped_column(
|
||||
TINYINT_TYPE, nullable=False, server_default="1", comment="状态:1启用 0禁用"
|
||||
)
|
||||
is_builtin: Mapped[int] = mapped_column(
|
||||
TINYINT_TYPE,
|
||||
nullable=False,
|
||||
server_default="0",
|
||||
comment="是否内置岗位:1内置(禁删禁停) 0自定义",
|
||||
)
|
||||
@@ -0,0 +1,159 @@
|
||||
"""计提参数模型:定义、变更批次与版本条目。
|
||||
|
||||
存储设计(M1 评审定稿):
|
||||
- 参数值按**生效日期时点化**存储(逐项版本条目,append-only),核算按业务
|
||||
日期回溯取值(对照表 #11:按回款到账日匹配参数版本),禁读「当前值」算历史
|
||||
- 「版本」由变更批次承载:一次保存 = 一个批次 = 一条变更记录;条目逐项留痕
|
||||
(旧值/新值),满足 #28 版本管理与留痕(需规 2.3.1 四)
|
||||
- 值一律为 Fraction 可解析字符串(如 "4/360",禁 0.011111),解析不经 float
|
||||
- **不设 (param_id, dimension_value, effective_date) 唯一键**:同日多次修正
|
||||
是合法留痕,解析取 (effective_date, id) 最新一条;唯一键会把同日二次变更
|
||||
逼成覆盖写、丢失中间值
|
||||
- 批次与条目均为 append-only(仅 create_time、无 update_time,同 login_logs
|
||||
先例):带 ON UPDATE 的列会让「未改也被刷新」造成留痕假象
|
||||
"""
|
||||
|
||||
from datetime import date, datetime
|
||||
|
||||
from sqlalchemy import Date, DateTime, ForeignKey, Index, Integer, String, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import BIGINT_UNSIGNED, TINYINT_TYPE, Base, TimestampMixin, mysql_table_args
|
||||
|
||||
|
||||
class ParamDefinition(Base, TimestampMixin):
|
||||
"""计提参数定义表。目录元数据(类型/单位/维度/取值域),随迁移种子初始化。"""
|
||||
|
||||
__tablename__ = "param_definitions"
|
||||
__table_args__ = mysql_table_args("计提参数定义表")
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||||
)
|
||||
param_code: Mapped[str] = mapped_column(
|
||||
String(64), nullable=False, unique=True, comment="参数编码,如 salesperson.rate.slope"
|
||||
)
|
||||
param_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="参数名称")
|
||||
param_group: Mapped[str] = mapped_column(
|
||||
String(32),
|
||||
nullable=False,
|
||||
comment="参数分组:业务员个人户/经理分成/企业户/信息员/支付环节/产品阈值/月工资口径",
|
||||
)
|
||||
value_type: Mapped[str] = mapped_column(
|
||||
String(16), nullable=False, comment="值类型:DECIMAL/INT/BOOL/ENUM/TEXT"
|
||||
)
|
||||
unit: Mapped[str | None] = mapped_column(String(16), comment="展示单位:‰/%/元/天,无单位为空")
|
||||
dimension_type: Mapped[str] = mapped_column(
|
||||
String(32),
|
||||
nullable=False,
|
||||
server_default="NONE",
|
||||
comment="维度类型:NONE/PRODUCT_CATEGORY/BUSINESS_ROLE",
|
||||
)
|
||||
options_text: Mapped[str | None] = mapped_column(
|
||||
String(255), comment="枚举选项(竖线分隔),仅 ENUM 使用"
|
||||
)
|
||||
default_value: Mapped[str | None] = mapped_column(
|
||||
String(64), comment="系统默认值(Fraction 可解析字符串)"
|
||||
)
|
||||
value_min: Mapped[str | None] = mapped_column(String(64), comment="取值下限(含),校验用")
|
||||
value_max: Mapped[str | None] = mapped_column(String(64), comment="取值上限(含),校验用")
|
||||
description: Mapped[str | None] = mapped_column(String(255), comment="口径说明(配置页展示)")
|
||||
sort_order: Mapped[int] = mapped_column(
|
||||
Integer, nullable=False, server_default="0", comment="显示排序"
|
||||
)
|
||||
status: Mapped[int] = mapped_column(
|
||||
TINYINT_TYPE, nullable=False, server_default="1", comment="状态:1启用 0停用"
|
||||
)
|
||||
|
||||
|
||||
class ParamChangeBatch(Base):
|
||||
"""参数变更批次表(append-only)。
|
||||
|
||||
一次提交 = 一个批次;版本号(如 P20261012-01)供对比与追溯引用。
|
||||
未生效批次可整批撤回(删批次与条目);已生效条目禁改禁删。
|
||||
"""
|
||||
|
||||
__tablename__ = "param_change_batches"
|
||||
__table_args__ = mysql_table_args("参数变更批次表")
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||||
)
|
||||
version_no: Mapped[str] = mapped_column(
|
||||
String(32), nullable=False, unique=True, comment="版本号,如 P20261012-01"
|
||||
)
|
||||
effective_date: Mapped[date] = mapped_column(
|
||||
Date, nullable=False, comment="生效日期(业务日期口径)"
|
||||
)
|
||||
change_type: Mapped[int] = mapped_column(
|
||||
TINYINT_TYPE, nullable=False, comment="生效方式:1立即生效 2指定日期生效"
|
||||
)
|
||||
remark: Mapped[str | None] = mapped_column(String(255), comment="变更说明")
|
||||
operator_id: Mapped[int | None] = mapped_column(
|
||||
BIGINT_UNSIGNED,
|
||||
ForeignKey("users.id", ondelete="SET NULL"),
|
||||
comment="操作人ID(账号删除后置空)",
|
||||
)
|
||||
operator_name: Mapped[str] = mapped_column(
|
||||
String(64), nullable=False, comment="操作人用户名(冗余固化)"
|
||||
)
|
||||
item_count: Mapped[int] = mapped_column(
|
||||
Integer, nullable=False, server_default="0", comment="变更参数项数"
|
||||
)
|
||||
create_time: Mapped[datetime] = mapped_column(
|
||||
DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP"), comment="创建时间"
|
||||
)
|
||||
|
||||
|
||||
class ParamValue(Base):
|
||||
"""参数版本条目表(append-only)。
|
||||
|
||||
解析规则:按 (param_id, dimension_value) 取 effective_date <= 业务日期 的
|
||||
ORDER BY effective_date DESC, id DESC 首条(同日多次变更取最新)。
|
||||
dimension_value 用空串而非 NULL:MySQL 组合索引对 NULL 不去重,空串语义更稳。
|
||||
"""
|
||||
|
||||
__tablename__ = "param_values"
|
||||
__table_args__ = mysql_table_args(
|
||||
"参数版本条目表(append-only,按生效日期时点化取值)",
|
||||
Index(
|
||||
"idx_param_values_param_id_dimension_value_effective_date",
|
||||
"param_id",
|
||||
"dimension_value",
|
||||
"effective_date",
|
||||
),
|
||||
Index("idx_param_values_effective_date", "effective_date"),
|
||||
Index("idx_param_values_batch_id", "batch_id"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||||
)
|
||||
param_id: Mapped[int] = mapped_column(
|
||||
BIGINT_UNSIGNED,
|
||||
ForeignKey("param_definitions.id", ondelete="RESTRICT"),
|
||||
nullable=False,
|
||||
comment="参数定义ID(param_definitions.id)",
|
||||
)
|
||||
dimension_value: Mapped[str] = mapped_column(
|
||||
String(32),
|
||||
nullable=False,
|
||||
server_default=text("''"),
|
||||
comment="维度取值:NONE维度为空串;产品类别/岗位编码为具体值",
|
||||
)
|
||||
effective_date: Mapped[date] = mapped_column(
|
||||
Date, nullable=False, comment="生效日期(按业务日期时点化取值)"
|
||||
)
|
||||
value_text: Mapped[str] = mapped_column(
|
||||
String(64), nullable=False, comment="参数值(Fraction 可解析字符串/枚举码/开关)"
|
||||
)
|
||||
old_value_text: Mapped[str | None] = mapped_column(String(64), comment="变更前值(留痕)")
|
||||
batch_id: Mapped[int] = mapped_column(
|
||||
BIGINT_UNSIGNED,
|
||||
ForeignKey("param_change_batches.id", ondelete="RESTRICT"),
|
||||
nullable=False,
|
||||
comment="变更批次ID(param_change_batches.id)",
|
||||
)
|
||||
create_time: Mapped[datetime] = mapped_column(
|
||||
DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP"), comment="创建时间"
|
||||
)
|
||||
Reference in new issue
Block a user