# 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 ```python 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 ```python 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:** - `` 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 1. Delete `at.master.order.shipment` model and related files 2. Remove Shipping tab from Master Order views 3. Clean up manifest and security files ### Phase 2: Partner Enhancement 1. Add `is_shipper` field to `res.partner` 2. Create partner form extension view ### Phase 3: Invoice Enhancement 1. Add shipment tracking fields to `account.move` 2. Add computed `shipment_status` field 3. Add Shipment Tracking section to invoice form 4. Add shipment columns to invoice list in Master Order ### Phase 4: Shipping Charge Workflow 1. Create "Add Shipping Charge" wizard 2. Implement invoice line creation 3. Implement vendor bill creation (auto-confirmed) ### Phase 5: Master Order Integration 1. Add `overall_shipment_status` computed field 2. Update Invoice tab view with shipment columns 3. Add status display in header ### Phase 6: Create Invoice Wizard Update 1. Add optional shipping company field 2. Add shipping method selection 3. 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