Files
wyndham-ARR/README.md
2026-08-06 22:40:18 +08:00

107 lines
7.4 KiB
Markdown
Raw 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:程序化 XML 入库
ARR 2.0 是独立于原 ARR 工程的程序化版本。用户只上传一次 Opera `RES_DETAIL` XML后续处理、校验、工件保存和 Finance 入库全部由 ARR 自己完成;生产路径不调用 Agent不暴露 MCP也不需要 prompt、`fetch_oss_file`、submission grant 或公网源文件地址。
## 处理链路
```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` 加 009018 增量迁移。017 必须在同一发布窗口先确认/应用 016 后才可应用;它增加价格复核 case/item/event 审计、`awaiting_review` 生命周期、最终人工价格 lineage 和受保护回滚。018 是前向约束修复,只为冻结人工清单增加 `manual_override_json` 工件类型。012 只增加月报发布元数据、Finance 日版本 lineage 和受控本地工件身份016 允许新月报 OSS 工件并保留旧 local 记录013 将用户上传的 XML 文件名独立保存为任务来源信息,内部源工件仍统一命名为 `source.xml`014/015 增加 Booking 当前整表指针以及可编辑的 Excel 提取草稿。ARR 2.0 使用原有 `artifact_callback` 通用工件交付表;不会读写 009/010 的 grant/MCP submission 表。
## Booking Excel 房型提取
“公司渠道明细”页可以上传原始 `.xlsx`,程序从同一工作表的 `Tour Code` 与精确泰文表头 `โรงแรม` 提取房型记录。提取结果先进入草稿,不会直接覆盖当前 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 负责
HTTPSWeb 负责应用登录和会话;没有 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 回滚基线。