system column十三Tech
← 返回业财专栏
ERP

业财通识19:可用库存——为什么账上有货却不能卖

2026/2/1118 min read
ERP库存可用库存超卖防控十三Tech

大家好,我是十三。

导言:仓库里明明有 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 接收预扣指令,向出库提供发运依据,从在途获取未来补给,向采购输出补货信号。

理解可用库存,就是理解为什么企业的库存管理不能只看"有多少",而必须回答"有多少能用、什么时候能用、能被谁用"。

在下一篇文章中,我们将探讨库存管理的另一个核心概念:安全库存。当需求波动和供应延迟同时发生时,企业应该在仓库里保留多少"缓冲垫",才能既不积压资金,又不断货停产。


往期回顾


关于十三Tech

资深服务端研发工程师、架构师、AI 编程实践者。
专注分享真实的技术实践经验,持续记录企业系统、架构设计与 AI 编程实践。