From 4f74b884d8ad0db1f76171cab21fbc707024c992 Mon Sep 17 00:00:00 2001 From: BeytullahCengiz88 Date: Thu, 16 Jul 2026 12:03:23 +0200 Subject: [PATCH] Refactor CMFRTAQFSResolveItemToGLAcc to pass IsHandled to DoCMFRTAQFSResolveItemToGLAcc and update documentation for clarity on event handling structure --- .../knowledge/events/cmfrt-onbefore-do-onafter.good.al | 10 ++++------ custom/knowledge/events/cmfrt-onbefore-do-onafter.md | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/custom/knowledge/events/cmfrt-onbefore-do-onafter.good.al b/custom/knowledge/events/cmfrt-onbefore-do-onafter.good.al index 209ef0c..523cdc7 100644 --- a/custom/knowledge/events/cmfrt-onbefore-do-onafter.good.al +++ b/custom/knowledge/events/cmfrt-onbefore-do-onafter.good.al @@ -6,20 +6,18 @@ codeunit 55043 "CMFRT AQ FS ProForma Meth" begin IsHandled := false; OnBeforeCMFRTAQFSResolveItemToGLAcc(SalesLine, IsHandled); - if IsHandled then - exit; - - DoCMFRTAQFSResolveItemToGLAcc(SalesLine); - + DoCMFRTAQFSResolveItemToGLAcc(SalesLine, IsHandled); OnAfterCMFRTAQFSResolveItemToGLAcc(SalesLine); end; - local procedure DoCMFRTAQFSResolveItemToGLAcc(var SalesLine: Record "Sales Line") + local procedure DoCMFRTAQFSResolveItemToGLAcc(var SalesLine: Record "Sales Line"; IsHandled: Boolean) var Item: Record Item; GeneralPostingSetup: Record "General Posting Setup"; ItemNotFoundErr: Label 'Item %1 was not found.', Comment = '%1 = Item No.'; begin + if IsHandled then + exit; Item.SetLoadFields("No.", "Gen. Prod. Posting Group", Description); if not Item.Get(SalesLine."CMFRT AQ FS Item No.") then Error(ItemNotFoundErr, SalesLine."CMFRT AQ FS Item No."); diff --git a/custom/knowledge/events/cmfrt-onbefore-do-onafter.md b/custom/knowledge/events/cmfrt-onbefore-do-onafter.md index 004e945..0953fb8 100644 --- a/custom/knowledge/events/cmfrt-onbefore-do-onafter.md +++ b/custom/knowledge/events/cmfrt-onbefore-do-onafter.md @@ -11,16 +11,16 @@ application-area: [all] ## Description -Global procedures in CMFRT Meth codeunits are thin shells: the body consists of firing `OnBefore` with `var IsHandled: Boolean`, exiting if handled, calling a local `Do` procedure that holds all business logic, and firing `OnAfter`. Local variables that only serve the business logic (record buffers, labels, working values) live in the `Do` procedure, not in the shell. This keeps the event bracket structurally impossible to bypass — the `OnAfter` event cannot be skipped by an early `exit` inside business logic, because business logic lives one level down. +Global procedures in CMFRT Meth codeunits are thin shells: the body consists of firing `OnBefore` with `var IsHandled: Boolean`, calling a local `Do` procedure that holds all business logic and the `if IsHandled then exit;` guard, and firing `OnAfter`. Local variables that only serve the business logic (record buffers, labels, working values) live in the `Do` procedure, not in the shell. This keeps the event bracket structurally impossible to bypass — the `OnAfter` event cannot be skipped by an early `exit` inside business logic, because business logic and handled exits live one level down. ## Best Practice -Write every global Meth procedure as: reset `IsHandled`, fire `OnBefore`, `if IsHandled then exit;`, call `Do(...)`, fire `OnAfter`. When review finds a global procedure whose body mixes event calls with business logic, extract the logic into `Do` and move its private variables and labels along with it. +Write every global Meth procedure as: reset `IsHandled`, fire `OnBefore`, call `Do(..., IsHandled)`, fire `OnAfter`. In `Do`, place `if IsHandled then exit;` as the first executable statement, then execute business logic. When review finds a global procedure whose body mixes event calls with business logic, extract the logic into `Do` and move its private variables and labels along with it. See sample: `cmfrt-onbefore-do-onafter.good.al`. ## Anti Pattern -A global procedure whose business logic sits inline between the `OnBefore` and `OnAfter` calls. Inline bodies grow early `exit` paths that silently skip the `OnAfter` event, and their local variables and labels accumulate at the shell level where every branch can touch them. Equally wrong: declaring the event pair but never calling the events from the procedure (dead events), which advertises an extension point that never fires. +A global procedure that keeps `if IsHandled then exit;` and business logic inline between the `OnBefore` and `OnAfter` calls. Inline bodies grow early `exit` paths that silently skip the `OnAfter` event, and their local variables and labels accumulate at the shell level where every branch can touch them. Equally wrong: declaring the event pair but never calling the events from the procedure (dead events), which advertises an extension point that never fires. See sample: `cmfrt-onbefore-do-onafter.bad.al`.