Files

122 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ARR 2.0:OHIP 自动取数与 XML 报表处理
ARR 2.0 同时提供两条报表入口:选择日期后从OHIP获取业务数据,或上传Opera `RES_DETAIL` XML。
两条入口共用筛选、去重、定价、价格复核及日报/月报规则;后续处理、校验、工件保存和Finance入库由ARR程序完成。
自动取数直接处理数据,不生成中间XML。生产处理不调用Agent、不暴露MCP。
## 当前交付
- 接口路径:选日期 → 获取15字段业务数据 → 按原规则处理 → 生成日报供下载 → 自动更新月报。
- XML路径:上传XML → 解析XML → 按原规则处理 → 生成日报供下载 → 自动更新月报。
- 8个查询接口与页面、数据处理、复核、入库和月报已衔接;日期选择交互已获用户确认。
- 当前酒店由OHIP平台路由,ARR核对返回酒店`OHIPSB02`;用户确认生产切换时再调整对应配置。
- 开发和本机模拟完成,正式环境配置及真实数据验收待执行;基础Compose需显式加入OHIP启动参数和持久目录挂载。
交付入口:[字段范围](ARR_XML_RAW_FIELDS.md) · [接口及实际参数](ARR_OHIP_REQUEST_PARAMETERS.md) ·
[页面使用与运行配置](arr_web/DIRECT_DATA_ENTRY.md) · [生产启用说明](deploy/OHIP_RELEASE_HANDOVER.md)。
需要完整了解业务边界、系统架构、模块职责、配置、测试、部署和交接注意事项,请阅读 [ARR 2.0 项目说明与交接指南](PROJECT_GUIDE.md)。
## 原 XML 处理链路
```text
浏览器上传 XML
-> ARR 将源 XML 作为 private 不可变对象写入 OSS
-> ARR 登记 processing run / attempt,并切换为 running
-> 固定版本 process_daily.py 在隔离临时目录生成 v4 JSON,以及正式 XLSX 或纯 PRICE_UNMATCHED 复核结果
-> ARR 将结果工件作为 private 不可变对象写入 OSS
-> DeliveryValidator 校验 Schema、哈希、行数、业务恒等式和独立日报复验
-> 纯 PRICE_UNMATCHED:只登记审计化复核 case/items/events,返回 needs_review(无 Finance/outbox/日报下载)
-> 员工填写并冻结全部缺价键后,以原 XML + 固定价表 + 清单重新处理并独立复验
-> 最终成功才在一个事务中写入/激活 Finance 版本与 arr.daily_version_committed,返回 succeeded
-> 其他业务错误返回 failed;基础设施重试保留冻结清单
-> 独立 monthly worker 领取事件
-> 从数据库内 ARRIVAL 派生月份与“更新至”日期
-> 生成并校验月报,原子登记 reporting 元数据和可下载工件
```
上传接口仍返回 HTTP `202` 以兼容现有页面,但请求会等到初始校验和状态登记结束,因此响应体里的任务状态已经是 `succeeded`、`needs_review` 或 `failed`,不是“远端已接收”。
## 保留的安全边界
- 源 XML、日报、两份 JSON、异常清单和(最终人工复核时)冻结清单都按 SHA-256、字节数、MIME 和对象身份校验。
- 纯 `PRICE_UNMATCHED` 只会进入待复核,不会生成日报、Finance 版本或失败 outbox;混合错误仍走失败链路。
- 最终人工价格清单绑定 job、原 XML SHA、业务日期、处理器/规则身份、case 和完整问题键集合,独立 `validate_daily.py` 会用同一清单重放后才允许入库。
- 同一 delivery 的重放保持幂等;用户重新上传会创建新的 job,并按现有业务日期版本规则在成功后安全替换当前版本。
- 数据库只对可识别的瞬时并发错误做最多四次事务重试。这不是模型或工具重试。
- 当前 bucket 可以是 `private` 或 `public-read`,但 ARR 2.0 写出的每个对象 ACL 都是 `private`;`public-read-write` 和已启用/暂停 versioning 会被拒绝。
## 本地启动
建议使用 Python 3.12:
```bash
python -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
cp .env.example .env.local
```
将 `.env.local` 中的数据库、OSS 和凭据注入当前 shell 后启动。Web 还必须从运行时 Secret
注入 `ARR_WEB_USERNAME` 和至少 12 位的 `ARR_WEB_PASSWORD`;任一缺失都会拒绝启动,真实值不得提交到仓库:
```bash
.venv/bin/python -m arr_web.run \
--host 127.0.0.1 \
--port 8765 \
--enable-processing \
--enable-monthly-generation \
--enable-company-reports
```
另开一个进程启动月报消费者:
```bash
.venv/bin/python -m monthly_reports.worker \
--db-config /absolute/path/to/booking-test-db.env \
--output-root /app/outputs/monthly_reports
```
浏览器访问 `http://127.0.0.1:8765` 后会先进入 ARR 登录页。登录后,`GET /api/health` 中相关 readiness
均为 `true` 才表示页面处理和下载能力可用;未登录的容器只使用无详情的 `GET /healthz` readiness。
worker 是独立无端口进程,应由进程管理器单独保活。
自动数据入口要求 `database/008_arr_mvp_v1_rebuild.sql` 加009–019增量迁移;019支持`ohip_json`来源和5.0结果,原XML保持4.0兼容。既有数据库实际版本须在部署时核对,不自动执行迁移。017必须在同一发布窗口先确认/应用016后才可应用;它增加价格复核case/item/event审计、`awaiting_review`生命周期、最终人工价格lineage和受保护回滚。018为冻结人工清单增加`manual_override_json`工件类型。012增加月报发布元数据和Finance日版本lineage;016允许新月报OSS工件并保留旧local记录;013保存用户上传XML文件名;014/015增加Booking当前整表指针和Excel提取草稿。ARR使用原有`artifact_callback`通用工件交付表,不读写009/010的grant/MCP submission表。
## Booking Excel 房型提取
“公司渠道明细”页可以上传原始 `.xlsx`。程序只在同一工作表中识别一组完整、精确的 Tour Code/Group Code 与酒店明细表头后提取房型记录:Tour Code 可为 `Tour Code`、`Group Code`、`Gourp Code`、`团号`、`团队代码` 或 `Tour Code / 主团号`;酒店明细可为 `โรงแรม`、`วางข้อมูลที่นี่ / 酒店明细` 或 `Raw Hotel Detail / วางข้อมูลที่นี่ / 酒店明细`。表头经过 Unicode、大小写、空白和标点归一化后仍须整格精确相等,不按月份、文件名、工作表名、关键词包含或模糊匹配。提取结果先进入草稿,不会直接覆盖当前 Booking 数据:
- Tour Code 会删除制表符、换行和空格;同一 Tour Code 以物理位置最后一行为准,最后一行明确写明取消时移除,单元格底色不代表取消。
- 只分析酒店文本圆括号内的房型信息。`【房型】` 后面的整数是数量;未单独写数量时按 1。
- `U-TWN`/`U-DBL` 后带任意数字或小数仍分别归一为 `U-TWN`/`U-DBL`;`高级房TWN`、`高级房DBL` 分别归一为 `TWN`、`DBL`。
- 无法确认的中括号内容保留原始标识、保留已识别数量并标为“待人工确认”;没有中括号的房型文本也进入人工确认。
- 多个房型拆成多条记录,重复房型不在提取阶段合并。附加费、儿童早餐和导游房等非客房项目忽略。
- 自动识别与人工记录都可修改或删除;待人工项目确认前不计入有效房量。全部待人工项确认或删除后,才可一次性启用整份工作簿;重新提取原文件会按源文件重建草稿。
对应持久化迁移是 `database/014_booking_current_source_batch.sql` 和 `database/015_booking_excel_review_drafts.sql`。
## 测试
```bash
.venv/bin/python -m unittest discover -s tests -p 'test_*.py' -v
```
`tests/test_arr_programmatic.py` 是关键竖切:它使用真实固定处理器、不可变对象存储、独立验证器和入库 repository 覆盖自动成功、纯缺价待复核、整数 `0` 输入并冻结为 `0.00` 重放、可重试基础设施错误和确定性最终失败。
## 部署
生产配置见 [deploy/README.md](deploy/README.md)。当前 Compose 模板仍只打包 `web` 与 `caddy`,Caddy 负责
HTTPS,Web 负责应用登录和会话;没有 MCP 端口、MCP 域名或 Agent Secret。月报和公司渠道明细都由
Python/openpyxl 生成,XLSX 与 `result.json` 上传现有 OSS;月报 worker 必须作为独立进程部署,
`.web-jobs` 队列状态仍使用 `/app/outputs` 持久卷。
## 当前月报行为
- 用户只上传 XML,页面不再要求月份、截止日或单独点击“生成月报”。
- worker 只消费最终成功提交的日报事件,使用纳入月报数据的最大 `ARRIVAL` 作为“更新至”;待人工处理和失败任务都不会创建该事件。
- 月报版本、lineage、渠道行数和两个工件身份持久化到 `reporting` schema;列表和下载由这些元数据驱动。
- 月报页可见时自动同步发布记录,新版本直接加入列表,不需要点击“刷新”。
- 每条数据行的 `TOTAL PRICE` 都是 `REAL PRICE × NIGHTS × NO_OF_ROOMS` 的 Excel 公式(当前列布局为 `=R[row]*C[row]*G[row]`)。
原工程 `/Users/chillishark/ARR项目0727` 未被修改,可继续作为 ARR 1.x 回滚基线。