52 lines
5.0 KiB
Markdown
52 lines
5.0 KiB
Markdown
# 多Excel整组上传、替换与恢复 CP18
|
||
|
||
状态:本地实现完成,最终测试记录见[证据](../../../.project-docs/50-evidence/topics/2026-09-16-ohip-attachment-set-cp18.md)。运行仍使用 Pending 适配器;没有执行真实迁移、酒店/邮件调用、重启、提交推送或部署。平台候选继续0.9.0,CP18不表示线上能力已发布。
|
||
|
||
## 用户看到的规则
|
||
|
||
员工确认一次后,系统使用本次确认中的全部预订Excel。只有一份时Name=Tour Code;多份时Name=Tour Code+序号(01、02,100继续100),Description均为Tour Code。排序来自原确认列表,一经保存不重新排序或重新编号。PDF、图片沿用既有原件筛选规则,不进入这个集合。
|
||
|
||
NEW:向本次已完整保存的实际Block/Reservation上传每份Excel。FIT依赖共享Guest和同次创建的实际Reservation,仍核对原Note实际子编号;不会以本地订单号代替酒店编号。
|
||
|
||
UPDATE:从CP7固定目标、CP8完整读取、CP10来源匹配得到整组旧文件,接收完整新Excel集合。支持3→2、1→2、2→1及新增文件;上传、查询全部新件后精确清理旧件。与新文件同名的已证明旧件可覆盖,实际返回同ID不删除;不同名旧件待全组新件核实后清理。酒店中无关附件保持原样。
|
||
|
||
## 内部接续
|
||
|
||
- `HotelBookingAttachmentSet` 保存计划、输入、旧元数据/来源证据、每父每文件请求摘要和结果;不持久文件字节、原邮件、凭据或下载URL。
|
||
- `HotelBookingAttachmentSetRepository` 是短事务业务端口;`JdbcHotelBookingAttachmentSetRepository` 在原执行行锁下检查确认快照、酒店、版本、租约、实际创建/更新绑定;逐笔发送使用CP5相同事务守卫。
|
||
- `OhipBookingAttachmentSetAdapter.prepareNew` 必须在完整创建后调用;`prepareUpdate` 必须在本次首次酒店写入前基于完整旧值/来源匹配调用。NEW原件清单在SAVE_ATTACHMENTS/RECONCILE冻结;UPDATE在PREPARE/RECONCILE冻结。
|
||
- `execute` 只在SAVE_ATTACHMENTS且未要求先核对时写;`reconcile` 仅查询。二者都加载同一份固定计划,核对原件和请求摘要。清理计划只能在全部上传回执已确认实际ID后追加一次;不更改原计划。
|
||
- V48新增`workflow_hotel_booking_attachment_set`,必须按正式迁移流程先行部署。原CP11/V44和CP16/V47单文件在途计划保持原入口;新入口遇到旧计划拒绝混用,不自动重冻或升级。
|
||
|
||
每次外呼在事务之外;前后都核对当前上下文。清单最多100原件、每父100旧件、预计上传/清理调用合计最多250笔,所有本次调用仍受300上限约束。完整附件列表小于4000;每次处理一个原件,不把100份大文件同时保存在内存。超限或租约不足保持未完成。
|
||
|
||
## 平台集合删除协议
|
||
|
||
沿用`deleteBlockAttachment`、`deleteReservationAttachment`,原四字段形式和旧新同名要求不变。新增互斥形式:
|
||
|
||
```json
|
||
{
|
||
"attachment_id": "旧实际ID",
|
||
"expected_sha256": "旧内容SHA256",
|
||
"expected_file_name": "旧实际名称",
|
||
"expected_description": "旧实际描述",
|
||
"replacement_set": [
|
||
{"id": "新实际ID", "sha256": "新内容SHA256", "file_name": "新实际名称", "description": "Tour Code"}
|
||
]
|
||
}
|
||
```
|
||
|
||
replacement_set为1..100项,实际ID及名称唯一,不能包含待删旧ID;描述字段必须存在且是字符串,允许精确空描述。平台验证父对象/酒店/非全局归属,以及每一新件元数据和下载内容;旧件若仍在则核对实际名称、描述和内容。全部正确才调用一次原生旧ID删除;旧件已不存在时只读核查新组。删除后重新核对旧ID消失及完整新组。
|
||
|
||
响应保留首项`attachment/file/sha256`,新增`replacements:[{attachment,sha256}]`;consumer同时检查所有条目、实际父列表、首项字节及后续逐件GET,不只检查第一份。原生列表允许额外非归属字段,不以整JSON对象相等误拒绝合法扩展。
|
||
|
||
## 失败与恢复
|
||
|
||
结果包含本轮实际查询`observations`及已确认写入`recordedWrites`。两者都不能单独证明整单完成,`businessComplete`固定false,最终办理汇总须覆盖日期、房量、Note、附件等所有要求。已有写成功后来源不可用、查询失效或末次上下文失效,仍保留已知事实并标为未完成。
|
||
|
||
相同幂等键不能换来源、正文、父对象或配置。UNKNOWN/ACCEPTED/REJECTED/CONFLICT均不自动重发;已保存成功回执后中断可从下一份接续。不能凭同名或同内容推断未保存编号的上传属于本次;不能凭名称或序号证明旧件归属。实际酒店并发修改会停止后续操作,多步调用不承诺跨文件原子性。
|
||
|
||
## 后续
|
||
|
||
下一checkpoint接完整GROUP/FIT NEW/UPDATE的执行顺序与最终真实值回显,继续消除FIT TA recorder、Meal/餐厅、配置/权限/发布和实际数据库/Oracle UAT缺口。当前没有新增待用户确定的产品规则。平台1名已授权开发测试代理已完成;新增代理仍先问许可。
|