Codeunit 408 DimensionManagement
- App
- Base Application
- Namespace
- Microsoft.Finance.Dimension
- Versions
- 17-28
Procedures, 127Events, 110Obsolete, 12
Versions171819202122232425262728
Source29
Source in 29
src/Layers/W1/BaseApp/Finance/Dimension/DimensionManagement.Codeunit.al4171 lines, Copyright (c) Microsoft Corporation. MIT
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
/// <summary>
/// Codeunit DimensionManagement (ID 408).
/// This codeunit provides comprehensive dimension management functionality including validation, default dimension handling,
/// dimension set management, and integration with various document types and journal entries.
/// It serves as the central engine for all dimension-related operations in the system.
/// </summary>
namespace Microsoft.Finance.Dimension;
using Microsoft.Assembly.Document;
using Microsoft.Bank.BankAccount;
using Microsoft.Bank.Reconciliation;
using Microsoft.CostAccounting.Setup;
using Microsoft.Finance.GeneralLedger.Account;
using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.FixedAssets.FixedAsset;
using Microsoft.Foundation.AuditCodes;
using Microsoft.HumanResources.Employee;
using Microsoft.Intercompany.Dimension;
using Microsoft.Intercompany.Partner;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Location;
using Microsoft.Inventory.Requisition;
using Microsoft.Inventory.Transfer;
using Microsoft.Projects.Project.Job;
using Microsoft.Projects.Project.Journal;
using Microsoft.Projects.Resources.Resource;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.Payables;
using Microsoft.Purchases.Vendor;
using Microsoft.Sales.Customer;
using Microsoft.Sales.Document;
using Microsoft.Sales.FinanceCharge;
using Microsoft.Sales.Receivables;
using Microsoft.Sales.Reminder;
using Microsoft.Utilities;
using System.Environment.Configuration;
using System.Globalization;
using System.Reflection;
using System.Utilities;
/// <summary>
/// Codeunit DimensionManagement (ID 408).
/// Central management system for all dimension-related operations including validation,
/// default dimension processing, dimension set creation and management, and integration
/// with documents and journal entries across all application areas.
/// </summary>
codeunit 408 DimensionManagement
{
Permissions = TableData "Gen. Journal Template" = rimd,
TableData "Gen. Journal Batch" = rimd,
tabledata "Default Dimension" = R,
tabledata "Dimension Set Entry" = R;
trigger OnRun()
begin
end;
var
#pragma warning disable AA0074
#pragma warning disable AA0470
Text000: Label 'Dimensions %1 and %2 can''t be used concurrently.';
Text001: Label 'Dimension combinations %1 - %2 and %3 - %4 can''t be used concurrently.';
ShortcutDimensionNotDefinedErr: Label 'Shortcut Dimension %2 is not defined in the %1.', Comment = '%1 - Table Caption, %2 - Shortcut Dimension No.';
Text003: Label '%1 is not an available %2 for that dimension.';
#pragma warning restore AA0470
#pragma warning restore AA0074
DefaultDimensionsValueCodeEmptyTxt: Label 'The %1 dimension is the default dimension, and it must have a value. You can set the value on the %2 page.', Comment = '%1 = the value of Dimension Code; %2 = page caption of Default Dimensions';
#pragma warning disable AA0074
#pragma warning disable AA0470
Text005: Label 'Select a %1 for the %2 %3 for %4 %5.';
#pragma warning restore AA0470
#pragma warning restore AA0074
SameCodeWrongDimOrNoCode01Err: Label 'The %1 must be %2 for %3 %4. Currently it''s %5.', Comment = '%1 = "Dimension value code" caption, %2 = expected "Dimension value code" value, %3 = "Dimension code" caption, %4 = "Dimension Code" value, %5 = current "Dimension value code" value';
SameCodeWrongDimOrNoCode02Err: Label 'The %1 must be %2 for %3 %4 for %5 %6. Currently it''s %7.', Comment = '%1 = "Dimension value code" caption, %2 = expected "Dimension value code" value, %3 = "Dimension code" caption, %4 = "Dimension Code" value, %5 = Table caption (Vendor), %6 = Table value (XYZ), %7 = current "Dimension value code" value';
BlankValueLbl: Label 'blank', Comment = 'This can be used with SameCodeWrongDimOrNoCode02Err. Example: The Dimension Value Code must be blank for Dimension code SALESCAMPAIGN for Vendor 10000. Currently it''s SUMMER.';
SameCodeMissingDim01Err: Label 'The %1 %2 with %3 %4 is required.', Comment = '%1 = "Dimension code" caption, %2= "Dimension Code" value, %3 = "Dimension value code" caption, %4 = "Dimension value code" value';
SameCodeMissingDim02Err: Label 'The %1 %2 with %3 %4 is required for %5 %6.', Comment = '%1 = "Dimension code" caption, %2= "Dimension Code" value, %3 = "Dimension value code" caption, %4 = "Dimension value code" value, %5 = Table caption (Vendor), %6 = Table value (XYZ)';
#pragma warning disable AA0074
#pragma warning disable AA0470
Text008: Label '%1 %2 must be blank.';
Text009: Label '%1 %2 must be blank for %3 %4.';
Text012: Label 'A %1 used in %2 has not been used in %3.';
Text013: Label '%1 for %2 %3 is not the same in %4 and %5.';
Text014: Label '%1 %2 is blocked.';
Text015: Label '%1 %2 can''t be found.';
#pragma warning restore AA0470
#pragma warning restore AA0074
DimValueBlockedErr: Label '%1 %2 - %3 is blocked.', Comment = '%1 = Dimension Value table caption, %2 = Dim Code, %3 = Dim Value';
DimValueMustNotBeErr: Label 'Dimension Value Type for %1 %2 - %3 must not be %4.', Comment = '%1 = Dimension Value table caption, %2 = Dim Code, %3 = Dim Value, %4 = Dimension Value Type value';
DimValueMissingErr: Label '%1 %2 - %3 is missing.', Comment = '%1 = Dimension Value table caption, %2 = Dim Code, %3 = Dim Value';
#pragma warning disable AA0074
Text019: Label 'You have changed a dimension.\\Do you want to update the lines?';
#pragma warning restore AA0074
DimValueNotAllowedForAccountErr: Label 'Dimension value %1, %2 is not allowed for %3, %4.', Comment = '%1 = Dim Code, %2 = Dim Value, %3 - table caption, %4 - account number.';
DimValueNotAllowedForAccountTypeErr: Label 'Dimension value %1 %2 is not allowed for account type %3.', Comment = '%1 = Dim Code, %2 = Dim Value, %3 - table caption.';
ToManyParametersErr: Label 'This filter selection exceeds the number of parameters that can be passed to SQL. Please reduce the number by adding additional filters.';
NoAllowedValuesSelectedErr: Label 'There are no allowed dimension values selected.';
DefaultDimPrioritiesMissingLbl: Label 'Default Dimension Priorities are not defined for Source Code: %1.', Comment = '%1 = Source Code';
AllowedDimensionValueConfirmTxt: Label 'Do you want dimension value %1 to be included in %2 in %3 default dimensions? Updating default dimensions may take some time.', Comment = '%1 = Dimension Value, %2 = Allowed Values Filter, %3 = No. of Default Dimension records that will be updated.';
HideNotificationTxt: Label 'Don''t show again';
OpenDefaultDimPrioritiesLbl: Label 'Do you want to initialize Dimension Priorities?';
LastErrorMessage: Record "Error Message";
TempJobTaskDimBuffer: Record "Job Task Dimension" temporary;
TempDimSetEntryBuffer: Record "Dimension Set Entry" temporary;
ErrorMessageMgt: Codeunit "Error Message Management";
InstructionMgt: Codeunit "Instruction Mgt.";
TempDimCombInitialized: Boolean;
TempDimCombEmpty: Boolean;
HasGotGLSetup: Boolean;
GLSetupShortcutDimCode: array[8] of Code[20];
DimSetFilterCtr: Integer;
IsCollectErrorsMode: Boolean;
SkipChangeDimensionsQst: Boolean;
SkipUpdateDimensions: Boolean;
SourceCode: Code[10];
/// <summary>
/// Enables error collection mode to accumulate dimension-related errors instead of immediately throwing them.
/// Used in batch processing scenarios where multiple validation errors need to be collected and reported together.
/// </summary>
procedure SetCollectErrorsMode()
begin
IsCollectErrorsMode := true;
end;
/// <summary>
/// Sets the source code for dimension operations based on the table ID.
/// Determines appropriate source code from Source Code Setup for different document types and journal entries.
/// </summary>
/// <param name="TableID">Table ID to determine the appropriate source code for dimension operations</param>
procedure SetSourceCode(TableID: Integer)
var
SourceCodeSetup: Record "Source Code Setup";
begin
SourceCodeSetup.Get();
case TableID of
Database::"Sales Header",
Database::"Sales Line":
SourceCode := SourceCodeSetup.Sales;
Database::"Purchase Header",
Database::"Purchase Line",
Database::"Requisition Line":
SourceCode := SourceCodeSetup.Purchases;
Database::"Bank Acc. Reconciliation",
Database::"Bank Acc. Reconciliation Line":
SourceCode := SourceCodeSetup."Payment Reconciliation Journal";
Database::"Reminder Header":
SourceCode := SourceCodeSetup.Reminder;
Database::"Finance Charge Memo Header":
SourceCode := SourceCodeSetup."Finance Charge Memo";
Database::"Assembly Header",
Database::"Assembly Line":
SourceCode := SourceCodeSetup.Assembly;
Database::"Transfer Line":
SourceCode := SourceCodeSetup.Transfer;
end;
OnAfterSetSourceCode(SourceCodeSetup, TableID, SourceCode);
end;
/// <summary>
/// Sets the source code for dimension operations based on the table ID and record variant.
/// Extends the standard SetSourceCode procedure with additional record context for specialized handling.
/// </summary>
/// <param name="TableID">Table ID to determine the appropriate source code for dimension operations</param>
/// <param name="RecordVar">Record variant providing additional context for source code determination</param>
procedure SetSourceCode(TableID: Integer; RecordVar: Variant)
begin
SetSourceCode(TableID);
OnAfterSetSourceCodeWithVar(TableID, RecordVar, SourceCode);
end;
/// <summary>
/// Returns the current source code set for dimension operations.
/// Used to retrieve the source code that was previously set via SetSourceCode procedures.
/// </summary>
/// <returns>Source code currently active for dimension operations</returns>
procedure GetSourceCode(): Code[10]
begin
exit(SourceCode);
end;
/// <summary>
/// Gets or creates a dimension set ID from the provided dimension set entries.
/// Creates a new dimension set if the combination doesn't exist, or returns existing set ID.
/// </summary>
/// <param name="DimSetEntry2">Dimension set entries to find or create dimension set ID for</param>
/// <returns>Dimension set ID corresponding to the provided dimension entries</returns>
procedure GetDimensionSetID(var DimSetEntry2: Record "Dimension Set Entry"): Integer
var
DimSetEntry: Record "Dimension Set Entry";
begin
OnBeforeGetDimensionSetIDProcedure(DimSetEntry2);
exit(DimSetEntry.GetDimensionSetID(DimSetEntry2));
end;
/// <summary>
/// Retrieves all dimension set entries for a specific dimension set ID.
/// Populates the temporary dimension set entry record with all dimensions from the specified set.
/// </summary>
/// <param name="TempDimSetEntry">Temporary dimension set entry record to populate with dimension data</param>
/// <param name="DimSetID">Dimension set ID to retrieve entries for</param>
procedure GetDimensionSet(var TempDimSetEntry: Record "Dimension Set Entry" temporary; DimSetID: Integer)
var
DimSetEntry: Record "Dimension Set Entry";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeGetDimensionSet(TempDimSetEntry, DimSetID, IsHandled);
if IsHandled then
exit;
TempDimSetEntry.DeleteAll();
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
if DimSetEntry.FindSet() then
repeat
TempDimSetEntry := DimSetEntry;
TempDimSetEntry.Insert();
until DimSetEntry.Next() = 0;
end;
/// <summary>
/// Displays the dimension set entries in a read-only modal page.
/// Shows all dimension values associated with the specified dimension set ID.
/// </summary>
/// <param name="DimSetID">Dimension set ID to display entries for</param>
/// <param name="NewCaption">Caption to display on the dimension set entries page</param>
procedure ShowDimensionSet(DimSetID: Integer; NewCaption: Text[250])
var
DimSetEntry: Record "Dimension Set Entry";
DimSetEntries: Page "Dimension Set Entries";
begin
DimSetEntry.Reset();
DimSetEntry.FilterGroup(2);
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
DimSetEntry.FilterGroup(0);
DimSetEntries.SetTableView(DimSetEntry);
DimSetEntries.SetFormCaption(NewCaption);
DimSetEntries.RunModal();
end;
/// <summary>
/// Opens the dimension set editor for modifying dimensions and returns the new dimension set ID.
/// Allows user to edit dimension values and creates a new dimension set if changes are made.
/// </summary>
/// <param name="DimSetID">Original dimension set ID to edit</param>
/// <param name="NewCaption">Caption to display on the dimension editor page</param>
/// <returns>New dimension set ID after editing, or original ID if no changes made</returns>
procedure EditDimensionSet(DimSetID: Integer; NewCaption: Text[250]): Integer
var
DimSetEntry: Record "Dimension Set Entry";
EditDimSetEntries: Page "Edit Dimension Set Entries";
NewDimSetID: Integer;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeEditDimensionSet(DimSetID, NewCaption, NewDimSetID, IsHandled);
if IsHandled then
exit(NewDimSetID);
NewDimSetID := DimSetID;
DimSetEntry.Reset();
DimSetEntry.FilterGroup(2);
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
DimSetEntry.FilterGroup(0);
EditDimSetEntries.SetTableView(DimSetEntry);
EditDimSetEntries.SetFormCaption(NewCaption);
OnEditDimensionSetOnBeforeEditDimEntries(EditDimSetEntries);
EditDimSetEntries.RunModal();
NewDimSetID := EditDimSetEntries.GetDimensionID();
OnAfterEditDimensionSet(NewDimSetID);
exit(NewDimSetID);
end;
/// <summary>
/// Opens the dimension set editor and updates global dimension values after editing.
/// Convenience procedure that combines dimension editing with global dimension value updates.
/// </summary>
/// <param name="DimSetID">Original dimension set ID to edit</param>
/// <param name="NewCaption">Caption to display on the dimension editor page</param>
/// <param name="GlobalDimVal1">Variable to receive updated global dimension 1 value</param>
/// <param name="GlobalDimVal2">Variable to receive updated global dimension 2 value</param>
/// <returns>New dimension set ID after editing, or original ID if no changes made</returns>
procedure EditDimensionSet(DimSetID: Integer; NewCaption: Text[250]; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20]): Integer
var
RecVariant: Variant;
begin
exit(EditDimensionSet(RecVariant, DimSetID, NewCaption, GlobalDimVal1, GlobalDimVal2));
end;
/// <summary>
/// Opens the dimension set editor with record context and updates global dimension values.
/// Extended version providing record variant context for specialized dimension handling.
/// </summary>
/// <param name="RecVariant">Record variant providing context for dimension editing</param>
/// <param name="DimSetID">Original dimension set ID to edit</param>
/// <param name="NewCaption">Caption to display on the dimension editor page</param>
/// <param name="GlobalDimVal1">Variable to receive updated global dimension 1 value</param>
/// <param name="GlobalDimVal2">Variable to receive updated global dimension 2 value</param>
/// <returns>New dimension set ID after editing, or original ID if no changes made</returns>
procedure EditDimensionSet(RecVariant: Variant; DimSetID: Integer; NewCaption: Text[250]; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20]): Integer
var
DimSetEntry: Record "Dimension Set Entry";
EditDimSetEntries: Page "Edit Dimension Set Entries";
NewDimSetID: Integer;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeEditDimensionSet2(DimSetID, NewCaption, GlobalDimVal1, GlobalDimVal2, NewDimSetID, IsHandled, RecVariant);
if IsHandled then
exit(NewDimSetID);
NewDimSetID := DimSetID;
DimSetEntry.Reset();
DimSetEntry.FilterGroup(2);
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
DimSetEntry.FilterGroup(0);
EditDimSetEntries.SetTableView(DimSetEntry);
EditDimSetEntries.SetFormCaption(NewCaption);
OnEditDimensionSetOnBeforeEditDimEntries(EditDimSetEntries);
EditDimSetEntries.RunModal();
NewDimSetID := EditDimSetEntries.GetDimensionID();
UpdateGlobalDimFromDimSetID(NewDimSetID, GlobalDimVal1, GlobalDimVal2);
OnAfterEditDimensionSet2(NewDimSetID, GlobalDimVal1, GlobalDimVal2);
exit(NewDimSetID);
end;
/// <summary>
/// Opens the reclassification dimension editor for modifying both source and destination dimensions.
/// Used in reclassification scenarios where both original and new dimension sets need to be edited.
/// </summary>
/// <param name="DimSetID">Source dimension set ID to edit</param>
/// <param name="NewDimSetID">Destination dimension set ID to edit</param>
/// <param name="NewCaption">Caption to display on the reclassification dimension editor page</param>
/// <param name="GlobalDimVal1">Variable to receive updated source global dimension 1 value</param>
/// <param name="GlobalDimVal2">Variable to receive updated source global dimension 2 value</param>
/// <param name="NewGlobalDimVal1">Variable to receive updated destination global dimension 1 value</param>
/// <param name="NewGlobalDimVal2">Variable to receive updated destination global dimension 2 value</param>
procedure EditReclasDimensionSet(var DimSetID: Integer; var NewDimSetID: Integer; NewCaption: Text[250]; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20]; var NewGlobalDimVal1: Code[20]; var NewGlobalDimVal2: Code[20])
var
EditReclasDimensions: Page "Edit Reclas. Dimensions";
begin
EditReclasDimensions.SetDimensionIDs(DimSetID, NewDimSetID);
EditReclasDimensions.SetFormCaption(NewCaption);
EditReclasDimensions.RunModal();
EditReclasDimensions.GetDimensionIDs(DimSetID, NewDimSetID);
UpdateGlobalDimFromDimSetID(DimSetID, GlobalDimVal1, GlobalDimVal2);
UpdateGlobalDimFromDimSetID(NewDimSetID, NewGlobalDimVal1, NewGlobalDimVal2);
end;
/// <summary>
/// Updates global dimension values from a dimension set ID.
/// Retrieves the first two global dimension values from the specified dimension set.
/// </summary>
/// <param name="DimSetID">Dimension set ID to extract global dimension values from</param>
/// <param name="GlobalDimVal1">Variable to receive global dimension 1 value</param>
/// <param name="GlobalDimVal2">Variable to receive global dimension 2 value</param>
procedure UpdateGlobalDimFromDimSetID(DimSetID: Integer; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20])
var
ShortcutDimCode: array[8] of Code[20];
begin
GetGlobalDimensions(DimSetID, ShortcutDimCode);
GlobalDimVal1 := ShortcutDimCode[1];
GlobalDimVal2 := ShortcutDimCode[2];
end;
/// <summary>
/// Combines multiple dimension sets into a single dimension set ID.
/// Merges dimensions from up to 10 different dimension sets, with later sets overriding earlier ones for same dimensions.
/// </summary>
/// <param name="DimensionSetIDArr">Array of dimension set IDs to combine</param>
/// <param name="GlobalDimVal1">Variable to receive combined global dimension 1 value</param>
/// <param name="GlobalDimVal2">Variable to receive combined global dimension 2 value</param>
/// <returns>New dimension set ID containing combined dimensions</returns>
procedure GetCombinedDimensionSetID(DimensionSetIDArr: array[10] of Integer; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20]): Integer
var
DimSetEntry: Record "Dimension Set Entry";
TempDimSetEntry: Record "Dimension Set Entry" temporary;
i: Integer;
begin
GetGLSetup(GLSetupShortcutDimCode);
GlobalDimVal1 := '';
GlobalDimVal2 := '';
DimSetEntry.Reset();
for i := 1 to 10 do
if DimensionSetIDArr[i] <> 0 then begin
DimSetEntry.SetRange("Dimension Set ID", DimensionSetIDArr[i]);
if DimSetEntry.FindSet() then
repeat
if TempDimSetEntry.Get(0, DimSetEntry."Dimension Code") then
TempDimSetEntry.Delete();
TempDimSetEntry := DimSetEntry;
TempDimSetEntry."Dimension Set ID" := 0;
TempDimSetEntry.Insert();
if GLSetupShortcutDimCode[1] = TempDimSetEntry."Dimension Code" then
GlobalDimVal1 := TempDimSetEntry."Dimension Value Code";
if GLSetupShortcutDimCode[2] = TempDimSetEntry."Dimension Code" then
GlobalDimVal2 := TempDimSetEntry."Dimension Value Code";
until DimSetEntry.Next() = 0;
end;
exit(GetDimensionSetID(TempDimSetEntry));
end;
/// <summary>
/// Calculates delta dimension set ID based on parent dimension set changes.
/// Updates a child dimension set when parent dimensions change, preserving child-specific dimensions.
/// </summary>
/// <param name="DimSetID">Original dimension set ID to update</param>
/// <param name="NewParentDimSetID">New parent dimension set ID</param>
/// <param name="OldParentDimSetID">Original parent dimension set ID</param>
/// <returns>Updated dimension set ID reflecting parent changes</returns>
procedure GetDeltaDimSetID(DimSetID: Integer; NewParentDimSetID: Integer; OldParentDimSetID: Integer): Integer
var
TempDimSetEntry: Record "Dimension Set Entry" temporary;
TempDimSetEntryNew: Record "Dimension Set Entry" temporary;
TempDimSetEntryDeleted: Record "Dimension Set Entry" temporary;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeGetDeltaDimSetID(DimSetID, NewParentDimSetID, OldParentDimSetID, IsHandled);
if IsHandled then
exit(DimSetID);
// Returns an updated DimSetID based on parent's old and new DimSetID
if NewParentDimSetID = OldParentDimSetID then
exit(DimSetID);
GetDimensionSet(TempDimSetEntry, DimSetID);
GetDimensionSet(TempDimSetEntryNew, NewParentDimSetID);
GetDimensionSet(TempDimSetEntryDeleted, OldParentDimSetID);
if TempDimSetEntryDeleted.FindSet() then
repeat
if TempDimSetEntryNew.Get(NewParentDimSetID, TempDimSetEntryDeleted."Dimension Code") then begin
if TempDimSetEntryNew."Dimension Value Code" = TempDimSetEntryDeleted."Dimension Value Code" then
TempDimSetEntryNew.Delete();
TempDimSetEntryDeleted.Delete();
end;
until TempDimSetEntryDeleted.Next() = 0;
if TempDimSetEntryDeleted.FindSet() then
repeat
if TempDimSetEntry.Get(DimSetID, TempDimSetEntryDeleted."Dimension Code") then
TempDimSetEntry.Delete();
until TempDimSetEntryDeleted.Next() = 0;
if TempDimSetEntryNew.FindSet() then
repeat
if TempDimSetEntry.Get(DimSetID, TempDimSetEntryNew."Dimension Code") then begin
if TempDimSetEntry."Dimension Value Code" <> TempDimSetEntryNew."Dimension Value Code" then begin
TempDimSetEntry."Dimension Value Code" := TempDimSetEntryNew."Dimension Value Code";
TempDimSetEntry."Dimension Value ID" := TempDimSetEntryNew."Dimension Value ID";
TempDimSetEntry.Modify();
end;
end else begin
TempDimSetEntry := TempDimSetEntryNew;
TempDimSetEntry."Dimension Set ID" := DimSetID;
TempDimSetEntry.Insert();
end;
until TempDimSetEntryNew.Next() = 0;
OnBeforeGetDimensionSetID(TempDimSetEntry);
exit(GetDimensionSetID(TempDimSetEntry));
end;
/// <summary>
/// Retrieves and caches General Ledger Setup shortcut dimension codes.
/// Loads all 8 shortcut dimension codes from General Ledger Setup for efficient repeated access.
/// </summary>
/// <param name="GLSetupShortcutDimCode">Array to populate with shortcut dimension codes from General Ledger Setup</param>
procedure GetGLSetup(var GLSetupShortcutDimCode: array[8] of Code[20])
var
GLSetup: Record "General Ledger Setup";
begin
if not HasGotGLSetup then begin
GLSetup.Get();
GLSetupShortcutDimCode[1] := GLSetup."Shortcut Dimension 1 Code";
GLSetupShortcutDimCode[2] := GLSetup."Shortcut Dimension 2 Code";
GLSetupShortcutDimCode[3] := GLSetup."Shortcut Dimension 3 Code";
GLSetupShortcutDimCode[4] := GLSetup."Shortcut Dimension 4 Code";
GLSetupShortcutDimCode[5] := GLSetup."Shortcut Dimension 5 Code";
GLSetupShortcutDimCode[6] := GLSetup."Shortcut Dimension 6 Code";
GLSetupShortcutDimCode[7] := GLSetup."Shortcut Dimension 7 Code";
GLSetupShortcutDimCode[8] := GLSetup."Shortcut Dimension 8 Code";
HasGotGLSetup := true;
end;
end;
local procedure GetLastDimErrorID(): Integer
begin
if ErrorMessageMgt.IsActive() then
exit(ErrorMessageMgt.GetCachedLastErrorID());
exit(LastErrorMessage.ID);
end;
local procedure FindLastErrorMessage(var Message: Text[250])
begin
if ErrorMessageMgt.IsActive() then
ErrorMessageMgt.GetLastError(Message)
else
Message := CopyStr(LastErrorMessage."Message", 1, MaxStrLen(Message));
end;
local procedure GetDimBufForDimSetID(DimSetID: Integer; var TempDimBuf: Record "Dimension Buffer" temporary)
var
DimSetEntry: Record "Dimension Set Entry";
begin
DimSetEntry.Reset();
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
if DimSetEntry.FindSet() then
repeat
InsertTempDimBufEntry(TempDimBuf, Database::"Dimension Buffer", 0, DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code");
until DimSetEntry.Next() = 0;
end;
/// <summary>
/// Validates dimension combinations for a dimension set ID.
/// Checks if the dimensions in the set violate any defined dimension combination restrictions.
/// </summary>
/// <param name="DimSetID">Dimension set ID to validate combinations for</param>
/// <returns>True if dimension combinations are valid, false if violations exist</returns>
procedure CheckDimIDComb(DimSetID: Integer): Boolean
var
TempDimBuf: Record "Dimension Buffer" temporary;
begin
GetDimBufForDimSetID(DimSetID, TempDimBuf);
exit(CheckDimComb(TempDimBuf));
end;
/// <summary>
/// Validates dimension value posting permissions for specified table entities.
/// Checks default dimensions and dimension value restrictions for the given accounts and dimension set.
/// </summary>
/// <param name="TableID">Array of table IDs for accounts to validate against</param>
/// <param name="No">Array of account numbers corresponding to the table IDs</param>
/// <param name="DimSetID">Dimension set ID to validate for posting</param>
/// <returns>True if dimension values are valid for posting, false if violations exist</returns>
procedure CheckDimValuePosting(TableID: array[10] of Integer; No: array[10] of Code[20]; DimSetID: Integer): Boolean
var
DimSetEntry: Record "Dimension Set Entry";
TempDefaultDim: Record "Default Dimension" temporary;
DimValuePerAccount: Record "Dim. Value per Account";
IsHandled: Boolean;
IsChecked: Boolean;
LastErrorID: Integer;
begin
IsChecked := false;
IsHandled := false;
OnBeforeCheckDimValuePosting(TableID, No, DimSetID, IsChecked, IsHandled, DimSetEntry);
if IsHandled then
exit(IsChecked);
if not CheckBlockedDimAndValues(DimSetID) then
if not IsCollectErrorsMode then
exit(false);
LastErrorID := GetLastDimErrorID();
DimSetEntry.Reset();
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
CollectDefaultDimsToCheck(TableID, No, TempDefaultDim);
TempDefaultDim.Reset();
if TempDefaultDim.FindSet() then
repeat
DimSetEntry.SetRange("Dimension Code", TempDefaultDim."Dimension Code");
IsHandled := false;
OnCheckDimValuePostingOnBeforeLogErrors(TempDefaultDim, DimSetEntry, LastErrorMessage, ErrorMessageMgt, isHandled);
if not IsHandled then begin
case TempDefaultDim."Value Posting" of
TempDefaultDim."Value Posting"::"Code Mandatory":
if not DimSetEntry.FindFirst() or (DimSetEntry."Dimension Value Code" = '') then
LogError(TempDefaultDim.RecordId, TempDefaultDim.FieldNo(TempDefaultDim."Value Posting"), GetMissedMandatoryDimErr(TempDefaultDim), '');
TempDefaultDim."Value Posting"::"Same Code":
if TempDefaultDim."Dimension Value Code" <> '' then begin
if DimSetEntry.FindFirst() then begin
if TempDefaultDim."Dimension Value Code" <> DimSetEntry."Dimension Value Code" then
LogSameCodeWrongDimErrWithSubContext(TempDefaultDim, DimSetEntry);
end
else
LogSameCodeMissingDimErrWithSubContext(TempDefaultDim, DimSetID);
end else
if DimSetEntry.FindFirst() then
LogError(TempDefaultDim.RecordId, TempDefaultDim.FieldNo(TempDefaultDim."Value Posting"), GetSameCodeBlankDimErr(TempDefaultDim), '');
TempDefaultDim."Value Posting"::"No Code":
if DimSetEntry.FindFirst() then
LogNoCodeFilledDimErrWithSubContext(TempDefaultDim, DimSetEntry);
end;
if DimValuePerAccount.Get(TempDefaultDim."Table ID", TempDefaultDim."No.", TempDefaultDim."Dimension Code", DimSetEntry."Dimension Value Code") then
if not DimValuePerAccount.Allowed then
LogError(TempDefaultDim.RecordId, TempDefaultDim.FieldNo(TempDefaultDim."Allowed Values Filter"), GetNotAllowedDimValuePerAccount(TempDefaultDim, DimSetEntry."Dimension Value Code"), '');
end;
if not IsCollectErrorsMode then
if LastErrorID <> GetLastDimErrorID() then
exit(false);
until TempDefaultDim.Next() = 0;
IsHandled := false;
OnCheckDimValuePostingOnBeforeExit(TableID, No, DimSetID, LastErrorMessage, ErrorMessageMgt, IsChecked, IsHandled);
if IsHandled then
exit(IsChecked);
exit(GetLastDimErrorID() = LastErrorID);
end;
/// <summary>
/// Validates dimension combinations within a dimension buffer.
/// Checks if the dimensions in the buffer violate any defined dimension combination restrictions.
/// </summary>
/// <param name="DimBuffer">Dimension buffer containing dimensions to validate</param>
/// <returns>True if dimension combinations are valid, false if violations exist</returns>
procedure CheckDimBuffer(var DimBuffer: Record "Dimension Buffer"): Boolean
var
TempDimBuf: Record "Dimension Buffer" temporary;
i: Integer;
begin
if DimBuffer.FindSet() then begin
i := 1;
repeat
InsertTempDimBufEntry(TempDimBuf, Database::"Dimension Buffer", i, DimBuffer."Dimension Code", DimBuffer."Dimension Value Code");
i := i + 1;
until DimBuffer.Next() = 0;
end;
exit(CheckDimComb(TempDimBuf));
end;
/// <summary>
/// Validates dimension combinations against dimension combination restrictions.
/// Core validation logic for checking dimension combination rules and generating error messages.
/// </summary>
/// <param name="TempDimBuf">Temporary dimension buffer containing dimensions to validate</param>
/// <returns>True if dimension combinations are valid, false if violations exist</returns>
procedure CheckDimComb(var TempDimBuf: Record "Dimension Buffer" temporary): Boolean
var
DimComb: Record "Dimension Combination";
CurrentDimCode: Code[20];
CurrentDimValCode: Code[20];
DimFilter: Text;
Separator: Text;
LastErrorID: Integer;
begin
OnBeforeCheckDimComb(DimComb, TempDimBuf);
if not TempDimCombInitialized then begin
TempDimCombInitialized := true;
if DimComb.IsEmpty() then
TempDimCombEmpty := true;
end;
if TempDimCombEmpty then
exit(true);
if not TempDimBuf.FindSet() then
exit(true);
repeat
DimFilter += Separator + TempDimBuf."Dimension Code";
Separator := '|';
until TempDimBuf.Next() = 0;
LastErrorID := GetLastDimErrorID();
DimComb.SetFilter("Dimension 1 Code", DimFilter);
DimComb.SetFilter("Dimension 2 Code", DimFilter);
if DimComb.FindSet() then
repeat
if DimComb."Combination Restriction" = DimComb."Combination Restriction"::Blocked then
LogError(
DimComb.RecordId, DimComb.FieldNo("Combination Restriction"),
StrSubstNo(Text000, DimComb."Dimension 1 Code", DimComb."Dimension 2 Code"), '')
else begin
TempDimBuf.SetRange("Dimension Code", DimComb."Dimension 1 Code");
TempDimBuf.FindFirst();
CurrentDimCode := TempDimBuf."Dimension Code";
CurrentDimValCode := TempDimBuf."Dimension Value Code";
TempDimBuf.SetRange("Dimension Code", DimComb."Dimension 2 Code");
TempDimBuf.FindFirst();
CheckDimValueComb(
TempDimBuf."Dimension Code", TempDimBuf."Dimension Value Code",
CurrentDimCode, CurrentDimValCode);
CheckDimValueComb(
CurrentDimCode, CurrentDimValCode,
TempDimBuf."Dimension Code", TempDimBuf."Dimension Value Code");
end;
if not IsCollectErrorsMode then
if LastErrorID <> GetLastDimErrorID() then
exit(false);
until DimComb.Next() = 0;
exit(GetLastDimErrorID() = LastErrorID);
end;
local procedure CheckDimValueComb(Dim1: Code[20]; Dim1Value: Code[20]; Dim2: Code[20]; Dim2Value: Code[20]): Boolean
var
DimValueCombination: Record "Dimension Value Combination";
IsHandled: Boolean;
begin
OnBeforeCheckDimValueComb(DimValueCombination);
if DimValueCombination.Get(Dim1, Dim1Value, Dim2, Dim2Value) then begin
IsHandled := false;
OnCheckDimValueCombOnBeforeLogError(Dim1, Dim1Value, Dim2, Dim2Value, IsHandled);
if not IsHandled then begin
LogError(
DimValueCombination.RecordId, 0, StrSubstNo(Text001, Dim1, Dim1Value, Dim2, Dim2Value), '');
exit(false);
end;
end;
exit(true);
end;
local procedure CollectDefaultDimsToCheck(TableID: array[10] of Integer; No: array[10] of Code[20]; var TempDefaultDim: Record "Default Dimension" temporary)
var
DefaultDim: Record "Default Dimension";
NoFilter: array[2] of Code[20];
i: Integer;
j: Integer;
Priority: array[2] of Integer;
begin
NoFilter[2] := '';
for i := 1 to ArrayLen(TableID) do
if (TableID[i] <> 0) and (No[i] <> '') then begin
DefaultDim.SetFilter("Value Posting", '<>%1', DefaultDim."Value Posting"::" ");
DefaultDim.SetRange("Table ID", TableID[i]);
NoFilter[1] := No[i];
for j := 1 to 2 do begin
DefaultDim.SetRange("No.", NoFilter[j]);
if DefaultDim.FindSet() then
repeat
TempDefaultDim.SetRange("Dimension Code", DefaultDim."Dimension Code");
if not TempDefaultDim.FindFirst() then begin
TempDefaultDim := DefaultDim;
TempDefaultDim.Insert();
end else begin
Priority[1] := GetDimensionPriorityForTable(TempDefaultDim."Table ID");
Priority[2] := GetDimensionPriorityForTable(DefaultDim."Table ID");
if not PriorityGreaterThan(Priority[1], Priority[2]) then begin
if PriorityGreaterThan(Priority[2], Priority[1]) then
TempDefaultDim.DeleteAll();
TempDefaultDim := DefaultDim;
if TempDefaultDim.Insert() then;
end;
end;
until DefaultDim.Next() = 0;
end;
end;
OnAfterCheckDimValuePosting(TableID, No, TempDefaultDim);
end;
local procedure PriorityGreaterThan(Priority1: Integer; Priority2: Integer): Boolean
begin
exit((Priority1 > 0) and ((Priority2 = 0) or (Priority1 < Priority2)));
end;
local procedure GetDimensionPriorityForTable(TableID: Integer): Integer
var
DefaultDimPriority: Record "Default Dimension Priority";
begin
if DefaultDimPriority.GET(SourceCode, TableID) then
exit(DefaultDimPriority.Priority);
exit(0);
end;
local procedure GetMissedMandatoryDimErr(DefaultDim: Record "Default Dimension"): Text
var
ObjectTranslation: Record "Object Translation";
DefaultDimensions: Page "Default Dimensions";
begin
if DefaultDim."No." = '' then
exit(
StrSubstNo(
DefaultDimensionsValueCodeEmptyTxt, DefaultDim."Dimension Code", DefaultDimensions.Caption));
exit(
StrSubstNo(
Text005,
DefaultDim.FieldCaption("Dimension Value Code"),
DefaultDim.FieldCaption("Dimension Code"),
DefaultDim."Dimension Code",
ObjectTranslation.TranslateTable(DefaultDim."Table ID"),
DefaultDim."No."));
end;
local procedure GetSameCodeBlankDimErr(DefaultDim: Record "Default Dimension"): Text
var
ObjectTranslation: Record "Object Translation";
begin
if DefaultDim."No." = '' then
exit(
StrSubstNo(
Text008,
DefaultDim.FieldCaption("Dimension Code"), DefaultDim."Dimension Code"));
exit(
StrSubstNo(
Text009,
DefaultDim.FieldCaption("Dimension Code"),
DefaultDim."Dimension Code",
ObjectTranslation.TranslateTable(DefaultDim."Table ID"),
DefaultDim."No."));
end;
local procedure LogSameCodeWrongDimOrNoCodeErr(DefaultDim: Record "Default Dimension"; LineDimensionValueCode: Code[20]; RequiredDimValueCode: Text[20])
var
ObjectTranslation: Record "Object Translation";
Message: Text;
begin
if DefaultDim."No." = '' then
Message := StrSubstNo(SameCodeWrongDimOrNoCode01Err, DefaultDim.FieldCaption("Dimension Value Code"), RequiredDimValueCode, DefaultDim.FieldCaption("Dimension Code"), DefaultDim."Dimension Code", LineDimensionValueCode)
else
Message := StrSubstNo(SameCodeWrongDimOrNoCode02Err, DefaultDim.FieldCaption("Dimension Value Code"), RequiredDimValueCode, DefaultDim.FieldCaption("Dimension Code"), DefaultDim."Dimension Code", ObjectTranslation.TranslateTable(DefaultDim."Table ID"), DefaultDim."No.", LineDimensionValueCode);
LogError(DefaultDim.RecordId, DefaultDim.FieldNo("Value Posting"), Message, '');
end;
local procedure LogSameCodeMissingDimErr(DefaultDim: Record "Default Dimension")
var
ObjectTranslation: Record "Object Translation";
Message: Text;
begin
if DefaultDim."No." = '' then
Message := StrSubstNo(SameCodeMissingDim01Err, DefaultDim.FieldCaption("Dimension Code"), DefaultDim."Dimension Code", DefaultDim.FieldCaption("Dimension Value Code"), DefaultDim."Dimension Value Code")
else
Message := StrSubstNo(SameCodeMissingDim02Err, DefaultDim.FieldCaption("Dimension Code"), DefaultDim."Dimension Code", DefaultDim.FieldCaption("Dimension Value Code"), DefaultDim."Dimension Value Code", ObjectTranslation.TranslateTable(DefaultDim."Table ID"), DefaultDim."No.");
LogError(DefaultDim.RecordId, DefaultDim.FieldNo("Value Posting"), Message, '');
end;
local procedure LogSameCodeWrongDimErrWithSubContext(DefaultDim: Record "Default Dimension"; DimSetEntry: Record "Dimension Set Entry")
begin
LogSameCodeWrongDimOrNoCodeErr(DefaultDim, DimSetEntry."Dimension Value Code", DefaultDim."Dimension Value Code");
ErrorMessageMgt.AddSubContextToLastErrorMessage('DimensionCodeSameError', DimSetEntry);
end;
local procedure LogSameCodeMissingDimErrWithSubContext(DefaultDim: Record "Default Dimension"; DimSetID: Integer)
begin
LogSameCodeMissingDimErr(DefaultDim);
ErrorMessageMgt.AddSubContextToLastErrorMessage('DimensionCodeSameMissingDimCodeError', DimSetID);
end;
local procedure LogNoCodeFilledDimErrWithSubContext(DefaultDim: Record "Default Dimension"; DimSetEntry: Record "Dimension Set Entry")
begin
LogSameCodeWrongDimOrNoCodeErr(DefaultDim, DimSetEntry."Dimension Value Code", BlankValueLbl);
ErrorMessageMgt.AddSubContextToLastErrorMessage('DimensionCodeMustBeBlank', DimSetEntry);
end;
/// <summary>
/// Generates error message for dimension values not allowed for specific accounts.
/// Creates appropriate error text based on whether a specific account or account type restriction applies.
/// </summary>
/// <param name="DefaultDim">Default dimension record containing the restriction rules</param>
/// <param name="DimValueCode">Dimension value code that is not allowed</param>
/// <returns>Formatted error message explaining the dimension value restriction</returns>
procedure GetNotAllowedDimValuePerAccount(DefaultDim: Record "Default Dimension"; DimValueCode: Code[20]): Text
var
ObjectTranslation: Record "Object Translation";
begin
if DefaultDim."No." = '' then
exit(
StrSubstNo(
DimValueNotAllowedForAccountTypeErr,
DefaultDim."Dimension Code",
DimValueCode,
ObjectTranslation.TranslateTable(DefaultDim."Table ID")));
exit(
StrSubstNo(
DimValueNotAllowedForAccountErr,
DefaultDim."Dimension Code",
DimValueCode,
ObjectTranslation.TranslateTable(DefaultDim."Table ID"),
DefaultDim."No."));
end;
/// <summary>
/// Retrieves the last dimension combination error message.
/// Returns the most recent error message from dimension validation operations.
/// </summary>
/// <returns>Last error message from dimension validation, empty if no errors occurred</returns>
procedure GetDimCombErr() ErrorMessage: Text[250]
begin
FindLastErrorMessage(ErrorMessage);
end;
/// <summary>
/// Updates global dimension values from default dimensions for a specific entity.
/// Retrieves default dimension values for the specified table and entity number.
/// </summary>
/// <param name="TableID">Table ID of the entity to retrieve default dimensions for</param>
/// <param name="No">Entity number to retrieve default dimensions for</param>
/// <param name="GlobalDim1Code">Variable to receive default global dimension 1 value</param>
/// <param name="GlobalDim2Code">Variable to receive default global dimension 2 value</param>
procedure UpdateDefaultDim(TableID: Integer; No: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20])
var
DefaultDim: Record "Default Dimension";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeUpdateDefaultDim(TableID, No, GlobalDim1Code, GlobalDim2Code, IsHandled);
if not IsHandled then begin
GetGLSetup(GLSetupShortcutDimCode);
if DefaultDim.Get(TableID, No, GLSetupShortcutDimCode[1]) then
GlobalDim1Code := DefaultDim."Dimension Value Code"
else
GlobalDim1Code := '';
if DefaultDim.Get(TableID, No, GLSetupShortcutDimCode[2]) then
GlobalDim2Code := DefaultDim."Dimension Value Code"
else
GlobalDim2Code := '';
end;
OnAfterUpdateDefaultDim(TableID, No, GlobalDim1Code, GlobalDim2Code);
end;
/// <summary>
/// Creates dimension set ID from default dimension sources with priority handling and inheritance.
/// Combines dimensions from multiple sources considering default dimension priorities and inheritance rules.
/// </summary>
/// <param name="DefaultDimSource">List of dictionaries containing table IDs and their corresponding primary key values</param>
/// <param name="SourceCode">Source code to determine default dimension priorities</param>
/// <param name="GlobalDim1Code">Variable to receive global dimension 1 value</param>
/// <param name="GlobalDim2Code">Variable to receive global dimension 2 value</param>
/// <param name="InheritFromDimSetID">Dimension set ID to inherit dimensions from</param>
/// <param name="InheritFromTableNo">Table number for inheritance context</param>
/// <returns>New dimension set ID containing combined and prioritized dimensions</returns>
procedure GetDefaultDimID(DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; SourceCode: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; InheritFromDimSetID: Integer; InheritFromTableNo: Integer) Result: Integer
var
DimVal: Record "Dimension Value";
DefaultDimPriority1: Record "Default Dimension Priority";
DefaultDimPriority2: Record "Default Dimension Priority";
DefaultDim: Record "Default Dimension";
TempDimBuf: Record "Dimension Buffer" temporary;
TempDimSetEntry: Record "Dimension Set Entry" temporary;
TempDimSetEntry0: Record "Dimension Set Entry" temporary;
i: Integer;
j: Integer;
NoFilter: array[2] of Code[20];
NewDimSetID: Integer;
IsHandled: Boolean;
TableIds: List of [Integer];
Nos: List of [Code[20]];
TableId: Integer;
No: Code[20];
DimSource: Dictionary of [Integer, Code[20]];
begin
IsHandled := false;
OnBeforeGetDefaultDimIDProcedure(DefaultDimSource, SourceCode, GlobalDim1Code, GlobalDim2Code, InheritFromDimSetID, InheritFromTableNo, DimVal, Result, IsHandled);
if IsHandled then
exit(Result);
GetGLSetup(GLSetupShortcutDimCode);
IsHandled := false;
OnGetDefaultDimIDOnBeforeGetInheritDimensionSet(TempDimSetEntry0, InheritFromDimSetID, InheritFromTableNo, IsHandled);
if not IsHandled then
if InheritFromDimSetID > 0 then
GetDimensionSet(TempDimSetEntry0, InheritFromDimSetID);
if TempDimSetEntry0.FindSet() then
repeat
InsertTempDimBufEntry(TempDimBuf, InheritFromTableNo, 0, TempDimSetEntry0."Dimension Code", TempDimSetEntry0."Dimension Value Code");
until TempDimSetEntry0.Next() = 0;
NoFilter[2] := '';
for i := 1 to DefaultDimSource.Count do begin
DimSource := DefaultDimSource.Get(i);
TableIds := DimSource.Keys;
Nos := DimSource.Values;
TableId := TableIds.Get(1);
No := Nos.Get(1);
if (TableId <> 0) and (No <> '') then begin
IsHandled := false;
OnGetDefaultDimOnBeforeCreate(
TempDimBuf, TableId, No, GLSetupShortcutDimCode, GlobalDim1Code, GlobalDim2Code, IsHandled, SourceCode);
if not IsHandled then begin
DefaultDim.SetRange("Table ID", TableId);
NoFilter[1] := No;
for j := 1 to 2 do begin
DefaultDim.SetRange("No.", NoFilter[j]);
if DefaultDim.FindSet() then
repeat
if DefaultDim."Dimension Value Code" <> '' then begin
TempDimBuf.SetRange("Dimension Code", DefaultDim."Dimension Code");
if not TempDimBuf.FindFirst() then
InsertTempDimBufEntry(TempDimBuf, DefaultDim."Table ID", 0, DefaultDim."Dimension Code", DefaultDim."Dimension Value Code")
else
if DefaultDimPriority1.Get(SourceCode, DefaultDim."Table ID") then begin
if DefaultDimPriority2.Get(SourceCode, TempDimBuf."Table ID") then begin
if DefaultDimPriority1.Priority < DefaultDimPriority2.Priority then begin
TempDimBuf.Delete();
InsertTempDimBufEntry(TempDimBuf, DefaultDim."Table ID", 0, DefaultDim."Dimension Code", DefaultDim."Dimension Value Code");
end;
end else begin
TempDimBuf.Delete();
InsertTempDimBufEntry(TempDimBuf, DefaultDim."Table ID", 0, DefaultDim."Dimension Code", DefaultDim."Dimension Value Code");
end;
end else
if DefDimPrioritiesNotExist(SourceCode) and (SourceCode <> '') then
if InstructionMgt.IsEnabled(InstructionMgt.DefaultDimPrioritiesCode()) then
InitializeDefaultDimPrioritiesMissingNotification(SourceCode);
if GLSetupShortcutDimCode[1] = TempDimBuf."Dimension Code" then
GlobalDim1Code := TempDimBuf."Dimension Value Code";
if GLSetupShortcutDimCode[2] = TempDimBuf."Dimension Code" then
GlobalDim2Code := TempDimBuf."Dimension Value Code";
end;
OnGetDefaultDimIDOnAfterAttributeGlobalDims(GlobalDim1Code, GlobalDim2Code);
until DefaultDim.Next() = 0;
end;
end;
end;
end;
OnGetDefaultDimIDOnBeforeFindNewDimSetIDProcedure(
TempDimBuf, DefaultDimSource, GlobalDim1Code, GlobalDim2Code, SourceCode,
GLSetupShortcutDimCode, TempDimSetEntry0, InheritFromDimSetID, InheritFromTableNo);
TempDimBuf.Reset();
if TempDimBuf.FindSet() then begin
repeat
DimVal.Get(TempDimBuf."Dimension Code", TempDimBuf."Dimension Value Code");
TempDimSetEntry."Dimension Code" := TempDimBuf."Dimension Code";
TempDimSetEntry."Dimension Value Code" := TempDimBuf."Dimension Value Code";
TempDimSetEntry."Dimension Value ID" := DimVal."Dimension Value ID";
OnGetDefaultDimIDOnBeforeTempDimSetEntryInsert(TempDimSetEntry, TempDimBuf, SourceCode);
TempDimSetEntry.Insert();
until TempDimBuf.Next() = 0;
NewDimSetID := GetDimensionSetID(TempDimSetEntry);
end;
exit(NewDimSetID);
end;
/// <summary>
/// Creates dimension set ID from default dimension sources with record context and inheritance.
/// Extended version that includes record variant context for specialized dimension handling and validation.
/// </summary>
/// <param name="RecVariant">Record variant providing context for dimension creation</param>
/// <param name="CurrFieldNo">Current field number being processed for dimension context</param>
/// <param name="DefaultDimSource">List of dictionaries containing table IDs and their corresponding primary key values</param>
/// <param name="SourceCode">Source code to determine default dimension priorities</param>
/// <param name="GlobalDim1Code">Variable to receive global dimension 1 value</param>
/// <param name="GlobalDim2Code">Variable to receive global dimension 2 value</param>
/// <param name="InheritFromDimSetID">Dimension set ID to inherit dimensions from</param>
/// <param name="InheritFromTableNo">Table number for inheritance context</param>
/// <returns>New dimension set ID containing combined and prioritized dimensions</returns>
procedure GetRecDefaultDimID(RecVariant: Variant; CurrFieldNo: Integer; DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; SourceCode: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; InheritFromDimSetID: Integer; InheritFromTableNo: Integer) Result: Integer
var
DefaultDimID: Integer;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeGetRecDefaultDimID(RecVariant, CurrFieldNo, DefaultDimSource, SourceCode, InheritFromDimSetID, InheritFromTableNo, Result, IsHandled);
if IsHandled then
exit(Result);
DefaultDimID := GetDefaultDimID(DefaultDimSource, SourceCode, GlobalDim1Code, GlobalDim2Code, InheritFromDimSetID, InheritFromTableNo);
OnAfterGetRecDefaultDimIDProcedure(RecVariant, CurrFieldNo, DefaultDimSource, SourceCode, InheritFromDimSetID, InheritFromTableNo, GlobalDim1Code, GlobalDim2Code, DefaultDimID);
exit(DefaultDimID);
end;
/// <summary>
/// Adds a new table ID and number pair to the beginning of the arrays, shifting existing entries.
/// Inserts the new entry at position 1 and moves all other entries one position down.
/// </summary>
/// <param name="TableID">Array of table IDs to modify</param>
/// <param name="No">Array of entity numbers corresponding to the table IDs</param>
/// <param name="NewTableId">New table ID to insert at the beginning</param>
/// <param name="NewNo">New entity number to insert at the beginning</param>
procedure AddFirstToTableIdArray(var TableID: array[10] of Integer; var No: array[10] of Code[20]; NewTableId: Integer; NewNo: Code[20])
var
Index: Integer;
begin
if NewNo = '' then
exit;
for Index := ArrayLen(TableID) downto 2 do begin
TableID[Index] := TableID[Index - 1];
No[Index] := No[Index - 1];
end;
TableID[1] := NewTableId;
No[1] := NewNo;
end;
/// <summary>
/// Adds a new table ID and number pair to the end of the arrays.
/// Finds the first empty position or uses the last position to insert the new entry.
/// </summary>
/// <param name="TableID">Array of table IDs to modify</param>
/// <param name="No">Array of entity numbers corresponding to the table IDs</param>
/// <param name="NewTableId">New table ID to insert at the end</param>
/// <param name="NewNo">New entity number to insert at the end</param>
procedure AddLastToTableIdArray(var TableID: array[10] of Integer; var No: array[10] of Code[20]; NewTableId: Integer; NewNo: Code[20])
var
Index: Integer;
begin
if NewNo = '' then
exit;
for Index := 1 to ArrayLen(TableID) do
if (No[Index] = '') or (Index = ArrayLen(TableID)) then begin
TableID[Index] := NewTableId;
No[Index] := NewNo;
exit;
end;
end;
/// <summary>
/// Converts an entity type option to its corresponding table ID for dimension processing.
/// Maps common master data types to their table IDs for default dimension handling.
/// </summary>
/// <param name="Type">Entity type option containing G/L Account, Customer, Vendor, Bank Account, Fixed Asset, IC Partner, or Employee</param>
/// <returns>Table ID corresponding to the specified entity type</returns>
procedure TypeToTableID1(Type: Option "G/L Account",Customer,Vendor,"Bank Account","Fixed Asset","IC Partner",Employee) TableId: Integer
begin
case Type of
Type::"G/L Account":
exit(Database::"G/L Account");
Type::Customer:
exit(Database::Customer);
Type::Vendor:
exit(Database::Vendor);
Type::Employee:
exit(Database::Employee);
Type::"Bank Account":
exit(Database::"Bank Account");
Type::"Fixed Asset":
exit(Database::"Fixed Asset");
Type::"IC Partner":
exit(Database::"IC Partner");
end;
OnAfterTypeToTableID1(Type, TableId);
end;
/// <summary>
/// Converts a resource/item type option to its corresponding table ID for dimension processing.
/// Maps resource, item, and G/L account types to their table IDs for default dimension handling.
/// </summary>
/// <param name="Type">Entity type option containing Resource, Item, or G/L Account</param>
/// <returns>Table ID corresponding to the specified entity type</returns>
procedure TypeToTableID2(Type: Option Resource,Item,"G/L Account"): Integer
var
TableID: Integer;
begin
case Type of
Type::Resource:
exit(Database::Resource);
Type::Item:
exit(Database::Item);
Type::"G/L Account":
exit(Database::"G/L Account");
else begin
OnTypeToTableID2(TableID, Type);
exit(TableID);
end;
end;
end;
/// <summary>
/// Converts a sales line type enum to its corresponding table ID for dimension processing.
/// Maps sales line types to their master data table IDs for default dimension handling.
/// </summary>
/// <param name="LineType">Sales line type enum specifying the type of line item</param>
/// <returns>Table ID corresponding to the specified sales line type, zero for blank lines</returns>
procedure SalesLineTypeToTableID(LineType: Enum "Sales Line Type") TableId: Integer
begin
case LineType of
"Sales Line Type"::" ":
exit(0);
"Sales Line Type"::"G/L Account":
exit(Database::"G/L Account");
"Sales Line Type"::Item:
exit(Database::Item);
"Sales Line Type"::Resource:
exit(Database::Resource);
"Sales Line Type"::"Fixed Asset":
exit(Database::"Fixed Asset");
"Sales Line Type"::"Charge (Item)":
exit(Database::"Item Charge");
end;
OnAfterSalesLineTypeToTableID(LineType, TableId);
end;
/// <summary>
/// Converts a purchase line type enum to its corresponding table ID for dimension processing.
/// Maps purchase line types to their master data table IDs for default dimension handling.
/// </summary>
/// <param name="LineType">Purchase line type enum specifying the type of line item</param>
/// <returns>Table ID corresponding to the specified purchase line type, zero for blank lines</returns>
procedure PurchLineTypeToTableID(LineType: Enum "Purchase Line Type") TableId: Integer
begin
case LineType of
"Purchase Line Type"::" ":
exit(0);
"Purchase Line Type"::"G/L Account":
exit(Database::"G/L Account");
"Purchase Line Type"::Item:
exit(Database::Item);
"Purchase Line Type"::Resource:
exit(Database::Resource);
"Purchase Line Type"::"Fixed Asset":
exit(Database::"Fixed Asset");
"Purchase Line Type"::"Charge (Item)":
exit(Database::"Item Charge");
end;
OnAfterPurchLineTypeToTableID(LineType, TableId);
end;
/// <summary>
/// Converts a requisition line type enum to its corresponding table ID for dimension processing.
/// Maps requisition line types to their master data table IDs for default dimension handling.
/// </summary>
/// <param name="LineType">Requisition line type enum specifying the type of line item</param>
/// <returns>Table ID corresponding to the specified requisition line type, zero for blank lines</returns>
procedure ReqLineTypeToTableID(LineType: Enum "Requisition Line Type") TableId: Integer
begin
case LineType of
"Requisition Line Type"::" ":
exit(0);
"Requisition Line Type"::"G/L Account":
exit(Database::"G/L Account");
"Requisition Line Type"::Item:
exit(Database::Item);
end;
OnAfterReqLineTypeToTableID(LineType, TableId);
end;
/// <summary>
/// Converts a basic item/resource type option to its corresponding table ID for dimension processing.
/// Maps item and resource types to their table IDs for default dimension handling.
/// </summary>
/// <param name="Type">Type option containing blank, Item, or Resource</param>
/// <returns>Table ID corresponding to the specified type, zero for blank type</returns>
procedure TypeToTableID4(Type: Option " ",Item,Resource) TableId: Integer
begin
case Type of
Type::" ":
exit(0);
Type::Item:
exit(Database::Item);
Type::Resource:
exit(Database::Resource);
end;
OnAfterTypeToTableID4(Type, TableId);
end;
/// <summary>
/// Deletes all default dimensions for a specific table and record number.
/// </summary>
/// <param name="TableID">ID of the table to delete default dimensions for</param>
/// <param name="No">Record number to delete default dimensions for</param>
procedure DeleteDefaultDim(TableID: Integer; No: Code[20])
var
DefaultDim: Record "Default Dimension";
begin
DefaultDim.SetRange("Table ID", TableID);
DefaultDim.SetRange("No.", No);
if not DefaultDim.IsEmpty() then
DefaultDim.DeleteAll();
OnAfterDeleteDefaultDim(TableID, No);
end;
/// <summary>
/// Renames default dimensions from old record number to new record number for a specific table.
/// </summary>
/// <param name="TableID">ID of the table containing the records being renamed</param>
/// <param name="OldNo">Original record number with default dimensions</param>
/// <param name="NewNo">New record number to transfer default dimensions to</param>
procedure RenameDefaultDim(TableID: Integer; OldNo: Code[20]; NewNo: Code[20])
var
DefaultDim: Record "Default Dimension";
DefaultDimToRename: Record "Default Dimension";
begin
DefaultDim.SetRange("Table ID", TableID);
DefaultDim.SetRange("No.", OldNo);
if DefaultDim.FindSet(true) then
repeat
DefaultDimToRename := DefaultDim;
DefaultDimToRename.Rename(DefaultDim."Table ID", NewNo, DefaultDim."Dimension Code");
until DefaultDim.Next() = 0;
end;
/// <summary>
/// Opens a lookup window for dimension values for a specific shortcut dimension field.
/// </summary>
/// <param name="FieldNumber">Shortcut dimension field number (1-8) to lookup values for</param>
/// <param name="ShortcutDimCode">Dimension value code that will be set if user selects a value</param>
procedure LookupDimValueCode(FieldNumber: Integer; var ShortcutDimCode: Code[20])
var
DimVal: Record "Dimension Value";
GLSetup: Record "General Ledger Setup";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeLookupDimValueCode(FieldNumber, ShortcutDimCode, IsHandled);
if IsHandled then
exit;
GetGLSetup(GLSetupShortcutDimCode);
if GLSetupShortcutDimCode[FieldNumber] = '' then
Error(ShortcutDimensionNotDefinedErr, GLSetup.TableCaption(), FieldNumber);
DimVal.SetRange("Dimension Code", GLSetupShortcutDimCode[FieldNumber]);
DimVal."Dimension Code" := GLSetupShortcutDimCode[FieldNumber];
DimVal.Code := ShortcutDimCode;
OnLookupDimValueCodeOnBeforeDimValRunModal(DimVal, FieldNumber);
if PAGE.RunModal(0, DimVal) = ACTION::LookupOK then begin
CheckDim(DimVal."Dimension Code");
CheckDimValue(DimVal."Dimension Code", DimVal.Code);
ShortcutDimCode := DimVal.Code;
end;
end;
/// <summary>
/// Validates a dimension value code for a specific shortcut dimension field and resolves partial matches.
/// </summary>
/// <param name="FieldNumber">Shortcut dimension field number (1-8) to validate for</param>
/// <param name="ShortcutDimCode">Dimension value code to validate; may be updated with exact match</param>
procedure ValidateDimValueCode(FieldNumber: Integer; var ShortcutDimCode: Code[20])
var
DimVal: Record "Dimension Value";
GLSetup: Record "General Ledger Setup";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeValidateDimValueCode(FieldNumber, ShortcutDimCode, IsHandled, GLSetupShortcutDimCode, DimVal);
if not IsHandled then begin
GetGLSetup(GLSetupShortcutDimCode);
if (GLSetupShortcutDimCode[FieldNumber] = '') and (ShortcutDimCode <> '') then
Error(ShortcutDimensionNotDefinedErr, GLSetup.TableCaption(), FieldNumber);
DimVal.SetRange("Dimension Code", GLSetupShortcutDimCode[FieldNumber]);
if ShortcutDimCode <> '' then begin
DimVal.SetRange(Code, ShortcutDimCode);
if not DimVal.FindFirst() then begin
DimVal.SetFilter(Code, StrSubstNo('%1*', ShortcutDimCode));
if DimVal.FindFirst() then
ShortcutDimCode := DimVal.Code
else
Error(
Text003,
ShortcutDimCode, DimVal.FieldCaption(Code));
end;
end;
end;
OnAfterValidateDimValueCode(FieldNumber, ShortcutDimCode, GLSetupShortcutDimCode, DimVal);
end;
/// <summary>
/// Validates a shortcut dimension value and updates the dimension set ID with the new value.
/// </summary>
/// <param name="FieldNumber">Shortcut dimension field number (1-8) to validate</param>
/// <param name="ShortcutDimCode">Dimension value code to validate and set</param>
/// <param name="DimSetID">Dimension set ID to update with the validated dimension value</param>
procedure ValidateShortcutDimValues(FieldNumber: Integer; var ShortcutDimCode: Code[20]; var DimSetID: Integer)
var
DimVal: Record "Dimension Value";
TempDimSetEntry: Record "Dimension Set Entry" temporary;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeValidateShortcutDimValues(DimVal, FieldNumber, ShortcutDimCode, DimSetID, IsHandled);
if IsHandled then
exit;
ValidateDimValueCode(FieldNumber, ShortcutDimCode);
DimVal."Dimension Code" := GLSetupShortcutDimCode[FieldNumber];
if ShortcutDimCode <> '' then begin
DimVal.Get(DimVal."Dimension Code", ShortcutDimCode);
if not CheckDim(DimVal."Dimension Code") then
Error(GetDimErr());
if not CheckDimValue(DimVal."Dimension Code", ShortcutDimCode) then
Error(GetDimErr());
end;
GetDimensionSet(TempDimSetEntry, DimSetID);
if TempDimSetEntry.Get(TempDimSetEntry."Dimension Set ID", DimVal."Dimension Code") then
if TempDimSetEntry."Dimension Value Code" <> ShortcutDimCode then
TempDimSetEntry.Delete();
if ShortcutDimCode <> '' then begin
TempDimSetEntry."Dimension Code" := DimVal."Dimension Code";
TempDimSetEntry."Dimension Value Code" := DimVal.Code;
TempDimSetEntry."Dimension Value ID" := DimVal."Dimension Value ID";
if TempDimSetEntry.Insert() then;
end;
DimSetID := GetDimensionSetID(TempDimSetEntry);
OnAfterValidateShortcutDimValues(FieldNumber, ShortcutDimCode, DimSetID);
end;
/// <summary>
/// Saves a default dimension value for a specific table record and shortcut dimension field.
/// </summary>
/// <param name="TableID">ID of the table to save default dimension for</param>
/// <param name="No">Record number to save default dimension for</param>
/// <param name="FieldNumber">Shortcut dimension field number (1-8) to save</param>
/// <param name="ShortcutDimCode">Dimension value code to save as default; empty value deletes existing default</param>
procedure SaveDefaultDim(TableID: Integer; No: Code[20]; FieldNumber: Integer; ShortcutDimCode: Code[20])
var
DefaultDim: Record "Default Dimension";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSaveDefaultDim(TableID, No, FieldNumber, ShortcutDimCode, IsHandled);
if IsHandled then
exit;
GetGLSetup(GLSetupShortcutDimCode);
if ShortcutDimCode <> '' then begin
if DefaultDim.Get(TableID, No, GLSetupShortcutDimCode[FieldNumber])
then begin
DefaultDim.Validate("Dimension Value Code", ShortcutDimCode);
DefaultDim.Modify();
end else begin
DefaultDim.Init();
DefaultDim.Validate("Table ID", TableID);
DefaultDim.Validate("No.", No);
DefaultDim.Validate("Dimension Code", GLSetupShortcutDimCode[FieldNumber]);
DefaultDim.Validate("Dimension Value Code", ShortcutDimCode);
DefaultDim.Insert();
end;
end else
if DefaultDim.Get(TableID, No, GLSetupShortcutDimCode[FieldNumber]) then
DefaultDim.Delete();
end;
/// <summary>
/// Retrieves global dimension values for all 8 shortcut dimension fields from a dimension set.
/// </summary>
/// <param name="DimSetID">Dimension set ID to retrieve values from</param>
/// <param name="ShortcutDimCode">Array to populate with dimension values for fields 1-8</param>
procedure GetGlobalDimensions(DimSetID: Integer; var ShortcutDimCode: array[8] of Code[20])
var
GetShortcutDimensionValues: Codeunit "Get Shortcut Dimension Values";
begin
GetShortcutDimensionValues.GetGlobalDimensions(DimSetID, ShortcutDimCode);
end;
/// <summary>
/// Retrieves shortcut dimension values for all 8 fields from a dimension set.
/// </summary>
/// <param name="DimSetID">Dimension set ID to retrieve values from</param>
/// <param name="ShortcutDimCode">Array to populate with dimension values for fields 1-8</param>
procedure GetShortcutDimensions(DimSetID: Integer; var ShortcutDimCode: array[8] of Code[20])
var
GetShortcutDimensionValues: Codeunit "Get Shortcut Dimension Values";
begin
GetShortcutDimensionValues.GetShortcutDimensions(DimSetID, ShortcutDimCode);
end;
/// <summary>
/// Validates dimension buffer values against posting restrictions and default dimension rules.
/// </summary>
/// <param name="DimBuffer">Dimension buffer containing values to validate</param>
/// <param name="TableID">Array of table IDs to check default dimension rules for</param>
/// <param name="No">Array of record numbers corresponding to table IDs</param>
/// <returns>True if all dimension values are valid for posting, false otherwise</returns>
procedure CheckDimBufferValuePosting(var DimBuffer: Record "Dimension Buffer"; TableID: array[10] of Integer; No: array[10] of Code[20]): Boolean
var
TempDimBuf: Record "Dimension Buffer" temporary;
i: Integer;
begin
if DimBuffer.FindSet() then begin
i := 1;
repeat
if (not CheckDimValue(
DimBuffer."Dimension Code", DimBuffer."Dimension Value Code")) or
(not CheckDim(DimBuffer."Dimension Code"))
then
exit(false);
TempDimBuf.Init();
TempDimBuf."Entry No." := i;
TempDimBuf."Dimension Code" := DimBuffer."Dimension Code";
TempDimBuf."Dimension Value Code" := DimBuffer."Dimension Value Code";
TempDimBuf.Insert();
i := i + 1;
until DimBuffer.Next() = 0;
end;
exit(CheckValuePosting(TableID, No, TempDimBuf));
end;
local procedure CheckValuePosting(TableID: array[10] of Integer; No: array[10] of Code[20]; var TempDimBuf: Record "Dimension Buffer" temporary): Boolean
var
DefaultDim: Record "Default Dimension";
i: Integer;
j: Integer;
NoFilter: array[2] of Text[250];
IsChecked: Boolean;
IsHandled: Boolean;
begin
IsChecked := false;
IsHandled := false;
OnBeforeCheckValuePosting(TableID, No, TempDimBuf, IsChecked, IsHandled);
if IsHandled then
exit(IsChecked);
DefaultDim.SetFilter("Value Posting", '<>%1', DefaultDim."Value Posting"::" ");
NoFilter[2] := '';
for i := 1 to ArrayLen(TableID) do
if (TableID[i] <> 0) and (No[i] <> '') then begin
DefaultDim.SetRange("Table ID", TableID[i]);
NoFilter[1] := No[i];
for j := 1 to 2 do begin
DefaultDim.SetRange("No.", NoFilter[j]);
if DefaultDim.FindSet() then begin
repeat
TempDimBuf.SetRange("Dimension Code", DefaultDim."Dimension Code");
case DefaultDim."Value Posting" of
DefaultDim."Value Posting"::"Code Mandatory":
if (not TempDimBuf.FindFirst()) or (TempDimBuf."Dimension Value Code" = '') then begin
LogError(
DefaultDim.RecordId, DefaultDim.FieldNo("Value Posting"), GetMissedMandatoryDimErr(DefaultDim), '');
exit(false);
end;
DefaultDim."Value Posting"::"Same Code":
if DefaultDim."Dimension Value Code" <> '' then
if TempDimBuf.FindFirst() then begin
if DefaultDim."Dimension Value Code" <> TempDimBuf."Dimension Value Code" then begin
LogSameCodeWrongDimOrNoCodeErr(DefaultDim, TempDimBuf."Dimension Value Code", DefaultDim."Dimension Value Code");
exit(false);
end;
end
else begin
LogSameCodeMissingDimErr(DefaultDim);
exit(false);
end
else
if TempDimBuf.FindFirst() then begin
LogError(
DefaultDim.RecordId, DefaultDim.FieldNo("Value Posting"), GetSameCodeBlankDimErr(DefaultDim), '');
exit(false);
end;
DefaultDim."Value Posting"::"No Code":
if TempDimBuf.FindFirst() then begin
LogSameCodeWrongDimOrNoCodeErr(DefaultDim, TempDimBuf."Dimension Value Code", BlankValueLbl);
exit(false);
end;
end;
OnCheckValuePostingOnAfterDefaultDimLoop(TempDimBuf, DefaultDim);
until DefaultDim.Next() = 0;
TempDimBuf.Reset();
end;
end;
end;
OnCheckValuePostingOnBeforeExit(TableID, No, TempDimBuf, LastErrorMessage, ErrorMessageMgt, IsChecked, IsHandled);
if IsHandled then
exit(IsChecked);
exit(true);
end;
/// <summary>
/// Retrieves the last dimension value posting error message.
/// </summary>
/// <returns>Error message text describing the dimension value posting issue</returns>
procedure GetDimValuePostingErr() ErrorMessage: Text[250]
begin
FindLastErrorMessage(ErrorMessage);
end;
/// <summary>
/// Populates a temporary table with object numbers that support default dimensions.
/// </summary>
/// <param name="TempAllObjWithCaption">Temporary record to populate with objects that can have default dimensions</param>
procedure DefaultDimObjectNoList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
begin
DefaultDimObjectNoWithoutGlobalDimsList(TempAllObjWithCaption);
DefaultDimObjectNoWithGlobalDimsList(TempAllObjWithCaption);
OnAfterDefaultDimObjectNoList(TempAllObjWithCaption);
end;
/// <summary>
/// Populates a temporary table with object numbers that support default dimensions and have global dimensions.
/// </summary>
/// <param name="TempAllObjWithCaption">Temporary record to populate with objects that can have default dimensions with global dimension support</param>
procedure DefaultDimObjectNoWithGlobalDimsList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
var
TempDimField: Record "Field" temporary;
TempDimSetIDField: Record "Field" temporary;
begin
TempDimField.SetFilter(
TableNo, '<>%1&<>%2&<>%3',
Database::"General Ledger Setup", Database::"Job Task", Database::"Change Global Dim. Header");
TempDimField.SetFilter(ObsoleteState, '<>%1', TempDimField.ObsoleteState::Removed);
TempDimField.SetFilter(FieldName, '*Global Dimension*');
TempDimField.SetRange(Type, TempDimField.Type::Code);
TempDimField.SetRange(Len, 20);
FillNormalFieldBuffer(TempDimField);
TempDimSetIDField.SetRange(RelationTableNo, Database::"Dimension Set Entry");
FillNormalFieldBuffer(TempDimSetIDField);
OnBeforeSetupObjectNoList(TempDimField);
if TempDimField.FindSet() then
repeat
TempDimSetIDField.SetRange(TableNo, TempDimField.TableNo);
if TempDimSetIDField.IsEmpty() then
DefaultDimInsertTempObject(TempAllObjWithCaption, TempDimField.TableNo);
until TempDimField.Next() = 0;
OnAfterSetupObjectNoList(TempAllObjWithCaption);
end;
local procedure DefaultDimObjectNoWithoutGlobalDimsList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
begin
DefaultDimInsertTempObject(TempAllObjWithCaption, Database::"IC Partner");
DefaultDimInsertTempObject(TempAllObjWithCaption, Database::Location);
OnAfterDefaultDimObjectNoWithoutGlobalDimsList(TempAllObjWithCaption);
end;
/// <summary>
/// Inserts a temporary object record for tables that support default dimensions.
/// </summary>
/// <param name="TempAllObjWithCaption">Temporary record to insert the object information into</param>
/// <param name="TableID">Table ID to check and insert if it supports default dimensions</param>
procedure DefaultDimInsertTempObject(var TempAllObjWithCaption: Record AllObjWithCaption temporary; TableID: Integer)
begin
if IsObsolete(TableID) then
exit;
if KeyContainsOneCodeField(TableID) or IsDefaultDimTable(TableID) then
InsertObject(TempAllObjWithCaption, TableID);
end;
local procedure IsDefaultDimTable(TableID: Integer) Result: Boolean
begin
// Local versions should add exceptions here
Result := TableID = 0;
OnAfterIsDefaultDimTable(TableID, Result);
end;
local procedure KeyContainsOneCodeField(TableID: Integer) Result: Boolean
var
FieldRef: FieldRef;
KeyRef: KeyRef;
RecRef: RecordRef;
begin
RecRef.Open(TableID);
KeyRef := RecRef.KeyIndex(1);
FieldRef := KeyRef.FieldIndex(1);
Result := (KeyRef.FieldCount = 1) and (FieldRef.Type = FieldType::Code);
RecRef.Close();
end;
/// <summary>
/// Populates a temporary table with object numbers that support global dimensions.
/// </summary>
/// <param name="TempAllObjWithCaption">Temporary record to populate with objects that support global dimension fields</param>
procedure GlobalDimObjectNoList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
var
"Field": Record "Field";
TempDimField: Record "Field" temporary;
TempDimSetIDField: Record "Field" temporary;
LastTableNo: Integer;
begin
TempDimSetIDField.SetRange(RelationTableNo, Database::"Dimension Set Entry");
FillNormalFieldBuffer(TempDimSetIDField);
TempDimField.SetFilter(FieldName, '*Global Dimension*|*Shortcut Dimension*|*Global Dim.*');
TempDimField.SetFilter(ObsoleteState, '<>%1', TempDimField.ObsoleteState::Removed);
TempDimField.SetRange(Type, TempDimField.Type::Code);
TempDimField.SetRange(Len, 20);
FillNormalFieldBuffer(TempDimField);
TempDimField.Reset();
if TempDimSetIDField.FindSet() then
repeat
TempDimField.SetRange(TableNo, TempDimSetIDField.TableNo);
if not TempDimField.IsEmpty() then begin
InsertObject(TempAllObjWithCaption, TempDimSetIDField.TableNo);
TempDimField.DeleteAll();
end;
until TempDimSetIDField.Next() = 0;
TempDimField.Reset();
TempDimField.SetFilter(ObsoleteState, '<>%1', TempDimField.ObsoleteState::Removed);
TempDimField.SetFilter(FieldName, '*Global Dim.*');
if TempDimField.FindSet() then
repeat
if LastTableNo <> TempDimField.TableNo then begin
LastTableNo := TempDimField.TableNo;
// Field No. 2 must relate to a table with Dim Set ID
if Field.Get(TempDimField.TableNo, 2) then begin
TempDimSetIDField.SetRange(TableNo, Field.RelationTableNo);
if not TempDimSetIDField.IsEmpty() then
InsertObject(TempAllObjWithCaption, TempDimField.TableNo);
end;
end;
until TempDimField.Next() = 0;
end;
/// <summary>
/// Populates a temporary table with job task object numbers that support dimensions.
/// </summary>
/// <param name="TempAllObjWithCaption">Temporary record to populate with job task objects that support dimension handling</param>
procedure JobTaskDimObjectNoList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
begin
// Table 1001 "Job Task" is an exception
// it has Table 1002 "Job Task Dimension" that implements default dimension behavior
InsertObject(TempAllObjWithCaption, Database::"Job Task");
end;
/// <summary>
/// Searches for dimension fields in a specific table using a field name filter.
/// </summary>
/// <param name="TableNo">Table number to search for dimension fields</param>
/// <param name="FieldNameFilter">Filter text to match against field names</param>
/// <param name="Field">Field record that will contain the found dimension field</param>
/// <returns>True if a dimension field matching the filter is found, false otherwise</returns>
procedure FindDimFieldInTable(TableNo: Integer; FieldNameFilter: Text; var "Field": Record "Field"): Boolean
begin
if IsObsolete(TableNo) then
exit(false);
Field.SetRange(TableNo, TableNo);
Field.SetFilter(FieldName, '*' + FieldNameFilter + '*');
Field.SetFilter(ObsoleteState, '<>%1', Field.ObsoleteState::Removed);
Field.SetRange(Class, Field.Class::Normal);
Field.SetRange(Type, Field.Type::Code);
Field.SetRange(Len, 20);
if Field.FindFirst() then
exit(true);
end;
local procedure FillNormalFieldBuffer(var TempField: Record "Field")
var
"Field": Record "Field";
begin
Field.CopyFilters(TempField);
Field.SetRange(Class, Field.Class::Normal);
Field.SetFilter(ObsoleteState, '<>%1', Field.ObsoleteState::Removed);
if Field.FindSet() then
repeat
if not IsObsolete(Field.TableNo) then begin
TempField := Field;
TempField.Insert();
end;
until Field.Next() = 0;
end;
/// <summary>
/// Retrieves the last document dimension consistency error message.
/// </summary>
/// <returns>Error message text describing the document dimension consistency issue</returns>
procedure GetDocDimConsistencyErr() ErrorMessage: Text[250]
begin
FindLastErrorMessage(ErrorMessage);
end;
/// <summary>
/// Validates that a dimension code exists and is not blocked.
/// </summary>
/// <param name="DimCode">Dimension code to validate</param>
/// <returns>True if the dimension is valid and not blocked, false otherwise</returns>
procedure CheckDim(DimCode: Code[20]): Boolean
var
Dim: Record Dimension;
IsHandled: Boolean;
Result: Boolean;
begin
IsHandled := false;
OnBeforeCheckDim(DimCode, Result, IsHandled, Dim);
if IsHandled then
exit(Result);
if Dim.Get(DimCode) then begin
if Dim.Blocked then begin
LogError(
Dim.RecordId, Dim.FieldNo(Blocked), StrSubstNo(Text014, Dim.TableCaption(), DimCode), '');
exit(false);
end;
end else begin
LogError(
Database::Dimension, 0, StrSubstNo(Text015, Dim.TableCaption(), DimCode), '');
exit(false);
end;
exit(true);
end;
/// <summary>
/// Validates that a dimension value exists and is not blocked for the specified dimension.
/// </summary>
/// <param name="DimCode">Dimension code to validate the value against</param>
/// <param name="DimValCode">Dimension value code to validate</param>
/// <returns>True if the dimension value is valid and not blocked, false otherwise</returns>
procedure CheckDimValue(DimCode: Code[20]; DimValCode: Code[20]) Result: Boolean
var
DimVal: Record "Dimension Value";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCheckDimValue(DimCode, DimValCode, Result, IsHandled, DimVal);
if not IsHandled then begin
if (DimCode <> '') and (DimValCode <> '') then
if DimVal.Get(DimCode, DimValCode) then begin
IsHandled := false;
OnCheckDimValueOnBeforeCheckDimValBlocked(DimCode, DimValCode, Result, IsHandled, DimVal);
if not IsHandled then
if DimVal.Blocked then begin
LogError(
DimVal.RecordId, DimVal.FieldNo(Blocked),
StrSubstNo(DimValueBlockedErr, DimVal.TableCaption(), DimCode, DimValCode), '');
exit(false);
end;
if not CheckDimValueAllowed(DimVal) then
exit(false);
end else begin
LogError(
Database::"Dimension Value", 0,
StrSubstNo(DimValueMissingErr, DimVal.TableCaption(), DimCode, DimValCode), '');
exit(false);
end;
Result := true;
end;
OnAfterCheckDimValue(DimCode, DimValCode, Result);
end;
local procedure CheckDimValueAllowed(DimVal: Record "Dimension Value") Result: Boolean
var
DimValueAllowed: Boolean;
DimErr: Text[250];
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCheckDimValueAllowed(DimVal, IsHandled, Result);
if IsHandled then
exit(Result);
DimValueAllowed :=
(DimVal."Dimension Value Type" in [DimVal."Dimension Value Type"::Standard, DimVal."Dimension Value Type"::"Begin-Total"]);
if not DimValueAllowed then
DimErr :=
StrSubstNo(
DimValueMustNotBeErr, DimVal.TableCaption(), DimVal."Dimension Code", DimVal.Code, Format(DimVal."Dimension Value Type"))
else
OnCheckDimValueAllowed(DimVal, DimValueAllowed, DimErr);
if not DimValueAllowed then
LogError(DimVal.RecordId, DimVal.FieldNo("Dimension Value Type"), DimErr, '');
exit(DimValueAllowed);
end;
/// <summary>
/// Validates that dimensions and dimension values in a dimension set are not blocked.
/// </summary>
/// <param name="DimSetID">Dimension set ID to validate for blocked dimensions and values</param>
/// <returns>True if no blocked dimensions or values are found, false otherwise</returns>
procedure CheckBlockedDimAndValues(DimSetID: Integer): Boolean
var
DimSetEntry: Record "Dimension Set Entry";
LastErrorID: Integer;
begin
if DimSetID = 0 then
exit(true);
LastErrorID := GetLastDimErrorID();
DimSetEntry.Reset();
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
if DimSetEntry.FindSet() then
repeat
if not CheckDim(DimSetEntry."Dimension Code") or
not CheckDimValue(DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code")
then
if not IsCollectErrorsMode then
exit(false);
until DimSetEntry.Next() = 0;
exit(GetLastDimErrorID() = LastErrorID);
end;
/// <summary>
/// Retrieves the last dimension error message.
/// </summary>
/// <returns>Error message text describing the dimension validation issue</returns>
procedure GetDimErr() ErrorMessage: Text[250]
begin
FindLastErrorMessage(ErrorMessage);
end;
/// <summary>
/// Logs a dimension error for a specific source record and field.
/// </summary>
/// <param name="SourceRecVariant">Source record variant where the error occurred</param>
/// <param name="SourceFieldNo">Field number where the error occurred</param>
/// <param name="Message">Error message to log</param>
/// <param name="HelpArticleCode">Help article code for additional guidance</param>
/// <returns>True if the error was successfully logged, false otherwise</returns>
procedure LogError(SourceRecVariant: Variant; SourceFieldNo: Integer; Message: Text; HelpArticleCode: Code[30]) IsLogged: Boolean
var
ForwardLinkMgt: Codeunit "Forward Link Mgt.";
begin
if ErrorMessageMgt.IsActive() then begin
if HelpArticleCode = '' then
HelpArticleCode := ForwardLinkMgt.GetHelpCodeForWorkingWithDimensions();
ErrorMessageMgt.LogContextFieldError(0, Message, SourceRecVariant, SourceFieldNo, HelpArticleCode);
IsLogged := true;
end else begin
LastErrorMessage.Init();
LastErrorMessage.ID += 1;
LastErrorMessage."Message" := CopyStr(Message, 1, MaxStrLen(LastErrorMessage."Message"));
IsLogged := false;
end;
end;
/// <summary>
/// Opens dimension value lookup dialog for a specified shortcut dimension field without updating the source record.
/// Validates that the shortcut dimension is properly configured before showing the lookup.
/// </summary>
/// <param name="FieldNumber">Shortcut dimension field number (1-8) to lookup values for</param>
procedure LookupDimValueCodeNoUpdate(FieldNumber: Integer)
var
DimVal: Record "Dimension Value";
GLSetup: Record "General Ledger Setup";
begin
OnBeforeLookupDimValueCodeNoUpdate(FieldNumber);
GetGLSetup(GLSetupShortcutDimCode);
if GLSetupShortcutDimCode[FieldNumber] = '' then
Error(ShortcutDimensionNotDefinedErr, GLSetup.TableCaption(), FieldNumber);
DimVal.SetRange("Dimension Code", GLSetupShortcutDimCode[FieldNumber]);
if PAGE.RunModal(0, DimVal) = ACTION::LookupOK then;
end;
/// <summary>
/// Copies dimension set entries from journal lines to intercompany journal line dimensions.
/// Converts company-specific dimension codes to intercompany dimension codes during the copy process.
/// </summary>
/// <param name="TableID">Source table identifier for the journal line</param>
/// <param name="TransactionNo">Intercompany transaction number</param>
/// <param name="PartnerCode">Intercompany partner code</param>
/// <param name="TransactionSource">Source of the intercompany transaction</param>
/// <param name="LineNo">Line number within the transaction</param>
/// <param name="DimSetID">Dimension set ID containing dimensions to copy</param>
procedure CopyJnlLineDimToICJnlDim(TableID: Integer; TransactionNo: Integer; PartnerCode: Code[20]; TransactionSource: Option; LineNo: Integer; DimSetID: Integer)
var
InOutBoxJnlLineDim: Record "IC Inbox/Outbox Jnl. Line Dim.";
DimSetEntry: Record "Dimension Set Entry";
ICDim: Code[20];
ICDimValue: Code[20];
begin
DimSetEntry.SetRange("Dimension Set ID", DimSetID);
if DimSetEntry.FindSet() then
repeat
ICDim := ConvertDimtoICDim(DimSetEntry."Dimension Code");
ICDimValue := ConvertDimValuetoICDimVal(DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code");
if (ICDim <> '') and (ICDimValue <> '') then begin
InOutBoxJnlLineDim.Init();
InOutBoxJnlLineDim."Table ID" := TableID;
InOutBoxJnlLineDim."IC Partner Code" := PartnerCode;
InOutBoxJnlLineDim."Transaction No." := TransactionNo;
InOutBoxJnlLineDim."Transaction Source" := TransactionSource;
InOutBoxJnlLineDim."Line No." := LineNo;
InOutBoxJnlLineDim."Dimension Code" := ICDim;
InOutBoxJnlLineDim."Dimension Value Code" := ICDimValue;
InOutBoxJnlLineDim.Insert();
end;
until DimSetEntry.Next() = 0;
end;
/// <summary>
/// Handles default dimension setup when a new default dimension is inserted.
/// Updates related job task dimensions and cost types when applicable.
/// </summary>
/// <param name="DefaultDimension">Default dimension record being inserted</param>
procedure DefaultDimOnInsert(DefaultDimension: Record "Default Dimension")
var
CallingTrigger: Option OnInsert,OnModify,OnDelete;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeDefaultDimOnInsert(DefaultDimension, IsHandled);
if IsHandled then
exit;
if DefaultDimension."Table ID" = Database::Job then
UpdateJobTaskDim(DefaultDimension, false);
UpdateCostType(DefaultDimension, CallingTrigger::OnInsert);
end;
/// <summary>
/// Handles default dimension changes when an existing default dimension is modified.
/// Updates related job task dimensions and cost types to reflect the changes.
/// </summary>
/// <param name="DefaultDimension">Default dimension record being modified</param>
procedure DefaultDimOnModify(DefaultDimension: Record "Default Dimension")
var
CallingTrigger: Option OnInsert,OnModify,OnDelete;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeDefaultDimOnModify(DefaultDimension, IsHandled);
if IsHandled then
exit;
if DefaultDimension."Table ID" = Database::Job then
UpdateJobTaskDim(DefaultDimension, false);
UpdateCostType(DefaultDimension, CallingTrigger::OnModify);
end;
/// <summary>
/// Handles default dimension cleanup when a default dimension is deleted.
/// Removes related job task dimensions and updates cost types accordingly.
/// </summary>
/// <param name="DefaultDimension">Default dimension record being deleted</param>
procedure DefaultDimOnDelete(DefaultDimension: Record "Default Dimension")
var
CallingTrigger: Option OnInsert,OnModify,OnDelete;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeDefaultDimOnDelete(DefaultDimension, IsHandled);
if IsHandled then
exit;
if DefaultDimension."Table ID" = Database::Job then
UpdateJobTaskDim(DefaultDimension, true);
UpdateCostType(DefaultDimension, CallingTrigger::OnDelete);
end;
/// <summary>
/// Copies intercompany journal line dimensions from one record set to another.
/// Creates duplicate dimension entries for intercompany transaction processing.
/// </summary>
/// <param name="FromInOutBoxLineDim">Source intercompany journal line dimensions to copy from</param>
/// <param name="ToInOutBoxlineDim">Target intercompany journal line dimensions to copy to</param>
procedure CopyICJnlDimToICJnlDim(var FromInOutBoxLineDim: Record "IC Inbox/Outbox Jnl. Line Dim."; var ToInOutBoxlineDim: Record "IC Inbox/Outbox Jnl. Line Dim.")
begin
if FromInOutBoxLineDim.FindSet() then
repeat
ToInOutBoxlineDim := FromInOutBoxLineDim;
ToInOutBoxlineDim.Insert();
until FromInOutBoxLineDim.Next() = 0;
end;
/// <summary>
/// Copies dimension set entries from documents to intercompany document dimensions.
/// Converts company-specific dimension codes to intercompany dimension codes for cross-company transactions.
/// </summary>
/// <param name="TableID">Source table identifier for the document</param>
/// <param name="TransactionNo">Intercompany transaction number</param>
/// <param name="PartnerCode">Intercompany partner code</param>
/// <param name="TransactionSource">Source of the intercompany transaction</param>
/// <param name="LineNo">Line number within the document</param>
/// <param name="DimSetEntryID">Dimension set ID containing dimensions to copy</param>
procedure CopyDocDimtoICDocDim(TableID: Integer; TransactionNo: Integer; PartnerCode: Code[20]; TransactionSource: Option; LineNo: Integer; DimSetEntryID: Integer)
var
InOutBoxDocDim: Record "IC Document Dimension";
DimSetEntry: Record "Dimension Set Entry";
ICDim: Code[20];
ICDimValue: Code[20];
begin
DimSetEntry.SetRange("Dimension Set ID", DimSetEntryID);
if DimSetEntry.FindSet() then
repeat
ICDim := ConvertDimtoICDim(DimSetEntry."Dimension Code");
ICDimValue := ConvertDimValuetoICDimVal(DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code");
if (ICDim <> '') and (ICDimValue <> '') then begin
InOutBoxDocDim.Init();
InOutBoxDocDim."Table ID" := TableID;
InOutBoxDocDim."IC Partner Code" := PartnerCode;
InOutBoxDocDim."Transaction No." := TransactionNo;
InOutBoxDocDim."Transaction Source" := TransactionSource;
InOutBoxDocDim."Line No." := LineNo;
InOutBoxDocDim."Dimension Code" := ICDim;
InOutBoxDocDim."Dimension Value Code" := ICDimValue;
InOutBoxDocDim.Insert();
end;
until DimSetEntry.Next() = 0;
end;
/// <summary>
/// Copies intercompany document dimensions from one record set to another with new table and transaction source.
/// Creates duplicate dimension entries for intercompany document processing across different table contexts.
/// </summary>
/// <param name="FromSourceICDocDim">Source intercompany document dimensions to copy from</param>
/// <param name="ToSourceICDocDim">Target intercompany document dimensions to copy to</param>
/// <param name="ToTableID">Target table identifier for the copied dimensions</param>
/// <param name="ToTransactionSource">Target transaction source for the copied dimensions</param>
procedure CopyICDocDimtoICDocDim(FromSourceICDocDim: Record "IC Document Dimension"; var ToSourceICDocDim: Record "IC Document Dimension"; ToTableID: Integer; ToTransactionSource: Integer)
begin
SetICDocDimFilters(FromSourceICDocDim, FromSourceICDocDim."Table ID", FromSourceICDocDim."Transaction No.", FromSourceICDocDim."IC Partner Code", FromSourceICDocDim."Transaction Source", FromSourceICDocDim."Line No.");
if FromSourceICDocDim.FindSet() then
repeat
ToSourceICDocDim := FromSourceICDocDim;
ToSourceICDocDim."Table ID" := ToTableID;
ToSourceICDocDim."Transaction Source" := ToTransactionSource;
ToSourceICDocDim.Insert();
until FromSourceICDocDim.Next() = 0;
end;
/// <summary>
/// Moves intercompany document dimensions from one record set to another with new table and transaction source.
/// Transfers dimension entries and deletes the source records during intercompany document processing.
/// </summary>
/// <param name="FromSourceICDocDim">Source intercompany document dimensions to move from</param>
/// <param name="ToSourceICDocDim">Target intercompany document dimensions to move to</param>
/// <param name="ToTableID">Target table identifier for the moved dimensions</param>
/// <param name="ToTransactionSource">Target transaction source for the moved dimensions</param>
procedure MoveICDocDimtoICDocDim(FromSourceICDocDim: Record "IC Document Dimension"; var ToSourceICDocDim: Record "IC Document Dimension"; ToTableID: Integer; ToTransactionSource: Integer)
begin
SetICDocDimFilters(FromSourceICDocDim, FromSourceICDocDim."Table ID", FromSourceICDocDim."Transaction No.", FromSourceICDocDim."IC Partner Code", FromSourceICDocDim."Transaction Source", FromSourceICDocDim."Line No.");
if FromSourceICDocDim.FindSet() then
repeat
ToSourceICDocDim := FromSourceICDocDim;
ToSourceICDocDim."Table ID" := ToTableID;
ToSourceICDocDim."Transaction Source" := ToTransactionSource;
ToSourceICDocDim.Insert();
FromSourceICDocDim.Delete();
until FromSourceICDocDim.Next() = 0;
end;
/// <summary>
/// Sets filters on intercompany document dimension record to isolate specific dimension entries.
/// Applies standard filters for table ID, transaction number, partner code, transaction source, and line number.
/// </summary>
/// <param name="ICDocDim">Intercompany document dimension record to apply filters to</param>
/// <param name="TableID">Table identifier to filter by</param>
/// <param name="TransactionNo">Transaction number to filter by</param>
/// <param name="PartnerCode">Intercompany partner code to filter by</param>
/// <param name="TransactionSource">Transaction source to filter by</param>
/// <param name="LineNo">Line number to filter by</param>
procedure SetICDocDimFilters(var ICDocDim: Record "IC Document Dimension"; TableID: Integer; TransactionNo: Integer; PartnerCode: Code[20]; TransactionSource: Integer; LineNo: Integer)
begin
ICDocDim.Reset();
ICDocDim.SetRange("Table ID", TableID);
ICDocDim.SetRange("Transaction No.", TransactionNo);
ICDocDim.SetRange("IC Partner Code", PartnerCode);
ICDocDim.SetRange("Transaction Source", TransactionSource);
ICDocDim.SetRange("Line No.", LineNo);
end;
/// <summary>
/// Deletes intercompany document dimensions that match the specified criteria.
/// Removes all dimension entries for a specific intercompany document transaction line.
/// </summary>
/// <param name="TableID">Table identifier to delete dimensions for</param>
/// <param name="ICTransactionNo">Intercompany transaction number</param>
/// <param name="ICPartnerCode">Intercompany partner code</param>
/// <param name="TransactionSource">Transaction source type</param>
/// <param name="LineNo">Line number within the transaction</param>
procedure DeleteICDocDim(TableID: Integer; ICTransactionNo: Integer; ICPartnerCode: Code[20]; TransactionSource: Option; LineNo: Integer)
var
ICDocDim: Record "IC Document Dimension";
begin
SetICDocDimFilters(ICDocDim, TableID, ICTransactionNo, ICPartnerCode, TransactionSource, LineNo);
if not ICDocDim.IsEmpty() then
ICDocDim.DeleteAll();
end;
/// <summary>
/// Deletes intercompany journal line dimensions that match the specified criteria.
/// Removes all dimension entries for a specific intercompany journal line transaction.
/// </summary>
/// <param name="TableID">Table identifier to delete dimensions for</param>
/// <param name="ICTransactionNo">Intercompany transaction number</param>
/// <param name="ICPartnerCode">Intercompany partner code</param>
/// <param name="TransactionSource">Transaction source type</param>
/// <param name="LineNo">Line number within the transaction</param>
procedure DeleteICJnlDim(TableID: Integer; ICTransactionNo: Integer; ICPartnerCode: Code[20]; TransactionSource: Option; LineNo: Integer)
var
ICJnlDim: Record "IC Inbox/Outbox Jnl. Line Dim.";
begin
ICJnlDim.SetRange("Table ID", TableID);
ICJnlDim.SetRange("Transaction No.", ICTransactionNo);
ICJnlDim.SetRange("IC Partner Code", ICPartnerCode);
ICJnlDim.SetRange("Transaction Source", TransactionSource);
ICJnlDim.SetRange("Line No.", LineNo);
if not ICJnlDim.IsEmpty() then
ICJnlDim.DeleteAll();
end;
local procedure ConvertICDimtoDim(FromICDimCode: Code[20]) DimCode: Code[20]
var
ICDim: Record "IC Dimension";
begin
if ICDim.Get(FromICDimCode) then
DimCode := ICDim."Map-to Dimension Code";
OnAfterConvertICDimtoDim(FromICDimCode, DimCode);
end;
local procedure ConvertICDimValuetoDimValue(FromICDimCode: Code[20]; FromICDimValue: Code[20]) DimValueCode: Code[20]
var
ICDimValue: Record "IC Dimension Value";
begin
if ICDimValue.Get(FromICDimCode, FromICDimValue) then
DimValueCode := ICDimValue."Map-to Dimension Value Code";
OnAfterConvertICDimValuetoDimValue(FromICDimCode, FromICDimValue, DimValueCode);
end;
/// <summary>
/// Converts a company-specific dimension code to its intercompany equivalent.
/// Uses the dimension's mapping configuration to return the corresponding IC dimension code.
/// </summary>
/// <param name="FromDim">Company dimension code to convert</param>
/// <returns>Mapped intercompany dimension code, or empty if no mapping exists</returns>
procedure ConvertDimtoICDim(FromDim: Code[20]) ICDimCode: Code[20]
var
Dim: Record Dimension;
begin
if Dim.Get(FromDim) then
ICDimCode := Dim."Map-to IC Dimension Code";
OnAfterConvertDimtoICDim(FromDim, ICDimCode);
end;
/// <summary>
/// Converts a company-specific dimension value to its intercompany equivalent.
/// Uses the dimension value's mapping configuration to return the corresponding IC dimension value code.
/// </summary>
/// <param name="FromDim">Company dimension code containing the value</param>
/// <param name="FromDimValue">Company dimension value code to convert</param>
/// <returns>Mapped intercompany dimension value code, or empty if no mapping exists</returns>
procedure ConvertDimValuetoICDimVal(FromDim: Code[20]; FromDimValue: Code[20]) ICDimValueCode: Code[20]
var
DimValue: Record "Dimension Value";
begin
OnBeforeConvertDimValuetoICDimVal(DimValue);
if DimValue.Get(FromDim, FromDimValue) then
ICDimValueCode := DimValue."Map-to IC Dimension Value Code";
OnAfterConvertDimValuetoICDimVal(FromDim, FromDimValue, ICDimValueCode);
end;
/// <summary>
/// Validates intercompany dimension value and checks if it exists and is not blocked.
/// Performs validation and logging for intercompany dimension value usage.
/// </summary>
/// <param name="ICDimCode">Intercompany dimension code to validate</param>
/// <param name="ICDimValCode">Intercompany dimension value code to validate</param>
/// <returns>True if the intercompany dimension value is valid and not blocked, false otherwise</returns>
procedure CheckICDimValue(ICDimCode: Code[20]; ICDimValCode: Code[20]): Boolean
var
ICDimVal: Record "IC Dimension Value";
IsHandled: Boolean;
Result: Boolean;
begin
Result := false;
IsHandled := false;
OnBeforeCheckICDimValue(ICDimCode, ICDimValCode, Result, IsHandled);
if IsHandled then
exit(Result);
if (ICDimCode <> '') and (ICDimValCode <> '') then
if ICDimVal.Get(ICDimCode, ICDimValCode) then begin
if ICDimVal.Blocked then begin
LogError(
ICDimVal.RecordId, ICDimVal.FieldNo(Blocked),
StrSubstNo(DimValueBlockedErr, ICDimVal.TableCaption(), ICDimCode, ICDimValCode), '');
exit(false);
end;
if not CheckICDimValueAllowed(ICDimVal) then begin
LogError(
ICDimVal.RecordId, ICDimVal.FieldNo("Dimension Value Type"),
StrSubstNo(
DimValueMustNotBeErr, ICDimVal.TableCaption(), ICDimCode, ICDimValCode,
Format(ICDimVal."Dimension Value Type")),
'');
exit(false);
end;
end else begin
LogError(
Database::"IC Dimension Value", 0,
StrSubstNo(DimValueMissingErr, ICDimVal.TableCaption(), ICDimCode, ICDimValCode), '');
exit(false);
end;
exit(true);
end;
local procedure CheckICDimValueAllowed(ICDimVal: Record "IC Dimension Value"): Boolean
var
DimValueAllowed: Boolean;
begin
DimValueAllowed :=
ICDimVal."Dimension Value Type" in [ICDimVal."Dimension Value Type"::Standard, ICDimVal."Dimension Value Type"::"Begin-Total"];
OnCheckICDimValueAllowed(ICDimVal, DimValueAllowed);
exit(DimValueAllowed);
end;
/// <summary>
/// Validates intercompany dimension and checks if it exists and is not blocked.
/// Performs validation and logging for intercompany dimension usage.
/// </summary>
/// <param name="ICDimCode">Intercompany dimension code to validate</param>
/// <returns>True if the intercompany dimension is valid and not blocked, false otherwise</returns>
procedure CheckICDim(ICDimCode: Code[20]): Boolean
var
ICDim: Record "IC Dimension";
IsHandled: Boolean;
Result: Boolean;
begin
Result := false;
IsHandled := false;
OnBeforeCheckICDim(ICDimCode, Result, IsHandled);
if IsHandled then
exit(Result);
if ICDim.Get(ICDimCode) then begin
if ICDim.Blocked then begin
LogError(
ICDim.RecordId, ICDim.FieldNo(Blocked), StrSubstNo(Text014, ICDim.TableCaption(), ICDimCode), '');
exit(false);
end;
end else begin
LogError(
Database::"IC Dimension", 0, StrSubstNo(Text015, ICDim.TableCaption(), ICDimCode), '');
exit(false);
end;
exit(true);
end;
/// <summary>
/// Saves or updates a job task dimension value for a specific shortcut dimension field.
/// Creates new job task dimension records or modifies existing ones based on field number and dimension code.
/// </summary>
/// <param name="JobNo">Job number to save dimension for</param>
/// <param name="JobTaskNo">Job task number to save dimension for</param>
/// <param name="FieldNumber">Shortcut dimension field number (1-8)</param>
/// <param name="ShortcutDimCode">Dimension value code to assign to the shortcut field</param>
procedure SaveJobTaskDim(JobNo: Code[20]; JobTaskNo: Code[20]; FieldNumber: Integer; ShortcutDimCode: Code[20])
var
JobTaskDim: Record "Job Task Dimension";
begin
GetGLSetup(GLSetupShortcutDimCode);
if ShortcutDimCode <> '' then begin
if JobTaskDim.Get(JobNo, JobTaskNo, GLSetupShortcutDimCode[FieldNumber])
then begin
JobTaskDim.Validate("Dimension Value Code", ShortcutDimCode);
JobTaskDim.Modify();
end else begin
JobTaskDim.Init();
JobTaskDim.Validate("Job No.", JobNo);
JobTaskDim.Validate("Job Task No.", JobTaskNo);
JobTaskDim.Validate("Dimension Code", GLSetupShortcutDimCode[FieldNumber]);
JobTaskDim.Validate("Dimension Value Code", ShortcutDimCode);
JobTaskDim.Insert();
end;
end else
if JobTaskDim.Get(JobNo, JobTaskNo, GLSetupShortcutDimCode[FieldNumber]) then
JobTaskDim.Delete();
end;
/// <summary>
/// Saves job task dimension value to temporary buffer for a specific shortcut dimension field.
/// Updates temporary dimension buffer with shortcut dimension values for later processing.
/// </summary>
/// <param name="FieldNumber">Shortcut dimension field number (1-8)</param>
/// <param name="ShortcutDimCode">Dimension value code to save to the temporary buffer</param>
procedure SaveJobTaskTempDim(FieldNumber: Integer; ShortcutDimCode: Code[20])
begin
GetGLSetup(GLSetupShortcutDimCode);
if ShortcutDimCode <> '' then begin
if TempJobTaskDimBuffer.Get('', '', GLSetupShortcutDimCode[FieldNumber])
then begin
TempJobTaskDimBuffer."Dimension Value Code" := ShortcutDimCode;
TempJobTaskDimBuffer.Modify();
end else begin
TempJobTaskDimBuffer.Init();
TempJobTaskDimBuffer."Dimension Code" := GLSetupShortcutDimCode[FieldNumber];
TempJobTaskDimBuffer."Dimension Value Code" := ShortcutDimCode;
TempJobTaskDimBuffer.Insert();
end;
end else
if TempJobTaskDimBuffer.Get('', '', GLSetupShortcutDimCode[FieldNumber]) then
TempJobTaskDimBuffer.Delete();
end;
/// <summary>
/// Inserts job task dimensions based on default dimensions from the job.
/// Creates job task dimension records and updates global dimension variables with values found.
/// </summary>
/// <param name="JobNo">Job number to create task dimensions for</param>
/// <param name="JobTaskNo">Job task number to create dimensions for</param>
/// <param name="GlobalDim1Code">Returns global dimension 1 code if found in job task dimensions</param>
/// <param name="GlobalDim2Code">Returns global dimension 2 code if found in job task dimensions</param>
procedure InsertJobTaskDim(JobNo: Code[20]; JobTaskNo: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20])
var
DefaultDim: Record "Default Dimension";
JobTaskDim: Record "Job Task Dimension";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeInsertJobTaskDim(JobNo, JobTaskNo, GlobalDim1Code, GlobalDim2Code, IsHandled);
if IsHandled then
exit;
GetGLSetup(GLSetupShortcutDimCode);
DefaultDim.SetRange("Table ID", Database::Job);
DefaultDim.SetRange("No.", JobNo);
if DefaultDim.FindSet(false) then
repeat
if DefaultDim."Dimension Value Code" <> '' then begin
JobTaskDim.Init();
JobTaskDim."Job No." := JobNo;
JobTaskDim."Job Task No." := JobTaskNo;
JobTaskDim."Dimension Code" := DefaultDim."Dimension Code";
JobTaskDim."Dimension Value Code" := DefaultDim."Dimension Value Code";
JobTaskDim.Insert();
if JobTaskDim."Dimension Code" = GLSetupShortcutDimCode[1] then
GlobalDim1Code := JobTaskDim."Dimension Value Code";
if JobTaskDim."Dimension Code" = GLSetupShortcutDimCode[2] then
GlobalDim2Code := JobTaskDim."Dimension Value Code";
end;
until DefaultDim.Next() = 0;
TempJobTaskDimBuffer.Reset();
if TempJobTaskDimBuffer.FindSet() then
repeat
if not JobTaskDim.Get(JobNo, JobTaskNo, TempJobTaskDimBuffer."Dimension Code") then begin
JobTaskDim.Init();
JobTaskDim."Job No." := JobNo;
JobTaskDim."Job Task No." := JobTaskNo;
JobTaskDim."Dimension Code" := TempJobTaskDimBuffer."Dimension Code";
JobTaskDim."Dimension Value Code" := TempJobTaskDimBuffer."Dimension Value Code";
JobTaskDim.Insert();
if JobTaskDim."Dimension Code" = GLSetupShortcutDimCode[1] then
GlobalDim1Code := JobTaskDim."Dimension Value Code";
if JobTaskDim."Dimension Code" = GLSetupShortcutDimCode[2] then
GlobalDim2Code := JobTaskDim."Dimension Value Code";
end;
until TempJobTaskDimBuffer.Next() = 0;
TempJobTaskDimBuffer.DeleteAll();
end;
/// <summary>
/// Inserts job task dimensions based on default dimension configuration.
/// Creates job task dimension entries and updates global dimension codes for the job task.
/// </summary>
/// <param name="DefaultDim">Default dimension record to use as template</param>
/// <param name="JobNo">Job number for the job task dimensions</param>
/// <param name="JobTaskNo">Job task number for the dimension assignment</param>
/// <param name="GlobalDim1Code">Returns the global dimension 1 code assigned</param>
/// <param name="GlobalDim2Code">Returns the global dimension 2 code assigned</param>
procedure InsertJobTaskDim(var DefaultDim: Record "Default Dimension"; JobNo: Code[20]; JobTaskNo: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20])
var
JobTaskDim: Record "Job Task Dimension";
begin
GetGLSetup(GLSetupShortcutDimCode);
DefaultDim.Reset();
DefaultDim.SetRange("Table ID", Database::"Job Task");
DefaultDim.SetRange("No.", JobTaskNo);
DefaultDim.SetFilter("Dimension Value Code", '<>%1', '');
if DefaultDim.FindSet(false) then
repeat
JobTaskDim.Init();
JobTaskDim."Job No." := JobNo;
JobTaskDim."Job Task No." := JobTaskNo;
JobTaskDim."Dimension Code" := DefaultDim."Dimension Code";
JobTaskDim."Dimension Value Code" := DefaultDim."Dimension Value Code";
JobTaskDim.Insert();
if JobTaskDim."Dimension Code" = GLSetupShortcutDimCode[1] then
GlobalDim1Code := JobTaskDim."Dimension Value Code";
if JobTaskDim."Dimension Code" = GLSetupShortcutDimCode[2] then
GlobalDim2Code := JobTaskDim."Dimension Value Code";
until DefaultDim.Next() = 0;
end;
local procedure UpdateJobTaskDim(DefaultDimension: Record "Default Dimension"; FromOnDelete: Boolean)
var
JobTaskDimension: Record "Job Task Dimension";
JobTask: Record "Job Task";
ConfirmManagement: Codeunit "Confirm Management";
IsHandled: Boolean;
begin
if DefaultDimension."Table ID" <> Database::Job then
exit;
JobTask.SetRange("Job No.", DefaultDimension."No.");
if JobTask.IsEmpty() then
exit;
if GetSkipUpdateDimensions() then
exit;
IsHandled := false;
OnUpdateJobTaskDimOnBeforConfirm(DefaultDimension, IsHandled);
if not IsHandled then
if not SkipChangeDimensionsQst then
if not ConfirmManagement.GetResponseOrDefault(Text019, true) then begin
SetSkipUpdateDimensions(true);
exit;
end;
JobTaskDimension.SetRange("Job No.", DefaultDimension."No.");
JobTaskDimension.SetRange("Dimension Code", DefaultDimension."Dimension Code");
JobTaskDimension.DeleteAll(true);
if FromOnDelete or
(DefaultDimension."Value Posting" = DefaultDimension."Value Posting"::"No Code") or
(DefaultDimension."Dimension Value Code" = '')
then
exit;
if JobTask.FindSet() then
repeat
Clear(JobTaskDimension);
JobTaskDimension."Job No." := JobTask."Job No.";
JobTaskDimension."Job Task No." := JobTask."Job Task No.";
JobTaskDimension."Dimension Code" := DefaultDimension."Dimension Code";
JobTaskDimension."Dimension Value Code" := DefaultDimension."Dimension Value Code";
JobTaskDimension.Insert(true);
until JobTask.Next() = 0;
OnAfterUpdateJobTaskDim(DefaultDimension);
end;
/// <summary>
/// Deletes all job task dimension records from temporary buffer.
/// </summary>
procedure DeleteJobTaskTempDim()
begin
TempJobTaskDimBuffer.Reset();
TempJobTaskDimBuffer.DeleteAll();
end;
/// <summary>
/// Copies job task dimensions from one job task to another job task.
/// </summary>
/// <param name="JobNo">Source job number</param>
/// <param name="JobTaskNo">Source job task number</param>
/// <param name="NewJobNo">Target job number</param>
/// <param name="NewJobTaskNo">Target job task number</param>
procedure CopyJobTaskDimToJobTaskDim(JobNo: Code[20]; JobTaskNo: Code[20]; NewJobNo: Code[20]; NewJobTaskNo: Code[20])
var
JobTaskDimension: Record "Job Task Dimension";
JobTaskDimension2: Record "Job Task Dimension";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCopyJobTaskDimToJobTaskDim(JobNo, JobTaskNo, NewJobNo, NewJobTaskNo, IsHandled);
if IsHandled then
exit;
JobTaskDimension.Reset();
JobTaskDimension.SetRange("Job No.", JobNo);
JobTaskDimension.SetRange("Job Task No.", JobTaskNo);
if JobTaskDimension.FindSet() then
repeat
if not JobTaskDimension2.Get(NewJobNo, NewJobTaskNo, JobTaskDimension."Dimension Code") then begin
JobTaskDimension2.Init();
JobTaskDimension2."Job No." := NewJobNo;
JobTaskDimension2."Job Task No." := NewJobTaskNo;
JobTaskDimension2."Dimension Code" := JobTaskDimension."Dimension Code";
JobTaskDimension2."Dimension Value Code" := JobTaskDimension."Dimension Value Code";
JobTaskDimension2.Insert(true);
end else begin
JobTaskDimension2."Dimension Value Code" := JobTaskDimension."Dimension Value Code";
JobTaskDimension2.Modify(true);
end;
until JobTaskDimension.Next() = 0;
JobTaskDimension2.Reset();
JobTaskDimension2.SetRange("Job No.", NewJobNo);
JobTaskDimension2.SetRange("Job Task No.", NewJobTaskNo);
if JobTaskDimension2.FindSet() then
repeat
if not JobTaskDimension.Get(JobNo, JobTaskNo, JobTaskDimension2."Dimension Code") then
JobTaskDimension2.Delete(true);
until JobTaskDimension2.Next() = 0;
end;
/// <summary>
/// Checks consistency between document dimension set entries and posted document dimension set entries.
/// Validates that dimension sets match between original document and posted document for audit compliance.
/// </summary>
/// <param name="DimSetEntry">Dimension set entries from the original document</param>
/// <param name="PostedDimSetEntry">Dimension set entries from the posted document</param>
/// <param name="DocTableID">Table ID of the original document</param>
/// <param name="PostedDocTableID">Table ID of the posted document</param>
/// <returns>True if dimension sets are consistent, false if discrepancies are found</returns>
procedure CheckDimIDConsistency(var DimSetEntry: Record "Dimension Set Entry"; var PostedDimSetEntry: Record "Dimension Set Entry"; DocTableID: Integer; PostedDocTableID: Integer): Boolean
var
ObjectTranslation: Record "Object Translation";
begin
if DimSetEntry.FindSet() then;
if PostedDimSetEntry.FindSet() then;
repeat
case true of
DimSetEntry."Dimension Code" > PostedDimSetEntry."Dimension Code":
begin
LogError(
DimSetEntry.RecordId, 0,
StrSubstNo(
Text012,
DimSetEntry.FieldCaption("Dimension Code"),
ObjectTranslation.TranslateTable(DocTableID),
ObjectTranslation.TranslateTable(PostedDocTableID)),
'');
exit(false);
end;
DimSetEntry."Dimension Code" < PostedDimSetEntry."Dimension Code":
begin
LogError(
DimSetEntry.RecordId, 0,
StrSubstNo(
Text012,
PostedDimSetEntry.FieldCaption("Dimension Code"),
ObjectTranslation.TranslateTable(PostedDocTableID),
ObjectTranslation.TranslateTable(DocTableID))
, '');
exit(false);
end;
DimSetEntry."Dimension Code" = PostedDimSetEntry."Dimension Code":
if DimSetEntry."Dimension Value Code" <> PostedDimSetEntry."Dimension Value Code" then begin
LogError(
DimSetEntry.RecordId, 0,
StrSubstNo(
Text013,
DimSetEntry.FieldCaption("Dimension Value Code"),
DimSetEntry.FieldCaption("Dimension Code"),
DimSetEntry."Dimension Code",
ObjectTranslation.TranslateTable(DocTableID),
ObjectTranslation.TranslateTable(PostedDocTableID)),
'');
exit(false);
end;
end;
until (DimSetEntry.Next() = 0) and (PostedDimSetEntry.Next() = 0);
exit(true);
end;
local procedure CreateDimSetEntryFromDimValue(DimValue: Record "Dimension Value"; var TempDimSetEntry: Record "Dimension Set Entry" temporary)
begin
TempDimSetEntry."Dimension Code" := DimValue."Dimension Code";
TempDimSetEntry."Dimension Value Code" := DimValue.Code;
TempDimSetEntry."Dimension Value ID" := DimValue."Dimension Value ID";
TempDimSetEntry.Insert();
end;
/// <summary>
/// Creates a dimension set ID from intercompany document dimensions by converting IC dimensions to company dimensions.
/// Processes all IC document dimension entries and builds a corresponding company dimension set.
/// </summary>
/// <param name="ICDocDim">Intercompany document dimensions to convert</param>
/// <returns>Dimension set ID representing the converted intercompany dimensions</returns>
procedure CreateDimSetIDFromICDocDim(var ICDocDim: Record "IC Document Dimension"): Integer
var
DimValue: Record "Dimension Value";
TempDimSetEntry: Record "Dimension Set Entry" temporary;
begin
OnBeforeCreateDimSetIDFromICDocDim(DimValue);
if ICDocDim.Find('-') then
repeat
DimValue.Get(
ConvertICDimtoDim(ICDocDim."Dimension Code"),
ConvertICDimValuetoDimValue(ICDocDim."Dimension Code", ICDocDim."Dimension Value Code"));
CreateDimSetEntryFromDimValue(DimValue, TempDimSetEntry);
until ICDocDim.Next() = 0;
exit(GetDimensionSetID(TempDimSetEntry));
end;
/// <summary>
/// Creates a dimension set ID from intercompany journal line dimensions by converting IC dimensions to company dimensions.
/// Processes all IC journal line dimension entries and builds a corresponding company dimension set.
/// </summary>
/// <param name="ICInboxOutboxJnlLineDim">Intercompany journal line dimensions to convert</param>
/// <returns>Dimension set ID representing the converted intercompany journal dimensions</returns>
procedure CreateDimSetIDFromICJnlLineDim(var ICInboxOutboxJnlLineDim: Record "IC Inbox/Outbox Jnl. Line Dim."): Integer
var
DimValue: Record "Dimension Value";
TempDimSetEntry: Record "Dimension Set Entry" temporary;
begin
OnBeforeCreateDimSetIDFromICJnlLineDim(DimValue);
if ICInboxOutboxJnlLineDim.Find('-') then
repeat
DimValue.Get(
ConvertICDimtoDim(ICInboxOutboxJnlLineDim."Dimension Code"),
ConvertICDimValuetoDimValue(
ICInboxOutboxJnlLineDim."Dimension Code", ICInboxOutboxJnlLineDim."Dimension Value Code"));
CreateDimSetEntryFromDimValue(DimValue, TempDimSetEntry);
until ICInboxOutboxJnlLineDim.Next() = 0;
exit(GetDimensionSetID(TempDimSetEntry));
end;
/// <summary>
/// Copies dimension buffer entries to dimension set entry records with proper dimension value ID assignment.
/// Validates dimension values during the copy process and populates dimension value IDs from master data.
/// </summary>
/// <param name="FromDimBuf">Source dimension buffer records to copy from</param>
/// <param name="DimSetEntry">Target dimension set entry records to copy to</param>
procedure CopyDimBufToDimSetEntry(var FromDimBuf: Record "Dimension Buffer"; var DimSetEntry: Record "Dimension Set Entry")
var
DimValue: Record "Dimension Value";
begin
OnBeforeCopyDimBufToDimSetEntry(DimValue);
if FromDimBuf.FindSet() then
repeat
DimValue.Get(FromDimBuf."Dimension Code", FromDimBuf."Dimension Value Code");
DimSetEntry."Dimension Code" := FromDimBuf."Dimension Code";
DimSetEntry."Dimension Value Code" := FromDimBuf."Dimension Value Code";
DimSetEntry."Dimension Value ID" := DimValue."Dimension Value ID";
DimSetEntry.Insert();
until FromDimBuf.Next() = 0;
end;
/// <summary>
/// Creates a dimension set ID from dimension buffer entries by building a temporary dimension set.
/// Validates dimension values and generates a unique dimension set ID for the buffer contents.
/// </summary>
/// <param name="DimBuf">Dimension buffer records to create dimension set ID from</param>
/// <returns>Generated dimension set ID representing the buffer dimension combination</returns>
procedure CreateDimSetIDFromDimBuf(var DimBuf: Record "Dimension Buffer"): Integer
var
DimValue: Record "Dimension Value";
TempDimSetEntry: Record "Dimension Set Entry" temporary;
begin
OnBeforeCreateDimSetIDFromDimBuf(DimValue);
if DimBuf.FindSet() then
repeat
DimValue.Get(DimBuf."Dimension Code", DimBuf."Dimension Value Code");
CreateDimSetEntryFromDimValue(DimValue, TempDimSetEntry);
until DimBuf.Next() = 0;
exit(GetDimensionSetID(TempDimSetEntry));
end;
/// <summary>
/// Creates dimensions for purchase lines using higher priority dimension sources.
/// Applies dimension priority rules to resolve conflicts between different dimension sources.
/// </summary>
/// <param name="PurchaseLine">Purchase line record containing the dimension data</param>
/// <param name="CurrFieldNo">Current field number triggering the dimension creation</param>
/// <param name="DimensionSetID">Returns the created dimension set ID</param>
/// <param name="DimValue1">Returns the global dimension 1 value code</param>
/// <param name="DimValue2">Returns the global dimension 2 value code</param>
/// <param name="SourceCode">Source code for the transaction</param>
/// <param name="PriorityTableID">Table ID used for priority determination</param>
procedure CreateDimForPurchLineWithHigherPriorities(PurchaseLine: Record "Purchase Line"; CurrFieldNo: Integer; var DimensionSetID: Integer; var DimValue1: Code[20]; var DimValue2: Code[20]; SourceCode: Code[10]; PriorityTableID: Integer)
var
DefaultDimSource: List of [Dictionary of [Integer, Code[20]]];
HighPriorityDefaultDimSource: List of [Dictionary of [Integer, Code[20]]];
begin
AddDimSource(DefaultDimSource, Database::Job, PurchaseLine."Job No.");
AddDimSource(DefaultDimSource, PurchLineTypeToTableID(PurchaseLine.Type), PurchaseLine."No.");
OnBeforeGetTableIDsForHigherPrioritiesProcedure(Database::"Purchase Line", PurchaseLine, CurrFieldNo, DefaultDimSource);
if GetTableIDsForHigherPriorities(
DefaultDimSource, HighPriorityDefaultDimSource, SourceCode, PriorityTableID)
then
DimensionSetID :=
GetRecDefaultDimID(
PurchaseLine, CurrFieldNo, HighPriorityDefaultDimSource, SourceCode, DimValue1, DimValue2, 0, 0);
end;
/// <summary>
/// Creates dimensions for sales lines using higher priority dimension sources.
/// Applies dimension priority rules to resolve conflicts between different dimension sources.
/// </summary>
/// <param name="SalesLine">Sales line record containing the dimension data</param>
/// <param name="CurrFieldNo">Current field number triggering the dimension creation</param>
/// <param name="DimensionSetID">Returns the created dimension set ID</param>
/// <param name="DimValue1">Returns the global dimension 1 value code</param>
/// <param name="DimValue2">Returns the global dimension 2 value code</param>
/// <param name="SourceCode">Source code for the transaction</param>
/// <param name="PriorityTableID">Table ID used for priority determination</param>
procedure CreateDimForSalesLineWithHigherPriorities(SalesLine: Record "Sales Line"; CurrFieldNo: Integer; var DimensionSetID: Integer; var DimValue1: Code[20]; var DimValue2: Code[20]; SourceCode: Code[10]; PriorityTableID: Integer)
var
DefaultDimSource: List of [Dictionary of [Integer, Code[20]]];
HighPriorityDefaultDimSource: List of [Dictionary of [Integer, Code[20]]];
begin
AddDimSource(DefaultDimSource, Database::Job, SalesLine."Job No.");
AddDimSource(DefaultDimSource, SalesLineTypeToTableID(SalesLine.Type), SalesLine."No.");
OnBeforeGetTableIDsForHigherPrioritiesProcedure(Database::"Sales Line", SalesLine, CurrFieldNo, DefaultDimSource);
if GetTableIDsForHigherPriorities(
DefaultDimSource, HighPriorityDefaultDimSource, SourceCode, PriorityTableID)
then
DimensionSetID :=
GetRecDefaultDimID(
SalesLine, CurrFieldNo, HighPriorityDefaultDimSource, SourceCode, DimValue1, DimValue2, 0, 0);
end;
/// <summary>
/// Creates dimensions for job journal lines using higher priority dimension sources.
/// Applies dimension priority rules to resolve conflicts between different dimension sources.
/// </summary>
/// <param name="JobJournalLine">Job journal line record containing the dimension data</param>
/// <param name="CurrFieldNo">Current field number triggering the dimension creation</param>
/// <param name="DimensionSetID">Returns the created dimension set ID</param>
/// <param name="DimValue1">Returns the global dimension 1 value code</param>
/// <param name="DimValue2">Returns the global dimension 2 value code</param>
/// <param name="SourceCode">Source code for the transaction</param>
/// <param name="PriorityTableID">Table ID used for priority determination</param>
procedure CreateDimForJobJournalLineWithHigherPriorities(JobJournalLine: Record "Job Journal Line"; CurrFieldNo: Integer; var DimensionSetID: Integer; var DimValue1: Code[20]; var DimValue2: Code[20]; SourceCode: Code[10]; PriorityTableID: Integer)
var
DefaultDimSource: List of [Dictionary of [Integer, Code[20]]];
HighPriorityDefaultDimSource: List of [Dictionary of [Integer, Code[20]]];
begin
AddDimSource(DefaultDimSource, Database::Job, JobJournalLine."Job No.");
AddDimSource(DefaultDimSource, Database::Location, JobJournalLine."Location Code");
AddDimSource(DefaultDimSource, TypeToTableID2(JobJournalLine.Type.AsInteger()), JobJournalLine."No.");
AddDimSource(DefaultDimSource, Database::"Resource Group", JobJournalLine."Resource Group No.");
OnBeforeGetTableIDsForHigherPrioritiesProcedure(Database::"Job Journal Line", JobJournalLine, CurrFieldNo, DefaultDimSource);
if GetTableIDsForHigherPriorities(
DefaultDimSource, HighPriorityDefaultDimSource, SourceCode, PriorityTableID)
then
DimensionSetID :=
GetRecDefaultDimID(
JobJournalLine, CurrFieldNo, HighPriorityDefaultDimSource, SourceCode, DimValue1, DimValue2, 0, 0);
OnAfterCreateDimForJobJournalLineWithHigherPrioritiesProcedure(JobJournalLine, CurrFieldNo, DimensionSetID, DimValue1, DimValue2, SourceCode, PriorityTableID, DefaultDimSource, HighPriorityDefaultDimSource);
end;
/// <summary>
/// Retrieves table IDs for higher priority dimension sources based on default dimension priority configuration.
/// Filters dimension sources to include only those with higher priority than the specified priority table.
/// </summary>
/// <param name="DefaultDimSource">List of default dimension sources to filter</param>
/// <param name="HighPriorityDefaultDimSource">Returns filtered list containing only higher priority sources</param>
/// <param name="SourceCode">Source code for priority lookup</param>
/// <param name="PriorityTableID">Table ID used as priority threshold for filtering</param>
/// <returns>True if higher priority sources exist, false otherwise</returns>
procedure GetTableIDsForHigherPriorities(DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; var HighPriorityDefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; SourceCode: Code[10]; PriorityTableID: Integer) Result: Boolean
var
DefaultDimensionPriority: Record "Default Dimension Priority";
InitialPriority: Integer;
i: Integer;
j: Integer;
TableID: Integer;
DimSource: Dictionary of [Integer, Code[20]];
begin
Clear(HighPriorityDefaultDimSource);
if DefaultDimensionPriority.Get(SourceCode, PriorityTableID) then
InitialPriority := DefaultDimensionPriority.Priority;
DefaultDimensionPriority.SetRange("Source Code", SourceCode);
DefaultDimensionPriority.SetFilter(Priority, '<=%1', InitialPriority);
i := 1;
for j := 1 to DefaultDimSource.Count do begin
DimSource := DefaultDimSource.Get(j);
TableID := DimSource.Keys.Get(1);
if TableID = 0 then
break;
DefaultDimensionPriority.Priority := 0;
DefaultDimensionPriority.SetRange("Table ID", TableID);
if ((InitialPriority = 0) or DefaultDimensionPriority.FindFirst()) and
((DefaultDimensionPriority.Priority < InitialPriority) or
((DefaultDimensionPriority.Priority = InitialPriority) and (TableID < PriorityTableID)))
then begin
Result := true;
AddDimSource(HighPriorityDefaultDimSource, TableID, DimSource.Values.Get(1));
i += 1;
end;
end;
exit(Result);
end;
/// <summary>
/// Builds a collection of dimension set IDs that match the specified dimension code and value filter.
/// Populates temporary dimension set entry buffer with matching dimension set IDs for subsequent filtering operations.
/// </summary>
/// <param name="DimCode">Dimension code to filter by</param>
/// <param name="DimValueFilter">Dimension value filter expression to apply</param>
procedure GetDimSetIDsForFilter(DimCode: Code[20]; DimValueFilter: Text)
var
DimSetEntry: Record "Dimension Set Entry";
begin
DimSetEntry.SetCurrentKey("Dimension Code", "Dimension Value Code", "Dimension Set ID");
DimSetEntry.SetFilter("Dimension Code", '%1', DimCode);
DimSetEntry.SetFilter("Dimension Value Code", DimValueFilter);
if DimSetEntry.FindSet() then
repeat
AddDimSetIDtoTempEntry(TempDimSetEntryBuffer, DimSetEntry."Dimension Set ID");
until DimSetEntry.Next() = 0;
if FilterIncludesBlank(DimCode, DimValueFilter) then
GetDimSetIDsForBlank(DimCode);
DimSetFilterCtr += 1;
end;
local procedure GetDimSetIDsForBlank(DimCode: Code[20])
var
TempDimSetEntry: Record "Dimension Set Entry" temporary;
DimSetEntry: Record "Dimension Set Entry";
PrevDimSetID: Integer;
i: Integer;
begin
AddDimSetIDtoTempEntry(TempDimSetEntry, 0);
for i := 1 to 2 do begin
if i = 2 then
DimSetEntry.SetFilter("Dimension Code", '%1', DimCode);
if DimSetEntry.FindSet() then begin
PrevDimSetID := 0;
repeat
if DimSetEntry."Dimension Set ID" <> PrevDimSetID then begin
AddDimSetIDtoTempEntry(TempDimSetEntry, DimSetEntry."Dimension Set ID");
PrevDimSetID := DimSetEntry."Dimension Set ID";
end;
until DimSetEntry.Next() = 0;
end;
end;
TempDimSetEntry.SetFilter("Dimension Value ID", '%1', 1);
if TempDimSetEntry.FindSet() then
repeat
AddDimSetIDtoTempEntry(TempDimSetEntryBuffer, TempDimSetEntry."Dimension Set ID");
until TempDimSetEntry.Next() = 0;
end;
procedure ChunkDimSetFilters(var TempDimensionSetEntry: Record "Dimension Set Entry" temporary): List of [Text]
var
DimSetFilters: List of [Text];
CurrentDimSetFilter: Text;
Parameters, MaxParameters : Integer;
MaxStrLen: Integer;
begin
MaxParameters := 1000;
MaxStrLen := 4000;
if not TempDimensionSetEntry.FindSet() then
exit(DimSetFilters);
CurrentDimSetFilter := '';
repeat
if CurrentDimSetFilter <> '' then
CurrentDimSetFilter += '|';
CurrentDimSetFilter += Format(TempDimensionSetEntry."Dimension Set ID");
Parameters += 1;
if (Parameters > MaxParameters) or (StrLen(CurrentDimSetFilter) > MaxStrLen) then begin
DimSetFilters.Add(CurrentDimSetFilter);
CurrentDimSetFilter := '';
Parameters := 0;
end;
until TempDimensionSetEntry.Next() = 0;
if CurrentDimSetFilter <> '' then
DimSetFilters.Add(CurrentDimSetFilter);
exit(DimSetFilters);
end;
/// <summary>
/// Gets dimension set filters as list of text for current dimension set filter counter.
/// </summary>
/// <returns>List of text containing dimension set filters for the current counter value</returns>
procedure GetDimSetFilters(): List of [Text]
begin
TempDimSetEntryBuffer.SetFilter("Dimension Value ID", '%1', DimSetFilterCtr);
exit(ChunkDimSetFilters(TempDimSetEntryBuffer));
end;
/// <summary>
/// Gets single dimension set filter string based on current dimension set filter counter.
/// </summary>
/// <returns>Dimension set filter as concatenated text string</returns>
procedure GetDimSetFilter() DimSetFilter: Text
var
Counter: integer;
MaxParameters: Integer;
StringLimitation: Integer;
begin
Counter := 0;
MaxParameters := 1000;
StringLimitation := 4000;
TempDimSetEntryBuffer.SetFilter("Dimension Value ID", '%1', DimSetFilterCtr);
if TempDimSetEntryBuffer.FindSet() then begin
DimSetFilter := Format(TempDimSetEntryBuffer."Dimension Set ID");
if TempDimSetEntryBuffer.Next() <> 0 then
repeat
Counter := Counter + 1;
DimSetFilter += '|' + Format(TempDimSetEntryBuffer."Dimension Set ID");
until TempDimSetEntryBuffer.Next() = 0;
if (Counter > MaxParameters) or (StrLen(DimSetFilter) > StringLimitation) then
Error(ToManyParametersErr);
end;
end;
local procedure FilterIncludesBlank(DimCode: Code[20]; DimValueFilter: Text): Boolean
var
TempDimSetEntry: Record "Dimension Set Entry" temporary;
begin
TempDimSetEntry."Dimension Code" := DimCode;
TempDimSetEntry.Insert();
TempDimSetEntry.SetFilter("Dimension Value Code", DimValueFilter);
exit(not TempDimSetEntry.IsEmpty);
end;
local procedure AddDimSetIDtoTempEntry(var TempDimSetEntry: Record "Dimension Set Entry" temporary; DimSetID: Integer)
begin
if TempDimSetEntry.Get(DimSetID, '') then begin
TempDimSetEntry."Dimension Value ID" += 1;
TempDimSetEntry.Modify();
end else begin
TempDimSetEntry."Dimension Set ID" := DimSetID;
TempDimSetEntry."Dimension Value ID" := 1;
TempDimSetEntry.Insert();
end;
end;
/// <summary>
/// Clears dimension set filter by resetting buffer and counter.
/// </summary>
procedure ClearDimSetFilter()
begin
TempDimSetEntryBuffer.Reset();
TempDimSetEntryBuffer.DeleteAll();
DimSetFilterCtr := 0;
end;
/// <summary>
/// Gets temporary dimension set entry from buffer.
/// </summary>
/// <param name="TempDimSetEntry">Temporary dimension set entry to copy buffer data to</param>
procedure GetTempDimSetEntry(var TempDimSetEntry: Record "Dimension Set Entry" temporary)
begin
TempDimSetEntry.Copy(TempDimSetEntryBuffer, true);
end;
/// <summary>
/// Updates cost accounting types when default dimensions are modified for G/L accounts.
/// Integrates dimension changes with cost accounting setup to maintain consistency between financial and cost dimensions.
/// </summary>
/// <param name="DefaultDimension">Default dimension record being modified</param>
/// <param name="CallingTrigger">Trigger context indicating the type of operation (Insert, Modify, Delete)</param>
procedure UpdateCostType(DefaultDimension: Record "Default Dimension"; CallingTrigger: Option OnInsert,OnModify,OnDelete)
var
GLAccount: Record "G/L Account";
CostAccSetup: Record "Cost Accounting Setup";
CostAccMgt: Codeunit "Cost Account Mgt";
begin
if CostAccSetup.Get() and (DefaultDimension."Table ID" = Database::"G/L Account") then
if GLAccount.Get(DefaultDimension."No.") then
CostAccMgt.UpdateCostTypeFromDefaultDimension(DefaultDimension, GLAccount, CallingTrigger);
end;
/// <summary>
/// Creates dimension set ID from job task dimensions and updates global dimension values.
/// </summary>
/// <param name="JobNo">Job number to get dimensions from</param>
/// <param name="JobTaskNo">Job task number to get dimensions from</param>
/// <param name="GlobalDimVal1">Returns global dimension 1 value</param>
/// <param name="GlobalDimVal2">Returns global dimension 2 value</param>
/// <returns>New dimension set ID created from job task dimensions</returns>
procedure CreateDimSetFromJobTaskDim(JobNo: Code[20]; JobTaskNo: Code[20]; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20]) NewDimSetID: Integer
var
JobTaskDimension: Record "Job Task Dimension";
DimValue: Record "Dimension Value";
TempDimSetEntry: Record "Dimension Set Entry" temporary;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCreateDimSetFromJobTaskDim(JobNo, JobTaskNo, GlobalDimVal1, GlobalDimVal2, NewDimSetID, IsHandled, DimValue);
if IsHandled then
exit(NewDimSetID);
JobTaskDimension.SetRange("Job No.", JobNo);
JobTaskDimension.SetRange("Job Task No.", JobTaskNo);
if JobTaskDimension.FindSet() then begin
repeat
DimValue.Get(JobTaskDimension."Dimension Code", JobTaskDimension."Dimension Value Code");
TempDimSetEntry."Dimension Code" := JobTaskDimension."Dimension Code";
TempDimSetEntry."Dimension Value Code" := JobTaskDimension."Dimension Value Code";
TempDimSetEntry."Dimension Value ID" := DimValue."Dimension Value ID";
TempDimSetEntry.Insert(true);
until JobTaskDimension.Next() = 0;
NewDimSetID := GetDimensionSetID(TempDimSetEntry);
UpdateGlobalDimFromDimSetID(NewDimSetID, GlobalDimVal1, GlobalDimVal2);
end;
end;
/// <summary>
/// Updates general journal line with dimension set ID and corresponding shortcut dimension codes.
/// </summary>
/// <param name="GenJnlLine">General journal line to update with dimensions</param>
/// <param name="DimSetID">Dimension set ID to assign to the journal line</param>
procedure UpdateGenJnlLineDim(var GenJnlLine: Record "Gen. Journal Line"; DimSetID: Integer)
begin
GenJnlLine."Dimension Set ID" := DimSetID;
UpdateGlobalDimFromDimSetID(
GenJnlLine."Dimension Set ID",
GenJnlLine."Shortcut Dimension 1 Code", GenJnlLine."Shortcut Dimension 2 Code");
OnAfterUpdateGenJnlLineDim(GenJnlLine, DimSetID);
end;
/// <summary>
/// Updates general journal line dimensions from corresponding customer ledger entry.
/// </summary>
/// <param name="GenJnlLine">General journal line to update with dimensions</param>
/// <param name="DtldCustLedgEntry">Detailed customer ledger entry containing dimension reference</param>
procedure UpdateGenJnlLineDimFromCustLedgEntry(var GenJnlLine: Record "Gen. Journal Line"; DtldCustLedgEntry: Record "Detailed Cust. Ledg. Entry")
var
CustLedgEntry: Record "Cust. Ledger Entry";
begin
if DtldCustLedgEntry."Cust. Ledger Entry No." <> 0 then begin
CustLedgEntry.Get(DtldCustLedgEntry."Cust. Ledger Entry No.");
UpdateGenJnlLineDim(GenJnlLine, CustLedgEntry."Dimension Set ID");
end;
end;
/// <summary>
/// Updates general journal line dimensions from corresponding vendor ledger entry.
/// </summary>
/// <param name="GenJnlLine">General journal line to update with dimensions</param>
/// <param name="DtldVendLedgEntry">Detailed vendor ledger entry containing dimension reference</param>
procedure UpdateGenJnlLineDimFromVendLedgEntry(var GenJnlLine: Record "Gen. Journal Line"; DtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry")
var
VendLedgEntry: Record "Vendor Ledger Entry";
begin
if DtldVendLedgEntry."Vendor Ledger Entry No." <> 0 then begin
VendLedgEntry.Get(DtldVendLedgEntry."Vendor Ledger Entry No.");
UpdateGenJnlLineDim(GenJnlLine, VendLedgEntry."Dimension Set ID");
end;
end;
/// <summary>
/// Gets dimension set entry default dimensions. Method is obsolete and clears dimension set entries.
/// </summary>
/// <param name="DimSetEntry">Dimension set entry record to clear</param>
procedure GetDimSetEntryDefaultDim(var DimSetEntry: Record "Dimension Set Entry")
begin
// Obsolete method
DimSetEntry.DeleteAll();
end;
/// <summary>
/// Inserts table object into temporary AllObjWithCaption record if not obsolete.
/// </summary>
/// <param name="TempAllObjWithCaption">Temporary record to insert object information</param>
/// <param name="TableID">Table ID to check and insert</param>
procedure InsertObject(var TempAllObjWithCaption: Record AllObjWithCaption temporary; TableID: Integer)
var
AllObjWithCaption: Record AllObjWithCaption;
begin
if IsObsolete(TableID) then
exit;
if AllObjWithCaption.Get(AllObjWithCaption."Object Type"::Table, TableID) then begin
TempAllObjWithCaption := AllObjWithCaption;
if TempAllObjWithCaption.Insert() then;
end;
end;
local procedure IsObsolete(TableID: Integer): Boolean
var
TableMetadata: Record "Table Metadata";
begin
if TableMetadata.Get(TableID) then
exit(TableMetadata.ObsoleteState = TableMetadata.ObsoleteState::Removed);
end;
/// <summary>
/// Gets consolidated dimension filter by combining dimension filter with dimension codes.
/// </summary>
/// <param name="Dimension">Dimension record to filter and process</param>
/// <param name="DimFilter">Dimension filter text to apply</param>
/// <returns>Consolidated dimension filter including original filter and dimension codes</returns>
procedure GetConsolidatedDimFilterByDimFilter(var Dimension: Record Dimension; DimFilter: Text) ConsolidatedDimFilter: Text
begin
Dimension.SetFilter("Consolidation Code", DimFilter);
ConsolidatedDimFilter += DimFilter;
if Dimension.FindSet() then
repeat
ConsolidatedDimFilter += '|' + Dimension.Code;
until Dimension.Next() = 0;
end;
/// <summary>
/// Resolves dimension value filter by expanding with totaling values.
/// </summary>
/// <param name="DimValueFilter">Dimension value filter to resolve and expand</param>
/// <param name="DimensionCode">Dimension code for which to resolve values</param>
procedure ResolveDimValueFilter(var DimValueFilter: Text; DimensionCode: Code[20])
begin
DimValueFilter := GetDimValuesWithTotalings(DimValueFilter, DimensionCode);
end;
local procedure GetDimValuesWithTotalings(DimValueFilter: Text; DimensionCode: Code[20]) ResultTxt: Text
var
FilterChars: Text;
DimParam: Text;
CharTxt: Text;
NextCharTxt: Text;
SingleQuoteCharTxt: Text;
DimFilterLen: Integer;
i: Integer;
begin
if DimensionCode = '' then
exit(DimValueFilter);
if DimValueFilter = '' then
exit(DimValueFilter);
FilterChars := '()|"&@<>=.';
SingleQuoteCharTxt := '''';
DimValueFilter := UpperCase(DimValueFilter);
DimFilterLen := StrLen(DimValueFilter);
i := 1;
repeat
DimParam := '';
CharTxt := Format(DimValueFilter[i]);
while (StrPos(FilterChars, CharTxt) > 0) and (i <= DimFilterLen) do begin
ResultTxt += CharTxt;
i += 1;
CharTxt := Format(DimValueFilter[i]);
end;
if CharTxt = SingleQuoteCharTxt then begin
repeat
DimParam += CharTxt;
i += 1;
CharTxt := Format(DimValueFilter[i]);
NextCharTxt := Format(DimValueFilter[i + 1]);
until ((CharTxt = SingleQuoteCharTxt) and (NextCharTxt <> SingleQuoteCharTxt)) or (i > DimFilterLen);
DimParam += CharTxt;
i += 1;
end else
while (StrPos(FilterChars, CharTxt) = 0) and (i <= DimFilterLen) do begin
DimParam += CharTxt;
i += 1;
CharTxt := Format(DimValueFilter[i]);
end;
if DimParam <> '' then
ResultTxt += ParseDimParam(DimParam, DimensionCode);
until i > DimFilterLen;
end;
local procedure ParseDimParam(DimValueFilter: Text; DimensionCode: Code[20]) ResultTxt: Text
var
DimensionValue: Record "Dimension Value";
TempDimensionValue: Record "Dimension Value" temporary;
CheckStr: Text;
begin
OnBeforeParseDimParam(DimensionValue);
// Possible input values: blank filter, code or code with *
if DelChr(DimValueFilter) = '' then
exit(DimValueFilter);
DimensionValue.SetRange("Dimension Code", DimensionCode);
DimensionValue.SetFilter(Code, DimValueFilter);
DimensionValue.SetFilter(Totaling, '<>%1', '');
if DimensionValue.IsEmpty() then
exit(DimValueFilter);
AddTempDimValueFromTotaling(TempDimensionValue, CheckStr, DimensionCode, DimValueFilter);
OnParseDimParamOnBeforeTempDimensionValueFindSet(TempDimensionValue);
if TempDimensionValue.FindSet() then
repeat
ResultTxt += TempDimensionValue.Code + '|'
until TempDimensionValue.Next() = 0;
if ResultTxt <> '' then
ResultTxt := '(' + CopyStr(ResultTxt, 1, StrLen(ResultTxt) - 1) + ')';
end;
local procedure AddTempDimValueFromTotaling(var TempDimensionValue: Record "Dimension Value" temporary; var CheckStr: Text; DimensionCode: Code[20]; Totaling: Text)
var
DimensionValue: Record "Dimension Value";
begin
if StrPos(CheckStr, '(' + Totaling + ')') > 0 then
exit;
CheckStr += '(' + Totaling + ')';
DimensionValue.SetRange("Dimension Code", DimensionCode);
DimensionValue.SetFilter(Code, Totaling);
if DimensionValue.FindSet() then
repeat
if DimensionValue.Totaling <> '' then
AddTempDimValueFromTotaling(TempDimensionValue, CheckStr, DimensionCode, DimensionValue.Totaling)
else begin
TempDimensionValue := DimensionValue;
if TempDimensionValue.Insert() then;
end;
until DimensionValue.Next() = 0;
end;
/// <summary>
/// Determines the visibility of shortcut dimension fields based on General Ledger Setup configuration.
/// Returns boolean values for each of the eight shortcut dimension fields indicating whether they should be visible in the UI.
/// </summary>
/// <param name="DimVisible1">Returns true if shortcut dimension 1 is configured and should be visible</param>
/// <param name="DimVisible2">Returns true if shortcut dimension 2 is configured and should be visible</param>
/// <param name="DimVisible3">Returns true if shortcut dimension 3 is configured and should be visible</param>
/// <param name="DimVisible4">Returns true if shortcut dimension 4 is configured and should be visible</param>
/// <param name="DimVisible5">Returns true if shortcut dimension 5 is configured and should be visible</param>
/// <param name="DimVisible6">Returns true if shortcut dimension 6 is configured and should be visible</param>
/// <param name="DimVisible7">Returns true if shortcut dimension 7 is configured and should be visible</param>
/// <param name="DimVisible8">Returns true if shortcut dimension 8 is configured and should be visible</param>
procedure UseShortcutDims(var DimVisible1: Boolean; var DimVisible2: Boolean; var DimVisible3: Boolean; var DimVisible4: Boolean; var DimVisible5: Boolean; var DimVisible6: Boolean; var DimVisible7: Boolean; var DimVisible8: Boolean)
var
GLSetup: Record "General Ledger Setup";
begin
GLSetup.Get();
DimVisible1 := GLSetup."Shortcut Dimension 1 Code" <> '';
DimVisible2 := GLSetup."Shortcut Dimension 2 Code" <> '';
DimVisible3 := GLSetup."Shortcut Dimension 3 Code" <> '';
DimVisible4 := GLSetup."Shortcut Dimension 4 Code" <> '';
DimVisible5 := GLSetup."Shortcut Dimension 5 Code" <> '';
DimVisible6 := GLSetup."Shortcut Dimension 6 Code" <> '';
DimVisible7 := GLSetup."Shortcut Dimension 7 Code" <> '';
DimVisible8 := GLSetup."Shortcut Dimension 8 Code" <> '';
OnAfterUseShortcutDims(DimVisible1, DimVisible2, DimVisible3, DimVisible4, DimVisible5, DimVisible6, DimVisible7, DimVisible8);
end;
/// <summary>
/// Opens page for managing allowed dimension values per account with buffer synchronization.
/// </summary>
/// <param name="DefaultDimension">Default dimension record to manage allowed values for</param>
procedure OpenAllowedDimValuesPerAccount(var DefaultDimension: Record "Default Dimension")
var
DimValuePerAccount: Record "Dim. Value per Account";
TempDimValuePerAccount: Record "Dim. Value per Account" temporary;
DimAllowedValuesPerAcc: Page "Dim. Allowed Values per Acc.";
begin
SyncDimValuePerAccountWithDimValues(DefaultDimension);
Commit();
FillDimValuePerAccountBuffer(DefaultDimension, TempDimValuePerAccount);
DimAllowedValuesPerAcc.SetBufferData(TempDimValuePerAccount);
DimAllowedValuesPerAcc.LookupMode(true);
if DimAllowedValuesPerAcc.RunModal() = Action::LookupOK then begin
DimAllowedValuesPerAcc.GetBufferData(TempDimValuePerAccount);
UpdateDefaultDimensionAllowedValuesFromBuffer(DimValuePerAccount, TempDimValuePerAccount);
DefaultDimension.UpdateDefaultDimensionAllowedValuesFilter();
end;
end;
local procedure UpdateDefaultDimensionAllowedValuesFromBuffer(var DimValuePerAccount: Record "Dim. Value per Account"; var TempDimValuePerAccount: Record "Dim. Value per Account" temporary)
begin
if TempDimValuePerAccount.FindSet() then
repeat
if DimValuePerAccount.Get(TempDimValuePerAccount."Table ID", TempDimValuePerAccount."No.", TempDimValuePerAccount."Dimension Code", TempDimValuePerAccount."Dimension Value Code") then begin
DimValuePerAccount.Allowed := TempDimValuePerAccount.Allowed;
DimValuePerAccount.Modify();
end;
until TempDimValuePerAccount.Next() = 0;
end;
/// <summary>
/// Fills temporary dimension value per account buffer from existing records or dimension values.
/// </summary>
/// <param name="DefaultDimension">Default dimension record to get account and dimension information</param>
/// <param name="TempDimValuePerAccount">Temporary buffer to fill with dimension value per account data</param>
procedure FillDimValuePerAccountBuffer(var DefaultDimension: Record "Default Dimension"; var TempDimValuePerAccount: Record "Dim. Value per Account" temporary)
var
DimValuePerAccount: Record "Dim. Value per Account";
DimValue: Record "Dimension Value";
begin
DimValuePerAccount.SetRange("Table ID", DefaultDimension."Table ID");
DimValuePerAccount.SetRange("No.", DefaultDimension."No.");
DimValuePerAccount.SetRange("Dimension Code", DefaultDimension."Dimension Code");
if DimValuePerAccount.FindSet() then
repeat
TempDimValuePerAccount := DimValuePerAccount;
TempDimValuePerAccount.Insert();
until DimValuePerAccount.Next() = 0
else begin
DimValue.SetRange("Dimension Code", DefaultDimension."Dimension Code");
if DimValue.FindSet() then
repeat
TempDimValuePerAccount.Init();
TempDimValuePerAccount."Dimension Code" := DimValue."Dimension Code";
TempDimValuePerAccount."Dimension Value Code" := DimValue.Code;
TempDimValuePerAccount."Table ID" := DefaultDimension."Table ID";
TempDimValuePerAccount."No." := DefaultDimension."No.";
TempDimValuePerAccount.Insert();
until DimValue.Next() = 0;
end;
end;
/// <summary>
/// Synchronizes dimension value per account records with dimension values.
/// Creates dimension value per account entries for all dimension values in the specified dimension.
/// </summary>
/// <param name="DefaultDimension">Default dimension record containing the dimension code to synchronize</param>
procedure SyncDimValuePerAccountWithDimValues(var DefaultDimension: Record "Default Dimension")
var
DimValuePerAccount: Record "Dim. Value per Account";
DimValue: Record "Dimension Value";
begin
DimValue.SetRange("Dimension Code", DefaultDimension."Dimension Code");
if DimValue.FindSet() then
repeat
if not DimValuePerAccount.Get(DefaultDimension."Table ID", DefaultDimension."No.", DefaultDimension."Dimension Code", DimValue.Code) then begin
DimValuePerAccount.Init();
DimValuePerAccount."Dimension Code" := DimValue."Dimension Code";
DimValuePerAccount."Dimension Value Code" := DimValue.Code;
DimValuePerAccount."Table ID" := DefaultDimension."Table ID";
DimValuePerAccount."No." := DefaultDimension."No.";
DimValuePerAccount.Insert();
end;
until DimValue.Next() = 0;
end;
/// <summary>
/// Synchronizes temporary dimension value per account records with dimension values.
/// Creates temporary dimension value per account entries for all dimension values in the specified dimension.
/// </summary>
/// <param name="DefaultDimension">Default dimension record containing the dimension code to synchronize</param>
/// <param name="TempDimValuePerAccount">Temporary buffer to populate with dimension value per account records</param>
procedure SyncTempDimValuePerAccountWithDimValues(var DefaultDimension: Record "Default Dimension"; var TempDimValuePerAccount: Record "Dim. Value per Account" temporary)
var
DimValue: Record "Dimension Value";
begin
DimValue.SetRange("Dimension Code", DefaultDimension."Dimension Code");
if DimValue.FindSet() then
repeat
if not TempDimValuePerAccount.Get(DefaultDimension."Table ID", DefaultDimension."No.", DefaultDimension."Dimension Code", DimValue.Code) then begin
TempDimValuePerAccount.Init();
TempDimValuePerAccount."Dimension Code" := DimValue."Dimension Code";
TempDimValuePerAccount."Dimension Value Code" := DimValue.Code;
TempDimValuePerAccount."Table ID" := DefaultDimension."Table ID";
TempDimValuePerAccount."No." := DefaultDimension."No.";
TempDimValuePerAccount.Insert();
end;
until DimValue.Next() = 0;
end;
/// <summary>
/// Opens the allowed dimension values per account page for multiple dimension selection.
/// Provides user interface for selecting allowed dimension values for specific account configurations.
/// </summary>
/// <param name="DefaultDimension">Default dimension record containing the configuration context</param>
/// <param name="TempDimValuePerAccount">Temporary buffer containing dimension value per account data</param>
procedure OpenAllowedDimValuesPerAccountDimMultiple(var DefaultDimension: Record "Default Dimension"; var TempDimValuePerAccount: Record "Dim. Value per Account" temporary)
var
DimAllowedValuesPerAcc: Page "Dim. Allowed Values per Acc.";
begin
SyncTempDimValuePerAccountWithDimValues(DefaultDimension, TempDimValuePerAccount);
TempDimValuePerAccount.Reset();
TempDimValuePerAccount.SetRange("Table ID", DefaultDimension."Table ID");
TempDimValuePerAccount.SetRange("No.", DefaultDimension."No.");
TempDimValuePerAccount.SetRange("Dimension Code", DefaultDimension."Dimension Code");
DimAllowedValuesPerAcc.SetBufferData(TempDimValuePerAccount);
DimAllowedValuesPerAcc.LookupMode(true);
if DimAllowedValuesPerAcc.RunModal() = Action::LookupOK then begin
DimAllowedValuesPerAcc.GetBufferData(TempDimValuePerAccount);
DefaultDimension.UpdateDefaultDimensionAllowedValuesFilter();
end;
end;
/// <summary>
/// Adds a dimension value to the allowed values filter for default dimensions.
/// Updates default dimension configurations to include the specified dimension value as allowed.
/// </summary>
/// <param name="DimensionValue">Dimension value record to add to allowed values</param>
procedure AddDefaultDimensionAllowedDimensionValue(DimensionValue: Record "Dimension Value")
var
DefaultDimension: Record "Default Dimension";
ConfirmManagement: Codeunit "Confirm Management";
Confirmed: Boolean;
IsHandled: Boolean;
ConfirmHandled: Boolean;
begin
IsHandled := false;
OnBeforeAddDefaultDimensionAllowedDimensionValue(DimensionValue, IsHandled);
if IsHandled then
exit;
DefaultDimension.SetRange("Dimension Code", DimensionValue."Dimension Code");
DefaultDimension.SetRange("Value Posting", DefaultDimension."Value Posting"::"Code Mandatory");
DefaultDimension.SetFilter("Allowed Values Filter", '<>%1', '');
OnAddDefaultDimensionAllowedDimensionValueOnAfterSetFilters(DefaultDimension);
if DefaultDimension.IsEmpty() then
exit;
OnAllowedDimensionValueConfirm(DimensionValue, DefaultDimension, Confirmed, ConfirmHandled);
if not ConfirmHandled then
Confirmed := ConfirmManagement.GetResponseOrDefault(StrSubstNo(AllowedDimensionValueConfirmTxt, DimensionValue.Code, DefaultDimension.FieldCaption("Allowed Values Filter"), DefaultDimension.Count()), false);
DefaultDimension.FindSet(true);
repeat
DefaultDimension.CreateDimValuePerAccountFromDimValue(DimensionValue, Confirmed);
if Confirmed then
DefaultDimension.AddDimensionValueToAllowedFilter(DimensionValue.Code);
until DefaultDimension.Next() = 0;
end;
/// <summary>
/// Updates default dimension allowed values filter when dimension values change.
/// Refreshes allowed values filter for all default dimensions using the specified dimension.
/// </summary>
/// <param name="DimensionValue">Dimension value record that has been modified</param>
procedure UpdateDefaultDimensionAllowedDimensionValues(DimensionValue: Record "Dimension Value")
var
DefaultDimension: Record "Default Dimension";
begin
DefaultDimension.SetRange("Dimension Code", DimensionValue."Dimension Code");
DefaultDimension.SetRange("Value Posting", DefaultDimension."Value Posting"::"Code Mandatory");
DefaultDimension.SetFilter("Allowed Values Filter", '<>%1', '');
if DefaultDimension.FindSet(true) then
repeat
DefaultDimension.UpdateDefaultDimensionAllowedValuesFilter();
until DefaultDimension.Next() = 0;
end;
/// <summary>
/// Validates that at least one allowed value is selected for dimension value per account configuration.
/// Throws an error if no allowed values are marked as selected.
/// </summary>
/// <param name="DimValuePerAccount">Dimension value per account record to validate</param>
procedure CheckIfNoAllowedValuesSelected(var DimValuePerAccount: Record "Dim. Value per Account")
begin
DimValuePerAccount.SetRange(Allowed, true);
if DimValuePerAccount.IsEmpty() then
Error(NoAllowedValuesSelectedErr);
end;
local procedure InsertTempDimBufEntry(var TempDimBuf: Record "Dimension Buffer" temporary; TableId: Integer; EntryNo: Integer; DimCode: Code[20]; DimValueCode: Code[20])
begin
TempDimBuf.Init();
TempDimBuf."Table ID" := TableId;
TempDimBuf."Entry No." := EntryNo;
TempDimBuf."Dimension Code" := DimCode;
TempDimBuf."Dimension Value Code" := DimValueCode;
TempDimBuf.Insert();
end;
/// <summary>
/// Adds dimension source to default dimension source list.
/// </summary>
/// <param name="DefaultDimSource">List of default dimension sources to add to</param>
/// <param name="TableId">Table ID for the dimension source</param>
/// <param name="No">Number/code for the dimension source</param>
procedure AddDimSource(var DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; TableId: Integer; No: Code[20])
var
DimSource: Dictionary of [Integer, Code[20]];
begin
DimSource.Add(TableId, No);
DefaultDimSource.Add(DimSource);
end;
/// <summary>
/// Adds dimension source to default dimension source list with position control.
/// </summary>
/// <param name="DefaultDimSource">List of default dimension sources to add to</param>
/// <param name="TableId">Table ID for the dimension source</param>
/// <param name="No">Number/code for the dimension source</param>
/// <param name="FirstPos">True to insert at first position, false to add at end</param>
procedure AddDimSource(var DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; TableId: Integer; No: Code[20]; FirstPos: Boolean)
var
DimSource: Dictionary of [Integer, Code[20]];
begin
DimSource.Add(TableId, No);
if FirstPos then
DefaultDimSource.Insert(1, DimSource)
else
DefaultDimSource.Add(DimSource);
end;
/// <summary>
/// Checks if default dimensions are defined for a specific table and record combination.
/// Returns true if any default dimension records exist for the table and record specified.
/// </summary>
/// <param name="TableValuePair">Dictionary containing table ID and record number pair to check</param>
/// <returns>True if default dimensions exist for the table and record, false otherwise</returns>
procedure IsDefaultDimDefinedForTable(TableValuePair: Dictionary of [Integer, Code[20]]): Boolean
var
DefaultDim: Record "Default Dimension";
begin
if TableValuePair.Count = 0 then exit(true);
DefaultDim.SetRange("Table ID", TableValuePair.Keys.Get(1));
DefaultDim.SetFilter("No.", '%1|%2', TableValuePair.Values.Get(1), '');
DefaultDim.SetFilter("Dimension Value Code", '<>%1', '');
if not DefaultDim.IsEmpty() then exit(true);
end;
local procedure DefDimPrioritiesNotExist(SourceCode: Code[20]): Boolean
var
DefaultDimPriority: Record "Default Dimension Priority";
begin
DefaultDimPriority.SetRange("Source Code", SourceCode);
if DefaultDimPriority.IsEmpty() then
exit(true);
end;
local procedure InitializeDefaultDimPrioritiesMissingNotification(SourceCode: Code[20])
var
MyNotifications: Record "My Notifications";
DefaultDimPrioritiesNotification: Notification;
begin
if not MyNotifications.IsEnabled(InstructionMgt.GetDefaultDimPrioritiesNotificationId()) then
exit;
DefaultDimPrioritiesNotification.Id := InstructionMgt.GetDefaultDimPrioritiesNotificationId();
DefaultDimPrioritiesNotification.Recall();
DefaultDimPrioritiesNotification.Message(StrSubstNo(DefaultDimPrioritiesMissingLbl, SourceCode));
DefaultDimPrioritiesNotification.Scope := NotificationScope::LocalScope;
DefaultDimPrioritiesNotification.SetData('SourceCode', SourceCode);
DefaultDimPrioritiesNotification.AddAction(HideNotificationTxt, Codeunit::DimensionManagement, 'DontNotifyCurrentUserAgain');
DefaultDimPrioritiesNotification.AddAction(OpenDefaultDimPrioritiesLbl, Codeunit::DimensionManagement, 'OpenDefaultDimPriorities');
DefaultDimPrioritiesNotification.Send();
end;
/// <summary>
/// Disables current user notification for default dimension priorities.
/// </summary>
/// <param name="Notification">Notification to disable for current user</param>
procedure DontNotifyCurrentUserAgain(Notification: Notification)
var
MyNotifications: Record "My Notifications";
begin
if not MyNotifications.Disable(InstructionMgt.GetDefaultDimPrioritiesNotificationId()) then
MyNotifications.InsertDefault(InstructionMgt.GetDefaultDimPrioritiesNotificationId(), InstructionMgt.GetDefaultDimPrioritiesTxt(),
InstructionMgt.GetDefaultDimPrioritiesDescriptionTxt(), false);
end;
/// <summary>
/// Opens default dimension priorities page with source code from notification data.
/// </summary>
/// <param name="DefaultDimPrioritiesNotification">Notification containing source code data</param>
procedure OpenDefaultDimPriorities(DefaultDimPrioritiesNotification: Notification)
var
DefaultDimPriority: Record "Default Dimension Priority";
begin
DefaultDimPriority."Source Code" := CopyStr(DefaultDimPrioritiesNotification.GetData('SourceCode'), 1, MaxStrLen(DefaultDimPriority."Source Code"));
Page.Run(Page::"Default Dimension Priorities", DefaultDimPriority);
end;
/// <summary>
/// Checks if any default dimensions have Code Mandatory value posting for given table IDs and numbers.
/// </summary>
/// <param name="TableID">Array of table IDs to check for default dimensions</param>
/// <param name="No">Array of numbers corresponding to table IDs</param>
/// <returns>True if any default dimension has Code Mandatory value posting, false otherwise</returns>
procedure CheckDefaultDimensionHasCodeMandatory(TableID: array[10] of Integer; No: array[10] of Code[20]) CodeMandatory: Boolean
var
TempDefaultDim: Record "Default Dimension" temporary;
begin
CollectDefaultDimsToCheck(TableID, No, TempDefaultDim);
TempDefaultDim.Reset();
TempDefaultDim.SetRange("Value Posting", TempDefaultDim."Value Posting"::"Code Mandatory");
if not TempDefaultDim.IsEmpty() then
CodeMandatory := true;
exit(CodeMandatory);
end;
/// <summary>
/// Sets flag to skip change dimensions confirmation question.
/// </summary>
/// <param name="Skip">True to skip confirmation question, false to show question</param>
procedure SetSkipChangeDimensionsQst(Skip: Boolean)
begin
SkipChangeDimensionsQst := Skip;
end;
/// <summary>
/// Sets flag to skip dimension updates.
/// </summary>
/// <param name="Skip">True to skip dimension updates, false to perform updates</param>
procedure SetSkipUpdateDimensions(Skip: Boolean)
begin
SkipUpdateDimensions := Skip;
end;
/// <summary>
/// Gets flag indicating whether dimension updates should be skipped.
/// </summary>
/// <returns>True if dimension updates should be skipped, false otherwise</returns>
procedure GetSkipUpdateDimensions(): Boolean
begin
exit(SkipUpdateDimensions);
end;
/// <summary>
/// Adds or updates the dimension value for the specified dimension set.
/// </summary>
/// <param name="DimSetID">Specifies the dimension set that is going to be updated.</param>
/// <param name="DimensionCode">Specifies the code of the dimension that is going to be updated.</param>
/// <param name="DimensionValueCode">Specifies the code of the dimension value that is going to set in the dimension set.</param>
/// <param name="AutoCreateMissingDimension">Specifies whether the dimension will be created if it doesn't exist.</param>
/// <param name="AutoCreateMissingDimensionValue">Specifies whether the dimension value will be created if it doesn't exist.</param>
/// <returns>Returns the new dimension set ID.</returns>
procedure SetDimensionValue(DimSetID: Integer; DimensionCode: Code[20]; DimensionValueCode: Code[20]; AutoCreateMissingDimension: Boolean; AutoCreateMissingDimensionValue: Boolean): Integer
begin
exit(SetDimensionValue(DimSetID, DimensionCode, '', DimensionValueCode, '', AutoCreateMissingDimension, AutoCreateMissingDimensionValue));
end;
/// <summary>
/// Adds or updates the dimension value for the specified dimension set. Any dimension or dimension value that doesn't exist will be created automatically.
/// </summary>
/// <param name="DimSetID">Specifies the dimension set that is going to be updated.</param>
/// <param name="DimensionCode">Specifies the code of the dimension that is going to be updated.</param>
/// <param name="DimensionValueCode">Specifies the code of the dimension value that is going to set in the dimension set.</param>
/// <param name="DimensionName">Specifies the name of the dimension, if the the dimension doesn't exist yet.</param>
/// <param name="DimensionValueName">Specifies the name of the dimension value, if the dimension value doesn't exist yet.</param>
/// <returns>Returns the new dimension set ID.</returns>
procedure SetDimensionValue(DimSetID: Integer; DimensionCode: Code[20]; DimensionValueCode: Code[20]; DimensionName: Text[30]; DimensionValueName: Text[50]): Integer
begin
exit(SetDimensionValue(DimSetID, DimensionCode, DimensionName, DimensionValueCode, DimensionValueName, true, true));
end;
/// <summary>
/// Adds or updates the dimension value for the specified dimension set.
/// </summary>
/// <param name="DimSetID">Specifies the dimension set that is going to be updated.</param>
/// <param name="DimensionCode">Specifies the code of the dimension that is going to be updated.</param>
/// <param name="DimensionValueCode">Specifies the code of the dimension value that is going to set in the dimension set.</param>
/// <param name="DimensionName">Specifies the name of the dimension, if the the dimension doesn't exist yet.</param>
/// <param name="DimensionValueName">Specifies the name of the dimension value, if the the dimension value doesn't exist yet.</param>
/// <param name="AutoCreateMissingDimension">Specifies whether the dimension will be create if it doesn't exist.</param>
/// <param name="AutoCreateMissingDimensionValue">Specifies whether the dimension value will be create if doesn't exist.</param>
/// <returns>Returns the new dimension set ID.</returns>
procedure SetDimensionValue(DimSetID: Integer; DimensionCode: Code[20]; DimensionName: Text[30]; DimensionValueCode: Code[20]; DimensionValueName: Text[50]; AutoCreateMissingDimension: Boolean; AutoCreateMissingDimensionValue: Boolean): Integer
var
TempDimensionSetEntry: Record "Dimension Set Entry" temporary;
Dimension: Record Dimension;
DimensionValue: Record "Dimension Value";
DimensionManagement: Codeunit DimensionManagement;
begin
if '' in [DimensionCode, DimensionValueCode] then
exit(DimSetID);
if AutoCreateMissingDimension then
if not Dimension.Get(DimensionCode) then
CreateDimension(Dimension, DimensionCode, DimensionName);
if AutoCreateMissingDimensionValue then
if not DimensionValue.Get(DimensionCode, DimensionValueCode) then
CreateDimensionValue(DimensionValue, DimensionCode, DimensionValueCode, DimensionValueName);
DimensionManagement.GetDimensionSet(TempDimensionSetEntry, DimSetID);
if not TempDimensionSetEntry.Get(DimSetID, DimensionCode) then begin
TempDimensionSetEntry.Init();
TempDimensionSetEntry.Validate("Dimension Set ID", DimSetID);
TempDimensionSetEntry.Validate("Dimension Code", DimensionCode);
TempDimensionSetEntry.Insert(true);
end;
TempDimensionSetEntry.Validate("Dimension Value Code", DimensionValueCode);
TempDimensionSetEntry.Modify(true);
exit(DimensionManagement.GetDimensionSetID(TempDimensionSetEntry));
end;
local procedure CreateDimension(var Dimension: Record Dimension; DimensionCode: Code[20]; DimensionName: Text[30])
begin
Dimension.Init();
Dimension.Validate("Code", DimensionCode);
Dimension.Validate(Name, DimensionName);
Dimension.Insert(true);
end;
local procedure CreateDimensionValue(var DimensionValue: Record "Dimension Value"; DimensionCode: Code[20]; DimensionValueCode: Code[20]; DimensionValueName: Text[50])
begin
DimensionValue.Init();
DimensionValue.Validate("Code", DimensionValueCode);
DimensionValue.Validate("Dimension Code", DimensionCode);
DimensionValue.Validate(Name, DimensionValueName);
DimensionValue.Insert(true);
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCheckDimValuePosting(TableID: array[10] of Integer; No: array[10] of Code[20]; var TempDefaultDim: Record "Default Dimension" temporary)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCheckDimValue(DimCode: Code[20]; DimValCode: Code[20]; var Result: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterConvertDimtoICDim(FromDim: Code[20]; var ICDimCode: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterConvertDimValuetoICDimVal(FromDimCode: Code[20]; FromDimValue: Code[20]; var ICDimValueCode: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterConvertICDimtoDim(FromICDimCode: Code[20]; var DimCode: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterConvertICDimValuetoDimValue(FromICDimCode: Code[20]; FromICDimValue: Code[20]; var DimValueCode: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCreateDimForJobJournalLineWithHigherPrioritiesProcedure(JobJournalLine: Record "Job Journal Line"; CurrFieldNo: Integer; var DimensionSetID: Integer; var DimValue1: Code[20]; var DimValue2: Code[20]; SourceCode: Code[10]; PriorityTableID: Integer; var DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; var HighPriorityDefaultDimSource: List of [Dictionary of [Integer, Code[20]]])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterEditDimensionSet2(var DimSetID: Integer; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterDeleteDefaultDim(TableID: Integer; No: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetupObjectNoList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnAfterDefaultDimObjectNoWithoutGlobalDimsList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterIsDefaultDimTable(TableID: Integer; var Result: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetSourceCodeWithVar(TableID: Integer; RecordVar: Variant; var SourceCode: Code[10])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterUpdateGenJnlLineDim(var GenJournalLine: Record "Gen. Journal Line"; DimSetID: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterUpdateDefaultDim(TableID: Integer; No: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterUpdateJobTaskDim(DefaultDimension: Record "Default Dimension")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterValidateDimValueCode(FieldNumber: Integer; var ShortcutDimCode: Code[20]; var GLSetupShortcutDimCode: array[8] of Code[20]; DimensionValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterValidateShortcutDimValues(FieldNumber: Integer; var ShortcutDimCode: Code[20]; var DimSetID: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAddDefaultDimensionAllowedDimensionValueOnAfterSetFilters(var DefaultDimension: Record "Default Dimension")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeAddDefaultDimensionAllowedDimensionValue(DimensionValue: Record "Dimension Value"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckDim(DimCode: Code[20]; var Result: Boolean; var IsHandled: Boolean; var Dimension: Record Dimension)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckDimComb(var DimensionCombination: Record "Dimension Combination"; var TempDimensionBuffer: Record "Dimension Buffer" temporary)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckDimValueComb(var DimensionValueCombination: Record "Dimension Value Combination")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckDimValue(DimCode: Code[20]; DimValCode: Code[20]; var Result: Boolean; var IsHandled: Boolean; var DimVal: Record "Dimension Value");
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckDimValueAllowed(var DimensionValue: Record "Dimension Value"; var IsHandled: Boolean; var Result: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckDimValuePosting(TableID: array[10] of Integer; No: array[10] of Code[20]; DimSetID: Integer; var IsChecked: Boolean; var IsHandled: Boolean; var DimensionSetEntry: Record "Dimension Set Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckICDim(ICDimCode: Code[20]; var Result: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetDimensionSetIDProcedure(var DimensionSetEntry: Record "Dimension Set Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckICDimValue(ICDimCode: Code[20]; ICDimValCode: Code[20]; var Result: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckValuePosting(TableID: array[10] of Integer; No: array[10] of Code[20]; var TempDimBuf: Record "Dimension Buffer" temporary; var IsChecked: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeConvertDimValuetoICDimVal(var DimValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCreateDimSetIDFromICDocDim(var DimValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCreateDimSetIDFromICJnlLineDim(var DimValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCopyDimBufToDimSetEntry(var DimValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCreateDimSetIDFromDimBuf(var DimValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeDefaultDimOnInsert(var DefaultDimension: Record "Default Dimension"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeDefaultDimOnDelete(var DefaultDimension: Record "Default Dimension"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeDefaultDimOnModify(var DefaultDimension: Record "Default Dimension"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetDimensionSet(var TempDimensionSetEntry: Record "Dimension Set Entry" temporary; var DimSetID: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeEditDimensionSet(DimSetID: Integer; NewCaption: Text[250]; var NewDimSetID: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeEditDimensionSet2(DimSetID: Integer; NewCaption: Text[250]; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20]; var NewDimSetID: Integer; var IsHandled: Boolean; RecVariant: Variant)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetDeltaDimSetID(var DimSetID: Integer; NewParentDimSetID: Integer; OldParentDimSetID: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetTableIDsForHigherPrioritiesProcedure(TableNo: Integer; RecVar: Variant; var FieldNo: Integer; var DefaultDimSource: List of [Dictionary of [Integer, Code[20]]])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeInsertJobTaskDim(JobNo: Code[20]; JobTaskNo: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeLookupDimValueCode(FieldNumber: Integer; var ShortcutDimCode: Code[20]; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeLookupDimValueCodeNoUpdate(FieldNumber: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeParseDimParam(var DimensionValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSaveDefaultDim(TableID: Integer; No: Code[20]; FieldNumber: Integer; ShortcutDimCode: Code[20]; var IsHandled: Boolean);
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSetupObjectNoList(var TempDimField: Record Field temporary)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeUpdateDefaultDim(TableID: Integer; No: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; var IsHandled: Boolean);
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeValidateDimValueCode(FieldNumber: Integer; var ShortcutDimCode: Code[20]; var IsHandled: Boolean; var GLSetupShortcutDimCode: array[8] of Code[20]; var DimVal: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeValidateShortcutDimValues(var DimVal: Record "Dimension Value"; FieldNumber: Integer; var ShortcutDimCode: Code[20]; var DimSetID: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnParseDimParamOnBeforeTempDimensionValueFindSet(var DimensionValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnTypeToTableID2(var TableID: Integer; Type: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckDimValueAllowed(DimVal: Record "Dimension Value"; var DimValueAllowed: Boolean; var DimErr: Text[250])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckICDimValueAllowed(ICDimVal: Record "IC Dimension Value"; var DimValueAllowed: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnGetDefaultDimIDOnAfterAttributeGlobalDims(var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnGetDefaultDimOnBeforeCreate(var TempDimBuf: Record "Dimension Buffer" temporary; TableID: Integer; No: Code[20]; GLSetupShortcutDimCode: array[8] of Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; var IsHandled: Boolean; SourceCode: Code[20])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnUpdateJobTaskDimOnBeforConfirm(DefaultDimension: Record "Default Dimension"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnGetDefaultDimIDOnBeforeTempDimSetEntryInsert(var DimensionSetEntry: Record "Dimension Set Entry"; var DimensionBuffer: Record "Dimension Buffer"; SourceCode: Code[20]);
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterTypeToTableID1(Type: Integer; var TableId: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSalesLineTypeToTableID(Type: Enum "Sales Line Type"; var TableId: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterPurchLineTypeToTableID(Type: Enum "Purchase Line Type"; var TableId: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterReqLineTypeToTableID(Type: Enum "Requisition Line Type"; var TableId: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterTypeToTableID4(Type: Integer; var TableId: Integer)
begin
end;
#if not CLEAN27
[Obsolete('This event is never raised.', '27.0')]
[IntegrationEvent(false, false)]
local procedure OnAfterTypeToTableID5(Type: Integer; var TableId: Integer)
begin
end;
#endif
[IntegrationEvent(false, false)]
local procedure OnBeforeGetDimensionSetID(var TempDimSetEntry: Record "Dimension Set Entry" temporary)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnEditDimensionSetOnBeforeEditDimEntries(var EditDimSetEntries: Page "Edit Dimension Set Entries")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnLookupDimValueCodeOnBeforeDimValRunModal(var DimensionValue: Record "Dimension Value"; FieldNumber: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckDimValuePostingOnBeforeLogErrors(TempDefaultDim: Record "Default Dimension" temporary; var DimSetEntry: Record "Dimension Set Entry"; var LastErrorMessage: Record "Error Message"; var ErrorMessageMgt: Codeunit "Error Message Management"; var isHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckValuePostingOnBeforeExit(TableID: array[10] of Integer; No: array[10] of Code[20]; var TempDimensionBuffer: Record "Dimension Buffer" temporary; var LastErrorMessage: Record "Error Message"; var ErrorMessageManagement: Codeunit "Error Message Management"; var IsChecked: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckValuePostingOnAfterDefaultDimLoop(var TempDimBuf: Record "Dimension Buffer" temporary; var DefaultDim: Record "Default Dimension")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckDimValuePostingOnBeforeExit(TableID: array[10] of Integer; No: array[10] of Code[20]; DimSetID: Integer; var LastErrorMessage: Record "Error Message"; var ErrorMessageManagement: Codeunit "Error Message Management"; var IsChecked: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCreateDimSetFromJobTaskDim(JobNo: Code[20]; JobTaskNo: Code[20]; var GlobalDimVal1: Code[20]; var GlobalDimVal2: Code[20]; var NewDimSetID: Integer; var IsHandled: Boolean; var DimValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetRecDefaultDimID(RecVariant: Variant; CurrFieldNo: Integer; var DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; var SourceCode: Code[20]; var InheritFromDimSetID: Integer; var InheritFromTableNo: Integer; var Result: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterGetRecDefaultDimIDProcedure(RecVariant: Variant; CurrFieldNo: Integer; var DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; var SourceCode: Code[20]; var InheritFromDimSetID: Integer; var InheritFromTableNo: Integer; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; var DefaultDimSetID: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetDefaultDimIDProcedure(var DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; SourceCode: Code[20]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; InheritFromDimSetID: Integer; InheritFromTableNo: Integer; var DimVal: Record "Dimension Value"; var Result: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnGetDefaultDimIDOnBeforeFindNewDimSetIDProcedure(var TempDimensionBuffer: Record "Dimension Buffer" temporary; DefaultDimSource: List of [Dictionary of [Integer, Code[20]]]; var GlobalDim1Code: Code[20]; var GlobalDim2Code: Code[20]; SourceCode: Code[20]; GLSetupShortcutDimCode: array[8] of Code[20]; var TempDimensionSetEntry0: Record "Dimension Set Entry" temporary; InheritFromDimSetID: Integer; InheritFromTableNo: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnGetDefaultDimIDOnBeforeGetInheritDimensionSet(var TempDimensionSetEntry0: Record "Dimension Set Entry" temporary; var InheritFromDimSetID: Integer; var InheritFromTableNo: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnAfterUseShortcutDims(var DimVisible1: Boolean; var DimVisible2: Boolean; var DimVisible3: Boolean; var DimVisible4: Boolean; var DimVisible5: Boolean; var DimVisible6: Boolean; var DimVisible7: Boolean; var DimVisible8: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCopyJobTaskDimToJobTaskDim(JobNo: Code[20]; JobTaskNo: Code[20]; NewJobNo: Code[20]; NewJobTaskNo: Code[20]; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckDimValueCombOnBeforeLogError(Dim1: Code[20]; Dim1Value: Code[20]; Dim2: Code[20]; Dim2Value: Code[20]; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCheckDimValueOnBeforeCheckDimValBlocked(DimCode: Code[20]; DimValCode: Code[20]; var Result: Boolean; var IsHandled: Boolean; var DimensionValue: Record "Dimension Value")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetSourceCode(var SourceCodeSetup: Record "Source Code Setup"; TableID: Integer; var SourceCode: Code[10]);
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAllowedDimensionValueConfirm(var DimensionValue: Record "Dimension Value"; var DefaultDimension: Record "Default Dimension"; var Confirmed: Boolean; var ConfirmHandled: Boolean);
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterEditDimensionSet(var DimSetID: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterDefaultDimObjectNoList(var TempAllObjWithCaption: Record AllObjWithCaption temporary)
begin
end;
}