# 09 — 逐行完成钱包批量订购与崩溃恢复

**What to build:** 钱包支付任务可以严格按 CSV 行号，分别使用每个资产结算代理的主钱包完成订购。同一代理资金不足只失败当前行，后续更便宜的行仍按当时可用金额判断；重复消息、并发 Worker 和进程中断恢复不会重复创建订单、扣款、写流水或激活套餐。

**Blocked by:**

- `.scratch/ur36-bulk-package-purchase/issues/05-single-asset-package-purchase-command.md` — 05 — 提供统一的单资产套餐订购命令
- `.scratch/ur36-bulk-package-purchase/issues/08-offline-bulk-row-purchase.md` — 08 — 逐行完成线下支付批量订购

**Status:** ready-for-agent

**架构通道:** 复杂写，Application → Order/Package Domain，辅助调用 Wallet Application/Port。

**完整业务边界:** 本票在已经验证的逐行任务闭环上增加 `wallet` 支付和故障恢复。它通过 UR#36 Ticket 05 间接消费 UR#38 的钱包能力，不直接依赖或重新实现 Wallet Domain。明确不预占整批资金、不并行结算、不迁移其他钱包用例。

- [ ] 每行按当前资产归属定位结算代理，并通过统一单资产订购命令调用 Wallet Application/Port；批量代码不读取信用字段计算可用金额，不直接更新钱包或创建钱包流水。
- [ ] 严格行序决定同一代理的资金使用优先级，不按代理汇总预占；当前行余额不足只失败该行，后续金额较小且资金足够时可以成功。
- [ ] 任务和明细使用状态条件、处理租约及稳定幂等键领取；只有租约所有者可以提交处理中状态，终态不可重复执行。
- [ ] 两个 Worker 同时领取、重复 Asynq 消息、任务租约过期和行租约过期时，订单、钱包扣款、真实金额流水、套餐激活及成功审计各最多一次。
- [ ] 单行事务提交前崩溃可安全重试；提交后但确认前崩溃可从订单、明细和幂等事实恢复，不得再次扣款。
- [ ] 钱包不足、无有效主钱包、信用关闭或额度不足等稳定业务失败记录中文安全原因；数据库、Redis 或底层钱包错误不泄露给前端。
- [ ] 任务终态汇总从明细重新聚合并记录涉及代理数、成功金额、成功数和失败数，同时写任务终态公共审计。
- [ ] 并发与故障测试覆盖多代理各扣主钱包、现金与信用、无钱包、前贵后便宜、普通订单并发、双 Worker、重复消息及事务提交前后故障。
