---
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火车票、携程机票/酒店、华住会酒店、美团发票五类差旅发票的自动化报销处理。*
