修正代理主钱包余额快照口径
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m0s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m0s
代理主钱包扣款流水必须记录扣款前后的真实余额,避免资金概况与流水展示出现双重扣减错觉。 Constraint: 项目禁止自动化测试,使用构建和数据库对账验证。 Rejected: 在资金汇总接口按历史充值总量或流水末条余额展示 | 资金概况口径应来自主钱包剩余余额。 Confidence: high Scope-risk: narrow Directive: 修改代理钱包扣款链路时必须同时维护余额字段与流水快照一致性。 Tested: go build ./...;migrate up 已执行到 141;只读 SQL 对账确认主钱包余额、成功流水累计、最新流水余额一致且 mismatch_tx_count=0。 Not-tested: 未新增自动化测试(项目规范禁止)。
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
-- 回滚说明:本迁移是历史资金流水快照修复,不执行反向恢复。
|
||||
-- 反向恢复会重新制造余额不一致,破坏主钱包剩余余额口径。
|
||||
|
||||
SELECT 1;
|
||||
@@ -0,0 +1,59 @@
|
||||
-- 修复代理主钱包扣款流水余额快照
|
||||
-- 历史扣款流水曾在扣款后重新读取钱包,导致 balance_before/balance_after 多扣一次。
|
||||
-- 以成功流水的 amount 顺序累计值为准,重算主钱包流水快照,并同步主钱包剩余余额。
|
||||
|
||||
WITH ordered_transactions AS (
|
||||
SELECT
|
||||
t.id,
|
||||
SUM(t.amount) OVER (
|
||||
PARTITION BY t.agent_wallet_id
|
||||
ORDER BY t.created_at, t.id
|
||||
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
) AS repaired_balance_after,
|
||||
SUM(t.amount) OVER (
|
||||
PARTITION BY t.agent_wallet_id
|
||||
ORDER BY t.created_at, t.id
|
||||
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
) - t.amount AS repaired_balance_before
|
||||
FROM tb_agent_wallet_transaction t
|
||||
INNER JOIN tb_agent_wallet w ON w.id = t.agent_wallet_id
|
||||
WHERE w.wallet_type = 'main'
|
||||
AND w.deleted_at IS NULL
|
||||
AND t.deleted_at IS NULL
|
||||
AND t.status = 1
|
||||
),
|
||||
updated_transactions AS (
|
||||
UPDATE tb_agent_wallet_transaction t
|
||||
SET
|
||||
balance_before = ordered_transactions.repaired_balance_before,
|
||||
balance_after = ordered_transactions.repaired_balance_after,
|
||||
updated_at = NOW()
|
||||
FROM ordered_transactions
|
||||
WHERE t.id = ordered_transactions.id
|
||||
AND (
|
||||
t.balance_before <> ordered_transactions.repaired_balance_before
|
||||
OR t.balance_after <> ordered_transactions.repaired_balance_after
|
||||
)
|
||||
RETURNING t.agent_wallet_id
|
||||
),
|
||||
wallet_balances AS (
|
||||
SELECT
|
||||
t.agent_wallet_id,
|
||||
SUM(t.amount) AS repaired_balance
|
||||
FROM tb_agent_wallet_transaction t
|
||||
INNER JOIN tb_agent_wallet w ON w.id = t.agent_wallet_id
|
||||
WHERE w.wallet_type = 'main'
|
||||
AND w.deleted_at IS NULL
|
||||
AND t.deleted_at IS NULL
|
||||
AND t.status = 1
|
||||
GROUP BY t.agent_wallet_id
|
||||
)
|
||||
UPDATE tb_agent_wallet w
|
||||
SET
|
||||
balance = wallet_balances.repaired_balance,
|
||||
updated_at = NOW()
|
||||
FROM wallet_balances
|
||||
WHERE w.id = wallet_balances.agent_wallet_id
|
||||
AND w.wallet_type = 'main'
|
||||
AND w.deleted_at IS NULL
|
||||
AND w.balance <> wallet_balances.repaired_balance;
|
||||
Reference in New Issue
Block a user