归档(07-28-travel-reimbursement-guide): 完成差旅报销与腾讯OCR任务

这个提交包含在:
2026-08-23 13:54:42 +08:00
父节点 bf3e1890c3
当前提交 e2d7e9d76a
共修改 7 个文件,包含 3 行新增和 3 行删除
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1,89 @@
# 技术设计
## 边界
本任务不开发新的 OCR provider,也不开放图片发票或改变审批流。在现有腾讯 provider 内把统一入口从 `VatInvoiceOCR` 改为 `RecognizeGeneralInvoice`,增加票种感知的安全归一化和上传大小门禁,再完成生产配置恢复、真实链路验证、差旅补助费用类型收口及两份既有业务文档更新。
生产配置写入、容器重建、腾讯 API 调用和真实样票上传均属于单独受控步骤;每一步只在前一步通过后继续。
## 配置与运行拓扑
- 生产环境文件继续作为 OCR 配置事实源。
- 凭证采用 OA OCR 专用的最小权限子用户密钥;不使用主账号永久密钥,不从聊天、仓库、日志、命令参数或历史残留复制。
- 用户在现场终端静默输入凭证。自动化只检查 provider、必要字段是否非空、文件权限和配置 smoke,不回显值或长度。
- 当前仅 server 执行 jobs,因此只重建 server,不启动 worker;重建后再次确认只有一个 OCR job executor。
- provider 从 `mock` 直接切换为 `tencent` 只能发生在服务开通、权限、计费状态和密钥均确认后。任一前置失败时保持禁止真实票据上传,不用 mock 代替真实能力。
- 计费只使用 `RecognizeGeneralInvoice` 对应的通用票据识别(高级版)每月 1,000 次专用免费包,不接独立火车票接口。生产固定中国大陆地域;控制台确认免费包已到账、后付费关闭,并配置费用或余额告警。免费包耗尽时服务失败关闭,应用记录额度类可解释终态,不自动付费续用。
### 生产部署根收敛
- 生产只读核验发现,活动 Compose 的工作目录被错误设置成标准部署根下的 `deploy/trialrun` 子目录,导致仓库再次同步到自身子目录,形成重复的 `deploy/trialrun/deploy/trialrun`。活动 server、环境文件和四个 systemd 运维 timer 均已引用该嵌套拓扑,因此它不是可直接删除的闲置副本。
- 本次发布把部署根收敛回 deploy 脚本约定的标准单层根。迁移窗口开始时先暂停相关 timer,将当前活动根原子改名为时间戳回退目录,再创建干净标准根;不在原目录上用 `rsync --delete` 就地清理,以免同时破坏活动配置与回退证据。
- 从回退目录把生产环境文件复制到标准根的预期相对位置,保持所有者和 `0600` 权限,不读取、打印或经本地中转 Secret。数据库和附件继续使用部署根之外的既有宿主目录,不搬迁、不初始化、不重置。
- 使用同一 Compose project 和已批准提交部署 server;数据库容器与数据卷保持原位,不创建 worker。部署后重新安装自动备份 daily/watchdog/drill-reminder 与 WARCH3 timer,使所有 WorkingDirectory、ExecStart 和环境文件引用只指向标准根。
- 验收包括活动 Compose 工作目录不再重复、环境文件唯一受控、server `/ready` 和构建标识正确、provider 为 `tencent`、仅一个 job executor、四个 timer 启用且各自 dry/status 检查通过。旧根作为短期回退保留,本任务不删除;后续删除需在新备份成功且另行批准后执行。
## 腾讯 API 合同
- API:`RecognizeGeneralInvoice`,版本 `2018-11-19`,由当前腾讯 Node SDK 调用。
- PDF 请求:Base64、第一页、关闭多页、切图、坐标、二维码和印章返回。
- 一份 PDF 只允许解析出一张受支持票据;零张、多张、未知或不支持子类型进入明确失败状态。
- 支持子类型按两族归一化:住宿 VAT/电子普通发票;电子发票(铁路电子客票)。
- 质量门禁按 `documentSubtype` 选择必填字段;无代码电子票据不再伪造发票代码。
- `OcrResult.result_json` 仅保存规范化业务字段和安全元数据,不保存 provider 原始响应或乘车人身份字段。
- PDF 原文件上限为 7MiB,使 Base64 后保持在腾讯 10M 上限内;大小错误在上传阶段阻断。
## 验证数据流
1. 用户在腾讯云控制台确认通用票据识别(高级版)每月免费包已到账、中国大陆地域、后付费关闭和费用/余额告警。
2. 用户创建或轮换 OA OCR 专用子用户密钥,并确认 OCR 服务可用。
3. 用户在现场终端把 provider、密钥和地域写入生产受控环境文件。
4. 重建 server,使新配置进入实际运行进程。
5. 运行外部依赖 smoke、运行时 smoke、`/ready`、构建标识和 job 拓扑检查。
6. 经样票单独授权后,通过现有 PDF 发票入口分别上传住宿电子普通发票和铁路电子客票样票。
7. 只记录 provider、状态、尝试/完成证据和脱敏字段命中摘要;不记录票面、完整字段或原始 payload。
8. 正常清理或归档测试业务记录,再允许杨俊提交真实票据。
### 授权样票验证工具边界
- 既有 `check-ocr-provider-samples.mjs` 必须与生产 adapter 使用同一 `RecognizeGeneralInvoice` 入口和按票种必填字段规则,不得继续引用已删除的 VAT-only 导出或把铁路电子客票套入 VAT 五字段门禁。
- 真实 PDF 从本地受控、Git 忽略的样票目录按匿名别名选择,经 SSH 标准输入直接流入生产 server 容器内存;不得把原件、临时副本或 manifest 写入远端磁盘、OA 附件存储、数据库、仓库或报告。
- 每个进程只接收一份 PDF,验证文件签名和 7MiB 上限后最多调用一次 `RecognizeGeneralInvoice`。住宿与铁路样票分两次执行,任一失败立即停止,不自动遍历目录中的其他文件。
- 输出只允许匿名别名、provider、票种、安全传输模式、耗时、字段命中布尔值、缺字段名和稳定错误码;不得输出文件名、原始响应、识别值、人员/企业名称、票号、金额或票面内容。
- live runner 的代码、合成测试和生产部署先通过,再单独取得两次真实 API 调用批准;工具可用不等于真实样票已验证。
- 当铁路票已被腾讯识别但金额缺失时,适配器可生成仅供 live runner 使用的临时字段形态诊断:只包含 `Total`/`Fare` 是否存在、是否为字符串或数字、是否非空及能否被当前金额解析器接受的布尔值。诊断不得携带字段值,必须在持久化白名单处被丢弃,普通 OCR job、缓存和数据库均不得保存。
- 字段形态诊断先用合成 provider 响应证明不输出金额或原始 payload,再部署;真实调用仍受单次授权和“铁路未 PASS 即停止住宿”约束。
## 文档口径
- `docs/员工快速上手.md` 增加一页式差旅报销步骤:火车票和住宿费拆明细,官方 PDF 绑定对应明细,两类费用均附支付截图,金额差异必须说明,提交后进入主管和财务流程。
- `docs/报销发票附件规则.md` 固化支付证明必交、敏感字段遮挡、退款/代付/优惠差异和无截图例外口径。
- OCR 结果仅辅助识别和查重;财务仍核对明细、PDF 原件和个人支付证明。
## 差旅补助与费用类型
- `travel_bus` 已由差旅行程 `transport_type=bus` 自动映射,业务语义是城际“大巴”;将其显示名收口为“大巴车票”,不得复用为市内交通补助。
- `travel_meal` 保留代码并将显示名收口为“伙食补助费”;新增 `travel_local_transport_allowance`,显示名为“市内交通补助费”。生产当前两类既有费用均无历史报销明细,种子脚本按代码幂等更新名称和新增类型。
- 伙食补助费为 100 元/人/天,市内交通补助费为 80 元/人/天,均按自然日包干且不要求发票;直接承担、重复报销和个人延长天数按 PRD 规则处理。
- 当前 `ReimbursementItem` 没有天数或数量字段,`ExpenseStandard.per_unit=day` 也不会在费用控制中乘以天数。因此本轮不创建 100/80 元 block 或 warn 标准,员工分别新增补助明细,以“天数 × 单价”人工算出总额并在说明写明计算式,由主管和财务复核。
- 自动带出差旅起止日、计算符合条件的补助天数以及按天校验属于后续产品能力,不阻塞本次真实报销。
## 报销附件上传与中文文件名
- 生产复现显示 PC 一次发送多个补充附件时触发 `FST_FILES_LIMIT`:全局 multipart 合同为 `files=1`,而报销附件路由、PC/手机页面和既有测试均按多文件设计。测试曾把全局上限改成 5,掩盖了生产差异。
- 保持全局 `files=1`,仅在报销附件 `request.parts()` 调用传入 `limits.files=5` 和既有文件大小限制;捕获 `FST_FILES_LIMIT` 并映射为 `VALID_001 / file=too_many_files`。
- 客户端共享 `MAX_REIMBURSEMENT_ATTACHMENT_FILES=5`,PC 与手机选择后先拦截超限并显示相同提示;API 仍接受数组,单次请求最多 5 个。
- 生产还复现了中文附件打开失败:原实现仅替换 CR/LF/引号,仍把中文直接放进 `filename="..."`,Node 以 `ERR_INVALID_CHAR` 拒绝响应头。
- 把现有采购附件的安全 Content-Disposition 构造能力提炼/扩展为可选 `attachment` 或 `inline` 处置类型,生成安全 ASCII `filename` 与 RFC 5987 UTF-8 `filename*`。报销附件与发票 PDF 使用 `inline`;采购、回单等既有 `attachment` 调用保持不变。
- 不改变文件原名在数据库中的业务展示值,不重写已上传文件;修复部署后既有中文名附件即可正常打开。
## 失败与回退
- adapter 聚焦测试、配置 smoke、腾讯调用或任一真实样票验证失败:停止开放真实票据,不继续制造 pending/retry 数据。
- 若新配置导致运行异常,恢复变更前环境文件的受控副本并重建同一 server;回退后不得使用 mock 处理真实票据。
- 若标准根部署、timer 重装或健康检查失败,停止继续发布,将 Compose 工作目录和 systemd unit 恢复到时间戳回退根并重建原 server;数据库和附件目录不参与回退切换。
- 样票失败记录使用可解释状态和脱敏摘要,不直接修改数据库字段绕过状态机。
## 历史凭证结论
2026 年 5 月的证据能证明真实腾讯 OCR 曾可用,但不能证明当时密钥仍有效或满足当前最小权限。当前生产机、历史容器、同机旧环境文件、开发机环境文件及 shell 历史均无可恢复凭证;数据库/附件备份也不包含环境密钥。因此本任务不设计“从旧部署复制密钥”的路径。
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1,178 @@
# 实施计划
## 1. 外部前置门禁
- [x] 用户确认采用 OA OCR 专用最小权限子用户密钥。
- [x] 用户在腾讯云侧创建该专用子用户和密钥。
- [x] 在实际账号确认通用票据识别(高级版)每月 1,000 次专用免费包已到账,生产配置使用中国大陆地域。
- [x] 在 OCR 控制台设置页确认后付费关闭;额度耗尽时接受 OCR 失败关闭。
- [x] 用户在腾讯云控制台配置并启用费用或余额告警作为二次兜底;任务只记录启用状态,不记录阈值、接收人或账户信息。
- [x] 腾讯 OCR 服务和 `ocr:RecognizeGeneralInvoice` 最小权限已通过生产 smoke 与两类真实样票验证,不接独立火车票接口。
- [x] 住宿电子普通发票和铁路电子客票各一份 PDF 的测试授权、仓库外受控位置和脱敏调用均已完成;票据未进入 Codex、聊天或仓库。
## 2. 腾讯 adapter 修正
- [x] 将现有腾讯调用改为 `RecognizeGeneralInvoice`,固定单页 PDF 和最小返回选项。
- [x] 分别归一化住宿 VAT/电子普通发票和 `ElectronicTrainTicketFull`。
- [x] 按安全票种标识执行必填字段检查;删除代码/号码互相伪回填。
- [x] 不持久化腾讯原始响应、乘车人姓名、证件号或完整票面字段;命中旧版腾讯缓存时按同一白名单压缩。
- [x] 发票上传增加 7MiB OCR 输入上限和明确错误。
- [x] 增加两类票种、无代码、多票/不支持票据、敏感字段、大小门禁和 provider 错误聚焦测试。
## 3. 生产配置
- [x] 对当前生产环境文件制作受控、限权、短期回退副本,不输出内容。
- [x] 由用户在现场终端静默写入 `OCR_PROVIDER=tencent` 及专用凭证;地域设置为中国大陆地域。
- [x] 脱敏检查 provider、凭证非空、环境文件权限和配置合同。
- [x] 仅重建实际执行 jobs 的 server,不启动独立 worker。
### 3.1 生产部署根收敛
- [x] 只读确认活动 Compose、生产环境文件和四个运维 timer 均引用重复嵌套部署根。
- [x] 暂停相关 timer,将活动根原子改名为时间戳回退目录,并建立干净标准单层部署根。
- [x] 把生产环境文件在远端复制到标准相对位置,保持所有者和 `0600` 权限;不回显或经本地传输 Secret。
- [x] 使用 `DEPLOY_DATA_MODE=existing`、既有外置数据库/附件宿主目录和同一 Compose project 发布批准提交;未初始化数据或创建 worker。
- [x] 重新安装 daily、watchdog、drill-reminder 和 WARCH3 timer,确认 unit 不再引用重复目录。
- [x] 验证 `/ready`、构建标识、单一 job executor、四个 timer 状态和一次受控备份/新鲜度检查;旧根仅保留作短期回退,不在本任务删除。
回退点:标准根发布或任一 timer 验收失败,恢复时间戳回退根及原 unit 引用并重建原 server;数据库和附件宿主目录不移动、不重置。
回退点:外部依赖 smoke 前若任一配置门禁失败,恢复变更前环境文件并重建 server;保持真实票据禁止上传。
## 4. 生产与真实能力验证
- [x] 检查公网 `/ready` 和预期构建标识。
- [x] 在 server 内运行现有 external deps 和运行时 smoke,不输出 Secret 或原始响应。
- [x] 确认实际 provider 为 `tencent`,且只有一个 OCR job executor。
- [x] 修正 live 样票脚本:复用 `RecognizeGeneralInvoice`、按票种必填字段和安全持久化白名单,支持单 PDF 标准输入且仅输出脱敏摘要。
- [x] 使用合成 PDF/provider 响应覆盖住宿、铁路、非 PDF、超限、缺字段和原始响应不输出,并完成本地门禁、提交和生产部署。
- [x] 为铁路 `Total`/`Fare` 增加只含存在、类型、非空和可解析布尔值的临时诊断;证明持久化白名单丢弃诊断且 live runner 不输出真实值。
- [x] 完成本地门禁、提交和生产部署后,使用剩余一次授权诊断铁路金额字段;铁路未 PASS 时仍不调用住宿样票。
- [x] 修正铁路空 `Total` 阻断可解析 `Fare` 回退的问题,增加回归测试并完成提交、生产部署与运行身份复核。
- [x] 经新增授权复验铁路票;仅在铁路 PASS 后调用住宿票,总计最多两次腾讯 OCR 调用。
- [x] 经单独样票批准后分别运行住宿电子普通发票和铁路电子客票 live OCR PDF 验收。
- [x] 只保存脱敏状态、耗时、provider 和字段命中摘要;确认不存在 mock 调用证据。
- [x] 探针未写入 OA、数据库或远端样票文件;完成只读残留检查,无需清理业务记录。
回退点:真实调用失败时停止样票和真实票据上传,保留可解释失败摘要;不得改库伪造成功或切回 mock 处理真实票据。
## 5. 文档更新
- [x] 更新 `docs/员工快速上手.md` 的差旅报销一页指南。
- [x] 更新 `docs/报销发票附件规则.md` 的支付截图、实报实销差异、退款/代付和人工复核规则。
- [x] 不新建平行员工指南,不写入真实票据、支付信息、账号或环境路径。
## 5.1 差旅补助规定落地
- [x] 修正 `travel_bus` 显示名为“大巴车票”,修正 `travel_meal` 显示名为“伙食补助费”,新增 `travel_local_transport_allowance` / “市内交通补助费”。
- [x] 增加聚焦测试,锁定城际大巴映射和两项补助费用类型不混用。
- [x] 更新员工指南和报销事实源,写明 100 元/天伙食补助、80 元/天市内交通补助、自然日、包干、直接承担、个人延长和其他费用实报实销规则。
- [x] 明确当前由员工按“天数 × 单价”人工填写总额;不配置会误判多日补助的单条费用标准。
- [x] 重新生成并检查一页版差旅报销 PDF。
## 5.2 真实首笔报销附件阻断修复
- [x] 报销附件路由显式支持单次最多 5 个文件,并稳定映射 `FST_FILES_LIMIT`。
- [x] PC/手机共享最多 5 个文件的选择限制、提示和客户端拦截。
- [x] 报销附件与发票 PDF 使用安全 ASCII fallback + RFC 5987 UTF-8 文件名响应头。
- [x] 测试恢复生产全局 `files=1`,覆盖路由级 5 个成功、6 个失败、中文名及头注入清理。
- [x] 完成后端、前端、流程、文档、敏感内容和 Trellis 门禁;提交后另行取得生产部署批准。
## 2026-07-30 报销附件阻断修复验证
- 生产日志根因已由聚焦回归锁定:PC 多文件请求触发全局 `FST_FILES_LIMIT`,中文原名直接进入响应头触发 `ERR_INVALID_CHAR`;手机并非独立后端链路。
- 报销附件路由保持生产全局 `files=1` 基线并局部覆盖为 5;第 6 个文件返回 `400 VALID_001 / too_many_files`,且附件和审计写入均为 0。
- 报销附件与发票 PDF 已统一使用安全 `inline` Content-Disposition;采购、员工附件和付款回单仍保持默认 `attachment`。
- 聚焦测试 3 个文件/47 项、后端全量 169 个文件/1082 项、Prisma validate、前端 typecheck/build、流程合同、文档审计、Trellis governance、敏感内容、task validate 与 `git diff --check` 均通过;文档审计仅保留 22 个既有未注册文档 warning。
- 本地验证检查点时主修复已提交为 `7341538`,但尚未推送或部署;后续生产结果见下节,PC/手机真实验收仍不得由代码门禁替代。
## 2026-07-30 报销附件修复生产部署
- 主修复 `7341538` 与提示修正 `030cf46` 已推送;生产来源提交为 `030cf46c92bd`,来源、环境契约和远端 Compose 配置门禁通过,未同步或覆盖生产 `.env`。
- 标准构建首次停在 Alpine 基础包下载且尚未执行 init、迁移或服务切换;确认旧服务仍以原构建正常提供 `/ready` 后终止未完成构建,改用同一 Dockerfile、同一构建参数和宿主网络完成镜像构建,再执行受控 init 与 `--no-build` 切换。
- Prisma 62 个迁移均为最新;配置种子保留 3 条既有审批规则,未重置管理员密码。external deps、runtime smoke、公网 `/ready`、12 位构建标识和前端资源扫描均通过。
- 运行拓扑保持单一 server 执行 jobs、无 worker;OCR provider 仍为腾讯。四个自动备份/WARCH3 timer 已刷新到新完整构建并保持 enabled/active。
- 首次主动备份因 automatic-backup unit 仍引用旧构建而被 runtime identity 守卫拒绝;刷新 unit 后重新执行配对备份与新鲜度检查均成功,未放宽守卫或绕过校验。
- 代码部署与公网检查已完成,但真实业务验收仍待杨俊在 PC 端一次上传多个附件并打开中文名附件;该人工验收通过前,不把两个现场问题标记为最终关闭。
## 6. 验证与审查
- [x] 静态核对页面/API 上传格式、明细绑定和员工/财务字段边界。
- [x] 运行腾讯 adapter、OCR service/job 和发票上传聚焦测试。
- [x] `cd server && npm run prisma:validate`
- [x] `node scripts/qa/check-process-contract.mjs --baseline --json`
- [x] `node scripts/qa/audit-docs.mjs --check-registry`(0 个错误;22 个既有未注册文档 warning,本任务未新增)
- [x] `node scripts/qa/check-trellis-governance.mjs`
- [x] `git diff --check`
- [x] 对生产配置、样票证据和文档口径进行只读复核。
- [x] 部署与公网检查均通过后,才通知杨俊可以提交真实差旅报销。
## 2026-07-29 live OCR 验收工具生产部署记录
- 已部署提交 `fa326f9`;公网 `/ready` 与运行容器构建标识一致。
- external deps smoke、runtime smoke 和公网前端资源扫描通过;实际 OCR provider 为 `tencent`。
- 运行拓扑为 server 单一 job executor,未启动 worker。
- 自动备份 daily、watchdog、drill-reminder 与 WARCH3 四个 timer 均为 enabled/active,冻结构建与标准部署根一致,未引用旧重复目录。
- 部署后受控自动备份和新鲜度检查均成功,未调用真实 OCR 样票。
- 真实住宿和铁路样票验收仍等待单独调用授权;在两类样票通过前,不通知员工上传真实票据。
## 2026-07-29 授权样票验收尝试
- 已匿名选择铁路 PDF 并执行最多一次 provider 调用,但外层 shell 在探针非零退出时提前终止,未保留已生成的脱敏 JSON,因此本次不能作为 PASS 或可解释 provider 终态证据。
- 按“第一份未取得明确 PASS 即停止”约束,未调用住宿样票,也未重试铁路样票。
- 空 stdin 捕获自检证明修正后的调用方式可在 provider 调用前保留 `HOLD/sample_empty` 摘要;该自检未消耗 OCR 次数。
- 本次没有创建 OA 发票、附件或数据库记录;真实样票仍未验收通过,员工上传门禁保持关闭。
- 经额外授权后,修正包装器重新验收铁路 PDF,明确得到 `HOLD/sample_pdf_invalid`;失败发生在 provider 调用前,本次未消耗腾讯 OCR 次数。
- 匿名结构预检确认铁路 PDF 的 EOF 后存在非空白尾随数据,不符合现行严格 PDF 终止边界;不截断原件、不放宽安全门禁,需重新取得官方原始电子票据。
- 住宿 PDF 的 PDF 头部、EOF 终止边界和 7 MiB 上限预检均通过,但因铁路票未 PASS,未调用住宿样票 provider。
- 用户另行指定的铁路 PDF 通过同一结构预检,证明上一份 `sample_pdf_invalid` 是旧文件特有的 EOF 尾随数据问题,不是所有铁路 PDF 或校验器普遍失败。
- 新铁路 PDF 经真实腾讯 OCR 识别为单张 `ElectronicTrainTicketFull`,票号、日期和购买方字段命中,但 `totalAmount` 未命中,终态为 `HOLD/missing_required_fields:totalAmount`;未输出或持久化任何识别值、原始响应或票面字段。
- 当前适配器已按腾讯 SDK 合同读取铁路票 `Total` 与 `Fare` 两个金额字段;现有脱敏摘要不能区分 provider 未返回金额与返回值格式不可解析,需在另行批准后增加字段形态布尔诊断。铁路票未 PASS,因此仍未调用住宿样票 provider。
## 2026-07-29 铁路金额字段诊断实现验证
- 聚焦测试 19 项、完整后端 168 个文件/1075 项、Prisma validate、前端 typecheck/build、流程合同、Trellis governance、敏感内容和 diff 门禁通过;仅有既有依赖弃用提示与 22 个既有未注册文档 warning。
- P2 聚合器的后端聚焦测试 94 项及前端门禁通过;其业务流因合成账号首次改密状态失败,live-readiness 因本地旧凭据和部署前构建标识不一致失败。进入 live OCR 步骤时已主动终止,生产最近 10 分钟新增发票和 OCR 尝试记录均为 0。
- 诊断只存在于 provider 返回到 live runner 的进程内对象,持久化 sanitizer 丢弃整个 diagnostics;合成敏感标记未出现在序列化摘要中。
- 诊断提交 `5f2788c` 已部署;公网构建、external deps、runtime smoke、单一 job executor、四个 timer、自动备份和新鲜度检查均通过。
- 最后一次授权调用确认腾讯返回的铁路 `Total` 是空字符串,而 `Fare` 非空且可被当前解析器接受。现有 `info?.Total ?? info?.Fare` 在解析前选择空字符串,阻断了 `Fare` 回退;根因是适配器空字符串回退顺序,不是 PDF、凭证、网络或腾讯票种识别失败。
- 本次仍为 `HOLD/missing_required_fields:totalAmount`,住宿样票未调用;所有既有真实 OCR 调用授权已用尽,修复后复验必须重新取得授权。
- 已将铁路金额改为分别解析 `Total` 与 `Fare` 后回退,并增加“空 `Total` + 可解析 `Fare`”回归测试;聚焦测试 10 项、Prisma validate、流程合同、Trellis governance、敏感内容和 task validate 均通过。
- 已在现有 OCR code-spec 固化同类字段回退规则和测试要求;本轮尚未提交、部署或调用腾讯 OCR。
## 2026-07-29 铁路金额修复与双样票验收
- 修复提交 `665cf4a` 已推送并部署;迁移状态、`/ready`、external deps、runtime smoke 和公网资源扫描通过,公网构建标识一致,生产 provider 为 `tencent`,仅一个 server 执行 jobs,未启动 worker。
- 自动备份 daily、watchdog、drill-reminder 与 WARCH3 四个 timer 已刷新到当前构建并保持 enabled/active;主动自动备份与新鲜度检查均成功。
- 通过标准输入运行的铁路样票明确 `PASS`:票种为铁路电子客票,号码、日期、金额和购买方必填字段命中;空 `Total` 未再阻断可解析 `Fare`,无缺失必填字段。
- 仅在铁路通过后运行住宿样票并明确 `PASS`:票种为数电发票,号码、日期、金额、税额、价税合计、销售方和购买方字段命中,无缺失必填字段。
- 两次授权腾讯 OCR 调用已全部用完。输出仅保留匿名 alias、票种和字段命中布尔值;两次探针均未创建 OA 发票或 OCR 数据,最近 30 分钟对应新增记录为 `0/0`,无需业务数据清理。
## 2026-07-29 差旅补助规定实施验证
- 已把城际大巴、伙食补助和市内交通补助收口为三个独立稳定代码;种子聚焦测试证明按代码幂等更新/创建,不配置 100/80 元单条费用标准。
- 员工指南与报销事实源已写明两项补助单价、自然日、包干、直接承担不重复领取、个人延长不计补助和人工算式要求;单页 PDF 已重新生成并完成视觉检查。
- 聚焦测试 3 个文件/17 项、后端全量 168 个文件/1077 项、Prisma validate、流程合同、文档审计、Trellis governance、敏感内容、task validate、Node 语法和 `git diff --check` 均通过;文档审计仅保留 22 个既有未注册文档 warning。
- 本地实施不等于生产费用类型已变更;生产落地结果见下节记录。
## 2026-07-29 差旅补助规定生产部署
- 提交 `13a3f4b` 已推送并部署;来源校验、环境契约、迁移状态、external deps、runtime smoke、公网 `/ready`、构建标识和前端资源扫描均通过。
- 标准 Compose 构建首次停在 Alpine 基础包下载,旧 server 始终保持可用;终止未完成构建后使用同一 Dockerfile、同一构建参数和宿主网络成功构建,再完成受控切换。
- 为遵守“定向费用类型写入”授权,本次未运行会改写其他主数据的全量 `seed:config` / `seed:trialrun`;通过受限 Prisma 包装器只执行 3 次目标 upsert。
- 生产只读核验确认“大巴车票”“伙食补助费”“市内交通补助费”三个独立费用类型均 enabled,相关 active 费用标准为 0,未引入多日补助误报。
- 运行拓扑为一个 server 执行 jobs、无 worker,OCR provider 为 `tencent`;自动备份 daily/watchdog/drill-reminder 与 WARCH3 四个 timer 已刷新冻结构建并保持 enabled/active。
- 员工指南、真实 OCR 和生产费用类型已对齐,杨俊可以从企业微信工作台进入并按四类明细创建真实差旅报销;实际提交仍由本人完成。
## 风险文件与操作
- 生产环境文件:包含 Secret,只允许用户现场静默输入;不得由补丁、聊天或命令参数传入。
- server 重建:短暂影响 OA;仅操作当前实际 server,保留回退配置。
- 真实样票:包含发票和个人/企业信息;只留在仓库外受控位置。
- 文档:员工指南必须短且与生产费用类型、PDF-only 和附件入口一致,避免把财务付款回单误写成员工材料。
## 2026-08-23 腾讯云费用告警收口
- 用户确认腾讯云费用或余额告警已经启用;未向 Codex 提供控制台登录态、二维码、阈值、接收人、账户余额或截图。
- 结合此前已确认的高级版免费包、中国大陆地域和后付费关闭,腾讯 OCR 费用控制闭环完成;额度耗尽继续按既有合同失败关闭,不自动产生后付费。
- 本步骤未进入腾讯云登录态,未修改 OA 生产配置、代码、数据库或真实业务数据。
@@ -0,0 +1,104 @@
# 差旅报销指南与腾讯 OCR 正式启用
## Goal
先把生产发票识别从 mock 切换到真实腾讯 OCR 并取得授权样票证据,再让杨俊及后续员工一次看懂差旅报销需要提交什么、分别上传到哪里、差旅补助如何计算,以及财务如何按“明细—发票—个人支付证明”复核。
## Background
- 当前报销单明细包含费用类型、发生日期、金额和说明;发票绑定到具体明细,补充附件属于整张报销单。
- 发票入口只接受 PDF;补充附件接受 PDF、JPG、PNG、WebP,可用于支付截图、订单和情况说明。
- 员工不填写财务付款凭证号、付款日期或付款渠道;这些字段属于审批通过后的财务处理。
- 生产已有 37 个 active 费用类型,其中“火车票”“住宿费”“机票”“打车费”“差旅餐补”各唯一存在;当前 active 费用标准为 0,不会自动执行金额上限。
- 用户已决定:火车票和住宿费均要求员工提交个人支付截图。
- 生产只读核验发现当前运行配置为 `OCR_PROVIDER=mock`,`TENCENT_SECRET_ID` 和 `TENCENT_SECRET_KEY` 均未配置;server 自身运行 jobs,当前没有独立 worker。
- 2026-05-05 的试运行证据证明生产腾讯 OCR 当时曾通过真实 PDF 验证;但当前生产环境、同机历史环境文件、已停止应用容器、开发机环境文件和 shell 历史均没有可恢复的旧腾讯密钥。现有自动备份只覆盖数据库和附件,不覆盖环境密钥,因此不能从备份恢复该凭证。
- 官方 API 和当前实现复核发现:现有腾讯 adapter 调用 `VatInvoiceOCR`,适合住宿增值税/电子普通发票,但不是统一覆盖电子发票(铁路电子客票)的推荐接口。官方 `RecognizeGeneralInvoice` 同时覆盖住宿常见 VAT 子类型和 `ElectronicTrainTicketFull`,当前锁定 SDK 已支持该方法。
- 当前实现会对所有票据强制要求发票代码和销售方,并在代码/号码缺失时互相回填;铁路电子客票及部分数电票会被误判失败或污染查重语义。现有 `raw` 结果还会持久化腾讯完整响应,铁路票返回可能包含乘车人证件信息。
- 腾讯要求文件 Base64 编码后不超过 10M,现有 OA 允许 10MiB 原始 PDF,存在上传成功后 OCR 必然超限的区间。
- 用户决定不接受 `off` 人工模式,要求配置并正式启用真实 OCR;在凭证配置和授权样票验证通过前,杨俊不得上传真实发票。
- 用户已确认采用推荐的凭证方案:在腾讯云创建或轮换 OA OCR 专用最小权限子用户密钥,并由用户在现场终端静默写入生产。
## Scope
- 核对报销明细、PDF 发票、补充附件、支付截图和财务付款记录的实际页面/API边界。
- 更新 `docs/员工快速上手.md`,增加一页可直接照做的差旅报销指南。
- 更新 `docs/报销发票附件规则.md`,固化火车票/住宿费支付证明、实报实销和 OCR 关闭期间人工核对规则。
- 配置并正式启用生产腾讯 OCR,完成配置门禁、受控发布、公网检查和授权 PDF 样票验证。
- 在现有腾讯 provider 内改用通用票据识别高级版,补齐住宿电子普通发票和铁路电子客票的安全归一化、质量门禁、大小限制和测试。
- 固化公司差旅补助规定,补齐不与城际大巴费用混淆的费用类型,并同步员工指南和报销事实源。
- 修复真实首笔报销暴露的 PC 多附件上传与中文文件名打开失败,保持 PC/手机和生产 multipart 合同一致。
## Requirements
- 火车票与住宿费必须拆为两条报销明细;每条分别填写费用类型、发生日期、实际合规金额和事由说明。
- 正式电子票据/发票使用官方 PDF,通过对应明细的“添加发票”入口上传并绑定;截图不得冒充正式发票。
- 火车票和住宿费的个人支付截图通过“附件材料/补充附件”上传,并用文件名或说明明确对应哪条明细。
- 支付截图仅保留商户、金额、时间和支付成功状态;银行卡号、支付账号、订单号等无关敏感字段应遮挡。
- 报销金额以个人实际支付的合规金额为准,原则上不得超过有效发票金额;优惠券、多人合并开票、部分自费或其他差异必须在明细中说明。
- 已退款、公司直接支付或他人承担的金额不得重复报销;确实无法提供支付截图时写情况说明,由财务决定退回或例外接受,不得伪造凭证。
- 腾讯 OCR 识别字段用于匹配、查重和财务复核,但不替代支付真实性、费用合理性或发票法律状态的人工判断;财务仍核对明细金额、PDF 原件和支付证明。
- 腾讯 provider 使用 `RecognizeGeneralInvoice`,每份 PDF 只识别第一页且只接受一张受支持票据;不请求切图、字段坐标、二维码或印章数据。
- 住宿 VAT/电子普通发票与铁路电子客票按各自官方返回结构归一化;铁路电子客票不强制要求不存在的发票代码或销售方,不得用发票号码伪造代码。
- 持久化结果只保留业务需要的规范化字段、安全票种标识和传输模式,不保存腾讯原始响应、乘车人姓名、证件号或完整票面字段。
- 正式 PDF 发票增加不高于 7MiB 的 OCR 输入门禁,避免 Base64 后超过腾讯 10M 限制;超限在上传阶段给出明确提示,不进入重试队列。
- 腾讯云凭证使用最小权限子用户或专用身份,不使用主账号永久密钥;凭证只通过用户现场终端写入生产受控环境文件,不进入聊天、命令参数、日志、仓库或 Trellis。
- 不复用来源、权限或有效性无法确认的历史密钥;优先在腾讯云侧为 OA OCR 创建或轮换专用子用户密钥,并撤销确认不再使用的旧密钥。
- 正式启用前需确认 OCR 服务已开通、调用费用/免费额度和告警边界;无凭证、权限不足、欠费或 API 未开通均不得把 provider 切成 `tencent`。
- 只使用 `RecognizeGeneralInvoice` 的通用票据识别(高级版)每月 1,000 次专用免费额度,不接仅老客户续费的独立火车票接口;生产使用中国大陆地域,必须在实际账号确认免费包到账、关闭后付费并配置费用或余额告警。额度耗尽时允许 OCR 明确失败,不得自动产生费用。
- 当前无独立 worker 且 server 自身运行 jobs,配置变更只重建实际加载配置的 server;不得额外启动第二个 OCR job executor。
- 真实能力必须使用已授权 PDF 样票验证;缺少授权样票只能证明配置齐全,不能宣称真实 OCR 已通过。
- 指南明确审批链:员工提交、直属主管审批、财务复核;财务付款和回单不由员工预填。
- 伙食补助费按 100 元/人/天包干,市内交通补助费按 80 元/人/天包干;两项补助均不要求发票。
- 补助按出差自然日计算,出发日和返回日均计 1 天,当天往返计 1 天;因个人原因延长的天数不计补助。
- 领取伙食补助后个人餐费不得另报;领取市内交通补助后,出差期间公交、地铁、出租车、网约车等不得另报。
- 公司或其他单位已直接承担餐食或车辆费用的,不重复领取相应补助;城际交通、住宿及其他经批准的必要差旅费用凭有效材料实报实销。
- 当前报销明细没有天数字段,两项补助分别作为独立明细人工填写总额和计算式,例如“伙食补助费:3 天 × 100 元”;不得把现有 `per_unit=day` 费用标准直接配置为 100/80 元,因为当前校验不会按天数乘算,会误判多日补助。
- `travel_bus` 保留为城际大巴车票费用;市内交通补助使用独立费用类型,不得共用代码或混同展示。
- 报销补充附件在 PC 与手机端均允许单次选择 1–5 个文件;服务端必须在该路由显式覆盖全局单文件 multipart 上限,第 6 个文件进入稳定的 `VALID_001` 错误,不得退化成 `SYS_001`。
- PC 与手机选择器均显示“单次最多 5 个”,并在请求前拦截超过 5 个文件的选择;客户端限制只改善体验,服务端仍是最终边界。
- 报销附件和发票 PDF 的中文原文件名不得直接进入 HTTP 响应头;`Content-Disposition` 使用安全 ASCII fallback 与 RFC 5987 `filename*`,同时清理控制字符、路径和响应头注入字符。
- 报销附件继续使用 `inline` 语义,发票 PDF 继续支持当前预览/下载流程;修复不得改变附件权限、用途留痕、审计或存储内容。
- 文档不放真实票据、支付截图、账号、订单号、银行信息或完整业务数据。
## Acceptance Criteria
- [x] 员工指南能在一页内回答“交什么、传到哪里、金额怎么填、哪些材料不能混传、提交后谁处理”。
- [x] 指南内容与当前页面、服务端格式限制及生产费用类型一致。
- [x] 业务事实源明确火车票和住宿费支付截图为必交补充材料,并包含遮挡、差异、退款和无截图例外规则。
- [x] 腾讯 adapter 使用 `RecognizeGeneralInvoice`,聚焦测试覆盖住宿电子普通发票、铁路电子客票、无代码票据、多票/不支持票据、大小门禁和敏感原始字段不持久化。
- [x] 腾讯云控制台确认通用票据识别(高级版)每月 1,000 次免费包已到账、中国大陆地域、后付费关闭和费用/余额告警可用;额度耗尽不产生后付费。
- [x] 生产实际 provider 为 `tencent`,只授予 `ocr:RecognizeGeneralInvoice`,两个凭证字段已配置但不泄露,external deps smoke、`/ready` 和运行 job 拓扑通过。
- [x] 住宿电子普通发票和铁路电子客票各一份已授权 PDF 经真实腾讯 OCR 进入可解释终态,并证明没有调用 mock;样票和原始识别 payload 不进入仓库或聊天。
- [x] 明确 OCR 只辅助字段识别/查重,财务仍执行明细—PDF 原件—支付证明复核。
- [x] 员工指南和报销事实源完整写明两项补助的单价、自然日口径、包干不另报、直接承担不重复领取和个人延长不计补助规则。
- [x] 生产种子数据中“伙食补助费”“市内交通补助费”均为独立 enabled 费用类型,`travel_bus` 仍明确表示城际大巴车票。
- [x] 未配置会把多日补助误判为超标的 100/80 元单条费用标准;指南要求员工按天数人工计算并在说明中写出算式。
- [x] 在真实 OCR 验收完成前不得仅因指南已完成就通知杨俊可以提交。
- [x] 全程不把真实票据、支付截图、完整账号、银行资料、Secret 或原始 payload 写入仓库、任务或聊天。
- [x] PC 与手机均可一次上传 1–5 个报销补充附件;选择第 6 个时客户端提前提示,绕过客户端直调服务端仍返回稳定 `VALID_001` 而非 500。
- [x] 中文文件名的报销附件和发票 PDF 均返回合法 `Content-Disposition`,保留 `inline` 与 UTF-8 文件名语义且无响应头注入。
- [x] 聚焦测试使用与生产一致的全局 `files=1` 基线,证明路由级覆盖有效,并覆盖 5 个成功、6 个失败、中文名和恶意文件名。
## Lifecycle Closeout
- 2026-08-23,用户在腾讯云控制台完成费用或余额告警配置并确认已启用;任务仅记录“已启用”这一脱敏结论,不记录告警阈值、接收人、账户余额、账号或控制台截图。
- 免费包、中国大陆地域、后付费关闭、最小权限、生产腾讯 OCR、两类授权样票、差旅指南、费用类型及附件修复均已完成,任务验收项全部关闭。
## Out of Scope
- 新增第二个 OCR provider、开放图片发票、自动验真或增加人工发票字段。
- 本轮不做通用发票平台或覆盖全部票种;仅支持现有住宿 VAT/电子普通发票和电子发票(铁路电子客票)主路径。
- 修改报销页面、上传格式、审批规则或自动按天计算;本轮只调整差旅相关费用类型名称并新增独立的市内交通补助类型,不配置 100/80 元费用标准。
- 改变全局 multipart 单文件默认值,或放宽发票上传“一份请求一张正式票据”的边界。
- 代替杨俊上传票据、创建报销、提交审批,或代替主管/财务处理。
- 制定覆盖所有费用类别的完整财务制度;本轮只收口首笔差旅的实报实销材料和两项包干补助。
## Test Plan
- 静态核对前后端上传格式、明细绑定、员工/财务字段边界。
- 运行腾讯 adapter 和 OCR job 聚焦单测,覆盖两类票种、缺字段、错误分类、大小限制和敏感字段最小化。
- 生产只读核对费用类型、OCR provider 和必要运行状态,仅输出类别与计数。
- 运行文档注册、敏感内容、流程合同、Trellis governance 和 `git diff --check`。
- 启用真实 OCR 后验证 `/ready`、构建标识、运行 provider=`tencent`、单一 job executor 和配置 smoke。
- 经单独样票批准后运行现有 live OCR 验收,输出只保留状态、耗时和脱敏字段命中摘要,并按正常业务/API 生命周期清理或归档测试记录。
@@ -0,0 +1,88 @@
# 腾讯 OCR API 调研
调研日期:2026-07-28。仅查阅腾讯云官方文档、当前锁定 SDK 和本地代码;未创建密钥、未调用付费 API、未上传票据。
## 官方资料
- 通用票据识别(高级版):https://cloud.tencent.com/document/api/866/90802
- 增值税发票识别:https://cloud.tencent.com/document/api/866/36210
- OCR 控制台访问管理:https://cloud.tencent.com/document/product/866/102912
- 免费额度:https://cloud.tencent.com/document/product/866/35945
- 计费概述:https://cloud.tencent.com/document/product/866/17619
- 混贴票据计费说明:https://cloud.tencent.com/document/product/866/48522
- 错误码计费说明:https://cloud.tencent.com/document/product/866/45470
- 新手常见问题:https://cloud.tencent.com/document/product/866/43818
- 欠费说明:https://cloud.tencent.com/document/product/866/30576
## 结论
### 1. 当前接口不适合作为两类差旅票据的统一入口
当前代码调用 `VatInvoiceOCR`。官方说明明确覆盖增值税专票、普票、电子专票、电子普票和数电普通/专用发票,适合住宿电子普通发票;但官方用于统一识别火车票、电子发票(铁路电子客票)和增值税发票的是 `RecognizeGeneralInvoice`。
`RecognizeGeneralInvoice` 明确返回 `ElectronicTrainTicketFull`,同时覆盖 `VatElectronicCommonInvoice`、`VatElectronicInvoiceFull` 等住宿发票常见子类型。因此本轮应在现有腾讯 provider 内改用该接口,而不是直接给当前 `VatInvoiceOCR` 配密钥。
### 2. 请求合同
- API 版本仍为 `2018-11-19`,请求域名为 `ocr.tencentcloudapi.com`。
- 当前锁定的 Node SDK 已包含 `RecognizeGeneralInvoice`;无需为了该方法先升级依赖。
- PDF 通过 Base64 传输,不需要公开文件 URL。
- Base64 编码后不得超过 10M;为避免 OA 的 10MiB 原文件上限在编码后超限,正式发票应增加不高于 7MiB 的 OCR 输入门禁。
- 本系统一份 PDF 对应一张发票,只识别第一页:`EnablePdf=true`、`PdfPageNumber=1`、`EnableMultiplePage=false`。
- 不请求切图、字段坐标、二维码或印章返回,避免无用数据和额外敏感内容。
- 默认接口频率为 5 次/秒;当前 job 串行处理,远低于该上限。
### 3. 返回结构和业务字段
- 住宿增值税/电子普通发票:从对应 VAT 子类型归一化发票代码(存在时)、号码、日期、不含税金额、税额、价税合计、销售方和购买方。
- 电子发票(铁路电子客票):从 `ElectronicTrainTicketFull` 归一化发票号码、开票日期、价税合计、税额和购买方;该票种可以没有发票代码和销售方,不能继续套用现有 VAT 五字段必填规则。
- 归一化结果需要保留安全的 `documentSubtype`,用它选择必填字段和脱敏处理;不得把乘车人姓名、证件号、完整票面字段或腾讯原始响应写入 `OcrResult.result_json`。
- 电子票据没有发票代码时,不再把发票号码复制到代码字段。文件 SHA-256 查重继续生效;号码级查重需要按已知无代码子类型做显式规则,不能依赖伪造代码绕过现有复合键。
### 4. CAM 最小权限
腾讯官方确认 OCR 支持接口级自定义授权,接口级授权的 `resource` 必须为 `*`。运行身份只需:
```json
{
"version": "2.0",
"statement": [
{
"effect": "allow",
"action": ["ocr:RecognizeGeneralInvoice"],
"resource": ["*"]
}
]
}
```
运行子用户不需要 `QcloudOCRFullAccess`,也不需要开通/关闭服务或控制台管理权限。OCR 服务开通、计费设置和告警由管理员在控制台完成。
### 5. 免费接口选择、计费和错误
- 官方免费额度表明确列出:`通用票据识别(高级版)` 使用同名专用资源包,免费额度为每月 1,000 次,当月有效、每月发放。它不是与其他票据接口共用的模糊额度。
- `增值税发票识别` 也有每月 1,000 次专用免费额度,但只能解决住宿常见 VAT/电子普通发票,不能统一覆盖电子发票(铁路电子客票)。
- 独立的 `火车票识别` 位于官方“仅老客户续费相关接口”区域,且增加第二套 API、权限、归一化和错误处理,不适合作为当前新接入方案。
- 因此最省钱且最简单的方案是只接 `RecognizeGeneralInvoice`:一个接口同时覆盖住宿和铁路电子客票,并消耗通用票据识别(高级版)的每月 1,000 次专用免费额度。按当前 8 人规模通常足够,但免费政策不是永久合同,上线前仍必须在实际账号控制台确认免费包已到账。
- 高级版免费额度耗尽后,如已购买预付费包则继续扣包;如开通后付费则可能继续计费。官方当前后付费起价为 0.15 元/次。
- 为确保零费用,生产应使用中国大陆地域,在 OCR 控制台设置页确认后付费关闭;免费额度耗尽后允许 OCR 不可用并进入可解释失败,不为保持识别可用而自动付费。境外地域按国际站后付费计费,不能抵扣国内账号资源包,因此不在本轮方案内。
- 官方 FAQ 说明,2021 年 12 月 14 日前开通 OCR 的客户在资源包耗尽后可能自动开通后付费;无论账号何时开通,都以实际控制台开关状态为准,不能只凭开通日期推断不会收费。
- 通用票据识别高级版按实际识别出的发票张数计费;增值税发票进入大票计费项,铁路电子客票/全电发票进入小票计费项。
- 每份 PDF 必须只含一张票据,使一次正常识别对应一次额度扣减;混贴或多票文件可能按实际识别张数扣减,应用继续拒绝多票结果。
- 免费/付费资源包耗尽且未开后付费时会不可用;应用需把它分类为额度/计费门禁失败,而不是票据质量失败。腾讯云侧同时设置费用或余额告警作为兜底。
- 高级版接口官方错误码已核对:`ResourceUnavailable.ResourcePackageRunOut` 表示资源包耗尽,`ResourceUnavailable.InArrears` 表示欠费,`ResourcesSoldOut.ChargeStatusException` 表示计费状态异常,`FailedOperation.UnOpenError` 表示服务未开通,`LimitExceeded.TooLargeFileError` 表示文件过大。这些状态对同一输入重试没有收益,应用应一次终止并给出配置/额度类提示。
- 大部分失败不计费,但官方明确有少量失败错误也可能计费。应用必须保留有限重试和可解释终态,不能无限重试。
- 需要区别处理未开通、欠费/资源包耗尽、文件过大、图片解码/模糊和一般 OCR 失败;不得把配置或额度错误伪装成票据质量问题。
## 当前实现差距
1. `server/src/services/ocr/tencent.js` 调用 `VatInvoiceOCR`,没有铁路电子客票结构解析。
2. `server/src/services/ocr/index.js` 对所有 `vat` 强制要求代码、号码、日期、金额、销售方;铁路电子客票和部分数电票会被误判失败。
3. 现有归一化会在代码/号码缺失时互相回填,掩盖无代码电子票据并污染复合查重语义。
4. 现有归一化把腾讯完整响应放进 `raw`,随后持久化到 `OcrResult.result_json`;改用高级版后可能保存乘车人证件信息。
5. OA 发票上传使用通用 10MiB 上限,可能产生“上传成功、腾讯因 Base64 超限失败”的死路。
6. 旧版腾讯 `OcrResult.result_json` 可能仍带 `raw`;新 adapter 不再生成还不够,命中历史缓存时也必须先按安全白名单压缩,避免旧格式绕过新隐私边界。
## 推荐
只使用 `RecognizeGeneralInvoice`,不拆成 `VatInvoiceOCR + TrainTicketOCR` 两个接口。先完成腾讯 adapter、票种归一化、按票种质量门禁、敏感响应最小化、7MiB PDF 门禁和聚焦测试;再由用户在实际腾讯云账号确认高级版每月 1,000 次免费包已到账、中国大陆地域、后付费关闭和费用告警,最后创建最小权限密钥并部署。住宿发票和铁路电子客票各用一份已授权 PDF 做真实验收;在此之前不允许真实票据进入当前 `mock` 环境。
@@ -0,0 +1,32 @@
{
"id": "travel-reimbursement-guide",
"name": "travel-reimbursement-guide",
"title": "差旅报销指南与腾讯OCR正式启用",
"description": "配置并验证生产腾讯OCR,随后固化火车票、住宿费发票和支付截图的提交位置、实报实销及财务复核规则。",
"status": "completed",
"dev_type": null,
"scope": "生产腾讯OCR启用、授权PDF样票验证及差旅报销员工指南与支付凭证规则",
"package": null,
"priority": "P2",
"creator": "shunli",
"assignee": "shunli",
"createdAt": "2026-07-28",
"completedAt": "2026-08-23",
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [
"docs/员工快速上手.md",
"docs/报销发票附件规则.md",
"server/src/routes/reimbursements.js",
"server/src/routes/invoicePool.js",
"client/src/pages/ReimbursementDetailPage.tsx"
],
"notes": "指南、差旅补助费用类型、附件修复、腾讯 OCR 生产启用和费用控制均已完成;用户于 2026-08-23 确认腾讯云费用或余额告警已启用,任务只保留脱敏状态结论。",
"meta": {}
}