版本变更记录
v1.0.2 (2026-08-19) — 应收账款脚本 FIFO 精确核销修复
针对 scripts/receivable_fifo_with_opening.py(工作流 D 应收账款方向)的两类致命 bug 修复,并增强金额解析健壮性:
-
项目号前缀笔误(JTEC ↔ JETC):挂账
JTEC-2026-0028(借 59,280)与入账JETC-2026-0028(贷 59,280)仅差一个字母 E,原按项目号精确核销的精确字符串匹配失败 → 59,280 元错误挂账未被抵消,虚增应收。- 修复:
extract_project_code现归一化JTEC→JETC(仅去多余 E,不合并 DLJS/JYFZ/STZX 等真实不同业务单位;项目号流水号如2024-006亦不唯一,严禁仅按流水号合并)。
- 修复:
-
反向凭证(调整/红冲)日期栅栏:
JETC-JYFZ-2024-022的「入账 603,961.73(早)→ 调整 603,961.73(晚、同金额)」本应互抵为 0,但原逻辑仅允许“贷方日期 ≥ 借方日期”配对,该贷方无法匹配晚于它的借方而被漏进全局 FIFO,错误吃掉其他项目的借方层(例:东部公司2025项目 434,059.73、ZNYH-2025-024 169,902)。- 修复:Step 3c 项目号配对后新增反向凭证互抵——对剩余借方(晚于同金额贷方)与剩余贷方抵消,处理“调整/红冲某笔入账”类。
-
金额解析健壮性:
parse_amt新增会计括号负数格式(1,500,000.00)→-1500000的解析(NC 部分导出用括号表负数)。
验证:江苏交通控股期末应收由错误值修正为 10,498,703.70(未结清行 10→9 笔,59,280 与 603,961.73 两行已消除);其余 33 家客商完全不变;全局总合计仍精确勾稽 85,724,855.87(= NC 明细账末行合并余额)。经逐户权威借贷勾稽(期初+真实借−真实贷),34 家 Sheet 借合计与 NC 完全一致,41 家零净额客商正确不列示。
注:本 skill 的「简化 FIFO」(工作流 A/B/C 单客商/应付账款脚本)刻意不做跨凭证精确匹配与凭证内轧差,与应收账款脚本的「凭证内配对 + 项目号精确核销」是两种不同的设计取舍,请按工作流说明选用对应脚本。
NC 账龄分析 → Excel 自动输出
Overview
从用友NC明细账数据(截图或 .xls 导出文件)中提取交易数据,按 FIFO 法计算账龄,输出标准8列明细表,并自动写入/追加到 22410103_账龄汇总表.xlsx。
⚠️ FIFO算法说明:脚本采用简化FIFO处理NC辅助明细账中的复杂分录:
- 负值翻转:贷方负数→借(取绝对值),借方负数→贷(取绝对值)。不做凭证内轧差——同一凭证号下的借贷分录可能是不同经济事项,不应互相抵消
- 简化FIFO:所有贷方层(含期初余额)按时间排序,借方按时间顺序从最早的贷方层开始逐层消耗。不做跨凭证金额匹配配对,不做早于最早贷方的借方剔除
- 期初余额处理:单客商明细账(新格式)中读取期初余额作为最早的贷方层;多客商旧格式不包含客商级别的期初余额,仅有期间净流入的客户才能进行FIFO分析
负值翻转规则:
- 贷方为负数(如
-280,000)→ 翻转为借方(取绝对值),表示冲销/减少负债 - 借方为负数 → 翻转为贷方(取绝对值),表示冲销/减少支付
为什么不做凭证内轧差(适用 fifo_with_opening.py / 单客商与应付账款场景):同一凭证号下借3,825,000(支付)和贷1,510,000(确认应付)是不同经济事项,轧差会错误匹配。注:多客商应收账款脚本 receivable_fifo_with_opening.py 已增加「同凭证号内同金额借贷配对抵消」逻辑,专门处理复合凭证(如同时挂应收+收现+冲合同负债),详见工作流 D 脚本选择说明。
为什么负值翻转未配对的视为期初调整:冲销分录(如"冲21年12月639#")对应的原始分录在文件范围外,不应参与FIFO消耗文件内的贷方层。
输出格式规范
8 列表头:
| 序号 | 业务日期 | 摘要 | 往来单位 | 金额(元) | 方向 | 科目 | 账龄 |
规则:
- 科目填科目编码(如
22410103),方向填「借」或「贷」 - 金额使用
#,##0.00格式,右对齐;其他列左对齐 - 表头行冻结(冻结至第4行),合计行使用
SUM公式 - 基准日 = 当天日期
- 账龄标签:
1年以内/1-2年/2-3年/3年以上 - 明细不合并:每笔剩余贷方余额层占一行,保留原始日期、凭证号、摘要
工作流 A:.xls 辅助明细账分析(FIFO 法)
适用于用户提供 NC 辅助明细账导出的 .xls 文件。
Step A1: 运行 FIFO 分析脚本
python scripts/fifo_aging_analysis.py <xls_path> \
--account-code 22410103 \
--base-date 2026-07-23 \
--output <result.json>
参数:
--account-code:科目编码,默认22410103--base-date:账龄基准日,默认当天(格式YYYY-MM-DD)--output:JSON 结果输出路径--counterparty:手动覆盖往来单位(自动从文件识别)
输出 JSON 结构:
{
"counterparty": "南京感动科技股份有限公司",
"account_code": "22410103",
"total_debit": 65717574.29,
"total_credit": 67160087.79,
"ending_balance": 1462513.50,
"layers": [
{
"date": "2024-12-31",
"voucher": "记-0734",
"summary": "项目验收,结转无形资产(质保金3%挂账)",
"amount": 778162.40,
"direction": "贷",
"aging": "1-2年"
}
],
"aging_check": { "layer_sum": 1462513.50, "match": true }
}
Step A2: 简化 FIFO 方法论
脚本使用简化FIFO计算每笔余额的构成明细:
Step 1 — 负值翻转(不做凭证内轧差):
- 所有分录逐一处理:贷方负数→借方(取绝对值),借方负数→贷方(取绝对值)
- 正数借贷保持不变
- 不做凭证内轧差:同一凭证号下借3,825,000(支付)和贷1,510,000(确认应付)可能是不同经济事项,不应互相抵消
Step 2 — 简化 FIFO(不做跨凭证匹配 + 不做期初剔除):
- 所有贷方层按日期排序(含期初余额作为最早的贷方层)
- 所有借方按日期排序
- 借方从最早的贷方层开始逐层FIFO消耗
- 不做跨凭证金额精确匹配:同金额借贷配对会导致同一凭证号下的不同经济事项被错误抵消(如记-0244贷92,530↔借92,530为确认应付+支付,应各自独立参与FIFO)
- 不做早于最早贷方的借方剔除:早期借方应消耗期初余额而非直接剔除(如借475,300应消耗期初509,290而非被剔除)
- 未被消耗的贷方层 = 期末余额构成明细
为什么使用简化 FIFO:
- 三遍法的跨凭证匹配在大量审定调整和同凭证双向分录场景下,会将不同经济事项错误配对,导致层合计≠期末余额
- 简化FIFO数学上更可靠,层合计始终与期末余额精确匹配
- 期初余额作为最早的贷方层,是正确FIFO的必要条件
Step A3: 生成内联预览
读取 JSON 中的 layers 和 aging_check,使用 show_widget 生成账龄分布图(饼图/环形图)和明细表格预览。
验证 aging_check.match == true 后展示结果。
Step A4: 追加或重建 Excel
场景 1 — 新增客商:将分析结果行追加到现有表格末尾,更新 SUM 公式。
场景 2 — 已有此客商记录:用 scripts/rebuild_aging_table.py 重建整个表格(将所有客商的最新分析结果合并输出)。
追加单行使用:
python scripts/append_to_aging_table.py \
"<xlsx_path>" "<序号>" "<业务日期>" "<摘要>" \
"<往来单位>" "<金额>" "<方向>" "<科目>" "<账龄>"
重建全表使用:
python scripts/rebuild_aging_table.py <manifest.json> <output.xlsx> \
--base-date 2026-07-23
Manifest.json 格式见该脚本的文档注释。
工作流 B:截图分析(手动录入)
适用于用户提供 NC 明细账截图(通常是 2241 系列"其他应付款"科目蓝底明细账界面)。
Step B1: 读取截图
使用 Read 工具读取截图。截图内容通常包含:
- 顶部:科目编码 + 科目名称、客商名称
- 格子区:日期、凭证号、摘要、借方、贷方、方向、余额
- 底部:当前合计、累计合计
Step B2: 提取数据
从截图中提取:
- 科目编码:从顶部标题行或筛选条件读取
- 往来单位:从客户名称/筛选条件读取
- 期末余额:底部「当前合计」行的余额值
- 方向:底部「当前合计」行的方向
- 业务日期:最后一笔业务记录的日期
- 摘要:简要概括形成余额的业务内容
Step B3: 计算账龄
date +%Y-%m-%d
根据业务日期和今天的差值归类账龄区间。
Step B4: 内联预览
使用 show_widget 生成预览表格。
Step B5: 追加到 Excel
调用 append_to_aging_table.py(同 Step A4 场景1)。
脚本清单
| 脚本 | 用途 |
|------|------|
| scripts/fifo_aging_analysis.py | 解析单客商 .xls(新格式含期初余额)→ 简化 FIFO → JSON |
| scripts/fifo_with_opening.py | 旧格式多客商 .xls + 辅助余额表 → 含期初余额的简化FIFO → 完整Excel |
| scripts/aging_detail_v3.py | 新格式多客商批量 FIFO 分析(行946起双格式混排 .xls)→ 完整 Excel |
| scripts/yangzi_bridge_aging.py | 旧格式多客商批量 FIFO 分析(无期初余额)→ 完整 Excel |
| scripts/append_to_aging_table.py | 追加单行到现有 Excel |
| scripts/rebuild_aging_table.py | 从 manifest 重建完整 Excel 明细表 |
| scripts/receivable_fifo_with_opening.py | 多客商应收账款 FIFO(含期初余额表 + 凭证内配对):先按(客商+凭证号)配对抵消同金额借贷,剩余走 FIFO;修复复合凭证虚增应收余额 |
| scripts/package_and_align.py | 发布工具:把源 skill 与市场克隆版对齐(保留 _icon.png/_meta.json 等)、升版本号、打成可上传 SkillHub 的 zip,并自检 zip 内版本与修复脚本。--bump patch 升版,--no-align 仅打包,--out 指定路径 |
.xls 文件格式说明
NC 辅助明细账 .xls 导出可能包含两种数据格式混排:
格式一:旧格式(单年度,行11-945)
- Row 8-9 表头:年 | 年 | 科目名称 | 客商名称 | 凭证号 | 摘要 | 对方科目 | 借方 | 贷方 | 方向 | 余额
- Col0=月份(1-12),Col1=日期,年份默认为表头期间
- 列映射:Col2=科目, Col3=客商, Col4=凭证号, Col5=摘要, Col6=对方科目, Col7=借方, Col8=贷方, Col9=方向, Col10=余额
格式二:新格式(多年度,行946起)
- Row 8-9 表头:年 | 年 | 科目名称 | 客商名称 | 凭证号 | 摘要 | 对方科目 | 借方 | 贷方 | 方向 | 余额
- Col0=4位年份(如2022),Col1=月份,Col2=日期
- 列映射:Col3=科目, Col4=客商, Col5=凭证号, Col6=摘要, Col7=对方科目, Col8=借方, Col9=贷方, Col10=方向, Col11=余额
格式判断方法
if len(Col0) >= 4 and 2000 <= int(Col0) <= 2099:
→ 新格式(Col0=年, Col1=月, Col2=日)
elif 1 <= int(Col0) <= 12:
→ 旧格式(Col0=月, Col1=日)
关键差异
| 项目 | 旧格式 | 新格式 | |------|--------|--------| | 数据范围 | 单年度(2026) | 多年度(2022-2026) | | 客商列 | Col3 | Col4 | | 借方列 | Col7 | Col8 | | 贷方列 | Col8 | Col9 | | 余额列 | Col10 | Col11 |
负值金额(审定调整/冲销分录)—— 必须处理
NC导出的审定调整和冲销常以负值金额呈现,格式特征:
- 贷方负值:如
- 165,934.32(负号后有空格),表示冲销/减少贷方余额 → 必须翻转为借方(取绝对值) - 借方负值:如
- 55,528.58,表示冲销/减少借方余额 → 必须翻转为贷方(取绝对值) - 同一凭证双负值:同一凭证号可能同时出现贷方负值和借方负值(如退款冲销),代表不同经济事项。Pass 1 凭证内轧差正确处理这种情况
为什么不能忽略负值:
- 忽略负贷方=1,500,000 → 漏记冲销分录,余额多算1,500,000
- 正确翻转后:借1,500,000与贷1,500,000暂估在简化FIFO中正确消耗,余额精确
解析方式:所有金额用 float(s.replace(",","").replace(" ","")) 解析,保留正负号,然后在负值翻转步骤中判断方向进行翻转。
其他格式特征
- 金额含逗号(如
165,934.32)、负号带空格(如- 165,934.32),统一用s.replace(",","").replace(" ","")解析 - 汇合行:
本月合计/本年累计行自动跳过 - 跨年度时新格式通过 Col0 年份列自动切换,旧格式通过"期初"行推断
工作流 C:多客商批量FIFO分析(双格式混排.xls)
适用于用户提供 NC 辅助明细账导出的 .xls 文件(含多个客商、多个年份的数据)。
典型场景
用户说"按往来单位分别进行账龄分析"、"分客商做账龄"、"按客商名称分析"——上传的 .xls 文件通常为 NC 系统导出的双格式混排文件,包含两种数据格式:
| 格式 | 位置 | Col0 | 覆盖年份 | 特征 | |------|------|------|---------|------| | 旧格式 | 行11-945 | 月份(1-12) | 2026.01-2026.07 | Col2=科目 Col3=客商 Col7=借方 Col8=贷方 | | 新格式 | 行946起 | 4位年份(2022) | 2022.01-2026.07 | Col3=科目 Col4=客商 Col8=借方 Col9=贷方 |
关键判断:新格式段覆盖完整时间范围(2022-2026.07),旧格式段是新格式段中2026年数据的子集。只解析新格式段(946行起),跳过旧格式段,无需做跨格式去重。
Step C1: 解析全量数据
用 Python 读取 .xls 新格式段(从约第946行到页脚前3行),按如下列映射提取:
Col0=年, Col1=月, Col2=日 → date_str = f"{year}-{month:02d}-{day:02d}"
Col4=客商名称, Col5=凭证号, Col6=摘要
Col8=借方金额, Col9=贷方金额
关键规则:
- 不做内部去重:同一凭证号下可能存在金额相同的不同经济事项(如记-0550两笔15k贷方分属不同项目),用(counterparty, date, voucher, amount)去重会误删合法数据
- 跳过"期初"、"本月合计"、"本年累计"等汇总行
- 金额含逗号、负号带空格等格式统一用
float(s.replace(",","").replace(" ",""))解析
Step C2: 逐客商简化FIFO计算
对每家客商独立执行简化FIFO(不做跨凭证匹配、不做期初剔除):
Step 1 — 负值翻转(不做凭证内轧差):
- 所有分录逐一处理:贷方负数→借方(取绝对值),借方负数→贷方(取绝对值)
- 正数借贷保持不变,不做凭证内借贷抵消
Step 2 — 简化 FIFO:
- 所有贷方层按日期排序
- 所有借方按日期排序
- 借方从最早的贷方层开始逐层FIFO消耗
- 不做跨凭证金额精确匹配:同金额借贷配对会导致不同经济事项被错误抵消
- 不做早于最早贷方的借方剔除:早期借方应消耗期初余额而非剔除
- 未被消耗的贷方层 = 期末余额的FIFO构成明细
输出结构(JSON/dict):
{
"cp": "南京感动科技股份有限公司",
"total_credit": 67287577.79,
"total_debit": 65675064.29,
"net": 1612513.50, # 期末余额
"detail": [ # Pass 3 FIFO剩余层
{"date": "2025-12-31", "vouch": "记-0457", "summary": "...", "amount": 257223.50, "aging": "1年以内"},
...
],
"aging": {"1年以内": 9501824.85, "2-3年": 39037828.40}
}
Step C3: 分类处理
根据简化FIFO后的净额方向区分:
| 类别 | 条件 | 处理 | |------|------|------| | 贷方余额(正常挂账) | net > 0.01 | 主分析对象,展示FIFO剩余层明细 | | 借方余额(期初消耗) | net < -0.01 | 本期支付>新增负债,差额来自期初余额。单独列表说明 | | 已结清 | |net| ≤ 0.01 | 不展开分析 |
Step C4: 生成Excel输出
生成包含以下Sheet的结构化文件:
- 往来单位总览 — 所有贷方余额单位一览表(含各账龄区间金额、明细笔数、链接到明细页)
- 借方余额消耗期初 — 借方余额单位列表(含净支付额和说明)
- 长账龄预警 — 2年以上未结清项逐笔明细(重点关注)
- 每家单位独立分析页 — 每家贷方余额单位一个Sheet,包含:
- ▎账龄分布(金额、占比、笔数、颜色标记)
- ▎FIFO余额构成明细(逐笔列示:序号、业务日期、凭证号、摘要、金额、方向、科目、账龄)
- 全部FIFO明细 — 所有未结清层一览
输出格式规范:
- 金额
#,##0.00右对齐,其他列左对齐 - 账龄颜色标记:🟢1年以内(绿) 🟡1-2年(黄) 🟠2-3年(橙) 🔴3年以上(红)
- 表头行冻结
- 每家单位Sheet名使用客商简称(≤25字符,去除特殊字符)
Step C5: 输出文件命名
{科目编码}_账龄_按往来单位分析.xlsx
如 22410103_账龄_按往来单位分析.xlsx
重要注意事项
- 必须使用新格式段:NC导出的双格式混排文件,新格式段(946行起)覆盖2022-2026完整范围,旧格式段(11-945行)仅2026年数据是其子集,直接跳过
- 禁止内部去重:同一凭证号下金额相同的多笔交易可能是不同经济事项(不同项目尾款、不同合同质保金等),不应去重
- 负值必须翻转:贷方负数→借方(取绝对值),借方负数→贷方(取绝对值)。忽略负值会导致冲销分录遗漏、余额计算严重错误
- 不做凭证内轧差:同一凭证号下的借和贷可能是不同经济事项(如借3,825,000支付+贷1,510,000确认应付),不应互相抵消。仅做逐条负值翻转
- 不做跨凭证金额匹配:同金额借贷配对(如Pass 1)会错误消除合法贷方层(如记-0244贷92,530↔借92,530视为不同事项各自独立参与FIFO)
- 不做期初剔除:早于最早贷方的借方不应被剔除,而应在简化FIFO中消耗期初余额(或消耗最早贷方层)
工作流 D:含期初余额的多客商 FIFO 分析
适用于旧格式汇总明细账(Col0=月份,多客商混排)+ 辅助余额表(提供各客商期初余额)。
脚本选择:
- 应付账款 / 其他应付款方向(如 22020109)→
scripts/fifo_with_opening.py(简化 FIFO,不做凭证内配对)- 应收账款方向(如 1122 系列)→
scripts/receivable_fifo_with_opening.py:在简化 FIFO 基础上增加凭证内配对——先按(客商+凭证号)将同金额借贷配对抵消,剩余再走 FIFO。用于正确处理复合凭证(同一凭证同时挂应收+收现+冲合同负债),避免应收余额被虚增。v1.0.2 修复即针对此脚本(见下“版本变更记录”)。
场景
用户上传两个文件:
- NC 辅助明细账 .xls(旧格式,含多客商2022.07-2026.06交易)
- 辅助余额表 .xls(覆盖2022.01-06,含各客商期初余额)
两者结合才能得到正确的各客商期末余额和账龄构成。
Step D1: 运行含期初余额的 FIFO 分析脚本
python scripts/fifo_with_opening.py <xls_path> <balance_xls_path> \
--account-code 22020109 \
--account-name "应付账款" \
--entity "沪通大桥" \
--base-date 2026-08-10 \
--output output.xlsx
参数:
xls_path:NC辅助明细账 .xls 路径(旧格式,Col0=月份)balance_xls_path:辅助余额表 .xls 路径(含各客商期末余额,用作期初余额)--account-code:科目编码,默认22020109--account-name:科目名称,默认应付账款(用于标题与明细「科目」列旁的说明)--entity:项目/主体名称(如沪通大桥、扬子大桥),仅用于标题显示,留空则不显示--base-date:账龄基准日,默认当天--output, -o:输出 Excel 路径--period-start:期间起始年份,默认2022--period-label:期间文字(如2022.07-2026.06);留空自动从明细账表头第6行读取
注意:脚本已去除标题与明细列中写死的「22020109」「扬子大桥」,全部改由参数驱动。切换科目/项目时必须显式传
--account-code与--entity,否则标题会沿用默认值。
期初余额表列识别:脚本从第 8/9 行表头动态定位「方向」列与最后一个「本币」列,兼容 6 列精简版(摘要/客商名称/币种/方向/原币/本币)与多列完整版。合计行客商名为空,会被自动跳过。
Step D2: 期初余额匹配规则
脚本自动从辅助余额表中提取各客商的"期末余额"作为期初:
| 期末方向 | 处理方式 | |:-------:|---------| | 贷 | 作为该客商最早的贷方层(负债转入),参与简化FIFO | | 借 | 作为该客商最早的借方层(预付转入),参与简化FIFO | | 平 | 期初为0,不处理 |
期初余额日期设为该客商第一笔交易日期,确保FIFO顺序正确。
Step D3: 验证结果
检查输出的 合计金额 是否等于明细账最后一行的余额值。如相等则说明期初余额匹配正确。
脚本清单
| 脚本 | 用途 |
|------|------|
| scripts/fifo_aging_analysis.py | 解析单客商 .xls(新格式含期初余额)→ 简化 FIFO → JSON |
| scripts/fifo_with_opening.py | 旧格式多客商 .xls + 辅助余额表 → 含期初余额的简化FIFO → 完整Excel |
| scripts/aging_detail_v3.py | 新格式多客商批量 FIFO 分析(行946起双格式混排 .xls)→ 完整 Excel |
| scripts/yangzi_bridge_aging.py | 旧格式多客商批量 FIFO 分析(无期初余额)→ 完整 Excel |
| scripts/append_to_aging_table.py | 追加单行到现有 Excel |
| scripts/rebuild_aging_table.py | 从 manifest 重建完整 Excel 明细表 |
| scripts/receivable_fifo_with_opening.py | 多客商应收账款 FIFO(含期初余额表 + 凭证内配对):先按(客商+凭证号)配对抵消同金额借贷,剩余走 FIFO;修复复合凭证虚增应收余额 |
| scripts/package_and_align.py | 发布工具:把源 skill 与市场克隆版对齐(保留 _icon.png/_meta.json 等)、升版本号、打成可上传 SkillHub 的 zip,并自检 zip 内版本与修复脚本。--bump patch 升版,--no-align 仅打包,--out 指定路径 |
微信扫一扫