wip(strategy-map): v4 口径落码(分线营收/新式毛利率/管理指标/C1 hold/57 归档)
This commit is contained in:
@@ -1,63 +1,109 @@
|
||||
"""战略地图 · 收入口径(revenue caliber)状态 —— 单一事实源
|
||||
"""战略地图 · 收入 / 毛利 / 管理指标口径(单一事实源,勿在别处写死)
|
||||
|
||||
口径来源:改造单 `project-20261018-cma-strategy-map-ux-revamp-fullstack` 增量 v2 §4。
|
||||
截至本文件落地(2026-10-18T23:00),A1 收入口径**尚未闭合**:
|
||||
- 业务称谓「代理」≠ 会计判定(总额法 total / 净额法 net / 混合 mixed 未裁);
|
||||
- 财务净额件与项目侧「三问」总额判定并存,正由 A1 补充单裁决。
|
||||
口径来源(引用勿改):
|
||||
/srv/hermes/mailbox/finance/pending-tasks/_reports/
|
||||
project-20261018-strategy-map-data-a1-addendum-finance-v2-return.md
|
||||
改造单 project-20261018-cma-strategy-map-ux-revamp-fullstack 增量 v4
|
||||
|
||||
因此本模块只声明**状态**与**业务线维度**,不存任何金额:
|
||||
- 接口照常返回 `revenue_caliber` 与分业务位(amount=None + status=pending);
|
||||
- 前端不得写死任一方法,不得把两块合并成一个「营业收入」;
|
||||
- 口径闭合后只改本文件(status/caliber/decided_by/closed_at),并回填金额取数逻辑,
|
||||
不需要改前端。
|
||||
终稿结论(2026-10-19):
|
||||
- 陕西博海、陕西酣客 **均总额法(主要责任人)**;
|
||||
- 增值税 = 销售货物 13%(账内 11 张凭证实测,6% 代理服务零证据);
|
||||
- 9,492.6 万 = 冲减采购成本/存货成本(唯一落位,**无「补贴收入/其他收益」行**),
|
||||
本模块不产生该数、也不允许任何调用点拼出该串;
|
||||
- F2 毛利率新式 = (收入净额 − 折扣后净进价成本) / 收入净额 × 100;
|
||||
旧式(含 `k` 的 5001/571103 组合)作废,**不得在本文件或调用点复现**;
|
||||
- 历史期缺同票折扣发票(四件套 0/4)⇒ 金额只作现值展示并带「测算/待票」标识。
|
||||
|
||||
铁律:未闭合前,页面与接口都**不得**输出单一汇总收入数。
|
||||
本模块只放**口径与科目映射**,不存金额;金额一律由 API 对库内 voucher_details 现算
|
||||
(filter: summary NOT LIKE '%结转%',否则损益双向抵销归零)。
|
||||
"""
|
||||
|
||||
# 口径状态:unclosed / closed
|
||||
STATUS = "unclosed"
|
||||
CALIBER = None # closed 时取 "total" / "net" / "mixed"
|
||||
CALIBER_LABEL = "口径待定"
|
||||
DECIDED_BY = None # closed 时填裁决单/ASK 编号
|
||||
CLOSED_AT = None # ISO 时间
|
||||
REASON = (
|
||||
"A1 收入口径尚未闭合(截至 2026-10-18T23:00):业务称谓「代理」≠ 会计判定,"
|
||||
"总额法/净额法/混合法并存,待 A1 补充单裁决"
|
||||
)
|
||||
# ── 收入口径状态(v4 起为已闭合)──────────────────────────────────────────────
|
||||
STATUS = "closed"
|
||||
CALIBER = "total" # total / net / mixed
|
||||
CALIBER_LABEL = "总额法(会计)· 增值税13%"
|
||||
DECIDED_BY = "A1 终稿(project-20261018-strategy-map-data-a1-addendum-finance-v2-return.md)"
|
||||
REASON = "两家均主要责任人 ⇒ 总额法;增值税销售货物 13% 实测,无税会差异"
|
||||
|
||||
# 分业务(不得合并;amount 由 closed 后的取数逻辑回填)
|
||||
BUSINESS_LINES = [
|
||||
{"key": "liquor_agency", "label": "酒类代销"},
|
||||
{"key": "it_self", "label": "IT自营"},
|
||||
# ── 按实体的科目映射(各账套科目体系不同:酣客 5001/5401,博海 6001/6401)──────
|
||||
SUBJECT_MAP = {
|
||||
1: {
|
||||
"revenue": "5001", # 主营业务收入
|
||||
"cost": "5401", # 主营业务成本
|
||||
"purchase_discount": "530111", # 商品折扣(采购)
|
||||
"purchase_gift": "530103", # 采购获赠(捐赠收益)
|
||||
"lines": [
|
||||
{"key": "liquor", "label": "酒类"},
|
||||
{"key": "other", "label": "其他"},
|
||||
],
|
||||
},
|
||||
2: {
|
||||
"revenue": "6001", # 主营业务收入
|
||||
"cost": "6401", # 主营业务成本
|
||||
"purchase_discount": "6603", # 财务费用-现金折扣(贷方=采购折扣)
|
||||
"purchase_gift": None,
|
||||
"lines": [
|
||||
{"key": "self_it", "label": "自营(IT)"},
|
||||
{"key": "agency_liquor", "label": "代销(酒类)"},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
# 酒类判定(财务 A1 件同一口径):摘要含以下任一关键词 ⇒ 酒类业务线
|
||||
WINE_KEYWORDS = ("酣客", "酒窖", "酣亲", "秦莉", "牛彦平", "横山")
|
||||
|
||||
# 采购来源(博海酒类采购:陕西酣客 / 酣客酒业)
|
||||
LIQUOR_SUPPLIERS = ("酣客", "酒业")
|
||||
|
||||
|
||||
def wine_sql(column: str = "summary") -> str:
|
||||
"""SQL 片段:酒类业务线判定(与财务回执同口径,勿改)。"""
|
||||
return "(" + " OR ".join(f"{column} LIKE '%{k}%'" for k in WINE_KEYWORDS) + ")"
|
||||
|
||||
|
||||
def supplier_sql(column: str = "summary") -> str:
|
||||
return "(" + " OR ".join(f"{column} LIKE '%{k}%'" for k in LIQUOR_SUPPLIERS) + ")"
|
||||
|
||||
|
||||
# ── 口径切换期标识位(v4 §4:不硬编码日期;生效日以任总拍板 ASK 为准)──────────
|
||||
CALIBER_SWITCH = {
|
||||
"has_switch": True,
|
||||
"label": "口径变更",
|
||||
"effective_date": None, # 未拍板前恒为 None —— 禁止写死日期
|
||||
"comparability": "口径变更·不可比",
|
||||
"note": "同比/达成率/预算执行率在切换期内不可比;生效日以任总拍板(ASK)为准",
|
||||
}
|
||||
|
||||
# ── 缺件披露(v4 §5:界面不得呈现为「已齐」)─────────────────────────────────
|
||||
MISSING_DOCS = [
|
||||
"经销/代理协议",
|
||||
"厂家价格政策",
|
||||
"逐笔折扣发票+合同审批单",
|
||||
"上游退货条款",
|
||||
"发票台账(invoice_check 空)",
|
||||
]
|
||||
|
||||
|
||||
def business_lines(entity_id: int) -> list:
|
||||
cfg = SUBJECT_MAP.get(entity_id)
|
||||
return list(cfg["lines"]) if cfg else []
|
||||
|
||||
|
||||
def snapshot(entity_id: int) -> dict:
|
||||
"""返回对外口径快照(无金额;未闭合时 amount 一律 None)。"""
|
||||
"""对外口径快照(无金额;金额见 /api/cma/maps/summary)。"""
|
||||
return {
|
||||
"entity_id": entity_id,
|
||||
"status": STATUS,
|
||||
"caliber": CALIBER,
|
||||
"caliber_label": CALIBER_LABEL,
|
||||
"caliber_options": [
|
||||
{"key": "total", "label": "总额法"},
|
||||
{"key": "net", "label": "净额法"},
|
||||
{"key": "mixed", "label": "混合法"},
|
||||
],
|
||||
"decided_by": DECIDED_BY,
|
||||
"closed_at": CLOSED_AT,
|
||||
"reason": REASON,
|
||||
"allow_single_total": False, # 分业务线分列;不合并成单一「营业收入」
|
||||
"businesses": [
|
||||
{
|
||||
"key": b["key"],
|
||||
"label": b["label"],
|
||||
"amount": None,
|
||||
"unit": "万元",
|
||||
"status": "pending",
|
||||
"missing_reason": "收入口径未闭合" if STATUS != "closed" else None,
|
||||
}
|
||||
for b in BUSINESS_LINES
|
||||
{"key": b["key"], "label": b["label"], "unit": "万元"}
|
||||
for b in business_lines(entity_id)
|
||||
],
|
||||
"allow_single_total": STATUS == "closed",
|
||||
"note": "未闭合前不显示单一汇总数;分业务分列,不合并为「营业收入」",
|
||||
"switch": CALIBER_SWITCH,
|
||||
"missing_docs": MISSING_DOCS,
|
||||
"note": "分业务线全额售价分列;禁净额、禁合并为单一「营业收入」",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user