Warehouse Inventory Tracking System — Project Plan
1. Project Overview
A web-based inventory tracking system for Carnation Company (the operator) to manage frozen goods received and dispatched on behalf of their customers:
-
Matthew's Foods
-
Abzal Fine Desserts
-
Jane's Pies and Cakes
Carnation Company logs all inbound and outbound movements, tracks inventory by SKU and Lot Number, and generates date-based reports — all from a single desktop-accessible interface.
2. Tech Stack
| Layer | Technology | |---|---| | **Backend** | Django (Python) | | **Frontend** | Django Templates | | **Styling** | Tailwind CSS + DaisyUI (via CDN — no build step) | | **Database** | SQLite (development) → PostgreSQL (production) | | **Authentication** | Django built-in auth + role-based middleware | | **Reports/Export** | openpyxl (Excel), reportlab (PDF) |
Tailwind + DaisyUI (CDN Setup)
No npm, no Node.js, no watchers required. Simply included in base.html:
<link href="https://cdn.jsdelivr.net/npm/daisyui@4/dist/full.min.css" rel="stylesheet" />
<script src="https://cdn.tailwindcss.com"></script>
> **Note:** CDN usage means no CSS purging (slightly larger bundle). Perfectly acceptable for an internal desktop tool with a small user base.
3. User Roles
| Role | Permissions | |---|---| | **Super Admin** | Full access — user management, client management, all reports, all inventory actions | | **Editor** | Can create and edit inventory entries (inbound/outbound) | | **Viewer** | Read-only access to inventory and reports |
- Total users: 5
- Login accessible from any browser (desktop-first)
4. Core Modules & Features
4.1 Authentication
-
Login / Logout
-
Role-based access control (middleware-enforced)
-
Session management
4.2 Client Management
-
Add, edit, and view sub-clients (e.g. Matthew's Foods)
-
All inventory is tagged to a specific client
-
Managed by Super Admin only
4.3 SKU Management
-
Manually input SKU codes and product names per client
-
SKUs are tied to Lot Numbers and Best Before Dates
-
View all SKUs per client
4.4 Inbound (Receiving Goods)
-
Record BOL (Bill of Lading) reference number
-
Input fields: Client, SKU, Lot Number, Quantity, Date Received, Best Before Date
-
Supports multiple SKU entries per BOL
-
Inventory quantity updated automatically on submission
4.5 Outbound (Dispatching Goods)
-
FIFO (First In, First Out) dispatch logic — oldest lot dispatched first
-
Input fields: Client, SKU, Quantity requested
-
System auto-suggests the correct Lot # based on FIFO order
-
Splits across multiple lots automatically if needed
-
Records: SKU, Lot #, Quantity pulled, Date dispatched, User who dispatched
4.6 Dashboard
-
Real-time inventory levels per Client → SKU → Lot #
-
Filter by client, SKU, or date range
-
Visual indicators for items approaching shelf life expiry
4.7 Reports
-
Date-based inventory snapshot (stock levels on any given date)
-
Full movement history (all inbound/outbound per client, SKU, and lot)
-
Exportable to CSV / Excel / PDF
5. Workflow
BOL Received
→ Record BOL Ref + Client + SKU + Lot # + Quantity + Best Before Date
→ Inventory Updated (quantity added to correct Lot)
Dispatch Request
→ Select Client + SKU + Quantity
→ FIFO Logic Identifies Correct Lot(s)
→ Confirm Dispatch
→ Inventory Deducted + Movement Logged
Generate Report
→ Select Client + Date Range
→ Snapshot or Movement History Exported
6. Project Structure
inventory_project/
│
├── manage.py
├── requirements.txt
│
├── config/ # Project-level settings
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│
├── apps/
│ ├── accounts/ # Auth, users, roles
│ │ ├── models.py
│ │ ├── views.py
│ │ └── urls.py
│ │
│ ├── clients/ # Carnation's sub-clients
│ │ ├── models.py
│ │ ├── views.py
│ │ └── urls.py
│ │
│ ├── inventory/ # Core inventory logic
│ │ ├── models.py
│ │ ├── views.py
│ │ ├── fifo.py # FIFO dispatch logic
│ │ └── urls.py
│ │
│ └── reports/ # Reporting and export
│ ├── views.py
│ └── urls.py
│
├── templates/
│ ├── base.html # Tailwind + DaisyUI CDN loaded here
│ ├── accounts/
│ ├── clients/
│ ├── inventory/
│ └── reports/
│
└── static/
└── css/custom.css # Minor style overrides only
7. Database Models
# accounts/models.py
class User(AbstractUser):
ROLES = [
('super_admin', 'Super Admin'),
('editor', 'Editor'),
('viewer', 'Viewer'),
]
role = models.CharField(max_length=20, choices=ROLES)
# clients/models.py
class Client(models.Model):
name = models.CharField(max_length=200) # e.g. Matthew's Foods
created_at = models.DateTimeField(auto_now_add=True)
# inventory/models.py
class SKU(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
sku_code = models.CharField(max_length=100)
product_name = models.CharField(max_length=200)
class Lot(models.Model):
sku = models.ForeignKey(SKU, on_delete=models.CASCADE)
lot_number = models.CharField(max_length=100)
best_before_date = models.DateField()
quantity_on_hand = models.PositiveIntegerField(default=0)
class InboundLog(models.Model):
lot = models.ForeignKey(Lot, on_delete=models.CASCADE)
bol_reference = models.CharField(max_length=100)
quantity = models.PositiveIntegerField()
date_received = models.DateField()
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
class OutboundLog(models.Model):
lot = models.ForeignKey(Lot, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
date_dispatched = models.DateField()
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
8. Page & URL Map
| URL | Page | Access |
|---|---|---|
| `/login` | Login page | Public |
| `/dashboard` | Live inventory overview | All |
| `/clients/` | Client list | Super Admin |
| `/clients/add` | Add new client | Super Admin |
| `/skus/` | SKU list per client | Editor+ |
| `/skus/add` | Add new SKU | Editor+ |
| `/inbound/` | Receive goods — BOL entry form | Editor+ |
| `/inbound/history` | Inbound movement history | All |
| `/outbound/` | Dispatch goods — FIFO form | Editor+ |
| `/outbound/history` | Outbound movement history | All |
| `/reports/` | Report generator + export | All |
| `/users/` | User management | Super Admin |
9. FIFO Dispatch Logic
# inventory/fifo.py
def get_fifo_lots(sku, quantity_needed):
"""
Returns lots ordered by oldest best_before_date first.
Splits across multiple lots if needed.
"""
lots = Lot.objects.filter(
sku=sku,
quantity_on_hand__gt=0
).order_by('best_before_date') # oldest first
dispatch_plan = []
remaining = quantity_needed
for lot in lots:
if remaining <= 0:
break
take = min(lot.quantity_on_hand, remaining)
dispatch_plan.append({'lot': lot, 'quantity': take})
remaining -= take
return dispatch_plan
10. Dependencies (requirements.txt)
Django>=5.0
psycopg2-binary # PostgreSQL driver (production)
openpyxl # Excel export
reportlab # PDF export
python-decouple # Environment variable management
whitenoise # Static file serving
11. Estimated Timeline (~15–17 Hours)
| Phase | Task | Est. Hours |
|---|---|---|
| 1 | Project setup, settings, base template with DaisyUI | 1.5 hrs |
| 2 | Auth — login, logout, role-based access middleware | 2 hrs |
| 3 | Client & SKU management (CRUD) | 2 hrs |
| 4 | Inbound flow — BOL entry, lot creation, inventory update | 2.5 hrs |
| 5 | Outbound flow — FIFO dispatch form + confirmation | 2.5 hrs |
| 6 | Dashboard — live inventory view per client/SKU/lot | 2 hrs |
| 7 | Reports — filters, date range, Excel/PDF export | 2 hrs |
| 8 | Testing, polish, deployment prep | 1.5 hrs |
| | **Total** | **~16 hrs** |
12. Open Questions (Confirm Before Starting)
-
Warehouses — One location or multiple? Should inventory be tracked per warehouse?
-
Units of measure — Cases, pallets, lbs, or generic units?
-
Shelf life alerts — Should the system flag or notify when items are near expiry?
-
BOL document — Record BOL number only, or allow PDF upload attachment?
-
Deployment target — Local server, shared hosting, or cloud VPS (e.g. DigitalOcean, Render)?
-
App name — Confirm final name for the system (currently placeholder: Inventory Management System)
Plan prepared for Heritcon LLC — Subject to revision as requirements are refined.