fix(billing): 删任务/删项目级联吞 ACTIVE 预留致 reserved_balance 永久冻结(审计 I2)
- 根因: CreditReservation.task 是 OneToOneField(CASCADE), AITask.project 也是 CASCADE
—— 删项目→级联删任务→ACTIVE 预留行被吞, 账户冻结份额永不归还(实测 4 账户漂移共 ¥42,
且随删项目持续增长)
- 修法: billing/signals.py 挂 AITask pre_delete, 删除前先 release_credit 释放(级联同样
触发, release 自带行锁+幂等); apps.py ready() 接线
- 回归测试 x3: 直删任务/删项目级联/已扣费不重复释放
- qa/repair_reserved_drift.py: 存量漂移回填脚本(dry-run 默认, --apply 落 RELEASE 流水),
已对线上 4 账户执行并复验清零
- qa/function-audit/output: 本轮 18 页模拟点击审计报告(0 真死按钮 0 JS 报错)
验证: 后端测试 213/213 通过, django check 无警告
补齐 aab4d7e: 该提交带走了 signals.py 之外的测试轮改动, 信号挂载点与回归测试在本提交收口
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,177 +1,33 @@
|
||||
[
|
||||
{
|
||||
"page": "dashboard",
|
||||
"blocked": 0,
|
||||
"total": 25,
|
||||
"works": 20,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 5,
|
||||
"noop": 0,
|
||||
"missing": 18
|
||||
},
|
||||
{
|
||||
"page": "products",
|
||||
"blocked": 0,
|
||||
"total": 25,
|
||||
"works": 24,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 1,
|
||||
"skipped": 0,
|
||||
"noop": 0,
|
||||
"missing": 6
|
||||
},
|
||||
{
|
||||
"page": "product-detail",
|
||||
"blocked": 0,
|
||||
"total": 29,
|
||||
"works": 22,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 6,
|
||||
"noop": 1,
|
||||
"missing": 9
|
||||
},
|
||||
{
|
||||
"page": "product-create",
|
||||
"blocked": 0,
|
||||
"total": 31,
|
||||
"works": 25,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 1,
|
||||
"skipped": 5,
|
||||
"noop": 0,
|
||||
"missing": 11
|
||||
},
|
||||
{
|
||||
"page": "projects",
|
||||
"blocked": 0,
|
||||
"total": 24,
|
||||
"works": 15,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 9,
|
||||
"noop": 0,
|
||||
"missing": 19
|
||||
},
|
||||
{
|
||||
"page": "projects-new",
|
||||
"blocked": 0,
|
||||
"total": 15,
|
||||
"works": 15,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 0,
|
||||
"noop": 0,
|
||||
"missing": 6
|
||||
},
|
||||
{
|
||||
"page": "pipeline",
|
||||
"blocked": 0,
|
||||
"total": 34,
|
||||
"works": 26,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 8,
|
||||
"skipped": 0,
|
||||
"noop": 0,
|
||||
"missing": 15
|
||||
},
|
||||
{
|
||||
"page": "library",
|
||||
"blocked": 0,
|
||||
"total": 38,
|
||||
"works": 23,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 1,
|
||||
"skipped": 13,
|
||||
"noop": 1,
|
||||
"missing": 10
|
||||
},
|
||||
{
|
||||
"page": "account",
|
||||
"blocked": 0,
|
||||
"total": 26,
|
||||
"works": 20,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 5,
|
||||
"noop": 1,
|
||||
"missing": 4
|
||||
},
|
||||
{
|
||||
"page": "team",
|
||||
"blocked": 0,
|
||||
"total": 17,
|
||||
"works": 17,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 0,
|
||||
"noop": 0,
|
||||
"missing": 4
|
||||
},
|
||||
{
|
||||
"page": "messages",
|
||||
"blocked": 0,
|
||||
"total": 28,
|
||||
"works": 20,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 7,
|
||||
"noop": 1,
|
||||
"missing": 9
|
||||
},
|
||||
{
|
||||
"page": "asset-factory",
|
||||
"blocked": 0,
|
||||
"total": 24,
|
||||
"works": 23,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 0,
|
||||
"noop": 1,
|
||||
"missing": 5
|
||||
},
|
||||
{
|
||||
"page": "image-optimize",
|
||||
"blocked": 0,
|
||||
"total": 24,
|
||||
"works": 21,
|
||||
"dead": 2,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 0,
|
||||
"noop": 1,
|
||||
"missing": 12
|
||||
},
|
||||
{
|
||||
"page": "model-photo",
|
||||
"blocked": 0,
|
||||
"total": 32,
|
||||
"total": 35,
|
||||
"works": 31,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 0,
|
||||
"skipped": 3,
|
||||
"noop": 1,
|
||||
"missing": 8
|
||||
"missing": 4
|
||||
},
|
||||
{
|
||||
"page": "model-photo",
|
||||
"blocked": 0,
|
||||
"total": 49,
|
||||
"works": 44,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 5,
|
||||
"noop": 0,
|
||||
"missing": 7
|
||||
},
|
||||
{
|
||||
"page": "model-photo-demo-a",
|
||||
"blocked": 0,
|
||||
"total": 38,
|
||||
"works": 33,
|
||||
"total": 39,
|
||||
"works": 34,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
@@ -182,37 +38,25 @@
|
||||
{
|
||||
"page": "model-photo-demo-b",
|
||||
"blocked": 0,
|
||||
"total": 37,
|
||||
"works": 34,
|
||||
"total": 38,
|
||||
"works": 36,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 2,
|
||||
"noop": 1,
|
||||
"noop": 0,
|
||||
"missing": 5
|
||||
},
|
||||
{
|
||||
"page": "platform-cover",
|
||||
"blocked": 0,
|
||||
"total": 38,
|
||||
"works": 35,
|
||||
"total": 48,
|
||||
"works": 46,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 1,
|
||||
"noop": 2,
|
||||
"missing": 8
|
||||
},
|
||||
{
|
||||
"page": "settings",
|
||||
"blocked": 0,
|
||||
"total": 26,
|
||||
"works": 25,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 0,
|
||||
"skipped": 1,
|
||||
"noop": 0,
|
||||
"missing": 9
|
||||
"disabled": 1,
|
||||
"skipped": 0,
|
||||
"noop": 1,
|
||||
"missing": 7
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user