大家好,我是十三。
导言:仓库里明明有 1000 件,为什么系统说只能卖 200 件
在上一篇文章中,我们聊完了库存的四大基础操作:入库、出库、盘点、调拨。这四件事解决了"货怎么进来、怎么出去、怎么核对、怎么搬运"的问题。
但有一个问题,这四篇文章都没有正面回答:
仓库的货架上明明放着 1000 件商品,销售打开系统,看到的可用数量却只有 200 件。剩下的 800 件去哪了?
答案是:它们还在仓库里,但不能卖。有的被客户预订了,有的被盘点冻结了,有的正在等待质检结果,还有一批正在从供应商那里运来的路上。
这就引出了我们今天要聊的核心概念:可用库存。它是库存管理中最关键的一个数字,也是销售、采购、仓库三个部门每天争论的焦点。
可用库存解决什么问题
要理解可用库存的价值,先看一个真实的业务困境。
假设你是销售,上午接到一个老客户电话,要下单 300 件某 SKU。你打开系统查询,账面库存显示 500 件,于是信心满满地告诉客户"有货,可以下单"。
客户下单后,仓库却反馈只能发出 200 件。原来在这 500 件中,有 150 件已经被其他订单锁定,有 100 件因为上午正在盘点而被冻结,还有 50 件是上午刚到货、质检结果还没出的待检品。
销售承诺了 300 件,实际只能发 200 件。客户不满,销售背锅,仓库喊冤。
业务定义:可用库存是指在特定时间点上,企业真正可以用于销售、生产领料或其他用途的库存数量。它不等于账面库存,也不等于实物库存,而是经过一系列业务规则计算后的"可动用"数量。
通俗理解:想象你钱包里有 1000 元现金,但其中 500 元是下周要交的房租,200 元已经答应借给朋友,100 元是刚收到的退款但还没到账。虽然你"有"1000 元,但你能自由支配的其实只有 200 元。可用库存就是这个道理。
没有这个指标,企业就会陷入"看起来有货、实际上发不出去"的混乱。销售盲目接单,仓库疲于解释,客户体验受损。可用库存的存在,就是为了在"账面数字"和"业务现实"之间架起一座桥梁。
三个容易混淆的概念
在讨论可用库存之前,必须先厘清三个经常被混为一谈的概念。
| 概念 | 通俗理解 | 计算方式 | 谁最关心 |
|---|---|---|---|
| 账面库存 | 系统里记录的库存总数 | 期初库存 + 累计入库 - 累计出库 | 财务部门 |
| 实物库存 | 仓库里实际摆放的货物数量 | 逐一清点或称重所得 | 仓库部门 |
| 可用库存 | 真正能被业务使用的库存数量 | 在库数量 - 冻结 - 已分配 + 在途 | 销售、采购 |
账面库存是财务视角的数字。它关心的是"资产有多少",不管这些货能不能动。只要入库单确认了,账面库存就增加;只要出库单确认了,账面库存就减少。盘点差异调整、暂估入账,都会影响账面库存。
实物库存是仓库视角的数字。它关心的是"货架上实际有多少"。实物库存可能和账面库存不一致,因为存在在途货物、损耗、盗窃、遗漏入库等情况。第 17 篇文章我们专门讨论过盘点,就是为了校准这两者之间的偏差。
可用库存是业务视角的数字。它关心的是"我现在能承诺多少"。可用库存必须在账面库存的基础上,扣除那些"已经被占用但还没出库"的部分,加上那些"还没入库但即将可用"的部分。
这三个数字,分别服务于不同的决策场景。财务做报表看账面库存,仓库管实物看实物库存,销售接单看可用库存。如果三个部门各自拿自己的数字去开会,结论永远对不上。
可用库存公式
理解了三个概念的差别,我们就可以进入今天的核心公式:
可用库存 = 在库数量 - 冻结数量 - 已分配数量 + 在途数量
这个公式并不复杂,但每个分量背后都有明确的业务含义。我们逐个拆解。
在库数量
业务定义:在库数量是指已经完成入库流程、存放在仓库指定库位上的货物数量。它是可用库存计算的起点。
通俗理解:在库数量就是"已经安家落户"的库存。货物经过收货、质检、上架,系统确认入库后,才计入在库数量。刚到仓库门口还没验收的、正在运输途中的,都不算在库。
在第 15 篇文章中,我们讨论过四种入库场景:采购入库、生产入库、退货入库、调拨入库。无论哪种场景,只有在系统中完成"入库确认"后,在库数量才会增加。
冻结数量
业务定义:冻结数量是指因特定业务原因被暂时锁定、不能用于销售或领料的库存数量。
常见冻结场景:
- 盘点冻结:仓库正在盘点某批货物,盘点完成前这批货不能被挪用。
- 质检冻结:货物刚到仓库,质检结果还没出,暂时不能销售。
- 待处理冻结:发现质量问题或标签错误,等待责任判定和处理方案。
- 预留冻结:为特定项目或客户预留的库存,普通销售订单不能使用。
冻结的本质是"暂停使用权"。货还在仓库里,所有权也没变,但在冻结解除之前,系统不允许任何人动用这批库存。第 17 篇文章讨论盘点时,我们详细解释过冻结机制的作用:它为盘点创造一个静止的参照系。
已分配数量
业务定义:已分配数量是指已经被销售订单、生产工单等业务单据锁定,但尚未实际出库的库存数量。
通俗理解:已分配就像餐厅里的"订位"。座位还空着,但已经被预订了。新的客人来了,你不能把他领到已预订的座位上去。
在第 16 篇文章中,我们讨论过出库的两种扣减策略:预扣和实扣。预扣就是在销售订单确认时,系统先将库存"分配"给这个订单,其他订单就不能再占用这部分库存。已分配数量,就是所有预扣订单的累计锁定量。
已分配和冻结的区别在于:冻结通常是操作层面的限制(盘点、质检),而分配是业务层面的承诺(客户已下单、生产已排程)。
在途数量
业务定义:在途数量是指已经下达采购订单或调拨单,但尚未完成入库的货物数量。
在第 6 篇文章中,我们专门讨论过采购在途的概念。已下单、供应商已确认、货物正在运输途中,这些货物虽然还没进仓库,但已经属于企业的资源,未来一定会变成可用库存。
在第 18 篇文章中,我们又看到了调拨在途。货物从 A 仓发出,还没到 B 仓,这段时间也属于在途。
为什么要在可用库存中加上在途?
如果不加,销售看到北京仓库存为 0,就会告诉客户"没货了"。但实际上,有 500 件正在从上海仓调往北京仓的路上,预计明天就到。加上在途数量,销售就能给出更准确的答复:"目前现货不足,但明天可以到货 500 件,可以先为您预留。"
一个完整的数值示例
我们用一张表来汇总一个 SKU 的库存状态:
| 分量 | 数量 | 含义 |
|---|---|---|
| 在库数量 | 1000 件 | 已完成入库,在货架上 |
| 冻结数量 | 150 件 | 正在盘点中 |
| 已分配数量 | 500 件 | 已确认的销售订单占用 |
| 在途数量 | 200 件 | 从供应商处采购,运输中 |
| 可用库存 | 550 件 | 1000 - 150 - 500 + 200 |
这个例子回答了文章开头的问题:账面在库有 1000 件,但可用库存只有 550 件。如果销售没有看到这个数字,直接按 1000 件去承诺,就会超卖 450 件。
库存分层模型
为了更好地理解可用库存的构成,我们可以把库存想象成一个多层结构。
graph TD
A[总库存视野] --> B[在库数量]
A --> C[在途数量]
B --> D[可用库存]
B --> E[冻结数量]
B --> F[已分配数量]
这个分层图展示了库存的两种基本状态:在库和在途。在库数量又被细分为三部分:可以直接动用的可用库存、因业务原因锁定的冻结库存、因订单承诺占用的已分配库存。
从数学关系上看:
在库数量 = 可用库存 + 冻结数量 + 已分配数量
总库存视野 = 在库数量 + 在途数量
对销售部门来说,最关心的是第一层分支中的可用库存。对采购部门来说,还要关注在途数量,因为它决定了未来几天的供应能力。对仓库部门来说,在库数量和其中的冻结数量决定了实际可操作的空间。
超卖防控:为什么可用库存是电商大促的生命线
超卖,是库存管理中最昂贵的错误之一。客户下单时系统显示有货,付款后仓库却发不出货,只能被迫退款、赔偿、道歉。大促期间一次超卖事件,可能引发数百次客诉,品牌损失远超商品本身的价值。
可用库存的设计,本质上就是为了防止超卖。但不同业务场景下,防超卖的策略并不相同。
场景一:双十一秒杀
秒杀场景的特点是瞬时流量极大、库存深度有限、售罄速度极快。
假设某热门 SKU 只有 1000 件库存,活动开始第一秒就有 10 万人同时点击购买。如果系统不做任何防护,1000 件库存可能在 0.1 秒内被同一批人重复扣减,导致超卖数倍。
秒杀场景的防护核心有两点:
第一,提前冻结库存。活动开始前,系统将秒杀商品的全部库存或大部分库存从"可用"状态转为"活动预留"状态。普通销售渠道不再能看到这批库存,避免活动开始前就被零散订单消耗。
第二,缩短锁定时长。秒杀订单的预扣有效期通常极短,比如 5 分钟未付款自动释放。这和普通订单的 24 小时锁定时长形成鲜明对比。锁定时长短,意味着库存被无效订单占用的风险低,即使发生大量未付款,也能快速回收库存继续售卖。
场景二:普通电商下单
普通场景没有秒杀那么极端,但并发量依然可观。同一款商品在同一时刻被多个客户加入购物车、提交订单,是日常运营中的常态。
普通场景的核心策略是预扣机制。客户点击"提交订单"的瞬间,系统立即检查可用库存。如果足够,立刻将对应数量从"可用"移到"已分配",并给客户一个支付倒计时。在倒计时结束前,其他客户看到的可用库存已经减少了。
如果客户未在时限内付款,系统自动释放预扣,库存回归可用池。第 16 篇文章中我们讨论过,预扣有效期是一个业务决策:太短会导致客户还没付完款库存就被释放,太长会导致库存周转率虚低。电商大促期间常见的做法是将有效期从 24 小时压缩到 15 分钟。
场景三:预售模式
预售是一种特殊的销售策略:商品还没到货,甚至还没生产,就开始接受订单。
预售场景下,可用库存的计算逻辑完全不同。系统没有实物库存可以预扣,只能根据在途数量或生产计划来"虚拟"可用库存。
例如,某商品预计 30 天后从工厂到货 5000 件。预售系统允许客户提前下单,但明确告知发货时间为 30 天后。此时系统分配的不再是"现有库存",而是"未来库存"。
预售对供应链计划的要求极高。如果实际到货量少于预售订单量,就会引发大规模延期发货。因此预售通常只用于需求相对确定、供应能力可控的商品,并且会设置预售上限,不会无限制接单。
两种锁的思路
在系统设计层面,防止超卖通常有两种思路。技术领域常把它们称为"悲观锁"和"乐观锁",但本质上它们是两种不同的业务排队策略。
悲观锁的思路是"排队"
当多个订单同时争抢同一件商品的库存时,系统让订单排队,一次只处理一个。就像银行柜台,一个窗口一次只服务一位客户,其他人拿号等待。这种方式简单直接,不会出现两个人同时抢到同一件库存的情况。代价是高峰期的处理速度会下降,排队订单多了,客户会感到卡顿。
乐观锁的思路是"先拿后验"
系统允许多个订单同时"尝试"扣减库存,但在真正保存结果之前,检查这个库存有没有被别人先一步占用。如果发现已经被占用了,就告诉客户"库存不足,请重试"。就像抢购时两个人同时奔向最后一件商品,先到的人拿走,后到的人看到货架空了。这种方式处理速度快,但可能会有少量客户体验到"明明看到了库存,下单时却提示无货"。
大多数电商系统会根据业务场景混合使用这两种思路。秒杀用"排队",普通下单用"先拿后验",预售则走独立的计划库存逻辑。
实时性挑战:库存扣减的原子操作
无论采用哪种防超卖策略,库存扣减都有一个根本要求:检查库存和扣减库存必须是一步完成的,中间不能被其他操作打断。
如果系统先检查库存(发现还有 1 件),然后停下来处理别的事情,另一个订单也在同一时刻检查库存(也发现还有 1 件),两个订单都会认为自己可以成交。结果两个客户都付了款,仓库却只有 1 件货。
这种"检查"和"扣减"两步之间的时间差,就是超卖的根源。
用一段简化的伪代码来理解正确的库存扣减逻辑:
function allocateStock(sku, requestQty, orderNo) {
const record = db.stock.findOne({ sku: sku });
const available = record.onHand
- record.frozen
- record.allocated
+ record.inTransit;
if (available < requestQty) {
return { ok: false, reason: "可用库存不足" };
}
record.allocated += requestQty;
db.stock.save(record);
logInventoryChange({
sku: sku, qty: requestQty, type: "分配", orderNo: orderNo
});
return { ok: true, remaining: available - requestQty };
}
这段代码的关键在于:findOne 查询库存记录、计算可用量、save 保存更新结果,这三步在数据库层面必须是一个不可分割的整体。就像银行柜员数钱、核对、递给你的过程,期间不能让第二个人同时把手伸进同一个抽屉。
在实际系统中,这个"不可分割"通常由数据库的锁定机制保证。当订单 A 正在修改某 SKU 的库存记录时,订单 B 必须等待 A 完成才能读取。这种等待在毫秒级完成,客户几乎无感知,但却从根本上杜绝了并发超卖。
可用库存与其他模块的关系
可用库存不是孤立存在的数字。它的准确性依赖于上游多个模块的数据质量,它的变化又会触发下游多个模块的业务动作。
与销售订单 SO 的关系
在第 8 篇文章中,我们讨论了销售订单 SO 的生成流程。当 SO 被确认时,可用库存必须同步减少——这就是预扣机制。
如果 SO 被客户取消,已分配的数量要释放回可用池。如果 SO 被修改(比如客户要求从 100 件改成 80 件),已分配数量也要相应调整。可用库存和销售订单之间,是一对实时联动的关系。
与出库的关系
第 16 篇文章详细拆解了出库的四种场景。出库确认时,系统需要完成两步动作:一是将已分配数量转为实际出库(减少在库数量),二是将库存扣减从"预扣"转为"实扣"。
如果出库时发现实物数量少于系统显示的在库数量,可用库存的计算就会出现偏差。这也是为什么第 17 篇文章强调盘点的重要性——盘点校准的不仅是账面库存,更是后续所有可用库存计算的基准。
与在途的关系
第 6 篇文章讨论了采购在途,第 18 篇文章又补充了调拨在途。在途数量是可用库存公式中的"加法项",但它有一个时间属性:在途货物不是立即可用,而是"预计 X 天后可用"。
系统在处理在途时,通常需要区分"当前可用库存"和"未来可用库存"。当前可用库存不包含在途,未来可用库存(如 3 天后)才将在途纳入计算。销售在答复客户"什么时候有货"时,依据的往往不是当前可用库存,而是带时间维度的可用库存预测。
与采购计划的关系
可用库存还直接驱动采购决策。当可用库存低于某个阈值时,系统触发补货提醒;当可用库存加上在途数量仍不能满足未来需求时,采购部门需要新建 PO。下一篇文章我们要讨论的安全库存,就是这个阈值的核心设定依据。
总结
回顾今天的内容,可用库存是连接"仓库里的货"和"业务能用的货"的关键桥梁。
我们厘清了三组概念:账面库存是财务视角的总数,实物库存是仓库视角的实际数,可用库存是业务视角的可动数。
我们拆解了核心公式:可用库存 = 在库数量 - 冻结数量 - 已分配数量 + 在途数量。每个分量都有明确的业务来源和系统记录依据。
我们讨论了超卖防控的三种场景:秒杀靠提前冻结和短锁定时,普通下单靠预扣机制,预售靠未来库存规划。
我们也触及了库存扣减的实时性挑战:检查与扣减必须原子化,这是防止并发超卖的技术底线。
最后,我们把可用库存放回了整个业财系统的上下文:它从 SO 接收预扣指令,向出库提供发运依据,从在途获取未来补给,向采购输出补货信号。
理解可用库存,就是理解为什么企业的库存管理不能只看"有多少",而必须回答"有多少能用、什么时候能用、能被谁用"。
在下一篇文章中,我们将探讨库存管理的另一个核心概念:安全库存。当需求波动和供应延迟同时发生时,企业应该在仓库里保留多少"缓冲垫",才能既不积压资金,又不断货停产。
往期回顾
- 业财通识18:调拨——多仓协同的物流调度
- 业财通识17:盘点——账实一致的最后防线
- 业财通识16:出库——从销售发货到领料消耗
- 业财通识15:入库——四种场景下的库存增加
- 业财通识14:应收账款——从开票到回款的风险管控
- 业财通识13:价格策略——多维定价与动态调整
- 业财通识12:一个客户,为什么会有三条记录?——CRM 作为主数据底座的三层模型
- 业财通识11:从开票到收款,企业如何收回每一分钱?
- 业财通识10:当货物发出,系统里发生了什么?
- 业财通识09:订单确认前,系统如何防止坏账风险?
- 业财通识08:企业赚钱的第一步,从"潜在客户"到"销售合同"
- 业财通识07:业财难点之"暂估入账"与冲销
- 业财通识06:什么是采购在途?它对库存预测的价值
- 业财通识05:商品世界的基石——SPU 与 SKU
- 业财通识04:万事俱备,如何优雅地"打款"给供应商?
- 业财通识03:收到供应商账单,能直接付款吗?
- 业财通识02:当货物上门,系统里发生了什么?
- 业财通识01:企业花钱的第一步,从"购物清单"到"法律合同"
关于十三Tech
资深服务端研发工程师、架构师、AI 编程实践者。
专注分享真实的技术实践经验,持续记录企业系统、架构设计与 AI 编程实践。