128 lines
4.3 KiB
Python
128 lines
4.3 KiB
Python
"""
|
||
报销全流程编排
|
||
|
||
将发票提取 → OCR 识别 → 浏览器填报串联为一条管道,
|
||
数据在内存中流转,同时生成 CSV / Markdown 中间产物。
|
||
"""
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
from . import get_logger
|
||
from .config import load_config
|
||
from .extractor import extract_invoices, save_csv as save_invoice_csv, save_markdown as save_invoice_md
|
||
from .ocr import enrich_with_ocr, _save_csv as save_ocr_csv, save_markdown_from_csv, _load_csv
|
||
|
||
log = get_logger("pipeline")
|
||
|
||
|
||
def run_pipeline(step: str = "all", username: str = None, password: str = None):
|
||
"""执行报销流程
|
||
|
||
Args:
|
||
step: all | invoice | ocr | submit
|
||
username: 覆盖 config.json 中的用户名
|
||
password: 覆盖 config.json 中的密码
|
||
"""
|
||
config = load_config()
|
||
if username:
|
||
config["username"] = username
|
||
if password:
|
||
config["password"] = password
|
||
|
||
# 工作目录(项目根目录)
|
||
project_dir = Path(__file__).parent.parent
|
||
|
||
# --------------------------------------------------
|
||
# Step 1: 发票提取
|
||
# --------------------------------------------------
|
||
invoices = None
|
||
|
||
if step in ("all", "invoice"):
|
||
log.info("=" * 60)
|
||
log.info("[1/3] 发票提取")
|
||
log.info("=" * 60)
|
||
|
||
invoices = extract_invoices(str(project_dir))
|
||
if not invoices:
|
||
log.error("未提取到任何发票数据")
|
||
return 1
|
||
|
||
save_invoice_csv(invoices, project_dir / "invoice_summary.csv")
|
||
save_invoice_md(invoices, project_dir / "invoice_summary.md")
|
||
|
||
if step == "invoice":
|
||
log.info("[1/3] 发票提取 完成")
|
||
return 0
|
||
|
||
# --------------------------------------------------
|
||
# Step 2: OCR 识别
|
||
# --------------------------------------------------
|
||
if step in ("all", "ocr"):
|
||
log.info("=" * 60)
|
||
log.info("[2/3] OCR 识别")
|
||
log.info("=" * 60)
|
||
|
||
csv_path = project_dir / "invoice_summary.csv"
|
||
|
||
if invoices is None:
|
||
rows = _load_csv(csv_path)
|
||
if rows is None:
|
||
return 1
|
||
else:
|
||
# 将 dict 列表转为 CSV 风格的 dict(对齐列名)
|
||
from .extractor import CSV_COLUMNS
|
||
rows = []
|
||
for idx, inv in enumerate(invoices, 1):
|
||
items = inv.get("_items", [])
|
||
first_item = items[0] if items else {}
|
||
rows.append({
|
||
"序号": str(idx),
|
||
"发票号码": inv.get("发票号码", ""),
|
||
"开票日期": inv.get("开票日期", ""),
|
||
"项目名称": first_item.get("项目名称", inv.get("项目名称", "")),
|
||
"规格型号": first_item.get("规格型号", inv.get("规格型号", "")),
|
||
"价税合计": inv.get("价税合计", ""),
|
||
"销售方名称": inv.get("销售方名称", ""),
|
||
"人员姓名": inv.get("人员姓名", ""),
|
||
"刷卡日期": inv.get("刷卡日期", ""),
|
||
"公务卡号": inv.get("公务卡号", ""),
|
||
"刷卡金额": inv.get("刷卡金额", ""),
|
||
"备注": inv.get("备注", ""),
|
||
"工号": inv.get("工号", ""),
|
||
})
|
||
|
||
rows = enrich_with_ocr(rows, str(project_dir))
|
||
save_ocr_csv(csv_path, rows)
|
||
save_markdown_from_csv(csv_path, rows)
|
||
invoices = rows
|
||
|
||
if step == "ocr":
|
||
log.info("[2/3] OCR 识别 完成")
|
||
return 0
|
||
|
||
# --------------------------------------------------
|
||
# Step 3: 浏览器填报
|
||
# --------------------------------------------------
|
||
if step in ("all", "submit"):
|
||
log.info("=" * 60)
|
||
log.info("[3/3] 报销提交")
|
||
log.info("=" * 60)
|
||
|
||
from .bot import load_invoice_data, run_bot
|
||
|
||
csv_path = project_dir / "invoice_summary.csv"
|
||
bot_invoices = load_invoice_data(str(csv_path), config)
|
||
run_bot(config, bot_invoices)
|
||
|
||
if step == "submit":
|
||
log.info("[3/3] 报销提交 完成")
|
||
return 0
|
||
|
||
# --------------------------------------------------
|
||
# 全流程完成
|
||
# --------------------------------------------------
|
||
log.info("=" * 60)
|
||
log.info("全流程执行完毕")
|
||
log.info("=" * 60)
|
||
return 0 |