Files
wyndham-ARR/README.md
2026-08-04 12:37:26 +08:00

104 lines
6.4 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:程序化 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 在隔离临时目录生成完整 JSON/XLSX
-> ARR 将结果工件作为 private 不可变对象写入 OSS
-> DeliveryValidator 校验 Schema、哈希、行数、业务恒等式和独立日报复验
-> PostgresIngestionRepository 在一个事务中写入/激活 Finance 版本
-> 写入 arr.daily_version_committed outbox 事件并返回 succeeded / failed 的终态回执
-> 独立 monthly worker 领取事件
-> 从数据库内 ARRIVAL 派生月份与“更新至”日期
-> 生成并校验月报,原子登记 reporting 元数据和可下载工件
```
上传接口仍返回 HTTP `202` 以兼容现有页面,但请求会等到校验和数据库提交结束,因此响应体里的任务状态已经是 `succeeded``failed`,不是“远端已接收”。
## 保留的安全边界
- 源 XML、日报、两份 JSON 和异常清单都按 SHA-256、字节数、MIME 和对象身份校验。
- 成功结果由独立 `validate_daily.py` 再验一次;验证失败不会写入半成品 Finance 版本。
- 同一 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` 加 009016 增量迁移。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 覆盖成功与业务失败。
## 部署
生产配置见 [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` 作为“更新至”XML 文件名和当前时间都不参与推导。
- 月报版本、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 回滚基线。