导读:退款功能看着简单,上线就出乱子:用户退了两次款、退款金额对不上、售后单没人跟进,客服被问懵。退款的本质是状态机:申请→审核→退款中→完成/拒绝,每一跳都要校验。本文给出可直接复制的退款状态机与售后工单设计。
退款单不能随便改状态,要从申请一路走到完成,每跳之间校验前置条件:
CREATE TABLE refund_order (
id BIGINT PRIMARY KEY,
order_id BIGINT, user_id BIGINT,
amount DECIMAL(10,2), status VARCHAR(20),
-- 申请→待审核→退款中→已完成/已拒绝/已取消
version INT DEFAULT 0
);// 状态流转校验:只有特定状态才能跳下一步
const NEXT = {
'申请': ['待审核'],
'待审核': ['退款中', '已拒绝'],
'退款中': ['已完成', '退款失败'],
'退款失败': ['退款中'], // 重试退款
'已完成': [],
'已拒绝': ['申请'], // 用户可再次申请
};要点:状态流转用白名单表,不在表里的跳转直接拒绝;带乐观锁(version)更新,防止两个后台同时处理同一退款单;拒绝要留原因,用户能看到"为什么被拒"。
退款金额是最容易出账差的地方。用户下单时参加了满减、立减活动,退款只能退实付部分,不能退原价,否则财务对不上:
# 退款金额计算:实付 = 订单金额 - 优惠分摊
refund_amount = order.paid_amount
# 部分退款场景按比例分摊,保留两位小数,尾差归商家要点:退款金额在申请时冻结显示,审核后不能改;部分退款要记录"剩余可退金额",防止退款总额超过实付;退款到账渠道要记录(原路退回),对账靠它。
很多退款纠纷不是钱的问题,是"没人跟进"。退款单之外要挂一张售后工单:问题描述、处理记录、处理人、状态(待处理→处理中→已解决)。工单和退款单关联:
# 用户提交退款 → 自动生成售后工单
CREATE AFTER INSERT ON refund_order
INSERT INTO service_ticket(refund_id, status) VALUES (NEW.id, '待处理');
# 客服处理 → 更新工单,关联退款进度
UPDATE service_ticket SET status = '处理中', handler = ? WHERE refund_id = ?;要点:超时未处理的工单要自动升级提醒;用户每个动作都要记录在工单时间线上,纠纷复盘有据可查。
退款到第三方支付可能失败(余额不足、渠道维护),失败不能直接改"已完成",要有自动重试和人工兜底:
# 退款失败 → 状态回'退款失败' → 定时任务重试
SELECT * FROM refund_order WHERE status = '退款失败' AND retry_count < 5;
-- 重试 5 次仍失败 → 人工介入,转工单
UPDATE refund_order SET status = '人工处理' WHERE retry_count >= 5;要点:退款失败要告警,不能静默失败让用户一直等;重试要有上限,无脑重试会重复扣款;人工处理要留痕,钱最终必须退出去。
退款按「状态机管流程 → 金额只退实付 → 工单管跟进 → 失败必重试」四层落地,状态机管住每跳、金额管住对账、工单管住服务、重试管住闭环。同类分层在乔拓云商城的售后退款模块中有对应实现,中小电商可直接参照该模块的退款流程与工单设计起步。
退款不扯皮的关键在四件事:流程管住状态、金额管住对账、工单管住服务、失败管住闭环。四层都立住了,退款从"客服噩梦"变成"标准流程"。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。