fix(cvp): BEP ⑤ 口径统一落地(变动成本率=完整口径)
ci/woodpecker/push/main Pipeline failed

- 派生器/口径:F_BEP_VC_RATE 新增;卡面/公式行文案改「月固定成本 ÷ 边际贡献率」
- 保本额 = 月固定成本 ÷ (1 − 变动成本率);实测渠补率(F_BEP_REBATE)降为 e1 专用 chip
- 报告卡口径说明文字同步(固定成本=固定费用合计)

任务: finance-20261003-cvp-fix-and-bohai-coverage-fullstack ⑤
This commit is contained in:
wecom-fullstack
2026-10-04 19:53:12 +08:00
committed by Hermes CI Fix
parent 4fe956fcf9
commit 587d5b3983
5 changed files with 240 additions and 77 deletions
+35 -15
View File
@@ -35,8 +35,10 @@ router = APIRouter(prefix="/api/cma/dashboard", tags=["驾驶舱"],
# 月销 = voucher_details subject 5001(主营业务收入) 贷方 YTD 月均(万元)
# 月管理费 = 5602% 借−贷 净额 YTD 月均(carry_forward=0 行域;账面口径含折旧)
# 折旧 = 560213 借−贷 净额 YTD 月均(同上;口径4 见 _decisions/cma-expense-profit-net-caliber-20261002.md)
# 渠补率 = **实测累计**(Σ571103借方 ÷ Σ5001贷方,YTD)——取自派生落库值 F_BEP_REBATE(单一事实源)
# 保本额 = 月固定成本 ÷ (1-渠补率)
# 变动成本率 = **实测累计**(⑤ 口径统一:酣客=Σ(5401+5403+571103−530103)÷Σ5001贷;
# 博海=Σ6401借÷Σ6001贷)——取自派生落库值 F_BEP_VC_RATE(单一事实源)
# 实测渠补率 = Σ571103借 ÷ Σ5001贷(酣客专用,F_BEP_REBATE,仅作 chip 展示,**不再充当变动成本率**)
# 保本额 = 月固定成本 ÷ 边际贡献率(边际贡献率 = 1 − 变动成本率)
# 2026-10-02 口径修订(任总 11:43 CST 放行「改,这样数据更加真实」):
# ① 渠补率不再用政策常量 84.61 参与计算,改用派生落库的实测累计值;
# 政策常量仅作对照返回(inputs.rebate_policy_pct),**不参与计算**;
@@ -46,10 +48,16 @@ router = APIRouter(prefix="/api/cma/dashboard", tags=["驾驶舱"],
# 不出保本值、不回落政策常量(不跨期回落,避免混期口径)。
# 账面口径(含折旧) / 现金口径(剔除折旧) 双口径只读返回,无写操作。
BEP_CODES = ("F_BEP_REVENUE", "F_BEP_COVER", "F_BEP_GAP",
"F_BEP_REVENUE_CASH", "F_BEP_COVER_CASH", "F_BEP_REBATE")
"F_BEP_REVENUE_CASH", "F_BEP_COVER_CASH",
"F_BEP_VC_RATE", "F_BEP_REBATE")
BEP_BOOK_CODES = ("F_BEP_REVENUE", "F_BEP_COVER", "F_BEP_GAP") # 账面3条必须齐全才 available
BEP_CASH_CODES = ("F_BEP_REVENUE_CASH", "F_BEP_COVER_CASH")
BEP_REBATE_CODE = "F_BEP_REBATE" # 变动/渠补率派生KPI编码(卡面单一事实源)
# 保本公式所用「变动成本率」编码(⑤ 口径统一 2026-10-03:边际贡献率 = 1 − 变动成本率)
BEP_VC_CODE = "F_BEP_VC_RATE"
# 实测渠补率编码(酣客 e1 专用、**可选**;⑤ 后**不再充当变动成本率**,仅作卡面 chip)
BEP_REBATE_CODE = "F_BEP_REBATE"
# fail-closed 必备六条:VC_RATE 必填;REBATE 因博海(e2)无渠补科目而不作必备
BEP_REQUIRED_CODES = tuple(c for c in BEP_CODES if c != BEP_REBATE_CODE)
# 展示用输入口径常量(**仅酣客(entity1)**;多实体一律走 app/utils/bep_caliber.py 的 ENTITY_CALIBERS,
# 2026-10-03 扩面:博海 entity2 为 6001/6401/6601+6602+6603/1602)
BEP_SALES_SUBJECT = "5001"
@@ -153,6 +161,10 @@ def get_bep_card(
· 渠补率 = 派生落库的**实测累计值**(F_BEP_REBATE,单一事实源);政策常量仅对照返回;
· 账面 / 现金两条路径**统一读派生落库值**(不再实时复算 voucher);
· fail-closed:六条派生值同期不齐(尤其缺渠补率)⇒ available=False,不出保本值、不回落常量。
2026-10-03 口径统一(⑤,任总 18:00 CST):**边际贡献率 = 1 − 变动成本率**(F_BEP_VC_RATE,
完整口径:销货成本+税金及附加+渠补−厂补 / 博海 6401÷6001),不再用渠补率充当变动成本率;
实测渠补率 F_BEP_REBATE 降为 e1 专用展示 chip(e2 无渠补科目 ⇒ None,不再纳入必备集)。
"""
cal = caliber_or_none(entity_id)
if cal is None:
@@ -199,20 +211,21 @@ def get_bep_card(
months = int(period[5:7])
period_from = f"{year}-01"
# fail-closed:六条派生值(含变动成本率)本期必须齐全,缺一条即不出保本值
missing_at_period = [c for c in BEP_CODES if by_code.get(c, {}).get(period) is None]
# fail-closed:必备派生值(含变动成本率)本期必须齐全,缺一条即不出保本值
missing_at_period = [c for c in BEP_REQUIRED_CODES if by_code.get(c, {}).get(period) is None]
if missing_at_period:
# ① 不适用(派生器 fail-closed 落库:remark 已注明「保本点不适用」)
# —— 与「缺数」区分:卡面显示「不适用」而非「数据不齐」,且不得显示 0。
na_remarks = [remark_map.get((c, period), "") for c in missing_at_period]
na_hit = [r for r in na_remarks if "不适用" in r]
if na_hit and BEP_REBATE_CODE not in missing_at_period:
if na_hit and BEP_VC_CODE not in missing_at_period:
reason = na_hit[0]
label = ("边际贡献为负 · 保本点不适用" if "边际贡献非正" in reason
else "固定成本退化 · 保本点不适用")
return {"available": False, "not_applicable": True, "entity_id": entity_id,
"period": period, "months": months,
"label": label, "reason": reason,
"vc_pct": by_code.get(BEP_VC_CODE, {}).get(period),
"rebate_pct": by_code.get(BEP_REBATE_CODE, {}).get(period),
"rebate_policy_pct": (cal.get("policy_pct")
if cal.get("policy_pct") is not None else BEP_REBATE_POLICY_PCT),
@@ -221,8 +234,8 @@ def get_bep_card(
"derived_periods": book_periods[:6],
"data_source": "derived", "readonly": True}
# ② 缺数(真不齐)
if BEP_REBATE_CODE in missing_at_period:
msg = (f"{cal['margin_label']}不可得:本期未落 F_BEP_REBATE 派生值 ⇒ 不出保本值"
if BEP_VC_CODE in missing_at_period:
msg = (f"{cal['margin_label']}不可得:本期未落 F_BEP_VC_RATE 派生值 ⇒ 不出保本值"
"(fail-closed,不回落政策常量、不跨期回落)")
else:
msg = ("本期派生值不齐 %s ⇒ 不出保本值(fail-closed,不跨期回落)"
@@ -233,16 +246,19 @@ def get_bep_card(
else BEP_REBATE_POLICY_PCT),
"derived_periods": book_periods[:6], "readonly": True}
# 六条派生落库值(同期)—— 账面 / 现金两条路径同一来源,卡面不做实时复算
d = {c: by_code[c][period] for c in BEP_CODES}
# 派生落库值(同期)—— 账面 / 现金两条路径同一来源,卡面不做实时复算
d = {c: by_code.get(c, {}).get(period) for c in BEP_CODES}
book_bep = float(d["F_BEP_REVENUE"])
book_cover = float(d["F_BEP_COVER"])
book_gap = float(d["F_BEP_GAP"])
cash_bep = float(d["F_BEP_REVENUE_CASH"])
cash_cover = float(d["F_BEP_COVER_CASH"])
cash_gap = round(100.0 - cash_cover, 1) # 缺口 = 100 − 覆盖率(与派生器同口径)
rebate_pct = float(d[BEP_REBATE_CODE]) # 实测累计渠补率(单一事实源)
cm_pct = round(100.0 - rebate_pct, 2)
# ⑤ 口径统一(任总 2026-10-03 18:00「统一」):保本公式用**变动成本率**(F_BEP_VC_RATE),
# 边际贡献率 = 1 − 变动成本率;F_BEP_REBATE(实测渠补率)仅酣客(e1)有,**不再充当变动成本率**。
vc_pct = float(d[BEP_VC_CODE])
cm_pct = round(100.0 - vc_pct, 2)
rebate_pct = (float(d[BEP_REBATE_CODE]) if d.get(BEP_REBATE_CODE) is not None else None)
# 输入口径(万元,展示用;数值口径一律以派生落库值为准)——按实体口径现算
inp = _bep_inputs(db, entity_id, cal, period_from, period, months)
@@ -272,9 +288,12 @@ def get_bep_card(
"sales_avg": round(sales_avg, 2),
"admin_avg": round(admin_avg, 2),
"dep_avg": round(dep_avg, 2),
"vc_pct": vc_pct,
"rebate_pct": rebate_pct,
"rebate_policy_pct": BEP_REBATE_POLICY_PCT, # 政策常量:仅作对照,不参与计算
"rebate_source": "derived:F_BEP_REBATE(Σ571103借方÷Σ5001贷方, YTD累计)",
"rebate_source": ("derived:F_BEP_VC_RATE(⑤完整口径:销货成本+税金及附加+渠补−厂补)"
if entity_id == 1
else "derived:F_BEP_VC_RATE(Σ6401借÷Σ6001贷)"),
"cm_pct": cm_pct,
},
"book": {
@@ -294,7 +313,8 @@ def get_bep_card(
},
"derived": derived,
"data_source": "derived", # 账面/现金同源:均读派生落库值
"formula": f"保本销售额 = 月固定成本 ÷ (1 − 实测渠补率{rebate_pct:.2f}%)",
"formula": (f"保本销售额 = 月固定成本 ÷ 边际贡献率{cm_pct:.2f}%"
f"(边际贡献率 = 1 − 变动成本率{vc_pct:.2f}%)"),
"readonly": True,
}