一体化对话式报销 Agent
Purpose
Provide a ready-to-run, two-in-one reimbursement toolkit for enterprise / personal finance scenarios:
- Excel 报销单生成 — turn conversational chat text or a JSON structure into a
formatted《费用报销申请单》.xlsx(14-column template, RMB uppercase total, auto-sum). - 邮箱发票自动化 — connect to a mailbox over IMAP and list / count / download
invoice attachments using natural-language commands (e.g. "拉取本周发票",
"下载所有差旅费发票").
The toolkit is fully self-contained Python (no LLM required) and degrades gracefully
when optional dependencies are missing.
When to use
- User asks to "生成报销单 / 做报销 / 录入报销信息 / 从JSON生成报销单".
- User asks to "查看发票邮件 / 拉取本周发票 / 下载差旅费发票 / 统计本月发票数量".
- User asks to "扫描微信发票 / 从微信聊天记录中找发票 / 自动提取微信发票".
- User needs the《费用报销申请单》Excel template filled programmatically.
- User wants a no-account demo of either flow (use
--demomode).
Deployment (run once per working directory)
The bundled scripts use relative imports, so reimburse_agent.py,
email_invoice_agent.py, and reimburse_engine.py must sit in the same folder.
- Copy the three scripts + example config into the target working directory:
-scripts/reimburse_agent.py
-scripts/email_invoice_agent.py
-scripts/reimburse_engine.py
-scripts/email_config.example.json - Install dependencies (graceful degradation if skipped — see Errors below):
pip install openpyxl imap-tools - (Email only) Create
email_config.jsonfrom the example and fill in real values:
-email— mailbox account
-auth_code— authorization code, NOT the login password
-provider— one ofqq/163/126/gmail/outlook/exmail,
or setimap_hostdirectly
-local_dir— where invoice attachments are saved (supports~)
-categories— keyword map for invoice categorization
- ⚠️ Security: Never commitemail_config.jsonto version control or share it publicly — it contains sensitive credentials.
Usage
Run from the directory containing the scripts.
Reimbursement form (Excel):
python reimburse_agent.py # interactive wizard
python reimburse_agent.py "生成报销单示例" # one-click sample xlsx
python reimburse_agent.py "从JSON生成报销单 a.json"
python reimburse_agent.py "从文本生成报销单 a.txt"
python reimburse_agent.py --demo "生成报销单示例" # no deps needed
Email invoices:
python reimburse_agent.py "查看全部发票邮件"
python reimburse_agent.py "拉取本周发票"
python reimburse_agent.py "下载所有差旅费发票"
python reimburse_agent.py "统计本月发票数量"
python reimburse_agent.py "下载最近7天的餐饮发票"
python reimburse_agent.py --demo "统计本月发票数量" # mock data, no account
Natural-language time words are supported: 本周/这周, 上周/上个星期, 本月/这个月,
上月/上个月, 今天, 最近N天, 全部/所有. Categories: 差旅/交通/住宿/餐饮/办公/通讯.
Type 帮助 for the full command menu, 退出 to quit interactive mode.
WeChat invoice scanning (macOS only):
python wechat_invoice_scanner.py # list all invoices
python wechat_invoice_scanner.py --recent 30 # invoices from last 30 days
python wechat_invoice_scanner.py --output json # JSON format output
python wechat_invoice_scanner.py --output reimburse # reimburse-Agent compatible format
python wechat_invoice_scanner.py --invoice-id 3 # view invoice #3 details
Scans ~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/<user>/msg/file/
for PDF files matching invoice keywords (dzfp_, 发票, invoice, etc.). Extracts invoice
number, date, buyer/seller names, tax IDs, amounts, and line items using pdfplumber.
Non-invoice PDFs (e.g., reimbursement reports) are automatically filtered out by checking
for 发票号码 or 开票日期 markers in the extracted text.
Note: WeChat database files (db_storage/message/*.db) are WCDB-encrypted and cannot
be read with standard SQLite. The scanner works at the file-system level only — it finds
invoice PDFs but cannot determine which chat sent them.
Engine details (reimburse_engine.py)
generate(data, output_path)— fills the template.data={basic, reason, invoices[], payments[], attachments_note}. SeeSAMPLE_INPUTin the script for
the exact schema.parse_chat(text)— heuristic parser converting semi-structured chat text into the
datadict (fields use Chinese labels like费用类别:,价税合计:).- English keys in
basicare mapped to Chinese template labels automatically. - Excel write errors (file open in Excel/WPS → PermissionError; bad directory →
OSError) surface asRuntimeErrorwith actionable Chinese messages.
Customization
The Excel template includes a company name line (line 2 of the sheet). To customize it
for your organization, edit reimburse_engine.py and change the string on line ~207:
ws["A2"] = "铯镨(××)科技有限公司 | 智能财务 · 对话式自动化报销单"
Replace with your own company name and subtitle. The engine code is fully self-contained
with no external template files — all formatting is generated programmatically.
Errors & graceful degradation
| Situation | Behavior |
|---|---|
openpyxl missing |
HAS_EXCEL=False; Excel feature shows install hint, email feature still works |
imap-tools missing |
HAS_IMAP_TOOLS=False; email shows install hint / suggests --demo |
Bad email_config.json |
Warning, falls back to built-in defaults |
| Unconfigured mailbox | AgentError: create email_config.json with auth code |
| Login failed | AgentError: check auth code ≠ password, IMAP enabled |
| Cannot reach server | AgentError: network / provider / port 993 hints |
| Local dir unwritable | AgentError: fix local_dir path/permissions |
| Some attachments fail | Others still download; summary shows failure count |
| No matching invoices | Prints 4 actionable suggestions instead of crashing |
All user-facing errors use the AgentError class (message only, no stack trace).
Known issues & fixes
163/126 (NetEase) "SELECT Unsafe Login"
Symptom: IMAP login succeeds but SELECT INBOX returns SELECT Unsafe Login. Please contact kefu@188.com for help.
Root cause: NetEase mail servers enforce mandatory IMAP ID command (RFC 2971) before allowing SELECT operations. Standard imap-tools does not send this command.
Fix: email_invoice_agent.py now auto-detects provider: "163" / "126" in email_config.json and switches to a native imaplib path that sends the required ID command after login:
imaplib.Commands["ID"] = ("AUTH",)
conn._simple_command("ID", '("name" "WorkBuddy" "version" "1.0" "vendor" "CiipPlatform")')
No config changes needed — just set "provider": "163" (or "126") and ensure the auth code is valid.
Reference
For the full beginner's manual (pre-config walkthrough, all commands, FAQ 11,
config-field reference, 30-second quick card), load references/报销Agent_新手使用手册.md.