Communitygithub.com

会议差旅报销 (Conference Expense Reimbursement)

为以色列大学国际会议之旅准备差旅报销申请:收集行程收据文件夹及邮箱中的收据(机票及附加服务、旅行保险、酒店、注册费、会议晚宴、海报打印、地面交通),将每项保存为命名的PDF文件,并根据内置的报销模板构建希伯来语从右至左的费用电子表格,使用以色列银行代表性汇率转换为谢克尔。

会议差旅报销 (Conference Expense Reimbursement) 是什么?

该技能(SKILL)自动化处理以色列大学研究人员或教师在海外参加会议后的差旅费用报销流程。其核心功能包括:从指定文件夹和用户邮箱中自动收集各类收据(如机票、酒店、注册费等),将它们保存为规范的PDF文件,并基于内置的Excel模板生成两份希伯来语、从右至左的报销电子表格。一份是提交给财务部门的正式文件(SENT),另一份是用户保留的内部副本(INTERNAL),内部副本包含预算与实际支出的对比。技能会自动从以色列银行官网获取“代表性汇率”(שער יציג),将外币金额转换为新谢克尔(ILS)。它支持多种模式(完整报销/部分输入),能够处理共享费用、发票拆分等复杂场景,并会在最终报告中列出所有需要手动补充的缺口。用户通过 AskUserQuestion 工具与技能交互,所有决策(如共享房间、汇率日期等)都以问题形式提出,避免歧义。该技能主要在 Claude Code 环境中运行,依赖 Python 脚本(如 build_claim.py 和 check_claim.py)来完成电子表格构建和验证。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/OrrZwebner/conference-reimbursement/tree/HEAD/skills/conference-reimbursement

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

会议差旅报销 (Conference Expense Reimbursement) 是做什么的?

使用相同的数据行生成两份电子表格,总额相同,并将它们引用的每张收据保存到 <conference folder>/החזרים/קבלות/ 中:

  • SENT 文件 <conference folder>/החזרים/<full name> הוצאות.xlsx — 唯一需要提交给财务部门的文件。B 列 סעיף = 预算表分类;包含收据工作表;银行信息块;汇率。不包含预算与实际支出的对比。
  • INTERNAL 文件 <conference folder>/החזרים/<full name> הוצאות - פנימי.xlsx — 用户的本地副本,永不附在邮件中发送或提交。B 列 השירות = 每项支出的具体内容(例如 “קפה”、“רכבת שדה–עיר”),在 הערות 列之后有一个 סעיף 分类列,并包含预算对比表。

两个文件均为希伯来语且从右至左显示;用英语与用户交流。电子表格的布局来源于内置的 assets/claim-template.xlsx(仅包含标签);用户无需自行提供电子表格。

个人资料(全名和银行信息)。 读取 ~/.config/conference-reimbursement/profile.json(格式为 {"full_name": "...", "bank": {"בנק": "...", "סניף": "...", "מספר חשבון": "..."}})。如果该文件缺失或不完整,使用 AskUserQuestion 工具询问缺失的字段(用户输入自己的值作为回答),然后以权限 600 保存该文件。文件仅保存在该路径下——不要放在任何仓库或项目文件夹内。切勿提交该文件,切勿在聊天或报告中打印银行详细信息(应说明“银行信息:来自个人资料”),且仅在暂存区域的 spec 文件的 bank 键中使用这些信息。

通过 AskUserQuestion 工具向用户提出所有问题——不要用散文形式提问——每次只做一个决策,并将推荐选项放在首位。

选择模式

  • 模式 A — 完整报销。 已批准的预算表 PDF、银行信息(个人资料)、收据文件夹和邮箱访问权限全部可用。执行步骤 1–7。
  • 模式 B — 部分输入。 上述一项或多项缺失。执行相同步骤,忽略缺失部分,切勿自行编造:
    • 用户拒绝提供银行信息 → 省略 bank;脚本写入空白标记单元格并警告“银行信息缺失——请手动填写”;在报告中说明;
    • 无邮箱访问权限 → 仅使用用户放入 קבלות/ 中的文件;在报告中说明未搜索邮箱;在步骤 7 中打印邮件正文而非草拟邮件;
    • 无预算表 → 省略 budget;INTERNAL 文件在无预算表的情况下构建,且不与批准金额进行比较。

