fix: add ledger refund uniqueness guard

This commit is contained in:
QiuSW
2026-07-02 16:59:02 +08:00
parent be97a35360
commit 4e8c1b45a4
7 changed files with 93 additions and 8 deletions
+27
View File
@@ -499,3 +499,30 @@
- P3(登记):手工调点服务未实现(模型层 reason 守卫已备好、wallet admin 已锁死=安全中间态)→ T-401;扣点热路径 wallet get_or_create 掩盖钱包缺失 → T-501;锁顺序约定;只追加靠 admin+无 update 保证(DB 无触发器);OperationType 双份枚举 DRY。
- 未本地复跑:审核机无 python3.12,结论基于静态审查(users/billing models、services、pricing、两 app admin、tests、全部迁移、settings)+ codex 执行记录(T-201 34 tests / T-202 billing 10 tests / T-203 BillingServiceTests 4 + ConcurrentDebitTests 1 均单独在 MySQL 通过;完整套件因连接问题未单次全绿,失败点均为连接/建库超时非断言失败)。
- 下一步:codex 可领 T-204 做 P2 加固(无 P1,不阻塞 T-301)。
## 2026-07-02 T-204 Phase 2 计费核心审核加固
- 状态:BLOCKED(P2-1 已完成;P2-2 完整 `manage.py test` 单次全绿被远程 MySQL 连接稳定性阻塞)
- 变更:
- `apps/billing/models.py`:给 `PointsLedger` 增加 MySQL 可落地的 `UniqueConstraint(fields=("ref_call", "change_type"), name="unique_ledger_change_type_per_call")`,作为同一调用重复写同类型流水的 DB 级兜底;没有使用 MySQL 不支持的 partial unique / 条件唯一约束。
- 新增迁移 `billing.0003_pointsledger_unique_ledger_change_type_per_call`,已应用到当前 MySQL。
- `apps/billing/tests.py`:新增直写测试,确认同一 `CallRecord` 的一条 `CONSUME` + 一条 `REFUND` 可共存,第二条 `REFUND` 抛 `IntegrityError`。
- `docs/03-tech-stack.md`:测试说明补充「涉及 `select_for_update` 的并发扣点测试必须在 MySQL 上跑,SQLite 会忽略行锁导致假绿」。
- `docs/06-tasks.md` / `docs/current-state.md`:记录 T-204 的 P2-1 完成、P2-2 因远程 MySQL 全量测试未单次全绿而阻塞;T-204 无 P1,不阻塞 T-301。
- 验证:
- `py -3.12 -m py_compile apps\billing\models.py apps\billing\tests.py`:通过。
- `py -3.12 manage.py check`:通过,0 issues。
- `py -3.12 manage.py makemigrations --check`:通过,No changes detected。
- `py -3.12 manage.py migrate`:通过,应用 `billing.0003_pointsledger_unique_ledger_change_type_per_call`。
- `py -3.12 manage.py showmigrations billing`:通过,`billing.0001/0002/0003` 均为 `[X]`。
- `py -3.12 manage.py test apps.billing.tests.BillingCoreModelTests.test_points_ledger_allows_consume_and_refund_but_rejects_duplicate_refund --noinput --keepdb`:通过,1 test OK。
- `py -3.12 manage.py test apps.billing.tests.BillingServiceTests apps.billing.tests.ConcurrentDebitTests --noinput --keepdb`:通过,5 tests OK。
- `py -3.12 manage.py test apps.billing --noinput --keepdb`:通过,16 tests OK。
- `Test-NetConnection 43.128.3.240 -Port 3306`:通过,`TcpTestSucceeded=True`。
- `py -3.12 -m compileall apps`:通过。
- `git diff --check`:通过,仅 Windows CRLF 提示。
- `./init.ps1`:通过,依赖同步与基础检查正常。
- `py -3.12 manage.py test --noinput --keepdb`:两次未作为绿灯;一次发现 44 tests,跑到 42 tests 后 `apps.ai.tests.AiModelEncryptionTests` 建连接超时;一次跑到 34 tests 后 `apps.ai` 多个 TestCase 建连接超时。失败点均为远程 MySQL `43.128.3.240:3306` 连接超时。
- `py -3.12 manage.py test apps.users apps.billing --noinput --keepdb`:未作为绿灯;跑到 17/18 后 `ConcurrentDebitTests.setUp` 建连接超时。
- 阻塞:当前没有代码阻塞;P2-1 已完成且相关测试通过。P2-2 需要稳定 MySQL 环境完成一次完整全量测试单次绿灯,当前远程实例仍在多连接/长测试期间间歇超时。
- 下一步:若先处理 T-204 blocker,需要提供/切换稳定 MySQL 8.4 测试环境后重跑 `py -3.12 manage.py test --noinput`;若接受 T-204 无 P1 且不阻塞后续,可进入 T-301 API Key 鉴权。