9.9 KiB
9.9 KiB
Invoice-Centric Shipment Tracking
Overview
This document describes the implementation of shipment tracking integrated directly into customer invoices, replacing the separate Shipment tab in Master Order.
Business Requirements
Core Principle
Invoice = Commercial + Shipment unit Shipment does not exist without invoice. Customer tracks shipment by invoice.
Key Decisions
| Decision | Value |
|---|---|
| Shipping Methods | Sea, Air (only) |
| Shipping Company Source | res.partner with is_shipper flag |
| Shipping Selection | Optional at invoice creation, editable on invoice form |
| Shipping Charge | Added later via button, creates vendor bill |
| Old Shipment Model | Delete at.master.order.shipment (testing phase) |
Workflow
Step 1: Create Invoice
┌─────────────────────────────────────────────────────────────┐
│ CREATE INVOICE WIZARD │
├─────────────────────────────────────────────────────────────┤
│ Products: [Product A, Product B...] │
│ │
│ ☐ Include Shipping (Optional) │
│ └── IF checked: │
│ Shipping Company: [MSC Shipping ▼] │
│ Shipping Method: [Sea ▼ / Air ▼] │
│ │
│ [Create Invoice] │
└─────────────────────────────────────────────────────────────┘
Result: Invoice created with optional shipping context (no charge yet)
Step 2: Add/Edit Shipping Details (On Invoice Form)
┌─────────────────────────────────────────────────────────────┐
│ INVOICE FORM - Shipment Tracking Section │
├─────────────────────────────────────────────────────────────┤
│ Shipping Company: [MSC ▼] Method: [🚢 Sea ▼] │
│ Container #: [MSKU8821456] Status: [In Transit] │
│ ETD: [2026-01-15] Actual Ship: [2026-01-16] │
│ ETA: [2026-02-12] Delivered: [________] │
│ Notes: [Customs cleared...] │
└─────────────────────────────────────────────────────────────┘
Step 3: Add Shipping Charge (Creates Bill)
User clicks [Add Shipping Charge] button on invoice:
┌─────────────────────────────────────────────────────────────┐
│ ADD SHIPPING CHARGE │
├─────────────────────────────────────────────────────────────┤
│ Shipping Company: MSC Shipping (from invoice) │
│ Shipping Cost: $800 ← Pay to shipper │
│ Shipping Charge: $1,000 ← Charge customer │
│ │
│ ☑ Add to Customer Invoice (as line) │
│ ☑ Create Vendor Bill for Shipping Cost │
│ │
│ [Confirm] │
└─────────────────────────────────────────────────────────────┘
Result:
- Invoice line added: "Shipping Charge: $1,000"
- Vendor bill created: Partner=MSC, Amount=$800, auto-confirmed
- Shipping margin tracked: $200 profit
Data Model Changes
1. New Field on res.partner
| Field | Type | Purpose |
|---|---|---|
is_shipper |
Boolean | Filter for shipping company dropdown |
2. New Fields on account.move (Customer Invoices)
| Field | Type | Required | Purpose |
|---|---|---|---|
shipper_id |
Many2one (res.partner) | No | Shipping company |
shipment_method |
Selection | No | 'sea' / 'air' |
container_tracking |
Char | No | Container # or AWB |
etd |
Date | No | Estimated Time of Departure |
eta |
Date | No | Estimated Time of Arrival |
actual_ship_date |
Date | No | When goods shipped |
actual_delivery_date |
Date | No | When goods delivered |
shipment_status |
Selection (Computed) | Auto | Status based on dates |
shipment_notes |
Text | No | Notes about shipment |
shipping_cost |
Float | No | Cost paid to shipper |
shipping_charge |
Float | No | Amount charged to customer |
shipping_margin |
Float (Computed) | Auto | charge - cost |
shipping_bill_id |
Many2one (account.move) | No | Link to shipping vendor bill |
3. New Field on at.master.order
| Field | Type | Purpose |
|---|---|---|
overall_shipment_status |
Selection (Computed) | Aggregated from invoices |
Shipment Status Logic
Invoice Level
IF not shipper_id:
status = 'no_shipping'
ELIF actual_delivery_date:
status = 'delivered'
ELIF actual_ship_date:
IF eta AND today > eta:
status = 'delayed'
ELSE:
status = 'in_transit'
ELIF shipper_id:
status = 'pending'
ELSE:
status = 'draft'
Master Order Level
invoice_statuses = [inv.shipment_status for inv in posted_invoices]
IF all(s == 'delivered' for s in invoice_statuses):
status = 'delivered'
ELIF any(s == 'delayed' for s in invoice_statuses):
status = 'delayed'
ELIF any(s == 'in_transit' for s in invoice_statuses):
status = 'in_transit'
ELIF any(s == 'pending' for s in invoice_statuses):
status = 'pending'
ELIF len(set(invoice_statuses)) > 1:
status = 'partial'
ELSE:
status = 'not_shipped'
View Changes
1. Master Order Form
REMOVE:
<page string="Shipping" name="shipping">entire section
MODIFY - Invoice Tab: Add columns to invoice list:
- Shipment Status (badge)
- Ship Method (icon)
- Container/Tracking
- ETA
ADD - Header:
- Overall shipment status field
2. Invoice Form
ADD - Before Notebook:
- Shipment Tracking section (visible only for
out_invoice)
ADD - Button:
- "Add Shipping Charge" button in header
3. Create Invoice Wizard
ADD:
- Optional shipping company selection
- Shipping method selection
Files to Modify
| File | Action |
|---|---|
models/shipment.py |
DELETE entire file |
models/__init__.py |
Remove shipment import |
views/shipment_views.xml |
DELETE entire file |
views/master_order_views.xml |
Remove Shipping tab, enhance Invoice tab |
security/ir.model.access.csv |
Remove shipment model access |
data/ir_sequence_data.xml |
Remove shipment sequence (if exists) |
__manifest__.py |
Remove shipment_views.xml reference |
models/account_move.py |
Add shipment tracking fields |
models/res_partner.py |
CREATE - Add is_shipper field |
models/master_order.py |
Add overall_shipment_status, remove shipment references |
wizard/create_invoice_wizard.py |
Add shipping company selection |
wizard/create_invoice_wizard_views.xml |
Add shipping fields to wizard |
Implementation Phases
Phase 1: Cleanup
- Delete
at.master.order.shipmentmodel and related files - Remove Shipping tab from Master Order views
- Clean up manifest and security files
Phase 2: Partner Enhancement
- Add
is_shipperfield tores.partner - Create partner form extension view
Phase 3: Invoice Enhancement
- Add shipment tracking fields to
account.move - Add computed
shipment_statusfield - Add Shipment Tracking section to invoice form
- Add shipment columns to invoice list in Master Order
Phase 4: Shipping Charge Workflow
- Create "Add Shipping Charge" wizard
- Implement invoice line creation
- Implement vendor bill creation (auto-confirmed)
Phase 5: Master Order Integration
- Add
overall_shipment_statuscomputed field - Update Invoice tab view with shipment columns
- Add status display in header
Phase 6: Create Invoice Wizard Update
- Add optional shipping company field
- Add shipping method selection
- Pass values to created invoice
Status Badge Colors
| Status | Color | Icon |
|---|---|---|
| No Shipping | Gray | ⚪ |
| Draft | Gray | ⚪ |
| Pending | Yellow | 🟡 |
| In Transit | Blue | 🚚 |
| Delayed | Red | 🔴 |
| Delivered | Green | ✅ |
Customer Portal (Future)
Portal enhancements will include:
- Shipment status visible on invoice list
- Shipment tracking section on invoice detail
- Carrier tracking link integration
Accounting Safety
- Shipment fields are informational only
- No impact on journal entries or reconciliation
- Shipping bill uses standard Odoo vendor bill workflow
- All changes tracked via Odoo tracking mechanism
Migration Notes
- No data migration needed (shipment model was in testing)
- Existing invoices will have empty shipment fields
- Users can populate shipment data on existing invoices manually