日常报销和差旅报销都可以走通
This commit is contained in:
+42
-4
@@ -18,12 +18,13 @@
|
||||
2. 解析发票和刷卡记录的金额,进行总额校验
|
||||
- 发票总额 < 刷卡总额时发出 warning
|
||||
3. 按金额降序排序
|
||||
4. 根据数量关系选择匹配策略:
|
||||
4. 文件名匹配(最高优先级):发票和刷卡记录的文件名(不含后缀)一致时直接匹配
|
||||
5. 根据数量关系选择匹配策略:
|
||||
- 数量相等 → 一对一匹配:按金额从大到小依次配对,相对容差内即匹配
|
||||
- 发票更多 → 一对多匹配:对每张刷卡记录贪心凑金额,相对容差内结束
|
||||
5. 构建以支付记录为主键的结果列表
|
||||
6. 未匹配的发票单独作为一条记录(无刷卡信息)
|
||||
7. 清理内部字段,输出支付记录列表
|
||||
6. 构建以支付记录为主键的结果列表
|
||||
7. 未匹配的发票单独作为一条记录(无刷卡信息)
|
||||
8. 清理内部字段,输出支付记录列表
|
||||
|
||||
## 容差计算
|
||||
|
||||
@@ -45,6 +46,7 @@
|
||||
match_invoices_to_cards(invoices, cards, tolerance) -> list[dict]
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from .. import get_logger
|
||||
@@ -170,10 +172,18 @@ def _match(
|
||||
"""执行匹配,返回 {card_index: [invoice_indices]} 的映射
|
||||
|
||||
tolerance 为相对容差比例(如 0.03 表示 3%)
|
||||
|
||||
匹配优先级(从高到低):
|
||||
1. 文件名匹配:发票和刷卡记录的文件名(不含后缀)一致时直接匹配
|
||||
2. 精确匹配:金额差 <= 0.01 元
|
||||
3. 一对一 / 一对多贪心匹配:按金额容差匹配
|
||||
"""
|
||||
result: dict[int, list[int]] = {}
|
||||
assigned: set[int] = set()
|
||||
|
||||
# ---- 阶段 0:文件名匹配(最高优先级)----
|
||||
_match_by_filename(invoices, cards, assigned, result)
|
||||
|
||||
if len(invoices) == len(cards):
|
||||
_match_one_to_one(invoices, cards, tolerance, assigned, result)
|
||||
else:
|
||||
@@ -182,6 +192,34 @@ def _match(
|
||||
return result
|
||||
|
||||
|
||||
def _match_by_filename(
|
||||
invoices: list[dict[str, Any]],
|
||||
cards: list[dict[str, Any]],
|
||||
assigned: set[int],
|
||||
result: dict[int, list[int]],
|
||||
) -> None:
|
||||
"""文件名匹配:发票和刷卡记录的文件名(不含后缀)一致时直接匹配"""
|
||||
for card_idx, card in enumerate(cards):
|
||||
card_name = card.get("_source_file", "")
|
||||
if not card_name:
|
||||
continue
|
||||
card_stem = Path(card_name).stem
|
||||
|
||||
for idx, inv in enumerate(invoices):
|
||||
if idx in assigned:
|
||||
continue
|
||||
inv_name = inv.get("_source_file", "")
|
||||
if not inv_name:
|
||||
continue
|
||||
inv_stem = Path(inv_name).stem
|
||||
|
||||
if inv_stem == card_stem:
|
||||
assigned.add(idx)
|
||||
result[card_idx] = [idx]
|
||||
log.info(f"[文件名匹配] {inv_name} ↔ {card_name}")
|
||||
break
|
||||
|
||||
|
||||
def _match_one_to_one(
|
||||
invoices: list[dict[str, Any]],
|
||||
cards: list[dict[str, Any]],
|
||||
|
||||
Reference in New Issue
Block a user