feat(calc): 二次分摊拆行与 #12 单笔侧开关——按方案比例拆给参与人、余额归负责人
- _personal_rate 的 TPL_MANAGER_SHARE 分支读 manager.personal.included:1=按业务员递减公式计提,0=单笔落 0(现状) - _load_allocations 装载生效方案并防御拦截(合计超 100%、参与人含负责人) - _persist_ledger 拆行落库:参与人=份额×比例(q2)、负责人=q2 全额−已分累计(行合计守恒防分漂);快照带 alloc_plan/alloc_role/alloc_ratio - _prepare_mode 重算改 list_active_by_receipt 作废全部拆分行;uk 三列版支持同回款按人多行 - business_service 保存侧同口径校验(超 100% 400、负责人自分 400、hint 文案定稿) - 集成用例 +5(拆行守恒/叠加进度登记/重算全作废/双拦截)+保存侧 3 条 Co-Authored-By: Claude Code <noreply@anthropic.com>
这个提交包含在:
1 父节点
48c0a86279
当前提交
ccfd20651b
5 个文件已更改
+479
-58
没有与搜索条件相匹配的文件
@@ -298,8 +298,24 @@ def _build_allocation_rows(
|
||||
编辑业务(哪怕只改备注)不应被历史参与人的离职状态卡死;仅对
|
||||
**新加入**的参与人做在职校验。
|
||||
|
||||
:raises BadRequestError: 新增参与人员不存在或已离职
|
||||
:raises BadRequestError: 新增参与人员不存在或已离职 / 比例合计超 100%
|
||||
/ 参与人含合同负责人(口径见澄清 #1/#2 答复 2026-10-19:分配绩效、
|
||||
余额归合同负责营销人员——超 100% 会把负责人份额算成负数,负责人
|
||||
自分份额则双重计入)
|
||||
"""
|
||||
business = business_repository.get_by_id(session, business_id)
|
||||
if business is None:
|
||||
raise NotFoundError("业务不存在")
|
||||
total = sum((Decimal(item.ratio) for item in items), Decimal("0"))
|
||||
if total > Decimal("100"):
|
||||
raise BadRequestError(
|
||||
f"二次分配比例合计 {total.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)}%"
|
||||
" 超过 100%(余额归合同负责营销人员,比例不可超满额)"
|
||||
)
|
||||
owner_id = business.owner_personnel_id
|
||||
if owner_id is not None and any(item.personnel_id == owner_id for item in items):
|
||||
raise BadRequestError("分摊参与人不可包含合同负责营销人员(负责人得余额份额)")
|
||||
|
||||
rows: list[SecondaryAllocation] = []
|
||||
for item in items:
|
||||
if item.personnel_id in old_ids:
|
||||
@@ -320,7 +336,7 @@ def _build_allocation_rows(
|
||||
|
||||
|
||||
def _allocation_hint(allocations: list[SecondaryAllocation]) -> str | None:
|
||||
"""方案合计/余额提示(不强制合计满额是需求原文;余额归属待澄清 #2)。
|
||||
"""方案合计/余额提示(不要求合计满额是需求原文;余额归属 = 澄清 #2 答复)。
|
||||
|
||||
无方案返回 None;合计恰满额只报合计,避免「余额 0」噪音。
|
||||
"""
|
||||
@@ -331,7 +347,7 @@ def _allocation_hint(allocations: list[SecondaryAllocation]) -> str | None:
|
||||
if total == Decimal("100"):
|
||||
return f"二次分配合计 {total_text}%"
|
||||
rest = (Decimal("100") - total).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||
return f"二次分配合计 {total_text}%,余额 {rest}%(归属待业务确认)"
|
||||
return f"二次分配合计 {total_text}%,余额 {rest}%(归合同负责营销人员)"
|
||||
|
||||
|
||||
def create_business(
|
||||
|
||||
在新工单中引用
屏蔽一个用户