All posts
General9 min read

Odoo for Logistics and 3PL Companies

Understand how Odoo supports third-party logistics (3PL) companies - multi-client inventory management, warehouse operations, freight tracking, billing per operation, and customer portal access for real-time shipment visibility.

Odoo for Logistics and 3PL Companies#

What 3PL Companies Need from an ERP#

Third-party logistics providers manage inventory, warehousing, and transportation on behalf of multiple clients. The core requirements are:

  • Multi-client inventory isolation - each client's stock separated and visible only to them
  • Billing per operation - charge clients per pick, pack, pallet, storage unit, or shipment
  • Real-time shipment visibility - clients want to see their stock levels and order status
  • Carrier integration - connect to FedEx, UPS, DHL, and other carriers for label generation
  • Proof of delivery - capture signatures and photos at delivery
  • Reporting by client - stock aging, throughput, and cost reports per client

Multi-Client Inventory in Odoo#

Method 1: Multi-company

Each client is a separate Odoo company sharing infrastructure but with isolated data. Pros: full data isolation. Cons: switching between companies is slow; reporting across all clients requires enterprise Odoo Reporting.

Method 2: Owner field on stock move lines

Odoo Inventory has a Product Owner field on stock moves and quants. This assigns ownership of inventory to a partner (your client) without separating it into different databases:

Inventory → Products → [Product] → On Hand → Owner column

Filter stock by owner to see each client's inventory level.

Method 3: Lot/Serial Numbers per Client

Use lot tracking where each lot belongs to a specific client, identified by a client prefix (e.g., CLI001-LOT-2024-001). This works for warehouses handling serialized goods.

Warehouse Structure for 3PL#

Warehouse: Main 3PL Hub
  Locations:
    ├── Input (receiving dock)
    ├── Quality Control
    ├── Storage
    │   ├── Client A  -  Pallet Rack A1-A20
    │   ├── Client B  -  Refrigerated B1-B10
    │   └── Client C  -  Bulk C1-C5
    ├── Packing
    └── Output (shipping dock)

Create client-specific sub-locations to track exactly where each client's stock sits:

Inventory → Configuration → Locations → New sub-location under Storage

Receiving and Put-Away for 3PL#

When clients ship goods to the 3PL warehouse:

  1. Create a Receipt under the client's product source location.
  2. Apply put-away rules to route to the client's designated zone automatically.
  3. Generate a Warehouse Receipt confirmation to send to the client.

Put-away rules:

Inventory → Configuration → Put Away Rules → New:

  • Product: Client A's products
  • Source location: Input
  • Destination: Storage / Client A

Order Fulfillment Workflow#

  1. Client places order in their system → sends to 3PL via EDI, email, or portal.
  2. 3PL creates a Delivery Order in Odoo with client's product and destination.
  3. Warehouse staff picks, packs, and validates the transfer.
  4. Carrier label generated via Odoo Delivery Carriers.
  5. Client sees the shipment status in the customer portal.

Billing per Operation#

3PL companies bill clients based on activity:

  • Storage fee: per pallet per day
  • Handling fee: per pick, per order, per line
  • Label/packaging fee: per shipment

Automate billing using Odoo Service products with time/quantity tracking:

Product: 3PL Handling Fee
Type: Service
Invoicing Policy: Based on Milestones or Timesheets

Or use Timesheet-based billing if staff log time per client operation.

Automated billing trigger example:

python
# In stock.picking (delivery order) on validation:
def _action_done(self):
    res = super()._action_done()
    if self.picking_type_id.name == 'Delivery Orders':
        # Create a handling fee service line for the client
        so = self.sale_id or self._find_client_contract()
        if so:
            so.order_line.create({
                'order_id': so.id,
                'product_id': env.ref('my_3pl.handling_fee').id,
                'product_uom_qty': len(self.move_line_ids),
                'price_unit': 2.50,  # per pick line
            })
    return res

Customer Portal for 3PL Clients#

Enable Customer Portal so clients can log in and see their:

  • Current stock levels by product
  • Open delivery orders and their status
  • Invoices and payment history

Settings → Customers → Customer Portal → enable

Clients access the portal at https://yourodoo.com/my/ using their email login.

Carrier Integration#

Inventory → Configuration → Delivery Carriers:

Connect FedEx, UPS, DHL, Canada Post, and others. Once configured:

  1. On a validated delivery, click Send to Shipper.
  2. Odoo calls the carrier API and retrieves a tracking number + label.
  3. Label prints automatically on your warehouse label printer.
  4. Tracking number is stored on the delivery order.

Inventory Aging and Slow-Mover Reports#

Inventory → Products → Current Stock (Pivot view) → Group by: Product, Owner

Add a custom stored field days_in_stock to identify inventory that hasn't moved:

python
days_in_stock = fields.Integer(
    compute='_compute_days_in_stock', store=True
)

@api.depends('date')
def _compute_days_in_stock(self):
    for quant in self:
        quant.days_in_stock = (fields.Date.today() - quant.date.date()).days

Bill clients for slow-moving stock as a storage surcharge after 90 days.

Common Mistakes#

  • Not isolating client locations - without per-client storage locations, picking the wrong client's stock is easy; always set up client-specific sub-locations
  • Using one product per item across clients - if two clients store the same SKU, use product variants or lot tracking to maintain ownership; don't share a single stock quant
  • No portal access for clients - clients calling the warehouse to check stock status is a sign the portal isn't set up; this adds avoidable manual work
  • Manual billing - manually invoicing clients per operation is error-prone at scale; automate handling fees through service products linked to delivery orders
  • Carrier label volume - 3PL operations generate thousands of labels; ensure your Odoo server has adequate resources and a fast label printer connected via direct IP (not USB)

Try ERPeek on your own Odoo module - ask questions, scaffold tests, and explore your codebase in plain language.

Get started free