Extract invoice information from images or text, classify expenses, and generate a professional Excel report with subtotals per category.
When to Use
- User has invoice photos / scanned receipts to process
- User describes expenses in text and wants them organized
- User needs a categorized reimbursement report (报销单)
- User mentions 发票报销, 报销汇总, 发票整理, expense report
Expense Categories
| Category | Keywords / Examples |
|---|---|
| Business entertainment | Client meals, business banquets, gifts, entertainment |
| Travel - Transportation | Air tickets, train tickets, high-speed rail, taxi, ride-hailing, ride-hailing, refueling, tolls, parking fees |
| Travel - Accommodation | Hotel, accommodation, guesthouse |
| Travel - Meals | Meals during business trips, work meals |
| Office supplies | Stationery, printing, office consumables, office equipment |
| Communication fees | Phone charges, data, internet fees, broadband |
| Other | Expenses not belonging to the above categories |
Workflow (MANDATORY)
Step 1: Collect Invoice Data
Accept input in any of these forms:
- Images: Read invoice photos using the Read tool. Extract: date, vendor, amount, item type, notes.
- Text descriptions: Parse the user's text for the same fields.
- Mixed: Multiple images + supplementary text.
For each invoice, extract these fields:
{
"date": "2026-04-15",
"vendor": "海底捞(国贸店)",
"item": "客户餐费",
"amount": 486.00,
"category": "业务招待",
"note": "与XX公司李总晚餐"
}
Step 2: Classify
Assign each invoice to a category from the table above. Rules:
- If the user explicitly states the category, use it.
- If the item/vendor clearly matches a category keyword, auto-assign.
- For ambiguous items (e.g., "餐费" could be 业务招待 or 差旅-餐饮):
- If the note mentions a client/customer → 业务招待
- If the context is a business trip → 差旅-餐饮
- If unclear, ask the user.
Step 3: Confirm with User
Before generating, show the extracted data as a table:
| # | 日期 | 商户 | 项目 | 金额 | 分类 | 备注 |
|---|------|------|------|------|------|------|
| 1 | 2026-04-15 | 海底捞 | 客户餐费 | 486.00 | 业务招待 | 与XX公司李总 |
| 2 | 2026-04-14 | 滴滴出行 | 打车 | 45.50 | 差旅-交通 | 机场→酒店 |
Use AskUserQuestion to ask: "以上信息是否正确? 需要修改或补充吗?"
Step 4: Generate Excel
Write the confirmed data to a temp JSON file, then run:
python expense-report-skill/scripts/generate_report.py \
--input /tmp/invoices.json \
--output "发票报销汇总-YYYYMMDD.xlsx"
JSON format (array of objects):
[
{"date": "2026-04-15", "vendor": "海底捞", "item": "客户餐费", "amount": 486.0, "category": "业务招待", "note": "与XX公司李总"},
{"date": "2026-04-14", "vendor": "滴滴出行", "item": "打车", "amount": 45.5, "category": "差旅-交通", "note": "机场→酒店"}
]
Step 5: Deliver
Tell the user:
- Output file path
- Total amount and breakdown by category
- Remind them to review the "分类汇总" sheet for the summary
Output Format
The Excel file contains two sheets:
- 发票报销汇总 — Full detail, grouped by category with subtotals
- 分类汇总 — Summary table: category, count, subtotal
Style: Skill Publisher warm-academic (terracotta headers #4F46E5, warm cream accents).
Edge Cases
- Blurry/unreadable image: Tell the user which fields couldn't be extracted; ask them to provide manually.
- Foreign currency: Note the currency; convert to CNY if user provides rate, otherwise keep original with note.
- Duplicate invoices: Flag potential duplicates (same date + vendor + amount) before generating.
- No date on invoice: Use the date the user provides, or mark as "日期不详".
Runtime context (shared)
Before running, read this Skill package's skill.yaml, with the host providing the skill-runtime/v1 context. The field resolution order is: current request, project context, personal Preferences, brand Profile, general defaults.
- Use only the fields declared in the Manifest; Profile stores public brand facts, Preferences stores personal work preferences.
required: trueWhen a field is missing, ask the user one focused question according to the Manifest's question configuration; save the answer only after the user explicitly agrees.- Errors provide a copyable
context_id, field path and source; diagnostic content avoids secrets, full private paths and raw configuration.
General feedback loop
When the user raises modification suggestions during a Skill-driven task, before continuing with the current artifact you must:
- First determine whether the suggestion is
task-specific(this time only) orreusable(reusable across tasks). task-specificOnly modify the current task, do not change the Skill.reusableFirst determine the scope: domain rules first update the corresponding canonical Skill; rules applicable to all Skills first update the shared specification.- After completing rule updates, versioning, lint and distribution verification, then apply the modification to the current task.
reusableThe modification invalidates previous "confirm", "continue", "send it" responses; after completing the current artifact modification and read-back you must stop and wait for the user's next instruction, without automatically proceeding to publishing, submission or other external writes.