# EDI maps A map comprises an `edi_map` row and ordered `edi_map_rule` rows. EDI paths resolve through the guide's loop tree; target paths support one association level. `condition`, `defaultValue` and `required` apply within each loop occurrence. Missing optional values preserve child alignment. `transformArgs` is a JSON object with string values. Omitted transforms copy the first value. An inbound `ediPath` may join several element paths with `+` (outside any `[...]` predicate); their values are concatenated in order. This is how a date and a time held in separate elements reach `DATETIME`: `G62[G6201=10]/G6202+G62[G6201=10]/G6204`. Inside a `[*]` loop path only the part after the anchor is split (`S5[*]/G6202+G6204`). A `condition` such as `present(G62[G6201=10]/G6202)` skips the rule when the elements are absent; a transform with no input otherwise fails the rule. | Transform | Arguments / result | | --- | --- | | DATE | CCYYMMDD or YYMMDD; fixed 1950–2049 century window; QQQ date | | TIME | HHMM, HHMMSS, fractional seconds; normalized string | | DATETIME | Date and time values, or `time` argument; `timezone` defaults UTC | | DATEPART / TIMEPART | Outbound halves of a DATETIME: a QQQ timestamp (an instant, an offset timestamp, or a zone-less one read as UTC) rendered as CCYYMMDD or HHMMSS in the `timezone` argument (default UTC) | | DECIMAL | `scale` implied decimal places, default 0 | | QUALIFIER | Sibling predicate in `ediPath`, e.g. `N1[N101=ST]/N104` | | CODE | Map-local translation object, e.g. `{"EA":"each","CA":"case"}` | | UNIT | `factor`, `divisor`, `scale` (defaults 1, 1, 6), HALF_UP | | CONSTANT | `value`; needs no EDI input | | CONCAT | `separator`, default empty; joins selected values | | SPLIT | Literal `separator` (comma), zero-based `index` (0) | | SUBSTRING | Zero-based `start` inclusive, `end` exclusive | | TRIM / UPPER | Whitespace trim / locale-independent uppercase | | LOOKUP | `table`, `key`, `result` (default id); exactly one permitted row | | SEQUENCE | Outbound loop occurrence, starting at `start` (default 1) | | HL | Outbound HL01 counter, HL02 nearest parent, HL03 `code`, HL04 child indicator | Supply the partner timezone explicitly for DATETIME. UNIT uses configured conversion factors/pack sizes; host-dependent field lookups and code-list translation can register named transforms through `EdiRuntime.current().transforms().register(name, transform)`. Transforms execute as the service session. LOOKUP explicitly enforces permissions. Samples reference encrypted PayloadStore objects. Preview JSON contains `values` and recursive `associations`; `expectedResultJson` uses the same shape. Comparisons show structured before/after JSON as Result lines. Preview never invokes target application. See the synthetic 850 resources under `src/main/resources/edi/maps` and [GUIDE-FORMAT.md](GUIDE-FORMAT.md). ## Outbound maps OUTBOUND rules are evaluated in sequence order. EDI path prefixes create nested loop scopes; the directly mapped QQQ association drives each occurrence. Nested QQQ paths such as `cartons.items.sku` are supported and fetched recursively by the worker. Constants within a loop can carry an association field as `qqqPath` to identify their scope. See the 856 samples for Shipment/Order/Pack/Item loops and parent numbering. DATE/TIME format QQQ values as X12 dates/times; DECIMAL multiplies by the implied `scale`. Other registered transforms operate on the source value. Conditions use the existing EDI rule language over segments already emitted. A missing required mapping input fails mapping; structurally invalid mapped output opens VALIDATION and is never sent. ST/SE or UNH/UNT are generated by the mapper; the worker allocates controls. Component-target paths use `-`, for example `LIN03-1` and `LIN03-2`, and retain components separately so the EDIFACT writer can escape data. ## Warehouse and logistics samples Phase d adds baseline guides and sample maps for four documents; test sources define the synthetic `sample_wms_*`, `sample_shipment_status` and `sample_load*` tables. Maps with a second direction use an `-in` or `-out` file suffix. | File | Direction | Target | Business key | | --- | --- | --- | --- | | `940-*-sample.json` | INBOUND | `sample_wms_order` + `lines` | W0502 (secondary W0503) | | `945-*-sample.json` / `945-in-*` | OUTBOUND / INBOUND | `sample_wms_shipment` + `lines` | W0602 | | `214-*-sample.json` | INBOUND | `sample_shipment_status` (flat, first LX event) | B1002 (secondary B1001) | | `204-*-sample.json` / `204-out-*` | INBOUND / OUTBOUND | `sample_load` + `stops` | B204 | Order dates and appointments arrive as `DATETIME` from a qualified G62 (`G62[G6201=10]/...`) or from the stop's G62 and leave as `DATEPART` plus `TIMEPART`. The 204 stop address is read from the nested loop (`S5[*]/S5N1/N102`; the guide gives the stop-level N1 loop its own id, `S5N1`, so it does not collide with the header N1 loop) and the stop sequence is mapped from S501. A 214 can carry several LX events; the sample map records the first (`LX[1]/...`) and a host that wants all of them maps an association instead. Optional outbound qualifiers such as MAN01 and L1102 are constants, so the sample source rows must carry the value they qualify (the carton SSCC, the bill of lading). ## EDIFACT retail samples Each of D96A and D01B includes `ORDERS--sample.json` inbound to `sample_order` and `lines`, and outbound `ORDRSP` from `sample_order`, `DESADV` from `sample_shipment` with `cartons.items`, and `INVOIC` from `sample_invoice` with `lines`. Test sources define these synthetic tables. ORDERS carries its business key in BGM02, date in qualified DTM01 component 2, buyer in qualified NAD02 component 1, and items in SG25. BGM's document codes are 220, 231, 351 and 380 respectively. These subsets intentionally carry only the fields exercised by the samples. Composite paths address values, not delimiter-joined strings. An identifier containing `+`, `:` or `'` remains a single value; the writer supplies release escapes. The outbound agreement owns UNA settings. Separate map resources per directory keep future version-specific changes isolated.