自动化差旅费用报销流程,支持12306火车票、携程机票/酒店、华住会酒店等电子发票的自动获取、解析和报销提交
---
name: travel-expense-reimbursement
title: 差旅费用自动报销助手
description: 自动化差旅费用报销流程,支持12306火车票、携程机票/酒店、华住会酒店等电子发票的自动获取、解析和报销提交
version: 1.0.0
author: custom
requires: [exec, read, write, edit]
skill_dependencies:
- himalaya
- pdf-ocr
- pincer-runtime
---
# 差旅费用自动报销助手
## 一、触发条件
1. 用户提问/指令包含【差旅报销、火车票报销、12306发票、携程发票、华住会发票、酒店报销、机票报销、电子客票、美团发票】时,**必须优先使用本技能**
2. 用户要求从邮箱获取各类差旅发票并处理报销时
3. 用户需要批量处理差旅相关PDF发票时
## 二、能力范围
- **支持**:
- 12306火车票电子客票
- 携程机票电子行程单
- 携程酒店住宿发票
- 华住会酒店住宿发票
- 美团发票(外卖、酒店、打车等)
- **功能**:读取邮箱、下载PDF附件、解析发票信息、生成报销数据、调用pincer-runtime提交报销
- **限制**:仅处理上述五类发票,其他类型发票需人工处理
## 三、依赖技能
本技能依赖以下技能完成工作:
| 技能 | 用途 |
|------|------|
| **himalaya** | 邮件访问、搜索12306邮件、下载PDF附件 |
| **pdf-ocr** | PDF/图片OCR文字提取、发票信息解析 |
| **pincer-runtime** | 报销系统自动化提交(底层使用 browser 工具实现浏览器自动化操作)|
## 四、执行步骤(严格按顺序执行)
### 步骤1:初始化工作目录
1. 设定工作目录为 `/by/.uiagent/files/`
2. 创建子目录结构:
```
/by/.uiagent/files/
├── inbox/ # 存放从邮箱下载的原始PDF
│ ├── railway/ # 12306火车票
│ ├── flight/ # 携程机票
│ ├── hotel_ctrip/ # 携程酒店
│ ├── hotel_huazhu/ # 华住会酒店
│ └── meituan/ # 美团发票
├── processed/ # 存放已解析的发票数据
├── output/ # 存放生成的报销文件
└── config.json # 配置文件(邮箱、报销系统账号等)
```
3. 如果目录已存在,保持现有结构,仅清空 `inbox/` 各子目录
### 步骤2:读取配置信息
1. 从 `config.json` 读取以下配置:
- `email_account`: 邮箱账号配置(供himalaya使用)
- `reimbursement_system`: 报销系统配置(供pincer-runtime使用)
- `company_info`: 购买方信息(统一社会信用代码、公司名称)
2. 如果 `config.json` 不存在或配置不完整:
- 提示用户补充配置
- 提供配置模板示例
- 等待用户确认后继续
### 步骤3:调用 himalaya 获取各类差旅邮件
#### 3.1 获取12306火车票邮件
1. 使用 himalaya 搜索发件人为 "12306" 的邮件:
```bash
himalaya envelope list "from 12306"
```
2. 对于每封找到的邮件:
- 获取邮件ID
- 使用 `himalaya attachment download <message_id>` 下载附件
- 仅保留PDF格式的附件,删除其他格式(如OFD、ZIP等)
- 将PDF文件移动到 `inbox/railway/` 目录
- 记录邮件信息到处理日志
#### 3.2 获取携程机票邮件
1. 使用 himalaya 搜索发件人含 "携程" 且主题含 "机票" 或 "行程单" 的邮件:
```bash
himalaya envelope list "from 携程"
```
然后过滤主题包含"机票"、"行程单"、"航班"的邮件
2. 对于每封符合条件的邮件:
- 获取邮件ID
- 使用 `himalaya attachment download <message_id>` 下载附件
- 仅保留PDF格式的附件
- 将PDF文件移动到 `inbox/flight/` 目录
- 记录邮件信息到处理日志
#### 3.3 获取携程酒店邮件
1. 使用 himalaya 搜索发件人含 "携程" 且主题含 "酒店" 或 "住宿" 的邮件:
```bash
himalaya envelope list "from 携程"
```
然后过滤主题包含"酒店"、"住宿"、"订单确认"的邮件
2. 对于每封符合条件的邮件:
- 获取邮件ID
- 使用 `himalaya attachment download <message_id>` 下载附件
- 仅保留PDF格式的附件(排除"行程单"、"确认单"等非发票文件)
- 将PDF文件移动到 `inbox/hotel_ctrip/` 目录
- 记录邮件信息到处理日志
#### 3.4 获取华住会酒店邮件
1. 使用 himalaya 搜索发件人含 "华住" 或 "华住会" 的邮件:
```bash
himalaya envelope list "from 华住"
```
2. 对于每封找到的邮件:
- 获取邮件ID
- 使用 `himalaya attachment download <message_id>` 下载附件
- 仅保留PDF格式的附件
- 将PDF文件移动到 `inbox/hotel_huazhu/` 目录
- 记录邮件信息到处理日志
#### 3.5 获取美团发票邮件
1. 使用 himalaya 搜索发件人含 "美团" 的邮件:
```bash
himalaya envelope list "from 美团"
```
2. 对于每封符合条件的邮件:
- 获取邮件ID
- 使用 `himalaya attachment download <message_id>` 下载附件
- 仅保留PDF格式的附件
- 将PDF文件移动到 `inbox/meituan/` 目录
- 记录邮件信息到处理日志
3. 如果某类邮件未找到:
- 提示用户 "未在邮箱中找到[某类]发票邮件"
- 询问是否手动上传PDF到对应 `inbox/` 子目录
### 步骤4:调用 pdf-processor 解析各类发票
#### 4.1 解析12306火车票
1. 遍历 `inbox/railway/` 目录中的所有PDF文件
2. 对每个PDF文件,调用pdf-ocr提取文字内容,提取关键字段:
- 发票号码
- 开票日期
- 出发站、到达站
- 车次
- 乘车日期、发车时间
- 座位信息(车厢、座位号、席别)
- 票价金额
- 乘客姓名、身份证号(脱敏)
- 购买方名称、统一社会信用代码
3. 保存为JSON格式到 `processed/` 目录:
```json
{
"type": "railway",
"invoice_number": "26329116804005647551",
"issue_date": "2026-05-26",
"departure": "南京南",
"arrival": "北京南",
"transport_number": "G50",
"travel_date": "2026-04-01",
"departure_time": "20:06",
"seat_info": "02车05A号 二等座",
"amount": 464.00,
"passenger_name": "马天澍",
"passenger_id": "3212011996****0216",
"buyer_name": "浩鲸云计算科技股份有限公司",
"buyer_tax_id": "91320100745379000T",
"pdf_path": "inbox/railway/26329116804005647551.pdf"
}
```
#### 4.2 解析携程机票
1. 遍历 `inbox/flight/` 目录中的所有PDF文件
2. 对每个PDF文件,调用pdf-ocr提取文字内容,提取关键字段:
- 发票号码/行程单号
- 开票日期
- 出发城市、到达城市
- 航班号
- 起飞日期、起飞时间
- 舱位等级
- 票价金额(含税)
- 乘客姓名
- 购买方名称、统一社会信用代码
3. 保存为JSON格式到 `processed/` 目录:
```json
{
"type": "flight",
"invoice_number": "2026052600123456",
"issue_date": "2026-05-26",
"departure": "南京",
"arrival": "北京",
"transport_number": "MU2811",
"travel_date": "2026-05-26",
"departure_time": "08:30",
"seat_info": "经济舱",
"amount": 850.00,
"passenger_name": "张三",
"passenger_id": "3201021990****1234",
"buyer_name": "浩鲸云计算科技股份有限公司",
"buyer_tax_id": "91320100745379000T",
"pdf_path": "inbox/flight/2026052600123456.pdf"
}
```
#### 4.3 解析携程酒店
1. 遍历 `inbox/hotel_ctrip/` 目录中的所有PDF文件
2. 对每个PDF文件,调用pdf-ocr提取文字内容,提取关键字段:
- 发票号码
- 开票日期
- 酒店名称
- 入住日期、离店日期
- 房间数量、晚数
- 金额
- 入住人姓名
- 购买方名称、统一社会信用代码
3. 保存为JSON格式到 `processed/` 目录:
```json
{
"type": "hotel_ctrip",
"invoice_number": "2026052600789012",
"issue_date": "2026-05-26",
"hotel_name": "南京金陵饭店",
"check_in": "2026-05-25",
"check_out": "2026-05-26",
"nights": 1,
"rooms": 1,
"amount": 580.00,
"guest_name": "张三",
"buyer_name": "浩鲸云计算科技股份有限公司",
"buyer_tax_id": "91320100745379000T",
"pdf_path": "inbox/hotel_ctrip/2026052600789012.pdf"
}
```
#### 4.4 解析华住会酒店
1. 遍历 `inbox/hotel_huazhu/` 目录中的所有PDF文件
2. 对每个PDF文件,调用pdf-ocr提取文字内容,提取关键字段:
- 发票号码
- 开票日期
- 酒店名称(如汉庭、全季等)
- 入住日期、离店日期
- 房间数量、晚数
- 金额
- 入住人姓名
- 购买方名称、统一社会信用代码
3. 保存为JSON格式到 `processed/` 目录:
```json
{
"type": "hotel_huazhu",
"invoice_number": "263291167890123456",
"issue_date": "2026-05-26",
"hotel_name": "汉庭酒店南京新街口店",
"check_in": "2026-05-25",
"check_out": "2026-05-26",
"nights": 1,
"rooms": 1,
"amount": 299.00,
"guest_name": "张三",
"buyer_name": "浩鲸云计算科技股份有限公司",
"buyer_tax_id": "91320100745379000T",
"pdf_path": "inbox/hotel_huazhu/263291167890123456.pdf"
}
```
#### 4.5 解析美团发票
1. 遍历 `inbox/meituan/` 目录中的所有PDF文件
2. 对每个PDF文件,调用pdf-ocr提取文字内容,提取关键字段:
- 发票号码
- 开票日期
- 服务类型(外卖、酒店、打车等)
- 商家名称
- 消费日期
- 金额
- 购买方名称、统一社会信用代码
3. 保存为JSON格式到 `processed/` 目录:
```json
{
"type": "meituan",
"invoice_number": "263291167890123789",
"issue_date": "2026-05-26",
"service_type": "外卖",
"merchant_name": "美团外卖商家",
"consume_date": "2026-05-25",
"amount": 45.00,
"buyer_name": "浩鲸云计算科技股份有限公司",
"buyer_tax_id": "91320100745379000T",
"pdf_path": "inbox/meituan/263291167890123789.pdf"
}
```
4. 按时间排序(火车票/机票按出发时间,酒店按入住时间,美团按消费日期),生成 `invoice-list.json`
#### 4.6 发票类型识别说明
由于不同供应商的发票格式差异,解析时需要根据以下特征识别发票类型:
| 发票类型 | 识别特征 |
|---------|---------|
| 12306火车票 | 包含"中国铁路"、"国家税务总局"、"电子客票"等字样 |
| 携程机票 | 包含"携程"、"航空运输电子客票行程单"等字样 |
| 携程酒店 | 包含"携程"、"住宿服务"、"酒店"等字样 |
| 华住会酒店 | 包含"华住"、"汉庭"、"全季"、"桔子"等品牌名称 |
| 美团发票 | 包含"美团"、"美团外卖"、"大众点评"等字样 |
### 步骤5:行程分析(核心步骤)
**重要**:本步骤依据 `/references/行程分析指南.md` 进行,分为三个阶段完成。
#### 5.1 第一阶段:生成详细行程安排
1. 读取 `processed/invoice-list.json` 中的车票和住宿发票信息
2. 根据发票信息分析行程,遵循以下原则:
- 行程是从出发地到目的地再返回的完整过程
- 短行程:仅一个目的地(如"南京 → 北京 → 南京")
- 长行程:多个目的地(如"南京 → 上海 → 杭州 → 北京 → 南京")
- 按时间顺序排列:车票按乘车日期+发车时间,住宿按入住日期
3. 生成分段行程信息,每个分段包含:
- 交通信息:出发地、出差地、交通工具、出发日期、结束日期
- 停留信息:住宿情况、开始日期、结束日期、住宿天数、住宿方式
4. 处理特殊情况:
- **当日往返**:根据发车时间早晚判断行程方向
- **车站名转城市名**:将"南京南站"转换为"南京"
- **信息缺失**:标注为"待确认",第二阶段补充
5. 输出结果到 `output/travel-schedule.md`,格式示例:
```
行程1:南京 → 北京 → 南京(短行程、停留住宿)
分段1交通:南京 → 北京,交通工具:高铁,出发日期:2026年03月18日,结束日期:2026年03月18日,出发地:南京,出差地:北京;
分段1停留:北京,住宿:有,开始日期:2026年03月18日,结束日期:2026年03月20日,住宿方式:宾馆,住宿天数:2;
分段1行程总天数:3天
------------------------------------
分段2交通:北京 → 南京,交通工具:高铁,出发日期:2026年03月20日,结束日期:2026年03月20日,出发地:北京,出差地:南京
分段2行程总天数:0天
```
#### 5.2 第二阶段:完善行程信息
1. 读取 `output/travel-schedule.md`
2. 针对包含"待确认"内容的行程,通过对话补充信息:
- 缺交通信息:询问交通工具、起始地、出发日期
- 缺住宿信息:询问是否住宿、入住协议酒店/宿舍/自行安排、入住时间
3. 根据用户回复更新 `travel-schedule.md`:
- 协议酒店 → 住宿方式填写"协议宾馆"
- 住宿舍 → 住宿方式填写"宿舍"
- 自行安排 → 住宿方式填写"自行安排"
4. 如用户表示某行程暂不处理:
- 将对应发票PDF移动到 `inbox/pending/` 目录
- 从 `travel-schedule.md` 中删除该行程
5. **重要**:确认 `travel-schedule.md` 中无"待确认"内容后,才进入第三阶段
#### 5.3 第三阶段:生成报销表单数据
1. 读取 `travel-schedule.md`
2. 根据 `/references/行程分析指南.md` 第三阶段的规则,逐行程处理:
**短行程(往返交通工具相同)**:
```
----------------------
行程:填写本行程名称
出发日期:填写分段1交通的出发日期
结束日期:填写分段2交通的结束日期
是否结束:填写是
总天数:填写分段1行程总天数加分段2行程总天数
出发地:填写分段1交通的出发地
出差地:填写分段1交通的出差地
交通:填写分段1交通的交通工具
是否享受补贴:填写是
宾馆天数:根据住宿方式填写
宿舍天数:根据住宿方式填写
是否入住协议酒店:根据住宿方式填写
```
**短行程(往返交通工具不同)**:分为两条记录
**长行程**:每个分段生成一条记录(除最后分段),最后分段单独处理
3. 输出到 `output/travel-detail.md`,严格遵循格式要求
4. 执行检查:
- 前一分段结束日期不晚于后一分段出发日期
- 除最后分段,其他分段"是否结束"为"否"
- 各分段通过"----------------------"分割
- 所有字段无缺失
5. **重要**:确认 `travel-schedule.md` 和 `travel-detail.md` 都已生成后,才进入下一步骤
**参考文档**:详细的行程分析规则请参见 `/references/行程分析指南.md`
### 步骤6:调用 pincer-runtime 提交报销
**前置条件**:必须已生成 `travel-detail.md` 文件
1. 检查 `output/travel-detail.md` 是否存在,如不存在则报错退出
2. 检查 `config.json` 中的报销系统配置是否完整
3. 调用 pincer-runtime 技能:
- 传入 `output/travel-detail.md` 作为输入数据源
- 执行报销系统自动化提交流程
- 监控提交状态
4. 记录提交结果到 `output/submission-log.json`
### 步骤7:输出结果
1. 向用户展示处理结果:
- 成功处理的发票数量
- 总金额
- 行程汇总
- 报销提交状态
2. 提供文件位置说明,方便用户查看详细数据
## 五、输出规范
1. **结果分段展示**,关键信息加粗
2. **命令执行、文件内容完整保留**,不随意删减
3. **执行失败时**,主动说明报错原因 + 简易修复建议
4. **发票信息表格化展示**,便于核对
## 六、安全约束
1. 所有涉及外部系统(邮箱、报销系统)的操作必须基于用户提供的配置
2. 敏感信息(密码、Token)不得明文存储,使用环境变量或加密存储
3. 删除操作前必须确认,禁止自动删除原始邮件或文件
4. PDF解析失败时保留原始文件,便于人工复核
## 七、配置模板
`config.json` 示例:
```json
{
"email_account": {
"name": "default",
"type": "imap"
},
"reimbursement_system": {
"type": "fol",
"url": "https://fol.example.com",
"credentials": {
"username": "${FOL_USERNAME}",
"password": "${FOL_PASSWORD}"
}
},
"company_info": {
"name": "浩鲸云计算科技股份有限公司",
"tax_id": "91320100745379000T"
}
}
```
## 八、错误处理
| 错误场景 | 处理方式 |
|---------|---------|
| himalaya未配置 | 提示用户配置邮箱账号 |
| 未找到某类邮件 | 提示该类发票未找到,询问是否手动上传PDF到对应inbox子目录 |
| PDF解析失败 | 保留文件,记录错误,继续处理其他文件 |
| 发票类型识别失败 | 提示无法识别发票类型,记录到待处理列表 |
| pincer-runtime提交失败 | 保存数据,提示用户手动提交 |
| 配置信息缺失 | 生成配置模板,引导用户补充 |
## 九、支持的邮箱发件人
| 发票类型 | 发件人特征 | 邮件主题特征 |
|---------|-----------|-------------|
| 12306火车票 | 12306@rails.com.cn | "电子发票通知" |
| 携程机票 | 含"携程" | "机票"、"行程单"、"航班" |
| 携程酒店 | 含"携程" | "酒店"、"住宿"、"订单确认" |
| 华住会酒店 | 含"华住"、"华住会" | "发票"、"电子发票" |
| 美团发票 | 含"美团" | "发票"、"电子发票" |
## 十、相关技能
- **himalaya**: 邮件管理CLI工具,用于访问邮箱、搜索邮件、下载附件
- **pdf-ocr**: PDF/图片OCR文字提取和解析工具,用于从发票中提取结构化数据
- **pincer-runtime**: 报销系统自动化工具,用于完成最终的报销提交
---
*本技能支持12306火车票、携程机票/酒店、华住会酒店、美团发票五类差旅发票的自动化报销处理。*
don't have the plugin yet? install it then click "run inline in claude" again.