在报告中将每个模式 B 的缺口列在“需手动完成”部分。

1. 收集输入(只读)

  1. 已批准的预算。 打开会议文件夹中的旅行预算表 PDF(*טופס נסיעות*)。自行阅读;不同机构的表格可能不同。记录每项批准的金额(美元为单位)(每日津贴 אש״ל、机票 טיסה、酒店、保险、注册、其他)以及旅行日期。
  2. 个人资料。 按上述方式加载全名和银行信息(仅在首次询问)。
  3. 实体收据。 列出 קבלות/ 中的文件,并读取每张图片(如有 HEIC 格式,先转换,见步骤 3)。记录日期、提供商、金额、货币、信用卡末四位数字和用餐人数。
  4. 邮箱收据。 在预订日期到返回日期再加约两周的时间范围内搜索邮箱,并查找用户的旅行标签或文件夹。在一个轮次中一次性运行每个类别的查询——先阅读 references/email-sources.md。不要仅局限于用户列出的内容:发现未被注意到的费用是任务的一部分;对找到的每一项都向用户提出。
  5. 排除其他行程。 打开时间窗口内的每笔财务转账和每个航班预订,核对会议、路线和日期。在报告中记录每项排除原因。

2. 询问政策决策

仅询问适用的决策,每次一个问题,并将推荐选项放在首位。以下默认值来自一次过去的报销申请;它们是建议,并非机构规则。

  • 合住酒店预订 → 仅自己的房间(推荐)/ 整个预订。
  • 共享餐食 → 全部账单 / 仅自己的份额。将所选选项标记出来,供财务人员参考。
  • 汇率 → 返回日期的以色列银行代表性汇率,每种货币一个汇率(推荐)/ 每张收据日期对应的汇率。
  • 共享物品(一张涵盖两人的海报发票)→ 报销用户自己的份额,并附上说明。
  • 与机票一起购买的附加服务(座位、行李、保险)→ 归入机票一项(推荐)。

3. 将收据保存为 PDF

  1. 邮件附件。 如果邮件连接器返回了邮件正文但未返回附件,首先重新检查它现在是否能够获取附件;如果不行,通过浏览器自动化下载(打开邮件,点击附件的下载图标,然后将文件从 ~/Downloads 移到指定位置)。如果没有浏览器自动化,请用户自行下载附件或将其放入 קבלות/ 文件夹。
  2. 无附件的邮件(订单确认信)→ 打印为 PDF。
  3. 将每个文件命名为 <内容> <提供商> <单据号>.pdf,使用希伯来语。
  4. HEIC 照片 → 在原文件旁添加一个 PDF 副本,切勿修改原文件。macOS 使用命令:sips -s format pdf IN.heic --out IN.pdf。其他系统使用 pillow-heif 库(如已安装),否则请用户将照片导出为 PDF 或 JPEG 格式。 对于电子表格的收据工作表,还需将每张照片和截图转换为 JPEG 格式,以收据的基础文件名命名,保存在暂存区域(切勿覆盖原文件):sips -s format jpeg -s formatOptions 70 -Z 1400 IN --out "<收据基础文件名>.jpg"。
  5. 读取每个保存的 PDF。从文档本身获取金额,而非邮件文本。如果两者不一致,以文档为准并标记差异。

