| 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 | 13897 |
| Technical Name |
eh_log_edi |
| 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 | 13897 |
| Technical Name |
eh_log_edi |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
EDI Hub for Freight and 3PL
Queue, translate, and dispatch EDIFACT freight messages with retry, dead-letter, and a full state machine.
Why this module
EDI Hub for Freight and 3PL
Nothing sends silently
Every dispatch is one row with a guarded state machine: draft, queued, sent, acked, closed, plus rejected and dead-letter. A cron walks the queued state every five minutes. You always know where each message is.
Failures land in a known place
A send error increments the retry counter against a per-message budget. When the budget is spent the row moves to dead-letter, not into silence, carrying its last error and an operator resume button. Mass-resume handles a backlog in one click.
Built once, sent the same twice
The wire payload is built by the translator, stored on the row, and never regenerated. A re-send uses the exact bytes. Inbound raw payloads are persisted before parse, so a parse failure never loses the evidence.
Day in the life
From freight job to carrier and back
An operator dispatches a freight job and clicks Queue IFTMIN. The hub creates one outbound row per EDI partner configured for that message type. The dispatch cron resolves the IFTMIN translator, builds the UN/EDIFACT D.96B forwarding instruction from the job (shipper and consignee NAD parties, gross weight, volume, envelope control numbers), and pushes it over the partner's transport. Later the carrier returns an IFTSTA status report. The receive entry point persists the raw bytes, the inbound cron parses the RFF reference, STS status code, DTM timestamp and LOC location, matches the freight job by name or tracking reference, and writes a normalised tracking event onto the job. An unknown status code falls through to in-transit with the original code preserved, so nothing is dropped on the floor.
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.
Inbound IFTSTA matches the freight job on either its name or its tracking reference. If no job matches, the parser returns cleanly without raising, so a stray status report for an unknown shipment is recorded and triaged rather than crashing the queue.
IFTSTA carrier status codes are mapped to normalised tracking events (picked up, in transit, customs hold, customs cleared, delivered, exception, and more). Any code outside the map records an in-transit event and preserves the original numeric code in the description, so carrier-specific statuses are never silently lost.
Free-text party fields (name, street, city) are stripped of the EDIFACT reserved characters (apostrophe, plus, colon, question mark) before they reach the wire, so a consignee name with punctuation cannot corrupt the segment structure of an outbound IFTMIN.
When a message exhausts its retry budget it moves to dead-letter with its last error and retry count intact. An operator resume button zeroes the counter, clears the error, and re-queues. The mass-action wizard does this across a whole selection at once.
The outbound payload is built once and stored as an attachment. Every retry re-uses the exact stored bytes rather than rebuilding, so the partner sees identical content across attempts even if the source record changed in between.
Outbound and inbound state can only change through the action buttons; a direct write to the state field is rejected. Illegal transitions (for example queued straight to closed) raise a state-conflict error rather than corrupting the workflow.
A partner can hold several EDI configurations (production, staging, different contracts), but only one may be the default per partner per company. A constraint blocks a second default before it is saved.
SFTP requires paramiko and HTTP a reachable endpoint. If paramiko is absent or AS2 is selected, the transport raises a clear, coded error telling the operator exactly what to install, rather than failing obscurely mid-dispatch.
What is inside
Built to do the job, end to end.
- EDI partner registry. eh.log.edi.partner pairs a res.partner with a transport, the message types it may exchange, a partner identifier (GLN, DUNS, EAN, or internal), a sender-identifier override, and a filename template. A partner can carry multiple configurations with a single enforced default.
- Message type master. eh.log.edi.message.type lists the EDIFACT or X12 message identifiers you support, each with a direction and encoding. A save-time constraint blocks any active message type whose translator is not registered in code, so a typo or an un-built message surfaces immediately, not at dispatch.
- Transport configuration. eh.log.edi.transport carries the endpoint and protocol for SFTP, SMTP, HTTP, or file drop, plus a mock transport for tests. Credentials resolve through the suite credentials helper. A constraint checks that host, target email, or URL is present for the chosen protocol.
- Outbound queue and dispatch cron. eh.log.edi.outbound is one row per attempt with a guarded state machine, retry counter, max-retries budget, dead-letter, transport reference, and last-error capture. A cron walks the queued state every five minutes and advances each row.
- Inbound queue and process cron. eh.log.edi.inbound mirrors outbound: received, parsed, processed, closed, plus rejected. The receive entry point persists raw bytes first; the cron parses then applies. Parse output is stored as JSON for operator review and replay.
- Reference translators. Two translators ship end to end: an IFTMIN outbound builder driven by the freight job and an IFTSTA inbound parser that writes onto the tracking event log. A shared base class provides EDIFACT segment composition and tolerant segment-splitting helpers. Adding a message type is a translator file plus a data row.
- Freight job integration. The freight job gains a Queue IFTMIN action, an EDI outbound count, and a smart-button view of its messages. Queuing creates one outbound row per active EDI partner subscribed to IFTMIN within the same company.
- Multi-company isolation and audit. Global record rules scope partner configurations, transports, and both queues by company. Outbound and inbound records carry mail.thread chatter with state tracking, so every transition is logged on the record timeline.
Honest about the edges
What this does not do, so nothing surprises you.
- The two translators that ship end to end are IFTMIN (outbound) and IFTSTA (inbound), both UN/EDIFACT D.96B. They implement a working subset of each spec, not the full message. Other message types and a full segment set are added by writing a translator class plus a data row.
- EDIFACT is the only encoding with shipped translators. X12, XML, and JSON exist as selectable encodings on the message-type model, but no X12, XML, or JSON translator is included.
- The IFTMIN builder uses a minimal UNB/UNH envelope and collapses goods to a single item. Per-partner schema variants, dangerous-goods, temperature, and customs-status segments are intended to be added in a translator subclass.
- SFTP dispatch requires the optional paramiko library on the Odoo host. AS2 is a listed protocol but is not implemented and raises a clear error pointing at the optional dependency.
- This is a B2B message hub. It is not a real-time carrier API client and not a customs regulator gateway; those belong to separate modules in the suite.
- Inbound receipt assumes payloads are delivered to the receive entry point by a transport adapter or endpoint you wire up; no inbound SFTP poller or mailbox listener ships in this module.
Odoo EDI, EDIFACT Odoo, IFTMIN, IFTSTA, freight EDI, logistics EDI hub, 3PL EDI integration, per-partner EDI mapping, SFTP EDI dispatch, EDI dead-letter retry, inbound outbound EDI queue, Odoo 19 freight forwarding, carrier status report integration, UN/EDIFACT D.96B, multi-company EDI
Please log in to comment on this module