Codeunit 2581 Dim Correction Run

App
Base Application
Namespace
Microsoft.Finance.Dimension.Correction
Versions
18-28

Procedures, 1Events, 2

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/Finance/Dimension/Correction/DimCorrectionRun.Codeunit.al205 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.Correction;

using Microsoft.Finance.Dimension;
using Microsoft.Finance.GeneralLedger.Ledger;
using System.Threading;

/// <summary>
/// Executes dimension correction processing by updating G/L entries with corrected dimension values.
/// Runs as background job queue entry with comprehensive error handling and progress tracking.
/// </summary>
codeunit 2581 "Dim Correction Run"
{
    TableNo = "Job Queue Entry";
    Permissions = tabledata "G/L Entry" = rimd;

    trigger OnRun()
    var
        DimensionCorrection: Record "Dimension Correction";
    begin
        DimensionCorrection.Get(Rec."Record ID to Process");
        RunDimensionCorrection(DimensionCorrection);
    end;

    /// <summary>
    /// Processes dimension correction by updating all affected G/L entries with new dimension values.
    /// </summary>
    /// <param name="DimensionCorrection">Dimension correction record to process</param>
    procedure RunDimensionCorrection(var DimensionCorrection: Record "Dimension Correction")
    var
        TempDimCorrectionSetBuffer: Record "Dim Correction Set Buffer" temporary;
        ErrorCount: Integer;
    begin
        Session.LogMessage('0000EHC', StrSubstNo(StartingDimensionCorrectionTelemetryLbl, DimensionCorrection."Entry No."), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', DimensionCorrectionTok);
        DimensionCorrectionMgt.ValidateBlockedNotUsed(DimensionCorrection);
        DimensionCorrectionMgt.SetStatusInProgress(DimensionCorrection);

        DimensionCorrectionMgt.GenerateSupportingTables(DimensionCorrection, TempDimCorrectionSetBuffer);

        if not DimensionCorrection."Validated Selected Entries" then begin
            DimensionCorrectionMgt.ValidateDimensionSets(DimensionCorrection, TempDimCorrectionSetBuffer, ErrorCount);
            DimensionCorrectionMgt.ValidateDimensionChanges(DimensionCorrection, TempDimCorrectionSetBuffer, ErrorCount);
        end;

        ChangeLedgerEntries(DimensionCorrection, TempDimCorrectionSetBuffer);

        DimensionCorrection.GetBySystemId(DimensionCorrection.SystemId);
        DimensionCorrection.Status := DimensionCorrection.Status::Completed;
        DimensionCorrection.Completed := true;
        DimensionCorrection.Modify();
        Commit();
        if DimensionCorrection."Update Analysis Views" then
            DimensionCorrectionMgt.ScheduleUpdateAnalysisViews(DimensionCorrection);

        Session.LogMessage('0000EHH', StrSubstNo(CompletedDimensionCorrectionTelemetryLbl, DimensionCorrection."Entry No.", DimensionCorrection."Total Updated Ledger Entries"), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', DimensionCorrectionTok);
    end;

    local procedure ChangeLedgerEntries(var DimensionCorrection: Record "Dimension Correction"; var TempDimCorrectionSetBuffer: Record "Dim Correction Set Buffer" temporary)
    var
        LastDimCorrectionEntryLog: Record "Dim Correction Entry Log";
        DimCorrectionEntryLog: Record "Dim Correction Entry Log";
        TempInvalidatedDimCorrection: Record "Invalidated Dim Correction" temporary;
        UpdateCounter: Integer;
    begin
        Session.LogMessage('0000EHI', StrSubstNo(StartingChangeLedgerEntriesLbl, DimensionCorrection."Entry No."), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', DimensionCorrectionTok);
        UpdateCounter := 0;

        if DimensionCorrection."Last Updated Entry No." > 0 then begin
            LastDimCorrectionEntryLog.SetRange("Dimension Correction Entry No.", DimensionCorrection."Entry No.");
            LastDimCorrectionEntryLog.SetFilter("Start Entry No.", '<=%1', DimensionCorrection."Last Updated Entry No.");
            LastDimCorrectionEntryLog.SetFilter("End Entry No.", '>%1', DimensionCorrection."Last Updated Entry No.");
            if LastDimCorrectionEntryLog.FindFirst() then
                ChangeLedgerEntries(DimensionCorrection."Last Updated Entry No." + 1, LastDimCorrectionEntryLog."End Entry No.", UpdateCounter, TempInvalidatedDimCorrection, TempDimCorrectionSetBuffer, DimensionCorrection);
        end;

        DimCorrectionEntryLog.SetRange("Dimension Correction Entry No.", DimensionCorrection."Entry No.");
        DimCorrectionEntryLog.SetFilter("Start Entry No.", '>=%1', DimensionCorrection."Last Updated Entry No.");
        DimCorrectionEntryLog.SetCurrentKey("Start Entry No.");
        DimCorrectionEntryLog.Ascending(true);

        if DimCorrectionEntryLog.FindSet() then
            repeat
                ChangeLedgerEntries(DimCorrectionEntryLog."Start Entry No.", DimCorrectionEntryLog."End Entry No.", UpdateCounter, TempInvalidatedDimCorrection, TempDimCorrectionSetBuffer, DimensionCorrection);
            until DimCorrectionEntryLog.Next() = 0;

        if UpdateCounter > 0 then begin
            DimensionCorrection.Modify();
            commit();
        end;

        Session.LogMessage('0000EHK', StrSubstNo(CompletedChangeLedgerEntriesLbl, DimensionCorrection."Entry No."), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', DimensionCorrectionTok);
    end;

    local procedure ChangeLedgerEntries(StartEntryNo: Integer; EndEntryNo: Integer; var UpdateCounter: Integer; var TempInvalidatedDimCorrection: Record "Invalidated Dim Correction" temporary; var TempDimCorrectionSetBuffer: Record "Dim Correction Set Buffer" temporary; var DimensionCorrection: Record "Dimension Correction")
    var
        GLEntry: Record "G/L Entry";
        StartDateTime: DateTime;
    begin
        StartDateTime := CurrentDateTime();

        GLEntry.SetFilter("Entry No.", '>=%1&<=%2', StartEntryNo, EndEntryNo);
        if GLEntry.FindSet() then
            repeat
                TempDimCorrectionSetBuffer.Get(DimensionCorrection."Entry No.", GLEntry."Dimension Set ID");
                if UpdateGLEntry(GLEntry, DimensionCorrection."Entry No.", TempDimCorrectionSetBuffer, TempInvalidatedDimCorrection) then
                    DimensionCorrection."Total Updated Ledger Entries" += 1;

                DimensionCorrection."Last Updated Entry No." := GLEntry."Entry No.";

                UpdateCounter += 1;
                if UpdateCounter >= DimensionCorrectionMgt.GetCommitCount() then begin
                    UpdateCounter := 0;
                    DimensionCorrection.Modify();
                    Commit();
                    Session.LogMessage('0000EHJ', StrSubstNo(CommitedLedgerEntriesUpdateTelemetryLbl, DimensionCorrection."Entry No.", Format(CurrentDateTime() - StartDateTime), DimensionCorrectionMgt.GetCommitCount()), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', DimensionCorrectionTok);
                    StartDateTime := CurrentDateTime();
                end;
            until GLEntry.Next() = 0;

        if UpdateCounter > 0 then begin
            DimensionCorrection.Modify();
            Commit();
        end;
    end;

    local procedure UpdateGLEntry(var GLEntry: Record "G/L Entry"; DimensionCorrectionEntryNo: Integer; var TempDimCorrectionSetBuffer: Record "Dim Correction Set Buffer" temporary; var TempInvalidatedDimCorrection: Record "Invalidated Dim Correction" temporary) Result: Boolean
    var
        InvalidatedDimCorrection: Record "Invalidated Dim Correction";
        DimCorrectionSetBuffer: Record "Dim Correction Set Buffer";
        DimensionManagement: Codeunit "DimensionManagement";
    begin
        GLEntry."Dimension Set ID" := TempDimCorrectionSetBuffer."Target Set ID";
        DimensionManagement.UpdateGlobalDimFromDimSetID(
            GLEntry."Dimension Set ID", GLEntry."Global Dimension 1 Code", GLEntry."Global Dimension 2 Code");
        OnUpdateGLEntryOnAfterUpdateGlobalDimFromDimSetID(GLEntry);

        if TempDimCorrectionSetBuffer."Multiple Target Set ID" then begin
            DimCorrectionSetBuffer.Get(TempDimCorrectionSetBuffer.RecordId);
            DimCorrectionSetBuffer.AddLedgerEntry(GLEntry."Entry No.");
            DimCorrectionSetBuffer.Modify();
        end;

        GLEntry."Dimension Changes Count" += 1;
        TempInvalidatedDimCorrection.SetRange("Parent Node Id", GLEntry."Last Dim. Correction Node");
        TempInvalidatedDimCorrection.SetRange("Invalidated Entry No.", GLEntry."Last Dim. Correction Entry No.");
        TempInvalidatedDimCorrection.SetRange("Invalidated By Entry No.", DimensionCorrectionEntryNo);
        if not TempInvalidatedDimCorrection.FindFirst() then begin
            InvalidatedDimCorrection.SetRange("Parent Node Id", GLEntry."Last Dim. Correction Node");
            InvalidatedDimCorrection.SetRange("Invalidated Entry No.", GLEntry."Last Dim. Correction Entry No.");
            InvalidatedDimCorrection.SetRange("Invalidated By Entry No.", DimensionCorrectionEntryNo);

            if not InvalidatedDimCorrection.FindFirst() then begin
                InvalidatedDimCorrection."Parent Node Id" := GLEntry."Last Dim. Correction Node";
                InvalidatedDimCorrection."Invalidated Entry No." := GLEntry."Last Dim. Correction Entry No.";
                InvalidatedDimCorrection."Invalidated By Entry No." := DimensionCorrectionEntryNo;
                InvalidatedDimCorrection.Insert(true);
            end;

            TempInvalidatedDimCorrection.TransferFields(InvalidatedDimCorrection, true);
            TempInvalidatedDimCorrection.Insert(true);
        end;

        GLEntry."Last Dim. Correction Entry No." := DimensionCorrectionEntryNo;
        GLEntry."Last Dim. Correction Node" := TempInvalidatedDimCorrection."Node Id";
        GLEntry.Modify(true);

        Result := true;
        OnAfterUpdateGLEntry(GLEntry, TempDimCorrectionSetBuffer, Result, DimensionCorrectionEntryNo, TempInvalidatedDimCorrection);
    end;

    var
        DimensionCorrectionMgt: Codeunit "Dimension Correction Mgt";
        StartingDimensionCorrectionTelemetryLbl: Label 'Starting Dimension Correction, Dimension Correction Entry No.: %1.', Locked = true, Comment = '%1 Dimension Correction Entry No.';
        CompletedDimensionCorrectionTelemetryLbl: Label 'Completed Dimension Correction, Dimension Correction Entry No.: %1. Total number of updated entries %2.', Locked = true, Comment = '%1 Dimension Correction Entry No., %2 number of updated entries';
        StartingChangeLedgerEntriesLbl: Label 'Starting Change Ledger Entries, Dimension Correction Entry No.: %1.', Locked = true, Comment = '%1 Dimension Correction Entry No.';
        CompletedChangeLedgerEntriesLbl: Label 'Completed Change Ledger Entries, Dimension Correction Entry No.: %1.', Locked = true, Comment = '%1 Dimension Correction Entry No.';
        CommitedLedgerEntriesUpdateTelemetryLbl: Label 'Commited G/L Entries update. Dimension Correction Entry No.: %1, Time from last commit: %2. Number of entries iterated: %3.', Locked = true, Comment = '%1 Dimension Correction Entry No., %2 - Time passed between commits, %3 Number';
        DimensionCorrectionTok: Label 'DimensionCorrection', Locked = true;

    /// <summary>
    /// Integration event raised after updating a G/L entry during dimension correction processing.
    /// </summary>
    /// <param name="GLEntry">G/L entry that was updated</param>
    /// <param name="TempDimCorrectionSetBuffer">Temporary dimension correction set buffer</param>
    /// <param name="Result">Processing result status</param>
    /// <param name="DimensionCorrectionEntryNo">Entry number of the dimension correction</param>
    /// <param name="TempInvalidatedDimCorrection">Temporary invalidated dimension correction record</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateGLEntry(var GLEntry: Record "G/L Entry"; var TempDimCorrectionSetBuffer: Record "Dim Correction Set Buffer"; var Result: Boolean; DimensionCorrectionEntryNo: Integer; var TempInvalidatedDimCorrection: Record "Invalidated Dim Correction" temporary)
    begin
    end;

    /// <summary>
    /// Integration event raised after updating global dimensions from dimension set ID.
    /// </summary>
    /// <param name="GLEntry">G/L entry with updated global dimensions</param>
    [IntegrationEvent(false, false)]
    local procedure OnUpdateGLEntryOnAfterUpdateGlobalDimFromDimSetID(var GLEntry: Record "G/L Entry")
    begin
    end;
}