-- ============================================================================= -- 修复订单 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_refund(refund_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=2(UpdateWithVersion) -- -> 按代理汇总扣减额,agent_wallet 先扣冻结再扣可用(UpdateWithVersion) -- -> agent_wallet_transaction 插入 type=refund、金额为负的流水 -- -- 本 SQL 对应关系: -- Step 2 = createRefundRecordAndUpdateOrder 的 Insert order_refund(platform_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 2~5 已包在事务中:任一步报错请执行 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;