0066

Two Moments in One Validation

table-extension
validate
trigger-order
sales-line

Two Moments in One Validation

The warehouse prints pick labels straight off the sales line, always in upper case, and the sales desk keeps swapping the item on a line until the customer is happy. After every swap two things must be true: the line carries a pick label for the item that is on it now, and it still remembers the description of the item it just replaced, so support can reconstruct what the clerk did.

Validating "No." on a sales line is not a quiet moment. Table 37 runs its own validation code in the middle of yours: it pulls the new item's values onto the line — the description among them — and resets line fields on the way, yours included. What your code sees, and whether what it writes survives, depends entirely on where in that sequence it runs. This is the task behind the oldest complaint in extension development: "my value gets overwritten by the base app".

Requirements

  1. Create a table extension for the "Sales Line" table with a field named "Pick Label" of type Text[100] and a field named "Previous Description" of type Text[100].
  2. Every time "No." is validated on a sales line, both fields must be up to date by the time that validation returns:
    • "Pick Label" — the line's Description as the finished validation left it, converted to upper case, character for character.
    • "Previous Description" — the Description the line carried immediately before that same validation started (blank if it carried none).
  3. That holds for every validation of "No.", including a second one performed before the line is saved: the two fields always describe the change that just happened, never the state stored in the database.
  4. Nothing else may touch either field. Validating another field on the line, or assigning "No." directly (SalesLine."No." := ...) without validating, must leave both fields exactly as they were.
  5. Do not modify base objects — extend them from the outside. Object names are yours to choose; only the two field names are graded.

Pick all object and field IDs in the range 50100–50199, and reference other objects by name, never by ID. No page extensions are needed — grading reads and writes the fields in code. Captions are good practice but not graded.

What the tests check

The tests build real sales orders with the standard libraries, using items whose descriptions are generated lowercase text, so a label that just copies the description — or a hardcoded one — fails. Putting an item on a new line must stamp "Pick Label" with that description in upper case and leave "Previous Description" blank, since that line replaced nothing; re-validating "No." to a second item must restamp the label, and must leave "Previous Description" holding the first item's description, read back from the database after the line is saved. One test re-validates "No." twice without saving in between and asserts "Previous Description" holds the description the line carried a moment earlier, not the one on disk. Two further tests assert that validating an unrelated field on the line, and assigning "No." without validating, leave both fields untouched. A last test checks that both fields are declared as Text with a maximum length of exactly 100. Except where a test says otherwise, the fields are read straight off the record in memory right after the validation, so the values must be there when it returns — there is no separate save step to fix them up in.

Learn More

Hint 1
Both fields are maintained during one and the same event — a Validate of "No." — but not at the same instant in it. Ask what the line looks like at each point: before table 37's own code runs, Description still belongs to the item that is leaving; after it has run, the description belongs to the item that arrived, and the line's other fields were reset on the way.
Hint 2
An extension can attach code to a base field's validation on either side of that base code: a table extension can modify("No.") and give it OnBeforeValidate and OnAfterValidate triggers, and the same two moments are also published as the table's OnBeforeValidateEvent and OnAfterValidateEvent, whose ElementName is the field name. Whatever you write in the earlier moment is gone by the time the later one runs.
Hint 3
You need both moments: read the old description in the earlier one, write both fields in the later one. Because the record itself is re-initialized in between, the description you captured has to wait somewhere that reset cannot reach — a global variable on the table extension, or a single-instance codeunit if you take the subscriber route.
ALBusiness Central 28.5
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.