4. 构建电子表格

  1. 获取所选日期的以色列银行代表性汇率(boi.org.il),涵盖使用的所有外币。将日期填入 rates.label:שער יציג בנק ישראל, <dd.mm.yyyy>。切勿使用记忆中的汇率或此前报销申请中的汇率。

  2. 在暂存区域写入 spec JSON。Schema、布局和模式 B 行为请参考:references/spec-format.md;合成的实例请参考:references/example-spec.json。 从个人资料中设置 bank。省略 template:默认使用内置模板。

  3. 行规则:

    • 每一行对应一张收据,按日期排序;
    • 金额仅出现在一个键中:原始货币(usd、eur 或其他也在 rates 中的货币代码)或 ils;
    • receipt = קבלות/ 中的文件基础名称,多个文件用 + 连接;
    • note 解释任何财务人员可能质疑的内容(共享账单、半张发票、从酒店发票中拆分出的项目);
    • line = 预算行名称,拼写必须与 budget 中的完全一致;SENT 文件的 B 列显示此名称(仅分类,不要显示“咖啡”或“晚餐”之类的具体描述——财务人员看到的是批准分类),INTERNAL 文件的 סעיף 列和预算表也使用它;
    • service = 用希伯来语简短描述项目(“קפה”、“ארוחת ערב”、“רכבת שדה–עיר”);仅在 INTERNAL 文件的 B 列中显示(如果省略,则显示分类);
    • 餐食(包括会议晚宴)归入每日津贴一项;
    • 酒店账单中的餐厅费用应单独列为餐食行,酒店行金额相应减少。
    • receipt_images = 步骤 3 中生成的 JPEG 文件(仅本次行程的照片和截图)。它们将放入 קבלות 工作表,每行 5 张,每张图片下方有一个标题单元格,内容为其文件基础名称。通过邮件收到的 PDF 不嵌入电子表格;它们将放入步骤 7 的压缩包中。
  4. 运行:

    python3 -I "${CLAUDE_PLUGIN_ROOT}/skills/conference-reimbursement/scripts/build_claim.py" spec.json
    

    一次运行即可生成两个文件。它输出 JSON,包含 output(SENT 文件)、output_internal(INTERNAL 文件)、total_ILS、total_USD 和 warnings。修复所有关于预算行的警告;将模式 B 的警告一并写入报告。output_internal 默认路径是在 SENT 路径的文件名 .xlsx 前加上 - פנימי;仅在需要将本地副本放置在其他位置时,才在 spec 中设置它。

  5. 脚本拒绝覆盖任一输出文件,除非在 spec 中设置了 "overwrite": true。切勿对用户已手动编辑过的文件设置此选项;应写入新文件名或询问用户。

5. 验证

“完成”意味着已运行并检查过。先阅读 references/pitfalls.md。

  1. 运行检查:

    python3 -I "${CLAUDE_PLUGIN_ROOT}/skills/conference-reimbursement/scripts/check_claim.py" spec.json
    
    • total / total_internal:脚本的 Python 总金额等于 LibreOffice 重新计算后每个文件的 סה״כ בש״ח 单元格值(精确到 0.01 ₪),因此两个文件的总金额相同;
    • sent_no_budget:SENT 文件中不包含预算对比表;
    • receipts:每个引用的文件都存在于 קבלות/ 文件夹中;
    • budget:每一行的 line 都是预算行,且 INTERNAL 文件预算表中的实际总额等于 total_ILS / USD 汇率。

    对于标记为 not_run 的检查项目,报告为“未运行”,切勿报告为“已通过”。

  2. 独立审计:启动一个子代理,仅向其提供 SENT 电子表格和收据文件夹——不要提供你的结论。要求它检查每一行的金额、货币、日期和文件是否与收据一致,并列出发票员可能质疑的任何问题。修复真实错误;对其他问题仅作报告。

6. 报告

