Files
cma-management/backend/app/utils/bep_caliber.py
T
Hermes CI Fix 289cc8f2cc
ci/woodpecker/push/main Pipeline was successful
fix(profit-caliber): 博海口径 §4-1/§4-2/§4-5 落地 —— 固定成本仅借方 + 6403 进变动 + 财务收益单列 + 批次备注
ASK-20261014-04(任总 2026-10-14 11:20「放行4」)批后口径:
- §4-1 博海固定成本弃净额:6601/6602/6603 仅借方(133.98 万,2026-01..09);2026-03 单月由 -9.02 万转正;
  6603 贷方(现金折扣收益 64.40 万)改 finance_income_terms 单列备查,不进固定成本/末行/勾稽。
- §4-2 博海变动成本追加 6403 营业税金及附加(530.17 万)。
- §4-3/§4-4 维持现行(酣客收入/边际贡献基数不动)。
- §4-5 管理利润表页加「数据批次/导入时刻」纯展示备注(import_logs)。
- 口径唯一源仍为 bep_caliber.ENTITY_CALIBERS;报表/卡面/派生器一律经 fixed_cost_spec() 解析(读口写口一致)。
2026-10-16 12:32:52 +08:00

143 lines
9.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""BEP(本量利·保本点)实体口径注册表 —— **单一事实源**。
被两侧共用,避免口径漂移:
· 派生落库写入面:`backend/scripts/kpi_bep_deriver.py`
· 卡面读取面 :`backend/app/api/dashboard.py::/bep-card`
口径(2026-10-03 财务裁定 + 任总 18:00「统一」,任务 finance-20261003-cvp-fix-and-bohai-coverage-fullstack):
| 项 | entity 1 陕西酣客 | entity 2 博海 |
|---|---|---|
| 变动成本(分子) | **(Σ5401借 + Σ5403借 + Σ571103借 − Σ530103贷)**〔⑤口径统一〕 | **Σ6401借 + Σ6403借**〔ASK-20261014-04 §4-2 批后口径〕 |
| 收入基数(分母) | Σ5001 贷方(主营业务收入) | Σ6001 贷方(主营业务收入,**不含** 6051)〔§4-4 维持现行〕 |
| 变动成本率 | 上式 ÷ Σ5001贷(**完整口径**,非渠补率) | 上式 ÷ Σ6001贷(主营业务成本率 + 税金及附加) |
| 实测渠补率(F_BEP_REBATE) | Σ571103借 ÷ Σ5001贷(**保留**为渠补单一事实源,**不再**充当变动成本率) | 无(None) |
| 固定成本 | `5601%` + `5602%` + `5603%` 借−贷净额〔⑤扩容〕 | `6601` + `6602` + `6603` **仅借方**〔ASK-20261014-04 §4-1 批后口径〕 |
| 财务收益(单列备查,**不进**固定成本) | 无(`560303` 利息收入 2026 零发生) | `6603` **贷方**(现金折扣收益等 64.40 万)〔§4-1〕 |
| 折旧剔除(现金口径) | `560213`(管理费用-折旧叶子) | `1602` 累计折旧**当期贷方发生额**(见下) |
| 本期利润结转科目 | `3103` 本年利润 | `4103` 本年利润 |
| 结账信号次选(落盘) | `/root/WB_WS/_data/zxt-hanke/{YYYY.MM}/check.md` | 无(只用 DB 信号) |
⑤ 口径统一依据(任总 2026-10-03 18:00 DM「统一」):完整口径唯一可勾稽至营业利润
`808.80 − 672.65 − 224.16 = −88.01 ≈ −88.00` 既定营业利润。
2026-08 锚点(YTD 月均):变动成本率 **83.17%**、边际贡献率 **16.83%**、固定月均 **28.02 万**、
保本 **166.45 万/月**、覆盖率 **60.74%**、缺口 **39.26%**、现金保本 **≈121.8 万/月**。
博海折旧口径说明:博海科目表只到 4 位一级科目(无费用类折旧叶子,**不存在** 酣客式 `560213`),
唯一含「折旧」的是资产类 `1602 累计折旧`;其**当期贷方发生额** = 当期计提折旧额(对方科目
计入 `6602 管理费用`),故取它作现金口径剔除项。实测 2026-01..07 每月 1,468.83 元,
2026-08 起无计提行 ⇒ 2026-08 剔除额为 0(已在回报件列明)。
⚠️ 博海账套的「期间损益结转腿」(`summary='结转期间损溢'`,凭证如 `记-705/记-706`)
**未**标 `carry_forward=1`(全账套 17343 行 carry_forward 恒 0)⇒ 若不显式剔除,
损益类科目「借−贷」净额在已结账月份恒为 0,会把指标静默清零
(口径见 `/srv/hermes/wisdom/_decisions/cma-expense-profit-net-caliber-20261002.md`)。
故博海口径 `exclude_closing=True`。
⑥ ASK-20261014-04 批后口径(任总 2026-10-14 11:20「放行4」= 放行 4-1 / 4-2 / 4-5;4-3 / 4-4 维持现行):
· §4-1(放行)博海固定成本**弃「借−贷净额」**:`6601` / `6602` / `6603` **仅借方**进固定成本
(2026-01..09 = 86.95 + 39.09 + 7.95 = **133.98 万**;净额口径为 69.58 万);
`6603` **贷方**(现金折扣收益等 64.40 万)**作收益项单列**,`finance_income_terms`,**不再冲减固定成本**
—— 净额口径的病灶是 2026-03 单月固定成本被折扣收益打成 **−9.02 万**(负值),批后为正值。
· §4-2(放行)博海变动成本追加 `6403 营业税金及附加`(2026-01..09 = 0.37 万)⇒ 530.17 万。
· §4-3 / §4-4(维持现行)`571112 商品折扣` 不冲减酣客收入;边际贡献收入基数维持 e1=`5001` /
e2=`6001`(**不含** e2 `6051`)。
· 落点唯一:本表 `ENTITY_CALIBERS`(含本头注);报表层 / 卡面 / 派生器**一律**经
`fixed_cost_spec()` 解析,不得另写科目集。酣客(e1)本次**未改**,仍走 `fixed_filters` 净额。
"""
CLOSING_SUMMARY_LIKE = "%结转%"
# 酣客结账信号次选来源(智享通落盘 check.md;与 app/api/data.py 的 ZXT_LANDING_DIR 同源)
ZXT_LANDING_DIR_HANKE = "/root/WB_WS/_data/zxt-hanke"
# 变动成本「带号科目项」记法: terms = [(sign, subject_code, field), ...]
# sign='+' ⇒ 取该科目 field 的发生额相加;sign='-' ⇒ 取该科目 field 的发生额相减
# field ∈ {'debit' → debit_amount, 'credit' → credit_amount, 'net' → 借−贷}
ENTITY_CALIBERS = {
1: dict(
name="陕西酣客",
margin_label="变动成本率",
margin_desc="(Σ5401借+Σ5403借+Σ571103借−Σ530103贷) ÷ Σ5001贷",
# ⑤ 口径统一(2026-10-03 任总「统一」):变动成本 = 销货成本 + 税金及附加 + 渠补 − 厂补
varcost_terms=[("+", "5401", "debit"), ("+", "5403", "debit"),
("+", "571103", "debit"), ("-", "530103", "credit")],
# F_BEP_REBATE 实测渠补率专用(单一事实源保留;不再充当变动成本率)
rebate_terms=[("+", "571103", "debit")],
revenue_field="credit_amount", revenue_filter=("eq", "5001"),
fixed_filters=[("like", "5601"), ("like", "5602"), ("like", "5603")],
# §4-1 未改酣客:仍走「借−贷净额」前缀口径 ⇒ fixed_terms 显式 None(不隐式继承)
fixed_terms=None,
finance_income_terms=None, # 酣客 560303 利息收入 2026 零发生 ⇒ 无单列财务收益项
fixed_label="固定成本(5601+5602+5603 借−贷净额)",
dep_field="net", dep_filter=("eq", "560213"),
closing_subject="3103",
landing_dir=ZXT_LANDING_DIR_HANKE,
exclude_closing=False,
policy_pct=84.61, # 政策常量:仅对照展示,不参与计算(仅酣客有)
),
2: dict(
name="博海",
margin_label="变动成本率(主营成本率+税金及附加)",
margin_desc="(Σ6401借+Σ6403借) ÷ Σ6001贷",
# §4-2(放行):追加 6403 营业税金及附加(与 e1 含 5403 对齐)
varcost_terms=[("+", "6401", "debit"), ("+", "6403", "debit")],
rebate_terms=None, # 博海无渠补科目
revenue_field="credit_amount", revenue_filter=("eq", "6001"),
# §4-1(放行):弃「借−贷净额」⇒ 带号科目项 + field=debit(仅借方);
# 6603 贷方(现金折扣收益)改走 finance_income_terms 单列,不再冲减固定成本
fixed_terms=[("+", "6601", "debit"), ("+", "6602", "debit"), ("+", "6603", "debit")],
fixed_filters=None, # 显式置空:禁止两套口径并存(fixed_cost_spec 以 terms 优先)
finance_income_terms=[("+", "6603", "credit")],
fixed_label="固定成本(6601+6602+6603 借方)",
dep_field="credit_amount", dep_filter=("eq", "1602"),
closing_subject="4103",
landing_dir=None,
exclude_closing=True,
policy_pct=None,
),
}
def caliber_or_none(entity_id: int):
"""取实体口径;未注册返回 None(调用方自行决定放行/拒答)。"""
return ENTITY_CALIBERS.get(entity_id)
def caliber_for(entity_id: int) -> dict:
"""取实体口径;未注册抛 KeyError(写入面用,fail-closed)。"""
cal = ENTITY_CALIBERS.get(entity_id)
if cal is None:
raise KeyError(f"entity={entity_id} 未注册 BEP 口径(见 app/utils/bep_caliber.py)")
return cal
# ── 固定成本 / 财务收益:**唯一解析口** ──────────────────────────────────────
# 报表层(app/utils/profit_lines.py)、卡面(app/api/dashboard.py)、派生器
# (scripts/kpi_bep_deriver.py)三处一律经本函数取科目构成,禁各自写一套(防「卡面新口径 /
# KPI 旧口径」)。§4-1 后:e2 走 terms(`6601/6602/6603` 仅借方),e1 走 filters(借−贷净额)。
def fixed_cost_spec(cal: dict):
"""固定成本取数规格 → (mode, spec)。
mode='terms' ⇒ spec = [(sign, code, field), ...](带号科目项;§4-1 后博海形态)
mode='filters' ⇒ spec = [(kind, code), ...](前缀/精确 OR + 借−贷净额;酣客形态)
"""
terms = cal.get("fixed_terms")
if terms:
return "terms", [tuple(t) for t in terms]
return "filters", [tuple(f) for f in (cal.get("fixed_filters") or [])]
def finance_income_terms(cal: dict) -> list:
"""财务收益(单列备查,**不进**固定成本)带号科目项;无则空列表(§4-1 只涉博海)。"""
return [tuple(t) for t in (cal.get("finance_income_terms") or [])]
def caliber_digest() -> str:
"""口径指纹(证据用):ENTITY_CALIBERS 的 md5 —— 口径一改指纹即变,便于「改前/改后」取证。"""
import hashlib
import json
blob = json.dumps(ENTITY_CALIBERS, sort_keys=True, ensure_ascii=False, default=str)
return hashlib.md5(blob.encode("utf-8")).hexdigest()