feat(ui): 面向客户的文案中文化
系统由财务与营销人员日常使用,不是给开发者看的。本批把会渲染到页面上的 文本统一改成业务语言: - param_registry 的 22 条参数说明重写为「管什么、钱怎么变、何时该调它」, 去掉英文枚举名、需求编号、内部阶段号与精度约束 - 前端补 formatByCode:变更记录、版本历史、快照对比只给裸 value_text, 需回目录按编码补 value_type 与 unit 才能翻译枚举,否则这些位置仍显示 INCLUDE/FULL/1;编辑弹窗 BOOL 改为开启/关闭下拉 - 后端错误文案:模板报错用中文模板名并给出下一步,产品类别不再甩 municipal_water / rail_transit - 台账与预览落库的计提说明口语化(rate_note / strategy_note / 聚合行 note), 去掉「基数开关=1」「#12 参数化」「9.8 方案公式」 分数原文 11/1125 与「聚合:20%+5%」不动——那是金额口径的可复核原文, 不是说明文案。init-dev.sql 种子 description 与 registry 同源。 Co-Authored-By: Claude Code <noreply@anthropic.com>
这个提交包含在:
1 父节点
111ac5425a
当前提交
61965e0b60
9 个文件已更改
+164
-104
没有与搜索条件相匹配的文件
@@ -44,7 +44,7 @@ from app.schemas.param import (
|
||||
ParamPreviewOut,
|
||||
ParamUsedOut,
|
||||
)
|
||||
from app.services import audit_service, formula
|
||||
from app.services import audit_service, calc_templates, formula
|
||||
from app.services.audit_service import AuditRecord, RequestMeta
|
||||
from app.services.formula import to_decimal
|
||||
from app.services.no_generator import next_no
|
||||
@@ -557,25 +557,25 @@ def _preview_rate(ctx: _PreviewContext, days: int) -> tuple[Fraction, str, Decim
|
||||
# 存储口径为 ‰ 数(如 "3"),除以 1000 转纯比例 —— performance_amount
|
||||
# 按纯比例相乘,漏换算会把绩效金额放大 1000 倍(与业务员分支同防线)
|
||||
rate = take("enterprise.rate") / 1000
|
||||
return rate, "企业户固定计提比例", None
|
||||
return rate, "企业户:不按回款天数,统一按固定比例计提", None
|
||||
|
||||
role_code = payload.business_role
|
||||
template = "TPL_SALESPERSON_DECAY"
|
||||
if role_code:
|
||||
role = business_role_repository.get_by_code(ctx.session, role_code)
|
||||
if role is None:
|
||||
raise BadRequestError(f"岗位 {role_code!r} 不存在")
|
||||
raise BadRequestError(f"岗位「{role_code}」不存在,请到岗位角色里确认")
|
||||
template = role.calc_template
|
||||
|
||||
if template == "TPL_MANAGER_SHARE":
|
||||
raise BadRequestError(
|
||||
"营销经理绩效为团队聚合口径(本团队 12.5% + 全公司 5%),不支持单笔预览"
|
||||
"营销经理的绩效按团队与全公司分成计算,不单笔试算;请到月度结算里查看"
|
||||
)
|
||||
if template == "TPL_INFO_SALES_FIXED":
|
||||
# ‰ 存储口径 → 纯比例,同企业户分支(不换算则绩效放大 1000 倍)
|
||||
rate = take("info.rate") / 1000
|
||||
# 信息员的基数是本人销售额(无折算与阈值),覆盖默认基数
|
||||
return rate, "信息员:本人销售额 × 计提比例", Decimal(payload.revenue)
|
||||
return rate, "信息员:按本人销售额乘计提比例,不随回款天数递减", Decimal(payload.revenue)
|
||||
if template == "TPL_SALESPERSON_DECAY":
|
||||
start = take("salesperson.rate.start")
|
||||
slope = take("salesperson.rate.slope")
|
||||
@@ -584,20 +584,27 @@ def _preview_rate(ctx: _PreviewContext, days: int) -> tuple[Fraction, str, Decim
|
||||
rate = formula.salesperson_rate(
|
||||
days, start=start, slope=slope, floor=floor, boundary_days=boundary
|
||||
)
|
||||
# 说明写成业务话:说清这笔为什么是这个比例、什么时候不再降
|
||||
return (
|
||||
rate,
|
||||
f"业务员递减:{to_decimal(start)}‰ 起,{days} 天(分界 {boundary} 天,超界取 {to_decimal(floor)}‰)",
|
||||
f"回款 {days} 天,从起始 {to_decimal(start)}‰ 按日递减"
|
||||
f"(满 {boundary} 天后固定按 {to_decimal(floor)}‰ 计算)",
|
||||
None,
|
||||
)
|
||||
raise BadRequestError(f"公式模板 {template} 暂不支持预览")
|
||||
# 提示里给模板中文名而不是编码:编码是内部标识,业务人员在岗位角色页看不到它
|
||||
tpl_name = calc_templates.TEMPLATES[template].name if template in calc_templates.TEMPLATES else template
|
||||
raise BadRequestError(
|
||||
f"「{tpl_name}」不支持单笔试算,请在岗位角色里改用业务员递减或信息员固定计提"
|
||||
)
|
||||
|
||||
|
||||
def _preview_rate_decision(ctx: _PreviewContext) -> _PreviewRateDecision:
|
||||
"""产品类别校验 + 回款天数 + 计提比例判定。"""
|
||||
payload = ctx.payload
|
||||
if payload.product_category and payload.product_category not in PRODUCT_CATEGORIES:
|
||||
# 提示里用中文类别名:前端下拉显示的是「市政水利」,报错却回英文编码会让人对不上
|
||||
raise BadRequestError(
|
||||
f"产品类别 {payload.product_category!r} 不存在,可选:municipal_water / rail_transit"
|
||||
f"产品类别「{payload.product_category}」不存在,可选:市政水利、轨道交通"
|
||||
)
|
||||
days = formula.payment_days(payload.ship_date, payload.receipt_date)
|
||||
rate, rate_text, base_override = _preview_rate(ctx, days)
|
||||
@@ -651,7 +658,10 @@ def _preview_probation_note(ctx: _PreviewContext) -> str | None:
|
||||
if not ctx.payload.probation:
|
||||
return None
|
||||
annual = ctx.take("probation.annual.threshold")
|
||||
return f"试用期绩效照算不发放;年累计超 {to_decimal(annual)} 元部分年底一次性结算"
|
||||
return (
|
||||
f"试用期人员:绩效照常计算但不发放;年内累计超过 {to_decimal(annual)} 元的部分,"
|
||||
"年底一次性结清。"
|
||||
)
|
||||
|
||||
|
||||
def preview(session: Session, payload: ParamPreviewIn) -> ParamPreviewOut:
|
||||
|
||||
在新工单中引用
屏蔽一个用户