Inventory Management
Inventory Management
Complete chemical and supply control — from receiving dock to technician truck.
Product Catalog
SKU, UPC & Barcode Support
Every product carries a SKU, scannable barcode, and optional GTIN-14 UPC for label printing and mobile scanning workflows.
Category Hierarchy
Organize products into nested categories for filtered reporting, reorder analysis, and screen grouping. Parent categories supported.
Tenant-Defined Units of Measure
Maintain your own UOM list (EA, LB, GAL, FT, etc.) — add custom units for any product line. Used by stock, purchase, and pack-tier dropdowns.
Net Content for Bulk Goods
Products sold by weight or volume but stocked in containers (e.g., 40-lb fertilizer bag, 5-gal paint pail, 1000-ft wire spool) carry a Net Content qty + UOM. The system derives per-LB / per-GAL pricing automatically and shows it inline on Products and Vendor Catalog pages.
Cost & Price Tracking
Maintain current unit cost and unit price per product. Cost flows into inventory valuation and snapshot reports.
Pack Hierarchy
Tier Definitions
Tenant-wide pack tiers — UNIT, INNER, PACKAGE, CASE, LAYER, PALLET — preconfigured and editable. Add custom tiers (BUNDLE, KIT, etc.) at any level by setting an integer level number between existing tiers.
Per-Product Pack Conversions
For each product, declare how many base units fit in each tier — e.g., Widget = 24 per Case, 1200 per Pallet. The system uses these to convert "5 cases" into "120 base units" automatically during receiving and (future) shipping.
Implicit Base Tier
The smallest tier (UNIT in the seed data) is the base by definition — qty_in_base is implicitly 1 with no explicit conversion row required. Higher tiers need an explicit per-product conversion.
Pack-Aware Transactions
Receive in cases, count in units, sell in pounds. The system stores everything in a single base unit so reports roll up consistently regardless of which tier any individual transaction was entered in.
Vendor Management
Vendor Directory
Centralized vendor list with code, name, address, primary contact info, notes, and active/inactive status. Receipts and purchase orders reference vendors here.
Multi-Person Contact Directory
Each vendor can carry multiple contacts (sales rep, account manager, AR clerk, customer service, owner) with their own role, email, phone, and notes. One contact per vendor is marked Primary as the default for POs and communications.
Vendor Catalog (Product ↔ Vendor)
Per (product, vendor) combination: track the vendor’s SKU for the product, their cost, lead time in days, and minimum order quantity (MOQ). Mark one vendor as the Preferred default for each product. Branch-specific overrides supported — different default vendor per branch is one row away.
Cost-per-Substance Comparison
When a product has Net Content (e.g., 40-lb bag), the Vendor Catalog shows derived cost-per-LB or cost-per-GAL inline so you can compare across vendors and across container sizes at a glance.
Independent of Purchase Orders
The Vendor Catalog data lives in the base Inventory module and is useful on its own — for receiving suggestions and cost reference. The optional Purchase Orders add-on consumes the same data for PO drafting; no parallel setup required.
Multi-Location Stock Levels
Real-Time On-Hand Quantities
Live qty_on_hand per product per location — warehouse, truck, and staging area — updated instantly on every transaction.
Receiving & Receipts
Vendor Receipts with Optional PO Link
Record every delivery against a vendor with date, quantities, and unit cost. Optionally link to a Purchase Order for ordered-vs-received variance tracking.
Pack-Tier Receiving
Enter "5 cases" instead of "120 units" — the system multiplies by your per-product Pack Conversion (24 units / case) and writes the equivalent base-unit total to inventory. Per-pack cost is also captured ("$50 / case") and converted to per-base-unit for valuation.
Save Draft or Save & Post
Save a partial receipt as a Draft to come back later (more arrives tomorrow), or save and post in one click when the shipment is fully accounted for. Drafts are fully editable — add lines, edit lines, remove lines — without affecting inventory until posted.
Trigger-Driven Ledger Posting
A database trigger fires on status change to POSTED, writing inventory_transaction rows and updating on-hand quantities atomically. If anything fails inside the transaction, the entire post rolls back — no half-applied receipts.
Cancel Without Side Effects
Cancel a draft (vendor backed out, entered by mistake) and the lines stay for audit trail but never touch inventory. Posted receipts remain immutable.
Auto-Numbered Documents
Every receipt gets a unique RCP-XXXXXX document number from the tenant-wide auto-sequence, consistent across all branches.
Opening Balance Receipts
Initial stock entered without a vendor (declaring "here's what we already have on hand") tags the inventory_transaction with txn_type=OPENING_BALANCE so it's split cleanly from real vendor receipts in reports and ledgers.
Transfers Between Locations
Branch-to-Branch & Truck Restocking
Move stock from any location to any other — warehouse to truck, branch to branch, staging to field.
Pending → In Transit → Completed Workflow
Transfers progress through a documented status chain. Stock at the source location is not reduced until the transfer is marked completed.
Partial Shipment Support
Record qty_shipped and qty_received separately so short shipments are tracked and the variance is visible.
Reservation Clearing
Fulfilling a transfer automatically releases any inventory reservation that created it.
Physical Counts
Full & Cycle Count Support
Create a count sheet for any location, enter counted quantities, and review variances before posting.
System vs. Counted Variance
Side-by-side comparison of system quantity and physical count. Variance is calculated and visible before any adjustment is made.
Manager Approval Gate
Configurable setting requires manager approval before a count can be posted to the ledger.
Variance Posting to Ledger
Posting a count writes COUNT_ADJUST transactions to the inventory ledger for full auditability.
Adjustments
Coded Adjustment Reasons
Every adjustment carries a reason code — Damaged, Expired, Lost, Found, Correction, Sample, Return — for loss analysis and reporting.
Positive & Negative Adjustments
Adjust quantity up (found, return) or down (damaged, expired) with ledger entries for each direction.
Negative Stock Guard
A tenant-configurable setting prevents adjustments from driving stock negative, with a hard database-level check.
Inventory Ledger & Valuation
Complete Transaction History
Every movement — receipt, transfer, count, adjustment — writes a permanent inventory_transaction row with before/after quantities and the triggering document.
Cost-Extended Valuation
Current inventory value calculated as qty_on_hand × unit_cost per product per location, aggregated by branch for balance sheet reporting.
Period Close & Snapshots
Monthly period close locks the ledger for the period and takes a full inventory snapshot with quantity and extended cost at close time.
Reporting Functions
fn_report_inventory() and fn_report_valuation() return branch-filtered summaries ready for export or dashboard display.