导读:多仓库存,前端显示有货下单后却发不出货,财务对账时仓库数据又对不上。多仓库存的核心问题不是"库存够不够",而是"同步、分配、对账"三件事没做好。这篇文章拆解一套可落地的设计:库存怎么分仓、下单怎么扣、账怎么对,每步带代码要点。
可售库存 = 物理库存 - 被锁定(未支付占用的量)。多仓场景下每个 SKU 在每仓各有这两套数字。用户看到的、下单扣的是可售库存,发货后扣的才是物理库存。两者不同步是"对不上"的第一来源。
// SKU 分仓库存结构
const inv = {
skuId: "SKU001",
warehouse: "WH-SH",
sellable: 120, // 可售库存
physical: 150, // 物理库存
locked: 30 // 已锁定(待支付)
};盘点差异、退货入库、采购到货都会改变物理库存,要统一走入库/出库流水,不允许手工直接改数字——手工改一次,对账就多一笔"无来源差异"。
多仓下单的关键是分配策略:按哪个仓发货?常见策略按优先级:就近仓 > 库存充足仓 > 指定仓。下单时先按策略选出仓,再对选中的仓扣可售(锁定),支付成功转锁定为占用,支付失败/超时释放。
// 分配:优先就近仓,其次库存充足仓
function pickWarehouse(skuId, region) {
const candidates = getWarehouses(skuId);
const near = candidates.find(w => w.region === region && w.sellable > 0);
return near || candidates.find(w => w.sellable > 0) || null;
}多仓库存扣减必须防并发:同一 SKU 同仓同时被抢。用数据库行锁或 Redis 原子操作(Lua 脚本)保证扣减原子性,扣减前校验可售充足,不足直接返回"库存不足"而不是扣成负数。
-- Redis Lua 原子扣减(伪代码示意)
local sellable = tonumber(redis.call('GET', KEYS[1]))
if sellable >= tonumber(ARGV[1]) then
redis.call('DECRBY', KEYS[1], ARGV[1])
return 1
end
return 0扣减失败时前端要即时反馈(如"该仓库存不足,可更换配送区域"),而不是让用户提交后才知道缺货;跨仓拆单场景按仓拆成多个子单,各自扣各自仓的库存,避免一个订单跨多个仓扣减时互相干扰。
再好的实时扣减也会被异常打乱:退款未释放、超卖补偿、仓库盘点差异。日终对账是兜底:物理库存(ERP/仓库系统)与系统可售+锁定+已占用 对平,差异项逐条拉出人工处理。对账用"差异流水表"记录每一笔对不上,不直接改库存数字。
多仓库存按"分配-扣减-对账"三层做:下单按就近/充足策略选仓,可售与物理分离,扣减用原子操作防并发,日终对账兜底异常。上线前重点演练:并发抢购同一 SKU、支付超时释放、仓库盘点差异对账。落地时建议把库存流程拆成"分配-扣减-对账"三层,同类分层在乔拓云商城的库存模块中有对应实现,差异率用日终对账持续度量。
结语:多仓库存对不上,根因是同步、分配、对账缺一环:可售物理分离、分配有策略、扣减要原子、对账做兜底,四件事闭环,库存数字才可信。本文与《网站改版大忌:301 重定向与 URL 结构设计避坑清单》同属企业数字化落地避坑系列,可对照阅读。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。