仓储与库存
本页是一篇完整方案指南:以 inventory 插件(com.auraboot.inventory,命名空间 inv,依赖 product-catalog + org-management)为例,从用户场景一路讲到开发实施和典型错误。它是 hybrid 插件——18 个 model、62 条命令、30 个页面用 DSL JSON 声明,而出库扣减、自动上架、批次溯源、余额事件投递这些有状态的写逻辑由插件自带的 PF4J handler(backend/,如 ConfirmWarehouseOutHandler、AutoPutawayHandler、LotTraceHandler、InventoryBalanceEventOutbox)实现。下面每个标识符你都能在插件里 grep 到、对运行实例调得通。
另有更轻的 OSS 模板
simple-inventory(命名空间tinv,只有产品/仓库/出入库 4 个 model),适合小型买卖存。本页讲完整 WMS。 源码(轻量模板):simple-inventory on GitHub ↗
1. 用户场景
一家电子元器件分销商,自有 raw_material(原料)、finished(成品)两类多个仓库,带库位。日常:
- 采购到货 → 收货质检 → 上架到库位 → 库存可用;
- 销售下单 → 系统分配/占用库存 → 生成拣货波次 → 拣货 → 出库;
- 元器件按批次/序列号管理,过期或不良要隔离/报废并可溯源;
- 仓间调拨需要审批;月度盘点要冻结、点数、确认差异。
仓管、销售、采购、生产、质检看到的库存视图和能做的操作各不相同。