按以下顺序报告:

  1. 两个文件的路径(SENT:待附加;INTERNAL:仅本地)、行数、总 ₪ 和约等 USD 金额,并与批准总额进行比较。
  2. 新增的收据(以及哪些是通过搜索用户列表之外的途径发现的)。
  3. 使用的汇率,包括来源和日期。
  4. 超出预算的行,以表格形式列出:行名称、批准金额、实际金额、差异。
  5. 不同来源(邮件与文档)之间的差异。
  6. 排除项(属于其他行程的项目)。
  7. 财务人员标记(来自 references/pitfalls.md)。
  8. 需手动完成的部分(模式 B 的缺口、脚本警告)。
  9. 未经询问而做出的决策。

7. 草拟发送给财务联系人的邮件

先阅读 references/email-draft.md;按顺序执行。仅使用和附加 SENT 文件(output,<full name> הוצאות.xlsx);切勿附加、上传或引用 INTERNAL - פנימי 文件——email_summary.py 会拒绝它。简而言之:

  1. 阅读用户与财务联系人之前的报销沟通线程(已发送邮件,大约两年内,包含回复),并模仿其风格和主题模式。
  2. 询问:银行信息是否包含在邮件中;是否包含预算或汇率行(默认:都不包含);是否密送给同行旅伴(默认:否;切勿编造地址)。
  3. 运行 scripts/zip_ereceipts.py spec.json → 生成包含电子收据 PDF 的 קבלות אלקטרוניות.zip 压缩包(使用 UTF-8 文件名;切勿使用 macOS 的 zip 命令)。照片和截图已包含在 קבלות 工作表中。
  4. 运行 scripts/email_summary.py spec.json … → 生成 RTL HTML 正文(“היי ,” / “מה שלומך? :)” … “תודה רבה!”),包含一个汇总表,其中有一个“קבלה”列,标明每张收据的位置,以及从电子表格中读取的银行信息。
  5. 检查其 total_ILS 是否与构建步骤中的总额一致;如有 rounding_diff 则提及。
  6. 先调用 Gmail 的 create_draft,并传入 htmlBody。然后通过 Claude 在 Chrome 中附加 SENT 电子表格和压缩包(在草稿的撰写文件输入框上使用 file_upload 方法),并确认两个附件都已添加——连接器仅支持在调用中以 base64 形式传递附件,而 update_draft 会丢弃它们。切勿发送邮件。向用户提供草稿链接。

公式

  • 行金额:ILS_i = amount_i × rate[cur_i],如果已经是 ₪ 金额则直接使用。
  • 总金额:T = Σ ILS_i;美元金额为 T / rate[USD]。
  • 每个预算行 ℓ(INTERNAL 文件):actual_ℓ = Σ_{line_i = ℓ} ILS_i / rate[USD];diff_ℓ = approved_ℓ − actual_ℓ,负值表示超出预算。当每一行的 line 都在预算表中时,Σ_ℓ actual_ℓ = T / rate[USD]。

示例:汇率 USD 4.00,EUR 4.50;注册费 $500,酒店 €600,出租车 ₪200 → 2,000 + 2,700 + 200 = 4,900 ₪ = $1,225。

判断事项

  • 酒店自身的发票优先于预订网站的确认单(因为酒店发票是税务凭证)。
  • 银行信息来自本地个人资料,应放入 spec 的 bank 键中;脚本会按标签写入这些信息。仅通过 AskUserQuestion 工具询问银行信息,不要用散文形式询问,也不要复述这些信息。
  • 如果之前有部分报销属于本次行程,应将相关行标记为“已报销”。
  • 用户所在机构的规则决定政策问题;如有疑问应向用户提问,而不是自行假设规则。

参考资料

  • references/email-sources.md — 每个类别的邮箱查询内容和检查事项(步骤 1.4)。
  • references/spec-format.md — spec 键、两个文件的布局、脚本输出、模式 B 行为(步骤 4)。
  • references/example-spec.json — 合成的完整 spec 示例(步骤 4)。
  • references/pitfalls.md — 以前见过的失败案例和财务人员标记检查清单(步骤 5–6)。
  • references/email-draft.md — 邮件草稿:之前的通信线程、措辞、附件(步骤 7)。

相关技能