This commit is contained in:
2026-02-12 15:16:54 +08:00
parent 07bf234b30
commit ca6dcc1b24
21 changed files with 2594 additions and 111 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,285 @@
-- =============================================================================
-- 修复订单 Q_176967208700018143d9f6支付宝已退款成功但库内未完成
-- =============================================================================
--
-- 【原因简述】
-- 后台发起支付宝退款后,支付宝侧已退款成功,但创建退款记录时因 unique_refund_no
-- 冲突Duplicate entry 'refund-Q_176967208700018143d9f6')导致 createRefundRecordAndUpdateOrder
-- 失败,后续流程未执行:订单未置为 refunded、未写退款记录、未扣代理佣金与钱包。
--
-- 【本单实际退款金额】支付宝已退 99.5 元(非整单金额)
--
-- 【与 adminrefundorderlogic 退款链路对照】
-- 代码路径AdminRefundOrder -> handleAlipayRefund -> createRefundRecordAndUpdateOrder + HandleCommissionAndWalletDeduction
--
-- handleAlipayRefund 成功分支:
-- 1) createRefundRecordAndUpdateOrder(order, req, refundNo, refundResp.TradeNo, ...)
-- -> 事务内Insert order_refundrefund_no, platform_refund_id=TradeNo, order_id, user_id, product_id, refund_amount, status=success, refund_time=NOW()
-- -> 事务内Update order仅 code 中赋了 status=refunded未显式设 refund_time/version
-- 2) HandleCommissionAndWalletDeduction(ctx, svcCtx, nil, order, req.RefundAmount)
-- -> 该订单下 agent_commission按 refundAmount 比例冲减refunded_amount 增加,满额则 status=2UpdateWithVersion
-- -> 按代理汇总扣减额agent_wallet 先扣冻结再扣可用UpdateWithVersion
-- -> agent_wallet_transaction 插入 type=refund、金额为负的流水
--
-- 本 SQL 对应关系:
-- Step 2 = createRefundRecordAndUpdateOrder 的 Insert order_refundplatform_refund_id 修复时无支付宝 TradeNo 填 NULL可从支付宝补
-- Step 3 = createRefundRecordAndUpdateOrder 的 Update order并显式补全 refund_time、version+1
-- Step 4 = HandleCommissionAndWalletDeduction 对 agent_commission 的冲减(按 99.5 比例)
-- Step 5 = HandleCommissionAndWalletDeduction 对 agent_wallet 扣减 + agent_wallet_transaction 插入
--
-- 【执行前请确认】
-- 1该订单在支付宝侧已退款成功2已备份相关表或先在测试环境执行。
-- Step 25 已包在事务中:任一步报错请执行 ROLLBACK若 step 1 未查到订单_order_not_found=1勿执行后续。
-- =============================================================================
-- 与表字段 collation 一致,避免 #1267 Illegal mix of collations若表为 utf8mb4_general_ci 则改为 COLLATE utf8mb4_general_ci
SET
@order_no = CONVERT(
'Q_176967208700018143d9f6' USING utf8mb4
) COLLATE utf8mb4_general_ci;
-- 本单实际退款金额(元)
SET @repair_refund_amount = 99.5;
-- 1) 取订单信息
SELECT
id,
user_id,
product_id,
amount,
version INTO @order_id,
@user_id,
@product_id,
@order_amount,
@order_version
FROM `order`
WHERE
order_no = @order_no
AND del_state = 0
LIMIT 1;
SET @refund_amount = @repair_refund_amount;
-- 若无记录则说明订单号错误,终止
SELECT IF(@order_id IS NULL, 1, 0) AS _order_not_found;
-- 若 _order_not_found=1 请勿继续执行后续语句
-- ---------- 以下为事务:任一步报错请执行 ROLLBACK ----------
START TRANSACTION;
-- 2) 补写退款记录(若该订单尚无成功状态的退款记录)
-- 代码中 platform_refund_id 来自支付宝 refundResp.TradeNo修复时无则填 NULL如有支付宝退款单号可事后 UPDATE 补上
INSERT INTO
order_refund (
refund_no,
order_id,
user_id,
product_id,
platform_refund_id,
refund_amount,
refund_reason,
status,
del_state,
version,
refund_time,
close_time,
delete_time
)
SELECT
CONCAT(
'refund-',
@order_no,
'-repair'
),
@order_id,
@user_id,
@product_id,
NULL,
@refund_amount,
NULL,
'success',
0,
0,
NOW(),
NULL,
NULL
FROM (
SELECT 1
) _one
WHERE
NOT EXISTS (
SELECT 1
FROM order_refund
WHERE
order_id = @order_id
AND status = 'success'
AND del_state = 0
);
-- 3) 订单状态改为已退款
UPDATE `order`
SET
status = 'refunded',
refund_time = NOW(),
version = version + 1,
update_time = NOW()
WHERE
id = @order_id
AND del_state = 0
AND status = 'paid';
-- 4) 代理佣金:按本次退款 99.5 元在该订单的佣金上比例冲减refunded_amount 增加,满额则 status=2
SET
@total_available = (
SELECT COALESCE(
SUM(amount - refunded_amount), 0
)
FROM agent_commission
WHERE
order_id = @order_id
AND del_state = 0
);
UPDATE agent_commission
SET
refunded_amount = LEAST(
amount,
refunded_amount + @repair_refund_amount * (amount - refunded_amount) / NULLIF(@total_available, 0)
),
status = CASE
WHEN LEAST(
amount,
refunded_amount + @repair_refund_amount * (amount - refunded_amount) / NULLIF(@total_available, 0)
) >= amount THEN 2
ELSE status
END,
version = version + 1,
update_time = NOW()
WHERE
order_id = @order_id
AND del_state = 0
AND @total_available > 0;
-- 5) 代理钱包扣减 + 流水(仅对尚未存在本单退款流水的代理扣减,避免重复执行导致重复扣款)
DROP TEMPORARY TABLE IF EXISTS _repair_wallet_snapshot;
CREATE TEMPORARY TABLE _repair_wallet_snapshot (
agent_id BIGINT NOT NULL,
balance_before DECIMAL(20, 4) NOT NULL,
frozen_before DECIMAL(20, 4) NOT NULL,
total_deduct DECIMAL(20, 4) NOT NULL,
PRIMARY KEY (agent_id)
);
-- 按 99.5 元在该订单各代理间按“可退佣金”比例分配扣减额(与 step 4 一致),仅扣减额>0 的代理
INSERT INTO
_repair_wallet_snapshot (
agent_id,
balance_before,
frozen_before,
total_deduct
)
SELECT
agent_id,
balance_before,
frozen_before,
total_deduct
FROM (
SELECT
c.agent_id, w.balance AS balance_before, w.frozen_balance AS frozen_before, @repair_refund_amount * COALESCE(
SUM(c.amount - c.refunded_amount), 0
) / NULLIF(@total_available, 0) AS total_deduct
FROM
agent_commission c
JOIN agent_wallet w ON w.agent_id = c.agent_id
AND w.del_state = 0
WHERE
c.order_id = @order_id
AND c.del_state = 0
AND @total_available > 0
AND NOT EXISTS (
SELECT 1
FROM agent_wallet_transaction t
WHERE
t.agent_id = c.agent_id
AND t.transaction_id = @order_no
AND t.transaction_type = 'refund'
AND t.del_state = 0
)
GROUP BY
c.agent_id, w.balance, w.frozen_balance
) _agent_deduct
WHERE
total_deduct > 0;
-- 从钱包扣减:优先扣冻结余额,不足再扣可用余额
UPDATE agent_wallet w
INNER JOIN _repair_wallet_snapshot r ON w.agent_id = r.agent_id
SET
w.frozen_balance = w.frozen_balance - LEAST(
r.total_deduct,
w.frozen_balance
),
w.balance = w.balance - (
r.total_deduct - LEAST(
r.total_deduct,
w.frozen_balance
)
),
w.version = w.version + 1,
w.update_time = NOW()
WHERE
w.del_state = 0;
-- 插入退款流水(金额为负数)
INSERT INTO
agent_wallet_transaction (
delete_time,
del_state,
version,
agent_id,
transaction_type,
amount,
balance_before,
balance_after,
frozen_balance_before,
frozen_balance_after,
transaction_id,
related_user_id,
remark
)
SELECT
NULL,
0,
0,
r.agent_id,
'refund',
- r.total_deduct,
r.balance_before,
r.balance_before - (
r.total_deduct - LEAST(
r.total_deduct,
r.frozen_before
)
),
r.frozen_before,
r.frozen_before - LEAST(
r.total_deduct,
r.frozen_before
),
@order_no,
NULL,
'订单退款修复(支付宝已退,库内补单)'
FROM _repair_wallet_snapshot r;
DROP TEMPORARY TABLE IF EXISTS _repair_wallet_snapshot;
COMMIT;
-- ---------- 事务结束 ----------
-- 6) 校验(可选)
-- 订单应为 refunded
-- SELECT id, order_no, status, refund_time FROM `order` WHERE id = @order_id;
-- 应有 success 退款记录refund_amount = 99.5
-- SELECT * FROM order_refund WHERE order_id = @order_id AND del_state = 0;
-- 佣金 refunded_amount 按 99.5 比例增加,满额则 status=2
-- SELECT id, agent_id, order_id, amount, refunded_amount, status FROM agent_commission WHERE order_id = @order_id;