Inventory Module Documentation
Overview
The Inventory Module is a robust stock management system designed for hospitality needs. It handles end-to-end supply chain tracking, from purchasing to consumption, with precise costing methods and full General Ledger integration.
Key Features
- Multi-Location Management: Track stock across unlimited physical locations (Main Store, Kitchens, Bars, Housekeeping).
- Advanced Costing: Supports FIFO (First-In, First-Out) and Weighted Average costing methods.
- Lot Tracking: Trace individual batches for expiry dates and specific cost layers.
- Accounting Integration: Automatic, real-time journal postings for all financial transactions.
- Stock Audit: Complete history of every movement (Purchase, Issue, Transfer, Adjust, Write-off).
- Reorder Management: Low stock alerts and reorder level tracking (Planned).
Architecture
Domain Layer (app/Domain/Inventory)
Models (7 Models)
InventoryItem (InventoryItem.php)
- Table:
inventory_items - Description: Master record for a product/SKU.
- Key Fields:
sku: Stock Keeping Unit (Unique).name: Product name.description: Extended details.unit_of_measure: Base unit (e.g., KG, PCS, LTR).category_id: Link toInventoryCategory.current_quantity: Total stock across all locations.average_cost: Current weighted average cost (updated on purchase).last_purchase_cost: Cost of most recent purchase.last_purchase_date: Timestamp of last purchase.inventory_account_id: Specific asset account (optional override).cogs_account_id: Specific expense account (optional override).reorder_level: Minimum quantity trigger.
- Relationships:
category(): Belongs to Category.lots(): Has many InventoryLots.transactions(): Has many InventoryTransactions.locationStocks(): Has many InventoryLocationStocks.
InventoryLocation (InventoryLocation.php)
- Table:
inventory_locations - Description: Physical storage location.
- Key Fields:
name: Location name (e.g., "Main Kitchen").type: STORE | KITCHEN | BAR | HOUSEKEEPING.is_active: Boolean status.
InventoryLot (InventoryLot.php)
- Table:
inventory_lots - Description: Tracks a specific batch of items received together. Critical for FIFO.
- Key Fields:
lot_number: Batch/Lot number (e.g., from vendor).purchase_date: Date received.expiry_date: Expiration date (optional).original_quantity: Initial qty received.remaining_quantity: Current qty available in lot.unit_cost: Cost per unit for this specific batch.
InventoryTransaction (InventoryTransaction.php)
- Table:
inventory_transactions - Description: Immutable ledger of stock movements.
- Key Fields:
transaction_type: PURCHASE | ISSUE_OUT | TRANSFER | ADJUSTMENT | WRITE_OFF.quantity: Net change in quantity (positive or negative).unit_cost: Cost applied to this transaction.total_cost:quantity * unit_cost.running_quantity: Snapshot of item quantity after transaction.running_average_cost: Snapshot of item average cost.reference_type: Morph link to source (e.g.,App\Models\PurchaseOrder).reference_id: Morph ID.journal_entry_id: Link to Accounting Entry.
InventoryLocationStock (InventoryLocationStock.php)
- Table:
inventory_location_stocks - Description: Pivot tracking quantity of Item X at Location Y.
- Key Fields:
quantity: Current stock at this location.
Services
InventoryService (InventoryService.php)
Purpose: Central logic for all stock movements and financial postings.
Key Methods:
purchaseIn(...)
Records receipt of goods.
- Logic:
- Calculates new weighted average cost (if method = weighted_average).
- Creates
InventoryTransaction(Type: PURCHASE). - Creates
InventoryLotfor FIFO tracking. - Updates
InventoryItem(qty, avg_cost). - Updates
InventoryLocationStock. - Accounting: Dr Inventory Asset, Cr Accounts Payable (or Cash).
issueOut(...)
Records consumption/sale of goods.
- Logic:
- Validates sufficient stock.
- FIFO Logic: Iterates through oldest available lots (
consumeFifoLots).- Consumes from Lot A, then Lot B, etc.
- Calculates weighted cost based on specific lots consumed.
- records
InventoryLotConsumptionfor traceability. - Creates
InventoryTransaction(Type: ISSUE_OUT). - Updates
InventoryItemandInventoryLocationStock. - Accounting: Dr COGS/Expense, Cr Inventory Asset.
transferStock(...)
Moves items between locations.
- Logic:
- Validates source location has stock.
- Decrements Source Location Stock.
- Increments Destination Location Stock.
- Creates
InventoryTransaction(Type: TRANSFER). - Accounting: None (Asset remains an asset).
adjustStock(...)
Corrections for stocktakes or discrepancies.
- Logic:
- Calculates difference (
newQty - oldQty). - Creates
InventoryTransaction(Type: ADJUSTMENT). - Accounting:
- Gain: Dr Inventory, Cr COGS/Gain Account.
- Loss: Dr COGS/Loss Account, Cr Inventory.
- Calculates difference (
writeOff(...)
Removes damaged or expired stock.
- Logic:
- Creates
InventoryTransaction(Type: WRITE_OFF). - Accounting: Dr Spoilage Expense (COGS), Cr Inventory.
- Creates
Accounting Integration
The module is tightly coupled with AccountingPoster.
Account Configuration
Accounts are resolved in this order of precedence:
- Item-Level Override:
inventory_item.inventory_account_id - Category-Level Override:
inventory_category.inventory_account_id(Planned) - System Default: Config
inventory.default_inventory_account_code(Default: 104)
Journal Entries
1. Purchase (Stock In)
| Account | Dr/Cr | Amount | Memo |
|---|---|---|---|
| Inventory Asset (104) | Debit | Total Cost | 50 KG @ $2.00 |
| Accounts Payable (201) | Credit | Total Cost | Purchase: Tomatoes |
2. Issue (Stock Out / Consumption)
| Account | Dr/Cr | Amount | Memo |
|---|---|---|---|
| COGS / Expense (604) | Debit | Cost of Goods | COGS: 10 KG |
| Inventory Asset (104) | Credit | Cost of Goods | Issue: Tomatoes |
3. Adjustment (Loss)
| Account | Dr/Cr | Amount | Memo |
|---|---|---|---|
| COGS / Inventory Loss | Debit | Variance Cost | Adjustment loss |
| Inventory Asset (104) | Credit | Variance Cost | Reason: Spillage |
Database Schema
mermaid
erDiagram
InventoryItem ||--o{ InventoryLot : "has batches"
InventoryItem ||--o{ InventoryTransaction : "history"
InventoryItem ||--o{ InventoryLocationStock : "at location"
InventoryTransaction ||--o{ InventoryLotConsumption : "consumes"
InventoryTransaction ||--|| JournalEntry : "posts financial"
InventoryLocation ||--o{ InventoryLocationStock : "stores"
inventory_items {
bigint id PK
string sku
string name
decimal current_quantity
decimal average_cost
enum costing_method "FIFO, AVG"
}
inventory_lots {
bigint id PK
string lot_number
date purchase_date
decimal remaining_quantity
decimal unit_cost
}
inventory_transactions {
bigint id PK
enum type "PURCHASE, ISSUE, TRANSFER"
decimal quantity
decimal unit_cost
decimal total_cost
bigint journal_entry_id FK
}Common Workflows
1. Receiving Goods (Purchase)
- Navigate to Inventory > Receive Stock.
- Select Item, Location, and Vendor.
- Enter Quantity, Unit Cost, and Lot Number (optional).
- Submit.
- System: Increases stock, creates Lot, posts Debit Inventory / Credit AP.
2. Issuing to Kitchen
- Navigate to Inventory > Issue Stock.
- Select Item and Source Location (Main Store).
- Enter Quantity and Reason (e.g., "Kitchen Requistion").
- Submit.
- System: Decreases stock (FIFO from oldest lot), posts Debit Food Cost / Credit Inventory.
3. Stock Transfer
- Navigate to Inventory > Transfer.
- Select Item, From Location, and To Location.
- Enter Quantity.
- Submit.
- System: Moves stock count between locations. No financial impact.
Audit Findings & Improvements
Strengths
- FIFO Implementation: The
consumeFifoLotsmethod correctly handles multi-lot consumption in a single transaction, providing accurate COGS. - Transactional Integrity: All inventory operations are wrapped in DB transactions, ensuring stock levels and accounting entries never drift.
- Granular History: Every single unit change is recorded in
inventory_transactions.
Issues Identified
Major
- N+1 Performance:
InventoryServicequeries for default account IDs inside transaction blocks. If doing bulk operations, this should be cached. - Account Resolution: Currently falls back to hardcoded strings ('104', '604') in config lookups. Should use the
AccountingMapServiceproposed in Phase 4.
Minor
- Soft Deletes: Missing on
InventoryItem. Deletion could orphaned transaction history. - Unit Conversions: No support for purchasing in Cases and issuing in Units.
Configuration
Config File: config/inventory.php
php
return [
'costing_method' => 'fifo', // 'fifo' or 'weighted_average'
'default_inventory_account_code' => '104',
'default_cogs_account_code' => '604',
];Module Version: 1.0 Status: Production Ready