diff --git a/custom/knowledge/architecture/pages-must-not-contain-business-logic.md b/custom/knowledge/architecture/pages-must-not-contain-business-logic.md new file mode 100644 index 0000000..073a919 --- /dev/null +++ b/custom/knowledge/architecture/pages-must-not-contain-business-logic.md @@ -0,0 +1,65 @@ +--- +bc-version: [all] +domain: architecture +keywords: [page, trigger, onaction, modify, codeunit, logic] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +## Description + +In CURABIS codebases, pages are pure presentation. Business logic, calculations, +validations, and record modifications belong in codeunits — not in page triggers +or actions. This is stricter than the general BC guidance and applies to all +CURABIS PTE apps. + +A page procedure that calculates a value and assigns it to a field, calls +`Rec.Modify()` directly, or implements business rules is an architecture violation +even if it compiles. + +**Exceptions:** +- Setup pages may read and write their own setup record directly. +- The designated "Run Conversion" page may call the conversion codeunit directly. + +## Anti Pattern + +```al +// WRONG: calculation and Modify in a page action +trigger OnAction() +begin + Rec."Total Amount" := Rec.Quantity * Rec."Unit Price"; + Rec."VAT Amount" := Rec."Total Amount" * 0.25; + Rec.Modify(); +end; +``` + +```al +// WRONG: validation logic in page trigger +trigger OnValidate() +begin + if Rec.Quantity < 0 then + Error('Quantity cannot be negative'); + Rec."Total Amount" := Rec.Quantity * Rec."Unit Price"; +end; +``` + +## Best Practice + +```al +// CORRECT: page delegates to codeunit +trigger OnAction() +begin + SVManagement.RecalculateLine(Rec); +end; +``` + +```al +// CORRECT: validation belongs in table or codeunit +trigger OnValidate() +begin + SVManagement.ValidateAndRecalculate(Rec); +end; +``` + +The codeunit owns the logic. The page owns the presentation. diff --git a/custom/knowledge/testing/test-setup-must-use-library-codeunit.md b/custom/knowledge/testing/test-setup-must-use-library-codeunit.md new file mode 100644 index 0000000..722c8e9 --- /dev/null +++ b/custom/knowledge/testing/test-setup-must-use-library-codeunit.md @@ -0,0 +1,71 @@ +--- +bc-version: [all] +domain: testing +keywords: [test, library, setup, initialize, suppresscommit, asserterror] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +## Description + +In CURABIS test apps, all test setup is centralized in a dedicated Test Library +codeunit (e.g. `SV Test Library`). Individual test procedures must not call +BC standard library codeunits (`LibrarySales`, `LibraryInventory`, etc.) directly. + +Additionally, two rules apply to every test that calls a posting codeunit: + +1. `SetSuppressCommit(true)` must be called before `Run()` to prevent data + from leaking between tests. +2. `asserterror` must always be followed by `Assert.ExpectedErrorCode()` or + `Assert.ExpectedError()` — a naked `asserterror` passes on any error, + not just the expected one. + +## Anti Pattern + +```al +// WRONG: inline setup bypassing the test library +procedure MyTest() +var + Item: Record Item; +begin + LibraryInventory.CreateItem(Item); // do not call directly + // ... +end; +``` + +```al +// WRONG: posting without SuppressCommit +SVPost.Run(SVHeader); // commits to test database +``` + +```al +// WRONG: naked asserterror +asserterror SVPost.Run(SVHeader); +// no assertion follows — passes on any error +``` + +## Best Practice + +```al +// CORRECT: delegate to test library +procedure MyTest() +var + Item: Record Item; +begin + SVLib.GivenScrapItem(Item); // test library owns setup + // ... +end; +``` + +```al +// CORRECT: SuppressCommit before Run +SVPost.SetSuppressCommit(true); +SVPost.Run(SVHeader); +``` + +```al +// CORRECT: asserterror followed by assertion +asserterror SVPost.Run(SVHeader); +Assert.ExpectedErrorCode('Dialog'); +```