Order Export & Tracking ImportDocs

Order Export & Tracking Import Documentation

Installation steps and a complete reference for every profile setting, mapping option, the automatic tracking import and the unified log, with concrete examples — the same level of detail our support uses to help customers.

View as Markdown

Installation

Requirements

Magento 2.4.x — tested on 2.4.9, compatible with previous 2.4.* releases. PHP 8.1–8.5. Requires codingrow/module-core (installed automatically as a Composer dependency) for the shared Codingrow admin menu and license validation.

Setup steps

  1. Add the credentials you'll receive by email to auth.json in your Magento project root:
    { "http-basic": { "repo.codingrow.com": { "username": "...", "password": "..." } } }
  2. composer config repositories.codingrow composer https://repo.codingrow.com
  3. composer require codingrow/module-oeti
  4. bin/magento module:enable Codingrow_Oeti
  5. bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush
  6. Paste your license key into Admin → Stores → Configuration → Codingrow → Order Export & Tracking Import → License → License Key, save, then bin/magento cache:flush.
  7. Under the same section's General group, set Enable module to "Yes" — the module ships enabled at the Magento level but functionally off, so it never exports anything until you explicitly turn it on.
  8. Create your first profile under Codingrow → Order Export & Tracking Import → Export Profiles — see Profiles below.

The whole profile admin, mapping builder, log and every notification email are available in 7 languages, auto-selected per admin user locale:

Uninstallation

composer remove codingrow/module-oeti then bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush. Profiles and the export/tracking log (codingrow_oeti_profile, codingrow_oeti_log, codingrow_oeti_tracking_log) are never deleted automatically — use Export profile first if you want to keep a copy of your profile configuration.

User guide

Profiles

Everything in the module is organized around profiles, listed under Codingrow → Order Export & Tracking Import → Export Profiles. Each profile is completely independent: its own name, its own enabled/disabled switch, its own trigger status(es), its own destination (channel + format), its own field mapping and its own row in the export log — you can run any number of profiles side by side (one per supplier, one per carrier, one for an internal ERP), and disabling or deleting one never affects the others.

A profile that is disabled (Profile enabled = "No") never exports anything, whether triggered automatically, from the manual action, or from the CLI command — this is independent from the module-wide Enable module switch under System Config, which acts as a single master off-switch for every profile at once.

Channels & formats

