English source · 4 min
EDI is an independent app, not another commerce engine
The app at extensions/apps/edi/ contains its own Manifest, mappings, Rust process,
codecs and tests. It uses the existing app gateway and immutable native callbacks.
App Studio clones that same package; a coding agent edits the same Manifest.
Neither installation nor release copies app files into core system directories.
Implemented document profiles
| Direction | Profile | Result |
|---|---|---|
| Inbound | UN/EDIFACT ORDERS D96A / D23A, bounded segment profile | Validate envelope/references/counts and supplier SKUs/whole quantities; map to an explicitly approved company unit and buyer. |
| Inbound | UBL 2.1 Order, bounded fields | Parse namespaced party/document/currency/SKU/quantity fields. |
| Inbound | cXML OrderRequest, original orders | Parse From/To identities, order number, currency and supplier items. |
| Outbound | EDIFACT ORDRSP / DESADV / INVOIC D96A | Render native order response, already-issued delivery note or invoice snapshots. |
| Outbound | UBL 2.1 OrderResponse / DespatchAdvice / Invoice | Render those same native immutable snapshots; no second document numbering or pricing engine. |
This is bounded syntax/profile support, not arbitrary trading-partner equivalence, EN16931/Peppol validation, certified transport or automatic regulatory compliance. XML parsing/escaping is tested; complete official UBL XSD and partner business-rule validation are not yet an acceptance gate. No AS2/AS4, SFTP, VAN or Peppol connection is bundled. Add these as app-owned transports with explicit partner configuration, credentials, signatures, acknowledgements and uncertainty handling.
Imported prices/totals are informational: the buyer's actual checkout uses native prices, taxes, stock, payment/shipping methods and B2B approval/budget policies. Unsupported EDIFACT segments/terms fail explicitly. The XML profiles do not preserve all possible source extensions; review required partner terms before adoption. Invoice export currently requires native net-tax mode, consistent positive VAT and line totals matching the native net total. Mixed/zero/exempt VAT or unrepresented shipping/discount charges are rejected until a corresponding profile is implemented. Older order snapshots lacking supplier SKU are rejected rather than reading mutable current catalog data. A delivery note is not proof of a physical shipment. Cancelled orders cannot be exported as accepted order responses. Replaying an identical inbound document rechecks current authority and preserves its existing receipt revision.
Install and configure
- In App Studio choose EDI procurement; keep its private partners/messages/inputs entities and reviewed service actions. The default package ID is
edi; clones need a matching serverAPP_ID. - Install into a controlled workspace and approve its exact immutable digest. Grant
data.read,data.write,b2b.read,b2b.manage; outbound documents additionally requireorders.read,documents.read,customers.pii. The current creator must hold the matching native rights. - Create the app callback credential with those explicit permissions and an expiry. Store it only in the app service's server configuration. Revocation or package upgrades invalidate it.
- Run
cargo build --locked --bin edi-gateway. SetAPP_BIND_ADDR(default0.0.0.0:8798), strongAPP_TOKEN, optionalAPP_IDandAPP_EDI_TENANTSas described in the app README. Register the service using the existingAPP_SERVICESoperator configuration; secrets stay server-side. - In the app, create one active mapping per partner: document format, sender/receiver identity, purchasing-unit reference and buyer customer reference. Mapping IDs are private app data with tenant-aware native references.
- Use
validate_document, thenimport_document. Validation alone has no commerce effects. Import creates a private native list owned by the mapped buyer; it cannot place an order. - Sign in as that buyer, select the company unit, apply the imported list and complete the ordinary approval/checkout. Issue documents in the existing order administration.
- Call
export_documentwithpartnerId,format,kind,orderIdand, for invoice/delivery note,receiptId. A rendered document is returned, not sent. The response reports its source snapshot andnetworkCertified:false.
The private native record_action callback can invoke only declared list/save
handlers under current Manifest/key/action permissions. It cannot recursively
call external services. b2b_requisition requires explicit B2B management and
valid mapped native identities. receipt_snapshot requires documents, orders and
PII authority and the matching tenant/order/receipt. It never creates a receipt.
Reliability and security
The document number plus partner/envelope identifies an import; a SHA-256 source hash detects conflicting reuse. A replay rechecks the active partner and native buyer/unit/catalog before returning the existing private list. Durable receipts use ordinary app records/outbox, with no app-owned filesystem queue or new SQL store. A restart does not forget an import. Input IDs/quantities/document length, XML node count, gateway body size, callbacks and process admission are bounded. DTD/external entity payloads are rejected. Callback URLs are operator-fixed HTTPS origins (loopback allowed for tests); documents cannot choose an egress destination.
Run DATABASE_URL=... TEST_PSQL=... python3 scripts/verify_integration.py --only edi
in a disposable database. It tests three imports, conflict/replay, wrong partner,
foreign identity, native checkout, immutable native outbound documents, revoked
credentials and cold restart. cargo test --bin edi-gateway covers parser and
serializer counterexamples. No real external messages or payments are sent.
Primary protocol references: UNECE ORDERS, UBL 2.1 Order, cXML, AS2, AS4, Peppol billing requirements.