Yii框架可构建健壮WMS,需用Service层统一库存操作、事务+原子校验保障账实一致、Behavior封装通用规则、ActiveRecord实现批次/FIFO管理。

Yii 框架本身不专为仓储业务设计,但凭借其清晰的 MVC 结构、强大的 ActiveRecord、灵活的验证规则和成熟的扩展生态,完全能支撑起一套健壮、可维护的仓储管理系统(WMS)。关键不在框架多“重”,而在于如何用好它的机制来贴合库存业务的真实逻辑——比如数量不可负、批次需追溯、调拨要闭环、盘点须留痕。
库存变动必须走事务 + 原子校验
入库、出库、调拨等操作本质是库存数量变更,任何环节出错都可能导致账实不符。Yii 中不能只靠前端传参或简单 SQL UPDATE。
- 所有库存写操作统一收口到 Service 层(如 InventoryService::adjustStock()),禁止 Controller 直接调用 Model save()
- 使用 $transaction = Yii::$app->db->beginTransaction() 包裹核心逻辑,包含:检查可用库存(出库前)、更新主表、写入明细流水、生成单据号、触发通知(如预警)
- 校验必须在事务内完成:例如出库时查 ItemStock::find()->where(['item_id' => $id, 'warehouse_id' => $wid])->andWhere('stock_qty >= :qty', [':qty' => $outQty])->one(),失败则 throw Exception 回滚
用行为(Behavior)封装通用库存规则
多个模型(如采购单、销售单、调拨单)都会影响库存,重复写校验和扣减逻辑易出错。Yii 的 Behavior 是解耦利器。
- 定义 StockOperationBehavior,绑定到各业务单据 Model 上
- 在 beforeSave() 中自动校验单据状态是否允许执行(如“已审核”才可出库)
- 提供 executeStockChange() 方法,统一处理:锁定库存行、更新 quantity 字段、记录 stock_log 表(含 operator_id、reason、before/after qty)
- 避免在每个控制器里手写 if-else 判断“能不能出”“够不够出”
批次与效期管理靠关联 + 查询优化
药品、食品、电子料件等场景要求按批号/生产日期/有效期管理。Yii ActiveRecord 天然适合表达这种关系。
- 建立 item_batch 表,字段含 item_id、batch_no、produce_date、expire_date、init_qty、current_qty
- 在 ItemStock 模型中定义 getBatches() 关联,使用 viaTable 或 hasMany() 链接到批次
- 出库时优先按“先进先出(FIFO)”选批次:用 ItemBatch::find()->where(...)->orderBy('produce_date')->one(),再扣减 current_qty
- 对 expire_date 建索引,配合 andFilterWhere([' 快速筛临期品
盘点差异处理要留痕且可反向冲正
盘点不是简单覆盖库存数,而是记录“盘盈/盘亏”动作,并支持后续核查与调整。
- 盘点单(inventory_check)状态分:草稿、已提交、已审核、已结账
- 差异行(check_item)存实际数、系统数、差异数、差异类型(盈/亏)、原因说明
- 审核通过后,不直接 UPDATE item_stock.quantity,而是调用 StockService::applyCheckResult($checkId),该方法生成一条 type=‘check_adjust’ 的库存流水,并更新 stock_qty
- 保留原始盘点单快照(JSON 存档或独立历史表),确保日后可追溯“谁在哪天盘了多少,为什么差”
不复杂但容易忽略:库存业务的核心不是“怎么改数字”,而是“为什么能改、谁允许改、改完有没有证据”。Yii 提供了足够好的骨架,真正决定系统可靠性的,是你在 Service 层写的那几行事务逻辑和在 Behavior 里埋下的那些约束钩子。


















