Import an Order from JSON
A webshop your company just signed pushes every confirmed order to Business Central as one JSON document. You are writing the import: a single call takes the raw document text and turns it into an order header with its lines — or refuses cleanly, without leaving half an order in the database.
The document
{
"orderNo": "SO-1042",
"orderDate": "2026-04-05",
"currencyCode": "EUR",
"customer": {
"name": "O'Brien & Sons",
"email": "orders@obrien.example"
},
"lines": [
{ "lineNo": 10000, "itemNo": "1896-S", "description": "Athens desk", "quantity": 2.5, "unitPrice": 149.9 },
{ "lineNo": 20000, "itemNo": "1900-S", "description": "Paris chair", "quantity": 1, "unitPrice": 96.4 }
]
}Facts about the feed:
orderDateis always ISO 8601 text (yyyy-mm-dd) — the import must store the correct date no matter which region settings the server runs with.quantityandunitPriceare JSON numbers;lineNois a JSON integer.- String values may carry JSON escapes — a customer may be named
O'Brien & \"Sons\"in the document — and must be stored decoded. currencyCode,customer.emailanddescriptionare optional; every other property shown above is required.- Values in the graded documents always fit the destination fields — there are no truncation rules to worry about.
Requirements
The starter ships two tables, "Web Order Header" and "Web Order Line" — keep them in your submission unchanged; the grading tests read them by name.
Create a codeunit named "Order Json Import" with one public procedure:
procedure ImportOrder(OrderJson: Text): Code[20]Header mapping:
orderNo→"Order No."orderDate→"Order Date"currencyCode→"Currency Code"customer.name→"Customer Name"customer.email→"Customer E-Mail"
Line mapping, one "Web Order Line" per element of lines (with "Order No." set to the header's):
lineNo→"Line No."itemNo→"Item No."description→Descriptionquantity→QuantityunitPrice→"Unit Price"
Rules:
- A valid document inserts exactly one
"Web Order Header"record plus one"Web Order Line"record per element oflines, and returns the imported"Order No.". - A missing optional property leaves its field blank; the import still succeeds.
- If the text is not valid JSON at all, fail with an error message that contains
invalid JSON(exact casing). - If a required property is missing, or its value cannot be converted to the destination type (an unparseable date, a quantity that is not a number), fail with an error message that contains that property's name exactly as it is spelled in the document. Every required property is graded this way:
orderNo,orderDate,customer,name(forcustomer.name),lineNo,itemNo,quantity,unitPrice. The message must name only the offending property: the tests also assert that none oforderNo,orderDate,quantity,itemNo,unitPriceappears in the message when a different property is at fault — so one catch-all message that lists every property fails. - If
linesis missing, not an array, or an empty array, fail with an error message that containslines. - The error must surface no matter how deep in the document the problem sits — a document whose second line is broken still fails naming the offending property. You do not need to clean up on failure (not graded): raising an error rolls back the open database transaction, so a failed import leaves nothing behind by itself.
What the tests check
The tests import a valid document and read back every mapped header and line field, including a customer name whose JSON escapes must arrive decoded; they store "orderDate": "2026-03-04" and expect 4 March 2026 — day and month must not swap; they import a three-line document and check each line's numbers exactly, plus a document generated from random values so constants can't pass; they omit the optional properties and expect blank fields. Then they feed broken documents — text that isn't JSON, one document per required property where it is missing (orderNo, orderDate, customer, customer.name, lineNo, itemNo, quantity, unitPrice), one per converted property where the value won't convert (a date of "sometime in spring", a quantity of "plenty", a unitPrice of "cheap", a lineNo of "first"), and a lines that is missing, a string, or an empty array — and expect errors with messages that contain invalid JSON (for the text that isn't JSON) or the offending property's name (substring match, exact casing), and none of the other property names listed in rule 4. Finally they feed a document whose second line carries the bad quantity and expect the same error naming quantity.