Overview
Warehouse 3PL is a third-party logistics (3PL) warehouse management system built as a custom Frappe app on top of ERPNext. It extends ERPNext's Stock module with a full set of 3PL-specific doctypes, workflows, and automation to manage multi-client warehouse operations from a single platform.

What is a 3PL?
A third-party logistics (3PL) provider stores and fulfills inventory on behalf of multiple clients (brands, manufacturers, e-commerce sellers). The warehouse operator:
- Receives goods from clients' suppliers
- Stores the goods in a shared physical facility
- Picks, packs, and ships orders on behalf of clients
- Bills clients for each service activity performed
The key challenge is that the goods belong to the clients, not the warehouse operator. The operator must track inventory precisely per client, isolate data between clients, and bill every touchpoint accurately.
System Architecture
warehouse_3pl/ ← Custom Frappe app
├── warehouse_3pl/
│ ├── doctype/ ← 24 custom doctypes
│ │ ├── warehouse_job_record/ ← Central job tracking (Enhanced Desk UI)
│ │ ├── asn/ ← Advance Shipment Notice
│ │ ├── receiving/ ← Receiving (GRN)
│ │ ├── putaway_task/ ← Directed putaway
│ │ ├── client_order/ ← Outbound sales orders
│ │ ├── wave/ ← Wave picking batches
│ │ ├── pick_task/ ← Pick instructions
│ │ ├── pack_task/ ← Pack instructions
│ │ ├── billing_transaction/ ← Activity-based billing log
│ │ ├── rate_card/ ← Per-client pricing
│ │ ├── inventory_policy/ ← Rule engine config
│ │ ├── warehouse_location/ ← Bin master
│ │ └── client_item/ ← Client SKU mapping
│ └── hooks.py ← ERPNext integration hooks
└── ...The app sits on top of the standard ERPNext stack:
Zero-Value Accounting
One of the foundational design decisions is zero-value stock accounting.
When goods are received into the warehouse, they are posted to stock at ₹0 / $0 value. This is because:
- The goods belong to the client, not the warehouse operator
- The operator has no cost basis in the inventory
- The operator earns revenue through service fees (receiving, storage, pick, pack, ship) — not by buying and reselling goods
INFO
All Stock Entries created by the system use valuation_rate = 0. ERPNext's standard accounting entries still fire, but the balance sheet impact is zero. The operator's P&L is driven entirely by Billing Transactions.
Clients can optionally supply their own item valuations for insurance or reporting purposes, but this does not affect the operator's books.
Key Modules
| Module | Purpose | Primary Doctypes |
|---|---|---|
| Job Management | Central tracking hub for engagements | Warehouse Job Record |
| Inbound | Receive goods from suppliers | ASN, Receiving, Putaway Task |
| Outbound | Fulfill client orders | Client Order, Wave, Pick Task, Pack Task |
| Billing | Activity-based charge logging | Billing Transaction, Rate Card |
| Masters | Configuration and setup | Inventory Policy, Warehouse Location, Client Item |
| Stock (ERPNext) | Inventory ledger | Stock Entry, Stock Ledger Entry, Batch |
System Architecture
Document Flow
Inbound
Outbound
Billing
Custom Doctypes
The app defines 24 custom doctypes:
| Doctype | Category | Purpose |
|---|---|---|
| Warehouse Job Record | Job Management | Central umbrella document — links all activities for a client engagement |
| Job Storage Info | Job Management | Child table — storage details within a job |
| Job Vehicle Info | Job Management | Child table — vehicle/container tracking |
| Job Operational Info | Job Management | Child table — operational log entries |
| Job Stock Movement | Job Management | Child table — stock in/out tracking |
| Job Voucher | Job Management | Child table — linked financial vouchers |
| ASN | Inbound | Advance Shipment Notice — pre-alerts expected receipts |
| ASN Item | Inbound | Line items within an ASN |
| Receiving | Inbound | Goods Receipt Note — records actual receipt |
| Receiving Item | Inbound | Line items within a Receiving |
| Putaway Task | Inbound | Directed bin assignment for received stock |
| Client Order | Outbound | Client's outbound fulfillment request |
| Client Order Item | Outbound | Line items within a Client Order |
| Wave | Outbound | Batches multiple Client Orders for picking |
| Wave Order | Outbound | Links Wave to Client Orders |
| Pick Task | Outbound | Per-bin pick instruction for warehouse operators |
| Pack Task | Outbound | Packing instruction after picking is complete |
| Billing Transaction | Billing | Single activity charge record |
| Rate Card | Billing | Per-client pricing schedule |
| Rate Card Item | Billing | Individual rates within a Rate Card |
| Inventory Policy | Config | Rule engine settings per client/zone/item group |
| Warehouse Location | Config | Physical bin master (Zone/Aisle/Rack/Level/Bin) |
| Client Item | Config | Maps client SKUs to internal ERPNext items |
| Warehouse Zone | Config | Zone definitions with temperature and type |
| Stock Balance | Reporting | Denormalized view of current stock per client/item/location |
ERPNext Extensions
The app adds custom fields to standard ERPNext doctypes:
| Doctype | Custom Fields Added |
|---|---|
| Customer | is_3pl_client (checkbox), client_code (short ID), default_rate_card (link) |
| Warehouse | zone_type (Ambient/Cold/Frozen/Hazmat), location_type (Bulk/Rack/Floor), 3pl_managed (checkbox) |
| Item | temperature_zone, velocity_class (A/B/C), lot_tracked (checkbox), client_item_id |
| Batch | client (link to Customer), expiry_date (for FEFO), po_number |
| Stock Entry | 3pl_reference_doctype, 3pl_reference_name, client (for filtering) |
| Delivery Note | client_order (link), wave (link), billing_logged (checkbox) |
Tech Stack
| Component | Version / Detail |
|---|---|
| Frappe Framework | v15 (Python-based web framework) |
| ERPNext | v15 (ERP application layer) |
| Python | 3.10+ |
| Database | MariaDB 10.6+ |
| Cache / Queue | Redis 6+ |
| Frontend | Vue 3 + Frappe UI (standard ERPNext desk) |
| API | REST (Frappe standard) + custom whitelisted methods |
TIP
The system runs on a standard Frappe bench. See frappe.io/bench for installation docs. No Docker or custom infrastructure is required.