| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Discuss (mail)
• Invoicing (account) • Purchase (purchase) • Sales (sale_management) |
| Community Apps Dependencies | Show |
| Lines of code | 12104 |
| Technical Name |
eh_log_track_trace |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Discuss (mail)
• Invoicing (account) • Purchase (purchase) • Sales (sale_management) |
| Community Apps Dependencies | Show |
| Lines of code | 12104 |
| Technical Name |
eh_log_track_trace |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
Track and Trace
One public tracking page and one normalized event log that every freight job, transport trip, and last-mile delivery posts to, fed by signed carrier webhooks and milestone email alerts.
Why this module
Track and Trace
Every record, one timeline
Freight jobs, transport trips, last-mile deliveries, and waves all post into a single append-only event log through one trackable mixin. New operational models inherit the mixin and are picked up automatically, no per-model wiring.
Carrier webhooks, signature first
Inbound posts to /track/event/<carrier> verify an HMAC-SHA256 signature against a per-carrier shared secret before any parsing. Each carrier maps its own event vocabulary to the shared code set, and the raw payload is retained for dispute forensics.
Public page that leaks nothing
The /track/<token> page needs no login. Tokens are HMAC-derived and not reversible to a record id, the response is sent no-store, and only timeline-safe fields render. Internal notes, costs, and references never reach the page.
Day in the life
A shipment moves from booking to doorstep.
A freight job is booked and the state transition emits a normalized booked event onto the log. The carrier integration posts in-transit and customs-hold updates to the signed webhook, each verified, mapped, and appended. A subscribed consignee gets a milestone email on customs clearance. The customer opens the bookmarked tracking link and watches the timeline build from origin to out-for-delivery to delivered, while operators see the same events plus the retained raw payloads on the back office.
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.
A webhook call with a missing or mismatched signature is rejected with a clean JSON error before the body is ever parsed. Signature is checked first, payload parsed second, record touched last.
A carrier event code with no mapping row is logged as a warning and acknowledged with an ignored status, so the carrier does not retry forever and an unknown code never lands on the public timeline.
A bot scraping random tokens hits a not-found page that returns no record data and is sent no-store. Tokens are 128-bit HMAC digests, so enumeration does not surface real shipments.
Tracking events are append-only. Direct ORM create is blocked outside the logging helper, the core event fields are immutable after write, and delete is refused, so a timeline cannot be quietly rewritten.
Rotating the token salt on the settings page deliberately invalidates every outstanding tracking link at once, the correct behavior when a link set must be revoked.
Events, subscriptions, and webhook endpoints carry a company and are scoped by global record rules, and carrier names are unique per company, so two tenants can register the same carrier without collision.
What is inside
Built to do the job, end to end.
- Trackable mixin and token. eh.log.track.trackable adds a computed non-enumerable tracking token, a public tracking URL, an event count, and a log_track_event helper to any model. The token is HMAC-SHA256 over model and id with a per-database salt, computed on access and never stored.
- Normalized append-only event log. eh.log.track.event is the single event store. A seeded code master collapses carrier and internal vocabularies into one customer-facing set spanning origin, transit, destination, exception, and delivery categories. Create is gated to the helper, core fields are locked, and delete is blocked.
- Public tracking page. A single un-authenticated /track/<token> route resolves the token, renders a QWeb timeline from public-safe event fields only, falls back to a not-found page on no match, and sends every response no-store.
- Carrier webhook endpoints. A row per carrier holds the shared-secret key, signature header, dotted JSON paths for reference, code, location, and timestamp, a target model, and a per-carrier code mapping table. The controller verifies, parses, resolves by tracking reference, maps, then appends.
- Milestone subscriptions. eh.log.track.subscription pairs a partner with a record and an optional set of event codes. Milestone events queue an email per matching subscription through a mail template, with a backfill flag to suppress notifications on historical loads.
- Settings, roles, and tests. Settings expose the public base URL and the rotatable token salt. User, manager, and auditor ACLs and global company-isolation rules ship in the box, alongside a test suite covering event logging, token round-trip, subscriptions, and webhook signature and mapping.
Honest about the edges
What this does not do, so nothing surprises you.
- This module provides shipment visibility and notifications. It does not perform customs declaration, HS-code validation, dangerous-goods classification, or container and seal management. Customs status appears only as timeline event codes such as customs hold and customs cleared.
- It does not generate or transmit EDI or carrier API messages outbound. Webhook ingestion is inbound only, one event per request, and carriers that batch multiple events per call are not supported by design.
- Multi-leg routing, quotation costing, and cost allocation live in the operational modules (freight, transport, last mile), not here. This module reads their state transitions and logs them.
- Customer self-service subscription from the public page is not included; subscriptions are created internally by an operator on a partner's behalf.
- Notifications are email only. There is no SMS or push channel, and the portal-only channel suppresses outbound mail so the partner sees events on the public page alone.
- Requires eh_log_base, eh_log_freight, eh_log_transport, and eh_log_last_mile. It extends those records and is not a standalone tracker for arbitrary Odoo models without the trackable mixin.
Odoo 19 track and trace, shipment tracking page, public parcel tracking Odoo, carrier webhook ingest, normalized event log, milestone shipment notifications, freight forwarding visibility, transport trip tracking, last-mile delivery status, HMAC webhook verification, multi-company logistics tracking, non-enumerable tracking token, append-only tracking log, Odoo logistics suite
Please log in to comment on this module