Every profile picks one channel (where the payload is delivered) and one format (how it's serialized) — the two choices are independent, so any format works with any channel.

ChannelTypical useKey settings
REST APISends the payload as an HTTP request to a webservice Destination URL, HTTP method (GET/POST/PUT/PATCH), authentication (None, HTTP Basic, Bearer token), minimum seconds between requests (rate limiting, 1 second by default)
FTP / SFTPUploads the payload as a file to a remote server Host, port (21 by default), username, password, remote path, optional FTPS (explicit TLS), passive mode
Local fileWrites the payload to a file under this store's own pub/media/, for an external system to pick up over HTTP Subfolder — the file lands under pub/media/codingrow_oeti/<subfolder>/ (default subfolder: "default")

Formats: JSON, XML or CSV, chosen independently of the channel above — the same field mapping (see below) drives all three, the format only changes how it's serialized.

Field mapping

The Mapping tab is a table of rows, each connecting a target (the field name in the output — a dot means one level of nesting, e.g. customer.email) to a source path chosen from a dropdown of every available order/customer/item field. Empty rows are ignored on save.

Rows are read top to bottom in the same shape as the output itself: an optional Header template first, then the order-level mapping rows, then any Repeat blocks (see below), and an optional Footer template last.

Transformations

Each mapping row can apply one transformation to the source value before it's written to the target field:

TransformWhat it does
NoneDirect copy of the source path's value (falls back to "Default value" when the source is empty).
Static valueIgnores the source entirely, always writes the fixed text in "Value".
Strip HTML tagsRemoves HTML markup from the source value — useful for a product name or description that carries residual formatting.
Text templateFree text with placeholders, e.g. {order.shipping_address.firstname} {order.shipping_address.lastname}. A function is also available inside a placeholder: striphtml{path} (same as the Strip HTML tags transform, usable inline) and substr{path,N} (drops the first N characters, e.g. substr{order.some_code,3}).
Search and replaceLooks for the "Search" text inside the source value (case-insensitive) and replaces it with "Value" exactly as given.
NumberSerializes the value as a real JSON number instead of a quoted string — use it when the destination validates the field's TYPE strictly (a quantity sent as the database-raw string "1.0000" gets rejected by some APIs, while 1.0 as a real number is accepted). This is not the default for numeric-looking fields on purpose: turning it on everywhere would silently strip leading zeros from things like a postcode or an article code, so it's an opt-in choice per row, not an automatic behaviour.

The same {path} / striphtml{} / substr{} syntax used in Text template rows is also available in Repeat block rows and in the profile's optional Header/Footer.

Repeat blocks

A repeat block builds a nested array in the output — the most common case is one entry per order item. Each block has a Block output key (where the array is written in the output) and a source collection (what it repeats over, e.g. the order's items), plus its own set of mapping rows underneath, evaluated once per element with "current" scoped to that element — so a row's source path inside a repeat block refers to fields of the current item, not the order as a whole.

Example. A block with output key items, source collection "Order items", and two rows (sku ← current item SKU, qty ← current item quantity) produces:
{
  "items": [
    { "sku": "43241", "qty": 2 }
  ]
}
A profile can define any number of independent repeat blocks — for example one for the item list and a separate one for a list of applied discounts.

Trigger conditions

The General tab has a nested AND/OR condition builder — the same tree-style interface as Magento's own Cart Price Rules (an "Add" link on every group to add a condition or a nested sub-group, a remove icon on any node) — that decides both which order rows a profile actually exports and whether the profile exports the order at all. Each condition compares a product attribute (e.g. sku, a custom "supplier code" attribute, price...) against a value, with an operator: equal to/not equal to, contains/does not contain, starts with/ends with, greater than/less than (or equal to), is empty/is not empty.

Conditions inside a group combine with ALL (AND) or ANY (OR), and groups can nest inside groups — for example sku contains "ABC" OR (supplier_code = "Supplier2" AND price > 10). No conditions configured = no filter, every row is exported (same as the old "Only supplier items" = "No" before version 1.3.0).

Typical use with several dropshipping suppliers: one profile per supplier, each with its own condition (e.g. Profile A: supplier_code = "Supplier1", Profile B: supplier_code = "Supplier2") — an order containing items from both suppliers correctly triggers both profiles in parallel, each one exporting only the rows that belong to it. If no row matches a given profile's conditions, that profile simply does not export that order (see the "Skipped" log status below) — not an error.

Every attribute used in a condition automatically becomes available as a mappable field in the payload (items.attributes.<code>, see Field mapping above). When the conditions exclude rows from an order, the live preview shows an explicit warning naming how many rows were left out and why — so an empty or shorter-than- expected payload is never a silent surprise.

Live preview

The Preview button on the profile edit page builds a temporary, never-saved profile from whatever is currently in the form — including changes you haven't saved yet — and runs it against a real order you pick, through the exact same code path used for a genuine export. The result is the literal JSON/XML/CSV payload that order would produce, so you can correct the mapping before ever activating the profile, instead of finding out from a failed real export.

Trigger & deduplication

The Trigger status multiselect on the General tab lists which order status(es) start an automatic export for that profile (Ctrl/Cmd-click to select more than one) — checked only on the automatic, event-driven trigger; the manual grid action and the CLI command ignore it on purpose, since triggering by hand is itself the deliberate choice to export regardless of status. The manual "Export via Codingrow Order Export" action on the Sales > Orders grid runs every enabled profile against the selected orders in one click — each profile's own Trigger conditions decide what it actually sends, exactly like the automatic trigger.

Every attempt is written to that profile's log (see below), and the log is also what prevents duplicates: the same order is never exported twice automatically by the same profile, whatever the order does afterwards (further edits, status changes back and forth). If a genuine resend is needed — after fixing a destination-side issue, for example — use Force resend, which explicitly bypasses this protection.

Tracking import

A per-profile Tracking Import tab (off by default) turns on a periodic poll that asks your supplier which items have shipped and, for those items, creates a native Magento shipment with its tracking number — independently per profile, reusing the profile's own Trigger conditions to know which items of the order belong to it.

SettingWhat it does
Reference fieldWhich already-mapped field holds the supplier's order reference. It is captured automatically on every export attempt — successful or failed — so tracking still works when the order already existed on the supplier's side (for example, entered by hand before the automatic export). No extra send-side configuration.
Item matching attributeWhich product attribute identifies an item for the supplier — usually the same one used in the Trigger conditions (e.g. a "supplier code"). Suppliers report their own items by their own code, not the Magento SKU, so the module has to be told which attribute to compare.
Verification endpointURL, authentication and frequency (in minutes), plus the mapping of the supplier's response: where to read the reference, the tracking number, the tracking URL (if any), the carrier and the list of shipped items.

Partial shipments. If an order has items from several suppliers (or one supplier ships in more than one wave), each check creates a shipment only for the items actually reported as shipped at that moment, never beyond what is still left to ship — so an order legitimately ending up with several shipments over time is the intended behaviour, not a bug.

Customer email. When the supplier provides a clickable tracking link (a URL, not just a number), the customer receives an email with a "Track your package" button instead of the plain native Magento email (which would show only the number, with no clickable link for a carrier Magento doesn't recognise natively). When the supplier provides no URL, the standard native email is used, unchanged.

No manual action is needed in normal operation: the check runs on its own in the background at the configured frequency (Magento cron must be running, as for any scheduled task).

Log & Force resend

From version 1.4.0 the log is no longer split per profile (a Log tab inside each profile). A single Log page (button on the Export Profiles grid) lists orders — not individual attempts — one per row, paginated, with the latest export status and the latest tracking status side by side: a single glance at an order even when several profiles/suppliers are involved.

Clicking View full history opens that order's complete history, split into two sections — Export log and Tracking log — each listing every attempt/check from every profile involved, with an expandable details row (exact request payload sent, response body received) and, on the export side, a per-row Force resend button.

On the export side an attempt is Success, Error or Skipped. Skipped is not an error: no order item matched that profile's Trigger conditions, so nothing was sent — useful with several profiles/suppliers to see at a glance why a given profile did not export a given order. On the tracking side, a failed check usually just means the supplier hasn't reported anything shipped for those items yet; it is retried automatically on the next poll, with no manual action needed.

A failed or skipped row's Force resend (export side only) re-runs the export for that exact order through that exact profile right now, bypassing the deduplication protection — a confirmation dialog spells this out first, since it's a deliberate override, available both from the main Log page and from the order detail. Tracking has no manual "force check" equivalent: the next scheduled poll simply tries again.

Failure notification emails

Two General-tab settings control failure notifications, independent of the log (which always records every attempt regardless of these settings): Notification recipients (one or more email addresses, comma-separated — leave empty to send nothing) and Send email for (which events trigger a notification).

The email body includes the actual error returned by the destination, not just a generic HTTP status line: when the response body is parseable JSON with a message field, that message is appended verbatim (e.g. "Destination returned HTTP 422 - Minimum product quantity is 1.0"); otherwise the raw response body is included, truncated to 500 characters — so the real cause is visible straight from the inbox, without opening the log.

Import / Export profile

The Export profile button on a profile's edit page downloads its entire configuration — general settings, destination, mapping rows and repeat blocks — as a single JSON file, with destination credentials deliberately excluded so the file is safe to store, share with support, or commit alongside a deployment. The Import profile button on the Export Profiles grid re-creates a profile from such a file — the typical use is moving a profile from a staging/demo store to production, or keeping a backup of a mapping you're happy with before experimenting further. Credentials always have to be re-entered by hand after an import, since they were never in the file to begin with.

License

One license per domain, entered under Admin → Stores → Configuration → Codingrow → Order Export & Tracking Import → License → License Key. Includes all updates for that domain. Need to move to a different domain (staging → production, or a site migration)? Your first domain change is free and instant from your account page — no waiting, no ticket needed. From the second change onward, a change is allowed once a year. You can also request a refund within 30 days of purchase, on your own, from the same account page.