Yii进销存系统业务模型需以5类核心实体为基础,通过ActiveRecord注入校验与业务逻辑,库存余额必须由StockLog流水实时聚合计算,所有主表预留扩展字段与软删除支持。

用 Yii 开发进销存系统,业务模型(Model)是整个系统的数据基石和逻辑中枢。它不单是数据库表的映射,更要承载采购、销售、库存变动、成本核算等核心规则。模型搭得扎实,后续控制器、视图、权限和报表才不会反复返工。
明确核心业务实体与关系
先梳理清楚进销存最关键的 5 类实体及其主从关系,避免后期字段冗余或关联断裂:
- 商品(Product):唯一标识(SKU)、名称、单位、默认进价/售价、是否启用——这是所有单据的基准;
- 供应商(Supplier) 和 客户(Customer):独立建模,不要合并为“联系人”,因二者在采购单/销售单中用途、字段(如账期、开票信息)完全不同;
- 采购单(PurchaseOrder) 与 销售单(SalesOrder):主表含单号、日期、状态、关联供应商/客户;明细表(PurchaseItem / SalesItem)必须单独建表,记录商品、数量、单价、折扣、实付金额;
- 库存流水(StockLog):不可省略!每笔入库、出库、调拨、盘点都生成一条日志,含操作类型、单据ID、商品ID、变动数量、操作时间、操作人——它是库存余额计算的唯一可信来源。
用 ActiveRecord 建模并注入业务约束
Yii 的 ActiveRecord 不仅做 CRUD,更是业务规则的载体。以 PurchaseItem 为例:
- 在
rules()中强制校验:['quantity', 'number', 'min' => 0.01]防止零或负数入库; - 重写
beforeSave()自动计算小计:$this->amount = $this->quantity * $this->unit_price;; - 定义关联:
public function getProduct() { return $this->hasOne(Product::class, ['id' => 'product_id']); },方便后续查商品名称、单位; - 添加事务钩子:在采购单主表的
afterSave()中触发库存更新,确保单据保存与库存变动原子性。
库存余额必须由流水实时推算
切忌在商品表里设一个 stock_quantity 字段并手动增减——这极易因并发或异常中断导致数据错乱。正确做法是:
- 商品表只保留
initial_stock(期初数)作为参考,不参与运算; - 库存余额通过
StockLog表聚合计算:StockLog::find()->where(['product_id' => $id])->sum('change_quantity'); - 高频查询场景下,可加 Redis 缓存该结果,但缓存失效必须绑定到
StockLog的增删操作; - 定期执行库存盘点单,生成反向流水(如盈亏调整),保持账实一致。
预留扩展字段与软删除支持
中小企业的业务常快速演进,建模时需留余地:
- 所有主表加
created_by、updated_by、created_at、updated_at,便于追溯和审计; - 使用软删除(
is_deletedtinyint 默认 0)而非物理删除,保障单据关联完整性; - 为未来可能的多仓库、多计量单位、批次/效期管理,提前在商品、库存流水表中预留
warehouse_id、unit_id、batch_no、expire_date等字段,即使初期不用也先建好; - 关键单据(如采购单)的状态字段用整型枚举(如 1=草稿、2=已提交、3=已入库、4=已关闭),比字符串更易索引且不易拼错。
模型不是一次写完就封存的,它要随业务理解加深持续迭代。重点守住三点:实体边界清晰、变动有迹可循、余额可推可验。不复杂但容易忽略。


















