0202

The Words That Follow the Item

Basics
Medium
extended-text
sales-line
run-trigger

The Words That Follow the Item

Sales maintains extended text on the item cards — safety notes, "assembly required", a legal blurb in the customer's language — and expects those lines under every order line, whether a person types the order or the integration drops it in overnight. Today the integration's lines arrive bare. Your job is a small order-line builder whose lines look exactly like the ones a user gets with the Insert Ext. Text action: the item line, and right behind it the words that belong to it. Business Central already knows which text belongs where; the trick is to ask it.

Requirements

Create a codeunit named "Order Line Builder" with two public procedures:

procedure AddItemLineWithText(var SalesHeader: Record "Sales Header"; ItemNo: Code[20]; Quantity: Decimal): Integer
procedure RemoveItemLine(var SalesHeader: Record "Sales Header"; LineNo: Integer)

Rules:

  1. AddItemLineWithText appends a line of type Item for ItemNo with Quantity to the sales order SalesHeader, stores it, and returns its "Line No.". Validate Type, "No." and Quantity the way the order page would, so the line picks up the item's description and price (not graded — the tests look at the line's type, item and quantity). Number the item line above every line already in the order — 10000 for an empty order and 10000 above the last line afterwards is the convention; only the ordering is graded.
  2. Right behind the item line come the item's extended text lines, exactly as the Insert Ext. Text action places them: one sales line per Extended Text Line, of blank type, with no "No." and zero quantity, its Description carrying the text, its "Attached to Line No." set to the item line's "Line No.", and numbered so that the text lines sit after their item line, in the order of the text lines, and before whatever item line is added next.
  3. Which text applies follows the standard rules, and codeunit "Transfer Extended Text" (378) already implements every one of them. An Extended Text Header of the item counts only if its "Sales Order" toggle is on; only if the order's "Document Date" lies inside its "Starting Date"–"Ending Date" window (a blank date is open-ended, and the boundary dates themselves count); and only if it fits the order's "Language Code", which the order header copies from the customer: a header in exactly that language wins, a header without a language and with "All Language Codes" on serves a customer whose language has no text of its own, and a customer without a language gets the headers without a language and nothing else.
  4. The item card's "Automatic Ext. Texts" toggle plays no part: the integration inserts the text for every item that has any, whatever the card says. The codeunit works in two steps — SalesCheckIfAnyExtText checks the stored line and collects the applicable text (its second parameter, true, is what makes it look regardless of the item toggle), and InsertSalesExtText writes what was collected. The second step has nothing to write unless the first one ran and returned true.
  5. An item that has no applicable text gets a bare item line: no blank lines under it.
  6. RemoveItemLine deletes item line LineNo from the order together with every line attached to it, and leaves the other lines and their text alone. The sales line's own OnDelete trigger already takes the attached lines along — but only when the delete runs it.

SalesHeader is always a stored, open sales order (document type Order), ItemNo an existing item, and LineNo the "Line No." of an item line the builder created. Nothing has to be released, shipped or posted. Pick object IDs in the range 50100–50199, and reference other objects by name, never by ID.

What the tests check

The grading tests create customers, items and sales orders with the standard libraries and seed the Extended Text Header and Extended Text Line records by hand, with generated texts, so a hardcoded description fails. They call AddItemLineWithText, read the item line back by the returned "Line No." and assert its type, item and quantity; that an item without extended text leaves the order with exactly one line; that a three-line text gives exactly three lines attached to the item line through "Attached to Line No.", numbered after it, with the texts in Description in the order of the text lines; and that those lines are of blank type, with no "No." and zero quantity. The items in those tests have "Automatic Ext. Texts" switched on; one further test switches it off and still expects the text. Negative tests seed a header with "Sales Order" unticked, one whose "Ending Date" is the day before the order's "Document Date", one whose "Starting Date" is the day after, and one without a language and with "All Language Codes" unticked for a customer who has a language — each expecting no attached lines — while two boundary tests put "Ending Date" and "Starting Date" exactly on the "Document Date" and expect the text. The language tests give an item a language-neutral text and a text in a generated language, and expect exactly the language text for a customer with that language, exactly the neutral text for a customer without a language, and the neutral text again for a customer whose own language has no text. One test adds two items with text and checks that the second item line is numbered after all of the first line's text and gets its own text behind it. The last test removes the first of two item lines and expects it and its text lines gone while the second line and its text stay.

Learn More

Hint 1
The Insert Ext. Text action on the order page does not work out which text applies by itself — it hands the line to codeunit "Transfer Extended Text" (378). That codeunit offers two procedures for sales lines: one that checks whether any text applies and collects it, and one that inserts what was collected. The second does nothing unless the first ran and said yes.
Hint 2
The check wants a stored line: it reads the line's Document No. and Line No. to find the order (language, document date) and to number and attach the text lines. Pass true as its second parameter — that is what tells it to ignore the item card's Automatic Ext. Texts toggle — and call the insert procedure with the same line only when the check returns true.
Hint 3
Delete() and Delete(true) differ in exactly one thing: whether the sales line's OnDelete trigger runs. The cascade to the lines carrying the item line's Line No. in "Attached to Line No." lives in that trigger — so Get the item line, delete it with the trigger, and leave the text lines to it.
ALBusiness Central 28.4
Press Compile to check your code compiles — Submit runs the tests.
The code editor is desktop-only
Open this problem on a computer to write and run code. Reading the description, tests and discussion works fine here.