feat: phase d - logistics documents 940, 945, 214, 204 #9

Merged
KofTwentyTwo merged 1 commits from feature/phase-d-logistics into develop 2026-10-14 12:47:13 +00:00
32 changed files with 8449 additions and 6 deletions

No files matched your search

+5
View File
@@ -6,6 +6,7 @@ Following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic
### Added
- Phase d warehouse and logistics baseline guides for 940, 945, 214 and 204 in 004010 and 005010 (syntax notes, situational control-total and stop rules, AT7 pairing), inbound/outbound sample maps (940 in, 945 out/in, 214 in, 204 in/out), DATEPART/TIMEPART outbound transforms and `+`-joined inbound paths for date/time pairs, and Harbor Logistics and Ridgeline Freight demo traffic.
- Phase b retail baseline guides for 855/856/810/846/860 in 004010 and 005010; inbound/outbound sample maps and nested outbound associations with SEQUENCE/HL transforms.
- Transactional RECORD_CHANGE and manual enqueue, host-wired ESB process, batch schedules, validated encrypted envelopes, send workers, retries and dead-letter alerts.
- Instance transport registry, MINA SFTP streaming push/poll with pinned host keys, gateway OUTBOX stand-in/download delivery, and authenticated HTTPS ingress/egress using core Standard Webhooks.
@@ -29,3 +30,7 @@ Following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic
- Per-instance runtime services and configuration, synthetic generators, exact acknowledgement fixtures, concurrent SQL tests, and payload tests that verify no temporary files are created.
- Repository scaffold to the QRun qbit repository standard: `qbit-build-parent` 2.0.0, QQQ 4.1.0-RC.5, Maven wrapper, Checkstyle, JaCoCo gate, CircleCI qqq-orb 0.6.8, release-candidate workflow, Dependabot, community files.
- `EdiQBitProducer` and `EdiQBitConfig` (table prefix `edi_`, permission base `edi`).
### Fixed
- Inbound apply no longer fails with a null-pointer error on a target table that has no associations (flat tables such as the 214 status sample).
+8
View File
@@ -21,6 +21,14 @@ pass the outbound worker and an in-memory gateway; incoming 997s reconcile some
An overdue group, an exhausted send and several open exceptions provide operational examples.
Two public self-signed certificates are generated in memory; private keys are never persisted.
Phase d adds warehouse and logistics traffic, seeded last so the retail scenarios above are
unchanged. Harbor Logistics (the 3PL) gets a gateway OUTBOX transport (the partner pulls over SFTP)
and sends three valid 940 shipping orders and one with a bad unit; the orders and lines land in
`sample_wms_order`, and two shipments (one short) go out as 945s. A fourth partner, Ridgeline Freight
(code RIDGELINE, gateway transport), receives two 204 load tenders (the second a change) and sends
four 214 status events (one rejected with a bad status code) that build `sample_shipment_status`.
The in-memory gateway accepts every send, and the rejected documents produce rejecting 997s.
The SFTP/HTTPS partner settings are illustrative `.invalid` destinations. Their agreements have
no outbound transport, so they cannot contact a real partner; resulting acknowledgement send
retries are visible. Northwind alone has configured outbound documents. The in-memory gateway
+10
View File
@@ -914,3 +914,13 @@ RC.5 adaptations implemented in this worktree:
- Worker claims use database row locks within the processing transaction. A crashed worker rolls back its claim; remote-send ambiguity remains at-least-once. Batch schedules are installed from active agreement documents during runtime initialization, with up to 100 transactions from one agreement document per envelope. Schedule changes require host scheduler refresh/restart. SFTP poll schedules are installed the same way.
- Acknowledgement deadlines start on the first successful send. Resend reuses the archived bytes; Resend As New re-envelopes the archive with new ISA/GS controls and linked tracking snapshots, without remapping changed source records.
- The test-scope demo uses `QApplicationJavalinServer`, Next UI 1.0.0-RC.14, fresh in-memory H2, anonymous demo authentication, synthetic certificates generated in memory, and an in-memory gateway OUTBOX provider. See `DEMO.md`. A host scheduler and production transport credentials remain host responsibilities.
## Phase d implementation notes (2026-10-14)
- Guides for 940, 945, 214 and 204 are in-house baselines in both releases, with the same structure in 004010 and 005010 (as in phase b). Code lists carry only the values the sample maps and tests use; ID elements without a list are unconstrained. Control totals (940 W7601 against the W0101 lines, 945 W0301 against the W1203 lines) and the 204 stop rules (first stop LD, at least one UL) are guide-level `SITUATIONAL` rules, because the rule evaluator reads whole-document values; per-segment relationships use syntax notes (AT7 status/reason and date/time pairing, W12 difference needs ordered and shipped) and the MS1 segment `condition`, which is evaluated per LX occurrence.
- The 204 stop-level N1 loop has its own loop id (`S5N1`, parent `S5`) so it does not merge with the header N1 loop; map paths name it (`S5[*]/S5N1/N102`).
- Mapping needed two small engine additions, documented in `MAPS.md`: inbound paths may join elements with `+` so `DATETIME` receives a date and a time from separate elements, and outbound `DATEPART`/`TIMEPART` split a QQQ timestamp. Optional inbound DECIMAL/DATETIME rules use a `condition` because a transform with no input still fails the rule (unchanged phase a behavior).
- `InboundApplier` assumed every target table has associations; a flat table (the 214 status sample) hit a null pointer. It is now null-safe.
- The 214 sample map records the first LX event per transaction into a flat status table and always inserts (no match key), so repeated statuses form a history; a host that wants every LX event maps an association.
- Demo: Harbor Logistics gets a gateway OUTBOX transport for 945s (the partner pulls over SFTP, per 5.3) after the retail seed has run, so its earlier acknowledgements keep their visible retries; the fourth partner Ridgeline Freight is added, so `EdiDemoServerTest` now expects four partners.
+28
View File
@@ -6,11 +6,18 @@ guide's loop tree; target paths support one association level. `condition`, `def
`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"}` |
@@ -48,3 +55,24 @@ language over segments already emitted. A missing required mapping input fails m
structurally invalid mapped output opens VALIDATION and is never sent. ST/SE are generated by
the mapper and group-local controls are assigned by the worker. Component-target paths are
currently rejected explicitly; the bundled retail maps use simple elements.
## 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).
@@ -37,7 +37,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecord;
*******************************************************************************/
public class BuiltInGuideLoader
{
public static final List<String> RESOURCES = List.of("850-004010", "850-005010", "997-004010", "997-005010", "999-005010X231A1", "855-004010", "855-005010", "810-004010", "810-005010", "846-004010", "846-005010", "860-004010", "860-005010", "856-004010", "856-005010");
public static final List<String> RESOURCES = List.of("850-004010", "850-005010", "997-004010", "997-005010", "999-005010X231A1", "855-004010", "855-005010", "810-004010", "810-005010", "846-004010", "846-005010", "860-004010", "860-005010", "856-004010", "856-005010", "940-004010", "940-005010", "945-004010", "945-005010", "214-004010", "214-005010", "204-004010", "204-005010");
/*******************************************************************************
** Read the documented JSON format in memory.
@@ -107,7 +107,7 @@ public class InboundApplier
var targetTable = QContext.getQInstance().getTable(table);
String backend = com.kingsrook.qbits.edi.EdiRuntime.current().config().getBackendName();
if(targetTable == null || !backend.equals(targetTable.getBackendName())
|| targetTable.getAssociations().stream().anyMatch(a -> !backend.equals(QContext.getQInstance().getTable(a.getAssociatedTableName()).getBackendName())))
|| targetTable.getAssociations() != null && targetTable.getAssociations().stream().anyMatch(a -> !backend.equals(QContext.getQInstance().getTable(a.getAssociatedTableName()).getBackendName())))
{
throw new IllegalArgumentException("Inbound targets and associations must share the EDI transactional backend");
}
@@ -139,7 +139,7 @@ public class InboundMapper
{
return;
}
List<String> values = path == null || path.isBlank() ? List.of() : evaluator.values(path);
List<String> values = path == null || path.isBlank() ? List.of() : values(evaluator, path);
if(values.isEmpty() && rule.getValueString("defaultValue") != null)
{
values = List.of(rule.getValueString("defaultValue"));
@@ -152,6 +152,20 @@ public class InboundMapper
target.withValue(field, value);
}
/*******************************************************************************
** A path may join several element paths with a plus outside any predicate, in order, so
** a transform such as DATETIME receives a date followed by a time from separate elements.
*******************************************************************************/
private static List<String> values(RuleEvaluator evaluator, String path)
{
List<String> values = new ArrayList<>();
for(String part : path.split("\\+(?![^\\[]*\\])"))
{
values.addAll(evaluator.values(part.trim()));
}
return (values);
}
/*******************************************************************************
** Missing optional business keys remain null.
*******************************************************************************/
@@ -23,9 +23,14 @@ package com.kingsrook.qbits.edi.map;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
@@ -71,6 +76,8 @@ public class TransformRegistry
register("TIME", (v, a) -> time(first(v)).toString());
register("DATETIME", (v, a) -> date(first(v)).atTime(time(v.size() > 1 ? v.get(1) : a.getOrDefault("time", "0000")))
.atZone(ZoneId.of(a.getOrDefault("timezone", "UTC"))).toInstant());
register("DATEPART", (v, a) -> zoned(first(v), a).format(DateTimeFormatter.ofPattern("yyyyMMdd")));
register("TIMEPART", (v, a) -> zoned(first(v), a).format(DateTimeFormatter.ofPattern("HHmmss")));
register("DECIMAL", (v, a) -> new BigDecimal(first(v)).movePointLeft(Integer.parseInt(a.getOrDefault("scale", "0"))));
register("CONCAT", (v, a) -> String.join(a.getOrDefault("separator", ""), v));
register("SPLIT", (v, a) -> first(v).split(java.util.regex.Pattern.quote(a.getOrDefault("separator", ",")), -1)[Integer.parseInt(a.getOrDefault("index", "0"))]);
@@ -146,6 +153,15 @@ public class TransformRegistry
return (values.getFirst());
}
/*******************************************************************************
** Outbound DATETIME halves: an instant, or a zone-less timestamp read as UTC, in the partner zone.
*******************************************************************************/
private static ZonedDateTime zoned(String value, Map<String, String> args)
{
Instant instant = value.endsWith("Z") || value.matches(".*[+-][0-9]{2}:[0-9]{2}$") ? OffsetDateTime.parse(value).toInstant() : LocalDateTime.parse(value).toInstant(ZoneOffset.UTC);
return (instant.atZone(ZoneId.of(args.getOrDefault("timezone", "UTC"))));
}
/*******************************************************************************
** Six-digit dates use the fixed 1950-2049 century window.
*******************************************************************************/
@@ -0,0 +1,877 @@
{
"name": "QQQ baseline 204 004010",
"standard": "X12",
"version": "004010",
"transactionSet": "204",
"functionalIdCode": "SM",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "B2",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 4
},
{
"position": 4,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 6,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PP",
"TP"
]
}
],
"rules": []
},
{
"segmentId": "B2A",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"00",
"01",
"04"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"LT"
]
}
],
"rules": []
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 300,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "MS3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 4
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 4,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"BT",
"SH",
"CN"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "S5",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 3
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"LD",
"UL"
]
},
{
"position": 3,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1,
"codes": [
"L",
"K"
]
},
{
"position": 5,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 6,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "PAIRED",
"positions": [
5,
6
]
}
]
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 5,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "AT8",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"G",
"N"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"L",
"K"
]
},
{
"position": 3,
"dataType": "R",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 4,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "S5N1",
"loopMaxRepeat": 5,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"SF",
"ST",
"SH",
"CN"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
],
"parentLoopId": "S5"
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "S5N1",
"loopMaxRepeat": 5,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": [],
"parentLoopId": "S5"
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "S5N1",
"loopMaxRepeat": 5,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": [],
"parentLoopId": "S5"
},
{
"segmentId": "OID",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "OID",
"parentLoopId": "S5",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 22
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 5,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 6,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 7,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
4,
5
]
},
{
"type": "PAIRED",
"positions": [
6,
7
]
}
]
},
{
"segmentId": "L3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1,
"codes": [
"G",
"N"
]
},
{
"position": 13,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
}
]
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": [
{
"type": "SITUATIONAL",
"expression": "eq(S5[1]/S502, 'LD')",
"snipLevel": 2,
"severity": "ERROR",
"message": "The first stop must be a pickup",
"ak3Code": "8",
"ak4Code": "7"
},
{
"type": "SITUATIONAL",
"expression": "present(S5[S502=UL]/S502)",
"snipLevel": 2,
"severity": "ERROR",
"message": "At least one delivery stop is required",
"ak3Code": "8",
"ak4Code": "7"
}
]
}
@@ -0,0 +1,877 @@
{
"name": "QQQ baseline 204 005010",
"standard": "X12",
"version": "005010",
"transactionSet": "204",
"functionalIdCode": "SM",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "B2",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 4
},
{
"position": 4,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 6,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PP",
"TP"
]
}
],
"rules": []
},
{
"segmentId": "B2A",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"00",
"01",
"04"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"LT"
]
}
],
"rules": []
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 300,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "MS3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 4
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 4,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"BT",
"SH",
"CN"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "S5",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 3
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"LD",
"UL"
]
},
{
"position": 3,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1,
"codes": [
"L",
"K"
]
},
{
"position": 5,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 6,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "PAIRED",
"positions": [
5,
6
]
}
]
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 5,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "AT8",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "S5",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"G",
"N"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"L",
"K"
]
},
{
"position": 3,
"dataType": "R",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 4,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "S5N1",
"loopMaxRepeat": 5,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"SF",
"ST",
"SH",
"CN"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
],
"parentLoopId": "S5"
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "S5N1",
"loopMaxRepeat": 5,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": [],
"parentLoopId": "S5"
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "S5N1",
"loopMaxRepeat": 5,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": [],
"parentLoopId": "S5"
},
{
"segmentId": "OID",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "OID",
"parentLoopId": "S5",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 22
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 5,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 6,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 7,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
4,
5
]
},
{
"type": "PAIRED",
"positions": [
6,
7
]
}
]
},
{
"segmentId": "L3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1,
"codes": [
"G",
"N"
]
},
{
"position": 13,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
}
]
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": [
{
"type": "SITUATIONAL",
"expression": "eq(S5[1]/S502, 'LD')",
"snipLevel": 2,
"severity": "ERROR",
"message": "The first stop must be a pickup",
"ak3Code": "8",
"ak4Code": "7"
},
{
"type": "SITUATIONAL",
"expression": "present(S5[S502=UL]/S502)",
"snipLevel": 2,
"severity": "ERROR",
"message": "At least one delivery stop is required",
"ak3Code": "8",
"ak4Code": "7"
}
]
}
@@ -0,0 +1,521 @@
{
"name": "QQQ baseline 214 004010",
"standard": "X12",
"version": "004010",
"transactionSet": "214",
"functionalIdCode": "QM",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "B10",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 4
}
],
"rules": []
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 300,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"SH",
"CN",
"CA"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "LX",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 6
}
],
"rules": []
},
{
"segmentId": "AT7",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"X1",
"X3",
"AF",
"D1",
"AG"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 5,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 6,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 7,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
1,
3
]
},
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "PAIRED",
"positions": [
5,
6
]
},
{
"type": "CONDITIONAL",
"positions": [
7,
6
]
}
]
},
{
"segmentId": "MS1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"condition": "in(AT701, 'X1', 'X3', 'AF', 'D1')",
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
}
]
},
{
"segmentId": "MS2",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 4
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
}
]
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": "LX",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "AT8",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"G",
"N"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"L",
"K"
]
},
{
"position": 3,
"dataType": "R",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 4,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
}
],
"rules": []
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": []
}
@@ -0,0 +1,521 @@
{
"name": "QQQ baseline 214 005010",
"standard": "X12",
"version": "005010",
"transactionSet": "214",
"functionalIdCode": "QM",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "B10",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 4
}
],
"rules": []
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 300,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"SH",
"CN",
"CA"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "LX",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 6
}
],
"rules": []
},
{
"segmentId": "AT7",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"X1",
"X3",
"AF",
"D1",
"AG"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 5,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 6,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 7,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
1,
3
]
},
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "PAIRED",
"positions": [
5,
6
]
},
{
"type": "CONDITIONAL",
"positions": [
7,
6
]
}
]
},
{
"segmentId": "MS1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"condition": "in(AT701, 'X1', 'X3', 'AF', 'D1')",
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
}
]
},
{
"segmentId": "MS2",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 4
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
}
]
},
{
"segmentId": "L11",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": "LX",
"loopMaxRepeat": 999,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "AT8",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 10,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"G",
"N"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 1,
"codes": [
"L",
"K"
]
},
{
"position": 3,
"dataType": "R",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 4,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
}
],
"rules": []
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": []
}
@@ -0,0 +1,690 @@
{
"name": "QQQ baseline 940 004010",
"standard": "X12",
"version": "004010",
"transactionSet": "940",
"functionalIdCode": "OW",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "W05",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2,
"codes": [
"N",
"D"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 22
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 22
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"ST",
"SF",
"BT"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N2",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 60
}
],
"rules": []
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "G61",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"IC"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "NTE",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 100,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 80
}
],
"rules": []
},
{
"segmentId": "W66",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PP",
"TP"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 35
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 35
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 4
}
],
"rules": []
},
{
"segmentId": "LX",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 6
}
],
"rules": []
},
{
"segmentId": "W01",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 7
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"EA",
"CA",
"PK",
"LB",
"KG"
]
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 12,
"maxLength": 12
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 5,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
},
{
"position": 6,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 7,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
4,
5
]
},
{
"type": "PAIRED",
"positions": [
6,
7
]
}
]
},
{
"segmentId": "G69",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "W76",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"LB",
"KG"
]
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": [
{
"type": "SITUATIONAL",
"expression": "present(N1[N101=ST]/N101)",
"snipLevel": 2,
"severity": "ERROR",
"message": "Ship-to party is required",
"ak3Code": "3",
"ak4Code": "1"
},
{
"type": "SITUATIONAL",
"expression": "eq(sum(W0101), W7601)",
"snipLevel": 2,
"severity": "ERROR",
"message": "Line quantities must add up to the total",
"ak3Code": "8",
"ak4Code": "7"
}
]
}
@@ -0,0 +1,690 @@
{
"name": "QQQ baseline 940 005010",
"standard": "X12",
"version": "005010",
"transactionSet": "940",
"functionalIdCode": "OW",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "W05",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2,
"codes": [
"N",
"D"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 22
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 22
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"ST",
"SF",
"BT"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N2",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 60
}
],
"rules": []
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "G61",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"IC"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "NTE",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 100,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 80
}
],
"rules": []
},
{
"segmentId": "W66",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PP",
"TP"
]
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 35
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 35
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 4
}
],
"rules": []
},
{
"segmentId": "LX",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 6
}
],
"rules": []
},
{
"segmentId": "W01",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 7
},
{
"position": 2,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"EA",
"CA",
"PK",
"LB",
"KG"
]
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 12,
"maxLength": 12
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 5,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
},
{
"position": 6,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 7,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
4,
5
]
},
{
"type": "PAIRED",
"positions": [
6,
7
]
}
]
},
{
"segmentId": "G69",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 45
}
],
"rules": []
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "W76",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"LB",
"KG"
]
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": [
{
"type": "SITUATIONAL",
"expression": "present(N1[N101=ST]/N101)",
"snipLevel": 2,
"severity": "ERROR",
"message": "Ship-to party is required",
"ak3Code": "3",
"ak4Code": "1"
},
{
"type": "SITUATIONAL",
"expression": "eq(sum(W0101), W7601)",
"snipLevel": 2,
"severity": "ERROR",
"message": "Line quantities must add up to the total",
"ak3Code": "8",
"ak4Code": "7"
}
]
}
@@ -0,0 +1,657 @@
{
"name": "QQQ baseline 945 004010",
"standard": "X12",
"version": "004010",
"transactionSet": "945",
"functionalIdCode": "SW",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "W06",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2,
"codes": [
"F",
"A",
"P"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 22
},
{
"position": 3,
"dataType": "DT",
"usage": "REQUIRED",
"minLength": 8,
"maxLength": 8
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 5,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 6,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 22
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"ST",
"SF",
"BT"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N2",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 60
}
],
"rules": []
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "W27",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 4
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 35
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PP",
"TP"
]
}
],
"rules": []
},
{
"segmentId": "LX",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 6
}
],
"rules": []
},
{
"segmentId": "W12",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PR"
]
},
{
"position": 2,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 3,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 7
},
{
"position": 4,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 5,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"EA",
"CA",
"PK",
"LB",
"KG"
]
},
{
"position": 7,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 8,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
},
{
"position": 9,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 10,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
}
],
"rules": [
{
"type": "CONDITIONAL",
"positions": [
4,
2,
3
]
},
{
"type": "PAIRED",
"positions": [
7,
8
]
},
{
"type": "PAIRED",
"positions": [
9,
10
]
}
]
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "MAN",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2,
"codes": [
"GM"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 48
}
],
"rules": []
},
{
"segmentId": "W03",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"LB",
"KG"
]
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": [
{
"type": "SITUATIONAL",
"expression": "eq(sum(W1203), W0301)",
"snipLevel": 2,
"severity": "ERROR",
"message": "Shipped quantities must add up to the total",
"ak3Code": "8",
"ak4Code": "7"
}
]
}
@@ -0,0 +1,657 @@
{
"name": "QQQ baseline 945 005010",
"standard": "X12",
"version": "005010",
"transactionSet": "945",
"functionalIdCode": "SW",
"segments": [
{
"segmentId": "ST",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 3,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
},
{
"segmentId": "W06",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2,
"codes": [
"F",
"A",
"P"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 22
},
{
"position": 3,
"dataType": "DT",
"usage": "REQUIRED",
"minLength": 8,
"maxLength": 8
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 5,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 6,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 22
}
],
"rules": []
},
{
"segmentId": "N1",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3,
"codes": [
"ST",
"SF",
"BT"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 60
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 2
},
{
"position": 4,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 80
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
3,
4
]
}
]
},
{
"segmentId": "N2",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 60
}
],
"rules": []
},
{
"segmentId": "N3",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 2,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 55
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 55
}
],
"rules": []
},
{
"segmentId": "N4",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": "N1",
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 30
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 3,
"maxLength": 15
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 3
}
],
"rules": []
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "G62",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 10,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"02",
"10",
"11"
]
},
{
"position": 2,
"dataType": "DT",
"usage": "SITUATIONAL",
"minLength": 8,
"maxLength": 8
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 1
},
{
"position": 4,
"dataType": "TM",
"usage": "SITUATIONAL",
"minLength": 4,
"maxLength": 8
},
{
"position": 5,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
1,
2
]
},
{
"type": "PAIRED",
"positions": [
3,
4
]
},
{
"type": "CONDITIONAL",
"positions": [
5,
4
]
}
]
},
{
"segmentId": "W27",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2
},
{
"position": 2,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 4
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 35
},
{
"position": 4,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PP",
"TP"
]
}
],
"rules": []
},
{
"segmentId": "LX",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 6
}
],
"rules": []
},
{
"segmentId": "W12",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"CC",
"PR"
]
},
{
"position": 2,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 3,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 7
},
{
"position": 4,
"dataType": "N0",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 7
},
{
"position": 5,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 2,
"codes": [
"EA",
"CA",
"PK",
"LB",
"KG"
]
},
{
"position": 7,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 8,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
},
{
"position": 9,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2
},
{
"position": 10,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 48
}
],
"rules": [
{
"type": "CONDITIONAL",
"positions": [
4,
2,
3
]
},
{
"type": "PAIRED",
"positions": [
7,
8
]
},
{
"type": "PAIRED",
"positions": [
9,
10
]
}
]
},
{
"segmentId": "N9",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 2,
"maxLength": 3
},
{
"position": 2,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 30
},
{
"position": 3,
"dataType": "AN",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 45
}
],
"rules": [
{
"type": "REQUIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "MAN",
"usage": "SITUATIONAL",
"minUse": 0,
"maxUse": 20,
"loopId": "LX",
"loopMaxRepeat": 200000,
"elements": [
{
"position": 1,
"dataType": "ID",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 2,
"codes": [
"GM"
]
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 48
}
],
"rules": []
},
{
"segmentId": "W03",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "R",
"usage": "SITUATIONAL",
"minLength": 1,
"maxLength": 10
},
{
"position": 3,
"dataType": "ID",
"usage": "SITUATIONAL",
"minLength": 2,
"maxLength": 2,
"codes": [
"LB",
"KG"
]
}
],
"rules": [
{
"type": "PAIRED",
"positions": [
2,
3
]
}
]
},
{
"segmentId": "SE",
"usage": "REQUIRED",
"minUse": 1,
"maxUse": 1,
"loopId": null,
"loopMaxRepeat": 200,
"elements": [
{
"position": 1,
"dataType": "N0",
"usage": "REQUIRED",
"minLength": 1,
"maxLength": 10
},
{
"position": 2,
"dataType": "AN",
"usage": "REQUIRED",
"minLength": 4,
"maxLength": 9
}
],
"rules": []
}
],
"rules": [
{
"type": "SITUATIONAL",
"expression": "eq(sum(W1203), W0301)",
"snipLevel": 2,
"severity": "ERROR",
"message": "Shipped quantities must add up to the total",
"ak3Code": "8",
"ak4Code": "7"
}
]
}
@@ -0,0 +1,129 @@
{
"map": {
"name": "Sample 204 004010",
"direction": "INBOUND",
"standard": "X12",
"version": "004010",
"transactionSet": "204",
"tableName": "sample_load",
"matchKeyFields": "shipmentId",
"onMatch": "UPDATE",
"businessKeyPath": "B204",
"businessKeyType": "LOAD",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "B204",
"qqqPath": "shipmentId",
"required": true
},
{
"sequence": 2,
"ediPath": "B202",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 3,
"ediPath": "B2A01",
"qqqPath": "purpose",
"required": false,
"transform": "CODE",
"transformArgs": "{\"00\": \"ORIGINAL\", \"04\": \"CHANGE\", \"01\": \"CANCEL\"}"
},
{
"sequence": 4,
"ediPath": "B206",
"qqqPath": "paymentMethod",
"required": false
},
{
"sequence": 5,
"ediPath": "L11[L1102=BM]/L1101",
"qqqPath": "bolNumber",
"required": false
},
{
"sequence": 6,
"ediPath": "N1[N101=BT]/N102",
"qqqPath": "billToName",
"required": false
},
{
"sequence": 7,
"ediPath": "L301",
"qqqPath": "totalWeight",
"required": false,
"transform": "DECIMAL",
"condition": "present(L301)"
},
{
"sequence": 8,
"ediPath": "S5[*]/S501",
"qqqPath": "stops.stopSequence",
"required": false
},
{
"sequence": 9,
"ediPath": "S5[*]/S502",
"qqqPath": "stops.stopReason",
"required": false
},
{
"sequence": 10,
"ediPath": "S5[*]/G6202+G6204",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(G6202)"
},
{
"sequence": 11,
"ediPath": "S5[*]/S503",
"qqqPath": "stops.weight",
"required": false,
"transform": "DECIMAL",
"condition": "present(S503)"
},
{
"sequence": 12,
"ediPath": "S5[*]/S5N1/N102",
"qqqPath": "stops.name",
"required": false
},
{
"sequence": 13,
"ediPath": "S5[*]/S5N1/N301",
"qqqPath": "stops.address",
"required": false
},
{
"sequence": 14,
"ediPath": "S5[*]/S5N1/N401",
"qqqPath": "stops.city",
"required": false
},
{
"sequence": 15,
"ediPath": "S5[*]/S5N1/N402",
"qqqPath": "stops.state",
"required": false
},
{
"sequence": 16,
"ediPath": "S5[*]/S5N1/N403",
"qqqPath": "stops.postal",
"required": false
},
{
"sequence": 17,
"ediPath": "S5[*]/OID/OID01",
"qqqPath": "stops.orderNumber",
"required": false
}
]
}
@@ -0,0 +1,129 @@
{
"map": {
"name": "Sample 204 005010",
"direction": "INBOUND",
"standard": "X12",
"version": "005010",
"transactionSet": "204",
"tableName": "sample_load",
"matchKeyFields": "shipmentId",
"onMatch": "UPDATE",
"businessKeyPath": "B204",
"businessKeyType": "LOAD",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "B204",
"qqqPath": "shipmentId",
"required": true
},
{
"sequence": 2,
"ediPath": "B202",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 3,
"ediPath": "B2A01",
"qqqPath": "purpose",
"required": false,
"transform": "CODE",
"transformArgs": "{\"00\": \"ORIGINAL\", \"04\": \"CHANGE\", \"01\": \"CANCEL\"}"
},
{
"sequence": 4,
"ediPath": "B206",
"qqqPath": "paymentMethod",
"required": false
},
{
"sequence": 5,
"ediPath": "L11[L1102=BM]/L1101",
"qqqPath": "bolNumber",
"required": false
},
{
"sequence": 6,
"ediPath": "N1[N101=BT]/N102",
"qqqPath": "billToName",
"required": false
},
{
"sequence": 7,
"ediPath": "L301",
"qqqPath": "totalWeight",
"required": false,
"transform": "DECIMAL",
"condition": "present(L301)"
},
{
"sequence": 8,
"ediPath": "S5[*]/S501",
"qqqPath": "stops.stopSequence",
"required": false
},
{
"sequence": 9,
"ediPath": "S5[*]/S502",
"qqqPath": "stops.stopReason",
"required": false
},
{
"sequence": 10,
"ediPath": "S5[*]/G6202+G6204",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(G6202)"
},
{
"sequence": 11,
"ediPath": "S5[*]/S503",
"qqqPath": "stops.weight",
"required": false,
"transform": "DECIMAL",
"condition": "present(S503)"
},
{
"sequence": 12,
"ediPath": "S5[*]/S5N1/N102",
"qqqPath": "stops.name",
"required": false
},
{
"sequence": 13,
"ediPath": "S5[*]/S5N1/N301",
"qqqPath": "stops.address",
"required": false
},
{
"sequence": 14,
"ediPath": "S5[*]/S5N1/N401",
"qqqPath": "stops.city",
"required": false
},
{
"sequence": 15,
"ediPath": "S5[*]/S5N1/N402",
"qqqPath": "stops.state",
"required": false
},
{
"sequence": 16,
"ediPath": "S5[*]/S5N1/N403",
"qqqPath": "stops.postal",
"required": false
},
{
"sequence": 17,
"ediPath": "S5[*]/OID/OID01",
"qqqPath": "stops.orderNumber",
"required": false
}
]
}
@@ -0,0 +1,218 @@
{
"map": {
"name": "Sample 204 004010 outbound",
"direction": "OUTBOUND",
"standard": "X12",
"version": "004010",
"transactionSet": "204",
"tableName": "sample_load",
"businessKeyPath": "B204",
"businessKeyType": "LOAD",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "B202",
"qqqPath": "carrierScac",
"required": true
},
{
"sequence": 2,
"ediPath": "B204",
"qqqPath": "shipmentId",
"required": true
},
{
"sequence": 3,
"ediPath": "B206",
"qqqPath": "paymentMethod",
"required": true
},
{
"sequence": 4,
"ediPath": "B2A01",
"qqqPath": "purpose",
"required": true,
"transform": "CODE",
"transformArgs": "{\"ORIGINAL\": \"00\", \"CHANGE\": \"04\", \"CANCEL\": \"01\"}"
},
{
"sequence": 5,
"ediPath": "B2A02",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"LT\"}"
},
{
"sequence": 6,
"ediPath": "L1101",
"qqqPath": "bolNumber",
"required": false
},
{
"sequence": 7,
"ediPath": "L1102",
"qqqPath": "bolNumber",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"BM\"}"
},
{
"sequence": 8,
"ediPath": "MS301",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 9,
"ediPath": "MS302",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"B\"}"
},
{
"sequence": 10,
"ediPath": "MS304",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"M\"}"
},
{
"sequence": 11,
"ediPath": "N1/N101",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"BT\"}"
},
{
"sequence": 12,
"ediPath": "N1/N102",
"qqqPath": "billToName",
"required": false
},
{
"sequence": 13,
"ediPath": "S5[*]/S501",
"qqqPath": "stops.stopSequence",
"required": true
},
{
"sequence": 14,
"ediPath": "S5[*]/S502",
"qqqPath": "stops.stopReason",
"required": true
},
{
"sequence": 15,
"ediPath": "S5[*]/S503",
"qqqPath": "stops.weight",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 16,
"ediPath": "S5[*]/S504",
"qqqPath": "stops.weight",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"L\"}"
},
{
"sequence": 17,
"ediPath": "S5[*]/G6201",
"qqqPath": "stops.stopReason",
"required": false,
"transform": "CODE",
"transformArgs": "{\"LD\": \"10\", \"UL\": \"02\"}"
},
{
"sequence": 18,
"ediPath": "S5[*]/G6202",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "DATEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 19,
"ediPath": "S5[*]/G6203",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"Y\"}"
},
{
"sequence": 20,
"ediPath": "S5[*]/G6204",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "TIMEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 21,
"ediPath": "S5[*]/S5N1/N101",
"qqqPath": "stops.stopReason",
"required": false,
"transform": "CODE",
"transformArgs": "{\"LD\": \"SF\", \"UL\": \"ST\"}"
},
{
"sequence": 22,
"ediPath": "S5[*]/S5N1/N102",
"qqqPath": "stops.name",
"required": false
},
{
"sequence": 23,
"ediPath": "S5[*]/S5N1/N301",
"qqqPath": "stops.address",
"required": false
},
{
"sequence": 24,
"ediPath": "S5[*]/S5N1/N401",
"qqqPath": "stops.city",
"required": false
},
{
"sequence": 25,
"ediPath": "S5[*]/S5N1/N402",
"qqqPath": "stops.state",
"required": false
},
{
"sequence": 26,
"ediPath": "S5[*]/S5N1/N403",
"qqqPath": "stops.postal",
"required": false
},
{
"sequence": 27,
"ediPath": "S5[*]/OID/OID01",
"qqqPath": "stops.orderNumber",
"required": false
},
{
"sequence": 28,
"ediPath": "L301",
"qqqPath": "totalWeight",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 29,
"ediPath": "L302",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"G\"}"
}
]
}
@@ -0,0 +1,218 @@
{
"map": {
"name": "Sample 204 005010 outbound",
"direction": "OUTBOUND",
"standard": "X12",
"version": "005010",
"transactionSet": "204",
"tableName": "sample_load",
"businessKeyPath": "B204",
"businessKeyType": "LOAD",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "B202",
"qqqPath": "carrierScac",
"required": true
},
{
"sequence": 2,
"ediPath": "B204",
"qqqPath": "shipmentId",
"required": true
},
{
"sequence": 3,
"ediPath": "B206",
"qqqPath": "paymentMethod",
"required": true
},
{
"sequence": 4,
"ediPath": "B2A01",
"qqqPath": "purpose",
"required": true,
"transform": "CODE",
"transformArgs": "{\"ORIGINAL\": \"00\", \"CHANGE\": \"04\", \"CANCEL\": \"01\"}"
},
{
"sequence": 5,
"ediPath": "B2A02",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"LT\"}"
},
{
"sequence": 6,
"ediPath": "L1101",
"qqqPath": "bolNumber",
"required": false
},
{
"sequence": 7,
"ediPath": "L1102",
"qqqPath": "bolNumber",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"BM\"}"
},
{
"sequence": 8,
"ediPath": "MS301",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 9,
"ediPath": "MS302",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"B\"}"
},
{
"sequence": 10,
"ediPath": "MS304",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"M\"}"
},
{
"sequence": 11,
"ediPath": "N1/N101",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"BT\"}"
},
{
"sequence": 12,
"ediPath": "N1/N102",
"qqqPath": "billToName",
"required": false
},
{
"sequence": 13,
"ediPath": "S5[*]/S501",
"qqqPath": "stops.stopSequence",
"required": true
},
{
"sequence": 14,
"ediPath": "S5[*]/S502",
"qqqPath": "stops.stopReason",
"required": true
},
{
"sequence": 15,
"ediPath": "S5[*]/S503",
"qqqPath": "stops.weight",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 16,
"ediPath": "S5[*]/S504",
"qqqPath": "stops.weight",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"L\"}"
},
{
"sequence": 17,
"ediPath": "S5[*]/G6201",
"qqqPath": "stops.stopReason",
"required": false,
"transform": "CODE",
"transformArgs": "{\"LD\": \"10\", \"UL\": \"02\"}"
},
{
"sequence": 18,
"ediPath": "S5[*]/G6202",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "DATEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 19,
"ediPath": "S5[*]/G6203",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"Y\"}"
},
{
"sequence": 20,
"ediPath": "S5[*]/G6204",
"qqqPath": "stops.appointmentAt",
"required": false,
"transform": "TIMEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 21,
"ediPath": "S5[*]/S5N1/N101",
"qqqPath": "stops.stopReason",
"required": false,
"transform": "CODE",
"transformArgs": "{\"LD\": \"SF\", \"UL\": \"ST\"}"
},
{
"sequence": 22,
"ediPath": "S5[*]/S5N1/N102",
"qqqPath": "stops.name",
"required": false
},
{
"sequence": 23,
"ediPath": "S5[*]/S5N1/N301",
"qqqPath": "stops.address",
"required": false
},
{
"sequence": 24,
"ediPath": "S5[*]/S5N1/N401",
"qqqPath": "stops.city",
"required": false
},
{
"sequence": 25,
"ediPath": "S5[*]/S5N1/N402",
"qqqPath": "stops.state",
"required": false
},
{
"sequence": 26,
"ediPath": "S5[*]/S5N1/N403",
"qqqPath": "stops.postal",
"required": false
},
{
"sequence": 27,
"ediPath": "S5[*]/OID/OID01",
"qqqPath": "stops.orderNumber",
"required": false
},
{
"sequence": 28,
"ediPath": "L301",
"qqqPath": "totalWeight",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 29,
"ediPath": "L302",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"G\"}"
}
]
}
@@ -0,0 +1,74 @@
{
"map": {
"name": "Sample 214 004010",
"direction": "INBOUND",
"standard": "X12",
"version": "004010",
"transactionSet": "214",
"tableName": "sample_shipment_status",
"businessKeyPath": "B1002",
"secondaryKeyPath": "B1001",
"businessKeyType": "SHIPMENT",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "B1002",
"qqqPath": "shipmentId",
"required": true
},
{
"sequence": 2,
"ediPath": "B1001",
"qqqPath": "proNumber",
"required": false
},
{
"sequence": 3,
"ediPath": "B1003",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 4,
"ediPath": "LX[1]/AT701",
"qqqPath": "statusCode",
"required": false
},
{
"sequence": 5,
"ediPath": "LX[1]/AT702",
"qqqPath": "reasonCode",
"required": false
},
{
"sequence": 6,
"ediPath": "LX[1]/MS101",
"qqqPath": "city",
"required": false
},
{
"sequence": 7,
"ediPath": "LX[1]/MS102",
"qqqPath": "state",
"required": false
},
{
"sequence": 8,
"ediPath": "LX[1]/MS202",
"qqqPath": "equipmentNumber",
"required": false
},
{
"sequence": 9,
"ediPath": "LX[1]/AT705+LX[1]/AT706",
"qqqPath": "eventAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(LX[1]/AT705)"
}
]
}
@@ -0,0 +1,74 @@
{
"map": {
"name": "Sample 214 005010",
"direction": "INBOUND",
"standard": "X12",
"version": "005010",
"transactionSet": "214",
"tableName": "sample_shipment_status",
"businessKeyPath": "B1002",
"secondaryKeyPath": "B1001",
"businessKeyType": "SHIPMENT",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "B1002",
"qqqPath": "shipmentId",
"required": true
},
{
"sequence": 2,
"ediPath": "B1001",
"qqqPath": "proNumber",
"required": false
},
{
"sequence": 3,
"ediPath": "B1003",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 4,
"ediPath": "LX[1]/AT701",
"qqqPath": "statusCode",
"required": false
},
{
"sequence": 5,
"ediPath": "LX[1]/AT702",
"qqqPath": "reasonCode",
"required": false
},
{
"sequence": 6,
"ediPath": "LX[1]/MS101",
"qqqPath": "city",
"required": false
},
{
"sequence": 7,
"ediPath": "LX[1]/MS102",
"qqqPath": "state",
"required": false
},
{
"sequence": 8,
"ediPath": "LX[1]/MS202",
"qqqPath": "equipmentNumber",
"required": false
},
{
"sequence": 9,
"ediPath": "LX[1]/AT705+LX[1]/AT706",
"qqqPath": "eventAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(LX[1]/AT705)"
}
]
}
@@ -0,0 +1,128 @@
{
"map": {
"name": "Sample 940 004010",
"direction": "INBOUND",
"standard": "X12",
"version": "004010",
"transactionSet": "940",
"tableName": "sample_wms_order",
"matchKeyFields": "orderNumber",
"onMatch": "UPDATE",
"businessKeyPath": "W0502",
"secondaryKeyPath": "W0503",
"businessKeyType": "ORDER",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "W0502",
"qqqPath": "orderNumber",
"required": true
},
{
"sequence": 2,
"ediPath": "W0503",
"qqqPath": "poNumber",
"required": false
},
{
"sequence": 3,
"ediPath": "W0501",
"qqqPath": "orderStatus",
"required": false,
"transform": "CODE",
"transformArgs": "{\"N\": \"NEW\", \"D\": \"CANCEL\"}"
},
{
"sequence": 4,
"ediPath": "N1[N101=ST]/N102",
"qqqPath": "shipToName",
"required": false
},
{
"sequence": 5,
"ediPath": "N1[N101=ST]/N301",
"qqqPath": "shipToAddress",
"required": false
},
{
"sequence": 6,
"ediPath": "N1[N101=ST]/N401",
"qqqPath": "shipToCity",
"required": false
},
{
"sequence": 7,
"ediPath": "N1[N101=ST]/N402",
"qqqPath": "shipToState",
"required": false
},
{
"sequence": 8,
"ediPath": "N1[N101=ST]/N403",
"qqqPath": "shipToPostal",
"required": false
},
{
"sequence": 9,
"ediPath": "W6605",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 10,
"ediPath": "G62[G6201=10]/G6202+G62[G6201=10]/G6204",
"qqqPath": "requestedShipAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(G62[G6201=10]/G6202)"
},
{
"sequence": 11,
"ediPath": "NTE02",
"qqqPath": "note",
"required": false
},
{
"sequence": 12,
"ediPath": "W7601",
"qqqPath": "totalQuantity",
"required": true,
"transform": "DECIMAL"
},
{
"sequence": 13,
"ediPath": "LX[*]/LX01",
"qqqPath": "lines.lineNumber",
"required": false
},
{
"sequence": 14,
"ediPath": "LX[*]/W0105",
"qqqPath": "lines.sku",
"required": false
},
{
"sequence": 15,
"ediPath": "LX[*]/G6901",
"qqqPath": "lines.description",
"required": false
},
{
"sequence": 16,
"ediPath": "LX[*]/W0101",
"qqqPath": "lines.quantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 17,
"ediPath": "LX[*]/W0102",
"qqqPath": "lines.unit",
"required": false
}
]
}
@@ -0,0 +1,128 @@
{
"map": {
"name": "Sample 940 005010",
"direction": "INBOUND",
"standard": "X12",
"version": "005010",
"transactionSet": "940",
"tableName": "sample_wms_order",
"matchKeyFields": "orderNumber",
"onMatch": "UPDATE",
"businessKeyPath": "W0502",
"secondaryKeyPath": "W0503",
"businessKeyType": "ORDER",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "W0502",
"qqqPath": "orderNumber",
"required": true
},
{
"sequence": 2,
"ediPath": "W0503",
"qqqPath": "poNumber",
"required": false
},
{
"sequence": 3,
"ediPath": "W0501",
"qqqPath": "orderStatus",
"required": false,
"transform": "CODE",
"transformArgs": "{\"N\": \"NEW\", \"D\": \"CANCEL\"}"
},
{
"sequence": 4,
"ediPath": "N1[N101=ST]/N102",
"qqqPath": "shipToName",
"required": false
},
{
"sequence": 5,
"ediPath": "N1[N101=ST]/N301",
"qqqPath": "shipToAddress",
"required": false
},
{
"sequence": 6,
"ediPath": "N1[N101=ST]/N401",
"qqqPath": "shipToCity",
"required": false
},
{
"sequence": 7,
"ediPath": "N1[N101=ST]/N402",
"qqqPath": "shipToState",
"required": false
},
{
"sequence": 8,
"ediPath": "N1[N101=ST]/N403",
"qqqPath": "shipToPostal",
"required": false
},
{
"sequence": 9,
"ediPath": "W6605",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 10,
"ediPath": "G62[G6201=10]/G6202+G62[G6201=10]/G6204",
"qqqPath": "requestedShipAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(G62[G6201=10]/G6202)"
},
{
"sequence": 11,
"ediPath": "NTE02",
"qqqPath": "note",
"required": false
},
{
"sequence": 12,
"ediPath": "W7601",
"qqqPath": "totalQuantity",
"required": true,
"transform": "DECIMAL"
},
{
"sequence": 13,
"ediPath": "LX[*]/LX01",
"qqqPath": "lines.lineNumber",
"required": false
},
{
"sequence": 14,
"ediPath": "LX[*]/W0105",
"qqqPath": "lines.sku",
"required": false
},
{
"sequence": 15,
"ediPath": "LX[*]/G6901",
"qqqPath": "lines.description",
"required": false
},
{
"sequence": 16,
"ediPath": "LX[*]/W0101",
"qqqPath": "lines.quantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 17,
"ediPath": "LX[*]/W0102",
"qqqPath": "lines.unit",
"required": false
}
]
}
@@ -0,0 +1,215 @@
{
"map": {
"name": "Sample 945 004010",
"direction": "OUTBOUND",
"standard": "X12",
"version": "004010",
"transactionSet": "945",
"tableName": "sample_wms_shipment",
"businessKeyPath": "W0602",
"businessKeyType": "WMS",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "W0601",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"F\"}"
},
{
"sequence": 2,
"ediPath": "W0602",
"qqqPath": "orderNumber",
"required": true
},
{
"sequence": 3,
"ediPath": "W0603",
"qqqPath": "shippedAt",
"required": true,
"transform": "DATEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 4,
"ediPath": "W0604",
"qqqPath": "shipmentNumber",
"required": false
},
{
"sequence": 5,
"ediPath": "W0606",
"qqqPath": "poNumber",
"required": false
},
{
"sequence": 6,
"ediPath": "N1/N101",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"ST\"}"
},
{
"sequence": 7,
"ediPath": "N1/N102",
"qqqPath": "shipToName",
"required": false
},
{
"sequence": 8,
"ediPath": "N1/N301",
"qqqPath": "shipToAddress",
"required": false
},
{
"sequence": 9,
"ediPath": "N1/N401",
"qqqPath": "shipToCity",
"required": false
},
{
"sequence": 10,
"ediPath": "N1/N402",
"qqqPath": "shipToState",
"required": false
},
{
"sequence": 11,
"ediPath": "N1/N403",
"qqqPath": "shipToPostal",
"required": false
},
{
"sequence": 12,
"ediPath": "G6201",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"11\"}"
},
{
"sequence": 13,
"ediPath": "G6202",
"qqqPath": "shippedAt",
"required": false,
"transform": "DATEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 14,
"ediPath": "G6203",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"Y\"}"
},
{
"sequence": 15,
"ediPath": "G6204",
"qqqPath": "shippedAt",
"required": false,
"transform": "TIMEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 16,
"ediPath": "W2701",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"M\"}"
},
{
"sequence": 17,
"ediPath": "W2702",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 18,
"ediPath": "W2703",
"qqqPath": "routing",
"required": false
},
{
"sequence": 19,
"ediPath": "LX[*]/LX01",
"qqqPath": "lines.lineNumber",
"required": false,
"transform": "SEQUENCE"
},
{
"sequence": 20,
"ediPath": "LX[*]/W1201",
"qqqPath": "lines.statusCode",
"required": false
},
{
"sequence": 21,
"ediPath": "LX[*]/W1202",
"qqqPath": "lines.orderedQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 22,
"ediPath": "LX[*]/W1203",
"qqqPath": "lines.shippedQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 23,
"ediPath": "LX[*]/W1204",
"qqqPath": "lines.shortQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 24,
"ediPath": "LX[*]/W1205",
"qqqPath": "lines.unit",
"required": false
},
{
"sequence": 25,
"ediPath": "LX[*]/W1207",
"qqqPath": "lines.sku",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"VN\"}"
},
{
"sequence": 26,
"ediPath": "LX[*]/W1208",
"qqqPath": "lines.sku",
"required": false
},
{
"sequence": 27,
"ediPath": "LX[*]/MAN01",
"qqqPath": "lines.sscc",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"GM\"}"
},
{
"sequence": 28,
"ediPath": "LX[*]/MAN02",
"qqqPath": "lines.sscc",
"required": false
},
{
"sequence": 29,
"ediPath": "W0301",
"qqqPath": "totalUnits",
"required": true,
"transform": "DECIMAL"
}
]
}
@@ -0,0 +1,215 @@
{
"map": {
"name": "Sample 945 005010",
"direction": "OUTBOUND",
"standard": "X12",
"version": "005010",
"transactionSet": "945",
"tableName": "sample_wms_shipment",
"businessKeyPath": "W0602",
"businessKeyType": "WMS",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "W0601",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"F\"}"
},
{
"sequence": 2,
"ediPath": "W0602",
"qqqPath": "orderNumber",
"required": true
},
{
"sequence": 3,
"ediPath": "W0603",
"qqqPath": "shippedAt",
"required": true,
"transform": "DATEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 4,
"ediPath": "W0604",
"qqqPath": "shipmentNumber",
"required": false
},
{
"sequence": 5,
"ediPath": "W0606",
"qqqPath": "poNumber",
"required": false
},
{
"sequence": 6,
"ediPath": "N1/N101",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"ST\"}"
},
{
"sequence": 7,
"ediPath": "N1/N102",
"qqqPath": "shipToName",
"required": false
},
{
"sequence": 8,
"ediPath": "N1/N301",
"qqqPath": "shipToAddress",
"required": false
},
{
"sequence": 9,
"ediPath": "N1/N401",
"qqqPath": "shipToCity",
"required": false
},
{
"sequence": 10,
"ediPath": "N1/N402",
"qqqPath": "shipToState",
"required": false
},
{
"sequence": 11,
"ediPath": "N1/N403",
"qqqPath": "shipToPostal",
"required": false
},
{
"sequence": 12,
"ediPath": "G6201",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"11\"}"
},
{
"sequence": 13,
"ediPath": "G6202",
"qqqPath": "shippedAt",
"required": false,
"transform": "DATEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 14,
"ediPath": "G6203",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"Y\"}"
},
{
"sequence": 15,
"ediPath": "G6204",
"qqqPath": "shippedAt",
"required": false,
"transform": "TIMEPART",
"transformArgs": "{\"timezone\": \"America/Chicago\"}"
},
{
"sequence": 16,
"ediPath": "W2701",
"qqqPath": null,
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"M\"}"
},
{
"sequence": 17,
"ediPath": "W2702",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 18,
"ediPath": "W2703",
"qqqPath": "routing",
"required": false
},
{
"sequence": 19,
"ediPath": "LX[*]/LX01",
"qqqPath": "lines.lineNumber",
"required": false,
"transform": "SEQUENCE"
},
{
"sequence": 20,
"ediPath": "LX[*]/W1201",
"qqqPath": "lines.statusCode",
"required": false
},
{
"sequence": 21,
"ediPath": "LX[*]/W1202",
"qqqPath": "lines.orderedQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 22,
"ediPath": "LX[*]/W1203",
"qqqPath": "lines.shippedQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 23,
"ediPath": "LX[*]/W1204",
"qqqPath": "lines.shortQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 24,
"ediPath": "LX[*]/W1205",
"qqqPath": "lines.unit",
"required": false
},
{
"sequence": 25,
"ediPath": "LX[*]/W1207",
"qqqPath": "lines.sku",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"VN\"}"
},
{
"sequence": 26,
"ediPath": "LX[*]/W1208",
"qqqPath": "lines.sku",
"required": false
},
{
"sequence": 27,
"ediPath": "LX[*]/MAN01",
"qqqPath": "lines.sscc",
"required": false,
"transform": "CONSTANT",
"transformArgs": "{\"value\": \"GM\"}"
},
{
"sequence": 28,
"ediPath": "LX[*]/MAN02",
"qqqPath": "lines.sscc",
"required": false
},
{
"sequence": 29,
"ediPath": "W0301",
"qqqPath": "totalUnits",
"required": true,
"transform": "DECIMAL"
}
]
}
@@ -0,0 +1,148 @@
{
"map": {
"name": "Sample 945 004010 inbound",
"direction": "INBOUND",
"standard": "X12",
"version": "004010",
"transactionSet": "945",
"tableName": "sample_wms_shipment",
"matchKeyFields": "shipmentNumber",
"onMatch": "UPDATE",
"businessKeyPath": "W0602",
"secondaryKeyPath": "W0604",
"businessKeyType": "WMS",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "W0602",
"qqqPath": "orderNumber",
"required": true
},
{
"sequence": 2,
"ediPath": "W0604",
"qqqPath": "shipmentNumber",
"required": false
},
{
"sequence": 3,
"ediPath": "W0606",
"qqqPath": "poNumber",
"required": false
},
{
"sequence": 4,
"ediPath": "G62[G6201=11]/G6202+G62[G6201=11]/G6204",
"qqqPath": "shippedAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(G62[G6201=11]/G6202)"
},
{
"sequence": 5,
"ediPath": "N1[N101=ST]/N102",
"qqqPath": "shipToName",
"required": false
},
{
"sequence": 6,
"ediPath": "N1[N101=ST]/N301",
"qqqPath": "shipToAddress",
"required": false
},
{
"sequence": 7,
"ediPath": "N1[N101=ST]/N401",
"qqqPath": "shipToCity",
"required": false
},
{
"sequence": 8,
"ediPath": "N1[N101=ST]/N402",
"qqqPath": "shipToState",
"required": false
},
{
"sequence": 9,
"ediPath": "N1[N101=ST]/N403",
"qqqPath": "shipToPostal",
"required": false
},
{
"sequence": 10,
"ediPath": "W2702",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 11,
"ediPath": "W2703",
"qqqPath": "routing",
"required": false
},
{
"sequence": 12,
"ediPath": "W0301",
"qqqPath": "totalUnits",
"required": true,
"transform": "DECIMAL"
},
{
"sequence": 13,
"ediPath": "LX[*]/LX01",
"qqqPath": "lines.lineNumber",
"required": false
},
{
"sequence": 14,
"ediPath": "LX[*]/W1201",
"qqqPath": "lines.statusCode",
"required": false
},
{
"sequence": 15,
"ediPath": "LX[*]/W1202",
"qqqPath": "lines.orderedQuantity",
"required": false,
"transform": "DECIMAL",
"condition": "present(W1202)"
},
{
"sequence": 16,
"ediPath": "LX[*]/W1203",
"qqqPath": "lines.shippedQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 17,
"ediPath": "LX[*]/W1204",
"qqqPath": "lines.shortQuantity",
"required": false,
"transform": "DECIMAL",
"condition": "present(W1204)"
},
{
"sequence": 18,
"ediPath": "LX[*]/W1205",
"qqqPath": "lines.unit",
"required": false
},
{
"sequence": 19,
"ediPath": "LX[*]/W1208",
"qqqPath": "lines.sku",
"required": false
},
{
"sequence": 20,
"ediPath": "LX[*]/MAN02",
"qqqPath": "lines.sscc",
"required": false
}
]
}
@@ -0,0 +1,148 @@
{
"map": {
"name": "Sample 945 005010 inbound",
"direction": "INBOUND",
"standard": "X12",
"version": "005010",
"transactionSet": "945",
"tableName": "sample_wms_shipment",
"matchKeyFields": "shipmentNumber",
"onMatch": "UPDATE",
"businessKeyPath": "W0602",
"secondaryKeyPath": "W0604",
"businessKeyType": "WMS",
"revision": 1,
"status": "ACTIVE"
},
"rules": [
{
"sequence": 1,
"ediPath": "W0602",
"qqqPath": "orderNumber",
"required": true
},
{
"sequence": 2,
"ediPath": "W0604",
"qqqPath": "shipmentNumber",
"required": false
},
{
"sequence": 3,
"ediPath": "W0606",
"qqqPath": "poNumber",
"required": false
},
{
"sequence": 4,
"ediPath": "G62[G6201=11]/G6202+G62[G6201=11]/G6204",
"qqqPath": "shippedAt",
"required": false,
"transform": "DATETIME",
"transformArgs": "{\"timezone\": \"America/Chicago\"}",
"condition": "present(G62[G6201=11]/G6202)"
},
{
"sequence": 5,
"ediPath": "N1[N101=ST]/N102",
"qqqPath": "shipToName",
"required": false
},
{
"sequence": 6,
"ediPath": "N1[N101=ST]/N301",
"qqqPath": "shipToAddress",
"required": false
},
{
"sequence": 7,
"ediPath": "N1[N101=ST]/N401",
"qqqPath": "shipToCity",
"required": false
},
{
"sequence": 8,
"ediPath": "N1[N101=ST]/N402",
"qqqPath": "shipToState",
"required": false
},
{
"sequence": 9,
"ediPath": "N1[N101=ST]/N403",
"qqqPath": "shipToPostal",
"required": false
},
{
"sequence": 10,
"ediPath": "W2702",
"qqqPath": "carrierScac",
"required": false
},
{
"sequence": 11,
"ediPath": "W2703",
"qqqPath": "routing",
"required": false
},
{
"sequence": 12,
"ediPath": "W0301",
"qqqPath": "totalUnits",
"required": true,
"transform": "DECIMAL"
},
{
"sequence": 13,
"ediPath": "LX[*]/LX01",
"qqqPath": "lines.lineNumber",
"required": false
},
{
"sequence": 14,
"ediPath": "LX[*]/W1201",
"qqqPath": "lines.statusCode",
"required": false
},
{
"sequence": 15,
"ediPath": "LX[*]/W1202",
"qqqPath": "lines.orderedQuantity",
"required": false,
"transform": "DECIMAL",
"condition": "present(W1202)"
},
{
"sequence": 16,
"ediPath": "LX[*]/W1203",
"qqqPath": "lines.shippedQuantity",
"required": false,
"transform": "DECIMAL"
},
{
"sequence": 17,
"ediPath": "LX[*]/W1204",
"qqqPath": "lines.shortQuantity",
"required": false,
"transform": "DECIMAL",
"condition": "present(W1204)"
},
{
"sequence": 18,
"ediPath": "LX[*]/W1205",
"qqqPath": "lines.unit",
"required": false
},
{
"sequence": 19,
"ediPath": "LX[*]/W1208",
"qqqPath": "lines.sku",
"required": false
},
{
"sequence": 20,
"ediPath": "LX[*]/MAN02",
"qqqPath": "lines.sscc",
"required": false
}
]
}
@@ -0,0 +1,357 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2025. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kingsrook.qbits.edi;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.databind.JsonNode;
import com.kingsrook.qbits.edi.storage.EdiRecords;
import com.kingsrook.qbits.edi.support.SystemWrites;
import com.kingsrook.qbits.edi.x12.X12EnvelopeReader;
import com.kingsrook.qbits.edi.x12.X12Interchange;
import com.kingsrook.qbits.edi.x12.X12Segment;
import com.kingsrook.qbits.edi.x12.X12Separators;
import com.kingsrook.qbits.edi.x12.X12TransactionSet;
import com.kingsrook.qbits.edi.x12.X12Writer;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSystemUserSession;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
/*******************************************************************************
** Synthetic warehouse and logistics schema, sample records and raw X12 builders
** shared by the phase d acceptance tests and the demo. Test sources only.
*******************************************************************************/
public final class LogisticsSupport
{
public static final String CARRIER = "SYNC";
/*******************************************************************************
** Utility class.
*******************************************************************************/
private LogisticsSupport()
{
}
/*******************************************************************************
** Create the test-scope warehouse, status and load tables with real associations.
*******************************************************************************/
public static void tables() throws Exception
{
table("sample_wms_order", "orderNumber", "poNumber", "orderStatus", "shipToName", "shipToAddress", "shipToCity", "shipToState", "shipToPostal", "carrierScac", "note",
"requestedShipAt:DATE_TIME", "totalQuantity:DECIMAL");
table("sample_wms_order_line", "parentId:INTEGER", "lineNumber:INTEGER", "sku", "description", "quantity:DECIMAL", "unit");
table("sample_wms_shipment", "orderNumber", "poNumber", "shipmentNumber", "carrierScac", "routing", "shipToName", "shipToAddress", "shipToCity", "shipToState", "shipToPostal",
"shippedAt:DATE_TIME", "totalUnits:DECIMAL");
table("sample_wms_shipment_line", "parentId:INTEGER", "lineNumber:INTEGER", "sku", "statusCode", "unit", "sscc", "orderedQuantity:DECIMAL", "shippedQuantity:DECIMAL", "shortQuantity:DECIMAL");
table("sample_shipment_status", "shipmentId", "proNumber", "carrierScac", "statusCode", "reasonCode", "city", "state", "equipmentNumber", "eventAt:DATE_TIME");
table("sample_load", "shipmentId", "carrierScac", "purpose", "paymentMethod", "bolNumber", "billToName", "totalWeight:DECIMAL");
table("sample_load_stop", "parentId:INTEGER", "stopSequence:INTEGER", "stopReason", "name", "address", "city", "state", "postal", "orderNumber", "appointmentAt:DATE_TIME", "weight:DECIMAL");
association("sample_wms_order", "sample_wms_order_line", "lines");
association("sample_wms_shipment", "sample_wms_shipment_line", "lines");
association("sample_load", "sample_load_stop", "stops");
var instance = QContext.getQInstance();
EdiRuntime.current().config().withServiceSessionSupplier(() -> new QSystemUserSession(instance));
}
/*******************************************************************************
** Define one table and its H2 schema; fields are STRING unless suffixed with a type.
*******************************************************************************/
private static void table(String name, String... fields) throws Exception
{
var instance = QContext.getQInstance();
String backend = EdiRuntime.current().config().getBackendName();
var table = new QTableMetaData().withName(name).withLabel(name).withBackendName(backend).withPrimaryKeyField("id")
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withBackendName("id"));
for(String field : fields)
{
String[] parts = field.split(":");
table.withField(new QFieldMetaData(parts[0], parts.length > 1 ? QFieldType.valueOf(parts[1]) : QFieldType.STRING).withBackendName(QInstanceEnricher.inferBackendName(parts[0])));
}
instance.addTable(table);
try(Connection connection = ConnectionManager.getConnection((RDBMSBackendMetaData) instance.getBackend(backend)); var statement = connection.createStatement())
{
statement.execute(H2Support.ddl(table, false));
}
}
/*******************************************************************************
** Join-backed child records, as the retail samples do.
*******************************************************************************/
private static void association(String parent, String child, String name)
{
var instance = QContext.getQInstance();
String join = parent + "_" + name;
instance.getTable(parent).withAssociation(new Association().withName(name).withAssociatedTableName(child).withJoinName(join));
instance.addJoin(new QJoinMetaData().withName(join).withType(JoinType.ONE_TO_MANY).withLeftTable(parent).withRightTable(child).withJoinOn(new JoinOn("id", "parentId")));
}
/*******************************************************************************
** Persist a bundled sample map (for example "945" or "945-in") against the installed guide.
*******************************************************************************/
public static QRecord installMap(String key, String version) throws Exception
{
JsonNode sample = RetailSupport.sample(key, version);
String set = sample.get("map").get("transactionSet").asText();
var guide = EdiRecords.query("edi_guide", EdiRecords.equal("transactionSet", set).withCriteria("version", QCriteriaOperator.EQUALS, version)).getFirst();
QRecord map = SystemWrites.insert("edi_map", RetailSupport.record(sample.get("map")).withValue("guideId", guide.getValue("id")));
for(var rule : sample.get("rules"))
{
SystemWrites.insert("edi_map_rule", RetailSupport.record(rule).withValue("mapId", map.getValue("id")));
}
return (map);
}
/*******************************************************************************
** The map record of a bundled sample, filling the supplied list with its rules; no database.
*******************************************************************************/
public static QRecord definition(String key, String version, List<QRecord> rules) throws Exception
{
JsonNode sample = RetailSupport.sample(key, version);
sample.get("rules").forEach(r -> rules.add(RetailSupport.record(r)));
return (RetailSupport.record(sample.get("map")));
}
/*******************************************************************************
** Shorthand for a segment whose position the reader assigns.
*******************************************************************************/
public static X12Segment s(String id, String... values)
{
return (X12Segment.of(id, 0, values));
}
/*******************************************************************************
** The functional group code for each logistics document.
*******************************************************************************/
public static String groupCode(String set)
{
return (switch(set)
{
case "940" -> "OW";
case "945" -> "SW";
case "214" -> "QM";
default -> "SM";
});
}
/*******************************************************************************
** Wrap a transaction body (without ST/SE) in a complete interchange from a sender to QQQTEST.
*******************************************************************************/
public static String interchange(String set, String version, String sender, String control, List<X12Segment> body)
{
List<X12Segment> all = new ArrayList<>();
String group = control.replaceFirst("^0+", "");
all.add(s("ISA", "00", "", "00", "", "ZZ", sender, "ZZ", "QQQTEST", "261015", "1200", version.equals("004010") ? "U" : "^", version.substring(0, 5), control, "0", "T", ":"));
all.add(s("GS", groupCode(set), sender, "QQQTEST", "20261015", "1200", group, "X", version));
all.add(s("ST", set, "0001"));
all.addAll(body);
all.add(s("SE", String.valueOf(body.size() + 2), "0001"));
all.add(s("GE", "1", group));
all.add(s("IEA", "1", control));
return (new X12Writer().write(all, X12Separators.DEFAULT, ""));
}
/*******************************************************************************
** Parse an interchange without the database runtime.
*******************************************************************************/
public static X12Interchange read(String text) throws Exception
{
return (new X12EnvelopeReader(100000).read(new ByteArrayInputStream(text.getBytes(StandardCharsets.US_ASCII))).getFirst());
}
/*******************************************************************************
** The single transaction of a one-document interchange built from a body.
*******************************************************************************/
public static X12TransactionSet transaction(String set, String version, List<X12Segment> body) throws Exception
{
return (read(interchange(set, version, "HARBORLOG", "000000001", body)).groups().getFirst().transactions().getFirst());
}
/*******************************************************************************
** Shared N1/N3/N4 party block.
*******************************************************************************/
private static List<X12Segment> party(String code, String name, String street, String city, String state, String postal)
{
return (List.of(s("N1", code, name, "92", "SITE1"), s("N3", street), s("N4", city, state, postal)));
}
/*******************************************************************************
** A 3PL receives a shipping order: one line per quantity, total in W76.
*******************************************************************************/
public static List<X12Segment> body940(String order, String po, int... quantities)
{
List<X12Segment> body = new ArrayList<>();
body.add(s("W05", "N", order, po));
body.addAll(party("ST", "Harbor Test Dock", "100 Synthetic Way", "Testville", "IL", "60000"));
body.add(s("G61", "IC", "Test Contact", "TE", "2025550100"));
body.add(s("N9", "PO", po));
body.add(s("G62", "10", "20261015", "Y", "1400", "CT"));
body.add(s("NTE", "GEN", "Synthetic note"));
body.add(s("W66", "PP", "M", "", "ROUTE-A", CARRIER));
int total = 0;
for(int i = 0; i < quantities.length; i++)
{
body.add(s("LX", String.valueOf(i + 1)));
body.add(s("W01", String.valueOf(quantities[i]), "EA", "", "VN", "SKU-" + (100 * (i + 1))));
body.add(s("G69", "Synthetic item " + (i + 1)));
body.add(s("N9", "LI", String.valueOf(i + 1)));
total += quantities[i];
}
body.add(s("W76", String.valueOf(total)));
return (body);
}
/*******************************************************************************
** A 3PL confirms a shipment; lines shipped short report the difference.
*******************************************************************************/
public static List<X12Segment> body945(String order, String po, String shipment, int[] ordered, int[] shipped)
{
List<X12Segment> body = new ArrayList<>();
body.add(s("W06", "F", order, "20261016", shipment, "", po));
body.addAll(party("ST", "Harbor Test Dock", "100 Synthetic Way", "Testville", "IL", "60000"));
body.add(s("N9", "PO", po));
body.add(s("G62", "11", "20261016", "Y", "0930", "CT"));
body.add(s("W27", "M", CARRIER, "ROUTE-A"));
int total = 0;
for(int i = 0; i < ordered.length; i++)
{
body.add(s("LX", String.valueOf(i + 1)));
boolean complete = ordered[i] == shipped[i];
body.add(s("W12", complete ? "CC" : "PR", String.valueOf(ordered[i]), String.valueOf(shipped[i]), complete ? "" : String.valueOf(ordered[i] - shipped[i]), "EA", "", "VN", "SKU-" + (100 * (i + 1))));
body.add(s("MAN", "GM", "00012345678900001" + (i + 1)));
total += shipped[i];
}
body.add(s("W03", String.valueOf(total)));
return (body);
}
/*******************************************************************************
** A carrier status event with an arrival or departure location.
*******************************************************************************/
public static List<X12Segment> body214(String shipment, String pro, String status, String reason, String city)
{
List<X12Segment> body = new ArrayList<>();
body.add(s("B10", pro, shipment, CARRIER));
body.add(s("L11", "BOL-8800", "BM"));
body.addAll(party("CN", "Harbor Test Dock", "100 Synthetic Way", "Testville", "IL", "60000"));
body.add(s("LX", "1"));
body.add(s("AT7", status, reason, "", "", "20261016", "1415", "CT"));
body.add(s("MS1", city, "IL", "US"));
body.add(s("MS2", CARRIER, "TRL12345"));
body.add(s("AT8", "G", "L", "1250", "10"));
return (body);
}
/*******************************************************************************
** A shipper tenders a two-stop load to a carrier.
*******************************************************************************/
public static List<X12Segment> body204(String shipment, String purpose)
{
List<X12Segment> body = new ArrayList<>();
body.add(s("B2", "", CARRIER, "", shipment, "", "PP"));
body.add(s("B2A", purpose, "LT"));
body.add(s("L11", "BOL-8800", "BM"));
body.add(s("MS3", CARRIER, "B", "Testville", "M"));
body.add(s("N1", "BT", "Synthetic Billing"));
body.add(s("S5", "1", "LD", "12500", "L", "20", "CA"));
body.add(s("G62", "10", "20261015", "Y", "1400", "CT"));
body.addAll(List.of(s("N1", "SF", "Synthetic Plant"), s("N3", "1 Origin Road"), s("N4", "Testville", "IL", "60000")));
body.add(s("OID", "ORD-7001", "PO-5001", "", "EA", "20"));
body.add(s("S5", "2", "UL", "12500", "L", "20", "CA"));
body.add(s("G62", "02", "20261016", "Y", "0800", "CT"));
body.addAll(List.of(s("N1", "ST", "Synthetic Receiver"), s("N3", "2 Dest Road"), s("N4", "Desttown", "TX", "75000")));
body.add(s("OID", "ORD-7001", "PO-5001", "", "EA", "20"));
body.add(s("L3", "12500", "G", "", "", "", "", "", "", "", "", "", "", "20"));
return (body);
}
/*******************************************************************************
** An order as a 3PL would hold it after receiving a 940, with one EA line per quantity.
*******************************************************************************/
public static QRecord orderRecord(String order, String po, int... quantities)
{
List<QRecord> lines = new ArrayList<>();
for(int i = 0; i < quantities.length; i++)
{
lines.add(new QRecord().withValue("lineNumber", i + 1).withValue("sku", "SKU-" + (100 * (i + 1))).withValue("description", "Synthetic item " + (i + 1))
.withValue("quantity", new BigDecimal(quantities[i])).withValue("unit", "EA"));
}
return (new QRecord().withValue("orderNumber", order).withValue("poNumber", po).withValue("orderStatus", "NEW").withValue("shipToName", "Harbor Test Dock").withValue("shipToAddress", "100 Synthetic Way")
.withValue("shipToCity", "Testville").withValue("shipToState", "IL").withValue("shipToPostal", "60000").withValue("carrierScac", CARRIER).withAssociatedRecords("lines", lines));
}
/*******************************************************************************
** Build the shipment a 3PL records after picking an order, optionally short on the last line.
*******************************************************************************/
public static QRecord shipmentFor(QRecord order, boolean shortLast)
{
List<QRecord> lines = new ArrayList<>();
List<QRecord> orderLines = order.getAssociatedRecords().get("lines");
BigDecimal total = BigDecimal.ZERO;
for(int i = 0; i < orderLines.size(); i++)
{
QRecord line = orderLines.get(i);
BigDecimal ordered = new BigDecimal(line.getValueString("quantity"));
boolean shorted = shortLast && i == orderLines.size() - 1;
BigDecimal shipped = shorted ? ordered.subtract(BigDecimal.ONE) : ordered;
total = total.add(shipped);
lines.add(new QRecord().withValue("lineNumber", i + 1).withValue("sku", line.getValueString("sku")).withValue("unit", line.getValueString("unit"))
.withValue("statusCode", shorted ? "PR" : "CC").withValue("orderedQuantity", ordered).withValue("shippedQuantity", shipped)
.withValue("shortQuantity", shorted ? BigDecimal.ONE : null).withValue("sscc", "00012345678900001" + (i + 1)));
}
return (new QRecord().withValue("orderNumber", order.getValueString("orderNumber")).withValue("poNumber", order.getValueString("poNumber")).withValue("shipmentNumber", "SHIP-" + order.getValueString("orderNumber"))
.withValue("carrierScac", order.getValueString("carrierScac")).withValue("routing", "ROUTE-A").withValue("shipToName", order.getValueString("shipToName")).withValue("shipToAddress", order.getValueString("shipToAddress"))
.withValue("shipToCity", order.getValueString("shipToCity")).withValue("shipToState", order.getValueString("shipToState")).withValue("shipToPostal", order.getValueString("shipToPostal"))
.withValue("shippedAt", Instant.parse("2026-10-16T14:30:00Z")).withValue("totalUnits", total).withAssociatedRecords("lines", lines));
}
/*******************************************************************************
** A two-stop load tendered by a shipper to a carrier, with appointments in Chicago time.
*******************************************************************************/
public static QRecord load(String shipment)
{
QRecord pickup = new QRecord().withValue("stopSequence", 1).withValue("stopReason", "LD").withValue("name", "Synthetic Plant").withValue("address", "1 Origin Road")
.withValue("city", "Testville").withValue("state", "IL").withValue("postal", "60000").withValue("orderNumber", "ORD-7001")
.withValue("appointmentAt", Instant.parse("2026-10-15T19:00:00Z")).withValue("weight", new BigDecimal("12500"));
QRecord delivery = new QRecord().withValue("stopSequence", 2).withValue("stopReason", "UL").withValue("name", "Synthetic Receiver").withValue("address", "2 Dest Road")
.withValue("city", "Desttown").withValue("state", "TX").withValue("postal", "75000").withValue("orderNumber", "ORD-7001")
.withValue("appointmentAt", Instant.parse("2026-10-16T13:00:00Z")).withValue("weight", new BigDecimal("12500"));
return (new QRecord().withValue("shipmentId", shipment).withValue("carrierScac", CARRIER).withValue("purpose", "ORIGINAL").withValue("paymentMethod", "PP")
.withValue("bolNumber", "BOL-8800").withValue("billToName", "Synthetic Billing").withValue("totalWeight", new BigDecimal("12500")).withAssociatedRecords("stops", List.of(pickup, delivery)));
}
}
@@ -0,0 +1,605 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2025. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kingsrook.qbits.edi;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.kingsrook.qbits.edi.ack.AckLevel;
import com.kingsrook.qbits.edi.ack.Ack997Builder;
import com.kingsrook.qbits.edi.flow.InboundPayload;
import com.kingsrook.qbits.edi.flow.InboundSink;
import com.kingsrook.qbits.edi.flow.InboxWorker;
import com.kingsrook.qbits.edi.flow.OutboundWorker;
import com.kingsrook.qbits.edi.flow.SendWorker;
import com.kingsrook.qbits.edi.guide.BuiltInGuideLoader;
import com.kingsrook.qbits.edi.guide.GuideValidator;
import com.kingsrook.qbits.edi.guide.ValidationFinding;
import com.kingsrook.qbits.edi.map.InboundMapper;
import com.kingsrook.qbits.edi.map.OutboundMapper;
import com.kingsrook.qbits.edi.map.TransformRegistry;
import com.kingsrook.qbits.edi.storage.EdiRecords;
import com.kingsrook.qbits.edi.storage.PayloadRef;
import com.kingsrook.qbits.edi.support.SystemWrites;
import com.kingsrook.qbits.edi.transport.gateway.standin.FileGatewayOutbox;
import com.kingsrook.qbits.edi.transport.gateway.standin.OutboxFileRef;
import com.kingsrook.qbits.edi.x12.X12Segment;
import com.kingsrook.qbits.edi.x12.X12Separators;
import com.kingsrook.qbits.edi.x12.X12TransactionSet;
import com.kingsrook.qbits.edi.x12.X12Writer;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/*******************************************************************************
** Warehouse and logistics baselines (940, 945, 214, 204) in both supported releases:
** guides, maps, round trips, crafted errors and partner routing through the pipeline.
*******************************************************************************/
class LogisticsTest
{
private final Map<String, byte[]> sent = new LinkedHashMap<>();
/*******************************************************************************
** Restore thread context and the gateway stand-in.
*******************************************************************************/
@AfterEach
void clear()
{
FileGatewayOutbox.register(null);
QContext.clear();
}
/*******************************************************************************
** Validate a synthetic body against the baseline guide of that version.
*******************************************************************************/
private static List<ValidationFinding> validate(String set, String version, List<X12Segment> body) throws Exception
{
return (new GuideValidator().validate(LogisticsSupport.transaction(set, version, body), new BuiltInGuideLoader().resource(set + "-" + version), false));
}
/*******************************************************************************
** Map a synthetic body inbound with a bundled sample map.
*******************************************************************************/
private static InboundMapper.Result map(String key, String set, String version, List<X12Segment> body) throws Exception
{
List<QRecord> rules = new ArrayList<>();
QRecord map = LogisticsSupport.definition(key, version, rules);
return (new InboundMapper(new TransformRegistry()).map(LogisticsSupport.transaction(set, version, body), new BuiltInGuideLoader().resource(set + "-" + version), map, rules));
}
/*******************************************************************************
** Build an outbound document from a record, prove it is clean, and prove the writer/reader round trip.
*******************************************************************************/
private static List<X12Segment> outbound(String key, String set, String version, QRecord source) throws Exception
{
List<QRecord> rules = new ArrayList<>();
QRecord map = LogisticsSupport.definition(key, version, rules);
X12TransactionSet built = new OutboundMapper().build(source, map, rules, "0001");
assertThat(EdiRuntime.current().validator().validate(built, new BuiltInGuideLoader().resource(set + "-" + version), false)).isEmpty();
List<X12Segment> body = built.segments().subList(1, built.segments().size() - 1);
X12TransactionSet parsed = LogisticsSupport.transaction(set, version, body);
assertThat(parsed.findings()).isEmpty();
assertThat(parsed.segments().stream().map(s -> s.id() + s.elements()).toList()).isEqualTo(built.segments().stream().map(s -> s.id() + s.elements()).toList());
return (body);
}
/*******************************************************************************
** Compact segment text, for exact expectations.
*******************************************************************************/
private static String text(List<X12Segment> body)
{
return (new X12Writer().write(body, X12Separators.DEFAULT, ""));
}
/*******************************************************************************
** Copy a body replacing one element of the nth occurrence of a segment.
*******************************************************************************/
private static List<X12Segment> with(List<X12Segment> body, String id, int nth, int element, String value)
{
List<X12Segment> copy = new ArrayList<>();
int seen = 0;
for(X12Segment segment : body)
{
if(segment.id().equals(id) && ++seen == nth)
{
List<String> values = new ArrayList<>();
for(int i = 1; i <= Math.max(segment.elements().size(), element); i++)
{
values.add(i == element ? value : segment.value(i));
}
copy.add(X12Segment.of(id, 0, values.toArray(String[]::new)));
}
else
{
copy.add(segment);
}
}
return (copy);
}
/*******************************************************************************
** A crafted error yields the expected AK3/AK4 codes and a rejecting 997 carrying them.
*******************************************************************************/
private static void rejects(String set, String version, List<X12Segment> body, String ak3, String ak4, String ackText) throws Exception
{
var interchange = LogisticsSupport.read(LogisticsSupport.interchange(set, version, "HARBORLOG", "000000001", body));
var group = interchange.groups().getFirst();
var findings = new GuideValidator().validate(group.transactions().getFirst(), new BuiltInGuideLoader().resource(set + "-" + version), false);
assertThat(findings).as(set + " " + ackText).anyMatch(f -> ak3.equals(f.ak3Code()) && ak4.equals(f.ak4Code()));
String ack = new X12Writer().write(new Ack997Builder().build(group, Map.of("0001", findings), AckLevel.ALL_TRANSACTIONS, "0002").segments(), X12Separators.DEFAULT, "");
assertThat(ack).as(set + " " + ackText).contains("AK2*" + set + "*0001~", "AK3*", "AK5*R").contains(ackText);
}
/*******************************************************************************
** A 3PL receives a shipping order and the sample map fills the order and its lines.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void shippingOrderInbound(String version) throws Exception
{
List<X12Segment> body = LogisticsSupport.body940("ORD-7001", "PO-5001", 10, 5);
assertThat(validate("940", version, body)).isEmpty();
var result = map("940", "940", version, body);
QRecord order = result.record();
assertThat(result.businessKey()).isEqualTo("ORD-7001");
assertThat(result.secondaryKey()).isEqualTo("PO-5001");
assertThat(order.getValueString("orderNumber")).isEqualTo("ORD-7001");
assertThat(order.getValueString("poNumber")).isEqualTo("PO-5001");
assertThat(order.getValueString("orderStatus")).isEqualTo("NEW");
assertThat(order.getValueString("shipToName")).isEqualTo("Harbor Test Dock");
assertThat(order.getValueString("shipToAddress")).isEqualTo("100 Synthetic Way");
assertThat(order.getValueString("shipToCity")).isEqualTo("Testville");
assertThat(order.getValueString("shipToState")).isEqualTo("IL");
assertThat(order.getValueString("shipToPostal")).isEqualTo("60000");
assertThat(order.getValueString("carrierScac")).isEqualTo("SYNC");
assertThat(order.getValueString("note")).isEqualTo("Synthetic note");
assertThat(order.getValueInstant("requestedShipAt")).isEqualTo(Instant.parse("2026-10-15T19:00:00Z"));
assertThat(order.getValueBigDecimal("totalQuantity")).isEqualByComparingTo("15");
var lines = order.getAssociatedRecords().get("lines");
assertThat(lines).hasSize(2);
assertThat(lines.get(1).getValueString("lineNumber")).isEqualTo("2");
assertThat(lines.get(1).getValueString("sku")).isEqualTo("SKU-200");
assertThat(lines.get(1).getValueString("description")).isEqualTo("Synthetic item 2");
assertThat(lines.get(1).getValueBigDecimal("quantity")).isEqualByComparingTo("5");
assertThat(lines.get(1).getValueString("unit")).isEqualTo("EA");
assertThat(map("940", "940", version, with(body, "W05", 1, 1, "D")).record().getValueString("orderStatus")).isEqualTo("CANCEL");
}
/*******************************************************************************
** Order shipped: the 940 becomes a shipment, the 945 goes out clean and maps back to the same shipment.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void orderShippedRoundTrip(String version) throws Exception
{
H2Support.create();
QRecord order = map("940", "940", version, LogisticsSupport.body940("ORD-7001", "PO-5001", 10, 5)).record();
QRecord shipment = LogisticsSupport.shipmentFor(order, true);
List<X12Segment> body = outbound("945", "945", version, shipment);
String x12 = text(body);
assertThat(x12).contains("W06*F*ORD-7001*20261016*SHIP-ORD-7001**PO-5001~", "G62*11*20261016*Y*093000~",
"W27*M*SYNC*ROUTE-A~", "W12*CC*10*10**EA**VN*SKU-100~", "W12*PR*5*4*1*EA**VN*SKU-200~", "MAN*GM*000123456789000012~", "W03*14~");
var tx = LogisticsSupport.transaction("945", version, body);
assertThat(new com.kingsrook.qbits.edi.guide.RuleEvaluator(tx.segments(), Map.of()).values("W0602")).containsExactly("ORD-7001");
var back = map("945-in", "945", version, body);
assertThat(back.businessKey()).isEqualTo("ORD-7001");
assertThat(back.secondaryKey()).isEqualTo("SHIP-ORD-7001");
QRecord record = back.record();
assertThat(record.getValueString("poNumber")).isEqualTo("PO-5001");
assertThat(record.getValueInstant("shippedAt")).isEqualTo(Instant.parse("2026-10-16T14:30:00Z"));
assertThat(record.getValueString("carrierScac")).isEqualTo("SYNC");
assertThat(record.getValueString("routing")).isEqualTo("ROUTE-A");
assertThat(record.getValueString("shipToCity")).isEqualTo("Testville");
assertThat(record.getValueBigDecimal("totalUnits")).isEqualByComparingTo("14");
var lines = record.getAssociatedRecords().get("lines");
assertThat(lines).extracting(l -> l.getValueString("statusCode")).containsExactly("CC", "PR");
assertThat(lines).extracting(l -> l.getValueString("sku")).containsExactly("SKU-100", "SKU-200");
assertThat(lines.get(0).getValueBigDecimal("shippedQuantity")).isEqualByComparingTo("10");
assertThat(lines.get(0).getValue("shortQuantity")).isNull();
assertThat(lines.get(1).getValueBigDecimal("orderedQuantity")).isEqualByComparingTo("5");
assertThat(lines.get(1).getValueBigDecimal("shippedQuantity")).isEqualByComparingTo("4");
assertThat(lines.get(1).getValueBigDecimal("shortQuantity")).isEqualByComparingTo("1");
assertThat(lines.get(1).getValueString("sscc")).isEqualTo("000123456789000012");
}
/*******************************************************************************
** A raw synthetic 945 (a shipper receiving from its 3PL) validates and maps.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void shipmentAdviceInbound(String version) throws Exception
{
List<X12Segment> body = LogisticsSupport.body945("ORD-7002", "PO-5002", "SHIP-9002", new int[] {4, 6}, new int[] {4, 6});
assertThat(validate("945", version, body)).isEmpty();
QRecord record = map("945-in", "945", version, body).record();
assertThat(record.getValueString("shipmentNumber")).isEqualTo("SHIP-9002");
assertThat(record.getValueBigDecimal("totalUnits")).isEqualByComparingTo("10");
assertThat(record.getAssociatedRecords().get("lines")).extracting(l -> l.getValueString("statusCode")).containsExactly("CC", "CC");
}
/*******************************************************************************
** Carrier status events map to one status row each, using the first LX event.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void carrierStatusInbound(String version) throws Exception
{
List<X12Segment> body = LogisticsSupport.body214("SHIP-9001", "PRO1234567", "AF", "NS", "Testville");
assertThat(validate("214", version, body)).isEmpty();
var result = map("214", "214", version, body);
assertThat(result.businessKey()).isEqualTo("SHIP-9001");
assertThat(result.secondaryKey()).isEqualTo("PRO1234567");
QRecord status = result.record();
assertThat(status.getValueString("shipmentId")).isEqualTo("SHIP-9001");
assertThat(status.getValueString("proNumber")).isEqualTo("PRO1234567");
assertThat(status.getValueString("carrierScac")).isEqualTo("SYNC");
assertThat(status.getValueString("statusCode")).isEqualTo("AF");
assertThat(status.getValueString("reasonCode")).isEqualTo("NS");
assertThat(status.getValueString("city")).isEqualTo("Testville");
assertThat(status.getValueString("state")).isEqualTo("IL");
assertThat(status.getValueString("equipmentNumber")).isEqualTo("TRL12345");
assertThat(status.getValueInstant("eventAt")).isEqualTo(Instant.parse("2026-10-16T19:15:00Z"));
List<X12Segment> events = new ArrayList<>(body.subList(0, body.size() - 1));
events.addAll(List.of(LogisticsSupport.s("LX", "2"), LogisticsSupport.s("AT7", "X1", "NS", "", "", "20261017", "0800", "CT"), LogisticsSupport.s("MS1", "Desttown", "TX", "US")));
assertThat(validate("214", version, events)).isEmpty();
assertThat(map("214", "214", version, events).record().getValueString("statusCode")).isEqualTo("AF");
}
/*******************************************************************************
** A shipper tenders a load: out, clean, and back in to the carrier's load and stops.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void loadTenderRoundTrip(String version) throws Exception
{
H2Support.create();
List<X12Segment> body = outbound("204-out", "204", version, LogisticsSupport.load("SHIP-3001"));
assertThat(text(body)).contains("B2**SYNC**SHIP-3001**PP~", "B2A*00*LT~", "L11*BOL-8800*BM~", "MS3*SYNC*B**M~", "N1*BT*Synthetic Billing~", "S5*1*LD*12500*L~", "G62*10*20261015*Y*140000~",
"N1*SF*Synthetic Plant~", "N4*Desttown*TX*75000~", "OID*ORD-7001~", "S5*2*UL*12500*L~", "G62*02*20261016*Y*080000~", "L3*12500*G~");
for(List<X12Segment> raw : List.of(body, LogisticsSupport.body204("SHIP-3001", "00")))
{
assertThat(validate("204", version, raw)).isEmpty();
var result = map("204", "204", version, raw);
assertThat(result.businessKey()).isEqualTo("SHIP-3001");
QRecord load = result.record();
assertThat(load.getValueString("carrierScac")).isEqualTo("SYNC");
assertThat(load.getValueString("purpose")).isEqualTo("ORIGINAL");
assertThat(load.getValueString("paymentMethod")).isEqualTo("PP");
assertThat(load.getValueString("bolNumber")).isEqualTo("BOL-8800");
assertThat(load.getValueString("billToName")).isEqualTo("Synthetic Billing");
assertThat(load.getValueBigDecimal("totalWeight")).isEqualByComparingTo("12500");
var stops = load.getAssociatedRecords().get("stops");
assertThat(stops).extracting(s -> s.getValueString("stopSequence")).containsExactly("1", "2");
assertThat(stops).extracting(s -> s.getValueString("stopReason")).containsExactly("LD", "UL");
assertThat(stops).extracting(s -> s.getValueString("name")).containsExactly("Synthetic Plant", "Synthetic Receiver");
assertThat(stops).extracting(s -> s.getValueString("address")).containsExactly("1 Origin Road", "2 Dest Road");
assertThat(stops).extracting(s -> s.getValueString("state")).containsExactly("IL", "TX");
assertThat(stops).extracting(s -> s.getValueInstant("appointmentAt")).containsExactly(Instant.parse("2026-10-15T19:00:00Z"), Instant.parse("2026-10-16T13:00:00Z"));
assertThat(stops).extracting(s -> s.getValueBigDecimal("weight")).allSatisfy(w -> assertThat(w).isEqualByComparingTo(new BigDecimal("12500")));
assertThat(stops).extracting(s -> s.getValueString("orderNumber")).containsExactly("ORD-7001", "ORD-7001");
}
assertThat(map("204", "204", version, LogisticsSupport.body204("SHIP-3001", "04")).record().getValueString("purpose")).isEqualTo("CHANGE");
assertThat(map("204", "204", version, LogisticsSupport.body204("SHIP-3001", "01")).record().getValueString("purpose")).isEqualTo("CANCEL");
}
/*******************************************************************************
** Crafted 940 errors produce the intended AK3/AK4 codes in a rejecting 997.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void invalidShippingOrder(String version) throws Exception
{
List<X12Segment> good = LogisticsSupport.body940("ORD-7001", "PO-5001", 10, 5);
rejects("940", version, with(good, "W01", 1, 2, "ZZ"), "8", "7", "AK4*2**7~");
rejects("940", version, with(good, "W76", 1, 1, "99"), "8", "7", "AK3*ST*");
List<X12Segment> noShipTo = new ArrayList<>(good);
noShipTo.subList(1, 4).clear();
rejects("940", version, noShipTo, "3", "1", "AK3*ST*");
rejects("940", version, with(good, "W05", 1, 2, ""), "8", "1", "AK4*2**1~");
rejects("940", version, with(good, "G62", 1, 4, ""), "8", "2", "AK4*3**2~");
}
/*******************************************************************************
** Crafted 945 errors: shipped versus ordered quantities, dates and carton codes.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void invalidShipmentAdvice(String version) throws Exception
{
List<X12Segment> good = LogisticsSupport.body945("ORD-7001", "PO-5001", "SHIP-9001", new int[] {10, 5}, new int[] {10, 4});
assertThat(validate("945", version, good)).isEmpty();
rejects("945", version, with(good, "W03", 1, 1, "99"), "8", "7", "AK3*ST*");
rejects("945", version, with(good, "W12", 2, 2, ""), "8", "2", "AK4*4**2~");
rejects("945", version, with(good, "W06", 1, 3, "20261345"), "8", "8", "AK4*3**8~");
rejects("945", version, with(good, "MAN", 1, 1, "XX"), "8", "7", "AK4*1**7~");
rejects("945", version, with(good, "W12", 1, 1, "QQ"), "8", "7", "AK4*1**7~");
}
/*******************************************************************************
** Crafted 214 errors: status and reason pairing, bad status code, time without a date, missing location.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void invalidShipmentStatus(String version) throws Exception
{
List<X12Segment> good = LogisticsSupport.body214("SHIP-9001", "PRO1234567", "AF", "NS", "Testville");
rejects("214", version, with(good, "AT7", 1, 2, ""), "8", "2", "AK4*1**2~");
rejects("214", version, with(good, "AT7", 1, 1, "ZZ"), "8", "7", "AK4*1**7~");
rejects("214", version, with(good, "AT7", 1, 5, ""), "8", "2", "AK4*5**2~");
rejects("214", version, with(good, "AT7", 1, 7, "CTX"), "8", "5", "AK4*7**5~");
List<X12Segment> noLocation = new ArrayList<>(good);
noLocation.removeIf(s -> s.id().equals("MS1"));
var findings = new GuideValidator().validate(LogisticsSupport.transaction("214", version, noLocation), new BuiltInGuideLoader().resource("214-" + version), false);
assertThat(findings).anyMatch(f -> "3".equals(f.ak3Code()) && "MS1".equals(f.segmentId()));
rejects("214", version, with(good, "B10", 1, 2, ""), "8", "1", "AK4*2**1~");
}
/*******************************************************************************
** Crafted 204 errors: stop reasons and ordering, missing shipment id, no delivery stop.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void invalidLoadTender(String version) throws Exception
{
List<X12Segment> good = LogisticsSupport.body204("SHIP-3001", "00");
assertThat(validate("204", version, good)).isEmpty();
rejects("204", version, with(good, "S5", 1, 2, "XX"), "8", "7", "AK4*2**7~");
rejects("204", version, with(good, "S5", 1, 2, "UL"), "8", "7", "AK3*ST*");
rejects("204", version, with(with(good, "S5", 2, 2, "LD"), "G62", 2, 1, "10"), "8", "7", "AK3*ST*");
rejects("204", version, with(good, "B2", 1, 4, ""), "8", "1", "AK4*4**1~");
rejects("204", version, with(good, "S5", 1, 4, ""), "8", "2", "AK4*3**2~");
List<X12Segment> noStops = new ArrayList<>(good);
noStops.removeIf(s -> !List.of("B2", "B2A", "L11", "MS3", "N1", "L3").contains(s.id()));
noStops.removeIf(s -> s.id().equals("N1") && !"BT".equals(s.value(1)));
var findings = new GuideValidator().validate(LogisticsSupport.transaction("204", version, noStops), new BuiltInGuideLoader().resource("204-" + version), false);
assertThat(findings).anyMatch(f -> "3".equals(f.ak3Code()) && "S5".equals(f.segmentId()));
}
/*******************************************************************************
** DATETIME halves, default times, and joined paths including a plus inside a predicate.
*******************************************************************************/
@Test
void dateTimeTransformsAndJoinedPaths() throws Exception
{
TransformRegistry registry = new TransformRegistry();
String chicago = "{\"timezone\":\"America/Chicago\"}";
assertThat(registry.apply("DATEPART", chicago, List.of("2026-10-16T01:30:00Z"))).isEqualTo("20261015");
assertThat(registry.apply("TIMEPART", chicago, List.of("2026-10-16T01:30:00Z"))).isEqualTo("203000");
assertThat(registry.apply("DATEPART", chicago, List.of("2026-11-02T05:30:00Z"))).isEqualTo("20261101");
assertThat(registry.apply("TIMEPART", chicago, List.of("2026-11-02T05:30:00Z"))).isEqualTo("233000");
assertThat(registry.apply("DATEPART", null, List.of("2026-10-15T19:00:00"))).isEqualTo("20261015");
assertThat(registry.apply("TIMEPART", null, List.of("2026-10-15T19:00:00"))).isEqualTo("190000");
assertThat(registry.apply("TIMEPART", null, List.of("2026-10-15T14:00:00-05:00"))).isEqualTo("190000");
assertThatThrownBy(() -> registry.apply("DATEPART", null, List.of())).hasMessage("Transform input is missing");
assertThat(registry.apply("DATETIME", "{\"time\":\"0800\"}", List.of("20261015"))).isEqualTo(Instant.parse("2026-10-15T08:00:00Z"));
assertThat(registry.apply("DATETIME", chicago, List.of("20261015", "1400"))).isEqualTo(Instant.parse("2026-10-15T19:00:00Z"));
List<X12Segment> body = new ArrayList<>(LogisticsSupport.body940("ORD-7001", "PO-5001", 3));
body.set(1, LogisticsSupport.s("N1", "ST", "Dock+Annex", "92", "SITE1"));
List<QRecord> rules = new ArrayList<>();
QRecord map = LogisticsSupport.definition("940", "004010", rules);
rules.clear();
rules.add(new QRecord().withValue("sequence", 1).withValue("ediPath", "N1[N102=Dock+Annex]/N301").withValue("qqqPath", "shipToAddress"));
rules.add(new QRecord().withValue("sequence", 2).withValue("ediPath", "W0502+W0503").withValue("qqqPath", "orderNumber").withValue("transform", "CONCAT").withValue("transformArgs", "{\"separator\":\"/\"}"));
var result = new InboundMapper(new TransformRegistry()).map(LogisticsSupport.transaction("940", "004010", body), new BuiltInGuideLoader().resource("940-004010"), map, rules);
assertThat(result.record().getValueString("shipToAddress")).isEqualTo("100 Synthetic Way");
assertThat(result.record().getValueString("orderNumber")).isEqualTo("ORD-7001/PO-5001");
}
/*******************************************************************************
** Configure the local identity and a transport-backed partner with an agreement.
*******************************************************************************/
private QRecord partner(String name, String code, String identity, String endpoint, String version) throws Exception
{
return (SystemWrites.call(() ->
{
QRecord partner = SystemWrites.insert("edi_partner", new QRecord().withValue("name", name).withValue("code", code).withValue("status", "ACTIVE").withValue("defaultTimezone", "America/Chicago"));
QRecord local = EdiRecords.query("edi_identity", EdiRecords.equal("interchangeId", "QQQTEST")).stream().findFirst()
.orElseGet(() -> unchecked(() -> SystemWrites.insert("edi_identity", new QRecord().withValue("standard", "X12").withValue("interchangeQualifier", "ZZ").withValue("interchangeId", "QQQTEST").withValue("applicationCode", "QQQTEST"))));
QRecord remote = SystemWrites.insert("edi_identity", new QRecord().withValue("partnerId", partner.getValue("id")).withValue("standard", "X12").withValue("interchangeQualifier", "ZZ").withValue("interchangeId", identity).withValue("applicationCode", identity));
QRecord transport = SystemWrites.insert("edi_transport", new QRecord().withValue("partnerId", partner.getValue("id")).withValue("name", endpoint).withValue("type", "GATEWAY").withValue("direction", "BOTH")
.withValue("gatewayEndpointName", endpoint).withValue("isActive", true).withValue("maxAttempts", 3));
return (SystemWrites.insert("edi_agreement", new QRecord().withValue("partnerId", partner.getValue("id")).withValue("localIdentityId", local.getValue("id")).withValue("partnerIdentityId", remote.getValue("id"))
.withValue("standard", "X12").withValue("usageIndicator", "T").withValue("applyTestDocuments", true).withValue("isActive", true).withValue("interchangeVersion", version.equals("004010") ? "00401" : "00501")
.withValue("outboundTransportId", transport.getValue("id"))));
}));
}
/*******************************************************************************
** Run a checked supplier from a stream lambda.
*******************************************************************************/
private static <T> T unchecked(SystemWrites.Work<T> work)
{
try
{
return (work.run());
}
catch(Exception e)
{
throw new IllegalStateException(e);
}
}
/*******************************************************************************
** Attach an agreement document with an installed sample map.
*******************************************************************************/
private void document(QRecord agreement, String direction, String set, String mapKey, String version, String table) throws Exception
{
SystemWrites.call(() ->
{
QRecord map = LogisticsSupport.installMap(mapKey, version);
QRecord document = new QRecord().withValue("agreementId", agreement.getValue("id")).withValue("direction", direction).withValue("transactionSet", set).withValue("version", version)
.withValue("functionalIdCode", LogisticsSupport.groupCode(set)).withValue("guideId", map.getValue("guideId")).withValue("mapId", map.getValue("id")).withValue("isActive", true);
if(direction.equals("INBOUND"))
{
document.withValue("ackExpectation", "997").withValue("ackLevel", "ALL_TRANSACTIONS");
}
else
{
document.withValue("sourceTableName", table).withValue("outboundTrigger", "RECORD_CHANGE").withValue("batchMode", "IMMEDIATE").withValue("ackExpectation", "997").withValue("ackDueMinutes", 1440);
}
return (SystemWrites.insert("edi_agreement_document", document));
});
}
/*******************************************************************************
** Deliver raw bytes through the durable intake, then run the inbox worker once.
*******************************************************************************/
private static void receive(String text, String external) throws Exception
{
new InboundSink(EdiRuntime.current().payloads()).receive(new InboundPayload("GATEWAY", external, "synthetic.edi", "127.0.0.1", new ByteArrayInputStream(text.getBytes(StandardCharsets.US_ASCII))));
new InboxWorker().runOnce();
}
/*******************************************************************************
** Capture whatever the sender hands to the gateway outbox, then send everything queued.
*******************************************************************************/
private void sendAll() throws Exception
{
FileGatewayOutbox.register((endpoint, name, input, size) ->
{
sent.put(name, input.readAllBytes());
return (new OutboxFileRef(sent.size(), endpoint, name, name, size, null, Instant.now()));
});
while(new SendWorker().runOnce() > 0)
{
// drain
}
}
/*******************************************************************************
** Read every query row of a table as the service session.
*******************************************************************************/
private static List<QRecord> rows(String table) throws Exception
{
return (SystemWrites.call(() -> EdiRecords.query(table, new QQueryFilter())));
}
/*******************************************************************************
** The captured outbound interchange carrying a transaction set.
*******************************************************************************/
private String sentWith(String marker)
{
return (sent.values().stream().map(b -> new String(b, StandardCharsets.US_ASCII)).filter(t -> t.contains(marker)).findFirst().orElseThrow());
}
/*******************************************************************************
** A 3PL partner: inbound 940 through routing and mapping, an unconfigured 214 and unknown sender
** rejected, then the 945 for the shipped order built, enveloped, validated and sent.
*******************************************************************************/
@ParameterizedTest
@ValueSource(strings = {"004010", "005010"})
void threePlPartnerRouting(String version) throws Exception
{
H2Support.create();
LogisticsSupport.tables();
EdiRuntime.current().initialize();
QRecord agreement = partner("Harbor Test 3PL", "HARBOR", "HARBORLOG", "harbor-outbox", version);
document(agreement, "INBOUND", "940", "940", version, null);
document(agreement, "OUTBOUND", "945", "945", version, "sample_wms_shipment");
receive(LogisticsSupport.interchange("940", version, "HARBORLOG", "000000011", LogisticsSupport.body940("ORD-7001", "PO-5001", 10, 5)), "940-a");
assertThat(rows("sample_wms_order")).singleElement().satisfies(o ->
{
assertThat(o.getValueString("orderNumber")).isEqualTo("ORD-7001");
assertThat(o.getValueString("orderStatus")).isEqualTo("NEW");
assertThat(o.getValueInstant("requestedShipAt")).isEqualTo(Instant.parse("2026-10-15T19:00:00Z"));
});
assertThat(rows("sample_wms_order_line")).extracting(l -> l.getValueString("sku")).containsExactlyInAnyOrder("SKU-100", "SKU-200");
assertThat(rows("sample_wms_order_line")).extracting(l -> l.getValueInteger("lineNumber")).containsExactlyInAnyOrder(1, 2);
assertThat(rows("edi_transaction")).anyMatch(t -> "INBOUND".equals(t.getValueString("direction")) && "940".equals(t.getValueString("transactionSet")) && "APPLIED".equals(t.getValueString("status"))
&& "ORD-7001".equals(t.getValueString("businessKey")) && "sample_wms_order".equals(t.getValueString("targetTableName")));
receive(LogisticsSupport.interchange("940", version, "HARBORLOG", "000000012", LogisticsSupport.body940("ORD-7001", "PO-5001", 12, 5)), "940-b");
assertThat(rows("sample_wms_order")).hasSize(1);
assertThat(rows("sample_wms_order").getFirst().getValueBigDecimal("totalQuantity")).isEqualByComparingTo("17");
receive(LogisticsSupport.interchange("214", version, "HARBORLOG", "000000013", LogisticsSupport.body214("SHIP-1", "PRO1", "AF", "NS", "Testville")), "214-unconfigured");
assertThat(rows("edi_transaction")).anyMatch(t -> "214".equals(t.getValueString("transactionSet")) && "INVALID".equals(t.getValueString("status")));
assertThat(rows("edi_exception")).extracting(e -> e.getValueString("type")).contains("VALIDATION");
receive(LogisticsSupport.interchange("940", version, "HARBORLOG", "000000015", with(LogisticsSupport.body940("ORD-7004", "PO-5004", 2), "W01", 1, 2, "ZZ")), "940-invalid");
assertThat(rows("edi_transaction")).anyMatch(t -> "940".equals(t.getValueString("transactionSet")) && "INVALID".equals(t.getValueString("status")));
assertThat(rows("sample_wms_order")).hasSize(1);
receive(LogisticsSupport.interchange("940", version, "NOSUCHPARTNER", "000000014", LogisticsSupport.body940("ORD-7003", "PO-5003", 1)), "940-unknown");
assertThat(rows("edi_exception")).extracting(e -> e.getValueString("type")).contains("UNKNOWN_PARTNER");
assertThat(rows("sample_wms_order")).hasSize(1);
QRecord order = LogisticsSupport.shipmentFor(map("940", "940", version, LogisticsSupport.body940("ORD-7001", "PO-5001", 12, 5)).record(), false);
SystemWrites.call(() -> SystemWrites.transaction(() -> RetailSupport.saveSource("sample_wms_shipment", order)));
assertThat(new OutboundWorker().runOnce()).isEqualTo(1);
assertThat(rows("edi_transaction")).anyMatch(t -> "OUTBOUND".equals(t.getValueString("direction")) && "945".equals(t.getValueString("transactionSet"))
&& "ORD-7001".equals(t.getValueString("businessKey")) && "sample_wms_shipment".equals(t.getValueString("targetTableName")));
sendAll();
assertThat(rows("edi_outbound_message")).allMatch(m -> "SENT".equals(m.getValueString("status")));
String interchange = sentWith("ST*945*");
var parsed = LogisticsSupport.read(interchange);
assertThat(parsed.findings()).isEmpty();
assertThat(parsed.groups().getFirst().gs().value(1)).isEqualTo("SW");
assertThat(parsed.groups().getFirst().gs().value(8)).isEqualTo(version);
assertThat(new GuideValidator().validate(parsed.groups().getFirst().transactions().getFirst(), new BuiltInGuideLoader().resource("945-" + version), false)).isEmpty();
assertThat(interchange).contains("W06*F*ORD-7001*20261016*SHIP-ORD-7001**PO-5001~", "W03*17~");
assertThat(sentWith("AK5*R")).contains("AK2*940*0001~", "AK4*2**7~");
}
/*******************************************************************************
** A carrier partner: a 204 tender goes out through the pipeline and 214 statuses build a history.
*******************************************************************************/
@Test
void carrierPartnerFlow() throws Exception
{
H2Support.create();
LogisticsSupport.tables();
EdiRuntime.current().initialize();
QRecord agreement = partner("Ridgeline Test Freight", "RIDGE", "RIDGELINE", "ridge-outbox", "004010");
document(agreement, "OUTBOUND", "204", "204-out", "004010", "sample_load");
document(agreement, "INBOUND", "214", "214", "004010", null);
SystemWrites.call(() -> SystemWrites.transaction(() -> RetailSupport.saveSource("sample_load", LogisticsSupport.load("SHIP-3001"))));
assertThat(new OutboundWorker().runOnce()).isEqualTo(1);
sendAll();
String tender = sentWith("ST*204*");
var parsed = LogisticsSupport.read(tender);
assertThat(parsed.groups().getFirst().gs().value(1)).isEqualTo("SM");
assertThat(new GuideValidator().validate(parsed.groups().getFirst().transactions().getFirst(), new BuiltInGuideLoader().resource("204-004010"), false)).isEmpty();
assertThat(rows("edi_transaction")).anyMatch(t -> "204".equals(t.getValueString("transactionSet")) && "SHIP-3001".equals(t.getValueString("businessKey")));
receive(LogisticsSupport.interchange("214", "004010", "RIDGELINE", "000000021", LogisticsSupport.body214("SHIP-3001", "PRO7654321", "X3", "NS", "Testville")), "214-a");
receive(LogisticsSupport.interchange("214", "004010", "RIDGELINE", "000000022", LogisticsSupport.body214("SHIP-3001", "PRO7654321", "AF", "NS", "Testville")), "214-b");
assertThat(rows("sample_shipment_status")).extracting(r -> r.getValueString("statusCode")).containsExactlyInAnyOrder("X3", "AF");
assertThat(rows("sample_shipment_status")).allSatisfy(r ->
{
assertThat(r.getValueString("shipmentId")).isEqualTo("SHIP-3001");
assertThat(r.getValueString("proNumber")).isEqualTo("PRO7654321");
assertThat(r.getValueInstant("eventAt")).isEqualTo(Instant.parse("2026-10-16T19:15:00Z"));
});
PayloadRef ref = new PayloadRef(rows("edi_outbound_message").getFirst().getValueString("payloadRef"), null, 0);
try(var stream = EdiRuntime.current().payloads().open(ref))
{
assertThat(LogisticsSupport.read(new String(stream.readAllBytes(), StandardCharsets.US_ASCII)).findings()).isEmpty();
}
}
}
@@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import com.kingsrook.qbits.edi.EdiRuntime;
import com.kingsrook.qbits.edi.H2Support;
import com.kingsrook.qbits.edi.LogisticsSupport;
import com.kingsrook.qbits.edi.RetailSupport;
import com.kingsrook.qbits.edi.Synthetic850;
import com.kingsrook.qbits.edi.flow.InboundSink;
@@ -80,8 +81,9 @@ public class EdiDemoServer extends AbstractQQQApplication implements AutoCloseab
{
instance = H2Support.create();
RetailSupport.tables();
LogisticsSupport.tables();
instance.setHomeAppName("edi");
for(String table : List.of("sample_order", "sample_shipment", "sample_invoice", "sample_inventory"))
for(String table : List.of("sample_order", "sample_shipment", "sample_invoice", "sample_inventory", "sample_wms_shipment", "sample_load"))
{
EdiRuntime.current().config().withSendAsEdiTable(table);
}
@@ -236,10 +238,87 @@ public class EdiDemoServer extends AbstractQQQApplication implements AutoCloseab
new SendWorker().runOnce();
installOutbox();
}
logistics(local, agreements.get(1));
return (null);
});
}
/*******************************************************************************
** Warehouse and logistics traffic: Harbor Logistics (3PL) sends 940s and receives 945s,
** and Ridgeline Freight (carrier) receives 204 tenders and sends 214 statuses.
*******************************************************************************/
private void logistics(QRecord local, QRecord harbor) throws Exception
{
QRecord harborTransport = SystemWrites.insert("edi_transport", new QRecord().withValue("partnerId", harbor.getValue("partnerId")).withValue("name", "harbor-outbox").withValue("type", "GATEWAY")
.withValue("direction", "OUTBOUND").withValue("gatewayEndpointName", "harbor-outbox").withValue("isActive", true).withValue("maxAttempts", 3));
SystemWrites.update("edi_agreement", new QRecord().withValue("id", harbor.getValue("id")).withValue("outboundTransportId", harborTransport.getValue("id")));
agreementDocument(harbor, "INBOUND", "940", "940", "sample_wms_order");
agreementDocument(harbor, "OUTBOUND", "945", "945", "sample_wms_shipment");
QRecord partner = SystemWrites.insert("edi_partner", new QRecord().withValue("name", "Ridgeline Freight").withValue("code", "RIDGELINE").withValue("contactName", "Ridgeline Freight Demo Contact")
.withValue("contactEmail", "ridgeline@example.invalid").withValue("contactPhone", "202-555-0103").withValue("status", "ACTIVE").withValue("defaultTimezone", "America/Chicago"));
QRecord remote = SystemWrites.insert("edi_identity", new QRecord().withValue("partnerId", partner.getValue("id")).withValue("standard", "X12").withValue("interchangeQualifier", "ZZ").withValue("interchangeId", "RIDGELINE").withValue("applicationCode", "RIDGELINE").withValue("isActive", true));
QRecord transport = SystemWrites.insert("edi_transport", new QRecord().withValue("partnerId", partner.getValue("id")).withValue("name", "ridgeline-gateway").withValue("type", "GATEWAY").withValue("direction", "BOTH")
.withValue("gatewayEndpointName", "ridgeline-outbox").withValue("isActive", true).withValue("maxAttempts", 3));
QRecord carrier = SystemWrites.insert("edi_agreement", new QRecord().withValue("partnerId", partner.getValue("id")).withValue("localIdentityId", local.getValue("id")).withValue("partnerIdentityId", remote.getValue("id"))
.withValue("standard", "X12").withValue("usageIndicator", "T").withValue("interchangeVersion", "00401").withValue("isActive", true).withValue("applyTestDocuments", true).withValue("outboundTransportId", transport.getValue("id")));
agreementDocument(carrier, "OUTBOUND", "204", "204-out", "sample_load");
agreementDocument(carrier, "INBOUND", "214", "214", "sample_shipment_status");
int control = 300;
receive(LogisticsSupport.interchange("940", "004010", "HARBORLOG", String.format("%09d", ++control), LogisticsSupport.body940("ORD-8001", "PO-8001", 10, 5)), "demo-940-" + control);
receive(LogisticsSupport.interchange("940", "004010", "HARBORLOG", String.format("%09d", ++control), LogisticsSupport.body940("ORD-8002", "PO-8002", 24)), "demo-940-" + control);
receive(LogisticsSupport.interchange("940", "004010", "HARBORLOG", String.format("%09d", ++control), LogisticsSupport.body940("ORD-8003", "PO-8003", 3, 3, 3)), "demo-940-" + control);
receive(LogisticsSupport.interchange("940", "004010", "HARBORLOG", String.format("%09d", ++control), invalidUnit(LogisticsSupport.body940("ORD-8004", "PO-8004", 2))), "demo-940-" + control);
enqueue("sample_wms_shipment", LogisticsSupport.shipmentFor(LogisticsSupport.orderRecord("ORD-8001", "PO-8001", 10, 5), false));
enqueue("sample_wms_shipment", LogisticsSupport.shipmentFor(LogisticsSupport.orderRecord("ORD-8002", "PO-8002", 24), true));
enqueue("sample_load", LogisticsSupport.load("SHIP-4001"));
enqueue("sample_load", LogisticsSupport.load("SHIP-4002").withValue("purpose", "CHANGE"));
for(String[] status : new String[][] {{"SHIP-4001", "X3"}, {"SHIP-4001", "AF"}, {"SHIP-4001", "D1"}, {"SHIP-4002", "ZZ"}})
{
receive(LogisticsSupport.interchange("214", "004010", "RIDGELINE", String.format("%09d", ++control), LogisticsSupport.body214(status[0], "PRO-" + status[0], status[1], "NS", "Testville")), "demo-214-" + control);
}
new OutboundWorker().runOnce();
while(new InboxWorker().runOnce() + new SendWorker().runOnce() > 0)
{
// Drain intake and delivery together; the in-memory gateway accepts every send.
}
}
/*******************************************************************************
** Replace the unit with a code outside the guide so the demo has a rejected 940.
*******************************************************************************/
private static List<com.kingsrook.qbits.edi.x12.X12Segment> invalidUnit(List<com.kingsrook.qbits.edi.x12.X12Segment> body)
{
return (body.stream().map(s -> s.id().equals("W01") ? LogisticsSupport.s("W01", s.value(1), "ZZ", "", s.value(4), s.value(5)) : s).toList());
}
/*******************************************************************************
** Persist a source record with its children and queue it for the outbound worker.
*******************************************************************************/
private static void enqueue(String table, QRecord source) throws Exception
{
QRecord saved = SystemWrites.transaction(() -> RetailSupport.saveSource(table, source));
OutboundEnqueue.enqueue(table, saved, "MANUAL", null);
}
/*******************************************************************************
** Attach a baseline guide and sample map as one agreement document.
*******************************************************************************/
private static void agreementDocument(QRecord agreement, String direction, String set, String mapKey, String table) throws Exception
{
QRecord map = LogisticsSupport.installMap(mapKey, "004010");
QRecord document = new QRecord().withValue("agreementId", agreement.getValue("id")).withValue("direction", direction).withValue("transactionSet", set).withValue("version", "004010")
.withValue("functionalIdCode", LogisticsSupport.groupCode(set)).withValue("guideId", map.getValue("guideId")).withValue("mapId", map.getValue("id")).withValue("isActive", true);
if(direction.equals("INBOUND"))
{
document.withValue("ackExpectation", "997").withValue("ackLevel", "ALL_TRANSACTIONS");
}
else
{
document.withValue("sourceTableName", table).withValue("outboundTrigger", "MANUAL").withValue("batchMode", "IMMEDIATE").withValue("ackExpectation", "997").withValue("ackDueMinutes", 1440);
}
SystemWrites.insert("edi_agreement_document", document);
}
/*******************************************************************************
** Synthetic change order retains a valid envelope and guide-compatible details.
*******************************************************************************/
@@ -86,7 +86,7 @@ class EdiDemoServerTest
demo.seed();
demo.seed();
assertThat(demo.defineQInstance().getHomeAppName()).isEqualTo("edi");
assertThat(SystemWrites.call(() -> EdiRecords.query("edi_partner", new QQueryFilter()))).hasSize(3);
assertThat(SystemWrites.call(() -> EdiRecords.query("edi_partner", new QQueryFilter()))).hasSize(4);
assertThat(SystemWrites.call(() -> EdiRecords.query("edi_certificate", new QQueryFilter()))).hasSize(2);
assertThat(SystemWrites.call(() -> EdiRecords.query("edi_inbox", new QQueryFilter()))).hasSizeGreaterThanOrEqualTo(40);
assertThat(SystemWrites.call(() -> EdiRecords.query("edi_transaction", new QQueryFilter()))).anyMatch(row -> "OUTBOUND".equals(row.getValueString("direction")));
@@ -94,8 +94,15 @@ class EdiDemoServerTest
assertThat(SystemWrites.call(() -> EdiRecords.query("edi_functional_group", new QQueryFilter()))).anyMatch(row -> row.getValueInstant("ackReceivedAt") != null);
assertThat(SystemWrites.call(() -> EdiRecords.query("edi_exception", new QQueryFilter()))).anyMatch(row -> "OVERDUE_ACK".equals(row.getValueString("type")));
var partners = SystemWrites.call(() -> EdiRecords.query("edi_partner", new QQueryFilter()));
assertThat(partners).extracting(row -> row.getValueString("code")).containsExactlyInAnyOrder("NORTHWIND", "HARBOR", "SUMMIT");
assertThat(partners).extracting(row -> row.getValueString("code")).containsExactlyInAnyOrder("NORTHWIND", "HARBOR", "SUMMIT", "RIDGELINE");
assertThat(partners).allSatisfy(row -> assertThat(row.getValueString("contactEmail")).endsWith("@example.invalid"));
assertThat(SystemWrites.call(() -> EdiRecords.query("sample_wms_order", new QQueryFilter()))).hasSize(3);
assertThat(SystemWrites.call(() -> EdiRecords.query("sample_shipment_status", new QQueryFilter()))).hasSize(3);
var transactions = SystemWrites.call(() -> EdiRecords.query("edi_transaction", new QQueryFilter()));
assertThat(transactions).anyMatch(row -> "945".equals(row.getValueString("transactionSet")) && "SENT".equals(row.getValueString("status")));
assertThat(transactions).anyMatch(row -> "204".equals(row.getValueString("transactionSet")) && "SENT".equals(row.getValueString("status")));
assertThat(transactions).anyMatch(row -> "940".equals(row.getValueString("transactionSet")) && "INVALID".equals(row.getValueString("status")));
assertThat(transactions).anyMatch(row -> "214".equals(row.getValueString("transactionSet")) && "INVALID".equals(row.getValueString("status")));
int port = demo.start(0);
assertThat(client.send(HttpRequest.newBuilder(URI.create("http://localhost:" + port + "/app/edi")).GET().build(), HttpResponse.BodyHandlers.ofString()).statusCode()).isEqualTo(200);
for(String table : java.util.List.of("edi_partner", "edi_transaction", "edi_exception"))