2. 需求痛点
- 没有实时可用量:Excel 里的「库存」既不扣占用也不并发安全,超卖频发。
- 批次断链:哪一批料发给了哪个客户、是否在隔离期,事后查不到。
- 操作无授权无审计:谁在什么时候改了库存、为什么,没有记录;改库存只能靠人盯。
- 集成困难:销售单、生产领料、QC 报告想自动触发库存动作,却只能靠人工二次录入。
这些都不是「再加一张表」能解决的,而是受控状态变更的问题。
3. 常规解法 vs AuraBoot 的设计哲学
3.1 常规解法是怎样的
如果让一个团队从零做库存,通常是这条路:
- 领域建模:画实体和关系——产品、仓库、库位、入库单、出库单、批次、库存余额……
- 建表:把实体翻译成一堆
CREATE TABLE,加外键、索引、状态字段。 - 写 CRUD:每个实体一套 Repository / Service / Controller,增删改查全手写。
- 把业务规则 hard-code 进 service:出库扣减、状态流转(draft→confirmed)、「确认前必须有明细」的校验、「可用量 = 实有 − 占用」的计算——全写死在 Java 里。
- 各处补横切关注点:权限判断散落在每个 controller;审计靠手动插日志;想把库存变更发给下游,再搭一套 MQ。
- 前端:每个页面手写表单、列表、详情。
- 想接 AI / 自动化:对不起,得再包一层 API、再定义一遍权限和风险边界。
能跑,但业务规则散落在代码各处,改一条规则要同时动 service + controller + 前端;并发扣减、审计、事件、AI 入口每一样都得自己扛。三个月起步,而且越改越脆。
3.2 AuraBoot 的设计哲学
AuraBoot 把这件事反过来:业务的「是什么」用声明描述,「怎么执行」由运行时统一兜底。三条核心理念:
- 元数据驱动:model / field / command / page / permission 都是声明(DSL JSON),不是手写代码。平台据此自动建表、生成接口、渲染页面——上面第 2、3、6 步基本消失。
- 单一命令管道:所有写入都是一条命令,走同一条 命令管道。鉴权、校验、事务、审计、发事件这些横切关注点由管道统一处理,不写进每个业务里——你声明
inv:confirm_warehouse_out时只关心「draft→confirmed + 扣库存」,并发安全和留痕是白送的(第 4、5 步从「自己扛」变成「平台默认」)。 - 命令即契约:同一条命令同时服务 UI 按钮、自动化规则、BPM 节点、AI agent(靠
cmd_risk_level+agent_hint分级)。AI 原生不是事后包 API,而是天生的(第 7 步免了)。
3.3 同一个功能,两种活法
于是普通做法里那些「自己扛」的事,在 AuraBoot 变成平台契约的默认能力。每一格的 AuraBoot 列都是下面能 grep 到的真实命令/模型,不是宣传话术:
| 能力 | 自己写(手写后端) | 打包 ERP / 典型低代码 | AuraBoot(本插件) |
|---|---|---|---|
| 出库扣减并发安全 | UPDATE stock SET qty=qty-?,高并发超卖,自己加锁/重试 | 出入库表单现成,但扣减逻辑写死,改规则要二开 | 走 inv:confirm_warehouse_out,命令管道内事务 + 状态机守卫,天然不超卖 |
| 可用 / 实有 / 占用三态 | 自己加 reserved 字段,到处手维护、易漂移 | 多数只有实有量,预留/占用要定制 | inv_balance 三态(inv_bal_qty / available_qty / reserved_qty),inv:allocate_inventory 统一占用 |
| 变更事件 / 可集成 | 没有事件,靠定时批量对账 | 闭源,想 hook 库存变更很难 | inv_balance_event_outbox 事件源化,下游(对账/看板/生产)订阅事件,可靠不丢 |
| 批次溯源 / 隔离 | 自建批次表 + 手写溯源查询 | 有批次,溯源/隔离常要加购模块 | inv:trace_lot / inv:quarantine_lot / inv:scrap_lot,状态机内建 |
| 被自动化 / AI 调用 | 还要再包一层 API,且无风险分级 | 基本无原生 AI 入口 | 同一条命令带 cmd_risk_level + agent_hint,UI / 自动化 / BPM / AI agent 同一条路径,安全可控 |
| 权限 + 审计 | 散落在各 controller,易漏 | 角色粗粒度,字段级常缺 | 五层权限 + 审计内建在命令管道,每次变更自动留痕 |
一句话:手写要三个月、还得自己扛并发和审计;打包 ERP 快但改不动;AuraBoot 用声明式配置就拿到一套 production 级的库存内核,而且每个能力都能被 AI 安全驱动、被你自由扩展。 下面看它具体怎么搭。
4. 功能设计
4.1 数据模型(18 个)
| Model | 用途 | 关键状态值 |
|---|---|---|
inv_warehouse / inv_warehouse_location | 仓库 / 库位;仓库类型 raw_material / finished / semi_finished / general | inv_warehouse_status:draft / confirmed |
inv_balance | 按产品×仓库的实时余额 | 字段 inv_bal_qty、inv_bal_available_qty、inv_bal_reserved_qty、inv_bal_safety_stock、inv_bal_avg_cost |
inv_inbound / inv_inbound_line | 入库单 + 明细 | inv_in_status:draft → confirmed |
inv_outbound / inv_outbound_line | 出库单 + 明细 | — |
inv_transfer / inv_transfer_line | 调拨单 + 明细 | inv_transfer_status:draft → pending → approved → confirmed / cancelled |
inv_pick_order / inv_pick_order_line / inv_pick_wave_common | 拣货单 / 行 / 波次 | inv_pick_status:pending / in_progress / completed / cancelled |
inv_stock_check / inv_stock_check_line | 盘点单 + 明细 | — |
inv_lot / inv_lot_transaction | 批次/序列号 + 流水 | inv_lot_status:active / quarantine / expired / scrapped |
inv_inventory_hold | 库存占用/冻结 | inv_ih_status:active / released / expired |
inv_balance_event_outbox | 余额变更事件发件箱 | — |
4.2 命令与状态机
命令命名 inv:<动词>_<名词>。代表性命令:
| 命令 | 作用 |
|---|---|
inv:confirm_warehouse_in / inv:confirm_warehouse_out | 确认入库 / 出库 |
inv:auto_putaway | 入库自动上架到库位 |
inv:allocate_inventory / inv:hold_inventory | 分配 / 冻结(写 inv_inventory_hold) |
inv:generate_pick_order / inv:start_pick / inv:complete_pick_order | 生成 / 开始 / 完成拣货 |
inv:create_pick_wave / inv:release_wave | 创建 / 释放拣货波次 |
inv:submit_stock_check / inv:confirm_stock_check | 提交 / 确认盘点 |
inv:approve_stock_transfer / inv:confirm_stock_transfer | 审批 / 确认调拨 |
inv:quarantine_lot / inv:scrap_lot / inv:trace_lot | 批次隔离 / 报废 / 溯源 |
每条命令都是一段声明。例如 inv:confirm_warehouse_in(config/commands/inv_confirm_warehouse_in.json)的真实定义:
{
"code": "inv:confirm_warehouse_in",
"displayName:zh-CN": "确认入库",
"type": "state_transition",
"modelCode": "inv_inbound",
"stateField": "inv_in_status",
"fromStates": ["draft"],
"toState": "confirmed",
"handler": "inv:confirm_warehouse_in",
"validation": {
"rules": [
{ "type": "has_children", "childModel": "inv_inbound_line",
"parentField": "inv_in_line_receipt_id", "minCount": 1,
"message:zh-CN": "请至少添加一条入库明细后再确认" }
]
},
"permissions": ["inv.warehouse.manage"],
"agent_hint": "Transition inv inbound status from draft to confirmed.",
"cmd_risk_level": "L1"
}读出来的设计信息:这是一条 state_transition(draft → confirmed),带 has_children 校验(没有明细行不让确认),要求 inv.warehouse.manage 权限,风险级 L1,并通过 agent_hint 告诉 agent 它能做什么。确认后由 handler 按行更新库存。
4.3 权限与角色
8 个权限码(<模块>.<资源>.<动作>,每资源 manage + read):
inv.warehouse.manage inv.warehouse.read
inv.pick.manage inv.pick.read
inv.lot.manage inv.lot.read
inv.inventory_hold.manage inv.inventory_hold.read
6 个角色:inv_admin、inv_warehouse(仓管)、inv_sales、inv_purchaser、inv_production、inv_quality_engineer。
4.4 页面
30 个页面:各 model 的 list / detail、入出库录单、拣货作业、盘点、批次台账等;另有 2 个 dashboard。
5. 具体开发与实施
先掌握基础。本插件是 hybrid:模型 / 命令 / 页面是 DSL 声明,而出库扣减、上架、批次、余额事件投递等有状态写逻辑由插件自带的 handler(
backend/)实现——二者都建立在平台核心契约上。动手前请先读:Model 与 Field · Command · 命令管道 · Permission · 插件清单 · Plugin 开发 · Page Designer。
落地一个像 inventory 这样的 hybrid 插件,步骤是:
- 定义 model 与字段 ——
config/models.json+config/fields/,字段类型用平台dataType(string/integer/enum/decimal/date…),不要写string(120)这种内联长度(长度是单独字段属性)。详见 Model 与 Field。 - 声明命令 —— 每个 model 一个
config/commands/<model>.json,状态流转用type: state_transition+fromStates/toState,并在permissions绑权限码。详见 Command。- 有状态写逻辑实现为 handler —— 像扣减、上架、批次溯源、余额事件投递这种纯声明表达不了的,在
backend/写 handler(实现命令对应的执行逻辑),打成 PF4J jar。简单 CRUD / 纯状态流转不需要 handler;本插件这类复杂写逻辑才用。详见 Plugin 开发。
- 有状态写逻辑实现为 handler —— 像扣减、上架、批次溯源、余额事件投递这种纯声明表达不了的,在
- 配 model-field binding ——
config/bindings/,并在resourceDirs注册(见「典型错误」)。 - 设计页面 ——
config/pages/,列表/表单/详情用 Page Designer 出 DSL。 - 权限、角色、字典、菜单 ——
config/permissions.json/roles.json/dicts.json/menus.json。 - 打包导入 —— hybrid 插件先
shadowJar出 PF4J jar、放进平台aura.plugins.dir并重启加载,再用auraCLI 的import-directory-sync(参数是目录 path)或平台导入接口同步配置;校验返回success:true才算导入成功(纯 config 插件可跳过 jar 步)。注意依赖顺序:先product-catalog、org-management,再inventory。详见 插件清单。
6. 常见配置
- 安全库存预警:在
inv_balance.inv_bal_safety_stock上配阈值,用自动化规则在available_qty < safety_stock时发命令/通知。 - 批次策略:
inv_lot_type选batch(批次)或serial(序列号);过期/不良走inv:quarantine_lot→inv:scrap_lot,全程inv:trace_lot可溯源。 - 多仓与库位:
inv_warehouse_type区分原料/成品仓;inv_warehouse_location建库位,inv:auto_putaway自动上架。 - 占用与分配:销售/生产下游通过
inv:allocate_inventory/inv:hold_inventory写inv_inventory_hold,inv_ih_reference_type标明来源(sales_order / production_order / qc_report / rma)。
7. 典型错误
- 命令码用点号:写成
inv.warehouse.in.confirm跑不通——真实是冒号 + 动词_名词:inv:confirm_warehouse_in。 - 绕过命令直接改库存表:直接 UPDATE
inv_balance会跳过状态机、handler 的按行更新和inv_balance_event_outbox事件投递,导致下游对账错乱。一切库存变更都走命令。 - 确认时没有明细行:
inv:confirm_warehouse_in的has_children校验会拒绝(「请至少添加一条入库明细」)——这是设计,不是 bug。 - bindingRules 写进 commands.json 内联:不会被导入;必须独立
bindingRules.json并在resourceDirs注册,否则报[S-EXT-HANDLER] references unregistered handler。详见 纯配置 Plugin。 - 命令执行 payload 结构:字段放在
{ "payload": { ... }, "operationType": ... },目标记录用targetRecordId(不是recordId)——放错位会出现「执行成功却字段为空」的迷惑性报错。