合并财务报表(hebing-caiwu-baobiao)v2.1.0
适用场景
用户提供 N 家分支机构《科目发生额及余额表.xlsx》文件夹,要求:
- 按会小企01表(资产负债表)/ 02表(利润表)格式输出合并财务报表(Excel)
- 输出资产负债表合并底稿、利润表合并底稿(行次/报表项目/各分支机构列)
- 说明内部往来抵消与差额处理、损益类未结转净额处理、科目口径不一致处理(映射表)
原则:源表零改动、审计留痕(映射表/调整行即留痕)。
环境说明
主路径:Python 3 + openpyxl(推荐)
- 运行时:
C:\Users\Administrator\.workbuddy\binaries\python\versions\3.13.12\python.exe - 依赖:openpyxl 3.1.5(已安装在
binaries/python/envs/default) - 解析方式:zipfile + xml.etree.ElementTree 纯标准库解析 xlsx(不依赖 openpyxl 读源表;openpyxl 仅用于写 Excel 输出)
- 优势:列自动检测、灵活容错、JSON 中间数据可复查
共同约束
- LibreOffice 不可用 → 生成 Excel 时填数值(合计行也算好写入),不写公式
- 中文路径/文件名先
cp到工作区再处理(避免编码问题)
源文件结构(自动检测,不假设固定值)
文件夹要求
- 包含 N 个
.xlsx文件(N ≥ 2),每个文件 = 一家分支机构的《科目发生额及余额表》 - 文件名建议含机构名(如
凯泽名苑1-7月发生额及余额表.xlsx),脚本会自动提取
工作表结构(自动适配)
脚本会自动扫描表头行确定以下参数,不需手动配置:
| 参数 | 说明 | 自动检测逻辑 | |---|---|---| | 数据起始行 | 表头下一行开始 | 扫描含"科目编号"或"科目编码"的行 | | 列映射 | 各字段所在列 | 通过表头文本匹配:科目类别/科目编码/科目名称/期初借方/期初贷方/本期借方发生额/本期贷方发生额/期末借方/期末贷方 | | 期间 | 数据覆盖期间 | 扫描编制单位行的日期文本 |
已知实际列布局(2026年XX公司数据验证):
B=科目类别 C=科目编码 D=科目名称 E=期初借 F=期初贷 G=本期借 H=本期贷 I=期末借 J=期末贷
⚠️ 历史版本曾假设 A-H 列(错误),已修正为 B-J 列。v2 起不再硬编码列号,以自动检测结果为准。
科目层级处理(关键!)
余额表中科目存在父子层级关系:
- 父科目行(如
1001货币资金)= 其下所有子科目(100101100102…)的合计 - 若将父+子全部加总 → 重复计算 → 借贷不平衡
解决方案(pipeline.py 已实现): 只保留"叶子科目"(其编码不是任何其他科目编码的前缀),丢弃父行。
丢弃规则: 若 code_A 是 code_B 的前缀且 len(code_A) < len(code_B) → code_A 视为父行,丢弃
科目编号规则
- 一级科目 = 编码前4位:1=资产 2=负债 3=权益 4=成本 5=损益
- 损益类一级科目:5001主营业务收入、5051其他业务收入、5301营业外收入、5401主营业务成本、5403税金及附加、5601销售费用、5602管理费用、5603财务费用、5711营业外支出、5801所得税费用
处理流程(6步)
Step 1: 解析原始余额表 → balances_data.json
脚本:work/pipeline.py(前半段)
- 逐 xlsx 解压 → 解析 sharedStrings.xml + sheet1.xml
- 自动检测列位置(表头匹配,回退到已知布局 B-J)
- 自动提取叶子科目(去父行)
- 每机构做借贷平衡校验(期初/本期/期末净额均应 ≈0)
- 输出:
balances_data.json(逐机构叶子行)
Step 2: 科目口径统一 → normalized.json + agg.json
脚本:work/pipeline.py(后半段)
- 以第1家机构为基准构建 baseCode2Name / baseName2Code 映射
- 统一各机构科目名称和编号
- 汇总为 agg.json(统一口径全机构加总)
- 校验:汇总后期初/本期/期末借贷差均为0
常见口径差异(已内置映射): | 差异类型 | 示例 | 处理 | |---|---|---| | 名称相同编号不同 | 应付工资(221101) vs 应付职工薪酬(2211) | 以基准编号为准 | | 销售费用子目 | 560101~560116 营销费用 | 归入 5602 管理费用 或 5601 销售费用 | | 应交税费拆分 | 222101/222104/222105 | 归入 2221 |
Step 3: 计算合并报表数值 → report_values.json
脚本:work/compute_report.py
核心算法:
- 净额法合并:资产/费用类 = 借方−贷方;负债/权益/收入类 = 贷方−借方
- 内部往来自然抵消:1301其他应收款(内部)/1302内部摊销/2351其他应付款(内部) 跨机构借贷相抵后净额≈0
- 重分类:应付职工薪酬等负债科目的借方余额(负值)重分类至其他应收款(资产侧)
- 未分配利润(期末) = 3103盈余公积 + 3104利润分配 + 未结转损益净额
- 未结转损益净额 = Σ收入期末贷 − Σ费用期末借
- 年初不含损益净额(年初数直接取期初余额)
⚠️ 利润表取数规则(硬性,经用户红笔核验,不可偏离):
- 收入类(5001主营业务收入 / 5051其他业务收入 / 5301营业外收入)= 本期贷方发生额(贷−借)
- 成本费用类(5401营业成本 / 5403税金及附加 / 5601销售费用 / 5602管理费用 / 5603财务费用 / 5711营业外支出 / 5801所得税费用)= 本期借方发生额(借−贷)
- 合并利润表必须自洽:营业收入 − 营业成本 − 税金及附加 − 销售费用 − 管理费用 − 财务费用 = 营业利润;+ 营业外收入 − 营业外支出 = 利润总额;− 所得税费用 = 净利润。任一项勾稽不符即说明取数方向错。
- 验证记录(2026-08-28 XX公司10家):营业收入 132,677.19 / 管理费用 59,354.00 / 财务费用 11,982.85 / 营业利润 61,340.34 / 利润总额 61,165.34 / 净利润 61,165.34,全部与 report_values.json 差 0。
资产负债表行映射(会小企01):
| 报表项目 | 科目编码前缀 | 备注 | |---|---|---| | 货币资金 | 1001, 1002 | | | 应收账款 | 1122 | | | 其他应收款 | 1221 | 含重分类转入的应付职工薪酬借方余额 | | 存货 | 1403, 1405, 4001, 4101 | | | 长期股权投资 | 1511, 1521 | | | 固定资产账面价值 | 1601+1501+1602 | 原价+累计折旧(负) | | 无形资产 | 1701+1702 | 账面价值 | | 长期待摊费用 | 1801 | | | 应付账款 | 2202 | | | 预收账款 | 2203 | | | 应付职工薪酬 | 2211 | 借方余额重分类出 | | 应交税费 | 2221 | | | 其他应付款 | 2241, 2181 | 含 2181 其他应付款(明细) | | 实收资本 | 3001 | | | 盈余公积 | 3101 | | | 未分配利润 | 3103, 3104 | 期末+未结转损益净额 |
校验(必须全部通过):
- 期末资产总计 = 负债合计 + 权益合计(差 < 0.01 元)
- 年初同上
- 净利润 = 未结转损益净额
Step 4: 生成合并报表 Excel
脚本:work/make_excel.py
- 使用 openpyxl 载入模板,填入计算数值
- 模板查找顺序(多级回退):
技能目录/templates/合并会计报表-样表.xlsx~/Desktop/小企业会计准则_会计报表格式.xlsx- 技能内嵌最小模板(无则报错提示)
- 输出文件名:
合并财务报表-N家分支机构.xlsx(N = 实际机构数) - 删除空表(如现金流量表无数据时)
- 写入编制单位、报表日期
- 权益间隔行(默认 8 行,环境变量
HB_EQUITY_PADDING):在"非流动负债合计"与"所有者权益"之间插入空白行,使左右两侧(资产 vs 负债+权益)排版对称美观
Step 4b: 用户重排样表变体(make_excel_new.py)
场景:用户已用 Excel 手工重排输出文件的版式(如插入"所有者权益"标题行、拆分固定资产原价/累计折旧/账面价值为分行、重排利润表行次)。此时标准模板单元格映射失效,且用户手填数值极易错位(实战曾出现:营业收入=0、表头 C4 误填 132,677.19、利润总额=0 而所得税=61,165.34 等)。
策略(关键):不直接在样表上重算合并数,而是复用已校验平衡的 report_values.json,按"旧→新"单元格映射只覆盖数值单元格、完整保留用户版式。
实测映射表(2026-08-28 XX公司10家,用户重排后 Desktop 样表): | 区域 | 旧键(report_values) | 新键(用户样表) | 说明 | |---|---|---|---| | 资产 C/D | C6..C36 / D6..D36 | 同 | 直接对应 | | 负债 G/H | G6..G23 / H6..H23 | 同 | 直接对应 | | 权益 G/H | G25..G30 / H25..H30 | G31..G36 / H31..H36 | 因插入"所有者权益"标题行整体下移 6 行 | | 利润表 营业收入 | PL.C4 | C5 | 行次平移 | | 利润表 营业利润 | PL.C24 | C25 | | | 利润表 利润总额 | PL.C33 | C34 | | | 利润表 净利润 | PL.C35 | C36 | | | 利润表 投资收益等无数据项 | — | 0 / 清空表头误填 | |
⚠️ 禁止在新样表上"重算合并数"回填——重算口径一旦与已验证的 report_values.json 有微小偏差即导致不平衡。始终以 report_values.json 为唯一真值源,下游填充一律引用,禁止重新聚合。
Step 5: 生成 HTML 编制报告(底稿)
脚本:work/gen_html.py
输出:报表编制底稿-合并财务报表-N家.html
角色定位:合并过程记录——逐机构工作底稿、内部往来 8 列明细(分支机构×科目×期初借/贷×本期借/贷×期末借/贷)、未结转损益处理、科目映射说明。可保留"底稿"字样。
包含6部分:
- 合并报表预览 — 资产负债表+利润表关键数摘要
- 资产负债表合并底稿 — 一级科目 × 各机构 + 合计列 + 调整行(未结转损益/重分类/内部往来)
- 利润表合并底稿 — 损益一级科目 × 各机构
- 内部往来抵消与差额处理 — 1301/1302/2351 逐机构明细
- 损益汇总与未结转处理 — 收入/费用汇总、未分配利润勾稽
- 科目映射说明 — 口径差异列表
Step 6: 生成 HTML 财务分析报告(数据分析视角)
脚本:work/gen_html2.py
输出:财务分析报告-合并财务报表-N家.html
角色定位:纯数据分析——税务风险矩阵、税会勾稽框架、三表勾稽、结构/盈利/偿债/异常科目分析、综合结论(P0/P1/P2)。全文不得出现"底稿/合并底稿"字样(编制过程只记录在 Step 5 底稿中)。首章为"数据概览",强调"本节仅作数据呈现,结构占比/变动原因/风险在后续展开",并新增"结构—盈利—偿债—异常"四维分析总览叙述。
数据输入:report_values.json + normalized.json + extra.json
报告结构(6节):
- 财务报表概览 — 主要科目年初/期末/变动率
- 税务类分析 — 2.1 税务风险矩阵 + 2.2 税会勾稽框架
- 财务类分析 — 3.1 三表勾稽 / 3.2 结构分析 / 3.3 盈利能力 / 3.4 营运偿债 / 3.5 异常科目
- 综合结论与行动建议 — P0/P1/P2 优先级
- 附录 — 完整合并报表
关键指标算法:
- 毛利率 = (营收−成本) / 营收
- 净利率 = 净利润 / 营业收入
- 资产负债率 = 负债合计 / 资产总计
- 流动比率 = 流动资产 / 流动负债
- 速动比率 = (流动资产−存货) / 流动负债
- 应收周转天数 = 期末应收 / (营收/期间天数)
- 所得税实际税负 = 所得税费用 / 利润总额
- 年化利润 = 累计利润 / 月数 × 12
可配置参数
| 参数 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
| 工作目录 | HB_WORK | 技能目录/work | 含 xlsx_src 子目录 |
| 输出目录 | HB_OUT | 与用户源文件夹同级 | Excel + HTML 输出目标 |
| 报表日期 | HB_RPTDATE | 从源数据期间推断 | 如 "2026年07月31日" |
| 编制单位 | HB_PREP | "XX集团(合并)" | 报表左上角单位名 |
| 模板路径 | HB_TEMPLATE | 多级回退查找 | 强制指定模板文件 |
| 权益间隔行数 | HB_EQUITY_PADDING | 8 | 资产负债表"非流动负债合计"与"所有者权益"间的空白行数,用于左右对称排版;设 0 关闭 |
故障排查指南
常见问题与解决方案
| # | 症状 | 原因 | 解决方案 |
|---|---|---|---|
| 1 | 汇总后借贷差 ≠ 0 | 父子科目重复加总 | pipeline.py 已自动去叶;若仍有差,检查是否有非数字编码行混入 |
| 2 | 合并报表不平衡 | 未分配利润未含损益净额 / 重分类遗漏 | compute_report.py v5+ 已处理;检查应付职工薪酬借方余额是否重分类 |
| 3 | KeyError 模板单元格 | 模板格式与预期不同 | 用实际模板核对行号(make_excel.py 日志有写入了哪些单元格) |
| 4 | 列数据全为0 | 列映射错误(A-H vs B-J等) | v2 已自动检测表头;若仍出错,手动检查源文件第4行表头文本 |
| 5 | 中文乱码 | 文件编码非UTF-8 | 所有 .py/.json/.html 统一 UTF-8 无BOM |
| 6 | 模板找不到 | 路径不存在或文件名不同 | 设置 HB_TEMPLATE 环境变量指向正确模板;或放一份到桌面 |
防回归经验(本次实战已修复的关键 Bug)
| # | 现象 | 根因 | 固化措施 |
|---|---|---|---|
| B1 | 解析后所有机构=0 行 | col_map 结构为 {列字母: 字段},原代码用 col_map.get("code") 按键查找,但键是 "C" 不是 "code" → 返回空串 | 构建反向表 {字段: 列字母} 按字段名查列字母(pipeline.py 已实现) |
| B2 | 数据起始行错(把行7当数据) | 实际是双行表头:主表头行7(期初余额/本期发生/期末余额)+ 子表头行8(借方/贷方),数据行9。仅匹配"期初借"会漏掉"期初余额" | 表头关键词同时兼容"期初借/期初余额""本期借/本期发生";检测到表头后自动跳过紧跟的子表头行(pipeline.py 已实现) |
| B3 | 合并报表不平衡 | 父子科目重复加总 / 未分配利润未含损益净额 / 应付职工薪酬借方余额未重分类 | pipeline 叶子过滤 + compute_report 损益并入未分配利润 + 重分类逻辑(均已固化) |
| B4 | 用户重排样表后数值错位 | 手工重排改变单元格位置,且手填数值易错 | 用 make_excel_new.py 复用 report_values.json 经"旧→新"映射回填,禁止重算 |
| B5 | 重算合并数与已验证值偏差 | 重算口径细节遗漏(如 2181 其他应付款未并入、年初误加损益净额) | 以 report_values.json 为唯一真值源,下游填充一律引用,禁止重新聚合 |
关键校验清单(交付前逐条确认)
- [ ]
balances_data.json: 每机构期初/本期/期末净额 ≈ 0 - [ ]
agg.json: 汇总后三期借贷差 ≈ 0 - [ ]
report_values.json: 期末资产总计 = 负债+权益(差<0.01);年初同上 - [ ] 输出 xlsx: 可重新打开、数值正确、日期已更新
- [ ] HTML 报告: 标签配对闭合、无
{xxx}占位符残留、无乱码 - [ ] 净利润 = 未结转损益净额(精确匹配)
文件结构
技能目录/
├── SKILL.md # 本文档
├── work/
│ ├── pipeline.py # Step1+2: 解析→归一→汇总(Python主路径)
│ ├── compute_report.py # Step3: 计算合并报表数值
│ ├── make_excel.py # Step4: 生成Excel(标准模板)
│ ├── make_excel_new.py # Step4b: 用户重排样表变体(复用report_values回填)
│ ├── gen_html.py # Step5: 编制报告HTML
│ ├── gen_html2.py # Step6: 分析报告HTML
│ ├── xlsx_src/ # [运行时] 源xlsx存放处
│ ├── balances_data.json # [输出] 原始解析结果
│ ├── normalized.json # [输出] 归一化后逐机构数据
│ ├── agg.json # [输出] 汇总数据
│ └── report_values.json # [输出] 最终报表数值
└── templates/
│ ├── 合并会计报表-样表.xlsx # [可选] 会小企01/02模板
│ └── 财务分析报告样本_脱敏.html # 分析报告CSS/结构参考
版本历史
v2.1.0 (2026-08-28)
- 固化利润表取数规则:收入类取贷方发生额、成本费用类取借方发生额(经用户红笔核验,列为硬性规则)
- 新增 Step 4b 用户重排样表变体:make_excel_new.py 复用 report_values.json 经"旧→新"单元格映射回填,禁止在样表上重算
- HTML 报告命名与角色区分:编制底稿(
报表编制底稿-合并财务报表-N家.html,可含"底稿")= 过程记录;分析报告(财务分析报告-合并财务报表-N家.html,不含"底稿")= 纯数据分析 - 新增防回归经验表(B1-B5 关键 Bug 及固化措施)
- 新增可配置项
HB_EQUITY_PADDING(权益间隔行数,默认 8,左右对称排版) - HTML 脚本 N 动态化:机构数 N 与机构名列表均从 normalized.json 动态注入,不再写死"10家"
- 文档增强:双行表头识别、col_map 反向查找、report_values 唯一真值源 等实战经验写入故障排查与流程说明
- 移除 v1.0.0 遗留脚本:删除 scripts/ 下 6 个 PowerShell 备选脚本(.ps1)及文档中对应引用(备选路径段、目录结构图、编码表),统一以 Python(work/) 为主路径,消除死代码与文档不一致
v2.0.0 (2026-08-28)
- 重大修复: 列映射从硬编码 A-H 改为自动表头检测(实际为 B-J)
- 新增: 父子科目叶子节点过滤(解决重复计算导致不平衡)
- 新增: 应付职工薪酬借方余额重分类至其他应收款
- 新增: 模板多级回退查找(技能→桌面→内嵌)
- 增强: 机构数 N 动态检测(不再写死15/10家)
- 增强: 报表日期从源数据期间自动推断
- 环境更新: Python + openpyxl 为主路径,PS 为备选
- 文档重写: 新增故障排查指南、可配置参数表、校验清单
v1.0.0 (初始版)
- 基于 PowerShell 的完整实现
- 假设 A-H 列、15 家机构、固定模板路径
Scan to join WeChat group