# Ecom Receipt Ledger

> 手写单据电子化台账技能。把手机拍的手写采购单/销售单照片，经多模态识别转成结构化明细：字迹潦草时按多遍读法加固（骨架/逐行/交叉复核/价格库校准），读不准的字段给候选值并生成补拍指令而不是硬猜；再做手写简写标准化映射（如「14pm改17pm」「15DD屏幕」「XR」→ 标准品名）、单价与历史价格库核对、数量×单价自动算账与差异标红、采购/销售按天按月的日结汇总与净收益对账，并把原始单据照片作为可点击超链接与缩略图钉回每一行数据。涉及「手写单据录入」「拍照记账」「存根簿电子化」「字迹太潦草识别不准」「每日采购销售对账」「闭店对账」「单据照片和表格关联」「简写看不懂/对不上」这类请求时使用。

- Skill: `xianglouw/ecom-receipt-ledger` (Agent Skill, multi-file: 21 files)
- Install (CLI): `npx skillmds@latest add xianglouw/ecom-receipt-ledger`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xianglouw/ecom-receipt-ledger/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: xianglouw (https://skillmd.com/u/xianglouw)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/xianglouw/ecom-receipt-ledger

---


# 阶段 2B · 手写单据电子化台账

给「纸质存根簿 + 手写单据」的门店与档口场景：一天几十张手写单，闭店后要逐笔敲进 Excel，`数量×单价` 算错、当日总计对不上、简写看不懂、查账要翻原始凭证。

本技能把这条链路做成四步闭环：

```text
拍照 → 潦草字迹加固识别（候选值/置信度/补拍指令）→ 简写标准化 → 价格库核对与自动算账 → 采购/销售日结 → 凭证回链
```

**边界：OCR 由多模态模型完成，本技能的脚本不做图像识别。** 脚本负责识别之后的所有确定性工作：字段归一、简写映射、价格核对、算账校验、日结汇总、凭证关联与台账导出。识别质量靠 [references/ocr-playbook.md](references/ocr-playbook.md)（拍照规范 + 两遍读法提示词）与 [references/handwriting-hardening.md](references/handwriting-hardening.md)（潦草字迹加固手册）保证。

**核心原则：认不准不入账。** 字段读不准就给候选值、置信度低于底线就隔离——错一笔进账，闭店后要翻半天才能找回来。

## 输入

| 输入 | 说明 |
|---|---|
| 单据识别结果表 | `.csv` / `.xlsx`，字段见 [references/field-schema.md](references/field-schema.md)：日期 / 业务方向 / 单据号 / 手写原文 / 规格 / 数量 / 单价 / 手写金额 / 凭证照片 / 识别置信度 |
| 简写映射表（`--alias`） | `.csv`：`简写,标准品名,类别,规格`，起步词表见 [references/alias-dictionary.md](references/alias-dictionary.md) |
| 历史价格库（`--price-ref`，可选） | `.csv`：`品名,业务方向,参考单价,下限,上限`；有则逐行核对单价偏离，只标不改 |
| 凭证照片目录（`--photos-dir`） | 原图按文件名归档；表里只写文件名，脚本自动拼路径 |
| 云端凭证地址（`--photos-base`） | 照片存在对象存储/网盘时，超链接直接指向云端 |

识别结果表由 Agent 按字段契约从照片批量提取；**提取时识别不出的字段写 `unknown` 或留空，不许猜**。

## 怎么跑

```bash
# 1) 只要有映射表和照片目录，一条命令出全套台账
python3 scripts/receipt_ledger.py 单据明细.csv --alias alias_map.csv \
  --price-ref price_ref.csv \
  --photos-dir photos --embed-photos --default-year 2026 \
  --out out/ledger.csv --out-xlsx out/ledger.xlsx --out-md out/ledger.md \
  --out-json out/ledger.json --quarantine out/bad_rows.csv

# 2) 表头不是标准名时手工指定，或把照片链接指向云端
python3 scripts/receipt_ledger.py 8月单据.xlsx --sheet 明细 --header-row 2 \
  --map 手写品名=item_raw --map 业务=业务方向 \
  --photos-base https://cdn.example.com/receipts/2026-09 --out-xlsx out/8月台账.xlsx

# 3) 先不嵌缩略图，只要轻量台账（一个手机相册几千张图时更快）
python3 scripts/receipt_ledger.py 单据明细.csv --alias alias_map.csv --photos-dir photos --out-xlsx out/台账.xlsx

# 4) 单据字迹差、想更严一点：底线提到 0.7，低于它的行一律不进日结
python3 scripts/receipt_ledger.py 单据明细.csv --alias alias_map.csv \
  --confidence-floor 0.7 --out-xlsx out/台账.xlsx --quarantine out/待补拍.csv
```

`--out-xlsx` 一次给八张工作表：**单据明细（关键格带底色）/ 日结 / 月结 / 异常行 / 待映射简写 / 补拍清单 / 价格核对 / 凭证索引**（没有内容的表不会写出）。示例数据与样张见 `examples/`（8 张示例单据照片 + 示例价格库 `price_ref.csv`）。

## 五件事怎么做

### 1. 手写简写标准化（不猜）

手写单里的缩写有两种：**型号代称**（`14pm改17pm`、`XR`、`8P`）和**零件行话**（`15DD屏幕`、`后摄总成`）。脚本按下述顺序处理：

1. 整串精确匹配映射表（归一化后比较：大小写、全角半角、空格差异自动忽略，`XR 电池` 与 `XR电池` 视为同一个键）；
2. 精确匹配不到时按最长子串匹配，处理「`14pm改17pm 后壳`」这类带后缀的写法；
3. 仍然匹配不上的一律**标 `未映射` 并进「待映射简写」工作表**，不猜测、不硬塞一个近似标准名——猜错会污染后续盘点与毛利统计。

映射表是团队资产：每次「待映射」清单出来就往回补，几轮之后命中率能到 95% 以上。

### 2. 潦草字迹加固与「认不准不入账」

字迹潦草的失效方式不止「看不清」一种：数字连笔被脑补、行与行串位、划掉的行被吞掉、单价列与金额列错位。处理办法是**分层拦截**，而不是让模型硬读一遍就出表：

| 分层 | 干什么 | 结果 |
|---|---|---|
| 多遍读法 | 骨架（几行、行号、方向、圈号）→ 逐行（四个关键格）→ 交叉复核（换读法再读一遍） | 两遍一致的字段才配高置信度 |
| 候选值 | 读不准的字段给 2–3 个候选写法（写在 `candidates` 列） | **该行不进日结**，进补拍清单 |
| 置信度底线 | `--confidence-floor`（默认 0.6）低于底线的行 | **不进日结**，进隔离清单与补拍清单 |
| 置信度告警线 | `--low-confidence`（默认 0.75）低于告警线的行 | 入账但标黄、进异常行与补拍清单 |
| 补拍指令 | 按照片聚合「哪一行、哪一格、怎么拍」 | 一次补拍解决一张单据上的所有未决项 |

完整方法与难点样例见 [references/handwriting-hardening.md](references/handwriting-hardening.md)。**这条链路的产出不是「一份看起来完整的表」，而是「一份知道哪几格还没读准的表」。**

### 3. 价格库核对与自动算账

系统金额 = 数量 × 单价，与单据上写的金额逐笔比对，分四档：

| 校验状态 | 判定条件 | 处理 |
|---|---|---|
| 一致 | 差异 ≤ `--tolerance`（默认 0.01） | 直接入账 |
| 小额差异 | 差异 ≤ max(1 元, 系统金额的 1%) | 入账，标注（抹零、四舍五入级） |
| 金额不符 | 超过上面两档 | **标红进「异常行」，必须人工看原单** |
| 金额缺失 | 单据没写金额 | 按 数量×单价 补齐并入账，标注待抽查 |
| 无法复核 | 缺数量或单价，且单据没写金额 | 不进账，退回补录 |

单价或数量缺失时**不要用同类单据的均价去填**——手写单的价格差异往往就是重点（换型号、清库存、拆机件）。

另有历史价格库（`--price-ref`）可选核对，三种结果：命中区间（把握度上调）、偏离区间（标「疑似识别错位」，回看原图）、库里没有（未收录）。**价格库只用来怀疑、不用来改写**：偏离也可能是行情变了。顺带检出两类高频错位——数量与单价写反（单价 ≤ 10 而数量 ≥ 100）、单价列抄成了金额（金额与单价同值且数量大于 1）。

### 4. 采购/销售日结

按「日期 × 业务方向」归集，产出每天采购金额、销售金额、净收益、净收益率、差异笔数、待复核笔数、凭证数；月结表同理按 `YYYY-MM` 归集。

方向写法自动归一：采购 / 进货 / 入库 / 应付 / purchase → **采购**；销售 / 出货 / 出库 / 应收 / sale → **销售**。两边的词都认不出来（比如空着）的行走隔离清单，**不默认归到采购**——方向错了会让净收益直接反向。日结 SOP 见 [references/daily-close-sop.md](references/daily-close-sop.md)。

### 5. 凭证回链（原始照片与数据行绑定）

| 做法 | 参数 | 效果 |
|---|---|---|
| 可点击超链接 | 默认开启 | 「凭证」列点一下直接打开原图（`file://` 或 `--photos-base` 的云端地址） |
| 缩略图内嵌 | `--embed-photos` | 「凭证索引」工作表里每行右边就是那张单据的缩略图，翻表等于翻凭证 |
| 原图归档 | `--photos-dir` | 原图按文件名统一归档，表里存相对路径，换机器也能重新挂上 |

缩略图用系统图像工具生成（macOS 自带 `sips`，顺手把 iPhone 的 HEIC 转成 JPG）；系统没有该工具时，小于 300KB 的原图直接嵌入，否则跳过并在 `flags` 里记一笔，不静默失败。

## 风险与人工边界

| 等级 | 本技能场景 | AI 权限 | 人工权限 |
|---|---|---|---|
| 高 | 金额不符、无法复核、方向判不出、隔离比例 > 20%、需要补拍的行超过三成 | 算差异 + 标红 + 隔离 + 出补拍清单 | 回看原始单据，确认识别错还是单子本身错；决定补拍还是人工录入 |
| 中 | 简写未映射、单据未写金额、识别置信度偏低、字段带候选值、单价偏离价格库、凭证缺照片、疑似重复行 | 出清单与建议（含按照片聚合的补拍指令） | 补映射表、补照片、确认重复、复核偏离单价 |
| 低 | 日期补年份、方向写法归一、金额精度统一、日结汇总 | 直接执行 | 事后抽查 |

**不猜数据、不静默丢行、不把没读准的格子当成读准了。** 算不了的进隔离清单，没读准的进补拍清单，映射不了的在待映射表里列出来，缺照片的标出来——每一笔都有交代。

## 输出契约

与其他跨境电商技能共用同一个 JSON 信封：

```json
{
  "task": "receipt_ledger",
  "status": "ok | partial | blocked",
  "confidence": 0.0,
  "data": {},
  "flags": [{ "level": "high | medium | low", "type": "", "detail": "", "action": "" }],
  "need_human_review": false,
  "sources": [{ "ref": "", "as_of": "" }],
  "assumptions": [],
  "audit": { "snapshot_at": "" }
}
```

- `data` 关键字段：`purchase` / `sales` / `net` / `net_margin`、`calc_check`（一致/小额差异/金额不符/无法复核笔数与差异合计）、`alias`（命中率与 top 未映射）、`photos`（linked/missing）、`price_check`（参考价命中/偏离/未收录与容差）、`confidence`（告警线、底线、低置信笔数、带候选值笔数）、`reshoot`（需补拍行数与涉及照片数）、`daily`（逐日采销与净收益）。
- 有 `high` 级 flag → `need_human_review` 必为 `true`；`confidence`：有 high ≤ 0.7、有 medium ≤ 0.85、有隔离行 ≤ 0.9，上限 0.95。

## 交付表格

**要台账就给文件。** 参数与其他阶段一致：

| 参数 | 产物 | 说明 |
|---|---|---|
| `--out` | 明细 CSV | UTF-8 BOM，Excel 双击不乱码 |
| `--out-xlsx` | Excel 工作簿 | 八张工作表，表头加粗冻结首行、数字可求和；单据明细里黄底=要复核、红底=异常或没读准；凭证索引含缩略图 |
| `--out-md` | 对账报告 | 总账 / 日结 / 校验 / 待确认清单 / 待映射 / 隔离行 / 口径假设 |
| `--quarantine` | 隔离行 CSV | 没进日结的行与原因 |
| `--out-json` | JSON 信封 | 给下游脚本、工单系统读 |

## 常见坑

- **一张单据多行明细**：同一张照片会出现在多行，凭证索引里正常；日结汇总按行算，不按照片算。
- **字迹潦草**：别把「识别出来了」当成「读准了」。字段带候选值、或置信度低于 `--confidence-floor`（默认 0.6）的行**不会进日结**，会进补拍清单——这是设计如此，不是报错。
- **一笔都没读准时**：脚本不会只丢一句「全部隔离」就走人。状态标 `blocked`（零笔入账），但明细/日结/补拍清单照样写出，先看补拍清单要重拍哪几张，或看隔离原因里是不是日期、采购/销售方向这两列没认出来。
- **单价看着离谱**：接一份 `--price-ref` 历史价格库，偏离行会被标出来；价格库只用来怀疑、不用来改写，偏离也可能是行情变了。
- **数量与单价写反**：单价 ≤ 10 而数量 ≥ 100 的行走会被自动标记，别当成正常单子入账。
- **重复录入**：连拍两次同一张单子，会产生完全相同的两行；脚本标「疑似重复」但**不自动删**，因为同一天真的可能卖出两台一样的机器。
- **日期只有月日**（`9.5`、`9月5日`）：按 `--default-year` 补年份，跨年归档时务必把年份传对。
- **手写金额与合计不一致**：单子上逐行金额加起来不等于「合计」时，先修明细行，别拿合计去倒推。
- **拆分单据**：采购与销售写在同一张纸上时，拆成两行录入，方向分别填，不要一行混着记。
- **HEIC 照片**：iPhone 默认 HEIC，`--embed-photos` 会转 JPG；不开缩略图时超链接指向原文件同样能打开。

## 作业习惯

- 先要数据再下结论；能算就不要估。
- 结论固定附「支撑数据 + 判定规则 + 边界/反例」三段。
- 每天闭店后先跑一次日结，差异行**当天**回看原单——隔天再找单据成本翻倍。
- 字迹差的行**一次补拍解决完**：按「补拍清单」按照片逐张重拍，别一边跑一边零散补；需要特写的行超过 5 行，整张重拍更快。
- 补拍清单**一行一个待办**：同一张照片有几行没读准就写几行，方便拿着手机逐条拍、逐条销。
- 术语保留英文缩写（SKU、PO、OCR），其余用中文。

## 上下游

- 上游：[`ecom-data-prep`](../ecom-data-prep/) 的字段归一与清洗口径；识别环节可用 `see` / `claude-vision-skill` 之类视觉能力，读法与补拍规则见 `references/handwriting-hardening.md`。
- 下游：标准品名台账喂给 [`ecom-selection-profit`](../ecom-selection-profit/) 做毛利测算、[`ecom-roi-review`](../ecom-roi-review/) 做周期复盘；补货需求转 [`ecom-po-build`](../ecom-po-build/) 出采购单。
- 总控与共享约定见 [`crossborder-ecom-ops`](../crossborder-ecom-ops/)。

