Codeunit 9079 Background Error Handling Mgt.

App
Base Application
Namespace
Microsoft.Utilities
Versions
17-28

Procedures, 26Events, 1Obsolete, 6

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/Utilities/BackgroundErrorHandlingMgt.Codeunit.al452 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.Utilities;

using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Inventory.Journal;
using Microsoft.Projects.Project.Journal;
using Microsoft.Projects.Resources.Journal;
using Microsoft.Purchases.Document;
using Microsoft.Sales.Document;
using System.Environment.Configuration;
using System.IO;
using System.Telemetry;
using System.Utilities;

codeunit 9079 "Background Error Handling Mgt."
{
    trigger OnRun()
    begin
    end;

    var
        JournalErrorsMgt: Codeunit "Journal Errors Mgt.";
        DocumentErrorsMgt: Codeunit "Document Errors Mgt.";
        ItemJournalErrorsMgt: Codeunit "Item Journal Errors Mgt.";
        JobJournalErrorsMgt: Codeunit "Job Journal Errors Mgt.";
        ResJournalErrorsMgt: Codeunit "Res. Journal Errors Mgt.";
        TranslationHelper: Codeunit "Translation Helper";
        FeatureTelemetry: Codeunit "Feature Telemetry";
        NullJSONTxt: Label 'null', Locked = true;
        CheckRunTxt: Label 'Check run', Locked = true;
        ErrorsFoundTxt: Label 'Errors Found', Locked = true;
        TableNameTxt: Label 'Table Name', Locked = true;
        DocumentTypeTxt: Label 'Document Type', Locked = true;
        TelemetryFeatureNameTxt: Label 'Check documents and journals while you work', Locked = true;

    procedure BackgroundValidationFeatureEnabled(): Boolean
    var
        GLSetup: Record "General Ledger Setup";
    begin
        GLSetup.Get();
        exit(GLSetup."Enable Data Check");
    end;

    procedure CleanTempErrorMessages(var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    begin
        CheckCleanDeletedGenJnlLinesErrors(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then begin
            TempErrorMessage.Reset();
            TempErrorMessage.DeleteAll();
        end else
            if ErrorHandlingParameters."Line Modified" then begin
                CleanDocumentRelatedErrors(
                    TempErrorMessage, ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name",
                    ErrorHandlingParameters."Previous Document No.", ErrorHandlingParameters."Previous Posting Date");
                CleanDocumentRelatedErrors(
                    TempErrorMessage, ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name",
                    ErrorHandlingParameters."Document No.", ErrorHandlingParameters."Posting Date");
            end;
    end;

    local procedure CheckCleanDeletedGenJnlLinesErrors(var TempErrorMessage: Record "Error Message" temporary)
    var
        TempGenJnlLine: Record "Gen. Journal Line" temporary;
    begin
        if JournalErrorsMgt.GetDeletedGenJnlLine(TempGenJnlLine, true) then begin
            TempErrorMessage.Reset();
            if TempGenJnlLine.FindSet() then
                repeat
                    TempErrorMessage.SetRange("Context Record ID", TempGenJnlLine.RecordId());
                    TempErrorMessage.DeleteAll();

                    CleanDocumentRelatedErrors(
                        TempErrorMessage, TempGenJnlLine."Journal Template Name", TempGenJnlLine."Journal Batch Name",
                        TempGenJnlLine."Document No.", TempGenJnlLine."Posting Date");
                until TempGenJnlLine.Next() = 0;
        end;
    end;

    procedure CleanItemJnlTempErrorMessages(var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        ItemJnlLine: Record "Item Journal Line";
    begin
        CheckCleanDeletedItemJnlLinesErrors(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then begin
            TempErrorMessage.Reset();
            TempErrorMessage.DeleteAll();
        end else begin
            if ItemJnlLine.Get(ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name", ErrorHandlingParameters."Line No.") then
                CleanItemJnlLineRelatedError(TempErrorMessage, ItemJnlLine);
            if ItemJnlLine.Get(ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name", ErrorHandlingParameters."Previous Line No.") then
                CleanItemJnlLineRelatedError(TempErrorMessage, ItemJnlLine);
        end;
    end;

    local procedure CleanItemJnlLineRelatedError(var TempErrorMessage: Record "Error Message" temporary; ItemJnlLine: Record "Item Journal Line")
    begin
        TempErrorMessage.SetRange("Context Table Number", Database::"Item Journal Line");
        TempErrorMessage.SetRange("Context Record ID", ItemJnlLine.RecordId());
        TempErrorMessage.DeleteAll();
    end;

    local procedure CheckCleanDeletedItemJnlLinesErrors(var TempErrorMessage: Record "Error Message" temporary)
    var
        TempItemJnlLine: Record "Item Journal Line" temporary;
    begin
        if ItemJournalErrorsMgt.GetDeletedItemJnlLine(TempItemJnlLine, true) then begin
            TempErrorMessage.Reset();
            if TempItemJnlLine.FindSet() then
                repeat
                    CleanItemJnlLineRelatedError(TempErrorMessage, TempItemJnlLine);
                until TempItemJnlLine.Next() = 0;
        end;
    end;

    local procedure CleanDocumentRelatedErrors(var TempErrorMessage: Record "Error Message" temporary; TemplateName: Code[10]; BatchName: Code[10]; DocumentNo: Code[20]; PostingDate: Date)
    var
        DocGenJnlLine: Record "Gen. Journal Line";
    begin
        TempErrorMessage.Reset();
        DocGenJnlLine.SetRange("Journal Template Name", TemplateName);
        DocGenJnlLine.SetRange("Journal Batch Name", BatchName);
        DocGenJnlLine.SetRange("Document No.", DocumentNo);
        DocGenJnlLine.SetRange("Posting Date", PostingDate);
        if DocGenJnlLine.FindSet() then
            repeat
                TempErrorMessage.SetRange("Context Record ID", DocGenJnlLine.RecordId());
                TempErrorMessage.DeleteAll();
            until DocGenJnlLine.Next() = 0;
    end;

    procedure CollectGenJnlCheckParameters(GenJnlLine: Record "Gen. Journal Line"; var ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        TempGenJnlLine: Record "Gen. Journal Line" temporary;
        TempxGenJnlLine: Record "Gen. Journal Line" temporary;
    begin
        ErrorHandlingParameters."Journal Template Name" := GenJnlLine."Journal Template Name";
        ErrorHandlingParameters."Journal Batch Name" := GenJnlLine."Journal Batch Name";
        ErrorHandlingParameters."Full Batch Check" := JournalErrorsMgt.GetFullBatchCheck();
        ErrorHandlingParameters."Line Modified" := JournalErrorsMgt.GetRecXRecOnModify(TempxGenJnlLine, TempGenJnlLine);
        ErrorHandlingParameters."Document No." := TempGenJnlLine."Document No.";
        ErrorHandlingParameters."Posting Date" := TempGenJnlLine."Posting Date";
        ErrorHandlingParameters."Previous Document No." := TempxGenJnlLine."Document No.";
        ErrorHandlingParameters."Previous Posting Date" := TempxGenJnlLine."Posting Date";
    end;

    procedure CollectItemJnlCheckParameters(ItemJnlLine: Record "Item Journal Line"; var ErrorHandlingParameters: Record "Error Handling Parameters")
    begin
        ErrorHandlingParameters."Journal Template Name" := ItemJnlLine."Journal Template Name";
        ErrorHandlingParameters."Journal Batch Name" := ItemJnlLine."Journal Batch Name";
        ErrorHandlingParameters."Line No." := ItemJnlLine."Line No.";
        ErrorHandlingParameters."Full Batch Check" := ItemJournalErrorsMgt.GetFullBatchCheck();
        ErrorHandlingParameters."Previous Line No." := ItemJournalErrorsMgt.GetItemJnlLinePreviousLineNo();
    end;

    procedure CollectSalesDocCheckParameters(SalesHeader: Record "Sales Header"; var ErrorHandlingParameters: Record "Error Handling Parameters")
    begin
        ErrorHandlingParameters."Document No." := SalesHeader."No.";
        ErrorHandlingParameters."Sales Document Type" := SalesHeader."Document Type";
        ErrorHandlingParameters."Full Document Check" := DocumentErrorsMgt.GetFullDocumentCheck();
        ErrorHandlingParameters."Line No." := DocumentErrorsMgt.GetModifiedSalesLineNo();
    end;

    procedure CollectPurchaseDocCheckParameters(PurchaseHeader: Record "Purchase Header"; var ErrorHandlingParameters: Record "Error Handling Parameters")
    begin
        ErrorHandlingParameters."Document No." := PurchaseHeader."No.";
        ErrorHandlingParameters."Purchase Document Type" := PurchaseHeader."Document Type";
        ErrorHandlingParameters."Full Document Check" := DocumentErrorsMgt.GetFullDocumentCheck();
        ErrorHandlingParameters."Line No." := DocumentErrorsMgt.GetModifiedPurchaseLineNo();
    end;


    procedure GetErrorsFromItemJnlCheckResultValues(ResultValues: List of [Text]; var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        ErrorMessageMgt: Codeunit "Error Message Management";
    begin
        CleanItemJnlTempErrorMessages(TempErrorMessage, ErrorHandlingParameters);
        ErrorMessageMgt.GetErrorsFromResultValues(ResultValues, TempErrorMessage);
        ItemJournalErrorsMgt.SetErrorMessages(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then
            ItemJournalErrorsMgt.SetFullBatchCheck(false);
    end;

    procedure GetErrorsFromResJnlCheckResultValues(ResultValues: List of [Text]; var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        ErrorMessageMgt: Codeunit "Error Message Management";
    begin
        CleanResJnlTempErrorMessages(TempErrorMessage, ErrorHandlingParameters);
        ErrorMessageMgt.GetErrorsFromResultValues(ResultValues, TempErrorMessage);
        ResJournalErrorsMgt.SetErrorMessages(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then
            ResJournalErrorsMgt.SetFullBatchCheck(false);
    end;

    procedure GetErrorsFromDocumentCheckResultValues(ResultValues: List of [Text]; var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        ErrorMessageMgt: Codeunit "Error Message Management";
    begin
        CleanSalesTempErrorMessages(TempErrorMessage, ErrorHandlingParameters);
        ErrorMessageMgt.GetErrorsFromResultValues(ResultValues, TempErrorMessage);
        DocumentErrorsMgt.SetErrorMessages(TempErrorMessage);

        if ErrorHandlingParameters."Full Document Check" then
            DocumentErrorsMgt.SetFullDocumentCheck(false);
    end;

    procedure CleanSalesTempErrorMessages(var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        TempSalesLine: Record "Sales Line" temporary;
    begin
        if ErrorHandlingParameters."Full Document Check" then begin
            TempErrorMessage.Reset();
            TempErrorMessage.DeleteAll();
        end else
            if ErrorHandlingParameters."Line No." <> 0 then begin
                TempSalesLine."Document Type" := ErrorHandlingParameters."Sales Document Type";
                TempSalesLine."Document No." := ErrorHandlingParameters."Document No.";
                TempSalesLine."Line No." := ErrorHandlingParameters."Line No.";
                TempErrorMessage.SetRange("Context Table Number", Database::"Sales Line");
                TempErrorMessage.SetRange("Context Record ID", TempSalesLine.RecordId());
                TempErrorMessage.DeleteAll();
            end;
    end;

    procedure CleanResJnlTempErrorMessages(var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        ResJnlLine: Record "Res. Journal Line";
    begin
        CheckCleanDeletedResJnlLinesErrors(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then begin
            TempErrorMessage.Reset();
            TempErrorMessage.DeleteAll();
        end else begin
            if ResJnlLine.Get(ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name", ErrorHandlingParameters."Line No.") then
                CleanResJnlLineRelatedError(TempErrorMessage, ResJnlLine);
            if ResJnlLine.Get(ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name", ErrorHandlingParameters."Previous Line No.") then
                CleanResJnlLineRelatedError(TempErrorMessage, ResJnlLine);
        end;
    end;

    local procedure CleanResJnlLineRelatedError(var TempErrorMessage: Record "Error Message" temporary; ResJnlLine: Record "Res. Journal Line")
    begin
        TempErrorMessage.SetRange("Context Table Number", Database::"Res. Journal Line");
        TempErrorMessage.SetRange("Context Record ID", ResJnlLine.RecordId());
        TempErrorMessage.DeleteAll();
    end;

    local procedure CheckCleanDeletedResJnlLinesErrors(var TempErrorMessage: Record "Error Message" temporary)
    var
        TempResJnlLine: Record "Res. Journal Line" temporary;
    begin
        if ResJournalErrorsMgt.GetDeletedResJnlLine(TempResJnlLine, true) then begin
            TempErrorMessage.Reset();
            if TempResJnlLine.FindSet() then
                repeat
                    CleanResJnlLineRelatedError(TempErrorMessage, TempResJnlLine);
                until TempResJnlLine.Next() = 0;
        end;
    end;

    procedure GetErrorsFromGenJnlCheckResultValues(ResultValues: List of [Text]; var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        ErrorMessageMgt: Codeunit "Error Message Management";
    begin
        CleanTempErrorMessages(TempErrorMessage, ErrorHandlingParameters);
        ErrorMessageMgt.GetErrorsFromResultValues(ResultValues, TempErrorMessage);
        JournalErrorsMgt.SetErrorMessages(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then
            JournalErrorsMgt.SetFullBatchCheck(false);
    end;

    procedure GetErrorsFromJobJnlCheckResultValues(ResultValues: List of [Text]; var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        ErrorMessageMgt: Codeunit "Error Message Management";
    begin
        CleanJobJnlTempErrorMessages(TempErrorMessage, ErrorHandlingParameters);
        ErrorMessageMgt.GetErrorsFromResultValues(ResultValues, TempErrorMessage);
        JobJournalErrorsMgt.SetErrorMessages(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then
            JobJournalErrorsMgt.SetFullBatchCheck(false);
    end;

    procedure CleanJobJnlTempErrorMessages(var TempErrorMessage: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters")
    var
        JobJnlLine: Record "Job Journal Line";
    begin
        CheckCleanDeletedJobJnlLinesErrors(TempErrorMessage);

        if ErrorHandlingParameters."Full Batch Check" then begin
            TempErrorMessage.Reset();
            TempErrorMessage.DeleteAll();
        end else begin
            if JobJnlLine.Get(ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name", ErrorHandlingParameters."Line No.") then
                CleanJobJnlLineRelatedError(TempErrorMessage, JobJnlLine);
            if JobJnlLine.Get(ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name", ErrorHandlingParameters."Previous Line No.") then
                CleanJobJnlLineRelatedError(TempErrorMessage, JobJnlLine);
        end;
    end;

    local procedure CleanJobJnlLineRelatedError(var TempErrorMessage: Record "Error Message" temporary; JobJnlLine: Record "Job Journal Line")
    begin
        TempErrorMessage.SetRange("Context Table Number", Database::"Job Journal Line");
        TempErrorMessage.SetRange("Context Record ID", JobJnlLine.RecordId());
        TempErrorMessage.DeleteAll();
    end;

    local procedure CheckCleanDeletedJobJnlLinesErrors(var TempErrorMessage: Record "Error Message" temporary)
    var
        TempJobJnlLine: Record "Job Journal Line" temporary;
    begin
        if JobJournalErrorsMgt.GetDeletedJobJnlLine(TempJobJnlLine, true) then begin
            TempErrorMessage.Reset();
            if TempJobJnlLine.FindSet() then
                repeat
                    CleanJobJnlLineRelatedError(TempErrorMessage, TempJobJnlLine);
                until TempJobJnlLine.Next() = 0;
        end;
    end;

    procedure PackDeletedDocumentsToArgs(var Args: Dictionary of [Text, Text])
    var
        TempGenJnlLine: Record "Gen. Journal Line" temporary;
    begin
        if JournalErrorsMgt.GetDeletedGenJnlLine(TempGenJnlLine, false) then begin
            TempGenJnlLine.FindSet();
            repeat
                Args.Add(Format(TempGenJnlLine."Line No."), DeletedDocumentToJson(TempGenJnlLine));
            until TempGenJnlLine.Next() = 0;
        end;
    end;

    local procedure DeletedDocumentToJson(TempGenJnlLine: Record "Gen. Journal Line" temporary) JSON: Text
    var
        JObject: JsonObject;
    begin
        JObject.Add(TempGenJnlLine.FieldName("Document No."), TempGenJnlLine."Document No.");
        JObject.Add(TempGenJnlLine.FieldName("Posting Date"), TempGenJnlLine."Posting Date");
        JObject.WriteTo(JSON);
    end;

    local procedure ParseDeletedDocument(JSON: Text; var TempGenJnlLine: Record "Gen. Journal Line" temporary): Boolean
    var
        JObject: JsonObject;
        DocumentNo: Text;
        PostingDateText: Text;
    begin
        if NullJSONTxt <> JSON then begin
            if not JObject.ReadFrom(JSON) then
                exit(false);
            if not GetJsonKeyValue(JObject, TempGenJnlLine.FieldName("Document No."), DocumentNo) then
                exit(false);
            if not GetJsonKeyValue(JObject, TempGenJnlLine.FieldName("Posting Date"), PostingDateText) then
                exit(false);

            TempGenJnlLine.Init();
            TempGenJnlLine."Document No." := CopyStr(DocumentNo, 1, MaxStrLen(TempGenJnlLine."Document No."));
            Evaluate(TempGenJnlLine."Posting Date", PostingDateText);

            exit(true);
        end;
    end;

    local procedure GetJsonKeyValue(var JObject: JsonObject; KeyName: Text; var KeyValue: Text): Boolean
    var
        JToken: JsonToken;
    begin
        if not JObject.Get(KeyName, JToken) then
            exit(false);

        KeyValue := JToken.AsValue().AsText();
        exit(true);
    end;

    procedure GetDeletedDocumentsFromArgs(Args: Dictionary of [Text, Text]; var TempGenJnlLine: Record "Gen. Journal Line" temporary)
    var
        JSON: Text;
    begin
        foreach JSON in Args.Values do
            if ParseDeletedDocument(JSON, TempGenJnlLine) then begin
                TempGenJnlLine."Line No." += 10000;
                TempGenJnlLine.Insert();
            end;
    end;

    procedure FeatureTelemetryLogUptakeUsed()
    begin
        FeatureTelemetry.LogUptake('0000GNO', TelemetryFeatureNameTxt, "Feature Uptake Status"::Used)
    end;

    procedure FeatureTelemetryLogUsage(ErrorsFound: Boolean; TableName: Text)
    var
        CustomDimensions: Dictionary of [Text, Text];
    begin
        TranslationHelper.SetGlobalLanguageToDefault();
        CustomDimensions.Add(ErrorsFoundTxt, Format(ErrorsFound));
        CustomDimensions.Add(TableNameTxt, TableName);
        FeatureTelemetry.LogUsage('0000GNP', TelemetryFeatureNameTxt, CheckRunTxt, CustomDimensions);
        TranslationHelper.RestoreGlobalLanguage();
    end;

    procedure FeatureTelemetryLogUsageSales(ErrorsFound: Boolean; TableName: Text; DocumentType: Enum "Sales Document Type")
    begin
        TranslationHelper.SetGlobalLanguageToDefault();
        FeatureTelemetryLogUsageDocument(ErrorsFound, TableName, Format(DocumentType));
        TranslationHelper.RestoreGlobalLanguage();
    end;


    procedure FeatureTelemetryLogUsagePurchase(ErrorsFound: Boolean; TableName: Text; DocumentType: Enum "Purchase Document Type")
    begin
        TranslationHelper.SetGlobalLanguageToDefault();
        FeatureTelemetryLogUsageDocument(ErrorsFound, TableName, Format(DocumentType));
        TranslationHelper.RestoreGlobalLanguage();
    end;

    local procedure FeatureTelemetryLogUsageDocument(ErrorsFound: Boolean; TableName: Text; DocumentType: Text)
    var
        CustomDimensions: Dictionary of [Text, Text];
    begin
        CustomDimensions.Add(ErrorsFoundTxt, Format(ErrorsFound));
        CustomDimensions.Add(TableNameTxt, TableName);
        CustomDimensions.Add(DocumentTypeTxt, DocumentType);
        FeatureTelemetry.LogUsage('0000GNM', TelemetryFeatureNameTxt, CheckRunTxt, CustomDimensions);
    end;

    [EventSubscriber(ObjectType::Table, Database::"General Ledger Setup", 'OnAfterValidateEvent', 'Enable Data Check', false, false)]
    local procedure AfterValidateGLSetupEnableDataCheck(var Rec: Record "General Ledger Setup"; var xRec: Record "General Ledger Setup"; CurrFieldNo: Integer)
    begin
        if Rec."Enable Data Check" then
            FeatureTelemetry.LogUptake('0000GNK', TelemetryFeatureNameTxt, "Feature Uptake Status"::Discovered)
        else
            FeatureTelemetry.LogUptake('0000GNN', TelemetryFeatureNameTxt, "Feature Uptake Status"::Undiscovered)
    end;

    [EventSubscriber(ObjectType::Table, Database::"My Notifications", 'OnAfterValidateEvent', 'Enabled', false, false)]
    local procedure AfterValidateMyNotificationsDataCheck(var Rec: Record "My Notifications"; var xRec: Record "My Notifications"; CurrFieldNo: Integer)
    begin
        if Rec."Notification Id" = DocumentErrorsMgt.GetShowDocumentCheckFactboxNotificationID() then
            if Rec.Enabled then
                FeatureTelemetry.LogUptake('0000GNL', TelemetryFeatureNameTxt, "Feature Uptake Status"::"Set up")
    end;
}