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,15 +1,15 @@
|
||||
{
|
||||
"name": "pipeline",
|
||||
"route": "/pipeline/1048451e-3b4a-4b66-a8f4-cb865096de2f",
|
||||
"url": "http://127.0.0.1:5173/pipeline/1048451e-3b4a-4b66-a8f4-cb865096de2f",
|
||||
"route": "/pipeline/cb82b6ee-c106-4380-b7d5-979c4b9c19a0",
|
||||
"url": "http://127.0.0.1:5173/pipeline/cb82b6ee-c106-4380-b7d5-979c4b9c19a0",
|
||||
"mode": "quick",
|
||||
"tally": {
|
||||
"total": 34,
|
||||
"works": 26,
|
||||
"total": 35,
|
||||
"works": 21,
|
||||
"dead": 0,
|
||||
"error": 0,
|
||||
"disabled": 8,
|
||||
"skipped": 0,
|
||||
"disabled": 2,
|
||||
"skipped": 12,
|
||||
"noop": 0,
|
||||
"blocked": 0
|
||||
},
|
||||
@@ -28,8 +28,8 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 22,
|
||||
"api": 0
|
||||
"mutations": 52,
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -46,7 +46,7 @@
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 17,
|
||||
"mutations": 19,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
@@ -64,7 +64,7 @@
|
||||
"url": false,
|
||||
"overlay": true,
|
||||
"self": false,
|
||||
"mutations": 14,
|
||||
"mutations": 17,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
@@ -82,8 +82,8 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 24,
|
||||
"api": 0
|
||||
"mutations": 40,
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -100,7 +100,7 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 36,
|
||||
"mutations": 43,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
@@ -108,81 +108,9 @@
|
||||
"idx": 5,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "active",
|
||||
"label": "视频项目",
|
||||
"href": "/projects",
|
||||
"disabled": false,
|
||||
"active": true,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 22,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "图片生成",
|
||||
"href": "/asset-factory",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 26,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "资产库",
|
||||
"href": "/library",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 37,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "团队",
|
||||
"href": "/team",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 22,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "消费",
|
||||
"href": "/account",
|
||||
"label": "模特库",
|
||||
"href": "/models",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
@@ -194,11 +122,119 @@
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "active",
|
||||
"label": "视频项目",
|
||||
"href": "/projects",
|
||||
"disabled": false,
|
||||
"active": true,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 24,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "图片生成",
|
||||
"href": "/asset-factory",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 24,
|
||||
"api": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "资产库",
|
||||
"href": "/library",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 38,
|
||||
"api": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "团队",
|
||||
"href": "/team",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 24,
|
||||
"api": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "消费",
|
||||
"href": "/account",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 108,
|
||||
"api": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "垃圾桶",
|
||||
"href": "/trash",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 25,
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 12,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "",
|
||||
"label": "设置",
|
||||
"href": "/settings",
|
||||
"disabled": false,
|
||||
@@ -208,12 +244,30 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 56,
|
||||
"mutations": 61,
|
||||
"api": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"idx": 13,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "user",
|
||||
"label": "账户",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 21,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 14,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "btn.btn-ghost.pipeline-back",
|
||||
@@ -226,12 +280,12 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 22,
|
||||
"mutations": 24,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 12,
|
||||
"idx": 15,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "icon-btn",
|
||||
@@ -244,12 +298,12 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 24,
|
||||
"mutations": 27,
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 13,
|
||||
"idx": 16,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "sp-dot.done",
|
||||
@@ -262,12 +316,12 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 20,
|
||||
"mutations": 24,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 14,
|
||||
"idx": 17,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "sp-dot",
|
||||
@@ -280,12 +334,12 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 22,
|
||||
"api": 0
|
||||
"mutations": 26,
|
||||
"api": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 15,
|
||||
"idx": 18,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "sp-dot",
|
||||
@@ -298,12 +352,12 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 23,
|
||||
"api": 0
|
||||
"mutations": 26,
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 16,
|
||||
"idx": 19,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "sp-dot",
|
||||
@@ -316,67 +370,27 @@
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 23,
|
||||
"api": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 17,
|
||||
"tag": "a",
|
||||
"role": "",
|
||||
"cls": "sp-dot",
|
||||
"label": "拼接导出",
|
||||
"href": "#stage-5",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": true,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 23,
|
||||
"mutations": 25,
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 18,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "ctl-btn",
|
||||
"label": "上一帧 (←)",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
"verdict": "disabled"
|
||||
},
|
||||
{
|
||||
"idx": 19,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "ctl-btn",
|
||||
"label": "播放 / 暂停 (空格)",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
"verdict": "disabled"
|
||||
},
|
||||
{
|
||||
"idx": 20,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "ctl-btn",
|
||||
"label": "下一帧 (→)",
|
||||
"cls": "btn.btn-sm.btn-primary",
|
||||
"label": "▶ 开始生成视频",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "disabled"
|
||||
"verdict": "skipped-destructive"
|
||||
},
|
||||
{
|
||||
"idx": 21,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "ctl-btn",
|
||||
"label": "静音",
|
||||
"cls": "btn.btn-sm",
|
||||
"label": "把所有已完成视频片段打包下载",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
@@ -386,62 +400,41 @@
|
||||
"idx": 22,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "active",
|
||||
"label": "字幕",
|
||||
"cls": "placeholder.video-thumb",
|
||||
"label": "点击查看详情(历史版本/提示词/重跑)",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": true,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 61,
|
||||
"api": 0
|
||||
}
|
||||
"active": false,
|
||||
"verdict": "skipped-destructive"
|
||||
},
|
||||
{
|
||||
"idx": 23,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "",
|
||||
"label": "转场",
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "btn.btn-ghost.btn-sm",
|
||||
"label": "重跑",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 33,
|
||||
"api": 0
|
||||
}
|
||||
"verdict": "skipped-destructive"
|
||||
},
|
||||
{
|
||||
"idx": 24,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "",
|
||||
"label": "BGM",
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "btn.btn-ghost.btn-sm",
|
||||
"label": "下载",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 35,
|
||||
"api": 0
|
||||
}
|
||||
"verdict": "disabled"
|
||||
},
|
||||
{
|
||||
"idx": 25,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "btn.btn-sm.btn-primary",
|
||||
"label": "已开启",
|
||||
"cls": "btn",
|
||||
"label": "返回故事板",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
@@ -450,132 +443,70 @@
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 30,
|
||||
"api": 0
|
||||
"mutations": 35,
|
||||
"api": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"idx": 26,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "swatch-card.selected",
|
||||
"label": "真实分享朴素白底",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": true,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 35,
|
||||
"api": 0
|
||||
}
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 27,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "swatch-card",
|
||||
"label": "真实分享影视黑底",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 30,
|
||||
"api": 0
|
||||
}
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 28,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "swatch-card",
|
||||
"label": "真实分享手写描边",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": true,
|
||||
"mutations": 35,
|
||||
"api": 0
|
||||
}
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 29,
|
||||
"tag": "div",
|
||||
"role": "button",
|
||||
"cls": "swatch-card",
|
||||
"label": "真实分享综艺暖黄",
|
||||
"href": "",
|
||||
"disabled": false,
|
||||
"active": false,
|
||||
"verdict": "works",
|
||||
"signals": {
|
||||
"url": false,
|
||||
"overlay": false,
|
||||
"self": false,
|
||||
"mutations": 36,
|
||||
"api": 0
|
||||
}
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 30,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "tl-action",
|
||||
"label": "撤销",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
"verdict": "disabled"
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 31,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "tl-action",
|
||||
"label": "重做",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
"verdict": "disabled"
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 32,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "tl-action",
|
||||
"label": "在播放头处分割所在片段",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
"verdict": "disabled"
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 33,
|
||||
"tag": "button",
|
||||
"role": "",
|
||||
"cls": "tl-action",
|
||||
"label": "复制选中片段",
|
||||
"href": "",
|
||||
"disabled": true,
|
||||
"active": false,
|
||||
"verdict": "disabled"
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
},
|
||||
{
|
||||
"idx": 34,
|
||||
"label": "",
|
||||
"tag": "",
|
||||
"verdict": "stale"
|
||||
}
|
||||
],
|
||||
"missing": [
|
||||
"搜索",
|
||||
"E E2E 桥接测试团队 20260529",
|
||||
"余额 ¥14,907.00",
|
||||
"账户",
|
||||
"余额 ¥14,072.00",
|
||||
"拼接导出",
|
||||
"添加人物",
|
||||
"添加场景",
|
||||
"↻ 整体重写",
|
||||
|
||||
Reference in New Issue
Block a user