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:
parent
c7212cd93f
commit
bc019cadf5
@ -0,0 +1,810 @@
|
||||
"""新增岗位角色与计提参数四表
|
||||
|
||||
Revision ID: bfbda9c3191d
|
||||
Revises: a45a8087831b
|
||||
Create Date: 2026-10-12 16:01:48.760620
|
||||
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
from datetime import date
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "bfbda9c3191d"
|
||||
down_revision: str | Sequence[str] | None = "a45a8087831b"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""应用迁移。"""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"business_roles",
|
||||
sa.Column(
|
||||
"id", mysql.BIGINT(unsigned=True), autoincrement=True, nullable=False, comment="主键ID"
|
||||
),
|
||||
sa.Column(
|
||||
"role_code",
|
||||
sa.String(length=32),
|
||||
nullable=False,
|
||||
comment="岗位编码:salesperson营销员 sales_manager营销经理 info_officer信息员,创建后不可修改",
|
||||
),
|
||||
sa.Column("role_name", sa.String(length=64), nullable=False, comment="岗位名称"),
|
||||
sa.Column(
|
||||
"calc_template",
|
||||
sa.String(length=32),
|
||||
nullable=False,
|
||||
comment="计提公式模板编码(以代码内模板注册表为准)",
|
||||
),
|
||||
sa.Column("description", sa.String(length=255), nullable=True, comment="岗位说明"),
|
||||
sa.Column(
|
||||
"sort_order", sa.Integer(), server_default="0", nullable=False, comment="显示排序"
|
||||
),
|
||||
sa.Column(
|
||||
"status",
|
||||
mysql.TINYINT(),
|
||||
server_default="1",
|
||||
nullable=False,
|
||||
comment="状态:1启用 0禁用",
|
||||
),
|
||||
sa.Column(
|
||||
"is_builtin",
|
||||
mysql.TINYINT(),
|
||||
server_default="0",
|
||||
nullable=False,
|
||||
comment="是否内置岗位:1内置(禁删禁停) 0自定义",
|
||||
),
|
||||
sa.Column(
|
||||
"create_time",
|
||||
sa.DateTime(),
|
||||
server_default=sa.text("CURRENT_TIMESTAMP"),
|
||||
nullable=False,
|
||||
comment="创建时间",
|
||||
),
|
||||
sa.Column(
|
||||
"update_time",
|
||||
sa.DateTime(),
|
||||
server_default=sa.text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"),
|
||||
nullable=False,
|
||||
comment="更新时间",
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_business_roles")),
|
||||
sa.UniqueConstraint("role_code", name=op.f("uk_business_roles_role_code")),
|
||||
comment="业务岗位角色表(与登录角色roles区分,决定计提公式与参数)",
|
||||
mysql_charset="utf8mb4",
|
||||
mysql_collate="utf8mb4_general_ci",
|
||||
mysql_engine="InnoDB",
|
||||
)
|
||||
op.create_table(
|
||||
"param_definitions",
|
||||
sa.Column(
|
||||
"id", mysql.BIGINT(unsigned=True), autoincrement=True, nullable=False, comment="主键ID"
|
||||
),
|
||||
sa.Column(
|
||||
"param_code",
|
||||
sa.String(length=64),
|
||||
nullable=False,
|
||||
comment="参数编码,如 salesperson.rate.slope",
|
||||
),
|
||||
sa.Column("param_name", sa.String(length=64), nullable=False, comment="参数名称"),
|
||||
sa.Column(
|
||||
"param_group",
|
||||
sa.String(length=32),
|
||||
nullable=False,
|
||||
comment="参数分组:业务员个人户/经理分成/企业户/信息员/支付环节/产品阈值/月工资口径",
|
||||
),
|
||||
sa.Column(
|
||||
"value_type",
|
||||
sa.String(length=16),
|
||||
nullable=False,
|
||||
comment="值类型:DECIMAL/INT/BOOL/ENUM/TEXT",
|
||||
),
|
||||
sa.Column(
|
||||
"unit", sa.String(length=16), nullable=True, comment="展示单位:‰/%/元/天,无单位为空"
|
||||
),
|
||||
sa.Column(
|
||||
"dimension_type",
|
||||
sa.String(length=32),
|
||||
server_default="NONE",
|
||||
nullable=False,
|
||||
comment="维度类型:NONE/PRODUCT_CATEGORY/BUSINESS_ROLE",
|
||||
),
|
||||
sa.Column(
|
||||
"options_text",
|
||||
sa.String(length=255),
|
||||
nullable=True,
|
||||
comment="枚举选项(竖线分隔),仅 ENUM 使用",
|
||||
),
|
||||
sa.Column(
|
||||
"default_value",
|
||||
sa.String(length=64),
|
||||
nullable=True,
|
||||
comment="系统默认值(Fraction 可解析字符串)",
|
||||
),
|
||||
sa.Column(
|
||||
"value_min", sa.String(length=64), nullable=True, comment="取值下限(含),校验用"
|
||||
),
|
||||
sa.Column(
|
||||
"value_max", sa.String(length=64), nullable=True, comment="取值上限(含),校验用"
|
||||
),
|
||||
sa.Column(
|
||||
"description", sa.String(length=255), nullable=True, comment="口径说明(配置页展示)"
|
||||
),
|
||||
sa.Column(
|
||||
"sort_order", sa.Integer(), server_default="0", nullable=False, comment="显示排序"
|
||||
),
|
||||
sa.Column(
|
||||
"status",
|
||||
mysql.TINYINT(),
|
||||
server_default="1",
|
||||
nullable=False,
|
||||
comment="状态:1启用 0停用",
|
||||
),
|
||||
sa.Column(
|
||||
"create_time",
|
||||
sa.DateTime(),
|
||||
server_default=sa.text("CURRENT_TIMESTAMP"),
|
||||
nullable=False,
|
||||
comment="创建时间",
|
||||
),
|
||||
sa.Column(
|
||||
"update_time",
|
||||
sa.DateTime(),
|
||||
server_default=sa.text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"),
|
||||
nullable=False,
|
||||
comment="更新时间",
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_param_definitions")),
|
||||
sa.UniqueConstraint("param_code", name=op.f("uk_param_definitions_param_code")),
|
||||
comment="计提参数定义表",
|
||||
mysql_charset="utf8mb4",
|
||||
mysql_collate="utf8mb4_general_ci",
|
||||
mysql_engine="InnoDB",
|
||||
)
|
||||
op.create_table(
|
||||
"param_change_batches",
|
||||
sa.Column(
|
||||
"id", mysql.BIGINT(unsigned=True), autoincrement=True, nullable=False, comment="主键ID"
|
||||
),
|
||||
sa.Column(
|
||||
"version_no", sa.String(length=32), nullable=False, comment="版本号,如 P20261012-01"
|
||||
),
|
||||
sa.Column("effective_date", sa.Date(), nullable=False, comment="生效日期(业务日期口径)"),
|
||||
sa.Column(
|
||||
"change_type",
|
||||
mysql.TINYINT(),
|
||||
nullable=False,
|
||||
comment="生效方式:1立即生效 2指定日期生效",
|
||||
),
|
||||
sa.Column("remark", sa.String(length=255), nullable=True, comment="变更说明"),
|
||||
sa.Column(
|
||||
"operator_id",
|
||||
mysql.BIGINT(unsigned=True),
|
||||
nullable=True,
|
||||
comment="操作人ID(账号删除后置空)",
|
||||
),
|
||||
sa.Column(
|
||||
"operator_name",
|
||||
sa.String(length=64),
|
||||
nullable=False,
|
||||
comment="操作人用户名(冗余固化)",
|
||||
),
|
||||
sa.Column(
|
||||
"item_count", sa.Integer(), server_default="0", nullable=False, comment="变更参数项数"
|
||||
),
|
||||
sa.Column(
|
||||
"create_time",
|
||||
sa.DateTime(),
|
||||
server_default=sa.text("CURRENT_TIMESTAMP"),
|
||||
nullable=False,
|
||||
comment="创建时间",
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["operator_id"],
|
||||
["users.id"],
|
||||
name=op.f("fk_param_change_batches_operator_id"),
|
||||
ondelete="SET NULL",
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_param_change_batches")),
|
||||
sa.UniqueConstraint("version_no", name=op.f("uk_param_change_batches_version_no")),
|
||||
comment="参数变更批次表",
|
||||
mysql_charset="utf8mb4",
|
||||
mysql_collate="utf8mb4_general_ci",
|
||||
mysql_engine="InnoDB",
|
||||
)
|
||||
op.create_table(
|
||||
"param_values",
|
||||
sa.Column(
|
||||
"id", mysql.BIGINT(unsigned=True), autoincrement=True, nullable=False, comment="主键ID"
|
||||
),
|
||||
sa.Column(
|
||||
"param_id",
|
||||
mysql.BIGINT(unsigned=True),
|
||||
nullable=False,
|
||||
comment="参数定义ID(param_definitions.id)",
|
||||
),
|
||||
sa.Column(
|
||||
"dimension_value",
|
||||
sa.String(length=32),
|
||||
server_default=sa.text("''"),
|
||||
nullable=False,
|
||||
comment="维度取值:NONE维度为空串;产品类别/岗位编码为具体值",
|
||||
),
|
||||
sa.Column(
|
||||
"effective_date", sa.Date(), nullable=False, comment="生效日期(按业务日期时点化取值)"
|
||||
),
|
||||
sa.Column(
|
||||
"value_text",
|
||||
sa.String(length=64),
|
||||
nullable=False,
|
||||
comment="参数值(Fraction 可解析字符串/枚举码/开关)",
|
||||
),
|
||||
sa.Column(
|
||||
"old_value_text", sa.String(length=64), nullable=True, comment="变更前值(留痕)"
|
||||
),
|
||||
sa.Column(
|
||||
"batch_id",
|
||||
mysql.BIGINT(unsigned=True),
|
||||
nullable=False,
|
||||
comment="变更批次ID(param_change_batches.id)",
|
||||
),
|
||||
sa.Column(
|
||||
"create_time",
|
||||
sa.DateTime(),
|
||||
server_default=sa.text("CURRENT_TIMESTAMP"),
|
||||
nullable=False,
|
||||
comment="创建时间",
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["batch_id"],
|
||||
["param_change_batches.id"],
|
||||
name=op.f("fk_param_values_batch_id"),
|
||||
ondelete="RESTRICT",
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["param_id"],
|
||||
["param_definitions.id"],
|
||||
name=op.f("fk_param_values_param_id"),
|
||||
ondelete="RESTRICT",
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_param_values")),
|
||||
comment="参数版本条目表(append-only,按生效日期时点化取值)",
|
||||
mysql_charset="utf8mb4",
|
||||
mysql_collate="utf8mb4_general_ci",
|
||||
mysql_engine="InnoDB",
|
||||
)
|
||||
op.create_index("idx_param_values_batch_id", "param_values", ["batch_id"], unique=False)
|
||||
op.create_index(
|
||||
"idx_param_values_effective_date", "param_values", ["effective_date"], unique=False
|
||||
)
|
||||
op.create_index(
|
||||
"idx_param_values_param_id_dimension_value_effective_date",
|
||||
"param_values",
|
||||
["param_id", "dimension_value", "effective_date"],
|
||||
unique=False,
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
# ---- 种子数据(生产与开发同源;口径依据 2026-10-12 业务裁决对照表)----
|
||||
# 显式指定 id:四张表均为本迁移新建、应用时必为空表,id 稳定可控;
|
||||
# param_values 按 param_id 引用定义,无法依赖自增(bulk_insert 取不回自增值)。
|
||||
op.bulk_insert(
|
||||
sa.table(
|
||||
"business_roles",
|
||||
sa.column("id", sa.BigInteger),
|
||||
sa.column("role_code", sa.String),
|
||||
sa.column("role_name", sa.String),
|
||||
sa.column("calc_template", sa.String),
|
||||
sa.column("description", sa.String),
|
||||
sa.column("sort_order", sa.Integer),
|
||||
sa.column("is_builtin", sa.Integer),
|
||||
),
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"role_code": "salesperson",
|
||||
"role_name": "营销员",
|
||||
"calc_template": "TPL_SALESPERSON_DECAY",
|
||||
"description": "业务员个人户:回款天数线性递减(10‰ − 天数×4/360‰,361 天起固定 4‰)",
|
||||
"sort_order": 1,
|
||||
"is_builtin": 1,
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"role_code": "sales_manager",
|
||||
"role_name": "营销经理",
|
||||
"calc_template": "TPL_MANAGER_SHARE",
|
||||
"description": "经理绩效:∑本团队业务员绩效×12.5% + ∑全公司业务员绩效×5%",
|
||||
"sort_order": 2,
|
||||
"is_builtin": 1,
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"role_code": "info_officer",
|
||||
"role_name": "信息员",
|
||||
"calc_template": "TPL_INFO_SALES_FIXED",
|
||||
"description": "信息员绩效:本人销售额×1‰",
|
||||
"sort_order": 3,
|
||||
"is_builtin": 1,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
op.bulk_insert(
|
||||
sa.table(
|
||||
"param_change_batches",
|
||||
sa.column("id", sa.BigInteger),
|
||||
sa.column("version_no", sa.String),
|
||||
sa.column("effective_date", sa.Date),
|
||||
sa.column("change_type", sa.Integer),
|
||||
sa.column("remark", sa.String),
|
||||
sa.column("operator_name", sa.String),
|
||||
sa.column("item_count", sa.Integer),
|
||||
),
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"version_no": "P20260101-00",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"change_type": 1,
|
||||
"remark": "初始版本(系统初始化种子,口径依据 2026-10-12 业务裁决)",
|
||||
"operator_name": "system",
|
||||
"item_count": 19,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
op.bulk_insert(
|
||||
sa.table(
|
||||
"param_definitions",
|
||||
sa.column("id", sa.BigInteger),
|
||||
sa.column("param_code", sa.String),
|
||||
sa.column("param_name", sa.String),
|
||||
sa.column("param_group", sa.String),
|
||||
sa.column("value_type", sa.String),
|
||||
sa.column("unit", sa.String),
|
||||
sa.column("dimension_type", sa.String),
|
||||
sa.column("options_text", sa.String),
|
||||
sa.column("default_value", sa.String),
|
||||
sa.column("value_min", sa.String),
|
||||
sa.column("value_max", sa.String),
|
||||
sa.column("description", sa.String),
|
||||
sa.column("sort_order", sa.Integer),
|
||||
),
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"param_code": "salesperson.rate.start",
|
||||
"param_name": "业务员起始计提比例",
|
||||
"param_group": "业务员个人户",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "‰",
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": None,
|
||||
"default_value": "10",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "线性递减段起始值:比例 = 起始 − 回款天数 × 斜率(≤分界天数)",
|
||||
"sort_order": 1,
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"param_code": "salesperson.rate.slope",
|
||||
"param_name": "业务员日递减斜率",
|
||||
"param_group": "业务员个人户",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "‰/天",
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": None,
|
||||
"default_value": "4/360",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "精确分数 4/360‰/天(=1/90),禁止按 0.011111 截断存储",
|
||||
"sort_order": 2,
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"param_code": "salesperson.rate.floor",
|
||||
"param_name": "业务员计提下限",
|
||||
"param_group": "业务员个人户",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "‰",
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": None,
|
||||
"default_value": "4",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "回款天数超过分界天数后固定取此比例(≥361 天 = 4‰)",
|
||||
"sort_order": 3,
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"param_code": "salesperson.days.boundary",
|
||||
"param_name": "线性递减分界天数",
|
||||
"param_group": "业务员个人户",
|
||||
"value_type": "INT",
|
||||
"unit": "天",
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": None,
|
||||
"default_value": "360",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "≤分界天数按公式线性递减(360 天=6‰);超过则取下限",
|
||||
"sort_order": 4,
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"param_code": "manager.share.team",
|
||||
"param_name": "经理本团队分成比例",
|
||||
"param_group": "经理分成",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "%",
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": None,
|
||||
"default_value": "12.5",
|
||||
"value_min": "0",
|
||||
"value_max": "100",
|
||||
"description": "∑本人带领业务员绩效 × 此比例(限本团队)",
|
||||
"sort_order": 5,
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"param_code": "manager.share.company",
|
||||
"param_name": "经理全公司分成比例",
|
||||
"param_group": "经理分成",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "%",
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": None,
|
||||
"default_value": "5",
|
||||
"value_min": "0",
|
||||
"value_max": "100",
|
||||
"description": "∑全部业务员绩效 × 此比例(全公司)",
|
||||
"sort_order": 6,
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"param_code": "enterprise.rate",
|
||||
"param_name": "企业户计提比例",
|
||||
"param_group": "企业户",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "‰",
|
||||
"dimension_type": "PRODUCT_CATEGORY",
|
||||
"options_text": None,
|
||||
"default_value": "3",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "所有企业户适用;2026-08-13 起由 2‰ 提高至 3‰",
|
||||
"sort_order": 7,
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"param_code": "info.rate",
|
||||
"param_name": "信息员计提比例",
|
||||
"param_group": "信息员",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "‰",
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": None,
|
||||
"default_value": "1",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "信息员绩效 = 本人销售额 × 此比例",
|
||||
"sort_order": 8,
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"param_code": "prepay.rate",
|
||||
"param_name": "预付款计提比例",
|
||||
"param_group": "支付环节",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "‰",
|
||||
"dimension_type": "NONE",
|
||||
"options_text": None,
|
||||
"default_value": "10",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "预付款统一按此比例计提",
|
||||
"sort_order": 9,
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"param_code": "barter.discount",
|
||||
"param_name": "以物抵顶折算比例",
|
||||
"param_group": "支付环节",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "%",
|
||||
"dimension_type": "NONE",
|
||||
"options_text": None,
|
||||
"default_value": "80",
|
||||
"value_min": "0",
|
||||
"value_max": "100",
|
||||
"description": "以物抵顶回款绩效按应发绩效的此比例折算",
|
||||
"sort_order": 10,
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"param_code": "payment.start.ratio",
|
||||
"param_name": "支付起付比例",
|
||||
"param_group": "支付环节",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "%",
|
||||
"dimension_type": "NONE",
|
||||
"options_text": None,
|
||||
"default_value": "60",
|
||||
"value_min": "0",
|
||||
"value_max": "100",
|
||||
"description": "单项业务回款额达销售额(不含运费)此比例后起付;达标前累计",
|
||||
"sort_order": 11,
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"param_code": "payment.weight.mode",
|
||||
"param_name": "支付权重应用方式",
|
||||
"param_group": "支付环节",
|
||||
"value_type": "ENUM",
|
||||
"unit": None,
|
||||
"dimension_type": "NONE",
|
||||
"options_text": "FULL|BALANCE",
|
||||
"default_value": "FULL",
|
||||
"value_min": None,
|
||||
"value_max": None,
|
||||
"description": "FULL=按 R×R 乘当月全额应发绩效;BALANCE=乘余额(语义待 M3 前确认)",
|
||||
"sort_order": 12,
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"param_code": "product.threshold",
|
||||
"param_name": "折算毛利润额阈值",
|
||||
"param_group": "产品阈值",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "%",
|
||||
"dimension_type": "PRODUCT_CATEGORY",
|
||||
"options_text": None,
|
||||
"default_value": "30",
|
||||
"value_min": "0",
|
||||
"value_max": "100",
|
||||
"description": "折算毛利润额 = 销售额 ×(毛利润率 − 阈值);市政水利 30%、轨交 20%",
|
||||
"sort_order": 13,
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"param_code": "salary.basic.mode",
|
||||
"param_name": "月工资基本工资口径",
|
||||
"param_group": "月工资口径",
|
||||
"value_type": "ENUM",
|
||||
"unit": None,
|
||||
"dimension_type": "BUSINESS_ROLE",
|
||||
"options_text": "INCLUDE|DEDUCT|EXCLUDE",
|
||||
"default_value": "INCLUDE",
|
||||
"value_min": None,
|
||||
"value_max": None,
|
||||
"description": "INCLUDE含基本工资 / DEDUCT扣除基本工资 / EXCLUDE不计",
|
||||
"sort_order": 14,
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"param_code": "probation.annual.threshold",
|
||||
"param_name": "试用期年累计结算阈值",
|
||||
"param_group": "月工资口径",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "元",
|
||||
"dimension_type": "NONE",
|
||||
"options_text": None,
|
||||
"default_value": "18000",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "试用期年累计绩效超过此值部分年底一次性结算",
|
||||
"sort_order": 15,
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"param_code": "probation.salary.basic",
|
||||
"param_name": "试用期基本工资标准",
|
||||
"param_group": "月工资口径",
|
||||
"value_type": "DECIMAL",
|
||||
"unit": "元",
|
||||
"dimension_type": "NONE",
|
||||
"options_text": None,
|
||||
"default_value": "3000",
|
||||
"value_min": "0",
|
||||
"value_max": None,
|
||||
"description": "试用期仅发基本工资、不发放绩效(归属待 M2 复核)",
|
||||
"sort_order": 16,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
op.bulk_insert(
|
||||
sa.table(
|
||||
"param_values",
|
||||
sa.column("id", sa.BigInteger),
|
||||
sa.column("param_id", sa.BigInteger),
|
||||
sa.column("dimension_value", sa.String),
|
||||
sa.column("effective_date", sa.Date),
|
||||
sa.column("value_text", sa.String),
|
||||
sa.column("batch_id", sa.BigInteger),
|
||||
),
|
||||
[
|
||||
# 业务员个人户(2026-02-17 折算公式执行日起)
|
||||
{
|
||||
"id": 1,
|
||||
"param_id": 1,
|
||||
"dimension_value": "salesperson",
|
||||
"effective_date": date(2026, 2, 17),
|
||||
"value_text": "10",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"param_id": 2,
|
||||
"dimension_value": "salesperson",
|
||||
"effective_date": date(2026, 2, 17),
|
||||
"value_text": "4/360",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"param_id": 3,
|
||||
"dimension_value": "salesperson",
|
||||
"effective_date": date(2026, 2, 17),
|
||||
"value_text": "4",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"param_id": 4,
|
||||
"dimension_value": "salesperson",
|
||||
"effective_date": date(2026, 2, 17),
|
||||
"value_text": "360",
|
||||
"batch_id": 1,
|
||||
},
|
||||
# 经理与信息员(2026-08-13 执行日起)
|
||||
{
|
||||
"id": 5,
|
||||
"param_id": 5,
|
||||
"dimension_value": "sales_manager",
|
||||
"effective_date": date(2026, 8, 13),
|
||||
"value_text": "12.5",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"param_id": 6,
|
||||
"dimension_value": "sales_manager",
|
||||
"effective_date": date(2026, 8, 13),
|
||||
"value_text": "5",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"param_id": 7,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 2, 17),
|
||||
"value_text": "2",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"param_id": 7,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 8, 13),
|
||||
"value_text": "3",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"param_id": 8,
|
||||
"dimension_value": "info_officer",
|
||||
"effective_date": date(2026, 8, 13),
|
||||
"value_text": "1",
|
||||
"batch_id": 1,
|
||||
},
|
||||
# 支付环节与通用口径(需规默认值,无历史冲突)
|
||||
{
|
||||
"id": 10,
|
||||
"param_id": 9,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "10",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"param_id": 10,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "80",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"param_id": 11,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "60",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"param_id": 12,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "FULL",
|
||||
"batch_id": 1,
|
||||
},
|
||||
# 产品阈值(按产品类别维度)
|
||||
{
|
||||
"id": 14,
|
||||
"param_id": 13,
|
||||
"dimension_value": "municipal_water",
|
||||
"effective_date": date(2026, 2, 17),
|
||||
"value_text": "30",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"param_id": 13,
|
||||
"dimension_value": "rail_transit",
|
||||
"effective_date": date(2026, 2, 17),
|
||||
"value_text": "20",
|
||||
"batch_id": 1,
|
||||
},
|
||||
# 月工资口径(按岗位维度)
|
||||
{
|
||||
"id": 16,
|
||||
"param_id": 14,
|
||||
"dimension_value": "salesperson",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "INCLUDE",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"param_id": 14,
|
||||
"dimension_value": "sales_manager",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "DEDUCT",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"param_id": 15,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "18000",
|
||||
"batch_id": 1,
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"param_id": 16,
|
||||
"dimension_value": "",
|
||||
"effective_date": date(2026, 1, 1),
|
||||
"value_text": "3000",
|
||||
"batch_id": 1,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""回滚迁移。
|
||||
|
||||
**注意(autogenerate 不会替你处理)**:生成的 `op.drop_index` 与
|
||||
`op.drop_table` 顺序需人工检查 —— 若某索引是外键的唯一支撑索引,
|
||||
单独 drop_index 会报 MySQL 1553(needed in a foreign key constraint)。
|
||||
**整表回滚应只保留 `op.drop_table`**,DROP TABLE 会连带删除索引与外键。
|
||||
"""
|
||||
# 整表回滚只保留 drop_table —— DROP TABLE 会连带删除索引与外键。
|
||||
# 原 autogenerate 输出的逐个 drop_index 会失败:组合索引最左列 param_id 与
|
||||
# idx_param_values_batch_id 分别是两个外键的唯一支撑索引(MySQL errno 1553)。
|
||||
# 删除顺序:先删引用方 param_values,再删被引用方。
|
||||
op.drop_table("param_values")
|
||||
op.drop_table("param_change_batches")
|
||||
op.drop_table("param_definitions")
|
||||
op.drop_table("business_roles")
|
||||
@ -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",
|
||||
|
||||
46
backend/app/models/business_role.py
Normal file
46
backend/app/models/business_role.py
Normal file
@ -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自定义",
|
||||
)
|
||||
159
backend/app/models/param.py
Normal file
159
backend/app/models/param.py
Normal file
@ -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="创建时间"
|
||||
)
|
||||
@ -19,6 +19,10 @@ EXPECTED_TABLES = {
|
||||
"role_permissions",
|
||||
"login_logs",
|
||||
"operation_logs",
|
||||
"business_roles",
|
||||
"param_definitions",
|
||||
"param_change_batches",
|
||||
"param_values",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -16,6 +16,10 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- 删除顺序遵循外键依赖:先删子表
|
||||
DROP TABLE IF EXISTS `param_values`;
|
||||
DROP TABLE IF EXISTS `param_change_batches`;
|
||||
DROP TABLE IF EXISTS `param_definitions`;
|
||||
DROP TABLE IF EXISTS `business_roles`;
|
||||
DROP TABLE IF EXISTS `operation_logs`;
|
||||
DROP TABLE IF EXISTS `role_permissions`;
|
||||
DROP TABLE IF EXISTS `user_roles`;
|
||||
@ -167,6 +171,89 @@ CREATE INDEX idx_operation_logs_user_id ON operation_logs (user_id);
|
||||
|
||||
CREATE INDEX idx_operation_logs_username ON operation_logs (username);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 业务岗位角色表(V3 迁移)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE business_roles (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
role_code VARCHAR(32) NOT NULL COMMENT '岗位编码:salesperson营销员 sales_manager营销经理 info_officer信息员,创建后不可修改',
|
||||
role_name VARCHAR(64) NOT NULL COMMENT '岗位名称',
|
||||
calc_template VARCHAR(32) NOT NULL COMMENT '计提公式模板编码(以代码内模板注册表为准)',
|
||||
description VARCHAR(255) COMMENT '岗位说明',
|
||||
sort_order INTEGER NOT NULL COMMENT '显示排序' DEFAULT '0',
|
||||
status TINYINT NOT NULL COMMENT '状态:1启用 0禁用' DEFAULT '1',
|
||||
is_builtin TINYINT NOT NULL COMMENT '是否内置岗位:1内置(禁删禁停) 0自定义' DEFAULT '0',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL COMMENT '更新时间' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_business_roles PRIMARY KEY (id),
|
||||
CONSTRAINT uk_business_roles_role_code UNIQUE (role_code)
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='业务岗位角色表(与登录角色roles区分,决定计提公式与参数)' COLLATE utf8mb4_general_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 计提参数定义表(V3 迁移)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE param_definitions (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
param_code VARCHAR(64) NOT NULL COMMENT '参数编码,如 salesperson.rate.slope',
|
||||
param_name VARCHAR(64) NOT NULL COMMENT '参数名称',
|
||||
param_group VARCHAR(32) NOT NULL COMMENT '参数分组:业务员个人户/经理分成/企业户/信息员/支付环节/产品阈值/月工资口径',
|
||||
value_type VARCHAR(16) NOT NULL COMMENT '值类型:DECIMAL/INT/BOOL/ENUM/TEXT',
|
||||
unit VARCHAR(16) COMMENT '展示单位:‰/%/元/天,无单位为空',
|
||||
dimension_type VARCHAR(32) NOT NULL COMMENT '维度类型:NONE/PRODUCT_CATEGORY/BUSINESS_ROLE' DEFAULT 'NONE',
|
||||
options_text VARCHAR(255) COMMENT '枚举选项(竖线分隔),仅 ENUM 使用',
|
||||
default_value VARCHAR(64) COMMENT '系统默认值(Fraction 可解析字符串)',
|
||||
value_min VARCHAR(64) COMMENT '取值下限(含),校验用',
|
||||
value_max VARCHAR(64) COMMENT '取值上限(含),校验用',
|
||||
description VARCHAR(255) COMMENT '口径说明(配置页展示)',
|
||||
sort_order INTEGER NOT NULL COMMENT '显示排序' DEFAULT '0',
|
||||
status TINYINT NOT NULL COMMENT '状态:1启用 0停用' DEFAULT '1',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL COMMENT '更新时间' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_param_definitions PRIMARY KEY (id),
|
||||
CONSTRAINT uk_param_definitions_param_code UNIQUE (param_code)
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='计提参数定义表' COLLATE utf8mb4_general_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 参数变更批次表(V3 迁移)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE param_change_batches (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
version_no VARCHAR(32) NOT NULL COMMENT '版本号,如 P20261012-01',
|
||||
effective_date DATE NOT NULL COMMENT '生效日期(业务日期口径)',
|
||||
change_type TINYINT NOT NULL COMMENT '生效方式:1立即生效 2指定日期生效',
|
||||
remark VARCHAR(255) COMMENT '变更说明',
|
||||
operator_id BIGINT UNSIGNED COMMENT '操作人ID(账号删除后置空)',
|
||||
operator_name VARCHAR(64) NOT NULL COMMENT '操作人用户名(冗余固化)',
|
||||
item_count INTEGER NOT NULL COMMENT '变更参数项数' DEFAULT '0',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_param_change_batches PRIMARY KEY (id),
|
||||
CONSTRAINT fk_param_change_batches_operator_id FOREIGN KEY(operator_id) REFERENCES users (id) ON DELETE SET NULL,
|
||||
CONSTRAINT uk_param_change_batches_version_no UNIQUE (version_no)
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='参数变更批次表' COLLATE utf8mb4_general_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 参数版本条目表(V3 迁移,append-only)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE param_values (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
param_id BIGINT UNSIGNED NOT NULL COMMENT '参数定义ID(param_definitions.id)',
|
||||
dimension_value VARCHAR(32) NOT NULL COMMENT '维度取值:NONE维度为空串;产品类别/岗位编码为具体值' DEFAULT '',
|
||||
effective_date DATE NOT NULL COMMENT '生效日期(按业务日期时点化取值)',
|
||||
value_text VARCHAR(64) NOT NULL COMMENT '参数值(Fraction 可解析字符串/枚举码/开关)',
|
||||
old_value_text VARCHAR(64) COMMENT '变更前值(留痕)',
|
||||
batch_id BIGINT UNSIGNED NOT NULL COMMENT '变更批次ID(param_change_batches.id)',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_param_values PRIMARY KEY (id),
|
||||
CONSTRAINT fk_param_values_batch_id FOREIGN KEY(batch_id) REFERENCES param_change_batches (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT fk_param_values_param_id FOREIGN KEY(param_id) REFERENCES param_definitions (id) ON DELETE RESTRICT
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='参数版本条目表(append-only,按生效日期时点化取值)' COLLATE utf8mb4_general_ci;
|
||||
|
||||
CREATE INDEX idx_param_values_batch_id ON param_values (batch_id);
|
||||
|
||||
CREATE INDEX idx_param_values_effective_date ON param_values (effective_date);
|
||||
|
||||
CREATE INDEX idx_param_values_param_id_dimension_value_effective_date ON param_values (param_id, dimension_value, effective_date);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 字典数据:角色(与 V1 迁移中的初始化数据一致)
|
||||
-- ---------------------------------------------------------------------------
|
||||
@ -174,6 +261,57 @@ INSERT INTO roles (role_code, role_name, description, sort_order) VALUES ('admin
|
||||
|
||||
INSERT INTO roles (role_code, role_name, description, sort_order) VALUES ('user', '普通用户', '业务操作', 2);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 字典数据:业务岗位与计提参数(与 V3 迁移种子一致;口径依据 2026-10-12 业务裁决)
|
||||
-- 显式指定 id:param_values 按 param_id 引用定义,与迁移种子保持同源一致
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO business_roles (id, role_code, role_name, calc_template, description, sort_order, is_builtin) VALUES
|
||||
(1, 'salesperson', '营销员', 'TPL_SALESPERSON_DECAY', '业务员个人户:回款天数线性递减(10‰ − 天数×4/360‰,361 天起固定 4‰)', 1, 1),
|
||||
(2, 'sales_manager', '营销经理', 'TPL_MANAGER_SHARE', '经理绩效:∑本团队业务员绩效×12.5% + ∑全公司业务员绩效×5%', 2, 1),
|
||||
(3, 'info_officer', '信息员', 'TPL_INFO_SALES_FIXED', '信息员绩效:本人销售额×1‰', 3, 1);
|
||||
|
||||
INSERT INTO param_change_batches (id, version_no, effective_date, change_type, remark, operator_name, item_count) VALUES
|
||||
(1, 'P20260101-00', '2026-01-01', 1, '初始版本(系统初始化种子,口径依据 2026-10-12 业务裁决)', 'system', 19);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES
|
||||
(1, 'salesperson.rate.start', '业务员起始计提比例', '业务员个人户', 'DECIMAL', '‰', 'BUSINESS_ROLE', NULL, '10', '0', NULL, '线性递减段起始值:比例 = 起始 − 回款天数 × 斜率(≤分界天数)', 1),
|
||||
(2, 'salesperson.rate.slope', '业务员日递减斜率', '业务员个人户', 'DECIMAL', '‰/天', 'BUSINESS_ROLE', NULL, '4/360', '0', NULL, '精确分数 4/360‰/天(=1/90),禁止按 0.011111 截断存储', 2),
|
||||
(3, 'salesperson.rate.floor', '业务员计提下限', '业务员个人户', 'DECIMAL', '‰', 'BUSINESS_ROLE', NULL, '4', '0', NULL, '回款天数超过分界天数后固定取此比例(≥361 天 = 4‰)', 3),
|
||||
(4, 'salesperson.days.boundary', '线性递减分界天数', '业务员个人户', 'INT', '天', 'BUSINESS_ROLE', NULL, '360', '0', NULL, '≤分界天数按公式线性递减(360 天=6‰);超过则取下限', 4),
|
||||
(5, 'manager.share.team', '经理本团队分成比例', '经理分成', 'DECIMAL', '%', 'BUSINESS_ROLE', NULL, '12.5', '0', '100', '∑本人带领业务员绩效 × 此比例(限本团队)', 5),
|
||||
(6, 'manager.share.company', '经理全公司分成比例', '经理分成', 'DECIMAL', '%', 'BUSINESS_ROLE', NULL, '5', '0', '100', '∑全部业务员绩效 × 此比例(全公司)', 6),
|
||||
(7, 'enterprise.rate', '企业户计提比例', '企业户', 'DECIMAL', '‰', 'PRODUCT_CATEGORY', NULL, '3', '0', NULL, '所有企业户适用;2026-08-13 起由 2‰ 提高至 3‰', 7),
|
||||
(8, 'info.rate', '信息员计提比例', '信息员', 'DECIMAL', '‰', 'BUSINESS_ROLE', NULL, '1', '0', NULL, '信息员绩效 = 本人销售额 × 此比例', 8),
|
||||
(9, 'prepay.rate', '预付款计提比例', '支付环节', 'DECIMAL', '‰', 'NONE', NULL, '10', '0', NULL, '预付款统一按此比例计提', 9),
|
||||
(10, 'barter.discount', '以物抵顶折算比例', '支付环节', 'DECIMAL', '%', 'NONE', NULL, '80', '0', '100', '以物抵顶回款绩效按应发绩效的此比例折算', 10),
|
||||
(11, 'payment.start.ratio', '支付起付比例', '支付环节', 'DECIMAL', '%', 'NONE', NULL, '60', '0', '100', '单项业务回款额达销售额(不含运费)此比例后起付;达标前累计', 11),
|
||||
(12, 'payment.weight.mode', '支付权重应用方式', '支付环节', 'ENUM', NULL, 'NONE', 'FULL|BALANCE', 'FULL', NULL, NULL, 'FULL=按 R×R 乘当月全额应发绩效;BALANCE=乘余额(语义待 M3 前确认)', 12),
|
||||
(13, 'product.threshold', '折算毛利润额阈值', '产品阈值', 'DECIMAL', '%', 'PRODUCT_CATEGORY', NULL, '30', '0', '100', '折算毛利润额 = 销售额 ×(毛利润率 − 阈值);市政水利 30%、轨交 20%', 13),
|
||||
(14, 'salary.basic.mode', '月工资基本工资口径', '月工资口径', 'ENUM', NULL, 'BUSINESS_ROLE', 'INCLUDE|DEDUCT|EXCLUDE', 'INCLUDE', NULL, NULL, 'INCLUDE含基本工资 / DEDUCT扣除基本工资 / EXCLUDE不计', 14),
|
||||
(15, 'probation.annual.threshold', '试用期年累计结算阈值', '月工资口径', 'DECIMAL', '元', 'NONE', NULL, '18000', '0', NULL, '试用期年累计绩效超过此值部分年底一次性结算', 15),
|
||||
(16, 'probation.salary.basic', '试用期基本工资标准', '月工资口径', 'DECIMAL', '元', 'NONE', NULL, '3000', '0', NULL, '试用期仅发基本工资、不发放绩效(归属待 M2 复核)', 16);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES
|
||||
(1, 1, 'salesperson', '2026-02-17', '10', 1),
|
||||
(2, 2, 'salesperson', '2026-02-17', '4/360', 1),
|
||||
(3, 3, 'salesperson', '2026-02-17', '4', 1),
|
||||
(4, 4, 'salesperson', '2026-02-17', '360', 1),
|
||||
(5, 5, 'sales_manager', '2026-08-13', '12.5', 1),
|
||||
(6, 6, 'sales_manager', '2026-08-13', '5', 1),
|
||||
(7, 7, '', '2026-02-17', '2', 1),
|
||||
(8, 7, '', '2026-08-13', '3', 1),
|
||||
(9, 8, 'info_officer', '2026-08-13', '1', 1),
|
||||
(10, 9, '', '2026-01-01', '10', 1),
|
||||
(11, 10, '', '2026-01-01', '80', 1),
|
||||
(12, 11, '', '2026-01-01', '60', 1),
|
||||
(13, 12, '', '2026-01-01', 'FULL', 1),
|
||||
(14, 13, 'municipal_water', '2026-02-17', '30', 1),
|
||||
(15, 13, 'rail_transit', '2026-02-17', '20', 1),
|
||||
(16, 14, 'salesperson', '2026-01-01', 'INCLUDE', 1),
|
||||
(17, 14, 'sales_manager', '2026-01-01', 'DEDUCT', 1),
|
||||
(18, 15, '', '2026-01-01', '18000', 1),
|
||||
(19, 16, '', '2026-01-01', '3000', 1);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 迁移版本记录:须等于当前 head,使 alembic upgrade head 成为空操作
|
||||
-- ---------------------------------------------------------------------------
|
||||
@ -182,4 +320,4 @@ CREATE TABLE alembic_version (
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COLLATE utf8mb4_general_ci;
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('a45a8087831b');
|
||||
INSERT INTO alembic_version (version_num) VALUES ('bfbda9c3191d');
|
||||
|
||||
153
db/migration/V3__add_business_roles_and_params.sql
Normal file
153
db/migration/V3__add_business_roles_and_params.sql
Normal file
@ -0,0 +1,153 @@
|
||||
-- Running upgrade a45a8087831b -> bfbda9c3191d
|
||||
|
||||
CREATE TABLE business_roles (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
role_code VARCHAR(32) NOT NULL COMMENT '岗位编码:salesperson营销员 sales_manager营销经理 info_officer信息员,创建后不可修改',
|
||||
role_name VARCHAR(64) NOT NULL COMMENT '岗位名称',
|
||||
calc_template VARCHAR(32) NOT NULL COMMENT '计提公式模板编码(以代码内模板注册表为准)',
|
||||
description VARCHAR(255) COMMENT '岗位说明',
|
||||
sort_order INTEGER NOT NULL COMMENT '显示排序' DEFAULT '0',
|
||||
status TINYINT NOT NULL COMMENT '状态:1启用 0禁用' DEFAULT '1',
|
||||
is_builtin TINYINT NOT NULL COMMENT '是否内置岗位:1内置(禁删禁停) 0自定义' DEFAULT '0',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL COMMENT '更新时间' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_business_roles PRIMARY KEY (id),
|
||||
CONSTRAINT uk_business_roles_role_code UNIQUE (role_code)
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='业务岗位角色表(与登录角色roles区分,决定计提公式与参数)' COLLATE utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE param_definitions (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
param_code VARCHAR(64) NOT NULL COMMENT '参数编码,如 salesperson.rate.slope',
|
||||
param_name VARCHAR(64) NOT NULL COMMENT '参数名称',
|
||||
param_group VARCHAR(32) NOT NULL COMMENT '参数分组:业务员个人户/经理分成/企业户/信息员/支付环节/产品阈值/月工资口径',
|
||||
value_type VARCHAR(16) NOT NULL COMMENT '值类型:DECIMAL/INT/BOOL/ENUM/TEXT',
|
||||
unit VARCHAR(16) COMMENT '展示单位:‰/%/元/天,无单位为空',
|
||||
dimension_type VARCHAR(32) NOT NULL COMMENT '维度类型:NONE/PRODUCT_CATEGORY/BUSINESS_ROLE' DEFAULT 'NONE',
|
||||
options_text VARCHAR(255) COMMENT '枚举选项(竖线分隔),仅 ENUM 使用',
|
||||
default_value VARCHAR(64) COMMENT '系统默认值(Fraction 可解析字符串)',
|
||||
value_min VARCHAR(64) COMMENT '取值下限(含),校验用',
|
||||
value_max VARCHAR(64) COMMENT '取值上限(含),校验用',
|
||||
description VARCHAR(255) COMMENT '口径说明(配置页展示)',
|
||||
sort_order INTEGER NOT NULL COMMENT '显示排序' DEFAULT '0',
|
||||
status TINYINT NOT NULL COMMENT '状态:1启用 0停用' DEFAULT '1',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL COMMENT '更新时间' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_param_definitions PRIMARY KEY (id),
|
||||
CONSTRAINT uk_param_definitions_param_code UNIQUE (param_code)
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='计提参数定义表' COLLATE utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE param_change_batches (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
version_no VARCHAR(32) NOT NULL COMMENT '版本号,如 P20261012-01',
|
||||
effective_date DATE NOT NULL COMMENT '生效日期(业务日期口径)',
|
||||
change_type TINYINT NOT NULL COMMENT '生效方式:1立即生效 2指定日期生效',
|
||||
remark VARCHAR(255) COMMENT '变更说明',
|
||||
operator_id BIGINT UNSIGNED COMMENT '操作人ID(账号删除后置空)',
|
||||
operator_name VARCHAR(64) NOT NULL COMMENT '操作人用户名(冗余固化)',
|
||||
item_count INTEGER NOT NULL COMMENT '变更参数项数' DEFAULT '0',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_param_change_batches PRIMARY KEY (id),
|
||||
CONSTRAINT fk_param_change_batches_operator_id FOREIGN KEY(operator_id) REFERENCES users (id) ON DELETE SET NULL,
|
||||
CONSTRAINT uk_param_change_batches_version_no UNIQUE (version_no)
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='参数变更批次表' COLLATE utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE param_values (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
|
||||
param_id BIGINT UNSIGNED NOT NULL COMMENT '参数定义ID(param_definitions.id)',
|
||||
dimension_value VARCHAR(32) NOT NULL COMMENT '维度取值:NONE维度为空串;产品类别/岗位编码为具体值' DEFAULT '',
|
||||
effective_date DATE NOT NULL COMMENT '生效日期(按业务日期时点化取值)',
|
||||
value_text VARCHAR(64) NOT NULL COMMENT '参数值(Fraction 可解析字符串/枚举码/开关)',
|
||||
old_value_text VARCHAR(64) COMMENT '变更前值(留痕)',
|
||||
batch_id BIGINT UNSIGNED NOT NULL COMMENT '变更批次ID(param_change_batches.id)',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_param_values PRIMARY KEY (id),
|
||||
CONSTRAINT fk_param_values_batch_id FOREIGN KEY(batch_id) REFERENCES param_change_batches (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT fk_param_values_param_id FOREIGN KEY(param_id) REFERENCES param_definitions (id) ON DELETE RESTRICT
|
||||
)CHARSET=utf8mb4 ENGINE=InnoDB COMMENT='参数版本条目表(append-only,按生效日期时点化取值)' COLLATE utf8mb4_general_ci;
|
||||
|
||||
CREATE INDEX idx_param_values_batch_id ON param_values (batch_id);
|
||||
|
||||
CREATE INDEX idx_param_values_effective_date ON param_values (effective_date);
|
||||
|
||||
CREATE INDEX idx_param_values_param_id_dimension_value_effective_date ON param_values (param_id, dimension_value, effective_date);
|
||||
|
||||
INSERT INTO business_roles (id, role_code, role_name, calc_template, description, sort_order, is_builtin) VALUES (1, 'salesperson', '营销员', 'TPL_SALESPERSON_DECAY', '业务员个人户:回款天数线性递减(10‰ − 天数×4/360‰,361 天起固定 4‰)', 1, 1);
|
||||
|
||||
INSERT INTO business_roles (id, role_code, role_name, calc_template, description, sort_order, is_builtin) VALUES (2, 'sales_manager', '营销经理', 'TPL_MANAGER_SHARE', '经理绩效:∑本团队业务员绩效×12.5% + ∑全公司业务员绩效×5%', 2, 1);
|
||||
|
||||
INSERT INTO business_roles (id, role_code, role_name, calc_template, description, sort_order, is_builtin) VALUES (3, 'info_officer', '信息员', 'TPL_INFO_SALES_FIXED', '信息员绩效:本人销售额×1‰', 3, 1);
|
||||
|
||||
INSERT INTO param_change_batches (id, version_no, effective_date, change_type, remark, operator_name, item_count) VALUES (1, 'P20260101-00', '2026-01-01', 1, '初始版本(系统初始化种子,口径依据 2026-10-12 业务裁决)', 'system', 19);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (1, 'salesperson.rate.start', '业务员起始计提比例', '业务员个人户', 'DECIMAL', '‰', 'BUSINESS_ROLE', NULL, '10', '0', NULL, '线性递减段起始值:比例 = 起始 − 回款天数 × 斜率(≤分界天数)', 1);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (2, 'salesperson.rate.slope', '业务员日递减斜率', '业务员个人户', 'DECIMAL', '‰/天', 'BUSINESS_ROLE', NULL, '4/360', '0', NULL, '精确分数 4/360‰/天(=1/90),禁止按 0.011111 截断存储', 2);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (3, 'salesperson.rate.floor', '业务员计提下限', '业务员个人户', 'DECIMAL', '‰', 'BUSINESS_ROLE', NULL, '4', '0', NULL, '回款天数超过分界天数后固定取此比例(≥361 天 = 4‰)', 3);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (4, 'salesperson.days.boundary', '线性递减分界天数', '业务员个人户', 'INT', '天', 'BUSINESS_ROLE', NULL, '360', '0', NULL, '≤分界天数按公式线性递减(360 天=6‰);超过则取下限', 4);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (5, 'manager.share.team', '经理本团队分成比例', '经理分成', 'DECIMAL', '%', 'BUSINESS_ROLE', NULL, '12.5', '0', '100', '∑本人带领业务员绩效 × 此比例(限本团队)', 5);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (6, 'manager.share.company', '经理全公司分成比例', '经理分成', 'DECIMAL', '%', 'BUSINESS_ROLE', NULL, '5', '0', '100', '∑全部业务员绩效 × 此比例(全公司)', 6);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (7, 'enterprise.rate', '企业户计提比例', '企业户', 'DECIMAL', '‰', 'PRODUCT_CATEGORY', NULL, '3', '0', NULL, '所有企业户适用;2026-08-13 起由 2‰ 提高至 3‰', 7);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (8, 'info.rate', '信息员计提比例', '信息员', 'DECIMAL', '‰', 'BUSINESS_ROLE', NULL, '1', '0', NULL, '信息员绩效 = 本人销售额 × 此比例', 8);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (9, 'prepay.rate', '预付款计提比例', '支付环节', 'DECIMAL', '‰', 'NONE', NULL, '10', '0', NULL, '预付款统一按此比例计提', 9);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (10, 'barter.discount', '以物抵顶折算比例', '支付环节', 'DECIMAL', '%', 'NONE', NULL, '80', '0', '100', '以物抵顶回款绩效按应发绩效的此比例折算', 10);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (11, 'payment.start.ratio', '支付起付比例', '支付环节', 'DECIMAL', '%', 'NONE', NULL, '60', '0', '100', '单项业务回款额达销售额(不含运费)此比例后起付;达标前累计', 11);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (12, 'payment.weight.mode', '支付权重应用方式', '支付环节', 'ENUM', NULL, 'NONE', 'FULL|BALANCE', 'FULL', NULL, NULL, 'FULL=按 R×R 乘当月全额应发绩效;BALANCE=乘余额(语义待 M3 前确认)', 12);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (13, 'product.threshold', '折算毛利润额阈值', '产品阈值', 'DECIMAL', '%', 'PRODUCT_CATEGORY', NULL, '30', '0', '100', '折算毛利润额 = 销售额 ×(毛利润率 − 阈值);市政水利 30%、轨交 20%', 13);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (14, 'salary.basic.mode', '月工资基本工资口径', '月工资口径', 'ENUM', NULL, 'BUSINESS_ROLE', 'INCLUDE|DEDUCT|EXCLUDE', 'INCLUDE', NULL, NULL, 'INCLUDE含基本工资 / DEDUCT扣除基本工资 / EXCLUDE不计', 14);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (15, 'probation.annual.threshold', '试用期年累计结算阈值', '月工资口径', 'DECIMAL', '元', 'NONE', NULL, '18000', '0', NULL, '试用期年累计绩效超过此值部分年底一次性结算', 15);
|
||||
|
||||
INSERT INTO param_definitions (id, param_code, param_name, param_group, value_type, unit, dimension_type, options_text, default_value, value_min, value_max, description, sort_order) VALUES (16, 'probation.salary.basic', '试用期基本工资标准', '月工资口径', 'DECIMAL', '元', 'NONE', NULL, '3000', '0', NULL, '试用期仅发基本工资、不发放绩效(归属待 M2 复核)', 16);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (1, 1, 'salesperson', '2026-02-17', '10', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (2, 2, 'salesperson', '2026-02-17', '4/360', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (3, 3, 'salesperson', '2026-02-17', '4', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (4, 4, 'salesperson', '2026-02-17', '360', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (5, 5, 'sales_manager', '2026-08-13', '12.5', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (6, 6, 'sales_manager', '2026-08-13', '5', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (7, 7, '', '2026-02-17', '2', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (8, 7, '', '2026-08-13', '3', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (9, 8, 'info_officer', '2026-08-13', '1', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (10, 9, '', '2026-01-01', '10', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (11, 10, '', '2026-01-01', '80', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (12, 11, '', '2026-01-01', '60', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (13, 12, '', '2026-01-01', 'FULL', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (14, 13, 'municipal_water', '2026-02-17', '30', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (15, 13, 'rail_transit', '2026-02-17', '20', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (16, 14, 'salesperson', '2026-01-01', 'INCLUDE', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (17, 14, 'sales_manager', '2026-01-01', 'DEDUCT', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (18, 15, '', '2026-01-01', '18000', 1);
|
||||
|
||||
INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (19, 16, '', '2026-01-01', '3000', 1);
|
||||
|
||||
UPDATE alembic_version SET version_num='bfbda9c3191d' WHERE alembic_version.version_num = 'a45a8087831b';
|
||||
|
||||
58
db/queries/计提参数.sql
Normal file
58
db/queries/计提参数.sql
Normal file
@ -0,0 +1,58 @@
|
||||
-- ============================================================================
|
||||
-- 计提参数查询留档(M1 参数体系)
|
||||
--
|
||||
-- 时点化取值核心规则:按 (param_id, dimension_value) 分组,取
|
||||
-- effective_date <= :biz_date 的 ORDER BY effective_date DESC, id DESC 首条
|
||||
-- (同日多次变更取最新一条,不设唯一键以保证完整留痕)。
|
||||
-- 参数总量约百行级,全量快照一次取回后在应用层按覆盖链
|
||||
-- (角色维度 > 产品类别维度 > 默认行)选择,无需在 SQL 层做维度回退。
|
||||
-- ============================================================================
|
||||
|
||||
-- 1. 全量快照:某业务日期下每个(参数, 维度值)的最新生效值
|
||||
-- 窗口函数版(MySQL 8.0+),供 param_repository.resolve_values 使用
|
||||
SELECT t.param_code, t.dimension_value, t.value_text, t.effective_date
|
||||
FROM (
|
||||
SELECT pd.param_code,
|
||||
pv.dimension_value,
|
||||
pv.value_text,
|
||||
pv.effective_date,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY pv.param_id, pv.dimension_value
|
||||
ORDER BY pv.effective_date DESC, pv.id DESC
|
||||
) AS rn
|
||||
FROM param_values pv
|
||||
JOIN param_definitions pd ON pd.id = pv.param_id
|
||||
WHERE pv.effective_date <= :biz_date
|
||||
AND pd.status = 1
|
||||
) t
|
||||
WHERE t.rn = 1;
|
||||
|
||||
-- 2. 单参数版本历史(变更留痕,供参数历史接口与导出)
|
||||
SELECT pv.effective_date,
|
||||
pv.dimension_value,
|
||||
pv.old_value_text,
|
||||
pv.value_text,
|
||||
b.version_no,
|
||||
b.operator_name,
|
||||
b.create_time
|
||||
FROM param_values pv
|
||||
JOIN param_change_batches b ON b.id = pv.batch_id
|
||||
WHERE pv.param_id = :param_id
|
||||
ORDER BY pv.effective_date DESC, pv.id DESC;
|
||||
|
||||
-- 3. 区间变更条目(对比视图辅助:应用层对两日期各执行查询 1 后逐项 diff,
|
||||
-- 本查询列出区间内实际发生过的变更,供变更记录分页与导出)
|
||||
SELECT pd.param_code,
|
||||
pd.param_name,
|
||||
pv.dimension_value,
|
||||
pv.old_value_text,
|
||||
pv.value_text,
|
||||
pv.effective_date,
|
||||
b.version_no,
|
||||
b.operator_name
|
||||
FROM param_values pv
|
||||
JOIN param_definitions pd ON pd.id = pv.param_id
|
||||
JOIN param_change_batches b ON b.id = pv.batch_id
|
||||
WHERE pv.effective_date > :from_date
|
||||
AND pv.effective_date <= :to_date
|
||||
ORDER BY pv.effective_date, pv.id;
|
||||
Loading…
Reference in New Issue
Block a user