-
Notifications
You must be signed in to change notification settings - Fork 687
Description
Why do you need this change?
Why do you need this change?
Further extensibility for CheckItemAnalysisViewDim as per enum request
#29601
Currently, the Item Analysis View framework in Business Central supports only three Item Analysis dimensions (ItemAnalysis1ΓÇô3). However, several Operating Companies rely on extended analytical classification for:
ΓÇó Financial analysis
ΓÇó Operational consumption reporting
ΓÇó Purchase and inventory performance extraction
To meet these reporting obligations, Client requires two additional Item Analysis dimensions ΓÇö ItemAnalysis4 and ItemAnalysis5. These dimensions are already part of the business model and are actively used across Operating Companies for material grouping and management-level analytics.
Alternatives Evaluation
We have evaluated the following existing events:
OnBeforeCheckIfDimUsed: This event is at CheckIfDimUsed procedure but does give flexibility to add additional Dimensions to check CheckItemAnalysisViewDim which is limited to 3 dimensions which is needed to further extend to 5 Dimensions.
Code is starting from Line 290 to 301.
another block of code starting from 397 to 417 Line.
These blocks of Code needs to be extracted to further procedure and aligned with OnBefore and OnAfter Events
IsHandled Justification:
While we're using a GetVendor Boolean parameter rather than IsHandled, the pattern serves a similar purpose and requires justification. The GetVendor parameter is necessary because:
Error Prevention: IsHandled false will keep process as normal execution, only will give flexibility to enhance financial reporting
Performance Optimization:Better handling over code execution and additional dimensions intergration.
Business Logic Requirements:The requested enhancement is required to support critical financial reporting, Item Analysis View enrichment, and data extraction processes used by multiple Heineken Operating Companies.
A standard integration event (without the ability to control execution) would not work because:
We cannot fully skip execution and add dimension to in already check part even after it is extended to enum.
Error handling after the fact is insufficient for user experience requirements
We need to update variable with additional dimensions to work with.
Microsoft Idea Proposal Document-348 Sent to Avnish (1).docx
Performance Considerations
Performance Impact: The addition of the event call adds minimal overhead (< 1ms) as it's a simple Boolean evaluation and event invocation. as we are simply adding a boolean check and then assigning value to code for runtime evaluation which will help with financial reporting to be correct
Timing-Critical Scenarios: This procedure is not in a posting or batch processing critical path. It's primarily used by user to run and is operated out of business hours
Expected Impact: Positive to get financial reporting correct and structured execution handle events for change
Data Sensitivity Review
The data exposed through this event includes:
Shortcut Dimension is being evaluated: which are required for financial reporting. which is Customer Content data
Safeguards: This event follows the safe structured model for event extensibility by keeping flow structured. No additional sensitive data exposure occurs beyond what's already available through standard table access.
Multi-Extension Interaction
The risk of conflicts is relatively low:
IsHandled false will allow standard behaviour to execute
IsHandled true will help to modify execution expected for reporting.
OnBefore will allow flexibility to correct financial reporting
OnAfter will help with adding additional check
Describe the request
Current Code Microsoft
Suugested update:
Extract it to new Procedure
From :
CheckAllDim := DimTypeChecked in [DimTypeChecked::" "];
CheckGlobalDim := DimTypeChecked in [DimTypeChecked::Global1, DimTypeChecked::Global2];
CheckShortcutDim := DimTypeChecked in [DimTypeChecked::Shortcut3, DimTypeChecked::Shortcut4, DimTypeChecked::Shortcut5,
DimTypeChecked::Shortcut6, DimTypeChecked::Shortcut7, DimTypeChecked::Shortcut8];
CheckBudgetDim := DimTypeChecked in [DimTypeChecked::Budget1, DimTypeChecked::Budget2, DimTypeChecked::Budget3,
DimTypeChecked::Budget4];
CheckAnalysisViewDim := DimTypeChecked in [DimTypeChecked::Analysis1, DimTypeChecked::Analysis2, DimTypeChecked::Analysis3,
DimTypeChecked::Analysis4];
CheckItemBudgetDim :=
DimTypeChecked in [DimTypeChecked::ItemBudget1, DimTypeChecked::ItemBudget2, DimTypeChecked::ItemBudget3];
CheckItemAnalysisViewDim :=
DimTypeChecked in [DimTypeChecked::ItemAnalysis1, DimTypeChecked::ItemAnalysis2, DimTypeChecked::ItemAnalysis3];
To
CheckAllDimesions(DimTypeChecked, CheckAllDim, CheckGlobalDim, CheckShortcutDim, CheckBudgetDim, CheckAnalysisViewDim, CheckItemBudgetDim, CheckItemAnalysisViewDim, UsedAsCustomDim, CustomDimErr);
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckAllDimesions(var DimTypeChecked: Enum DimTypeChecked; var CheckAllDim: Boolean; var CheckGlobalDim: Boolean; var CheckShortcutDim: Boolean; var CheckBudgetDim: Boolean; var CheckAnalysisViewDim: Boolean; var CheckItemBudgetDim: Boolean; var CheckItemAnalysisViewDim: Boolean; var UsedAsCustomDim: Boolean; var CustomDimErr: Text;var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCheckAllDimesions(var DimTypeChecked: Enum DimTypeChecked; var CheckAllDim: Boolean; var CheckGlobalDim: Boolean; var CheckShortcutDim: Boolean; var CheckBudgetDim: Boolean; var CheckAnalysisViewDim: Boolean; var CheckItemBudgetDim: Boolean; var CheckItemAnalysisViewDim: Boolean; var UsedAsCustomDim: Boolean; var CustomDimErr: Text)
begin
end;
local procedure CheckAllDimesions(var DimTypeChecked: Enum DimTypeChecked; var CheckAllDim: Boolean; var CheckGlobalDim: Boolean; var CheckShortcutDim: Boolean; var CheckBudgetDim: Boolean; var CheckAnalysisViewDim: Boolean; var CheckItemBudgetDim: Boolean; var CheckItemAnalysisViewDim: Boolean;var UsedAsCustomDim: Boolean; var CustomDimErr: Text)
var
IsHandled: Boolean;
begin
OnBeforeCheckAllDimesions(DimTypeChecked, CheckAllDim, CheckGlobalDim, CheckShortcutDim, CheckBudgetDim, CheckAnalysisViewDim, CheckItemBudgetDim, CheckItemAnalysisViewDim, UsedAsCustomDim,CustomDimErr,IsHandled);
if IsHandled then
exit;
CheckAllDim := DimTypeChecked in [DimTypeChecked::" "];
CheckGlobalDim := DimTypeChecked in [DimTypeChecked::Global1, DimTypeChecked::Global2];
CheckShortcutDim := DimTypeChecked in [DimTypeChecked::Shortcut3, DimTypeChecked::Shortcut4, DimTypeChecked::Shortcut5,
DimTypeChecked::Shortcut6, DimTypeChecked::Shortcut7, DimTypeChecked::Shortcut8];
CheckBudgetDim := DimTypeChecked in [DimTypeChecked::Budget1, DimTypeChecked::Budget2, DimTypeChecked::Budget3,
DimTypeChecked::Budget4];
CheckAnalysisViewDim := DimTypeChecked in [DimTypeChecked::Analysis1, DimTypeChecked::Analysis2, DimTypeChecked::Analysis3,
DimTypeChecked::Analysis4];
CheckItemBudgetDim :=
DimTypeChecked in [DimTypeChecked::ItemBudget1, DimTypeChecked::ItemBudget2, DimTypeChecked::ItemBudget3];
CheckItemAnalysisViewDim :=
DimTypeChecked in [DimTypeChecked::ItemAnalysis1, DimTypeChecked::ItemAnalysis2, DimTypeChecked::ItemAnalysis3];
OnAfterCheckAllDimesions(DimTypeChecked, CheckAllDim, CheckGlobalDim, CheckShortcutDim, CheckBudgetDim, CheckAnalysisViewDim, CheckItemBudgetDim, CheckItemAnalysisViewDim, UsedAsCustomDim, CustomDimErr);
end;
Part 2: Microsoft implementation:
Extract it to new Procedure
Line 397 to 417
CheckIfDimUsedAsItemAnalysisViewDim(ItemAnalysisView,DimChecked, DimTypeChecked, AnalysisViewChecked, AnalysisAreaChecked, CheckAllDim, CheckItemAnalysisViewDim, UsedAsCustomDim, CustomDimErr);//NewProcedure
local procedure CheckIfDimUsedAsItemAnalysisViewDim(ItemAnalysisView: Record "Item Analysis View";
DimChecked: Code[20];
DimTypeChecked: Enum "DimTypeChecked";
AnalysisViewChecked: Code[10];
AnalysisAreaChecked: Integer;
CheckAllDim: Boolean;
CheckItemAnalysisViewDim: Boolean; var UsedAsCustomDim: Boolean; var CustomDimErr: Text)
var
IsHandled: Boolean;
begin
// OnBefore: subscriber can modify before main logic
OnBeforeCheckIfDimUsedAsItemAnalysisViewDim(ItemAnalysisView,
DimChecked,
DimTypeChecked,
AnalysisViewChecked,
AnalysisAreaChecked,
CheckAllDim,
CheckItemAnalysisViewDim,
UsedAsItemAnalysisViewDim, UsedAsCustomDim, CustomDimErr,
IsHandled);
if IsHandled then
exit;
// Main logic
if CheckAllDim or CheckItemAnalysisViewDim then begin
if AnalysisViewChecked <> '' then begin
ItemAnalysisView.SetRange("Analysis Area", AnalysisAreaChecked);
ItemAnalysisView.SetRange(Code, AnalysisViewChecked);
end;
if ItemAnalysisView.FindSet() then
repeat
if (DimTypeChecked <> DimTypeChecked::ItemAnalysis1) and
(DimChecked = ItemAnalysisView."Dimension 1 Code")
then
UsedAsItemAnalysisViewDim := true;
if (DimTypeChecked <> DimTypeChecked::ItemAnalysis2) and
(DimChecked = ItemAnalysisView."Dimension 2 Code")
then
UsedAsItemAnalysisViewDim := true;
if (DimTypeChecked <> DimTypeChecked::ItemAnalysis3) and
(DimChecked = ItemAnalysisView."Dimension 3 Code")
then
UsedAsItemAnalysisViewDim := true;
until ItemAnalysisView.Next() = 0;
end;
// OnAfter: pass LOCAL variable by reference
OnAfterCheckIfDimUsedAsItemAnalysisViewDim(ItemAnalysisView,
DimChecked,
DimTypeChecked,
AnalysisViewChecked,
AnalysisAreaChecked,
CheckAllDim,
CheckItemAnalysisViewDim,
UsedAsItemAnalysisViewDim, UsedAsCustomDim, CustomDimErr);
end;
Integrationevent
local procedure OnBeforeCheckIfDimUsedAsItemAnalysisViewDim(ItemAnalysisView: Record "Item Analysis View";var DimChecked: Code[20]; var DimTypeChecked: Enum DimTypeChecked; var AnalysisViewChecked: Code[10]; var AnalysisAreaChecked: Integer; var CheckAllDim: Boolean; var CheckItemAnalysisViewDim: Boolean; var UsedAsItemAnalysisViewDim: Boolean; var UsedAsCustomDim: Boolean; var CustomDimErr: Text; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCheckIfDimUsedAsItemAnalysisViewDim(var ItemAnalysisView: Record "Item Analysis View";var DimChecked: Code[20]; var DimTypeChecked: Enum DimTypeChecked; var AnalysisViewChecked: Code[10]; var AnalysisAreaChecked: Integer; var CheckAllDim: Boolean; var CheckItemAnalysisViewDim: Boolean; var UsedAsItemAnalysisViewDim: Boolean; var UsedAsCustomDim: Boolean; var CustomDimErr: Text)
begin
end;
New CheckIfDimUsed() will be like
procedure CheckIfDimUsed(DimChecked: Code[20]; DimTypeChecked: Enum DimTypeChecked; BudgetNameChecked: Code[10]; AnalysisViewChecked: Code[10]; AnalysisAreaChecked: Integer): Boolean
var
GLSetup: Record "General Ledger Setup";
GLBudgetName: Record "G/L Budget Name";
AnalysisView: Record "Analysis View";
ItemBudgetName: Record "Item Budget Name";
ItemAnalysisView: Record "Item Analysis View";
CustomDimErr: Text;
CheckAllDim: Boolean;
CheckGlobalDim: Boolean;
CheckShortcutDim: Boolean;
CheckBudgetDim: Boolean;
CheckAnalysisViewDim: Boolean;
CheckItemBudgetDim: Boolean;
CheckItemAnalysisViewDim: Boolean;
UsedAsCustomDim: Boolean;
begin
if DimChecked = '' then
exit;
OnBeforeCheckIfDimUsed(DimChecked, DimTypeChecked, UsedAsCustomDim, CustomDimErr, AnalysisViewChecked, AnalysisAreaChecked);
CheckAllDimesions(DimTypeChecked, CheckAllDim, CheckGlobalDim, CheckShortcutDim, CheckBudgetDim, CheckAnalysisViewDim, CheckItemBudgetDim, CheckItemAnalysisViewDim, UsedAsCustomDim, CustomDimErr);//New Procedure
UsedAsGlobalDim := false;
UsedAsShortcutDim := false;
UsedAsBudgetDim := false;
UsedAsAnalysisViewDim := false;
UsedAsItemBudgetDim := false;
UsedAsItemAnalysisViewDim := false;
if CheckAllDim or CheckGlobalDim or CheckShortcutDim or CheckBudgetDim or CheckItemBudgetDim then begin
GLSetup.Get();
if (DimTypeChecked <> DimTypeChecked::Global1) and
(DimChecked = GLSetup."Global Dimension 1 Code")
then
UsedAsGlobalDim := true;
if (DimTypeChecked <> DimTypeChecked::Global2) and
(DimChecked = GLSetup."Global Dimension 2 Code")
then
UsedAsGlobalDim := true;
end;
if CheckGlobalDim or CheckShortcutDim then begin
if (DimTypeChecked <> DimTypeChecked::Shortcut3) and
(DimChecked = GLSetup."Shortcut Dimension 3 Code")
then
UsedAsShortcutDim := true;
if (DimTypeChecked <> DimTypeChecked::Shortcut4) and
(DimChecked = GLSetup."Shortcut Dimension 4 Code")
then
UsedAsShortcutDim := true;
if (DimTypeChecked <> DimTypeChecked::Shortcut5) and
(DimChecked = GLSetup."Shortcut Dimension 5 Code")
then
UsedAsShortcutDim := true;
if (DimTypeChecked <> DimTypeChecked::Shortcut6) and
(DimChecked = GLSetup."Shortcut Dimension 6 Code")
then
UsedAsShortcutDim := true;
if (DimTypeChecked <> DimTypeChecked::Shortcut7) and
(DimChecked = GLSetup."Shortcut Dimension 7 Code")
then
UsedAsShortcutDim := true;
if (DimTypeChecked <> DimTypeChecked::Shortcut8) and
(DimChecked = GLSetup."Shortcut Dimension 8 Code")
then
UsedAsShortcutDim := true;
end;
if CheckAllDim or CheckGlobalDim or CheckBudgetDim then begin
if BudgetNameChecked <> '' then
GLBudgetName.SetRange(Name, BudgetNameChecked);
if GLBudgetName.FindSet() then
repeat
if (DimTypeChecked <> DimTypeChecked::Budget1) and
(DimChecked = GLBudgetName."Budget Dimension 1 Code")
then
UsedAsBudgetDim := true;
if (DimTypeChecked <> DimTypeChecked::Budget2) and
(DimChecked = GLBudgetName."Budget Dimension 2 Code")
then
UsedAsBudgetDim := true;
if (DimTypeChecked <> DimTypeChecked::Budget3) and
(DimChecked = GLBudgetName."Budget Dimension 3 Code")
then
UsedAsBudgetDim := true;
if (DimTypeChecked <> DimTypeChecked::Budget4) and
(DimChecked = GLBudgetName."Budget Dimension 4 Code")
then
UsedAsBudgetDim := true;
until GLBudgetName.Next() = 0;
end;
if CheckAllDim or CheckGlobalDim or CheckItemBudgetDim then begin
if BudgetNameChecked <> '' then begin
ItemBudgetName.SetRange("Analysis Area", AnalysisAreaChecked);
ItemBudgetName.SetRange(Name, BudgetNameChecked);
end;
if ItemBudgetName.FindSet() then
repeat
if (DimTypeChecked <> DimTypeChecked::ItemBudget1) and
(DimChecked = ItemBudgetName."Budget Dimension 1 Code")
then
UsedAsItemBudgetDim := true;
if (DimTypeChecked <> DimTypeChecked::ItemBudget2) and
(DimChecked = ItemBudgetName."Budget Dimension 2 Code")
then
UsedAsItemBudgetDim := true;
if (DimTypeChecked <> DimTypeChecked::ItemBudget3) and
(DimChecked = ItemBudgetName."Budget Dimension 3 Code")
then
UsedAsItemBudgetDim := true;
until ItemBudgetName.Next() = 0;
end;
CheckIfDimUsedAsAnalysisViewDim(AnalysisView, DimChecked, DimTypeChecked, CheckAllDim, CheckAnalysisViewDim, AnalysisViewChecked);
CheckIfDimUsedAsItemAnalysisViewDim(ItemAnalysisView,DimChecked, DimTypeChecked, AnalysisViewChecked, AnalysisAreaChecked, CheckAllDim, CheckItemAnalysisViewDim, UsedAsCustomDim, CustomDimErr);//NewProcedure
if UsedAsGlobalDim or
UsedAsShortcutDim or
UsedAsBudgetDim or
UsedAsAnalysisViewDim or
UsedAsItemBudgetDim or
UsedAsItemAnalysisViewDim or
UsedAsCustomDim
then begin
MakeCheckDimErr(CustomDimErr);
exit(true);
end;
exit(false);
end;
Client Code:
CheckItemAnalysisViewDim :=
//DimTypeChecked IN [DimTypeChecked::ItemAnalysis1,DimTypeChecked::ItemAnalysis2,DimTypeChecked::ItemAnalysis3]; //HEI.02 commented
DimTypeChecked IN [DimTypeChecked::ItemAnalysis1,DimTypeChecked::ItemAnalysis2,DimTypeChecked::ItemAnalysis3,DimTypeChecked::ItemAnalysis4,DimTypeChecked::ItemAnalysis5]; //HEI.02
IF CheckAllDim OR CheckItemAnalysisViewDim THEN BEGIN
IF AnalysisViewChecked <> '' THEN BEGIN
ItemAnalysisView.SETRANGE("Analysis Area",AnalysisAreaChecked);
ItemAnalysisView.SETRANGE(Code,AnalysisViewChecked);
END;
IF ItemAnalysisView.FINDSET THEN
REPEAT
IF (DimTypeChecked <> DimTypeChecked::ItemAnalysis1) AND
(DimChecked = ItemAnalysisView."Dimension 1 Code")
THEN
UsedAsItemAnalysisViewDim := TRUE;
IF (DimTypeChecked <> DimTypeChecked::ItemAnalysis2) AND
(DimChecked = ItemAnalysisView."Dimension 2 Code")
THEN
UsedAsItemAnalysisViewDim := TRUE;
IF (DimTypeChecked <> DimTypeChecked::ItemAnalysis3) AND
(DimChecked = ItemAnalysisView."Dimension 3 Code")
THEN
UsedAsItemAnalysisViewDim := TRUE;
//HEI.02<<
IF (DimTypeChecked <> DimTypeChecked::ItemAnalysis4) AND
(DimChecked = ItemAnalysisView."Shortcut 1 Code")
THEN
UsedAsItemAnalysisViewDim := TRUE;
IF (DimTypeChecked <> DimTypeChecked::ItemAnalysis5) AND
(DimChecked = ItemAnalysisView."Shortcut 2 Code")
THEN
UsedAsItemAnalysisViewDim := TRUE;
//HEI.02>>
UNTIL ItemAnalysisView.NEXT = 0;
END;