Docs / Optional Verification / Partial Fulfillment
One order, two shipments, and a backorder that must be fulfilled
The retailer orders 10 units of ITEM-A at $12.50 and 10 of ITEM-B at $25.00. The supplier initially backorders B, then ships it in two installments. The scenario checks that each item is eventually shipped and invoiced in the right quantity—not just that the grand totals agree.
This is an optional verification layer. It reuses the full-shipment example's PO, ASN, and invoice maps, with a different 855 map and conversation definition. Your application still decides when to ship and invoice; the scenario neither reserves inventory nor sends documents.
Follow the remaining quantity
- 850: order A × 10 and B × 10.The merchandise total is $375.00.
- 855: accept A; backorder B.BAK02
ACdenotes an acknowledgment with detail/change. The sample uses line ACK01IAfor A andIBfor B, with each ACK quantity covering its entire PO line. Backordering B does not cancel or reduce its ordered quantity. - First 856 and 810: ship A × 10 and B × 4.The invoice is $225.00. B × 6 remains outstanding. The run stays pending; you do not need to know how many more shipments will follow.
- Second 856 and 810: ship B × 6.The second invoice is $150.00. Quantities now match, but matching totals alone do not mean that document collection is finished.
- Declare that no more ASNs or invoices are expected.Close both steps in the run view or through the API. The scenario checks the final per-item quantities, prices, references, and deadlines. Closing while B × 6 is still outstanding fails; it does not forgive the backorder.
The 855 must arrive within 2 days of the order, both ASNs within 14 days, and each invoice within 2 days of its ASN. Every invoice must name its ASN and contain exactly its item/unit quantities. Shipment and invoice identifiers must be unique. After the fulfillment window expires, call Advance to reevaluate a missing remainder: it fails rather than remaining pending. This is an explicit clock evaluation, not a background shipment monitor.
The detailed 855 is required in this example. Use the full-shipment variant when you need an optional, header-only acknowledgment instead. Codes and required dates vary by partner: the D&H 855 guide illustrates line acceptance and backorder codes, but this synthetic example is not a D&H compliance profile.
Use the tested files together
- Scenario definition and Test-traffic binding with Mapper expressions.
- 850 map, saved case, and sample 850.
- Detailed 855 map, saved case, and sample 855.
- Reusable 856 map, two saved cases, first ASN, and remainder ASN.
- Reusable 810 map, two saved cases, first invoice, and remainder invoice.
- Fixture index and passing, pending, and failing conversation cases. These are offline test inputs, not API requests or live evidence.
Start in Mapper
- Adapt and test the four maps.Follow the supplier setup workflow, using the detailed 855 above. Outgoing saved cases validate generated 004010 X12. Review your partner's guide before deploying maps or sending traffic.
- Create the conversation.Choose New scenario definition → Partial shipments and backorders. Validate and publish the editable draft with its fresh identity. If copying JSON instead, replace the reserved
modernedi.examplesnamespace. - Reuse the binding form.For this unchanged example, the form defaults to the supplier workspace actor and Test traffic. Choose the retailer partner and four current maps, then use Fill empty facts from example for each step with a resolved 004010 syntax context. Review the expressions; existing values are preserved. A changed graph needs manually adapted expressions. Partner
42and mapping IDs101–104in the download are placeholders and are never copied by the shortcut. Let the form select your published identity and hash. - Start without an expected shipment count.This definition has no run parameters. It permits up to three ASNs and three invoices, with
"closure": {"kind": "explicit"}on both steps. Three is a safety limit, not an expected count. To support more, edit both occurrence maxima and revalidate the definition's runtime capacity. - Attach actual persisted transactions.Attach the 850, detailed 855, and each 856/810 pair to their corresponding steps. The first pair leaves the run pending. Fresh transactions must meet the binding's frozen-configuration and Test-traffic eligibility checks. Test and Production share deployed maps; they are not separate map deployments.
- Finish collecting each repeated step.When your application or operator knows fulfillment is complete, use the run view's No more documents controls for the ASN and invoice steps. The confirmation is irreversible. The server records who closed the step, when, and with how many documents; every existing check still applies.
The offline fixture does not require mapping-success, MDN, or 997/999 evidence. Its saved cases prove local mapping behavior, not partner delivery. Add those evidence requirements to your definition when needed, and use the ordinary authorized send workflow for live exchanges.
Automate the same completion decision
With scenario-runs:write, call POST /v1/scenario-runs/{runId}/advance using the current If-Match ETag and an Idempotency-Key:
{ "closeSteps": ["advanceShipNotice", "invoice"] }
Only steps marked closable: true in the current run can close. One request records both decisions atomically. Retrying the same request with the same key replays its result. This action sends no EDI and needs no messages:write scope. An empty {} still performs ordinary Advance; it never implicitly closes a step.
Closure declares finality; it is not a successful test result or a business message inferred from the 855 or ASN. A short shipment, missing invoice, or failed check can still fail the run. You can refresh an already attached transaction's pending MDN, acknowledgment, or mapping evidence while the run remains active, but cannot attach a new document to a closed step. Use a new run if more documents must be included. If a deadline has already failed, ordinary Advance records that failure; late closure cannot bypass it.
Why a grand total is not enough
Shipping A × 11 and B × 9 still adds up to 20 units, but is not the ordered fulfillment. A keyed_sum_equal assertion compares totals separately for every item/unit key:
{
"id": "shippedQuantitiesByItem",
"operator": "keyed_sum_equal",
"left": { "kind": "keyed_facts", "stepId": "purchaseOrder",
"keyFact": "lineKeys", "fact": "quantities" },
"right": { "kind": "keyed_facts", "stepId": "advanceShipNotice",
"keyFact": "lineKeys", "fact": "quantities" }
}
Mapper extracts two aligned lists from each document: string keys and decimal quantities. The interpreter adds quantities by key across effective occurrences, then compares both the key sets and their totals. The same key can recur in later shipments. Lists of different lengths, blank keys, or duplicate keys within one document fail. Include the unit in the key—this example uses a JSON-encoded item/unit pair—so cases and eaches cannot silently mix.
keyed_equal uses the same inputs for a different purpose: the decimal value must remain consistent for each key, within and across both streams. Here it ensures that every invoice uses the order's unit price. Numeric spellings such as 12.5 and 12.50 agree. Both operators wait for both occurrence streams to close before passing and retain evidence for the keys as well as the amounts.
The ordinary per-document checks still matter: positive quantities, valid item qualifiers, USD currency, valid acknowledgment codes, rounded line totals, and TDS cents conversion. Cross-document totals complement those checks; they do not replace them. The existing Mapper language performs extraction and arithmetic, not a second scenario scripting language.
Keep the boundaries explicit
- Unknown count, explicit finality, one invoice per shipment. Your operator or application decides when no more documents are expected; the scenario does not infer a final shipment. Consolidated invoices, substitutions, order changes, cancellations, and permanently unfilled backorders require different rules. This example does not implement an inventory or backorder-management system.
- One ACK and one item/unit row per order line. Multiple ACK dispositions for part of the same line, repeated item/unit lines, and promised delivery dates are not modeled. The example checks its stated fulfillment window, not partner-specific promised dates.
- Simple USD merchandise. No tax, freight, discounts, allowances, packing hierarchy, or unit conversion is reconciled. Adapt identifier positions and other requirements to your partner guide.
- Verification, not certification. A pass covers these named checks, not every segment or external ERP/warehouse side effect. Keyed operators are conversation assertions, not branch predicates or transition correlations.
The maintained cases exercise the actual maps, X12 extraction, and interpreter: completion in one or two shipments, matching quantities without closure, early closure with an outstanding backorder, wrong item allocations, under/over-shipment, unknown items or units, changed prices, wrong shipment references, duplicate identifiers, incorrect totals, rejected line dispositions, and late or missing shipments.
Keep the extension with its maps
Use the existing workspace export or Git connection after reviewing the maps, saved mapping cases, definition, and binding. These downloads are not a complete workspace replacement bundle. Export creates portable partner/map references; do not commit the placeholder numeric IDs as your live configuration.
The binding includes four saved conversation tests: complete split fulfillment, an open backorder, out-of-order attachment, and early closure with missing quantities. Configuration verification runs these with the saved mapping cases before apply. Use a separate fresh run against the applied binding to verify live traffic, or automate that lifecycle through the Scenario Integration API. Earlier evidence remains tied to its original configuration.