From 0e8c5713faa6645d0219f10029e9694a64395220 Mon Sep 17 00:00:00 2001 From: liuwenxin <1009266660@qq.com> Date: Mon, 19 Oct 2026 11:09:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(migration):=20V8=20=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E7=AD=94=E5=A4=8D=E5=8F=A3=E5=BE=84=E8=90=BD=E5=AE=9E=E2=80=94?= =?UTF-8?q?=E2=80=94=E5=AE=A1=E6=89=B9=E5=BC=80=E5=85=B3=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E3=80=81=E6=92=A4=E8=AF=95=E7=94=A8=E6=9C=9F?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=8F=82=E6=95=B0=E3=80=81=E7=BB=8F=E7=90=86?= =?UTF-8?q?=E5=9F=BA=E6=95=B0=E5=BC=80=E5=85=B3=E3=80=81=E5=8F=B0=E8=B4=A6?= =?UTF-8?q?=E5=88=86=E6=91=8A=E5=94=AF=E4=B8=80=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - #5/#7 答复默认开启:两审批开关 default 翻 1,插 10-19 生效行保时点历史 - #16 答复逐人维护:撤 probation.salary.basic(无业务消费点,月结已读 personnel.salary_standard) - #12 答复参数化:新增 manager.personal.included(默认 0=不计入聚合基数) - #1 答复分配绩效铺路:台账 uk 扩为 (receipt_id, calc_version, personnel_id) 支持分摊拆行 - schema_sync 解析器过滤 ADD CONSTRAINT 误捕获 Co-Authored-By: Claude Code --- ...»�理基数开关_台账分摊唯一键.py | 193 ++++++++++++++++++ backend/app/models/performance_ledger.py | 22 +- backend/app/services/param_registry.py | 47 +++-- backend/tests/integration/conftest.py | 11 +- backend/tests/integration/test_schema_sync.py | 5 +- backend/tests/unit/test_param_registry.py | 5 +- db/init/init-dev.sql | 22 +- ...�理基数开关_台账分摊唯一键.sql | 22 ++ 8 files changed, 282 insertions(+), 45 deletions(-) create mode 100644 backend/alembic/versions/c7d2e5a81f30_v8_业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.py create mode 100644 db/migration/V8__业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.sql diff --git a/backend/alembic/versions/c7d2e5a81f30_v8_业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.py b/backend/alembic/versions/c7d2e5a81f30_v8_业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.py new file mode 100644 index 0000000..9f31b73 --- /dev/null +++ b/backend/alembic/versions/c7d2e5a81f30_v8_业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.py @@ -0,0 +1,193 @@ +"""V8:业务答复口径落实(2026-10-19 回执)。 + +四件事,全部源于《待澄清问题清单》2026-10-19 答复: + +1. 审批开关默认值翻转(#5/#7 答复「默认开启」):param_definitions 的 + default_value 更新为 '1';param_values **插入生效日 2026-10-19 的新行** + 而非改历史行——参数体系时点化(按业务日期回溯),直接改种子行会篡改 + 10-19 之前的口径历史。 +2. 撤销试用期统一工资参数(#16 答复「按人员档案逐人维护」):删除 + probation.salary.basic 的定义与版本行;月结基本工资已直接读 + personnel.salary_standard(该参数自 M3 ④ 实现起即无业务消费点)。 +3. 新增经理个人户聚合基数开关(#12 答复「作为参数配置,手动调整是否 + 纳入」):manager.personal.included,默认 0=不计入(维持暂口径)。 +4. 绩效台账唯一键加 personnel_id(二次分配分摊铺路,澄清 #1 答复 + 「分配绩效」):分摊后同一回款同版本按人各落一行(负责人余额行 + + 参与人比例行),uk(receipt_id, calc_version) 会撞;扩为三列后聚合行 + (receipt_id NULL)依旧不受 MySQL 唯一索引约束。 + +迁移 downgrade 只保留 drop_table/行级种子反向 DELETE(V6 教训:逐个 +drop_index 会撞外键支撑索引 errno 1553)。 +""" + +from datetime import date + +import sqlalchemy as sa +from alembic import op + +revision = "c7d2e5a81f30" +down_revision = "3bca400421c6" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + """种子行级变更 + 台账唯一键扩展(无表结构新增/删除)。""" + # 1. 审批开关默认值翻转(#5/#7:默认开启,业务可关闭) + op.execute( + "UPDATE param_definitions SET default_value = '1' " + "WHERE id IN (17, 18)" + ) + # 时点化生效行:插新行不改历史(10-19 前仍按 0 解析) + 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), + ), + [ + { + "id": 23, + "param_id": 17, + "dimension_value": "", + "effective_date": date(2026, 10, 19), + "value_text": "1", + "batch_id": 1, + }, + { + "id": 24, + "param_id": 18, + "dimension_value": "", + "effective_date": date(2026, 10, 19), + "value_text": "1", + "batch_id": 1, + }, + ], + ) + + # 2. 撤销试用期统一工资参数(#16:按人员档案 personnel.salary_standard 逐人维护) + op.execute("DELETE FROM param_values WHERE id = 19") + op.execute("DELETE FROM param_definitions WHERE id = 16") + + # 3. 经理个人户聚合基数开关(#12:参数化,默认不计入) + 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), + sa.column("status", sa.Integer), + ), + [ + { + "id": 20, + "param_code": "manager.personal.included", + "param_name": "经理个人户计入聚合基数", + "param_group": "经理分成", + "value_type": "BOOL", + "unit": None, + "dimension_type": "NONE", + "options_text": None, + "default_value": "0", + "value_min": None, + "value_max": None, + "description": ( + "经理 12.5%+5% 聚合时是否计入经理本人名下经理个人户业绩(澄清 #12 " + "业务答复 2026-10-19:作为参数配置、手动调整是否纳入):" + "0=不计入(默认,暂口径) 1=计入" + ), + "sort_order": 20, + "status": 1, + } + ], + ) + 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), + ), + [ + { + "id": 25, + "param_id": 20, + "dimension_value": "", + "effective_date": date(2026, 1, 1), + "value_text": "0", + "batch_id": 1, + } + ], + ) + + # 4. 台账唯一键扩为三列(分摊拆行:同回款同版本按人一行) + # 顺序要紧:旧 uk 是 fk_performance_ledgers_receipt_id 的唯一支撑索引, + # 先删会撞 errno 1553(外键无支撑索引);先建新键(receipt_id 仍居最左) + # 再做替换,两键短暂并存无冲突。 + op.create_unique_constraint( + "uk_performance_ledgers_receipt_id_calc_version_personnel", + "performance_ledgers", + ["receipt_id", "calc_version", "personnel_id"], + ) + op.drop_constraint( + "uk_performance_ledgers_receipt_id_calc_version", + "performance_ledgers", + type_="unique", + ) + + +def downgrade() -> None: + """反向:唯一键复原 + 种子行级回退(顺序与 upgrade 相反)。 + + 试用期参数(definitions 16 / values 19)的原始种子在 V3,按 V6 downgrade + 的行级反向惯例显式重插,保证可重放。 + """ + # 与 upgrade 同因的顺序:先建回旧键再删新键(旧键支撑 receipts 外键) + op.create_unique_constraint( + "uk_performance_ledgers_receipt_id_calc_version", + "performance_ledgers", + ["receipt_id", "calc_version"], + ) + op.drop_constraint( + "uk_performance_ledgers_receipt_id_calc_version_personnel", + "performance_ledgers", + type_="unique", + ) + + op.execute("DELETE FROM param_values WHERE id = 25") + op.execute("DELETE FROM param_definitions WHERE id = 20") + + op.execute( + "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, status) VALUES " + "(16, 'probation.salary.basic', '试用期基本工资标准', '月工资口径', 'DECIMAL', " + "'元', 'NONE', NULL, '3000', '0', NULL, " + "'试用期仅发基本工资、不发放绩效(归属待 M2 复核)', 16, 1)" + ) + op.execute( + "INSERT INTO param_values (id, param_id, dimension_value, effective_date, " + "value_text, batch_id) VALUES (19, 16, '', '2026-01-01', '3000', 1)" + ) + + op.execute("DELETE FROM param_values WHERE id IN (23, 24)") + op.execute( + "UPDATE param_definitions SET default_value = '0' WHERE id IN (17, 18)" + ) diff --git a/backend/app/models/performance_ledger.py b/backend/app/models/performance_ledger.py index 9015206..d080e57 100644 --- a/backend/app/models/performance_ledger.py +++ b/backend/app/models/performance_ledger.py @@ -5,15 +5,20 @@ is_active 翻 0 —— 这是全表唯一的受控 UPDATE(模型注释与 test 均已声明例外),行内容永不改写;历史版本可回溯(重算授权留痕的需求口径)。 防重三层:服务层 CAS(UPDATE ... WHERE settlement_status=0,rowcount=0 -即 400)+ FOR UPDATE 行锁 + 库级 uk(receipt_id, calc_version) 兜底。 +即 400)+ FOR UPDATE 行锁 + 库级 uk(receipt_id, calc_version, personnel_id) +兜底。uk 含 personnel_id:二次分配分摊(澄清 #1 答复 2026-10-19,分配 +绩效——按方案比例拆给参与人、余额归合同负责人)后同一回款同版本按人 +各落一行,拆分仍是「一次核算」的组成部分;聚合行 receipt_id 为 NULL, +MySQL 唯一索引对 NULL 不去重,天然不约束。 经理聚合行(calc_type=2,receipt_id 为 NULL):月度批处理时按「本团队 业务员绩效 ×12.5% + 全公司 ×5%」落一行;其唯一性由月结生成的 settlement_month 串行化 + 服务层保证(MySQL 无部分唯一索引,docstring 声明即可)。 -#12 策略点(待业务答复):经理个人户业绩暂不计入聚合基数——聚合集中 -在 settlement_service 的聚合函数,答复后只改该函数。 +#12 答复(2026-10-19):经理个人户业绩是否计入聚合基数改为参数 +``manager.personal.included``(默认 0=不计入)——消费点在 settlement_service +的聚合函数。 """ from datetime import date @@ -43,11 +48,14 @@ class PerformanceLedger(Base, TimestampMixin): __tablename__ = "performance_ledgers" __table_args__ = mysql_table_args( "绩效核算台账表(append-only 版本行;重算插新版本旧行仅翻 is_active)", - # 库级防重兜底:同一回款同版本仅一行(服务层 CAS+行锁之外的第二道 - # 闸);聚合行 receipt_id 为 NULL,MySQL 唯一索引对 NULL 不去重, - # 天然不约束聚合行 + # 库级防重兜底:同一回款同版本按人仅一行(分摊拆行后负责人+参与人 + # 各占一行;服务层 CAS+行锁之外的第二道闸)。聚合行 receipt_id 为 + # NULL,MySQL 唯一索引对 NULL 不去重,天然不约束聚合行 UniqueConstraint( - "receipt_id", "calc_version", name="uk_performance_ledgers_receipt_id_calc_version" + "receipt_id", + "calc_version", + "personnel_id", + name="uk_performance_ledgers_receipt_id_calc_version_personnel", ), Index("idx_performance_ledgers_month_active", "settlement_month", "is_active"), Index( diff --git a/backend/app/services/param_registry.py b/backend/app/services/param_registry.py index dfc0cf6..48305cc 100644 --- a/backend/app/services/param_registry.py +++ b/backend/app/services/param_registry.py @@ -242,20 +242,6 @@ PARAM_REGISTRY: dict[str, ParamSpec] = { description="试用期年累计绩效超过此值部分年底一次性结算", sort_order=15, ), - ParamSpec( - code="probation.salary.basic", - name="试用期基本工资标准", - group="月工资口径", - value_type="DECIMAL", - unit="元", - dimension_type="NONE", - options=None, - default_value="3000", - value_min="0", - value_max=None, - description="试用期仅发基本工资、不发放绩效(归属待 M2 复核)", - sort_order=16, - ), ParamSpec( code="approval.secondary_allocation.enabled", name="二次分配审批开关", @@ -264,12 +250,13 @@ PARAM_REGISTRY: dict[str, ParamSpec] = { unit=None, dimension_type="NONE", options=None, - default_value="0", + default_value="1", value_min=None, value_max=None, description=( "0=二次分配方案提交即生效(系统自动通过全节点留痕,留痕不断链);" - "1=提交后进入财务复核→领导审核审批流(2026-10-15 复核审批补充需求)" + "1=提交后进入财务复核→领导审核审批流。" + "默认开启(澄清 #5 业务答复 2026-10-19),业务可关闭" ), sort_order=17, ), @@ -281,12 +268,13 @@ PARAM_REGISTRY: dict[str, ParamSpec] = { unit=None, dimension_type="NONE", options=None, - default_value="0", + default_value="1", value_min=None, value_max=None, description=( - "预留参数:月度结算审批链开关(M3 ④ 月结子块接入时消费);" - "0=结算生成即生效,1=走财务复核→领导审核审批流" + "月度结算审批链开关(④ 月结提交时消费):" + "0=结算生成即生效,1=走财务复核→领导审核审批流。" + "默认开启(澄清 #7 业务答复 2026-10-19,月结涉及工资发放从严),业务可关闭" ), sort_order=18, ), @@ -303,10 +291,29 @@ PARAM_REGISTRY: dict[str, ParamSpec] = { value_max=None, description=( "0=调整单提交即生效(系统自动通过留痕);1=走财务复核→领导审核审批流。" - "调整单是已锁定月份补发/扣减的唯一通道" + "调整单是已锁定月份补发/扣减的唯一通道(澄清 #9:走同一审批链," + "默认值业务未明确,暂按直接生效,业务可开启)" ), sort_order=19, ), + ParamSpec( + code="manager.personal.included", + name="经理个人户计入聚合基数", + group="经理分成", + value_type="BOOL", + unit=None, + dimension_type="NONE", + options=None, + default_value="0", + value_min=None, + value_max=None, + description=( + "经理 12.5%+5% 聚合时是否计入经理本人名下经理个人户业绩(澄清 #12 " + "业务答复 2026-10-19:作为参数配置、手动调整是否纳入):" + "0=不计入(默认,暂口径) 1=计入" + ), + sort_order=20, + ), ] } diff --git a/backend/tests/integration/conftest.py b/backend/tests/integration/conftest.py index 670f445..d84f14d 100644 --- a/backend/tests/integration/conftest.py +++ b/backend/tests/integration/conftest.py @@ -190,13 +190,14 @@ def _purge_test_data() -> None: # 审批单无 t_ 前缀可用,按 AP 编号前缀全量清(steps 外键 CASCADE 随删; # ref_id 固化无外键,业务已在上一步删除,无悬挂影响) session.execute(delete(ApprovalOrder).where(ApprovalOrder.order_no.like("AP%"))) - # 开关参数恢复种子基线:测试提交的变更批次条目 id 均大于种子终值 22 - # (V3 十九条 + V6 两条 + V7 调整单开关一条),删新条目与新批次后解析 - # 回退到种子值(开关=0) - stray_values = list(session.execute(select(ParamValue).where(ParamValue.id > 22)).scalars()) + # 开关参数恢复种子基线:测试提交的变更批次条目 id 均大于种子终值 25 + # (V3 十九条 + V6 两条 + V7 调整单一条 + V8 经理基数开关一条;V8 另 + # 插入两个审批开关的 10-19 生效行 id 23/24,均属种子),删新条目与 + # 新批次后解析回退到种子值 + stray_values = list(session.execute(select(ParamValue).where(ParamValue.id > 25)).scalars()) if stray_values: stray_batches = {v.batch_id for v in stray_values} - session.execute(delete(ParamValue).where(ParamValue.id > 22)) + session.execute(delete(ParamValue).where(ParamValue.id > 25)) session.execute(delete(ParamChangeBatch).where(ParamChangeBatch.id.in_(stray_batches))) # 系统设置恢复种子单行(test_settings 会改公司名/传 logo——残留会让 # 后续 e2e 的品牌断言在污染状态下运行);uploads 下的测试 logo 一并删 diff --git a/backend/tests/integration/test_schema_sync.py b/backend/tests/integration/test_schema_sync.py index 78721f0..5ac2d72 100644 --- a/backend/tests/integration/test_schema_sync.py +++ b/backend/tests/integration/test_schema_sync.py @@ -61,7 +61,10 @@ def _migration_final_state(paths: list[Path]) -> dict[str, set[str]]: for table, columns in _parse_tables(sql).items(): merged.setdefault(table, set()).update(columns) for table, column in _ALTER_ADD.findall(sql): - merged.setdefault(table, set()).add(column) + # ADD CONSTRAINT ... UNIQUE 的「CONSTRAINT」不是列(与 _parse_tables + # 的约束关键词同一份清单过滤),V8 台账唯一键三列扩展即此形态 + if column.upper() not in _NON_COLUMN_KEYWORDS: + merged.setdefault(table, set()).add(column) for table, column in _ALTER_DROP.findall(sql): merged.setdefault(table, set()).discard(column) return merged diff --git a/backend/tests/unit/test_param_registry.py b/backend/tests/unit/test_param_registry.py index c15fc87..d389410 100644 --- a/backend/tests/unit/test_param_registry.py +++ b/backend/tests/unit/test_param_registry.py @@ -18,7 +18,8 @@ from app.services.param_registry import ( validate_and_normalize, ) -# 与 db/migration 迁移种子保持一致的 19 项编码(V3 十六项 + V6 审批开关两项 + V7 调整单开关) +# 与 db/migration 迁移种子保持一致的 19 项编码(V3 十六项 + V6 审批开关两项 +# + V7 调整单开关;V8 撤试用期统一工资参数 #16、增经理个人户基数开关 #12) EXPECTED_CODES = { "salesperson.rate.start", "salesperson.rate.slope", @@ -35,10 +36,10 @@ EXPECTED_CODES = { "product.threshold", "salary.basic.mode", "probation.annual.threshold", - "probation.salary.basic", "approval.secondary_allocation.enabled", "approval.monthly_settlement.enabled", "approval.adjustment.enabled", + "manager.personal.included", } diff --git a/db/init/init-dev.sql b/db/init/init-dev.sql index 91589b5..4074593 100644 --- a/db/init/init-dev.sql +++ b/db/init/init-dev.sql @@ -434,7 +434,7 @@ INSERT INTO business_roles (id, role_code, role_name, calc_template, description (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); +(1, 'P20260101-00', '2026-01-01', 1, '初始版本(系统初始化种子,口径依据 2026-10-12 业务裁决与 2026-10-19 澄清答复)', '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), @@ -452,10 +452,10 @@ INSERT INTO param_definitions (id, param_code, param_name, param_group, value_ty (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), -(17, 'approval.secondary_allocation.enabled', '二次分配审批开关', '审批开关', 'BOOL', NULL, 'NONE', NULL, '0', NULL, NULL, '0=二次分配方案提交即生效(系统自动通过全节点留痕,留痕不断链);1=提交后进入财务复核→领导审核审批流(2026-10-15 复核审批补充需求)', 17), -(18, 'approval.monthly_settlement.enabled', '月度结算审批开关', '审批开关', 'BOOL', NULL, 'NONE', NULL, '0', NULL, NULL, '预留参数:月度结算审批链开关(M3 ④ 月结子块接入时消费);0=结算生成即生效,1=走财务复核→领导审核审批流', 18), -(19, 'approval.adjustment.enabled', '调整单审批开关', '审批开关', 'BOOL', NULL, 'NONE', NULL, '0', NULL, NULL, '0=调整单提交即生效(系统自动通过留痕);1=走财务复核→领导审核审批流。调整单是已锁定月份补发/扣减的唯一通道', 19); +(17, 'approval.secondary_allocation.enabled', '二次分配审批开关', '审批开关', 'BOOL', NULL, 'NONE', NULL, '1', NULL, NULL, '0=二次分配方案提交即生效(系统自动通过全节点留痕,留痕不断链);1=提交后进入财务复核→领导审核审批流。默认开启(澄清 #5 业务答复 2026-10-19),业务可关闭', 17), +(18, 'approval.monthly_settlement.enabled', '月度结算审批开关', '审批开关', 'BOOL', NULL, 'NONE', NULL, '1', NULL, NULL, '月度结算审批链开关(④ 月结提交时消费):0=结算生成即生效,1=走财务复核→领导审核审批流。默认开启(澄清 #7 业务答复 2026-10-19,月结涉及工资发放从严),业务可关闭', 18), +(19, 'approval.adjustment.enabled', '调整单审批开关', '审批开关', 'BOOL', NULL, 'NONE', NULL, '0', NULL, NULL, '0=调整单提交即生效(系统自动通过留痕);1=走财务复核→领导审核审批流。调整单是已锁定月份补发/扣减的唯一通道(澄清 #9:走同一审批链,默认值业务未明确,暂按直接生效,业务可开启)', 19), +(20, 'manager.personal.included', '经理个人户计入聚合基数', '经理分成', 'BOOL', NULL, 'NONE', NULL, '0', NULL, NULL, '经理 12.5%+5% 聚合时是否计入经理本人名下经理个人户业绩(澄清 #12 业务答复 2026-10-19:作为参数配置、手动调整是否纳入):0=不计入(默认,暂口径) 1=计入', 20); INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (1, 1, 'salesperson', '2026-02-17', '10', 1), @@ -476,10 +476,12 @@ INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_t (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), -(20, 17, '', '2026-01-01', '0', 1), -(21, 18, '', '2026-01-01', '0', 1), -(22, 19, '', '2026-01-01', '0', 1); +-- 审批开关默认开启(澄清 #5/#7 答复 2026-10-19);试用期统一工资参数已撤 +-- (#16 答复:按人员档案 personnel.salary_standard 逐人维护),本脚本直达终态 +(20, 17, '', '2026-01-01', '1', 1), +(21, 18, '', '2026-01-01', '1', 1), +(22, 19, '', '2026-01-01', '0', 1), +(25, 20, '', '2026-01-01', '0', 1); -- --------------------------------------------------------------------------- -- 业务表(V5 迁移;业务编号自动生成,五项汇总冗余列由服务层事务内维护) @@ -845,7 +847,7 @@ CREATE TABLE performance_ledgers ( create_time DATETIME NOT NULL COMMENT '创建时间' DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL COMMENT '更新时间' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT pk_performance_ledgers PRIMARY KEY (id), - CONSTRAINT uk_performance_ledgers_receipt_id_calc_version UNIQUE (receipt_id, calc_version), + CONSTRAINT uk_performance_ledgers_receipt_id_calc_version_personnel UNIQUE (receipt_id, calc_version, personnel_id), CONSTRAINT fk_performance_ledgers_settlement_id FOREIGN KEY(settlement_id) REFERENCES monthly_settlements (id) ON DELETE RESTRICT, CONSTRAINT fk_performance_ledgers_personnel_id FOREIGN KEY(personnel_id) REFERENCES personnel (id) ON DELETE RESTRICT, CONSTRAINT fk_performance_ledgers_receipt_id FOREIGN KEY(receipt_id) REFERENCES receipts (id) ON DELETE RESTRICT diff --git a/db/migration/V8__业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.sql b/db/migration/V8__业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.sql new file mode 100644 index 0000000..9c3a73d --- /dev/null +++ b/db/migration/V8__业务答复口径落实_审批开关默认_试用期参数_经理基数开关_台账分摊唯一键.sql @@ -0,0 +1,22 @@ +-- Running upgrade 3bca400421c6 -> c7d2e5a81f30 + +UPDATE param_definitions SET default_value = '1' WHERE id IN (17, 18); + +INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (23, 17, '', '2026-10-19', '1', 1); + +INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (24, 18, '', '2026-10-19', '1', 1); + +DELETE FROM param_values WHERE id = 19; + +DELETE FROM param_definitions WHERE id = 16; + +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, status) VALUES (20, 'manager.personal.included', '经理个人户计入聚合基数', '经理分成', 'BOOL', NULL, 'NONE', NULL, '0', NULL, NULL, '经理 12.5%+5% 聚合时是否计入经理本人名下经理个人户业绩(澄清 #12 业务答复 2026-10-19:作为参数配置、手动调整是否纳入):0=不计入(默认,暂口径) 1=计入', 20, 1); + +INSERT INTO param_values (id, param_id, dimension_value, effective_date, value_text, batch_id) VALUES (25, 20, '', '2026-01-01', '0', 1); + +ALTER TABLE performance_ledgers ADD CONSTRAINT uk_performance_ledgers_receipt_id_calc_version_personnel UNIQUE (receipt_id, calc_version, personnel_id); + +ALTER TABLE performance_ledgers DROP INDEX uk_performance_ledgers_receipt_id_calc_version; + +UPDATE alembic_version SET version_num='c7d2e5a81f30' WHERE alembic_version.version_num = '3bca400421c6'; +