导读:门店退换货最怕两件事:货收回来了没人知道往哪放,钱退了但单据对不上。线下退换货不是“把货退回去”一个动作,而是一条从登记到质检、从回库到换货/退款的完整流转。本文给一套可抄走的落地流程:退换货单怎么建、质检怎么判定、货怎么回库、账怎么对平,并附状态机与对照表。
一次完整的门店退换货,至少要经过五个环节:
这五个环节任何一个断了,就会出现“货收了但库存没回补”“钱退了但单据还在待处理”之类的对不上。
不要为退、换、修各建一套单,用一张退换货单贯穿全流程,状态字段驱动流转:
{
"returnNo": "TH202610150001",
"orderNo": "SO202610140031",
"sku": "SKU-1032",
"qty": 1,
"reason": "尺码不合适",
"qualityCheck": { "result": "PASS", "handler": "E1001", "time": "2026-10-15 10:20:00" },
"status": "SETTLED",
"settleType": "REFUND",
"refundAmount": 129.0,
"createdAt": "2026-10-15 10:05:00"
}要点:质检结果、处理人、处理时间都作为独立字段记录,而不是写在备注里——后续对账、追责、复盘都靠它。
质检最容易出的问题是不规范:同一个商品,今天能退明天不能退。把判定收敛成明确的状态机,每个状态只允许固定的迁移:
当前状态 | 允许的判定 | 下一状态 |
|---|---|---|
待质检 | 通过 | 待回库 |
待质检 | 不通过(质量问题) | 待协商 |
待质检 | 换新 | 待换货 |
待回库 | 入库完成 | 待结算 |
待结算 | 退款完成/换货出库 | 已完成 |
待协商 | 协商完成 | 待回库 / 已完成 |
const RETURN_STATUS = {
PENDING_CHECK: '待质检',
PASS: '待回库',
NEGOTIATING: '待协商',
PENDING_EXCHANGE: '待换货',
PENDING_SETTLE: '待结算',
DONE: '已完成',
};
function canTransit(from, to) {
const rules = {
PENDING_CHECK: ['PASS', 'NEGOTIATING', 'PENDING_EXCHANGE'],
PASS: ['PENDING_SETTLE'],
NEGOTIATING: ['PASS', 'DONE'],
PENDING_EXCHANGE: ['DONE'],
PENDING_SETTLE: ['DONE'],
};
return (rules[from] || []).includes(to);
}要点:非法迁移直接报错并留痕;对“跳过质检直接退款”这类越权操作,要在后端拦截而不是靠前端隐藏按钮。
质检通过后,商品回库并回补库存,同时生成库存流水。这里最容易漏的是“货回了但库存没动”,或者“退款退了但订单状态还挂着”。
BEGIN;
UPDATE inventory SET stock = stock + 1, updated_at = NOW()
WHERE sku = 'SKU-1032' AND store_id = 5;
INSERT INTO inventory_flow (sku, store_id, change_type, delta, return_no, created_at)
VALUES ('SKU-1032', 5, 'RETURN_IN', 1, 'TH202610150001', NOW());
UPDATE return_order SET status = 'PENDING_SETTLE', updated_at = NOW()
WHERE return_no = 'TH202610150001';
COMMIT;要点:库存回补和状态迁移放在同一个事务里,要么都成功要么都回滚,避免“半对账”状态。
退款环节同样要对平:退款金额必须与退换货单上的金额一致,退款成功后再把退换货单置为“已完成”,并写一条结算流水。对账口径统一为:退换货单数 = 回库流水数 = 结算流水数,三条线数字一致才算闭环。
换货和退货的最大区别是多了“出库”环节:顾客把旧货交回来,门店要把新货发出去。换货流程建议单独走一条状态分支,而不是在退货单上硬挂一个换货字段:
EXCHANGE_OUT;{
"returnNo": "TH202610150002",
"status": "PENDING_EXCHANGE",
"exchangeOut": {
"outNo": "EO202610150001",
"sku": "SKU-2011",
"qty": 1,
"picked": true,
"pickedAt": "2026-10-15 14:30:00"
}
}要点:换货出库与退货回库是两条独立流水,都要在退换货单上留痕;顾客取货后状态才可关闭,避免“货没拿走但单据已完结”的对不上。
退换货涉及退款,天然是敏感操作。三件事必须做:
INSERT INTO return_operation_log (return_no, action, operator, from_status, to_status, created_at)
VALUES ('TH202610150002', 'QUALITY_PASS', 'E1001', 'PENDING_CHECK', 'PENDING_EXCHANGE', NOW());要点:操作日志与退换货单分开存储,但用退换货单号关联;日结或纠纷复盘时,任何一笔状态变化都能定位到操作人与时间。
门店每天日结时,退换货数据要并入当日报表:当日退款笔数、退款金额、换货出库数量、回库数量。建议在日结任务里加一道校验:当日“已完成”退换货单的退款金额合计,应等于当日退款流水合计;不相等则日结挂起并提示对账,而不是带着差异静默通过。
要点:把“退换货对账”做成日结的强制校验项,差异当天发现、当天处理,避免月底集中对账时翻旧账。
退换货单上的原因字段积累起来就是一张“问题地图”:尺码不合适集中说明码数标注有问题,质量问题集中说明供应商或物流有问题。每月按原因聚合一次,把 TOP3 原因反馈给采购与运营,退换货率才有下降的抓手。这块属于“数据度量”而非“事后补救”,是流程闭环的最后一步。
退换货流程建议按“单据 + 状态机 + 库存流水 + 结算流水”四层设计:单据承载信息,状态机约束流转,流水承载账务。同类分层在乔拓云门店系统的售后模块中有对应实现,线上运营中最常见的问题集中在“质检判定不规范”和“库存回补与单据状态不同步”两处,先补上这两块,对账类问题会大幅减少。
门店退换货看着是客服动作,实际是库存、单据、资金三条线的联动。把流程拆成登记、质检、回库、结算四个阶段,每阶段有明确状态、有留痕流水,账就永远对得平。先把状态机和事务边界立起来,再逐步规范质检标准,是最不容易返工的做法。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。