- formula.py 八个纯函数:回款天数(首日计1)、业务员分段递减(360=6‰/361=4‰)、折算毛利润额化简式(防除零)、乘法方向绩效、以物抵顶/R×R/起付 - param_registry.py:16 项参数元数据(与迁移种子同源)+ Fraction 精确解析(4/360 禁截断)+ 类型/取值域/枚举校验 - calc_templates.py:5 个公式模板注册表(岗位绑定的受控集合) - 新增 43 项单元用例:精确分数断言(899/90000、27 天、9/25),畸形值拒绝 Co-Authored-By: Claude Code <noreply@anthropic.com>
73 lines
2.6 KiB
Python
73 lines
2.6 KiB
Python
"""计提公式模板注册表(代码内有限集合)。
|
||
|
||
一期不引入规则引擎的落地方式:公式骨架固定(本表枚举),变化的是参数值
|
||
(系统设置维护)。岗位角色(business_roles.calc_template)绑定模板编码,
|
||
新增岗位 = 选模板 + 配参数,无需改代码(需求 #28)。
|
||
新增公式形态(如未来「按产品数量计提」)需要新增模板 —— 一期接受,
|
||
岗位表单中模板为带说明的受控下拉,避免误以为可自由写公式。
|
||
"""
|
||
|
||
from dataclasses import dataclass
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class TemplateSpec:
|
||
"""公式模板元数据。"""
|
||
|
||
code: str
|
||
name: str
|
||
params: tuple[str, ...]
|
||
description: str
|
||
|
||
|
||
TEMPLATES: dict[str, TemplateSpec] = {
|
||
"TPL_SALESPERSON_DECAY": TemplateSpec(
|
||
code="TPL_SALESPERSON_DECAY",
|
||
name="业务员个人户·天数线性递减",
|
||
params=(
|
||
"salesperson.rate.start",
|
||
"salesperson.rate.slope",
|
||
"salesperson.rate.floor",
|
||
"salesperson.days.boundary",
|
||
),
|
||
description="分段:≤分界天数 = 起始 − 天数×斜率;>分界天数 = 下限",
|
||
),
|
||
"TPL_MANAGER_SHARE": TemplateSpec(
|
||
code="TPL_MANAGER_SHARE",
|
||
name="营销经理·团队与全公司分成",
|
||
params=("manager.share.team", "manager.share.company"),
|
||
description="聚合:∑本团队业务员绩效×12.5% + ∑全公司业务员绩效×5%",
|
||
),
|
||
"TPL_ENTERPRISE_FIXED": TemplateSpec(
|
||
code="TPL_ENTERPRISE_FIXED",
|
||
name="企业户·固定计提",
|
||
params=("enterprise.rate",),
|
||
description="乘法:折算毛利润额 × 计提比例",
|
||
),
|
||
"TPL_INFO_SALES_FIXED": TemplateSpec(
|
||
code="TPL_INFO_SALES_FIXED",
|
||
name="信息员·销售额固定比例",
|
||
params=("info.rate",),
|
||
description="乘法:本人销售额 × 计提比例",
|
||
),
|
||
"TPL_PREPAY_FIXED": TemplateSpec(
|
||
code="TPL_PREPAY_FIXED",
|
||
name="预付款·固定计提",
|
||
params=("prepay.rate",),
|
||
description="乘法:回款额 × 计提比例",
|
||
),
|
||
}
|
||
|
||
|
||
def get_template(code: str) -> TemplateSpec:
|
||
"""取模板元数据。未注册编码属代码缺陷(500),不是用户错误。"""
|
||
tpl = TEMPLATES.get(code)
|
||
if tpl is None:
|
||
raise ValueError(f"公式模板编码未注册:{code}")
|
||
return tpl
|
||
|
||
|
||
def required_params(code: str) -> tuple[str, ...]:
|
||
"""模板声明的参数编码列表(岗位表单展示与校验用)。"""
|
||
return get_template(code).params
|