EDI SPS Commerce
edi_spscommerce · OCA/edi
-
Security25/25No findings
-
Activity25/25Human commit this month
-
Required by5/250 modules depend on it
-
Maturity5/25In 1 Odoo series since 19.0
Heuristic over the facts below, not an audit · How it's computed
Description
EDI integration with SPS Commerce via their canonical RSX XML
format (namespace http://www.spscommerce.com/RSX, schema v7.7.0), on
top of the OCA EDI framework (edi_core_oca), targeting Odoo 19.0.
RSX is SPS's proprietary normalized schema: one document type covers every trading partner — SPS maps each partner's native X12/EDIFACT/API behind it, so we integrate once instead of per-partner segment maps.
Documents covered:
- Orders inbound — RSX
Orders→ draftsale.order - Shipments outbound (ASN) —
stock.picking→ RSXShipments - Invoices outbound —
account.move→ RSXInvoices
All three share one group vocabulary (Address, Dates, References, Notes,
PaymentTerms, Taxes, ChargesAllowances, CarrierInformation, part-number
id block). Inbound payloads are parsed by services/rsx.py
(xmltodict) into schema-shaped dicts; outbound payloads are rendered
by QWeb edi.exchange.template.output templates that consume the
business records directly.
Transport is pluggable per exchange record:
- SPS-hosted SFTP (
sftp.spscommerce.com) viaedi_storage_oca— inbound files polled fromout/testout, outbound uploaded toin/testin; - Manual drop (fallback) — import wizard for inbound, local directory for outbound.
This module is a POC in active development: the mappings cover the core fields and defer the long schema tail (carrier detail, pack levels, charges/allowances, taxes detail) to the partner implementation guide.
Not affiliated with or endorsed by SPS Commerce.
Dependencies
- Odoo dependencies
- Python dependencies
- xmltodict, PyYAML, openupgradelib, fsspec>=2024.5.0
- System dependencies
- None
- Required by
- None
Code analysis
Extracted from the source by best-effort static analysis (no code is executed); details may be incomplete.
Views touched 6
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
qweb_sps_address |
qweb | New | ||
qweb_sps_invoices |
qweb | New | ||
qweb_sps_item_ids |
qweb | New | ||
qweb_sps_meta |
qweb | New | ||
qweb_sps_shipments |
qweb | New | ||
view_edi_sps_import_wizard_form |
edi.sps.import.wizard.form | edi.sps.import.wizard | form | New |
HTTP endpoints 0
No HTTP endpoints found for this module.
Models touched 6
No new fields.
Public methods (0)No public methods.
No new fields.
Public methods (0)No public methods.
No new fields.
Public methods (7)-
check(self, exchange_record)Poll remote done/error dirs — only meaningful with a storage. -
generate(self, exchange_record)Render the outbound payload via the type's QWeb output template. Document structure *and* the RSX -> Odoo field mapping live in the ``edi.exchange.template.output`` QWeb document: the template consumes the business record directly (``record`` / ``exchange_record`` / ``backend`` are already in the render context). This method only injects ``meta`` (envelope ids from the exchange-type settings) — the template's customization surface needs no code. -
input_validate(self, exchange_record, value=None, **kw)Validate the received payload is RSX XML of the expected document. -
output_validate(self, exchange_record, value=None, **kw) -
process(self, exchange_record)Parse the received payload and create business documents. -
receive(self, exchange_record)Fetch the payload: attached content first, storage second. Attached content wins so the import wizard and manual exchange records keep working even when the backend has a storage configured. Records created by the storage poller carry only a filename, so they fall through to the remote fetch. -
send(self, exchange_record)Deliver the payload: storage transport first, local dir fallback. With ``backend_id.storage_id`` set, delegates to ``edi.oca.storage.handler.send`` which uploads to ``output_dir_pending`` on the remote filesystem. Otherwise writes the payload to ``rsx.outbound_dir`` (manual fallback).
-
exchange_fileBinaryrequired=Truestring='RSX file' -
exchange_filenameCharstring='Filename' -
exchange_type_idMany2one → edi.exchange.typecomodel_name='edi.exchange.type'domain=[('direction', '=', 'input'), ('backend_type_id.code', '=', 'sps')]required=Truestring='Exchange type'
-
action_import(self)
No new fields.
Public methods (0)No public methods.
No new fields.
Public methods (1)-
button_validate(self)