| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Invoicing (account)
• Sales (sale_management) • Discuss (mail) • Purchase (purchase) |
| Community Apps Dependencies | Show |
| Lines of code | 10377 |
| Technical Name |
eh_log_last_mile |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Invoicing (account)
• Sales (sale_management) • Discuss (mail) • Purchase (purchase) |
| Community Apps Dependencies | Show |
| Lines of code | 10377 |
| Technical Name |
eh_log_last_mile |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
Last Mile Delivery for Odoo 19
One driver, thirty stops, one wave. Plan the day, dispatch in one click, capture proof of delivery and cash on delivery, and reconcile the shift before the keys come back.
Why this module
Last Mile Delivery for Odoo 19
State machines, not status fields
Both the wave and each stop run an enforced transition map. A wave moves draft, dispatched, in-progress, completed, closed. A stop moves scheduled, out-for-delivery, delivered, failed, returned. Illegal jumps raise. Direct writes to state are rejected, so status only changes through the action that does the work.
COD that actually reconciles
Per-stop expected COD aggregates up the wave into expected, collected, and outstanding. Marking a COD stop delivered demands the collected amount, and collected can never exceed expected. A wave will not close while COD is still outstanding, so the driver settles before the shift signs off.
Every attempt is on the record
Each knock at a door writes an append-only attempt row with outcome, timestamp, and optional GPS coordinates. After the configurable attempt cap (default three) the stop auto-routes to failed, then to return-to-sender or back to scheduled for a fresh run. Attempt entries are immutable except for notes.
Day in the life
A working day, one wave at a time
Morning: the dispatcher builds a wave for a driver and vehicle, drops in the day's stops from confirmed sale orders or as ad-hoc pickups, and orders them by drag-and-drop. One dispatch action runs a pre-flight (no empty waves, no expired driver licence), stamps the departure time, and pushes every scheduled stop to out-for-delivery. On the road: each drop is marked delivered with recipient name, signature, and photo, or marked failed with an outcome that logs an attempt. COD stops capture the collected cash and method at the door. Failures past the attempt cap fall to failed, then return-to-sender. End of shift: the wave will not complete while any stop is still pending, and will not close while COD is outstanding. The driver manifest PDF carries the stop list and the cash-up table for the hand-back.
Edge cases
The cases most modules quietly ignore.
In the shipped code today, each one a place where a cheaper module silently does the wrong thing.
Collected COD cannot exceed the expected amount on a stop. The mark-delivered action rejects an over-collection rather than silently banking it, and a COD stop refuses to close as delivered until the collected figure is entered.
A failed knock does not fail the stop. The attempt is logged and the stop stays out-for-delivery until attempts reach the configured cap (default three), at which point it auto-routes to failed. The cap is set per company and mirrored as a system parameter.
A wave cannot be completed while any stop is still pending (scheduled or out-for-delivery), and cannot be closed while COD outstanding is above zero. Both raise a clear, coded error naming the blocker.
Once an attempt is captured, every field except notes is immutable. You cannot rewrite the outcome or the timestamp of a delivery attempt after the fact, so the attempt history stands as an audit trail.
Dispatch is blocked if the wave has no deliveries or if the assigned driver's licence has expired, with the expiry date surfaced in the error. The wave will not leave the yard on a stale licence.
A failed stop can be rescheduled back to scheduled for another run, or sent return-to-sender with a captured reason (max attempts, address incorrect, refused, damaged, recall, other). The route is explicit, not a guess.
Bulk mark-delivered deliberately skips any stop carrying a COD amount, because cash collection cannot be bulk-confirmed. The wizard reports how many were marked and how many skipped, so COD stops never get closed blind.
Waves, deliveries, and attempts are all scoped by global company-isolation record rules. A dispatcher in one company never sees another company's stops or cash.
What is inside
Built to do the job, end to end.
- Waves and stops. eh.log.last.mile.wave is the daily plan for one driver and vehicle, auto-numbered, with departed and completed timestamps and live counters for stops, delivered, failed, pending, and completion percentage. eh.log.last.mile.delivery is one stop, carrying customer, delivery address, promised window, package count, weight, and cargo description.
- Proof of delivery and attempts. Each stop holds recipient name and role, a signature image, and a photo image, all captured at the delivered action. eh.log.last.mile.attempt is the append-only log of every door knock with outcome (delivered, customer-not-home, refused, address-incorrect, damaged, vehicle-breakdown, other), timestamp, notes, and optional GPS latitude and longitude.
- COD and cash-up. Per-stop expected and collected COD with a collection method (cash, card, transfer, none), rolled up on the wave into expected, collected, and outstanding monetary totals. The driver manifest PDF prints the stop sequence and an end-of-shift cash-up table for the hand-back.
- Sale order link and dispatch tools. A Last Mile flag and a deliveries stat button sit on the sale order; deliveries spawn from a confirmed order or stand alone for ad-hoc pickups. Mass-dispatch and mass-mark-delivered wizards act on selections, and kanban, calendar, pivot, and graph views drive the dispatch board. Built on eh_log_base, eh_log_quotation, and eh_log_transport.
Honest about the edges
What this does not do, so nothing surprises you.
- No route optimisation. Stops are sequenced manually by drag-and-drop; the module does not compute an optimal visiting order or distances.
- No live map tracking. GPS latitude and longitude are recorded on attempt entries as data, but there is no real-time vehicle map or moving-dot tracking screen.
- No customer notifications. The module does not send SMS or email delivery alerts, tracking links, or window reminders to recipients.
- No driver mobile app. Proof of delivery (signature, photo, recipient) is captured through the standard Odoo backend actions, not a dedicated offline driver device app.
- No carrier or EDI integration. This module does not connect to third-party parcel carriers, label printers, or EDI tracking feeds.
- This is the last-mile distribution module of the suite. International freight, customs declarations, and dangerous-goods classification live in other ERP Heritage logistics modules, not here.
- Requires the ERP Heritage logistics base, quotation, and transport modules, which supply the shared driver and vehicle records and the reporting layout.
Odoo 19 last mile delivery, last mile delivery management Odoo, Odoo route dispatch, Odoo proof of delivery ePOD, cash on delivery Odoo COD, delivery wave planning, Odoo delivery attempts and returns, driver manifest Odoo, multi-stop dispatch Odoo Community, B2C delivery distribution Odoo, Odoo logistics suite, return to sender workflow, last mile route board, Odoo Community delivery tracking
Please log in to comment on this module