10 KiB
10 KiB
技术设计
边界
本任务不开发新的 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 上限内;大小错误在上传阶段阻断。
验证数据流
- 用户在腾讯云控制台确认通用票据识别(高级版)每月免费包已到账、中国大陆地域、后付费关闭和费用/余额告警。
- 用户创建或轮换 OA OCR 专用子用户密钥,并确认 OCR 服务可用。
- 用户在现场终端把 provider、密钥和地域写入生产受控环境文件。
- 重建 server,使新配置进入实际运行进程。
- 运行外部依赖 smoke、运行时 smoke、
/ready、构建标识和 job 拓扑检查。 - 经样票单独授权后,通过现有 PDF 发票入口分别上传住宿电子普通发票和铁路电子客票样票。
- 只记录 provider、状态、尝试/完成证据和脱敏字段命中摘要;不记录票面、完整字段或原始 payload。
- 正常清理或归档测试业务记录,再允许杨俊提交真实票据。
授权样票验证工具边界
- 既有
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处置类型,生成安全 ASCIIfilename与 RFC 5987 UTF-8filename*。报销附件与发票 PDF 使用inline;采购、回单等既有attachment调用保持不变。 - 不改变文件原名在数据库中的业务展示值,不重写已上传文件;修复部署后既有中文名附件即可正常打开。
失败与回退
- adapter 聚焦测试、配置 smoke、腾讯调用或任一真实样票验证失败:停止开放真实票据,不继续制造 pending/retry 数据。
- 若新配置导致运行异常,恢复变更前环境文件的受控副本并重建同一 server;回退后不得使用 mock 处理真实票据。
- 若标准根部署、timer 重装或健康检查失败,停止继续发布,将 Compose 工作目录和 systemd unit 恢复到时间戳回退根并重建原 server;数据库和附件目录不参与回退切换。
- 样票失败记录使用可解释状态和脱敏摘要,不直接修改数据库字段绕过状态机。
历史凭证结论
2026 年 5 月的证据能证明真实腾讯 OCR 曾可用,但不能证明当时密钥仍有效或满足当前最小权限。当前生产机、历史容器、同机旧环境文件、开发机环境文件及 shell 历史均无可恢复凭证;数据库/附件备份也不包含环境密钥。因此本任务不设计“从旧部署复制密钥”的路径。