--- last_reviewed: 2026-10-19 --- # src/core/matching — 金额匹配 | 文件 | 职责 | |------|------| | `matcher.py` | 匹配引擎:一对一、一对多贪心、未匹配处理、CSV 汇总构造 | | `runner.py` | 从会话缓存跑完整流程:分组 → 匹配 → 写 `match_result.json`、`invoice_groups.json`、两份 CSV、`travel_applications.json` | ## 匹配策略 | 场景 | 策略 | |------|------| | 发票数 == 支付数 | 一对一:按金额降序配对,相对容差内即匹配 | | 发票数 > 支付数 | 一对多:贪心凑额,默认相对容差 3% | | 文件名一致 | 最高优先级,直接匹配 | | 未匹配发票 | 单列一条支付记录,`remark` 标 `unmatched` | ## 业务约束 - 发票总额应 >= 支付总额,违反要报出来 - 输出以支付记录为主键 `match_from_cache()` 额外返回 `review_required`:未匹配项、发票总额小于支付总额、一对多凑额。 **信封 `ok: true` 只代表贪心跑完了,不代表配对对了**——调用方必须逐条复核,等额发票尤其容易配错。