Codeunit 411 Dimension Buffer Management, source in 29

Source29

src/Layers/W1/BaseApp/Finance/Dimension/DimensionBufferManagement.Codeunit.al357 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.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.Finance.Dimension;

/// <summary>
/// Manages dimension buffer operations for temporary storage and retrieval of dimension data.
/// Provides functionality to insert, find, retrieve, and manage dimension entries in temporary buffers
/// used for dimension analysis and reporting scenarios.
/// </summary>
codeunit 411 "Dimension Buffer Management"
{

    trigger OnRun()
    begin
    end;

    var
        TempDimensionIDBuffer: Record "Dimension ID Buffer" temporary;
        TempDimBuf: Record "Dimension Buffer" temporary;
        TempDimEntryBuf: Record "Dimension Entry Buffer" temporary;
        NextDimBufNo: Integer;

    /// <summary>
    /// Inserts dimension entries into the buffer and returns a new entry number.
    /// Creates a new entry set in the dimension buffer with sequential entry numbering.
    /// </summary>
    /// <param name="DimBuf">Dimension buffer containing dimensions to insert</param>
    /// <returns>Entry number assigned to the inserted dimension set, zero if no dimensions provided</returns>
    procedure InsertDimensions(var DimBuf: Record "Dimension Buffer"): Integer
    var
        NewEntryNo: Integer;
    begin
        if DimBuf.FindSet() then begin
            TempDimBuf.Reset();
            TempDimBuf.SetCurrentKey("Entry No.");
            if TempDimBuf.FindLast() then
                NewEntryNo := TempDimBuf."Entry No." + 1
            else
                NewEntryNo := 1;
            InsertDimensionsUsingEntryNo(DimBuf, NewEntryNo);
            exit(NewEntryNo);
        end;
        exit(0);
    end;

    /// <summary>
    /// Inserts dimension entries into the buffer using a specific entry number.
    /// Assigns the provided entry number to all dimensions in the buffer set.
    /// </summary>
    /// <param name="DimBuf">Dimension buffer containing dimensions to insert</param>
    /// <param name="EntryNo">Specific entry number to assign to the dimension set</param>
    procedure InsertDimensionsUsingEntryNo(var DimBuf: Record "Dimension Buffer"; EntryNo: Integer)
    var
        DimCount: Integer;
        IsHandled: Boolean;
    begin
        DimCount := DimBuf.Count();
        if DimBuf.Find('-') then
            repeat
                TempDimBuf.Init();
                TempDimBuf := DimBuf;
                TempDimBuf."Entry No." := EntryNo;
                TempDimBuf."No. Of Dimensions" := DimCount;
                IsHandled := false;
                OnInsertDimensionsUsingEntryNoOnBeforeTempDimBufInsert(TempDimBuf, DimBuf, EntryNo, IsHandled);
                if not IsHandled then
                    TempDimBuf.Insert();
            until DimBuf.Next() = 0;
    end;

    /// <summary>
    /// Finds existing dimension set in the buffer and returns its entry number.
    /// Searches for a matching set of dimensions and returns the entry number if found.
    /// </summary>
    /// <param name="DimBuf">Dimension buffer containing dimensions to search for</param>
    /// <returns>Entry number of matching dimension set, zero if not found</returns>
    procedure FindDimensions(var DimBuf: Record "Dimension Buffer"): Integer
    begin
        exit(FindDimensionsKnownDimBufCount(DimBuf, DimBuf.Count));
    end;

    /// <summary>
    /// Finds existing dimension set with known dimension count and returns its entry number.
    /// Optimized search method when the number of dimensions in the set is already known.
    /// </summary>
    /// <param name="DimBuf">Dimension buffer containing dimensions to search for</param>
    /// <param name="DimBufCount">Known count of dimensions in the buffer for optimization</param>
    /// <returns>Entry number of matching dimension set, zero if not found</returns>
    procedure FindDimensionsKnownDimBufCount(var DimBuf: Record "Dimension Buffer"; DimBufCount: Integer): Integer
    var
        Found: Boolean;
        EndOfDimBuf: Boolean;
        EndOfTempDimBuf: Boolean;
        PrevEntryNo: Integer;
    begin
        if not DimBuf.Find('-') then
            exit(0);

        TempDimBuf.Reset();
        TempDimBuf.SetCurrentKey("No. Of Dimensions");
        TempDimBuf.SetRange("No. Of Dimensions", DimBufCount);
        TempDimBuf.SetRange("Table ID", DimBuf."Table ID");
        TempDimBuf.SetRange("Dimension Code", DimBuf."Dimension Code");
        TempDimBuf.SetRange("Dimension Value Code", DimBuf."Dimension Value Code");
        OnFindDimensionsKnownDimBufCountBeforeProcessingLinesOnAfterFilterTempDimBuf(TempDimBuf, DimBuf);
        if not TempDimBuf.Find('-') then begin
            TempDimBuf.Reset();
            exit(0);
        end;
        if TempDimBuf."No. Of Dimensions" = 1 then begin
            TempDimBuf.Reset();
            exit(TempDimBuf."Entry No.");
        end;

        DimBuf.Next();
        while (not EndOfTempDimBuf) and (not Found) do begin
            PrevEntryNo := TempDimBuf."Entry No.";
            EndOfDimBuf := false;
            TempDimBuf.SetFilter("Entry No.", '>=%1', TempDimBuf."Entry No.");
            repeat
                TempDimBuf.SetRange("Dimension Code", DimBuf."Dimension Code");
                TempDimBuf.SetRange("Dimension Value Code", DimBuf."Dimension Value Code");
                OnFindDimensionsKnownDimBufCountOnAfterFilterTempDimBuf(TempDimBuf, DimBuf);
                EndOfTempDimBuf := not TempDimBuf.Find('-');
                if not EndOfTempDimBuf then
                    EndOfDimBuf := DimBuf.Next() = 0;
            until EndOfTempDimBuf or EndOfDimBuf or (PrevEntryNo <> TempDimBuf."Entry No.");
            if EndOfDimBuf and (PrevEntryNo = TempDimBuf."Entry No.") then
                Found := true
            else
                DimBuf.Find('-');
        end;
        TempDimBuf.Reset();
        if Found then
            exit(TempDimBuf."Entry No.");

        exit(0);
    end;

    /// <summary>
    /// Retrieves all dimensions for a specific entry number into the dimension buffer.
    /// Populates the provided dimension buffer with all dimensions associated with the entry number.
    /// </summary>
    /// <param name="EntryNo">Entry number to retrieve dimensions for</param>
    /// <param name="DimBuf">Dimension buffer to populate with the retrieved dimensions</param>
    /// <returns>True if dimensions were found and retrieved, false if entry number not found</returns>
    procedure GetDimensions(EntryNo: Integer; var DimBuf: Record "Dimension Buffer"): Boolean
    begin
        TempDimBuf.SetRange("Entry No.", EntryNo);
        if not TempDimBuf.Find('-') then
            exit(false);

        repeat
            DimBuf.Init();
            DimBuf := TempDimBuf;
            DimBuf.Insert();
        until TempDimBuf.Next() = 0;
        exit(true);
    end;

    /// <summary>
    /// Clears all dimension entries from the temporary dimension buffer.
    /// Removes all stored dimension data to prepare for new operations.
    /// </summary>
    procedure DeleteAllDimensions()
    begin
        TempDimBuf.Reset();
        TempDimBuf.DeleteAll();
    end;

    /// <summary>
    /// Collects dimension entry numbers for selected dimensions in analysis scenarios.
    /// Manages dimension entry collection for analysis views and reporting with optional collection control.
    /// </summary>
    /// <param name="SelectedDim">Selected dimensions to collect entries for</param>
    /// <param name="DimSetID">Dimension set ID to process</param>
    /// <param name="EntryNo">Entry number being processed</param>
    /// <param name="ForgetDimEntryNo">Dimension entry number to remove from collection</param>
    /// <param name="DoCollect">Whether to actually collect the dimension entry</param>
    /// <param name="DimEntryNo">Variable to receive the collected dimension entry number</param>
    procedure CollectDimEntryNo(var SelectedDim: Record "Selected Dimension"; DimSetID: Integer; EntryNo: Integer; ForgetDimEntryNo: Integer; DoCollect: Boolean; var DimEntryNo: Integer)
    var
        TempDimBuf: Record "Dimension Buffer" temporary;
        DimSetEntry: Record "Dimension Set Entry";
    begin
        if SelectedDim.Find('-') then begin
            repeat
                if DimSetEntry.Get(DimSetID, SelectedDim."Dimension Code") then begin
                    TempDimBuf."Dimension Code" := DimSetEntry."Dimension Code";
                    TempDimBuf."Dimension Value Code" := DimSetEntry."Dimension Value Code";
                    TempDimBuf.Insert();
                end;
            until SelectedDim.Next() = 0;
            DimEntryNo := FindDimensions(TempDimBuf);
            if DimEntryNo = 0 then
                DimEntryNo := InsertDimensions(TempDimBuf);
        end else
            DimEntryNo := 0;

        if (DimEntryNo <> ForgetDimEntryNo) and DoCollect then begin
            TempDimEntryBuf."No." := EntryNo;
            TempDimEntryBuf."Dimension Entry No." := DimEntryNo;
            TempDimEntryBuf.Insert();
        end;
    end;

    /// <summary>
    /// Finds the first dimension entry number and corresponding entry number in the collection.
    /// Initializes iteration through collected dimension entries for analysis processing.
    /// </summary>
    /// <param name="DimEntryNo">Variable to receive the first dimension entry number</param>
    /// <param name="EntryNo">Variable to receive the first entry number</param>
    /// <returns>True if entries exist and first entry found, false if collection is empty</returns>
    procedure FindFirstDimEntryNo(var DimEntryNo: Integer; var EntryNo: Integer): Boolean
    var
        Found: Boolean;
    begin
        TempDimEntryBuf.SetCurrentKey("Dimension Entry No.");
        Found := TempDimEntryBuf.Find('-');
        DimEntryNo := TempDimEntryBuf."Dimension Entry No.";
        EntryNo := TempDimEntryBuf."No.";
        exit(Found);
    end;

    /// <summary>
    /// Advances to the next dimension entry number and corresponding entry number in the collection.
    /// Continues iteration through collected dimension entries for analysis processing.
    /// </summary>
    /// <param name="DimEntryNo">Variable to receive the next dimension entry number</param>
    /// <param name="EntryNo">Variable to receive the next entry number</param>
    /// <returns>True if next entry exists, false if end of collection reached</returns>
    procedure NextDimEntryNo(var DimEntryNo: Integer; var EntryNo: Integer): Boolean
    var
        Found: Boolean;
    begin
        Found := TempDimEntryBuf.Next() <> 0;
        DimEntryNo := TempDimEntryBuf."Dimension Entry No.";
        EntryNo := TempDimEntryBuf."No.";
        exit(Found);
    end;

    /// <summary>
    /// Clears all collected dimension entry numbers from the collection.
    /// Removes all entries from the dimension entry buffer to prepare for new collection.
    /// </summary>
    procedure DeleteAllDimEntryNo()
    begin
        TempDimEntryBuf.DeleteAll();
    end;

    /// <summary>
    /// Gets or creates a unique dimension ID for a dimension combination.
    /// Returns an existing ID if the dimension combination already exists, or creates a new one.
    /// </summary>
    /// <param name="Dimbuf">Dimension buffer containing dimensions to get ID for</param>
    /// <returns>Unique dimension ID for the dimension combination, zero if no dimensions provided</returns>
    procedure GetDimensionId(var Dimbuf: Record "Dimension Buffer"): Integer
    var
        NewDimensionComb: Boolean;
    begin
        if not Dimbuf.FindFirst() then
            exit(0);

        if NextDimBufNo = 0 then
            NextDimBufNo := 1;

        NewDimensionComb := false;
        TempDimensionIDBuffer.ID := 0;
        repeat
            if NewDimensionComb then
                InsertDimIdBuf(Dimbuf)
            else
                if not TempDimensionIDBuffer.Get(TempDimensionIDBuffer.ID, Dimbuf."Dimension Code", Dimbuf."Dimension Value Code") then begin
                    NewDimensionComb := true;
                    InsertDimIdBuf(Dimbuf);
                end;
        until Dimbuf.Next() = 0;

        exit(TempDimensionIDBuffer.ID);
    end;

    /// <summary>
    /// Retrieves all dimensions for a specific dimension ID into a dimension buffer.
    /// Reconstructs the dimension combination from the dimension ID buffer into the provided buffer.
    /// </summary>
    /// <param name="DimId">Dimension ID to retrieve dimensions for</param>
    /// <param name="DimBuf">Dimension buffer to populate with the retrieved dimensions</param>
    procedure RetrieveDimensions(DimId: Integer; var DimBuf: Record "Dimension Buffer")
    begin
        DimBuf.Reset();
        DimBuf.DeleteAll();

        if DimId <= 0 then
            exit;

        TempDimensionIDBuffer.SetCurrentKey(ID);
        TempDimensionIDBuffer.SetRange(ID, DimId);
        repeat
            TempDimensionIDBuffer.FindFirst();
            DimBuf.Init();
            DimBuf."Entry No." := DimId;
            DimBuf."Dimension Code" := TempDimensionIDBuffer."Dimension Code";
            DimBuf."Dimension Value Code" := TempDimensionIDBuffer."Dimension Value";
            DimBuf.Insert();
            TempDimensionIDBuffer.SetRange(ID, TempDimensionIDBuffer."Parent ID");
        until TempDimensionIDBuffer."Parent ID" = 0;
    end;

    local procedure InsertDimIdBuf(var DimBuf: Record "Dimension Buffer")
    begin
        TempDimensionIDBuffer."Parent ID" := TempDimensionIDBuffer.ID;
        TempDimensionIDBuffer."Dimension Code" := DimBuf."Dimension Code";
        TempDimensionIDBuffer."Dimension Value" := DimBuf."Dimension Value Code";
        TempDimensionIDBuffer.ID := NextDimBufNo;
        NextDimBufNo += 1;
        TempDimensionIDBuffer.Insert();
    end;

    /// <summary>
    /// Integration event raised before inserting a dimension buffer entry during dimension insertion.
    /// Allows customization of dimension buffer data before the entry is inserted.
    /// </summary>
    /// <param name="TempDimBuf">Temporary dimension buffer being prepared for insertion</param>
    /// <param name="DimBuf">Source dimension buffer containing original dimension data</param>
    /// <param name="EntryNo">Entry number being assigned to the dimension set</param>
    /// <param name="IsHandled">Set to true to skip the standard insertion logic</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertDimensionsUsingEntryNoOnBeforeTempDimBufInsert(var TempDimBuf: Record "Dimension Buffer"; var DimBuf: Record "Dimension Buffer"; EntryNo: Integer; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Integration event raised after filtering temporary dimension buffer during dimension search.
    /// Allows additional filtering logic before processing dimension matching lines.
    /// </summary>
    /// <param name="TempDimensionBuffer">Temporary dimension buffer with applied filters</param>
    /// <param name="DimensionBuffer">Source dimension buffer being searched for</param>
    [IntegrationEvent(false, false)]
    local procedure OnFindDimensionsKnownDimBufCountBeforeProcessingLinesOnAfterFilterTempDimBuf(var TempDimensionBuffer: Record "Dimension Buffer"; DimensionBuffer: Record "Dimension Buffer")
    begin
    end;

    /// <summary>
    /// Integration event raised after filtering temporary dimension buffer during dimension search.
    /// Allows additional filtering logic during the dimension matching process.
    /// </summary>
    /// <param name="TempDimensionBuffer">Temporary dimension buffer with applied filters</param>
    /// <param name="DimensionBuffer">Source dimension buffer being searched for</param>
    [IntegrationEvent(false, false)]
    local procedure OnFindDimensionsKnownDimBufCountOnAfterFilterTempDimBuf(var TempDimensionBuffer: Record "Dimension Buffer"; DimensionBuffer: Record "Dimension Buffer")
    begin
    end;
}