引言
本文件面向DouPHP电商系统的“采购入库集成”模块,目标是提供一套完整的表结构设计文档与业务流程说明。内容涵盖:
- 采购订单表与库存表的关联设计(采购单号、商品明细、采购数量、入库数量、批次号等关键字段)
- 采购入库流程(采购申请、到货验收、质量检验、入库上架)
- 批次管理与库存计价方法(FIFO/LIFO)
- 采购成本控制、库存周转率优化、供应链可视化技术方案
- 为电商平台开发者提供可落地的数据模型参考
项目结构
围绕采购入库集成的代码与数据主要分布在以下位置:
- 订单与库存校验:核心服务位于 core/service/order,前台结算与购物车涉及库存锁定与释放逻辑
- 产品与库存:产品模型 admin/model/product/Product.php 中维护 stock 字段,作为可售库存的基准
- 数据库表结构:系统表结构定义位于 _'/doc/开发手册/系统表结构.sql,包含订单、订单项、地址快照等基础表
- 后台订单处理:_'/module/order/admin/service/order/OrderService.php 负责发货、状态推进与库存解锁
graph TB
A["前端/管理端"] --> B["订单服务(OrderService)"]
B --> C["库存校验(OrderStockGuard)"]
B --> D["产品模型(Product)"]
D --> E["产品表(product.stock)"]
B --> F["订单表(order, order_item)"]
F --> G["订单地址快照(order_address)"]
核心组件
- 订单核心服务(OrderService):编排订单生命周期、状态机、支付联动、库存校验与批量任务触发
- 前台结算服务(CheckoutService):完成下单前的库存校验、创建订单、根据配置决定是否锁定库存
- 购物车服务(CartService):添加商品到购物车时进行库存限制检查
- 产品模型(Product):维护 product 表及 stock 字段,用于可售库存展示与计算
- 后台订单服务(Admin OrderService):发货、物流信息回填、首次发货时解锁库存并推进订单状态
架构总览
采购入库集成在现有订单与库存能力之上,通过新增“采购订单”“采购明细”“入库记录”“批次库存”等表,形成从采购到上架的闭环。整体架构如下:
sequenceDiagram
participant S as "供应商"
participant P as "采购申请"
participant PO as "采购订单(主/细)"
participant QC as "质量检验"
participant WH as "仓库入库"
participant BK as "批次库存"
participant PR as "产品库存(product.stock)"
S-->>P : 到货通知
P->>PO : 生成采购订单(含明细、采购数量)
PO->>QC : 发起质检
QC-->>PO : 质检结果(合格/不合格)
PO->>WH : 合格品入库
WH->>BK : 按批次登记入库数量
BK->>PR : 更新可售库存(可选策略)
详细组件分析
采购订单与库存关联设计
- 采购订单主表(建议命名:purchase_order)
- 关键字段:采购单号、供应商ID、采购日期、状态、总金额、备注
- 采购订单明细表(建议命名:purchase_order_item)
- 关键字段:采购单号、商品ID、商品名称、规格、单位、采购数量、单价、金额、已入库数量、退货数量、备注
- 入库记录表(建议命名:purchase_inbound)
- 关键字段:入库单号、采购单号、商品ID、批次号、入库数量、质检结果、入库时间、仓库/库位
- 批次库存表(建议命名:inventory_batch)
- 关键字段:商品ID、批次号、在库数量、可用数量、成本价、入库时间、过期时间、状态
- 产品库存(product.stock)
- 由批次库存汇总或策略计算得到可售库存,供前台销售与库存校验使用
erDiagram
PURCHASE_ORDER {
int id PK
string purchase_sn UK
int supplier_id
datetime created_at
tinyint status
decimal total_amount
text remark
}
PURCHASE_ORDER_ITEM {
int id PK
int purchase_order_id FK
int product_id
string product_name
string spec
string unit
int purchase_qty
decimal unit_price
decimal amount
int inbound_qty
int return_qty
text remark
}
PURCHASE_INBOUND {
int id PK
string inbound_sn UK
int purchase_order_id FK
int product_id
string batch_no
int qty
tinyint qc_result
datetime inbound_at
string warehouse
string location
}
INVENTORY_BATCH {
int id PK
int product_id
string batch_no
int on_hand_qty
int available_qty
decimal cost_price
datetime in_time
datetime expire_time
tinyint status
}
PRODUCT {
int id PK
int stock
...其他字段...
}
PURCHASE_ORDER ||--o{ PURCHASE_ORDER_ITEM : "包含"
PURCHASE_ORDER ||--o{ PURCHASE_INBOUND : "产生"
PURCHASE_INBOUND }o--|| INVENTORY_BATCH : "登记批次"
INVENTORY_BATCH }o--|| PRODUCT : "影响可售库存"
采购入库流程(申请→验收→质检→入库上架)
flowchart TD
Start(["开始"]) --> Apply["创建采购申请"]
Apply --> CreatePO["生成采购订单(主/细)"]
CreatePO --> Receive["到货登记"]
Receive --> QC{"质检是否合格?"}
QC -- 否 --> Reject["退回/报废处理"]
QC -- 是 --> Inbound["创建入库单并登记批次"]
Inbound --> UpdateBatch["更新批次库存(可用/在库)"]
UpdateBatch --> UpdateProduct["同步更新产品可售库存"]
UpdateProduct --> End(["结束"])
Reject --> End
批次管理与库存计价(FIFO/LIFO)
- 批次维度:以“商品+批次号”为最小库存单元,记录在库数量、可用数量、成本价、有效期等
- 计价方法:
- FIFO(先进先出):出库优先消耗最早入库批次
- LIFO(后进先出):出库优先消耗最近入库批次
- 实现要点:
- 出库扣减按批次队列顺序选择批次
- 成本核算基于所选批次的成本价累计
- 支持批次冻结/解冻、部分出库、退库回滚
flowchart TD
OutStart["出库请求"] --> Pick["选择计价策略(FIFO/LIFO)"]
Pick --> SelectBatch["按策略选择批次队列"]
SelectBatch --> Deduct["逐批次扣减可用数量"]
Deduct --> CalcCost["累计出库成本"]
CalcCost --> UpdateStock["更新批次与产品库存"]
UpdateStock --> OutEnd["完成"]
与现有订单/库存能力的衔接
- 库存校验:前台下单前会调用库存校验,确保可售库存充足;采购入库后应同步提升 product.stock
- 库存锁定:下单后可根据配置锁定库存;发货或取消时解锁库存;采购入库不影响销售侧锁定逻辑,但需保证可售库存一致性
- 订单状态推进:后台首次填写物流信息时推进订单状态并解锁库存,采购入库完成后也应具备类似的状态推进与审计日志
依赖关系分析
- 采购入库模块依赖:
- 产品主数据(product):stock 字段作为可售库存基准
- 订单与订单项(order, order_item):用于销售侧库存占用与释放
- 系统表结构(SQL):提供表结构与索引基线
- 耦合点:
- 入库成功后对 product.stock 的更新需与批次库存保持一致
- 出库扣减需读取批次库存队列,避免超卖
- 与订单状态机解耦,仅通过库存与成本数据交互
graph LR
PO["采购订单"] --> PI["入库记录"]
PI --> IB["批次库存"]
IB --> PR["产品库存(product.stock)"]
SO["销售订单"] --> SI["销售出库"]
SI --> IB
性能考虑
- 索引设计
- 采购订单:purchase_sn 唯一索引;supplier_id、status、created_at 复合索引
- 采购明细:purchase_order_id、product_id 复合索引;inbound_qty 索引便于统计
- 入库记录:inbound_sn 唯一索引;purchase_order_id、product_id、batch_no 复合索引
- 批次库存:product_id、batch_no 唯一索引;available_qty、in_time 索引用于出库与盘点
- 事务与并发
- 入库与批次更新在同一事务内执行,避免中间态
- 出库扣减采用行级锁或乐观锁,防止超卖
- 查询优化
- 常用报表(在库、可用、批次明细)建立物化视图或汇总表
- 历史归档:批次与入库记录按时间分区或归档表
故障排查指南
- 库存不一致
- 现象:product.stock 与批次库存合计不一致
- 排查:核对最近一次入库/出库事务是否完整提交;检查是否有未处理的异常回滚
- 超卖
- 现象:销售订单超过实际可用库存
- 排查:确认出库扣减是否按批次队列顺序执行;检查并发锁机制是否生效
- 批次成本异常
- 现象:出库成本与预期不符
- 排查:确认计价策略(FIFO/LIFO)配置;检查批次成本价是否正确录入
- 质检不合格处理
- 现象:不合格品仍进入可用库存
- 排查:入库记录中质检结果字段是否正确;批次状态是否被错误标记为可用
结论
本方案在DouPHP现有订单与库存能力基础上,引入采购订单、入库记录与批次库存,形成端到端的采购入库闭环。通过批次维度的精细化管理与FIFO/LIFO计价策略,可实现准确的成本核算与库存控制。结合索引优化、事务一致性与并发控制,能够支撑高并发场景下的稳定运行。同时,为供应链可视化与周转率优化提供了坚实的数据基础。
附录:数据模型与字段规范
- 采购订单主表(purchase_order)
- 字段:id、purchase_sn、supplier_id、created_at、status、total_amount、remark
- 说明:purchase_sn 唯一;status 表示采购单状态(如待审批、已批准、部分入库、已完成、已关闭)
- 采购订单明细表(purchase_order_item)
- 字段:id、purchase_order_id、product_id、product_name、spec、unit、purchase_qty、unit_price、amount、inbound_qty、return_qty、remark
- 说明:inbound_qty 累计入库数量;return_qty 累计退货数量
- 入库记录表(purchase_inbound)
- 字段:id、inbound_sn、purchase_order_id、product_id、batch_no、qty、qc_result、inbound_at、warehouse、location
- 说明:qc_result 表示质检结果(如合格、不合格、待定)
- 批次库存表(inventory_batch)
- 字段:id、product_id、batch_no、on_hand_qty、available_qty、cost_price、in_time、expire_time、status
- 说明:on_hand_qty 在库数量;available_qty 可用数量;status 表示批次状态(如在库、冻结、过期)
- 产品库存(product.stock)
- 字段:stock(可售库存)
- 说明:由批次库存按策略汇总或实时计算得到