Codeunit 1535 Approvals Mgmt.

App
Base Application
Namespace
System.Automation
Versions
17-28

Procedures, 122Events, 155

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/OtherCapabilities/Approvals/ApprovalsMgmt.Codeunit.al3724 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 System.Automation;

using Microsoft.EServices.EDocument;
using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Posting;
using Microsoft.Foundation.BatchProcessing;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Journal;
using Microsoft.Inventory.Requisition;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.Posting;
using Microsoft.Purchases.Vendor;
using Microsoft.Sales.Customer;
using Microsoft.Sales.Document;
using Microsoft.Sales.Posting;
using Microsoft.Utilities;
using System.Environment;
using System.Environment.Configuration;
using System.Security.User;
using System.Telemetry;
using System.Threading;
using System.Utilities;

codeunit 1535 "Approvals Mgmt."
{
    Permissions = TableData "Approval Entry" = Rimd,
                  TableData "Approval Comment Line" = rimd,
                  TableData "Posted Approval Entry" = rimd,
                  TableData "Posted Approval Comment Line" = rimd,
                  TableData "Overdue Approval Entry" = rimd,
                  TableData "Notification Entry" = rimd;

    trigger OnRun()
    begin
    end;

    var
        WorkflowEventHandling: Codeunit "Workflow Event Handling";
        WorkflowManagement: Codeunit "Workflow Management";

#pragma warning disable AA0470
        UserIdNotInSetupErr: Label 'User ID %1 does not exist in the Approval User Setup window.', Comment = 'User ID NAVUser does not exist in the Approval User Setup window.';
        ApproverUserIdNotInSetupErr: Label 'You must set up an approver for user ID %1 in the Approval User Setup window.', Comment = 'You must set up an approver for user ID NAVUser in the Approval User Setup window.';
        WFUserGroupNotInSetupErr: Label 'The workflow user group member with user ID %1 does not exist in the Approval User Setup window.', Comment = 'The workflow user group member with user ID NAVUser does not exist in the Approval User Setup window.';
        SubstituteNotFoundErr: Label 'There is no substitute, direct approver, or approval administrator for user ID %1 in the Approval User Setup window.', Comment = 'There is no substitute for user ID NAVUser in the Approval User Setup window.';
#pragma warning restore AA0470
        NoSuitableApproverFoundErr: Label 'No qualified approver was found.';
        DelegateOnlyOpenRequestsErr: Label 'You can only delegate open approval requests.';
        ApproveOnlyOpenRequestsErr: Label 'You can only approve open approval requests.';
        RejectOnlyOpenRequestsErr: Label 'You can only reject open approval entries.';
        ApprovalsDelegatedMsg: Label 'The selected approval requests have been delegated.';
        NoReqToApproveErr: Label 'There is no approval request to approve.';
        NoReqToRejectErr: Label 'There is no approval request to reject.';
        NoReqToDelegateErr: Label 'There is no approval request to delegate.';
        PendingApprovalMsg: Label 'An approval request has been sent.';
#pragma warning disable AA0470
        PurchaserUserNotFoundErr: Label 'The salesperson/purchaser user ID %1 does not exist in the Approval User Setup window for %2 %3.', Comment = 'Example: The salesperson/purchaser user ID NAVUser does not exist in the Approval User Setup window for Salesperson/Purchaser code AB.';
#pragma warning restore AA0470
        NoApprovalRequestsFoundErr: Label 'No approval requests exist.';
        NoWFUserGroupMembersErr: Label 'A workflow user group with at least one member must be set up.';
#pragma warning disable AA0470
        DocStatusChangedMsg: Label '%1 %2 has been automatically approved. The status has been changed to %3.', Comment = 'Order 1001 has been automatically approved. The status has been changed to Released.';
        UnsupportedRecordTypeErr: Label 'Record type %1 is not supported by this workflow response.', Comment = 'Record type Customer is not supported by this workflow response.';
#pragma warning restore AA0470
        SalesPrePostCheckErr: Label 'Sales %1 %2 must be approved and released before you can perform this action.', Comment = '%1=document type, %2=document no., e.g. Sales Order 321 must be approved...';
        PurchPrePostCheckErr: Label 'Purchase %1 %2 must be approved and released before you can perform this action.', Comment = '%1=document type, %2=document no., e.g. Purchase Order 321 must be approved...';
        NoWorkflowEnabledErr: Label 'No approval workflow for this record type is enabled.';
        ApprovalReqCanceledForSelectedLinesMsg: Label 'The approval request for the selected record has been canceled.';
        PendingJournalBatchApprovalExistsErr: Label 'An approval request already exists.', Comment = '%1 is the Document No. of the journal line';
        ApprovedJournalBatchApprovalExistsMsg: Label 'An approval request for this batch has already been sent and approved. Do you want to send another approval request?';
#pragma warning disable AA0470
        ApporvalChainIsUnsupportedMsg: Label 'Only Direct Approver is supported as Approver Limit Type option for %1. The approval request will be approved automatically.', Comment = 'Only Direct Approver is supported as Approver Limit Type option for Gen. Journal Batch DEFAULT, CASH. The approval request will be approved automatically.';
#pragma warning restore AA0470
        RecHasBeenApprovedMsg: Label '%1 has been approved.', Comment = '%1 = Record Id';
        NoPermissionToDelegateErr: Label 'You do not have permission to delegate one or more of the selected approval requests.';
        NothingToApproveErr: Label 'There is nothing to approve.';
        ApproverChainErr: Label 'No sufficient approver was found in the approver chain.';
        PreventModifyRecordWithOpenApprovalEntryMsg: Label 'You can''t modify a record pending approval. Add a comment or reject the approval to modify the record.';
        PreventInsertRecordWithOpenApprovalEntryForCurrUserMsg: Label 'You can''t insert a record for active batch approval request. To insert a record, you can Reject approval and document requested changes in approval comment lines.';
        PreventInsertRecordWithOpenApprovalEntryMsg: Label 'You can''t insert a record that has active approval request. Do you want to cancel the batch approval request first?';
        PreventDeleteRecordWithOpenApprovalEntryMsg: Label 'You can''t delete a record that has open approval entries. Do you want to cancel the approval request first?';
        PreventDeleteRecordWithOpenApprovalEntryForCurrUserMsg: Label 'You can''t delete a record that has open approval entries. To delete a record, you can Reject approval and document requested changes in approval comment lines.';
        PreventDeleteRecordWithOpenApprovalEntryForSenderMsg: Label 'You can''t delete a record that has open approval entries. To delete a record, you need to Cancel approval request first.';
        PreventModifyRecordWithOpenApprovalEntryNewMsg: Label 'You can''t modify a record that has active approval request. Do you want to cancel the batch approval request first?';
        JobQueueDelegatedAdminCategoryTxt: Label 'AL JobQueueEntries Delegated Admin', Locked = true;
        JobQueueWorkflowSetupErr: Label 'The Job Queue approval workflow has not been setup.';
        DelegatedAdminSendingApprovalLbl: Label 'Delegated admin sending approval', Locked = true;
        ImposedRestrictionLbl: Label 'Imposed restriction';
        PendingApprovalLbl: Label 'Pending Approval';
        RestrictBatchUsageDetailsLbl: Label 'The restriction was imposed because the journal batch requires approval.';

    [IntegrationEvent(false, false)]
    procedure OnSendPurchaseDocForApproval(var PurchaseHeader: Record "Purchase Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendSalesDocForApproval(var SalesHeader: Record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendIncomingDocForApproval(var IncomingDocument: Record "Incoming Document")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelPurchaseApprovalRequest(var PurchaseHeader: Record "Purchase Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelSalesApprovalRequest(var SalesHeader: Record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelIncomingDocApprovalRequest(var IncomingDocument: Record "Incoming Document")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendCustomerForApproval(var Customer: Record Customer)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendVendorForApproval(var Vendor: Record Vendor)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendItemForApproval(var Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelCustomerApprovalRequest(var Customer: Record Customer)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelVendorApprovalRequest(var Vendor: Record Vendor)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelItemApprovalRequest(var Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendGeneralJournalBatchForApproval(var GenJournalBatch: Record "Gen. Journal Batch")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelGeneralJournalBatchApprovalRequest(var GenJournalBatch: Record "Gen. Journal Batch")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendGeneralJournalLineForApproval(var GenJournalLine: Record "Gen. Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelGeneralJournalLineApprovalRequest(var GenJournalLine: Record "Gen. Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendItemJournalBatchForApproval(var ItemJournalBatch: Record "Item Journal Batch")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelItemJournalBatchApprovalRequest(var ItemJournalBatch: Record "Item Journal Batch")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendRequisitionWkshBatchForApproval(var RequisitionWkshName: Record "Requisition Wksh. Name")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelRequisitionWkshBatchApprovalRequest(var RequisitionWkshName: Record "Requisition Wksh. Name")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnApproveApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRejectApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDelegateApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnRenameRecordInApprovalRequest(OldRecordId: RecordID; NewRecordId: RecordID)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnDeleteRecordInApprovalRequest(RecordIDToApprove: RecordID)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendJobQueueEntryForApproval(var JobQueueEntry: Record "Job Queue Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelJobQueueEntryApprovalRequest(var JobQueueEntry: Record "Job Queue Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnSendVendorBankAccountForApproval(var VendorBankAccount: Record "Vendor Bank Account")
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnCancelVendorBankAccountApprovalRequest(var VendorBankAccount: Record "Vendor Bank Account")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsVendorBankApprovalsWorkflowEnabled(var VendorBankAccount: Record "Vendor Bank Account"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPopulateApprovalEntryArgument(var RecRef: RecordRef; var ApprovalEntryArgument: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance")
    begin
    end;

    procedure ApproveRecordApprovalRequest(RecordID: RecordID)
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        if not FindOpenApprovalEntryForCurrUser(ApprovalEntry, RecordID) then
            Error(NoReqToApproveErr);

        ApprovalEntry.SetRecFilter();
        ApproveApprovalRequests(ApprovalEntry);
    end;

    procedure ApproveGenJournalLineRequest(GenJournalLine: Record "Gen. Journal Line")
    var
        GenJournalBatch: Record "Gen. Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        GenJournalBatch.Get(GenJournalLine."Journal Template Name", GenJournalLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, GenJournalBatch.RecordId) then
            ApproveRecordApprovalRequest(GenJournalBatch.RecordId);
        Clear(ApprovalEntry);
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, GenJournalLine.RecordId) then
            ApproveRecordApprovalRequest(GenJournalLine.RecordId);
    end;

    procedure ApproveItemJournalRequest(ItemJournalLine: Record "Item Journal Line")
    var
        ItemJournalBatch: Record "Item Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        ItemJournalBatch.Get(ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, ItemJournalBatch.RecordId()) then
            ApproveRecordApprovalRequest(ItemJournalBatch.RecordId());
    end;

    procedure ApproveRequisitionWkshRequest(RequisitionLine: Record "Requisition Line")
    var
        RequisitionWkshName: Record "Requisition Wksh. Name";
        ApprovalEntry: Record "Approval Entry";
    begin
        RequisitionWkshName.Get(RequisitionLine."Worksheet Template Name", RequisitionLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, RequisitionWkshName.RecordId()) then
            ApproveRecordApprovalRequest(RequisitionWkshName.RecordId());
    end;

    procedure RejectRecordApprovalRequest(RecordID: RecordID)
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        if not FindOpenApprovalEntryForCurrUser(ApprovalEntry, RecordID) then
            Error(NoReqToRejectErr);

        ApprovalEntry.SetRecFilter();
        RejectApprovalRequests(ApprovalEntry);
    end;

    procedure RejectGenJournalLineRequest(GenJournalLine: Record "Gen. Journal Line")
    var
        GenJournalBatch: Record "Gen. Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        GenJournalBatch.Get(GenJournalLine."Journal Template Name", GenJournalLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, GenJournalBatch.RecordId) then
            RejectRecordApprovalRequest(GenJournalBatch.RecordId);
        Clear(ApprovalEntry);
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, GenJournalLine.RecordId) then
            RejectRecordApprovalRequest(GenJournalLine.RecordId);
    end;

    procedure RejectItemJournalRequest(ItemJournalLine: Record "Item Journal Line")
    var
        ItemJournalBatch: Record "Item Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        ItemJournalBatch.Get(ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, ItemJournalBatch.RecordId()) then
            RejectRecordApprovalRequest(ItemJournalBatch.RecordId());
    end;

    procedure RejectRequisitionWkshRequest(RequisitionLine: Record "Requisition Line")
    var
        RequisitionWkshName: Record "Requisition Wksh. Name";
        ApprovalEntry: Record "Approval Entry";
    begin
        RequisitionWkshName.Get(RequisitionLine."Worksheet Template Name", RequisitionLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, RequisitionWkshName.RecordId()) then
            RejectRecordApprovalRequest(RequisitionWkshName.RecordId());
    end;

    procedure DelegateRecordApprovalRequest(RecordID: RecordID)
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        if not FindOpenApprovalEntryForCurrUser(ApprovalEntry, RecordID) then
            Error(NoReqToDelegateErr);

        ApprovalEntry.SetRecFilter();
        DelegateApprovalRequests(ApprovalEntry);
    end;

    procedure DelegateGenJournalLineRequest(GenJournalLine: Record "Gen. Journal Line")
    var
        GenJournalBatch: Record "Gen. Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        GenJournalBatch.Get(GenJournalLine."Journal Template Name", GenJournalLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, GenJournalBatch.RecordId) then
            DelegateRecordApprovalRequest(GenJournalBatch.RecordId);
        Clear(ApprovalEntry);
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, GenJournalLine.RecordId) then
            DelegateRecordApprovalRequest(GenJournalLine.RecordId);
    end;

    procedure DelegateItemJournalRequest(ItemJournalLine: Record "Item Journal Line")
    var
        ItemJournalBatch: Record "Item Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        ItemJournalBatch.Get(ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, ItemJournalBatch.RecordId()) then
            DelegateRecordApprovalRequest(ItemJournalBatch.RecordId());
    end;

    procedure DelegateRequisitionWkshRequest(RequisitionLine: Record "Requisition Line")
    var
        RequisitionWkshName: Record "Requisition Wksh. Name";
        ApprovalEntry: Record "Approval Entry";
    begin
        RequisitionWkshName.Get(RequisitionLine."Worksheet Template Name", RequisitionLine."Journal Batch Name");
        if FindOpenApprovalEntryForCurrUser(ApprovalEntry, RequisitionWkshName.RecordId()) then
            DelegateRecordApprovalRequest(RequisitionWkshName.RecordId());
    end;

    procedure ApproveApprovalRequests(var ApprovalEntry: Record "Approval Entry")
    var
        ApprovalEntryToUpdate: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeApproveApprovalRequests(ApprovalEntry, IsHandled);
        if IsHandled then
            exit;

        if ApprovalEntry.FindSet() then
            repeat
                ApprovalEntryToUpdate := ApprovalEntry;
                ApproveSelectedApprovalRequest(ApprovalEntryToUpdate);
            until ApprovalEntry.Next() = 0;
    end;

    procedure RejectApprovalRequests(var ApprovalEntry: Record "Approval Entry")
    var
        ApprovalEntryToUpdate: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeRejectApprovalRequests(ApprovalEntry, IsHandled);
        if IsHandled then
            exit;

        if ApprovalEntry.FindSet() then
            repeat
                ApprovalEntryToUpdate := ApprovalEntry;
                RejectSelectedApprovalRequest(ApprovalEntryToUpdate);
            until ApprovalEntry.Next() = 0;
    end;

    procedure DelegateApprovalRequests(var ApprovalEntry: Record "Approval Entry")
    var
        ApprovalEntryToUpdate: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeDelegateApprovalRequests(ApprovalEntry, IsHandled);
        if IsHandled then
            exit;

        if ApprovalEntry.FindSet() then begin
            repeat
                ApprovalEntryToUpdate := ApprovalEntry;
                DelegateSelectedApprovalRequest(ApprovalEntryToUpdate, true);
            until ApprovalEntry.Next() = 0;
            Message(ApprovalsDelegatedMsg);
        end;

        OnAfterDelegateApprovalRequest(ApprovalEntry);
    end;

    local procedure ApproveSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeApproveSelectedApprovalRequest(ApprovalEntry, IsHandled);
        if IsHandled then
            exit;
        CheckOpenStatus(ApprovalEntry, "Approval Action"::Approve, ApproveOnlyOpenRequestsErr);

        if ApprovalEntry."Approver ID" <> UserId then
            CheckUserAsApprovalAdministrator(ApprovalEntry);

        ApprovalEntry.Validate(Status, ApprovalEntry.Status::Approved);
        ApprovalEntry.Modify(true);
        OnApproveApprovalRequest(ApprovalEntry);
    end;

    local procedure RejectSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeRejectSelectedApprovalRequest(ApprovalEntry, IsHandled);
        if not IsHandled then begin
            CheckOpenStatus(ApprovalEntry, "Approval Action"::Reject, RejectOnlyOpenRequestsErr);

            if ApprovalEntry."Approver ID" <> UserId then
                CheckUserAsApprovalAdministrator(ApprovalEntry);

            OnRejectApprovalRequest(ApprovalEntry);
            ApprovalEntry.Get(ApprovalEntry."Entry No.");
            ApprovalEntry.Validate(Status, ApprovalEntry.Status::Rejected);
            ApprovalEntry.Modify(true);
        end;

        OnAfterRejectSelectedApprovalRequest(ApprovalEntry);
    end;

    procedure DelegateSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry"; CheckCurrentUser: Boolean)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeDelegateSelectedApprovalRequest(ApprovalEntry, CheckCurrentUser, IsHandled);
        if not IsHandled then begin
            CheckOpenStatus(ApprovalEntry, "Approval Action"::Delegate, DelegateOnlyOpenRequestsErr);

            if CheckCurrentUser and (not ApprovalEntry.CanCurrentUserEdit()) then
                Error(NoPermissionToDelegateErr);

            IsHandled := false;
            OnDelegateSelectedApprovalRequestOnBeforeSubstituteUserIdForApprovalEntry(ApprovalEntry, IsHandled);
            if IsHandled then
                exit;

            SubstituteUserIdForApprovalEntry(ApprovalEntry);
        end;

        OnAfterDelegateSelectedApprovalRequest(ApprovalEntry);
    end;

    local procedure CheckOpenStatus(ApprovalEntry: Record "Approval Entry"; ApprovalAction: Enum "Approval Action"; ErrorMessage: Text)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckStatus(ApprovalEntry, ApprovalAction, IsHandled);
        if IsHandled then
            exit;

        if ApprovalEntry.Status <> ApprovalEntry.Status::Open then
            Error(ErrorMessage);
    end;

    local procedure SubstituteUserIdForApprovalEntry(ApprovalEntry: Record "Approval Entry")
    var
        UserSetup: Record "User Setup";
        ApprovalAdminUserSetup: Record "User Setup";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSubstituteUserIdForApprovalEntry(ApprovalEntry, IsHandled);
        if IsHandled then
            exit;

        if not UserSetup.Get(ApprovalEntry."Approver ID") then
            Error(ApproverUserIdNotInSetupErr, ApprovalEntry."Sender ID");
        OnSubstituteUserIdForApprovalEntryOnAfterCheckUserSetupApprovalEntryApproverID(UserSetup, ApprovalEntry);

        if UserSetup.Substitute = '' then
            if UserSetup."Approver ID" = '' then begin
                ApprovalAdminUserSetup.SetRange("Approval Administrator", true);
                if ApprovalAdminUserSetup.FindFirst() then
                    UserSetup.Get(ApprovalAdminUserSetup."User ID")
                else
                    Error(SubstituteNotFoundErr, UserSetup."User ID");
            end else
                UserSetup.Get(UserSetup."Approver ID")
        else
            UserSetup.Get(UserSetup.Substitute);

        OnSubstituteUserIdForApprovalEntryOnBeforeAssignApproverID(ApprovalEntry, UserSetup);
        ApprovalEntry."Approver ID" := UserSetup."User ID";
        ApprovalEntry.Modify(true);
        OnDelegateApprovalRequest(ApprovalEntry);
    end;

    procedure FindOpenApprovalEntryForCurrUser(var ApprovalEntry: Record "Approval Entry"; RecordID: RecordID): Boolean
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Open);
        ApprovalEntry.SetRange("Approver ID", UserId);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if not ApprovalEntry.IsEmpty() then
            ApprovalEntry.SetRange("Related to Change", false);

        OnFindOpenApprovalEntryForCurrUserOnAfterApprovalEntrySetFilters(ApprovalEntry);
        exit(ApprovalEntry.FindFirst());
    end;

    procedure FindApprovalEntryForCurrUser(var ApprovalEntry: Record "Approval Entry"; RecordID: RecordID): Boolean
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetRange("Approver ID", UserId);
        OnFindApprovalEntryForCurrUserOnAfterApprovalEntrySetFilters(ApprovalEntry);

        exit(ApprovalEntry.FindFirst());
    end;

    procedure FindLastApprovalEntryForCurrUser(var ApprovalEntry: Record "Approval Entry"; RecordID: RecordID): Boolean
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetRange("Approver ID", UserId);
        exit(ApprovalEntry.FindLast());
    end;

    procedure FindApprovalEntryByRecordId(var ApprovalEntry: Record "Approval Entry"; RecordID: RecordID): Boolean
    begin
        ApprovalEntry.Reset();
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        exit(ApprovalEntry.FindLast());
    end;

    local procedure ShowPurchApprovalStatus(PurchaseHeader: Record "Purchase Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeShowPurchApprovalStatus(PurchaseHeader, IsHandled);
        if IsHandled then
            exit;

        PurchaseHeader.Find();

        case PurchaseHeader.Status of
            PurchaseHeader.Status::Released:
                Message(DocStatusChangedMsg, PurchaseHeader."Document Type", PurchaseHeader."No.", PurchaseHeader.Status);
            PurchaseHeader.Status::"Pending Approval":
                if HasOpenOrPendingApprovalEntries(PurchaseHeader.RecordId) then
                    Message(PendingApprovalMsg);
            PurchaseHeader.Status::"Pending Prepayment":
                Message(DocStatusChangedMsg, PurchaseHeader."Document Type", PurchaseHeader."No.", PurchaseHeader.Status);
        end;
    end;

    local procedure ShowSalesApprovalStatus(SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeShowSalesApprovalStatus(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        SalesHeader.Find();

        case SalesHeader.Status of
            SalesHeader.Status::Released:
                Message(DocStatusChangedMsg, SalesHeader."Document Type", SalesHeader."No.", SalesHeader.Status);
            SalesHeader.Status::"Pending Approval":
                if HasOpenOrPendingApprovalEntries(SalesHeader.RecordId) then
                    Message(PendingApprovalMsg);
            SalesHeader.Status::"Pending Prepayment":
                Message(DocStatusChangedMsg, SalesHeader."Document Type", SalesHeader."No.", SalesHeader.Status);
        end;
    end;

    local procedure ShowApprovalStatus(RecId: RecordID; WorkflowInstanceId: Guid)
    begin
        if HasPendingApprovalEntriesForWorkflow(RecId, WorkflowInstanceId) then
            Message(PendingApprovalMsg)
        else
            Message(RecHasBeenApprovedMsg, Format(RecId, 0, 1));
    end;

    procedure ApproveApprovalRequestsForRecord(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        ApprovalEntry: Record "Approval Entry";
        ApprovalEntryToUpdate: Record "Approval Entry";
    begin
        ApprovalEntry.SetCurrentKey("Table ID", "Document Type", "Document No.", "Sequence No.");
        ApprovalEntry.SetRange("Table ID", RecRef.Number);
        ApprovalEntry.SetRange("Record ID to Approve", RecRef.RecordId);
        ApprovalEntry.SetFilter(Status, '%1|%2', ApprovalEntry.Status::Created, ApprovalEntry.Status::Open);
        ApprovalEntry.SetRange("Workflow Step Instance ID", WorkflowStepInstance.ID);
        OnApproveApprovalRequestsForRecordOnAfterApprovalEntrySetFilters(ApprovalEntry, WorkflowStepInstance, RecRef);
        if ApprovalEntry.FindSet() then
            repeat
                ApprovalEntryToUpdate := ApprovalEntry;
                ApprovalEntryToUpdate.Validate(Status, ApprovalEntry.Status::Approved);
                OnApproveApprovalRequestsForRecordOnBeforeApprovalEntryToUpdateModify(ApprovalEntryToUpdate);
                ApprovalEntryToUpdate.Modify(true);
                CreateApprovalEntryNotification(ApprovalEntryToUpdate, WorkflowStepInstance);
            until ApprovalEntry.Next() = 0;
    end;

    procedure CancelApprovalRequestsForRecord(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        ApprovalEntry: Record "Approval Entry";
        ApprovalEntryToUpdate: Record "Approval Entry";
        OldStatus: Enum "Approval Status";
    begin
        ApprovalEntry.SetCurrentKey("Table ID", "Document Type", "Document No.", "Sequence No.");
        ApprovalEntry.SetRange("Table ID", RecRef.Number);
        ApprovalEntry.SetRange("Record ID to Approve", RecRef.RecordId);
        ApprovalEntry.SetFilter(Status, '<>%1&<>%2', ApprovalEntry.Status::Rejected, ApprovalEntry.Status::Canceled);
        ApprovalEntry.SetRange("Workflow Step Instance ID", WorkflowStepInstance.ID);
        OnCancelApprovalRequestsForRecordOnAfterSetApprovalEntryFilters(ApprovalEntry, RecRef);
        if ApprovalEntry.FindSet() then
            repeat
                OldStatus := ApprovalEntry.Status;
                ApprovalEntryToUpdate := ApprovalEntry;
                ApprovalEntryToUpdate.Validate(Status, ApprovalEntryToUpdate.Status::Canceled);
                ApprovalEntryToUpdate.Modify(true);
                if OldStatus in [ApprovalEntry.Status::Open, ApprovalEntry.Status::Approved] then
                    CreateApprovalEntryNotification(ApprovalEntryToUpdate, WorkflowStepInstance);
                OnCancelApprovalRequestsForRecordOnAfterCreateApprovalEntryNotification(ApprovalEntryToUpdate, WorkflowStepInstance, OldStatus);
            until ApprovalEntry.Next() = 0;
    end;

    procedure RejectApprovalRequestsForRecord(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        ApprovalEntry: Record "Approval Entry";
        ApprovalEntryToUpdate: Record "Approval Entry";
        OldStatus: Enum "Approval Status";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeRejectApprovalRequestsForRecord(RecRef, WorkflowStepInstance, IsHandled);
        if IsHandled then
            exit;

        ApprovalEntry.SetCurrentKey("Table ID", "Document Type", "Document No.", "Sequence No.");
        ApprovalEntry.SetRange("Table ID", RecRef.Number);
        ApprovalEntry.SetRange("Record ID to Approve", RecRef.RecordId);
        ApprovalEntry.SetFilter(Status, '<>%1&<>%2', ApprovalEntry.Status::Rejected, ApprovalEntry.Status::Canceled);
        ApprovalEntry.SetRange("Workflow Step Instance ID", WorkflowStepInstance.ID);
        OnRejectApprovalRequestsForRecordOnAfterSetApprovalEntryFilters(ApprovalEntry, WorkflowStepInstance, RecRef);
        if ApprovalEntry.FindSet() then
            repeat
                OldStatus := ApprovalEntry.Status;
                ApprovalEntryToUpdate := ApprovalEntry;
                ApprovalEntryToUpdate.Validate(Status, ApprovalEntry.Status::Rejected);
                OnRejectApprovalRequestsForRecordOnBeforeApprovalEntryToUpdateModify(ApprovalEntryToUpdate);
                ApprovalEntryToUpdate.Modify(true);
                if OldStatus in [ApprovalEntry.Status::Open] then
                    CreateApprovalEntryNotification(ApprovalEntryToUpdate, WorkflowStepInstance);
                OnRejectApprovalRequestsForRecordOnAfterCreateApprovalEntryNotification(ApprovalEntryToUpdate, WorkflowStepInstance, OldStatus);
            until ApprovalEntry.Next() = 0;
    end;

    procedure SendApprovalRequestFromRecord(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        ApprovalEntry: Record "Approval Entry";
        ApprovalEntry2: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        ApprovalEntry.SetCurrentKey("Table ID", "Record ID to Approve", Status, "Workflow Step Instance ID", "Sequence No.");
        ApprovalEntry.SetRange("Table ID", RecRef.Number);
        ApprovalEntry.SetRange("Record ID to Approve", RecRef.RecordId);
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Created);
        ApprovalEntry.SetRange("Workflow Step Instance ID", WorkflowStepInstance.ID);
        IsHandled := false;
        OnSendApprovalRequestFromRecordOnAfterSetApprovalEntryFilters(ApprovalEntry, RecRef, IsHandled, WorkflowStepInstance);
        if IsHandled then
            exit;

        if ApprovalEntry.FindFirst() then begin
            ApprovalEntry2.CopyFilters(ApprovalEntry);
            ApprovalEntry2.SetRange("Sequence No.", ApprovalEntry."Sequence No.");
            if ApprovalEntry2.FindSet(true) then
                repeat
                    ApprovalEntry2.Validate(Status, ApprovalEntry2.Status::Open);
                    ApprovalEntry2.Modify(true);
                    CreateApprovalEntryNotification(ApprovalEntry2, WorkflowStepInstance);
                until ApprovalEntry2.Next() = 0;
            IsHandled := false;
            OnSendApprovalRequestFromRecordOnBeforeFindApprovedApprovalEntryForWorkflowUserGroup(ApprovalEntry, IsHandled);
            if not IsHandled then
                if FindApprovedApprovalEntryForWorkflowUserGroup(ApprovalEntry, WorkflowStepInstance) then
                    if (ApprovalEntry."Sender ID" <> ApprovalEntry."Approver ID") or
                    FindOpenApprovalEntryForSequenceNo(RecRef, WorkflowStepInstance, ApprovalEntry."Sequence No.")
                    then
                        OnApproveApprovalRequest(ApprovalEntry);
            exit;
        end;

        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Approved);
        if ApprovalEntry.FindLast() then
            OnApproveApprovalRequest(ApprovalEntry)
        else
            Error(NoApprovalRequestsFoundErr);
    end;

    procedure SendApprovalRequestFromApprovalEntry(ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        ApprovalEntry2: Record "Approval Entry";
        ApprovalEntry3: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSendApprovalRequestFromApprovalEntry(ApprovalEntry, WorkflowStepInstance, IsHandled);
        if IsHandled then
            exit;

        if ApprovalEntry.Status = ApprovalEntry.Status::Open then begin
            CreateApprovalEntryNotification(ApprovalEntry, WorkflowStepInstance);
            exit;
        end;

        if FindOpenApprovalEntriesForWorkflowStepInstance(ApprovalEntry, WorkflowStepInstance."Record ID") then
            exit;

        ApprovalEntry2.SetCurrentKey("Table ID", "Document Type", "Document No.", "Sequence No.");
        ApprovalEntry2.SetRange("Record ID to Approve", ApprovalEntry."Record ID to Approve");
        ApprovalEntry2.SetRange(Status, ApprovalEntry2.Status::Created);
        ApprovalEntry2.SetRange("Workflow Step Instance ID", ApprovalEntry."Workflow Step Instance ID");
        OnSendApprovalRequestFromApprovalEntryOnAfterSetApprovalEntry2Filters(ApprovalEntry2, ApprovalEntry);

        if ApprovalEntry2.FindFirst() then begin
            ApprovalEntry3.CopyFilters(ApprovalEntry2);
            ApprovalEntry3.SetRange("Sequence No.", ApprovalEntry2."Sequence No.");
            if ApprovalEntry3.FindSet() then
                repeat
                    ApprovalEntry3.Validate(Status, ApprovalEntry3.Status::Open);
                    ApprovalEntry3.Modify(true);
                    CreateApprovalEntryNotification(ApprovalEntry3, WorkflowStepInstance);
                until ApprovalEntry3.Next() = 0;
        end;
    end;

    procedure CreateApprovalRequests(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        WorkflowStepArgument: Record "Workflow Step Argument";
        ApprovalEntryArgument: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateApprovalRequests(RecRef, WorkflowStepInstance, IsHandled);
        if IsHandled then
            exit;

        PopulateApprovalEntryArgument(RecRef, WorkflowStepInstance, ApprovalEntryArgument);

        if WorkflowStepArgument.Get(WorkflowStepInstance.Argument) then
            case WorkflowStepArgument."Approver Type" of
                WorkflowStepArgument."Approver Type"::"Salesperson/Purchaser":
                    CreateApprReqForApprTypeSalespersPurchaser(WorkflowStepArgument, ApprovalEntryArgument);
                WorkflowStepArgument."Approver Type"::Approver:
                    CreateApprReqForApprTypeApprover(WorkflowStepArgument, ApprovalEntryArgument);
                WorkflowStepArgument."Approver Type"::"Workflow User Group":
                    CreateApprReqForApprTypeWorkflowUserGroup(WorkflowStepArgument, ApprovalEntryArgument);
                else
                    OnCreateApprovalRequestsOnElseCase(WorkflowStepArgument, ApprovalEntryArgument);
            end;

        OnCreateApprovalRequestsOnAfterCreateRequests(RecRef, WorkflowStepArgument, ApprovalEntryArgument);

        if WorkflowStepArgument."Show Confirmation Message" then
            InformUserOnStatusChange(RecRef, WorkflowStepInstance.ID);
    end;

    procedure CreateAndAutomaticallyApproveRequest(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        ApprovalEntryArgument: Record "Approval Entry";
        WorkflowStepArgument: Record "Workflow Step Argument";
    begin
        PopulateApprovalEntryArgument(RecRef, WorkflowStepInstance, ApprovalEntryArgument);
        if not WorkflowStepArgument.Get(WorkflowStepInstance.Argument) then
            WorkflowStepArgument.Init();

        CreateApprovalRequestForUser(WorkflowStepArgument, ApprovalEntryArgument);

        InformUserOnStatusChange(RecRef, WorkflowStepInstance.ID);
    end;

    local procedure CreateApprReqForApprTypeSalespersPurchaser(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
        ApprovalEntryArgument.TestField("Salespers./Purch. Code");

        case WorkflowStepArgument."Approver Limit Type" of
            WorkflowStepArgument."Approver Limit Type"::"Approver Chain":
                begin
                    CreateApprovalRequestForSalespersPurchaser(WorkflowStepArgument, ApprovalEntryArgument);
                    CreateApprovalRequestForChainOfApprovers(WorkflowStepArgument, ApprovalEntryArgument);
                end;
            WorkflowStepArgument."Approver Limit Type"::"Direct Approver":
                CreateApprovalRequestForSalespersPurchaser(WorkflowStepArgument, ApprovalEntryArgument);
            WorkflowStepArgument."Approver Limit Type"::"First Qualified Approver":
                begin
                    CreateApprovalRequestForSalespersPurchaser(WorkflowStepArgument, ApprovalEntryArgument);
                    CreateApprovalRequestForApproverWithSufficientLimit(WorkflowStepArgument, ApprovalEntryArgument);
                end;
            WorkflowStepArgument."Approver Limit Type"::"Specific Approver":
                begin
                    CreateApprovalRequestForSalespersPurchaser(WorkflowStepArgument, ApprovalEntryArgument);
                    CreateApprovalRequestForSpecificUser(WorkflowStepArgument, ApprovalEntryArgument);
                end;
        end;

        OnAfterCreateApprReqForApprTypeSalespersPurchaser(WorkflowStepArgument, ApprovalEntryArgument);
    end;

    local procedure CreateApprReqForApprTypeApprover(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
        case WorkflowStepArgument."Approver Limit Type" of
            WorkflowStepArgument."Approver Limit Type"::"Approver Chain":
                begin
                    CreateApprovalRequestForUser(WorkflowStepArgument, ApprovalEntryArgument);
                    CreateApprovalRequestForChainOfApprovers(WorkflowStepArgument, ApprovalEntryArgument);
                end;
            WorkflowStepArgument."Approver Limit Type"::"Direct Approver":
                CreateApprovalRequestForApprover(WorkflowStepArgument, ApprovalEntryArgument);
            WorkflowStepArgument."Approver Limit Type"::"First Qualified Approver":
                begin
                    CreateApprovalRequestForUser(WorkflowStepArgument, ApprovalEntryArgument);
                    CreateApprovalRequestForApproverWithSufficientLimit(WorkflowStepArgument, ApprovalEntryArgument);
                end;
            WorkflowStepArgument."Approver Limit Type"::"Specific Approver":
                CreateApprovalRequestForSpecificUser(WorkflowStepArgument, ApprovalEntryArgument);
        end;

        OnAfterCreateApprReqForApprTypeApprover(WorkflowStepArgument, ApprovalEntryArgument);
    end;

    local procedure CreateApprReqForApprTypeWorkflowUserGroup(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    var
        UserSetup: Record "User Setup";
        WorkflowUserGroupMember: Record "Workflow User Group Member";
        ApproverId: Code[50];
        SequenceNo: Integer;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateApprReqForApprTypeWorkflowUserGroup(WorkflowUserGroupMember, WorkflowStepArgument, ApprovalEntryArgument, SequenceNo, IsHandled);
        if not IsHandled then begin
            if not UserSetup.Get(UserId) then
                Error(UserIdNotInSetupErr, UserId);
            SequenceNo := GetLastSequenceNo(ApprovalEntryArgument);

            WorkflowUserGroupMember.SetCurrentKey("Workflow User Group Code", "Sequence No.");
            WorkflowUserGroupMember.SetRange("Workflow User Group Code", WorkflowStepArgument."Workflow User Group Code");

            if not WorkflowUserGroupMember.FindSet() then
                Error(NoWFUserGroupMembersErr);

            repeat
                ApproverId := WorkflowUserGroupMember."User Name";
                if not UserSetup.Get(ApproverId) then
                    Error(WFUserGroupNotInSetupErr, ApproverId);
                IsHandled := false;
                OnCreateApprReqForApprTypeWorkflowUserGroupOnBeforeMakeApprovalEntry(WorkflowUserGroupMember, ApprovalEntryArgument, WorkflowStepArgument, ApproverId, IsHandled);
                if not IsHandled then
                    MakeApprovalEntry(ApprovalEntryArgument, SequenceNo + WorkflowUserGroupMember."Sequence No.", ApproverId, WorkflowStepArgument);
            until WorkflowUserGroupMember.Next() = 0;
        end;
        OnAfterCreateApprReqForApprTypeWorkflowUserGroup(WorkflowStepArgument, ApprovalEntryArgument);
    end;

    procedure CreateApprovalRequestForChainOfApprovers(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
        CreateApprovalRequestForApproverChain(WorkflowStepArgument, ApprovalEntryArgument, false);
    end;

    procedure CreateApprovalRequestForApproverWithSufficientLimit(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
        CreateApprovalRequestForApproverChain(WorkflowStepArgument, ApprovalEntryArgument, true);
    end;

    local procedure CreateApprovalRequestForApproverChain(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry"; SufficientApproverOnly: Boolean)
    var
        ApprovalEntry: Record "Approval Entry";
        UserSetup: Record "User Setup";
        ApproverId: Code[50];
        SequenceNo: Integer;
        MaxCount: Integer;
        i: Integer;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateApprovalRequestForApproverChain(WorkflowStepArgument, ApprovalEntryArgument, SufficientApproverOnly, IsHandled);
        if IsHandled then
            exit;

        ApproverId := CopyStr(UserId(), 1, MaxStrLen(ApproverId));

        ApprovalEntry.SetCurrentKey("Record ID to Approve", "Workflow Step Instance ID", "Sequence No.");
        ApprovalEntry.SetRange("Table ID", ApprovalEntryArgument."Table ID");
        ApprovalEntry.SetRange("Record ID to Approve", ApprovalEntryArgument."Record ID to Approve");
        ApprovalEntry.SetRange("Workflow Step Instance ID", ApprovalEntryArgument."Workflow Step Instance ID");
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Created);
        OnCreateApprovalRequestForApproverChainOnAfterSetApprovalEntryFilters(ApprovalEntry, ApprovalEntryArgument);
        if ApprovalEntry.FindLast() then
            ApproverId := ApprovalEntry."Approver ID"
        else
            if (WorkflowStepArgument."Approver Type" = WorkflowStepArgument."Approver Type"::"Salesperson/Purchaser") and
                (WorkflowStepArgument."Approver Limit Type" = WorkflowStepArgument."Approver Limit Type"::"First Qualified Approver")
            then begin
                FindUserSetupBySalesPurchCode(UserSetup, ApprovalEntryArgument);
                ApproverId := UserSetup."User ID";
            end;

        UserSetup.Reset();
        MaxCount := UserSetup.Count();

        if not UserSetup.Get(ApproverId) then
            Error(ApproverUserIdNotInSetupErr, ApprovalEntry."Sender ID");

        IsHandled := false;
        OnCreateApprovalRequestForApproverChainOnAfterCheckApprovalEntrySenderID(UserSetup, WorkflowStepArgument, ApprovalEntryArgument, IsHandled);
        if IsHandled then
            exit;

        if not IsSufficientApprover(UserSetup, ApprovalEntryArgument) then
            repeat
                i += 1;
                if i > MaxCount then
                    Error(ApproverChainErr);
                ApproverId := UserSetup."Approver ID";

                IsHandled := false;
                OnCreateApprovalRequestForApproverChainOnBeforeCheckApproverId(UserSetup, WorkflowStepArgument, ApprovalEntryArgument, IsHandled);
                if IsHandled then
                    exit;

                if ApproverId = '' then
                    Error(NoSuitableApproverFoundErr);

                if not UserSetup.Get(ApproverId) then
                    Error(ApproverUserIdNotInSetupErr, UserSetup."User ID");

                OnCreateApprovalRequestForApproverChainOnAfterCheckUserSetupSenderID(UserSetup, WorkflowStepArgument, ApprovalEntryArgument);

                // Approval Entry should not be created only when IsSufficientApprover is false and SufficientApproverOnly is true
                if IsSufficientApprover(UserSetup, ApprovalEntryArgument) or (not SufficientApproverOnly) then begin
                    SequenceNo := GetLastSequenceNo(ApprovalEntryArgument) + 1;
                    MakeApprovalEntry(ApprovalEntryArgument, SequenceNo, ApproverId, WorkflowStepArgument);
                end;

            until IsSufficientApprover(UserSetup, ApprovalEntryArgument);

        OnAfterCreateApprovalRequestForApproverChain(ApprovalEntryArgument, ApproverId, WorkflowStepArgument, UserSetup, SufficientApproverOnly);
    end;

    local procedure CreateApprovalRequestForApprover(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    var
        UserSetup: Record "User Setup";
        UsrId: Code[50];
        SequenceNo: Integer;
        IsUserAllowedToApproveIfNoApprovalUserExists: Boolean;
    begin
        UsrId := UserId;

        SequenceNo := GetLastSequenceNo(ApprovalEntryArgument);

        if not UserSetup.Get(UserId) then
            Error(UserIdNotInSetupErr, UsrId);

        IsUserAllowedToApproveIfNoApprovalUserExists := UserSetup."Approval Administrator";
        OnCreateApprovalRequestForApproverOnAfterCheckUserSetupUserID(UserSetup, WorkflowStepArgument, ApprovalEntryArgument, IsUserAllowedToApproveIfNoApprovalUserExists);

        UsrId := UserSetup."Approver ID";
        if not UserSetup.Get(UsrId) then begin
            if not IsUserAllowedToApproveIfNoApprovalUserExists then
                Error(ApproverUserIdNotInSetupErr, UserSetup."User ID");
            UsrId := UserId;
        end;

        SequenceNo += 1;
        MakeApprovalEntry(ApprovalEntryArgument, SequenceNo, UsrId, WorkflowStepArgument);
    end;

    local procedure CreateApprovalRequestForSalespersPurchaser(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    var
        UserSetup: Record "User Setup";
        SequenceNo: Integer;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateApprovalRequestForSalespersPurchaser(WorkflowStepArgument, ApprovalEntryArgument, IsHandled);
        if IsHandled then
            exit;

        SequenceNo := GetLastSequenceNo(ApprovalEntryArgument);

        FindUserSetupBySalesPurchCode(UserSetup, ApprovalEntryArgument);

        SequenceNo += 1;

        if WorkflowStepArgument."Approver Limit Type" = WorkflowStepArgument."Approver Limit Type"::"First Qualified Approver" then begin
            if IsSufficientApprover(UserSetup, ApprovalEntryArgument) then
                MakeApprovalEntry(ApprovalEntryArgument, SequenceNo, UserSetup."User ID", WorkflowStepArgument);
        end else
            MakeApprovalEntry(ApprovalEntryArgument, SequenceNo, UserSetup."User ID", WorkflowStepArgument);
    end;

    procedure CreateApprovalRequestForUser(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    var
        SequenceNo: Integer;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateApprovalRequestForUser(WorkflowStepArgument, ApprovalEntryArgument, IsHandled);
        if IsHandled then
            exit;

        SequenceNo := GetLastSequenceNo(ApprovalEntryArgument);

        SequenceNo += 1;
        MakeApprovalEntry(ApprovalEntryArgument, SequenceNo, UserId, WorkflowStepArgument);
    end;

    procedure CreateApprovalRequestForSpecificUser(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    var
        UserSetup: Record "User Setup";
        UsrId: Code[50];
        SequenceNo: Integer;
    begin
        UsrId := WorkflowStepArgument."Approver User ID";

        SequenceNo := GetLastSequenceNo(ApprovalEntryArgument);

        if not UserSetup.Get(UsrId) then
            Error(UserIdNotInSetupErr, UsrId);

        SequenceNo += 1;
        MakeApprovalEntry(ApprovalEntryArgument, SequenceNo, UsrId, WorkflowStepArgument);
    end;

    procedure MakeApprovalEntry(ApprovalEntryArgument: Record "Approval Entry"; SequenceNo: Integer; ApproverId: Code[50]; WorkflowStepArgument: Record "Workflow Step Argument")
    var
        ApprovalEntry: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeMakeApprovalEntry(ApprovalEntry, ApprovalEntryArgument, WorkflowStepArgument, ApproverId, IsHandled);
        if IsHandled then
            exit;

        ApprovalEntry."Table ID" := ApprovalEntryArgument."Table ID";
        ApprovalEntry."Document Type" := ApprovalEntryArgument."Document Type";
        ApprovalEntry."Document No." := ApprovalEntryArgument."Document No.";
        ApprovalEntry."Salespers./Purch. Code" := ApprovalEntryArgument."Salespers./Purch. Code";
        ApprovalEntry."Sequence No." := SequenceNo;
        ApprovalEntry."Sender ID" := CopyStr(UserId(), 1, 50);
        ApprovalEntry.Amount := ApprovalEntryArgument.Amount;
        ApprovalEntry."Amount (LCY)" := ApprovalEntryArgument."Amount (LCY)";
        ApprovalEntry."Currency Code" := ApprovalEntryArgument."Currency Code";
        ApprovalEntry."Approver ID" := ApproverId;
        ApprovalEntry."Workflow Step Instance ID" := ApprovalEntryArgument."Workflow Step Instance ID";
        if ApproverId = UserId then
            ApprovalEntry.Status := ApprovalEntry.Status::Approved
        else
            ApprovalEntry.Status := ApprovalEntry.Status::Created;
        ApprovalEntry."Date-Time Sent for Approval" := CreateDateTime(Today, Time);
        ApprovalEntry."Last Date-Time Modified" := CreateDateTime(Today, Time);
        ApprovalEntry."Last Modified By User ID" := CopyStr(UserId(), 1, 50);
        ApprovalEntry."Due Date" := CalcDate(WorkflowStepArgument."Due Date Formula", Today);

        case WorkflowStepArgument."Delegate After" of
            WorkflowStepArgument."Delegate After"::Never:
                Evaluate(ApprovalEntry."Delegation Date Formula", '');
            WorkflowStepArgument."Delegate After"::"1 day":
                Evaluate(ApprovalEntry."Delegation Date Formula", '<1D>');
            WorkflowStepArgument."Delegate After"::"2 days":
                Evaluate(ApprovalEntry."Delegation Date Formula", '<2D>');
            WorkflowStepArgument."Delegate After"::"5 days":
                Evaluate(ApprovalEntry."Delegation Date Formula", '<5D>');
            else
                Evaluate(ApprovalEntry."Delegation Date Formula", '');
        end;
        ApprovalEntry."Available Credit Limit (LCY)" := ApprovalEntryArgument."Available Credit Limit (LCY)";
        SetApproverType(WorkflowStepArgument, ApprovalEntry);
        SetLimitType(WorkflowStepArgument, ApprovalEntry);
        ApprovalEntry."Record ID to Approve" := ApprovalEntryArgument."Record ID to Approve";
        ApprovalEntry."Approval Code" := ApprovalEntryArgument."Approval Code";
        IsHandled := false;
        OnBeforeApprovalEntryInsert(ApprovalEntry, ApprovalEntryArgument, WorkflowStepArgument, ApproverId, IsHandled);
        if IsHandled then
            exit;
        ApprovalEntry.Insert(true);
    end;

    procedure CalcPurchaseDocAmount(PurchaseHeader: Record "Purchase Header"; var ApprovalAmount: Decimal; var ApprovalAmountLCY: Decimal)
    var
        TempPurchaseLine: Record "Purchase Line" temporary;
        TotalPurchaseLine: Record "Purchase Line";
        TotalPurchaseLineLCY: Record "Purchase Line";
        PurchPost: Codeunit "Purch.-Post";
        TempAmount: Decimal;
        VAtText: Text[30];
    begin
        PurchaseHeader.CalcInvDiscForHeader();
        PurchPost.GetPurchLines(PurchaseHeader, TempPurchaseLine, 0);
        OnCalcPurchaseDocAmountOnAfterPurchPostGetPurchLines(TempPurchaseLine);
        Clear(PurchPost);
        PurchPost.SumPurchLinesTemp(
          PurchaseHeader, TempPurchaseLine, 0, TotalPurchaseLine, TotalPurchaseLineLCY,
          TempAmount, VAtText);
        ApprovalAmount := TotalPurchaseLine.Amount;
        ApprovalAmountLCY := TotalPurchaseLineLCY.Amount;

        OnAfterCalcPurchaseDocAmount(PurchaseHeader, TotalPurchaseLine, TotalPurchaseLineLCY, ApprovalAmount, ApprovalAmountLCY);
    end;

    procedure CalcSalesDocAmount(SalesHeader: Record "Sales Header"; var ApprovalAmount: Decimal; var ApprovalAmountLCY: Decimal)
    var
        TempSalesLine: Record "Sales Line" temporary;
        TotalSalesLine: Record "Sales Line";
        TotalSalesLineLCY: Record "Sales Line";
        SalesPost: Codeunit "Sales-Post";
        TempAmount: array[5] of Decimal;
        VAtText: Text[30];
    begin
        SalesHeader.CalcInvDiscForHeader();
        SalesPost.GetSalesLines(SalesHeader, TempSalesLine, 0);
        Clear(SalesPost);
        SalesPost.SumSalesLinesTemp(
          SalesHeader, TempSalesLine, 0, TotalSalesLine, TotalSalesLineLCY,
          TempAmount[1], VAtText, TempAmount[2], TempAmount[3], TempAmount[4]);
        ApprovalAmount := TotalSalesLine.Amount;
        ApprovalAmountLCY := TotalSalesLineLCY.Amount;
        OnAfterCalcSalesDocAmount(SalesHeader, TotalSalesLine, TotalSalesLineLCY, ApprovalAmount, ApprovalAmountLCY);
    end;

    procedure PopulateApprovalEntryArgument(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance"; var ApprovalEntryArgument: Record "Approval Entry")
    var
        Customer: Record Customer;
        GenJournalBatch: Record "Gen. Journal Batch";
        GenJournalLine: Record "Gen. Journal Line";
        PurchaseHeader: Record "Purchase Header";
        SalesHeader: Record "Sales Header";
        IncomingDocument: Record "Incoming Document";
        Vendor: Record Vendor;
        RequisitionWkshName: Record "Requisition Wksh. Name";
        ItemJournalBatch: Record "Item Journal Batch";
        EnumAssignmentMgt: Codeunit "Enum Assignment Management";
        ApprovalAmount: Decimal;
        ApprovalAmountLCY: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePopulateApprovalEntryArgument(WorkflowStepInstance, ApprovalEntryArgument, IsHandled);
        if not IsHandled then begin
            ApprovalEntryArgument.Init();
            ApprovalEntryArgument."Table ID" := RecRef.Number;
            ApprovalEntryArgument."Record ID to Approve" := RecRef.RecordId;
            ApprovalEntryArgument."Document Type" := ApprovalEntryArgument."Document Type"::" ";
            ApprovalEntryArgument."Approval Code" := WorkflowStepInstance."Workflow Code";
            ApprovalEntryArgument."Workflow Step Instance ID" := WorkflowStepInstance.ID;

            case RecRef.Number of
                DATABASE::"Purchase Header":
                    begin
                        RecRef.SetTable(PurchaseHeader);
                        CalcPurchaseDocAmount(PurchaseHeader, ApprovalAmount, ApprovalAmountLCY);
                        ApprovalEntryArgument."Document Type" := EnumAssignmentMgt.GetPurchApprovalDocumentType(PurchaseHeader."Document Type");
                        ApprovalEntryArgument."Document No." := PurchaseHeader."No.";
                        ApprovalEntryArgument."Salespers./Purch. Code" := PurchaseHeader."Purchaser Code";
                        ApprovalEntryArgument.Amount := ApprovalAmount;
                        ApprovalEntryArgument."Amount (LCY)" := ApprovalAmountLCY;
                        ApprovalEntryArgument."Currency Code" := PurchaseHeader."Currency Code";
                    end;
                DATABASE::"Sales Header":
                    begin
                        RecRef.SetTable(SalesHeader);
                        CalcSalesDocAmount(SalesHeader, ApprovalAmount, ApprovalAmountLCY);
                        ApprovalEntryArgument."Document Type" := EnumAssignmentMgt.GetSalesApprovalDocumentType(SalesHeader."Document Type");
                        ApprovalEntryArgument."Document No." := SalesHeader."No.";
                        ApprovalEntryArgument."Salespers./Purch. Code" := SalesHeader."Salesperson Code";
                        ApprovalEntryArgument.Amount := ApprovalAmount;
                        ApprovalEntryArgument."Amount (LCY)" := ApprovalAmountLCY;
                        ApprovalEntryArgument."Currency Code" := SalesHeader."Currency Code";
                        ApprovalEntryArgument."Available Credit Limit (LCY)" := GetAvailableCreditLimit(SalesHeader);
                    end;
                DATABASE::Customer:
                    begin
                        RecRef.SetTable(Customer);
                        ApprovalEntryArgument."Salespers./Purch. Code" := Customer."Salesperson Code";
                        ApprovalEntryArgument."Currency Code" := Customer."Currency Code";
                        ApprovalEntryArgument."Available Credit Limit (LCY)" := Customer.CalcAvailableCredit();
                    end;
                DATABASE::"Gen. Journal Batch":
                    RecRef.SetTable(GenJournalBatch);
                DATABASE::"Gen. Journal Line":
                    begin
                        RecRef.SetTable(GenJournalLine);
                        case GenJournalLine."Document Type" of
                            GenJournalLine."Document Type"::Invoice:
                                ApprovalEntryArgument."Document Type" := ApprovalEntryArgument."Document Type"::Invoice;
                            GenJournalLine."Document Type"::"Credit Memo":
                                ApprovalEntryArgument."Document Type" := ApprovalEntryArgument."Document Type"::"Credit Memo";
                            GenJournalLine."Document Type"::" ":
                                ApprovalEntryArgument."Document Type" := ApprovalEntryArgument."Document Type"::" ";
                            GenJournalLine."Document Type"::"Payment":
                                ApprovalEntryArgument."Document Type" := ApprovalEntryArgument."Document Type"::"Payment";
                            else
                                ApprovalEntryArgument."Document Type" := GenJournalLine."Document Type";
                        end;
                        ApprovalEntryArgument."Document No." := GenJournalLine."Document No.";
                        ApprovalEntryArgument."Salespers./Purch. Code" := GenJournalLine."Salespers./Purch. Code";
                        ApprovalEntryArgument.Amount := GenJournalLine.Amount;
                        ApprovalEntryArgument."Amount (LCY)" := GenJournalLine."Amount (LCY)";
                        ApprovalEntryArgument."Currency Code" := GenJournalLine."Currency Code";
                    end;
                DATABASE::"Incoming Document":
                    begin
                        RecRef.SetTable(IncomingDocument);
                        ApprovalEntryArgument."Document No." := Format(IncomingDocument."Entry No.");
                    end;
                DATABASE::Vendor:
                    begin
                        RecRef.SetTable(Vendor);
                        ApprovalEntryArgument."Salespers./Purch. Code" := Vendor."Purchaser Code";
                    end;
                Database::"Requisition Wksh. Name":
                    RecRef.SetTable(RequisitionWkshName);
                Database::"Item Journal Batch":
                    RecRef.SetTable(ItemJournalBatch);
                else
                    OnPopulateApprovalEntryArgument(RecRef, ApprovalEntryArgument, WorkflowStepInstance);
            end;
        end;

        OnAfterPopulateApprovalEntryArgument(WorkflowStepInstance, ApprovalEntryArgument, IsHandled, RecRef);
    end;

    procedure CreateApprovalEntryNotification(ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance")
    var
        WorkflowStepArgument: Record "Workflow Step Argument";
        NotificationEntry: Record "Notification Entry";
        IsNotificationRequiredForCurrentUser: Boolean;
        IsNotifySenderRequired: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateApprovalEntryNotification(ApprovalEntry, IsHandled, WorkflowStepInstance);
        if not IsHandled then begin
            if not WorkflowStepArgument.Get(WorkflowStepInstance.Argument) then
                exit;

            IsNotificationRequiredForCurrentUser := (ApprovalEntry."Approver ID" <> UserId) or IsBackground();
            IsNotifySenderRequired := ((ApprovalEntry."Sender ID" <> UserId) or IsBackground()) and (ApprovalEntry."Sender ID" <> ApprovalEntry."Approver ID");

            ApprovalEntry.Reset();
            if IsNotificationRequiredForCurrentUser and (ApprovalEntry.Status <> ApprovalEntry.Status::Rejected) then
                NotificationEntry.CreateNotificationEntry(
                    NotificationEntry.Type::Approval, ApprovalEntry."Approver ID",
                    ApprovalEntry, WorkflowStepArgument."Link Target Page", WorkflowStepArgument."Custom Link", CopyStr(UserId(), 1, 50));
            if WorkflowStepArgument."Notify Sender" and IsNotifySenderRequired then
                NotificationEntry.CreateNotificationEntry(
                    NotificationEntry.Type::Approval, ApprovalEntry."Sender ID",
                    ApprovalEntry, WorkflowStepArgument."Link Target Page", WorkflowStepArgument."Custom Link", CopyStr(UserId(), 1, 50));
        end;

        OnAfterCreateApprovalEntryNotification(ApprovalEntry, WorkflowStepArgument);
    end;

    local procedure SetApproverType(WorkflowStepArgument: Record "Workflow Step Argument"; var ApprovalEntry: Record "Approval Entry")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSetApproverType(WorkflowStepArgument, ApprovalEntry, IsHandled);
        if IsHandled then
            exit;

        case WorkflowStepArgument."Approver Type" of
            WorkflowStepArgument."Approver Type"::"Salesperson/Purchaser":
                ApprovalEntry."Approval Type" := ApprovalEntry."Approval Type"::"Sales Pers./Purchaser";
            WorkflowStepArgument."Approver Type"::Approver:
                ApprovalEntry."Approval Type" := ApprovalEntry."Approval Type"::Approver;
            WorkflowStepArgument."Approver Type"::"Workflow User Group":
                ApprovalEntry."Approval Type" := ApprovalEntry."Approval Type"::"Workflow User Group";
        end;

        OnAfterSetApproverType(WorkflowStepArgument, ApprovalEntry);
    end;

    local procedure SetLimitType(WorkflowStepArgument: Record "Workflow Step Argument"; var ApprovalEntry: Record "Approval Entry")
    begin
        case WorkflowStepArgument."Approver Limit Type" of
            WorkflowStepArgument."Approver Limit Type"::"Approver Chain",
            WorkflowStepArgument."Approver Limit Type"::"First Qualified Approver":
                ApprovalEntry."Limit Type" := ApprovalEntry."Limit Type"::"Approval Limits";
            WorkflowStepArgument."Approver Limit Type"::"Direct Approver":
                ApprovalEntry."Limit Type" := ApprovalEntry."Limit Type"::"No Limits";
            WorkflowStepArgument."Approver Limit Type"::"Specific Approver":
                ApprovalEntry."Limit Type" := ApprovalEntry."Limit Type"::"No Limits";
        end;

        if ApprovalEntry."Approval Type" = ApprovalEntry."Approval Type"::"Workflow User Group" then
            ApprovalEntry."Limit Type" := ApprovalEntry."Limit Type"::"No Limits";

        OnAfterSetLimitType(WorkflowStepArgument, ApprovalEntry);
    end;

    local procedure IsSufficientPurchApprover(UserSetup: Record "User Setup"; DocumentType: Enum "Purchase Document Type"; ApprovalAmountLCY: Decimal): Boolean
    var
        PurchaseHeader: Record "Purchase Header";
        IsHandled: Boolean;
        IsSufficient: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsSufficientPurchApprover(UserSetup, DocumentType, ApprovalAmountLCY, IsSufficient, IsHandled);
        if IsHandled then
            exit(IsSufficient);

        if UserSetup."User ID" = UserSetup."Approver ID" then
            exit(true);

        case DocumentType of
            PurchaseHeader."Document Type"::Quote:
                if UserSetup."Unlimited Request Approval" or
                   ((ApprovalAmountLCY <= UserSetup."Request Amount Approval Limit") and (UserSetup."Request Amount Approval Limit" <> 0))
                then
                    exit(true);
            else
                if UserSetup."Unlimited Purchase Approval" or
                   ((ApprovalAmountLCY <= UserSetup."Purchase Amount Approval Limit") and (UserSetup."Purchase Amount Approval Limit" <> 0))
                then
                    exit(true);
        end;

        exit(false);
    end;

    local procedure IsSufficientSalesApprover(UserSetup: Record "User Setup"; DocumentType: Enum "Sales Document Type"; ApprovalAmountLCY: Decimal): Boolean
    var
        IsHandled: Boolean;
        IsSufficient: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsSufficientSalesApprover(UserSetup, DocumentType, ApprovalAmountLCY, IsSufficient, IsHandled);
        if IsHandled then
            exit(IsSufficient);

        if UserSetup."User ID" = UserSetup."Approver ID" then
            exit(true);

        if UserSetup."Unlimited Sales Approval" or
           ((ApprovalAmountLCY <= UserSetup."Sales Amount Approval Limit") and (UserSetup."Sales Amount Approval Limit" <> 0))
        then
            exit(true);

        exit(false);
    end;

    local procedure IsSufficientGenJournalLineApprover(UserSetup: Record "User Setup"; ApprovalEntryArgument: Record "Approval Entry") Result: Boolean
    var
        GenJournalLine: Record "Gen. Journal Line";
        RecRef: RecordRef;
        IsHandled: Boolean;
    begin
        RecRef.Get(ApprovalEntryArgument."Record ID to Approve");
        RecRef.SetTable(GenJournalLine);

        IsHandled := false;
        OnIsSufficientGenJournalLineApproverOnAfterRecRefSetTable(UserSetup, ApprovalEntryArgument, GenJournalLine, Result, IsHandled);
        if IsHandled then
            exit;

        if GenJournalLine.IsForPurchase() then
            exit(IsSufficientPurchApprover(UserSetup, ApprovalEntryArgument."Document Type", ApprovalEntryArgument."Amount (LCY)"));

        if GenJournalLine.IsForSales() then
            exit(IsSufficientSalesApprover(UserSetup, ApprovalEntryArgument."Document Type", ApprovalEntryArgument."Amount (LCY)"));

        if GenJournalLine.IsForGLAccount() then
            exit(IsSufficientGLAccountApprover(UserSetup, ApprovalEntryArgument."Amount (LCY)"));

        exit(true);
    end;

    local procedure IsSufficientGLAccountApprover(UserSetup: Record "User Setup"; ApprovalAmountLCY: Decimal): Boolean
    begin
        if UserSetup."User ID" = UserSetup."Approver ID" then
            exit(true);

        if UserSetup."Unlimited Request Approval" or
            ((ApprovalAmountLCY <= UserSetup."Request Amount Approval Limit") and (UserSetup."Request Amount Approval Limit" <> 0))
        then
            exit(true);

        exit(false);
    end;

    procedure IsSufficientApprover(UserSetup: Record "User Setup"; ApprovalEntryArgument: Record "Approval Entry"): Boolean
    var
        IsSufficient: Boolean;
        IsHandled: Boolean;
    begin
        OnBeforeIsSufficientApprover(UserSetup, ApprovalEntryArgument);
        IsSufficient := true;
        case ApprovalEntryArgument."Table ID" of
            DATABASE::"Purchase Header":
                IsSufficient := IsSufficientPurchApprover(UserSetup, ApprovalEntryArgument."Document Type", ApprovalEntryArgument."Amount (LCY)");
            DATABASE::"Sales Header":
                IsSufficient := IsSufficientSalesApprover(UserSetup, ApprovalEntryArgument."Document Type", ApprovalEntryArgument."Amount (LCY)");
            DATABASE::"Gen. Journal Line":
                IsSufficient := IsSufficientGenJournalLineApprover(UserSetup, ApprovalEntryArgument);
            else
                OnSufficientApproverElseCase(UserSetup, ApprovalEntryArgument, IsSufficient);
        end;

        IsHandled := false;
        OnAfterIsSufficientApprover(UserSetup, ApprovalEntryArgument, IsSufficient, IsHandled);
        if not IsHandled then
            if ApprovalEntryArgument."Table ID" in [Database::"Gen. Journal Batch", Database::"Item Journal Batch", Database::"Requisition Wksh. Name"] then
                Message(ApporvalChainIsUnsupportedMsg, Format(ApprovalEntryArgument."Record ID to Approve"));

        exit(IsSufficient);
    end;

    local procedure GetAvailableCreditLimit(SalesHeader: Record "Sales Header"): Decimal
    begin
        exit(SalesHeader.CheckAvailableCreditLimit());
    end;

    procedure PrePostApprovalCheckSales(var SalesHeader: Record "Sales Header"): Boolean
    var
        IsHandled: Boolean;
        Result: Boolean;
    begin
        IsHandled := false;
        OnBeforePrePostApprovalCheckSales(SalesHeader, IsHandled, Result);
        if IsHandled then
            exit(Result);

        if IsSalesHeaderPendingApproval(SalesHeader) then
            Error(SalesPrePostCheckErr, SalesHeader."Document Type", SalesHeader."No.");

        exit(true);
    end;

    procedure PrePostApprovalCheckPurch(var PurchaseHeader: Record "Purchase Header") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePrePostApprovalCheckPurch(PurchaseHeader, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if IsPurchaseHeaderPendingApproval(PurchaseHeader) then
            Error(PurchPrePostCheckErr, PurchaseHeader."Document Type", PurchaseHeader."No.");

        exit(true);
    end;

    procedure IsIncomingDocApprovalsWorkflowEnabled(var IncomingDocument: Record "Incoming Document"): Boolean
    begin
        exit(WorkflowManagement.CanExecuteWorkflow(IncomingDocument, WorkflowEventHandling.RunWorkflowOnSendIncomingDocForApprovalCode()));
    end;

    procedure IsPurchaseApprovalsWorkflowEnabled(var PurchaseHeader: Record "Purchase Header") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsPurchaseApprovalsWorkflowEnabled(PurchaseHeader, Result, IsHandled);
        if IsHandled then
            exit(Result);
        exit(WorkflowManagement.CanExecuteWorkflow(PurchaseHeader, WorkflowEventHandling.RunWorkflowOnSendPurchaseDocForApprovalCode()));
    end;

    procedure IsPurchaseHeaderPendingApproval(var PurchaseHeader: Record "Purchase Header"): Boolean
    begin
        if PurchaseHeader.Status <> PurchaseHeader.Status::Open then
            exit(false);

        exit(IsPurchaseApprovalsWorkflowEnabled(PurchaseHeader));
    end;

    procedure IsSalesApprovalsWorkflowEnabled(var SalesHeader: Record "Sales Header"): Boolean
    begin
        exit(WorkflowManagement.CanExecuteWorkflow(SalesHeader, WorkflowEventHandling.RunWorkflowOnSendSalesDocForApprovalCode()));
    end;

    procedure IsSalesHeaderPendingApproval(var SalesHeader: Record "Sales Header"): Boolean
    begin
        if SalesHeader.Status <> SalesHeader.Status::Open then
            exit(false);

        exit(IsSalesApprovalsWorkflowEnabled(SalesHeader));
    end;

    procedure IsOverdueNotificationsWorkflowEnabled(): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetFilter(Status, '%1|%2', ApprovalEntry.Status::Created, ApprovalEntry.Status::Open);
        ApprovalEntry.SetFilter("Due Date", '<%1', Today);
        if not ApprovalEntry.FindSet() then
            ApprovalEntry.Init();

        exit(WorkflowManagement.WorkflowExists(ApprovalEntry, ApprovalEntry,
            WorkflowEventHandling.RunWorkflowOnSendOverdueNotificationsCode()));
    end;

    procedure IsVendorBankApprovalsWorkflowEnabled(var VendorBankAccount: Record "Vendor Bank Account") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsVendorBankApprovalsWorkflowEnabled(VendorBankAccount, Result, IsHandled);
        if IsHandled then
            exit(Result);

        exit(WorkflowManagement.CanExecuteWorkflow(VendorBankAccount,
            WorkflowEventHandling.RunWorkflowOnSendVendorBankAccountForApprovalCode()));
    end;

    procedure IsGeneralJournalBatchApprovalsWorkflowEnabled(var GenJournalBatch: Record "Gen. Journal Batch") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsGeneralJournalBatchApprovalsWorkflowEnabled(GenJournalBatch, Result, IsHandled);
        if IsHandled then
            exit(Result);

        exit(WorkflowManagement.CanExecuteWorkflow(GenJournalBatch,
            WorkflowEventHandling.RunWorkflowOnSendGeneralJournalBatchForApprovalCode()));
    end;

    procedure IsGeneralJournalLineApprovalsWorkflowEnabled(var GenJournalLine: Record "Gen. Journal Line") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsGeneralJournalLineApprovalsWorkflowEnabled(GenJournalLine, Result, IsHandled);
        if IsHandled then
            exit(Result);

        exit(WorkflowManagement.CanExecuteWorkflow(GenJournalLine,
            WorkflowEventHandling.RunWorkflowOnSendGeneralJournalLineForApprovalCode()));
    end;

    procedure IsItemJournalBatchApprovalsWorkflowEnabled(var ItemJournalBatch: Record "Item Journal Batch") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsItemJournalBatchApprovalsWorkflowEnabled(ItemJournalBatch, Result, IsHandled);
        if IsHandled then
            exit(Result);

        exit(WorkflowManagement.CanExecuteWorkflow(ItemJournalBatch, WorkflowEventHandling.RunWorkflowOnSendItemJournalBatchForApprovalCode()));
    end;

    procedure IsRequisitionWkshBatchApprovalsWorkflowEnabled(var RequisitionWkshName: Record "Requisition Wksh. Name") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsRequisitionWkshBatchApprovalsWorkflowEnabled(RequisitionWkshName, Result, IsHandled);
        if IsHandled then
            exit(Result);

        exit(WorkflowManagement.CanExecuteWorkflow(RequisitionWkshName, WorkflowEventHandling.RunWorkflowOnSendRequisitionWkshBatchForApprovalCode()));
    end;

    procedure CheckPurchaseApprovalPossible(var PurchaseHeader: Record "Purchase Header") Result: Boolean
    var
        IsHandled: Boolean;
        ShowNothingToApproveError: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckPurchaseApprovalPossible(PurchaseHeader, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if not IsPurchaseApprovalsWorkflowEnabled(PurchaseHeader) then
            Error(NoWorkflowEnabledErr);

        ShowNothingToApproveError := not PurchaseHeader.PurchLinesExist();
        OnCheckPurchaseApprovalPossibleOnAfterCalcShowNothingToApproveError(PurchaseHeader, ShowNothingToApproveError);
        if ShowNothingToApproveError then
            Error(NothingToApproveErr);

        OnAfterCheckPurchaseApprovalPossible(PurchaseHeader);

        exit(true);
    end;

    procedure CheckIncomingDocApprovalsWorkflowEnabled(var IncomingDocument: Record "Incoming Document"): Boolean
    begin
        if not IsIncomingDocApprovalsWorkflowEnabled(IncomingDocument) then
            Error(NoWorkflowEnabledErr);

        exit(true);
    end;

    procedure CheckSalesApprovalPossible(var SalesHeader: Record "Sales Header"): Boolean
    var
        IsHandled: Boolean;
        Result: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckSalesApprovalPossible(SalesHeader, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if not IsSalesApprovalsWorkflowEnabled(SalesHeader) then
            Error(NoWorkflowEnabledErr);

        if not SalesHeader.SalesLinesExist() then
            Error(NothingToApproveErr);

        OnAfterCheckSalesApprovalPossible(SalesHeader);

        exit(true);
    end;

    procedure CheckCustomerApprovalsWorkflowEnabled(var Customer: Record Customer) Result: Boolean
    begin
        if not WorkflowManagement.CanExecuteWorkflow(Customer, WorkflowEventHandling.RunWorkflowOnSendCustomerForApprovalCode()) then begin
            if WorkflowManagement.EnabledWorkflowExist(DATABASE::Customer, WorkflowEventHandling.RunWorkflowOnCustomerChangedCode()) then
                exit(false);
            Error(NoWorkflowEnabledErr);
        end;
        Result := true;
        OnAfterCheckCustomerApprovalsWorkflowEnabled(Customer, Result);
    end;

    procedure CheckVendorApprovalsWorkflowEnabled(var Vendor: Record Vendor): Boolean
    begin
        if not WorkflowManagement.CanExecuteWorkflow(Vendor, WorkflowEventHandling.RunWorkflowOnSendVendorForApprovalCode()) then begin
            if WorkflowManagement.EnabledWorkflowExist(DATABASE::Vendor, WorkflowEventHandling.RunWorkflowOnVendorChangedCode()) then
                exit(false);
            Error(NoWorkflowEnabledErr);
        end;
        exit(true);
    end;

    procedure CheckVendorBankAccountApprovalsWorkflowEnabled(var VendorBankAccount: Record "Vendor Bank Account") Result: Boolean
    begin
        if not WorkflowManagement.CanExecuteWorkflow(VendorBankAccount, WorkflowEventHandling.RunWorkflowOnSendVendorBankAccountForApprovalCode()) then begin
            if WorkflowManagement.EnabledWorkflowExist(DATABASE::"Vendor Bank Account", WorkflowEventHandling.RunWorkflowOnSendVendorBankAccountForApprovalCode()) then
                exit(false);
            Error(NoWorkflowEnabledErr);
        end;
        exit(true);
    end;

    procedure CheckItemApprovalsWorkflowEnabled(var Item: Record Item) Result: Boolean
    begin
        if not WorkflowManagement.CanExecuteWorkflow(Item, WorkflowEventHandling.RunWorkflowOnSendItemForApprovalCode()) then begin
            if WorkflowManagement.EnabledWorkflowExist(DATABASE::Item, WorkflowEventHandling.RunWorkflowOnItemChangedCode()) then
                exit(false);
            Error(NoWorkflowEnabledErr);
        end;
        Result := true;
        OnAfterCheckItemApprovalsWorkflowEnabled(Item, Result);
    end;

    procedure CheckGeneralJournalBatchApprovalsWorkflowEnabled(var GenJournalBatch: Record "Gen. Journal Batch"): Boolean
    begin
        if not
           WorkflowManagement.CanExecuteWorkflow(GenJournalBatch,
             WorkflowEventHandling.RunWorkflowOnSendGeneralJournalBatchForApprovalCode())
        then
            Error(NoWorkflowEnabledErr);

        exit(true);
    end;

    procedure CheckGeneralJournalLineApprovalsWorkflowEnabled(var GenJournalLine: Record "Gen. Journal Line"): Boolean
    begin
        if not
           WorkflowManagement.CanExecuteWorkflow(GenJournalLine,
             WorkflowEventHandling.RunWorkflowOnSendGeneralJournalLineForApprovalCode())
        then
            Error(NoWorkflowEnabledErr);

        exit(true);
    end;

    procedure CheckItemJournalBatchApprovalsWorkflowEnabled(var ItemJournalBatch: Record "Item Journal Batch"): Boolean
    begin
        if not WorkflowManagement.CanExecuteWorkflow(ItemJournalBatch, WorkflowEventHandling.RunWorkflowOnSendItemJournalBatchForApprovalCode()) then
            Error(NoWorkflowEnabledErr);

        exit(true);
    end;

    procedure CheckRequisitionWkshBatchApprovalsWorkflowEnabled(var RequisitionWkshName: Record "Requisition Wksh. Name"): Boolean
    begin
        if not WorkflowManagement.CanExecuteWorkflow(RequisitionWkshName, WorkflowEventHandling.RunWorkflowOnSendRequisitionWkshBatchForApprovalCode()) then
            Error(NoWorkflowEnabledErr);

        exit(true);
    end;

    procedure CheckJobQueueEntryApprovalEnabled(): Boolean
    begin
        exit(WorkflowManagement.EnabledWorkflowExist(Database::"Job Queue Entry", WorkflowEventHandling.RunWorkflowOnSendJobQueueEntryForApprovalCode()));
    end;

    procedure DeleteApprovalEntry(Variant: Variant)
    var
        RecRef: RecordRef;
    begin
        RecRef.GetTable(Variant);
        DeleteApprovalEntries(RecRef.RecordId);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnMoveGenJournalLine', '', false, false)]
    procedure PostApprovalEntriesMoveGenJournalLine(var GenJournalLine: Record "Gen. Journal Line"; ToRecordID: RecordID)
    begin
        PostApprovalEntries(GenJournalLine.RecordId, ToRecordID, GenJournalLine."Document No.");
    end;

    [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteGenJournalLine(var Rec: Record "Gen. Journal Line"; RunTrigger: Boolean)
    begin
        if not Rec.IsTemporary then
            DeleteApprovalEntries(Rec.RecordId);
    end;

    [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Batch", 'OnMoveGenJournalBatch', '', false, false)]
    procedure PostApprovalEntriesMoveGenJournalBatch(var Sender: Record "Gen. Journal Batch"; ToRecordID: RecordID)
    var
        RecordRestrictionMgt: Codeunit "Record Restriction Mgt.";
    begin
        if PostApprovalEntries(Sender.RecordId, ToRecordID, '') then begin
            RecordRestrictionMgt.AllowRecordUsage(Sender);
            DeleteApprovalEntries(Sender.RecordId);
        end;
    end;

    [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Batch", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteGenJournalBatch(var Rec: Record "Gen. Journal Batch"; RunTrigger: Boolean)
    var
        GenJnlTemplate: Record "Gen. Journal Template";
    begin
        if Rec.IsTemporary then
            exit;

        if GenJnlTemplate.Get(Rec."Journal Template Name") then
            if not GenJnlTemplate."Increment Batch Name" then
                DeleteApprovalEntries(Rec.RecordId);
    end;

    [EventSubscriber(ObjectType::Table, Database::"Item Journal Batch", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteItemJournalBatch(var Rec: Record "Item Journal Batch"; RunTrigger: Boolean)
    var
        ItemJnlTemplate: Record "Item Journal Template";
    begin
        if Rec.IsTemporary then
            exit;

        if ItemJnlTemplate.Get(Rec."Journal Template Name") then
            if not ItemJnlTemplate."Increment Batch Name" then
                DeleteApprovalEntries(Rec.RecordId());
    end;

    [EventSubscriber(ObjectType::Table, Database::"Item Journal Batch", 'OnMoveItemJournalBatch', '', false, false)]
    procedure PostApprovalEntriesMoveItemJournalBatch(var Sender: Record "Item Journal Batch"; ToRecordID: RecordID)
    var
        RecordRestrictionMgt: Codeunit "Record Restriction Mgt.";
    begin
        if PostApprovalEntries(Sender.RecordId(), ToRecordID, '') then begin
            RecordRestrictionMgt.AllowRecordUsage(Sender);
            DeleteApprovalEntries(Sender.RecordId());
        end;
    end;

    [EventSubscriber(ObjectType::Table, Database::"Requisition Wksh. Name", 'OnMoveRequisitionWkshBatch', '', false, false)]
    procedure PostApprovalEntriesMoveRequisitionWkshBatch(var Sender: Record "Requisition Wksh. Name"; ToRecordID: RecordID)
    var
        RecordRestrictionMgt: Codeunit "Record Restriction Mgt.";
    begin
        if PostApprovalEntries(Sender.RecordId(), ToRecordID, '') then begin
            RecordRestrictionMgt.AllowRecordUsage(Sender);
            DeleteApprovalEntries(Sender.RecordId());
        end;
    end;

    [EventSubscriber(ObjectType::Table, Database::"Requisition Wksh. Name", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteRequisitionWkshName(var Rec: Record "Requisition Wksh. Name"; RunTrigger: Boolean)
    var
        ReqWkshTemplate: Record "Req. Wksh. Template";
    begin
        if Rec.IsTemporary then
            exit;

        if ReqWkshTemplate.Get(Rec."Worksheet Template Name") then
            if not ReqWkshTemplate."Increment Batch Name" then
                DeleteApprovalEntries(Rec.RecordId());
    end;

    [EventSubscriber(ObjectType::Table, Database::"Customer", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteCustomer(var Rec: Record Customer; RunTrigger: Boolean)
    begin
        if not Rec.IsTemporary then
            DeleteApprovalEntries(Rec.RecordId);
    end;

    [EventSubscriber(ObjectType::Table, Database::"Vendor", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteVendor(var Rec: Record Vendor; RunTrigger: Boolean)
    begin
        if not Rec.IsTemporary then
            DeleteApprovalEntries(Rec.RecordId);
    end;

    [EventSubscriber(ObjectType::Table, Database::"Vendor Bank Account", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteVendorBankAccount(var Rec: Record "Vendor Bank Account"; RunTrigger: Boolean)
    begin
        if not Rec.IsTemporary then
            DeleteApprovalEntries(Rec.RecordId);
    end;

    [EventSubscriber(ObjectType::Table, Database::"Item", 'OnAfterDeleteEvent', '', false, false)]
    procedure DeleteApprovalEntriesAfterDeleteItem(var Rec: Record Item; RunTrigger: Boolean)
    begin
        if not Rec.IsTemporary then
            DeleteApprovalEntries(Rec.RecordId);
    end;

    procedure PostApprovalEntries(ApprovedRecordID: RecordID; PostedRecordID: RecordID; PostedDocNo: Code[20]): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
        PostedApprovalEntry: Record "Posted Approval Entry";
        RecordLinkManagement: Codeunit "Record Link Management";
    begin
        ApprovalEntry.SetAutoCalcFields("Pending Approvals", "Number of Approved Requests", "Number of Rejected Requests");
        ApprovalEntry.SetRange("Table ID", ApprovedRecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", ApprovedRecordID);
        OnPostApprovalEntriesOnAfterApprovalEntrySetFilters(ApprovalEntry, ApprovedRecordID.TableNo);
        if not ApprovalEntry.FindSet() then
            exit(false);

        repeat
            PostedApprovalEntry.Init();
            PostedApprovalEntry.TransferFields(ApprovalEntry);
            PostedApprovalEntry."Number of Approved Requests" := ApprovalEntry."Number of Approved Requests";
            PostedApprovalEntry."Number of Rejected Requests" := ApprovalEntry."Number of Rejected Requests";
            PostedApprovalEntry."Table ID" := PostedRecordID.TableNo;
            PostedApprovalEntry."Document No." := PostedDocNo;
            PostedApprovalEntry."Posted Record ID" := PostedRecordID;
            PostedApprovalEntry."Entry No." := 0;
            OnPostApprovalEntriesOnBeforePostedApprovalEntryInsert(PostedApprovalEntry, ApprovalEntry);
            PostedApprovalEntry.Insert(true);
            RecordLinkManagement.CopyLinks(ApprovalEntry, PostedApprovalEntry);
        until ApprovalEntry.Next() = 0;

        PostApprovalCommentLines(ApprovedRecordID, PostedRecordID, PostedDocNo);
        exit(true);
    end;

    local procedure PostApprovalCommentLines(ApprovedRecordID: RecordID; PostedRecordID: RecordID; PostedDocNo: Code[20])
    var
        ApprovalCommentLine: Record "Approval Comment Line";
        PostedApprovalCommentLine: Record "Posted Approval Comment Line";
    begin
        ApprovalCommentLine.SetRange("Table ID", ApprovedRecordID.TableNo);
        ApprovalCommentLine.SetRange("Record ID to Approve", ApprovedRecordID);
        OnPostApprovalCommentLinesOnAfterApprovalCommentLineSetFilters(ApprovalCommentLine, ApprovedRecordID.TableNo);
        if ApprovalCommentLine.FindSet() then
            repeat
                PostedApprovalCommentLine.Init();
                PostedApprovalCommentLine.TransferFields(ApprovalCommentLine);
                PostedApprovalCommentLine."Entry No." := 0;
                PostedApprovalCommentLine."Table ID" := PostedRecordID.TableNo;
                PostedApprovalCommentLine."Document No." := PostedDocNo;
                PostedApprovalCommentLine."Posted Record ID" := PostedRecordID;
                OnPostApprovalCommentLinesOnBeforePostedApprovalCommentLineInsert(PostedApprovalCommentLine, ApprovalCommentLine);
                PostedApprovalCommentLine.Insert(true);
            until ApprovalCommentLine.Next() = 0;
    end;

    procedure ShowPostedApprovalEntries(PostedRecordID: RecordID)
    var
        PostedApprovalEntry: Record "Posted Approval Entry";
    begin
        PostedApprovalEntry.FilterGroup(2);
        PostedApprovalEntry.SetRange("Posted Record ID", PostedRecordID);
        PostedApprovalEntry.FilterGroup(0);
        PAGE.Run(PAGE::"Posted Approval Entries", PostedApprovalEntry);
    end;

    procedure DeletePostedApprovalEntries(PostedRecordID: RecordID)
    var
        PostedApprovalEntry: Record "Posted Approval Entry";
    begin
        PostedApprovalEntry.SetRange("Table ID", PostedRecordID.TableNo);
        PostedApprovalEntry.SetRange("Posted Record ID", PostedRecordID);
        if not PostedApprovalEntry.IsEmpty() then
            PostedApprovalEntry.DeleteAll();
        DeletePostedApprovalCommentLines(PostedRecordID);
    end;

    local procedure DeletePostedApprovalCommentLines(PostedRecordID: RecordID)
    var
        PostedApprovalCommentLine: Record "Posted Approval Comment Line";
    begin
        PostedApprovalCommentLine.SetRange("Table ID", PostedRecordID.TableNo);
        PostedApprovalCommentLine.SetRange("Posted Record ID", PostedRecordID);
        if not PostedApprovalCommentLine.IsEmpty() then
            PostedApprovalCommentLine.DeleteAll();
    end;

    procedure SetStatusToPendingApproval(var Variant: Variant)
    var
        SalesHeader: Record "Sales Header";
        PurchaseHeader: Record "Purchase Header";
        IncomingDocument: Record "Incoming Document";
        RecRef: RecordRef;
        IsHandled: Boolean;
    begin
        OnBeforeSetStatusToPendingApproval(Variant);
        RecRef.GetTable(Variant);

        case RecRef.Number of
            DATABASE::"Purchase Header":
                begin
                    RecRef.SetTable(PurchaseHeader);
                    PurchaseHeader.Validate(Status, PurchaseHeader.Status::"Pending Approval");
                    PurchaseHeader.Modify(true);
                    Variant := PurchaseHeader;
                end;
            DATABASE::"Sales Header":
                begin
                    RecRef.SetTable(SalesHeader);
                    SalesHeader.Validate(Status, SalesHeader.Status::"Pending Approval");
                    SalesHeader.Modify(true);
                    Variant := SalesHeader;
                end;
            DATABASE::"Incoming Document":
                begin
                    RecRef.SetTable(IncomingDocument);
                    IncomingDocument.Validate(Status, IncomingDocument.Status::"Pending Approval");
                    IncomingDocument.Modify(true);
                    Variant := IncomingDocument;
                end;
            else begin
                IsHandled := false;
                OnSetStatusToPendingApproval(RecRef, Variant, IsHandled);
                if not IsHandled then
                    Error(UnsupportedRecordTypeErr, RecRef.Caption);
            end;
        end;
    end;

    procedure InformUserOnStatusChange(Variant: Variant; WorkflowInstanceId: Guid)
    var
        RecRef: RecordRef;
    begin
        RecRef.GetTable(Variant);

        case RecRef.Number of
            DATABASE::"Purchase Header":
                ShowPurchApprovalStatus(Variant);
            DATABASE::"Sales Header":
                ShowSalesApprovalStatus(Variant);
            else
                ShowCommonApprovalStatus(RecRef, WorkflowInstanceId);
        end;
    end;

    local procedure ShowCommonApprovalStatus(var RecRef: RecordRef; WorkflowInstanceId: Guid)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeShowCommonApprovalStatus(RecRef, IsHandled);
        if IsHandled then
            exit;

        ShowApprovalStatus(RecRef.RecordId, WorkflowInstanceId);
    end;

    procedure GetApprovalComment(Variant: Variant)
    var
        BlankGUID: Guid;
    begin
        ShowApprovalComments(Variant, BlankGUID);
    end;

    procedure GetApprovalCommentForWorkflowStepInstanceID(Variant: Variant; WorkflowStepInstanceID: Guid)
    begin
        ShowApprovalComments(Variant, WorkflowStepInstanceID);
    end;

    local procedure ShowApprovalComments(Variant: Variant; WorkflowStepInstanceID: Guid)
    var
        ApprovalCommentLine: Record "Approval Comment Line";
        ApprovalEntry: Record "Approval Entry";
        RecRef: RecordRef;
    begin
        RecRef.GetTable(Variant);

        case RecRef.Number of
            DATABASE::"Approval Entry":
                begin
                    ApprovalEntry := Variant;
                    RecRef.Get(ApprovalEntry."Record ID to Approve");
                    ApprovalCommentLine.SetRange("Table ID", RecRef.Number);
                    ApprovalCommentLine.SetRange("Record ID to Approve", ApprovalEntry."Record ID to Approve");
                end;
            DATABASE::"Purchase Header":
                begin
                    ApprovalCommentLine.SetRange("Table ID", RecRef.Number);
                    ApprovalCommentLine.SetRange("Record ID to Approve", RecRef.RecordId);
                    FindOpenApprovalEntryForCurrUser(ApprovalEntry, RecRef.RecordId);
                end;
            DATABASE::"Sales Header":
                begin
                    ApprovalCommentLine.SetRange("Table ID", RecRef.Number);
                    ApprovalCommentLine.SetRange("Record ID to Approve", RecRef.RecordId);
                    FindOpenApprovalEntryForCurrUser(ApprovalEntry, RecRef.RecordId);
                end;
            else
                SetCommonApprovalCommentLineFilters(RecRef, ApprovalEntry, ApprovalCommentLine);
        end;
        OnShowApprovalCommentsOnAfterSetApprovalCommentLineFilters(ApprovalCommentLine, ApprovalEntry, RecRef);

        if IsNullGuid(WorkflowStepInstanceID) and (not IsNullGuid(ApprovalEntry."Workflow Step Instance ID")) then
            WorkflowStepInstanceID := ApprovalEntry."Workflow Step Instance ID";

        RunApprovalCommentsPage(ApprovalCommentLine, WorkflowStepInstanceID);
    end;

    local procedure SetCommonApprovalCommentLineFilters(var RecRef: RecordRef; var ApprovalEntry: Record "Approval Entry"; var ApprovalCommentLine: Record "Approval Comment Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSetCommonApprovalCommentLineFilters(RecRef, ApprovalCommentLine, IsHandled);
        if IsHandled then
            exit;

        ApprovalCommentLine.SetRange("Table ID", RecRef.Number);
        ApprovalCommentLine.SetRange("Record ID to Approve", RecRef.RecordId);
        FindOpenApprovalEntryForCurrUser(ApprovalEntry, RecRef.RecordId);
    end;

    local procedure RunApprovalCommentsPage(var ApprovalCommentLine: Record "Approval Comment Line"; WorkflowStepInstanceID: Guid)
    var
        ApprovalComments: Page "Approval Comments";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeRunApprovalCommentsPage(ApprovalCommentLine, WorkflowStepInstanceID, IsHandled);
        if IsHandled then
            exit;

        ApprovalComments.SetTableView(ApprovalCommentLine);
        ApprovalComments.SetWorkflowStepInstanceID(WorkflowStepInstanceID);
        ApprovalComments.Run();
    end;

    procedure HasOpenApprovalEntriesForCurrentUser(RecordID: RecordID): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Open);
        ApprovalEntry.SetRange("Approver ID", UserId);
        OnHasOpenApprovalEntriesForCurrentUserOnAfterSetApprovalEntrySetFilters(ApprovalEntry);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if ApprovalEntry.IsEmpty() then
            exit(false);
        ApprovalEntry.SetRange("Related to Change", false);

        OnHasOpenApprovalEntriesForCurrentUserOnAfterSetApprovalEntryFilters(ApprovalEntry);

        exit(not ApprovalEntry.IsEmpty());
    end;

    procedure HasOpenApprovalEntries(RecordID: RecordID) Result: Boolean
    var
        ApprovalEntry: Record "Approval Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeHasOpenApprovalEntries(RecordID, Result, IsHandled);
        if IsHandled then
            exit(Result);

        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Open);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if ApprovalEntry.IsEmpty() then
            exit(false);
        ApprovalEntry.SetRange("Related to Change", false);
        OnHasOpenApprovalEntriesOnAfterApprovalEntrySetFilters(ApprovalEntry);
        exit(not ApprovalEntry.IsEmpty);
    end;

    procedure HasOpenOrPendingApprovalEntries(RecordID: RecordID): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetFilter(Status, '%1|%2', ApprovalEntry.Status::Open, ApprovalEntry.Status::Created);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if ApprovalEntry.IsEmpty() then
            exit(false);
        ApprovalEntry.SetRange("Related to Change", false);
        exit(not ApprovalEntry.IsEmpty);
    end;

    procedure HasOpenOrPendingApprovalEntriesForCurrentUser(RecordID: RecordID): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetFilter(Status, '%1|%2', ApprovalEntry.Status::Open, ApprovalEntry.Status::Created);
        ApprovalEntry.SetRange("Approver ID", UserId);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if ApprovalEntry.IsEmpty() then
            exit(false);
        ApprovalEntry.SetRange("Related to Change", false);
        exit(not ApprovalEntry.IsEmpty);
    end;

    procedure HasApprovedApprovalEntries(RecordID: RecordID): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Approved);
        if ApprovalEntry.IsEmpty() then
            exit(false);
        ApprovalEntry.SetRange("Related to Change", false);
        exit(not ApprovalEntry.IsEmpty);
    end;


    procedure HasApprovalEntries(RecordID: RecordID): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if ApprovalEntry.IsEmpty() then
            exit(false);
        ApprovalEntry.SetRange("Related to Change", false);
        exit(not ApprovalEntry.IsEmpty);
    end;

    local procedure HasPendingApprovalEntriesForWorkflow(RecId: RecordID; WorkflowInstanceId: Guid): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Record ID to Approve", RecId);
        ApprovalEntry.SetFilter(Status, '%1|%2', ApprovalEntry.Status::Open, ApprovalEntry.Status::Created);
        ApprovalEntry.SetFilter("Workflow Step Instance ID", WorkflowInstanceId);
        OnHasPendingApprovalEntriesForWorkflowOnAfterApprovalEntrySetFilters(ApprovalEntry);
        exit(not ApprovalEntry.IsEmpty);
    end;

    procedure HasAnyOpenJournalLineApprovalEntries(JournalTemplateName: Code[20]; JournalBatchName: Code[20]): Boolean
    var
        GenJournalLine: Record "Gen. Journal Line";
        ApprovalEntry: Record "Approval Entry";
        GenJournalLineRecRef: RecordRef;
        GenJournalLineRecordID: RecordID;
    begin
        ApprovalEntry.SetRange("Table ID", DATABASE::"Gen. Journal Line");
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Open);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if not ApprovalEntry.IsEmpty() then
            ApprovalEntry.SetRange("Related to Change", false);
        OnHasAnyOpenJournalLineApprovalEntriesOnAfterApprovalEntrySetFilters(ApprovalEntry);
        if ApprovalEntry.IsEmpty() then
            exit(false);

        GenJournalLine.SetRange("Journal Template Name", JournalTemplateName);
        GenJournalLine.SetRange("Journal Batch Name", JournalBatchName);
        if GenJournalLine.IsEmpty() then
            exit(false);

        if GenJournalLine.Count < ApprovalEntry.Count then begin
            GenJournalLine.FindSet();
            repeat
                if HasOpenApprovalEntries(GenJournalLine.RecordId) then
                    exit(true);
            until GenJournalLine.Next() = 0;
        end else begin
            ApprovalEntry.FindSet();
            repeat
                GenJournalLineRecordID := ApprovalEntry."Record ID to Approve";
                GenJournalLineRecRef := GenJournalLineRecordID.GetRecord();
                GenJournalLineRecRef.SetTable(GenJournalLine);
                if (GenJournalLine."Journal Template Name" = JournalTemplateName) and
                   (GenJournalLine."Journal Batch Name" = JournalBatchName)
                then
                    exit(true);
            until ApprovalEntry.Next() = 0;
        end;

        exit(false)
    end;

    procedure TrySendJournalBatchApprovalRequest(var GenJournalLine: Record "Gen. Journal Line")
    var
        GenJournalBatch: Record "Gen. Journal Batch";
    begin
        GetGeneralJournalBatch(GenJournalBatch, GenJournalLine);
        CheckGeneralJournalBatchApprovalsWorkflowEnabled(GenJournalBatch);
        if HasOpenApprovalEntries(GenJournalBatch.RecordId) or
           HasAnyOpenJournalLineApprovalEntries(GenJournalBatch."Journal Template Name", GenJournalBatch.Name)
        then
            Error(PendingJournalBatchApprovalExistsErr);
        if HasApprovedApprovalEntries(GenJournalBatch.RecordId) then
            if not Confirm(ApprovedJournalBatchApprovalExistsMsg) then
                exit;
        OnSendGeneralJournalBatchForApproval(GenJournalBatch);
    end;

    procedure TrySendJournalLineApprovalRequests(var GenJournalLine: Record "Gen. Journal Line")
    begin
        OnBeforeTrySendJournalLineApprovalRequests(GenJournalLine);
        if GenJournalLine.Count = 1 then
            CheckGeneralJournalLineApprovalsWorkflowEnabled(GenJournalLine);

        repeat
            OnTrySendJournalLineApprovalRequestsOnBeforeLoopIteration(GenJournalLine);
            if WorkflowManagement.CanExecuteWorkflow(GenJournalLine,
                 WorkflowEventHandling.RunWorkflowOnSendGeneralJournalLineForApprovalCode()) and
               not HasOpenApprovalEntries(GenJournalLine.RecordId)
            then
                OnSendGeneralJournalLineForApproval(GenJournalLine);
        until GenJournalLine.Next() = 0;
    end;

    procedure TryCancelJournalBatchApprovalRequest(var GenJournalLine: Record "Gen. Journal Line")
    var
        GenJournalBatch: Record "Gen. Journal Batch";
        WorkflowWebhookManagement: Codeunit "Workflow Webhook Management";
    begin
        GetGeneralJournalBatch(GenJournalBatch, GenJournalLine);
        OnCancelGeneralJournalBatchApprovalRequest(GenJournalBatch);
        WorkflowWebhookManagement.FindAndCancel(GenJournalBatch.RecordId);
    end;

    procedure TryCancelJournalLineApprovalRequests(var GenJournalLine: Record "Gen. Journal Line")
    var
        WorkflowWebhookManagement: Codeunit "Workflow Webhook Management";
    begin
        repeat
            if HasOpenApprovalEntries(GenJournalLine.RecordId) then
                OnCancelGeneralJournalLineApprovalRequest(GenJournalLine);
            WorkflowWebhookManagement.FindAndCancel(GenJournalLine.RecordId);
        until GenJournalLine.Next() = 0;
        Message(ApprovalReqCanceledForSelectedLinesMsg);
    end;

    procedure ShowJournalApprovalEntries(var GenJournalLine: Record "Gen. Journal Line")
    var
        ApprovalEntry: Record "Approval Entry";
        GenJournalBatch: Record "Gen. Journal Batch";
    begin
        GetGeneralJournalBatch(GenJournalBatch, GenJournalLine);

        ApprovalEntry.SetFilter("Table ID", '%1|%2', DATABASE::"Gen. Journal Batch", DATABASE::"Gen. Journal Line");
        ApprovalEntry.SetFilter("Record ID to Approve", '%1|%2', GenJournalBatch.RecordId, GenJournalLine.RecordId);
        ApprovalEntry.SetRange("Related to Change", false);
        PAGE.Run(PAGE::"Approval Entries", ApprovalEntry);
    end;

    local procedure GetGeneralJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch"; var GenJournalLine: Record "Gen. Journal Line")
    begin
        if not GenJournalBatch.Get(GenJournalLine."Journal Template Name", GenJournalLine."Journal Batch Name") then
            GenJournalBatch.Get(GenJournalLine.GetFilter("Journal Template Name"), GenJournalLine.GetFilter("Journal Batch Name"));
    end;

    procedure TrySendJournalBatchApprovalRequest(var ItemJournalLine: Record "Item Journal Line")
    var
        ItemJournalBatch: Record "Item Journal Batch";
    begin
        GetItemJournalBatch(ItemJournalBatch, ItemJournalLine);
        CheckItemJournalBatchApprovalsWorkflowEnabled(ItemJournalBatch);

        if HasOpenApprovalEntries(ItemJournalBatch.RecordId()) or
           HasAnyOpenJournalLineApprovalEntries(ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name)
        then
            Error(PendingJournalBatchApprovalExistsErr);

        if HasApprovedApprovalEntries(ItemJournalBatch.RecordId()) then
            if not Confirm(ApprovedJournalBatchApprovalExistsMsg) then
                exit;

        OnSendItemJournalBatchForApproval(ItemJournalBatch);
    end;

    procedure TryCancelJournalBatchApprovalRequest(var ItemJournalLine: Record "Item Journal Line")
    var
        ItemJournalBatch: Record "Item Journal Batch";
        WorkflowWebhookManagement: Codeunit "Workflow Webhook Management";
    begin
        GetItemJournalBatch(ItemJournalBatch, ItemJournalLine);
        OnCancelItemJournalBatchApprovalRequest(ItemJournalBatch);
        WorkflowWebhookManagement.FindAndCancel(ItemJournalBatch.RecordId());
    end;

    procedure ShowJournalApprovalEntries(var ItemJournalLine: Record "Item Journal Line")
    var
        ApprovalEntry: Record "Approval Entry";
        ItemJournalBatch: Record "Item Journal Batch";
    begin
        GetItemJournalBatch(ItemJournalBatch, ItemJournalLine);

        ApprovalEntry.SetRange("Table ID", Database::"Item Journal Batch");
        ApprovalEntry.SetRange("Record ID to Approve", ItemJournalBatch.RecordId());
        ApprovalEntry.SetRange("Related to Change", false);
        Page.Run(Page::"Approval Entries", ApprovalEntry);
    end;

    local procedure GetItemJournalBatch(var ItemJournalBatch: Record "Item Journal Batch"; var ItemJournalLine: Record "Item Journal Line")
    begin
        if not ItemJournalBatch.Get(ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name") then
            ItemJournalBatch.Get(ItemJournalLine.GetFilter("Journal Template Name"), ItemJournalLine.GetFilter("Journal Batch Name"));
    end;

    procedure TrySendWorksheetBatchApprovalRequest(var RequisitionLine: Record "Requisition Line")
    var
        RequisitionWkshName: Record "Requisition Wksh. Name";
    begin
        GetRequisitionWkshBatch(RequisitionWkshName, RequisitionLine);
        CheckRequisitionWkshBatchApprovalsWorkflowEnabled(RequisitionWkshName);

        if HasOpenApprovalEntries(RequisitionWkshName.RecordId()) then
            Error(PendingJournalBatchApprovalExistsErr);

        if HasApprovedApprovalEntries(RequisitionWkshName.RecordId()) then
            if not Confirm(ApprovedJournalBatchApprovalExistsMsg) then
                exit;

        OnSendRequisitionWkshBatchForApproval(RequisitionWkshName);
    end;

    procedure TryCancelWorksheetBatchApprovalRequest(var RequisitionLine: Record "Requisition Line")
    var
        RequisitionWkshName: Record "Requisition Wksh. Name";
        WorkflowWebhookManagement: Codeunit "Workflow Webhook Management";
    begin
        GetRequisitionWkshBatch(RequisitionWkshName, RequisitionLine);
        OnCancelRequisitionWkshBatchApprovalRequest(RequisitionWkshName);
        WorkflowWebhookManagement.FindAndCancel(RequisitionWkshName.RecordId());
    end;

    procedure ShowWorksheetApprovalEntries(var RequisitionLine: Record "Requisition Line")
    var
        ApprovalEntry: Record "Approval Entry";
        RequisitionWkshName: Record "Requisition Wksh. Name";
    begin
        GetRequisitionWkshBatch(RequisitionWkshName, RequisitionLine);

        ApprovalEntry.SetRange("Table ID", Database::"Requisition Wksh. Name");
        ApprovalEntry.SetRange("Record ID to Approve", RequisitionWkshName.RecordId());
        ApprovalEntry.SetRange("Related to Change", false);
        Page.Run(Page::"Approval Entries", ApprovalEntry);
    end;

    local procedure GetRequisitionWkshBatch(var RequisitionWkshName: Record "Requisition Wksh. Name"; var RequisitionLine: Record "Requisition Line")
    begin
        if not RequisitionWkshName.Get(RequisitionLine."Worksheet Template Name", RequisitionLine."Journal Batch Name") then
            RequisitionWkshName.Get(RequisitionLine.GetFilter("Worksheet Template Name"), RequisitionLine.GetFilter("Journal Batch Name"));
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Approvals Mgmt.", 'OnRenameRecordInApprovalRequest', '', false, false)]
    procedure RenameApprovalEntries(OldRecordId: RecordID; NewRecordId: RecordID)
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Record ID to Approve", OldRecordId);
        if not ApprovalEntry.IsEmpty() then
            ApprovalEntry.ModifyAll("Record ID to Approve", NewRecordId, true);
        ChangeApprovalComments(OldRecordId, NewRecordId);
    end;

    local procedure ChangeApprovalComments(OldRecordId: RecordID; NewRecordId: RecordID)
    var
        ApprovalCommentLine: Record "Approval Comment Line";
    begin
        ApprovalCommentLine.SetRange("Record ID to Approve", OldRecordId);
        if not ApprovalCommentLine.IsEmpty() then
            ApprovalCommentLine.ModifyAll("Record ID to Approve", NewRecordId, true);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Approvals Mgmt.", 'OnDeleteRecordInApprovalRequest', '', false, false)]
    procedure DeleteApprovalEntries(RecordIDToApprove: RecordID)
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecordIDToApprove.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordIDToApprove);
        OnDeleteApprovalEntriesOnAfterApprovalEntrySetFilters(ApprovalEntry);
        if not ApprovalEntry.IsEmpty() then
            ApprovalEntry.DeleteAll(true);
        DeleteApprovalCommentLines(RecordIDToApprove);
    end;

    procedure DeleteApprovalCommentLines(RecordIDToApprove: RecordID)
    var
        ApprovalCommentLine: Record "Approval Comment Line";
    begin
        ApprovalCommentLine.SetRange("Table ID", RecordIDToApprove.TableNo);
        ApprovalCommentLine.SetRange("Record ID to Approve", RecordIDToApprove);
        OnDeleteApprovalCommentLinesOnAfterApprovalCommentLineSetFilters(ApprovalCommentLine);
        if not ApprovalCommentLine.IsEmpty() then
            ApprovalCommentLine.DeleteAll(true);
    end;

    procedure CopyApprovalEntryQuoteToOrder(FromRecID: RecordID; ToDocNo: Code[20]; ToRecID: RecordID)
    var
        FromApprovalEntry: Record "Approval Entry";
        ToApprovalEntry: Record "Approval Entry";
        FromApprovalCommentLine: Record "Approval Comment Line";
        ToApprovalCommentLine: Record "Approval Comment Line";
        NextEntryNo: Integer;
    begin
        FromApprovalEntry.SetRange("Table ID", FromRecID.TableNo);
        FromApprovalEntry.SetRange("Record ID to Approve", FromRecID);
        if FromApprovalEntry.FindSet() then begin
            repeat
                ToApprovalEntry := FromApprovalEntry;
                ToApprovalEntry."Entry No." := 0; // Auto increment
                ToApprovalEntry."Document Type" := ToApprovalEntry."Document Type"::Order;
                ToApprovalEntry."Document No." := ToDocNo;
                ToApprovalEntry."Record ID to Approve" := ToRecID;
                ToApprovalEntry.Insert();
            until FromApprovalEntry.Next() = 0;

            FromApprovalCommentLine.SetRange("Table ID", FromRecID.TableNo);
            FromApprovalCommentLine.SetRange("Record ID to Approve", FromRecID);
            if FromApprovalCommentLine.FindSet() then begin
                NextEntryNo := ToApprovalCommentLine.GetLastEntryNo() + 1;
                repeat
                    ToApprovalCommentLine := FromApprovalCommentLine;
                    ToApprovalCommentLine."Entry No." := NextEntryNo;
                    ToApprovalCommentLine."Document Type" := ToApprovalCommentLine."Document Type"::Order;
                    ToApprovalCommentLine."Document No." := ToDocNo;
                    ToApprovalCommentLine."Record ID to Approve" := ToRecID;
                    ToApprovalCommentLine.Insert();
                    NextEntryNo += 1;
                until FromApprovalCommentLine.Next() = 0;
            end;
        end;
    end;

    procedure GetLastSequenceNo(ApprovalEntryArgument: Record "Approval Entry"): Integer
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetCurrentKey("Record ID to Approve", "Workflow Step Instance ID", "Sequence No.");
        ApprovalEntry.SetRange("Table ID", ApprovalEntryArgument."Table ID");
        ApprovalEntry.SetRange("Record ID to Approve", ApprovalEntryArgument."Record ID to Approve");
        ApprovalEntry.SetRange("Workflow Step Instance ID", ApprovalEntryArgument."Workflow Step Instance ID");
        OnGetLastSequenceNoOnAfterSetApprovalEntryFilters(ApprovalEntry, ApprovalEntryArgument);
        if ApprovalEntry.FindLast() then
            exit(ApprovalEntry."Sequence No.");
        exit(0);
    end;

    procedure OpenApprovalEntriesPage(RecId: RecordID)
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecId.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecId);
        PAGE.RunModal(PAGE::"Approval Entries", ApprovalEntry);
    end;

    procedure OpenApprovalsSales(SalesHeader: Record "Sales Header")
    begin
        RunWorkflowEntriesPage(
            SalesHeader.RecordId(), DATABASE::"Sales Header", SalesHeader."Document Type", SalesHeader."No.");
    end;

    procedure OpenApprovalsPurchase(PurchHeader: Record "Purchase Header")
    begin
        RunWorkflowEntriesPage(
            PurchHeader.RecordId(), DATABASE::"Purchase Header", PurchHeader."Document Type", PurchHeader."No.");
    end;

    procedure RunWorkflowEntriesPage(RecordIDInput: RecordID; TableId: Integer; DocumentType: Enum "Approval Document Type"; DocumentNo: Code[20])
    var
        ApprovalEntry: Record "Approval Entry";
        WorkflowWebhookEntry: Record "Workflow Webhook Entry";
        Approvals: Page Approvals;
        WorkflowWebhookEntries: Page "Workflow Webhook Entries";
        ApprovalEntries: Page "Approval Entries";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeRunWorkflowEntriesPage(RecordIDInput, TableId, DocumentType, DocumentNo, IsHandled);
        if IsHandled then
            exit;

        // if we are looking at a particular record, we want to see only record related workflow entries
        if DocumentNo <> '' then begin
            ApprovalEntry.SetRange("Record ID to Approve", RecordIDInput);
            WorkflowWebhookEntry.SetRange("Record ID", RecordIDInput);
            // if we have flows created by multiple applications, start generic page filtered for this RecordID
            if not ApprovalEntry.IsEmpty() and not WorkflowWebhookEntry.IsEmpty() then begin
                Approvals.Setfilters(RecordIDInput);
                Approvals.Run();
            end else begin
                // otherwise, open the page filtered for this record that corresponds to the type of the flow
                if not WorkflowWebhookEntry.IsEmpty() then begin
                    WorkflowWebhookEntries.Setfilters(RecordIDInput);
                    WorkflowWebhookEntries.Run();
                    exit;
                end;

                if not ApprovalEntry.IsEmpty() then begin
                    ApprovalEntries.SetRecordFilters(TableId, DocumentType, DocumentNo);
                    ApprovalEntries.Run();
                    exit;
                end;

                // if no workflow exist, show (empty) joint workflows page
                Approvals.Setfilters(RecordIDInput);
                Approvals.Run();
            end
        end else
            // otherwise, open the page with all workflow entries
            Approvals.Run();
    end;

    procedure CanCancelApprovalForRecord(RecID: RecordID) Result: Boolean
    var
        ApprovalEntry: Record "Approval Entry";
        UserSetup: Record "User Setup";
    begin
        if not UserSetup.Get(UserId) then
            exit(false);

        ApprovalEntry.SetRange("Table ID", RecID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecID);
        ApprovalEntry.SetFilter(Status, '%1|%2', ApprovalEntry.Status::Created, ApprovalEntry.Status::Open);

        if not UserSetup."Approval Administrator" then
            ApprovalEntry.SetRange("Sender ID", UserId);
        // Initial check before performing an expensive query due to the "Related to Change" flow field.
        if not ApprovalEntry.IsEmpty() then
            ApprovalEntry.SetRange("Related to Change", false);

        Result := ApprovalEntry.FindFirst();
        OnAfterCanCancelApprovalForRecord(RecID, Result, ApprovalEntry, UserSetup);
    end;

    procedure HasApprovalEntriesSentByCurrentUser(RecordId: RecordId): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecordID.TableNo);
        ApprovalEntry.SetRange("Record ID to Approve", RecordID);
        ApprovalEntry.SetFilter(Status, '<>%1', ApprovalEntry.Status::Canceled);
        ApprovalEntry.SetRange("Sender ID", UserId());
        exit(not ApprovalEntry.IsEmpty());
    end;

    local procedure FindUserSetupBySalesPurchCode(var UserSetup: Record "User Setup"; ApprovalEntryArgument: Record "Approval Entry")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeFindUserSetupBySalesPurchCode(UserSetup, ApprovalEntryArgument, IsHandled);
        if not IsHandled then
            if ApprovalEntryArgument."Salespers./Purch. Code" <> '' then begin
                UserSetup.SetCurrentKey("Salespers./Purch. Code");
                UserSetup.SetRange("Salespers./Purch. Code", ApprovalEntryArgument."Salespers./Purch. Code");
                if not UserSetup.FindFirst() then
                    Error(
                      PurchaserUserNotFoundErr, UserSetup."User ID", UserSetup.FieldCaption("Salespers./Purch. Code"),
                      UserSetup."Salespers./Purch. Code");
            end;

        OnAfterFindUserSetupBySalesPurchCode(UserSetup, ApprovalEntryArgument);
    end;

    local procedure CheckUserAsApprovalAdministrator(ApprovalEntry: Record "Approval Entry")
    var
        UserSetup: Record "User Setup";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckUserAsApprovalAdministrator(ApprovalEntry, IsHandled);
        if IsHandled then
            exit;

        UserSetup.Get(UserId);
        UserSetup.TestField("Approval Administrator");
    end;

    local procedure FindApprovedApprovalEntryForWorkflowUserGroup(var ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance"): Boolean
    var
        WorkflowStepArgument: Record "Workflow Step Argument";
        WorkflowResponseHandling: Codeunit "Workflow Response Handling";
        WorkflowInstance: Query "Workflow Instance";
    begin
        WorkflowStepInstance.SetLoadFields(Argument);
        WorkflowStepInstance.SetRange("Function Name", WorkflowResponseHandling.CreateApprovalRequestsCode());
        WorkflowStepInstance.SetRange("Record ID", WorkflowStepInstance."Record ID");
        WorkflowStepInstance.SetRange("Workflow Code", WorkflowStepInstance."Workflow Code");
        WorkflowStepInstance.SetRange(Type, WorkflowInstance.Type::Response);
        WorkflowStepInstance.SetRange(Status, WorkflowInstance.Status::Completed);
        if WorkflowStepInstance.FindSet() then
            repeat
                if WorkflowStepArgument.Get(WorkflowStepInstance.Argument) then
                    if WorkflowStepArgument."Approver Type" = WorkflowStepArgument."Approver Type"::"Workflow User Group" then begin
                        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Approved);
                        exit(ApprovalEntry.FindLast());
                    end;
            until WorkflowStepInstance.Next() = 0;
        exit(false);
    end;

    local procedure FindOpenApprovalEntriesForWorkflowStepInstance(ApprovalEntry: Record "Approval Entry"; WorkflowStepInstanceRecID: RecordID): Boolean
    var
        ApprovalEntry2: Record "Approval Entry";
    begin
        if ApprovalEntry."Approval Type" = ApprovalEntry."Approval Type"::"Workflow User Group" then
            ApprovalEntry2.SetFilter("Sequence No.", '>%1', ApprovalEntry."Sequence No.");
        ApprovalEntry2.SetFilter("Record ID to Approve", '%1|%2', WorkflowStepInstanceRecID, ApprovalEntry."Record ID to Approve");
        ApprovalEntry2.SetRange(Status, ApprovalEntry2.Status::Open);
        ApprovalEntry2.SetRange("Workflow Step Instance ID", ApprovalEntry."Workflow Step Instance ID");

        OnFindOpenApprovalEntriesForWorkflowStepInstanceOnAfterSetApprovalEntry2Filters(ApprovalEntry2, ApprovalEntry, WorkflowStepInstanceRecID);

        exit(not ApprovalEntry2.IsEmpty);
    end;

    local procedure IsBackground(): Boolean
    var
        ClientTypeManagement: Codeunit "Client Type Management";
    begin
        exit(ClientTypeManagement.GetCurrentClientType() in [ClientType::Background]);
    end;

    procedure PreventDeletingRecordWithOpenApprovalEntry(Variant: Variant)
    var
        GenJournalBatch: Record "Gen. Journal Batch";
        ItemJournalBatch: Record "Item Journal Batch";
        RequisitionWkshName: Record "Requisition Wksh. Name";
        ConfirmManagement: Codeunit "Confirm Management";
        WorkflowWebhookMgt: Codeunit "Workflow Webhook Management";
        RecRef: RecordRef;
    begin
        RecRef.GetTable(Variant);
        if HasOpenOrPendingApprovalEntriesForCurrentUser(RecRef.RecordId) then
            if (CanCancelApprovalForRecord(RecRef.RecordId)) or (RecRef.Number in [Database::"Item Journal Batch", Database::"Requisition Wksh. Name"]) then
                Error(PreventDeleteRecordWithOpenApprovalEntryForCurrUserMsg);

        if (HasOpenApprovalEntries(RecRef.RecordId) and CanCancelApprovalForRecord(RecRef.RecordId))
         or WorkflowWebhookMgt.HasPendingWorkflowWebhookEntryByRecordId(RecRef.RecordId) then
            case RecRef.Number of
                Database::"Gen. Journal Batch":
                    if ConfirmManagement.GetResponseOrDefault(PreventDeleteRecordWithOpenApprovalEntryMsg, true) then begin
                        RecRef.SetTable(GenJournalBatch);
                        OnCancelGeneralJournalBatchApprovalRequest(GenJournalBatch);
                    end else
                        Error('');
                Database::"Gen. Journal Line":
                    Error(PreventDeleteRecordWithOpenApprovalEntryForSenderMsg);
                Database::"Item Journal Batch":
                    if ConfirmManagement.GetResponseOrDefault(PreventDeleteRecordWithOpenApprovalEntryMsg, true) then begin
                        RecRef.SetTable(ItemJournalBatch);
                        OnCancelItemJournalBatchApprovalRequest(ItemJournalBatch);
                    end else
                        Error('');
                Database::"Requisition Wksh. Name":
                    if ConfirmManagement.GetResponseOrDefault(PreventDeleteRecordWithOpenApprovalEntryMsg, true) then begin
                        RecRef.SetTable(RequisitionWkshName);
                        OnCancelRequisitionWkshBatchApprovalRequest(RequisitionWkshName);
                    end else
                        Error('');
                else
                    OnPreventDeletingRecordWithOpenApprovalEntryElseCase(RecRef, Variant);
            end;
    end;

    procedure PreventInsertRecIfOpenApprovalEntryExist(Variant: Variant)
    var
        GenJournalBatch: Record "Gen. Journal Batch";
        ItemJournalBatch: Record "Item Journal Batch";
        RequisitionWkshName: Record "Requisition Wksh. Name";
        WorkflowWebhookMgt: Codeunit "Workflow Webhook Management";
        ConfirmManagement: Codeunit "Confirm Management";
        RecRef: RecordRef;
    begin
        RecRef.GetTable(Variant);
        case RecRef.Number of
            Database::"Gen. Journal Batch":
                begin
                    if HasOpenOrPendingApprovalEntriesForCurrentUser(RecRef.RecordId) and CanCancelApprovalForRecord(RecRef.RecordId) then
                        Error(PreventInsertRecordWithOpenApprovalEntryForCurrUserMsg);

                    if (HasOpenApprovalEntries(RecRef.RecordId) and CanCancelApprovalForRecord(RecRef.RecordId))
                      or WorkflowWebhookMgt.HasPendingWorkflowWebhookEntryByRecordId(RecRef.RecordId) then
                        if ConfirmManagement.GetResponseOrDefault(PreventInsertRecordWithOpenApprovalEntryMsg, true) then begin
                            RecRef.SetTable(GenJournalBatch);
                            OnCancelGeneralJournalBatchApprovalRequest(GenJournalBatch);
                        end else
                            Error('');
                end;
            Database::"Item Journal Batch":
                begin
                    if HasOpenOrPendingApprovalEntriesForCurrentUser(RecRef.RecordId()) then
                        Error(PreventInsertRecordWithOpenApprovalEntryForCurrUserMsg);

                    if (HasOpenApprovalEntries(RecRef.RecordId()) and CanCancelApprovalForRecord(RecRef.RecordId())) or WorkflowWebhookMgt.HasPendingWorkflowWebhookEntryByRecordId(RecRef.RecordId()) then
                        if ConfirmManagement.GetResponseOrDefault(PreventInsertRecordWithOpenApprovalEntryMsg, true) then begin
                            RecRef.SetTable(ItemJournalBatch);
                            OnCancelItemJournalBatchApprovalRequest(ItemJournalBatch);
                        end else
                            Error('');
                end;
            Database::"Requisition Wksh. Name":
                begin
                    if HasOpenOrPendingApprovalEntriesForCurrentUser(RecRef.RecordId()) then
                        Error(PreventInsertRecordWithOpenApprovalEntryForCurrUserMsg);

                    if (HasOpenApprovalEntries(RecRef.RecordId()) and CanCancelApprovalForRecord(RecRef.RecordId())) or WorkflowWebhookMgt.HasPendingWorkflowWebhookEntryByRecordId(RecRef.RecordId()) then
                        if ConfirmManagement.GetResponseOrDefault(PreventInsertRecordWithOpenApprovalEntryMsg, true) then begin
                            RecRef.SetTable(RequisitionWkshName);
                            OnCancelRequisitionWkshBatchApprovalRequest(RequisitionWkshName);
                        end else
                            Error('');
                end;
            else
                OnPreventInsertRecIfOpenApprovalEntryExistElseCase(RecRef, Variant);
        end;
    end;

    internal procedure PreventModifyRecIfOpenApprovalEntryExist(Variant: Variant)
    var
        ItemJournalBatch: Record "Item Journal Batch";
        RequisitionWkshName: Record "Requisition Wksh. Name";
        WorkflowWebhookMgt: Codeunit "Workflow Webhook Management";
        ConfirmManagement: Codeunit "Confirm Management";
        RecRef: RecordRef;
    begin
        RecRef.GetTable(Variant);
        case RecRef.Number of
            Database::"Item Journal Batch":
                begin
                    PreventModifyRecIfOpenApprovalEntryExistForCurrentUser(Variant);

                    if (HasOpenApprovalEntries(RecRef.RecordId()) and CanCancelApprovalForRecord(RecRef.RecordId())) or WorkflowWebhookMgt.HasPendingWorkflowWebhookEntryByRecordId(RecRef.RecordId()) then
                        if ConfirmManagement.GetResponseOrDefault(PreventModifyRecordWithOpenApprovalEntryNewMsg, true) then begin
                            RecRef.SetTable(ItemJournalBatch);
                            OnCancelItemJournalBatchApprovalRequest(ItemJournalBatch);
                        end else
                            Error('');
                end;
            Database::"Requisition Wksh. Name":
                begin
                    PreventModifyRecIfOpenApprovalEntryExistForCurrentUser(Variant);

                    if (HasOpenApprovalEntries(RecRef.RecordId()) and CanCancelApprovalForRecord(RecRef.RecordId())) or WorkflowWebhookMgt.HasPendingWorkflowWebhookEntryByRecordId(RecRef.RecordId()) then
                        if ConfirmManagement.GetResponseOrDefault(PreventModifyRecordWithOpenApprovalEntryNewMsg, true) then begin
                            RecRef.SetTable(RequisitionWkshName);
                            OnCancelRequisitionWkshBatchApprovalRequest(RequisitionWkshName);
                        end else
                            Error('');
                end;
        end;
    end;

    procedure PreventModifyRecIfOpenApprovalEntryExistForCurrentUser(Variant: Variant)
    var
        WorkflowWebhookMgt: Codeunit "Workflow Webhook Management";
        RecRef: RecordRef;
        ErrInfo: ErrorInfo;
        RejectApprovalRequestLbl: Label 'Reject approval';
        ShowCommentsLbl: Label 'Show comments';
        RejectApprovalRequestToolTipLbl: Label 'Reject approval request';
        ShowCommentsToolTipLbl: Label 'Show approval comments';
    begin
        RecRef.GetTable(Variant);
        if HasOpenOrPendingApprovalEntriesForCurrentUser(RecRef.RecordId) or WorkflowWebhookMgt.HasPendingWorkflowWebhookEntryByRecordId(RecRef.RecordId) then begin
            ErrInfo.ErrorType(ErrorType::Client);
            ErrInfo.Verbosity(Verbosity::Error);
            ErrInfo.Message(PreventModifyRecordWithOpenApprovalEntryMsg);
            ErrInfo.TableId(RecRef.Number);
            ErrInfo.RecordId(RecRef.RecordId);
            ErrInfo.AddAction(RejectApprovalRequestLbl, Codeunit::"Approvals Mgmt.", 'RejectApprovalRequest', RejectApprovalRequestToolTipLbl);
            ErrInfo.AddAction(ShowCommentsLbl, Codeunit::"Approvals Mgmt.", 'ShowApprovalCommentLinesForJournal', ShowCommentsToolTipLbl);
            Error(ErrInfo);
        end;
    end;

    procedure ShowApprovalCommentLinesForJournal(ErrInfo: ErrorInfo)
    var
        ApprovalCommentLine: Record "Approval Comment Line";
        ApprovalComments: Page "Approval Comments";
    begin
        ApprovalCommentLine.SetRange("Table ID", ErrInfo.TableId());
        ApprovalCommentLine.SetRange("Record ID to Approve", ErrInfo.RecordId());
        ApprovalComments.SetTableView(ApprovalCommentLine);
        ApprovalComments.RunModal();
    end;

    procedure RejectApprovalRequest(ErrInfo: ErrorInfo)
    begin
        RejectRecordApprovalRequest(ErrInfo.RecordId());
    end;

    procedure SendJournalLinesApprovalRequests(var GenJournalLine: Record "Gen. Journal Line")
    var
        BatchProcessingMgt: Codeunit "Batch Processing Mgt.";
        NoOfSelected: Integer;
        NoOfSkipped: Integer;
    begin
        OnBeforeSendJournalLinesApprovalRequests(GenJournalLine);

        NoOfSelected := GenJournalLine.Count();

        if NoOfSelected = 1 then begin
            TrySendJournalLineApprovalRequests(GenJournalLine);
            exit;
        end;

        repeat
            if not HasOpenApprovalEntries(GenJournalLine.RecordId) then
                GenJournalLine.Mark(true);
        until GenJournalLine.Next() = 0;
        GenJournalLine.MarkedOnly(true);
        if GenJournalLine.Find('-') then;
        NoOfSkipped := NoOfSelected - GenJournalLine.Count();
        BatchProcessingMgt.BatchProcess(GenJournalLine, Codeunit::"Approvals Journal Line Request", Enum::"Error Handling Options"::"Show Error", NoOfSelected, NoOfSkipped);
    end;

    procedure GetGenJnlBatchApprovalStatus(GenJournalLine: Record "Gen. Journal Line"; var GenJnlBatchApprovalStatus: Text[20]; EnabledGenJnlBatchWorkflowsExist: Boolean)
    var
        ApprovalEntry: Record "Approval Entry";
        GenJournalBatch: Record "Gen. Journal Batch";
    begin
        Clear(GenJnlBatchApprovalStatus);
        if not EnabledGenJnlBatchWorkflowsExist then
            exit;
        if not GenJournalBatch.Get(GenJournalLine."Journal Template Name", GenJournalLine."Journal Batch Name") then
            exit;

        if FindLastApprovalEntryForCurrUser(ApprovalEntry, GenJournalBatch.RecordId) then
            GenJnlBatchApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, GenJournalBatch)
        else
            if FindApprovalEntryByRecordId(ApprovalEntry, GenJournalBatch.RecordId) then
                GenJnlBatchApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, GenJournalBatch);
    end;

    procedure GetGenJnlLineApprovalStatus(GenJournalLine: Record "Gen. Journal Line"; var GenJnlLineApprovalStatus: Text[20]; EnabledGenJnlLineWorkflowsExist: Boolean)
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        Clear(GenJnlLineApprovalStatus);
        if not EnabledGenJnlLineWorkflowsExist then
            exit;

        if FindLastApprovalEntryForCurrUser(ApprovalEntry, GenJournalLine.RecordId) then
            GenJnlLineApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, GenJournalLine)
        else
            if FindApprovalEntryByRecordId(ApprovalEntry, GenJournalLine.RecordId) then
                GenJnlLineApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, GenJournalLine);
    end;

    procedure GetItemJnlBatchApprovalStatus(ItemJournalLine: Record "Item Journal Line"; var ItemJnlBatchApprovalStatus: Text[20]; EnabledItemJnlBatchWorkflowsExist: Boolean)
    var
        ApprovalEntry: Record "Approval Entry";
        ItemJournalBatch: Record "Item Journal Batch";
    begin
        Clear(ItemJnlBatchApprovalStatus);
        if not EnabledItemJnlBatchWorkflowsExist then
            exit;

        if not ItemJournalBatch.Get(ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name") then
            exit;

        if FindLastApprovalEntryForCurrUser(ApprovalEntry, ItemJournalBatch.RecordId()) then
            ItemJnlBatchApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, ItemJournalBatch)
        else
            if FindApprovalEntryByRecordId(ApprovalEntry, ItemJournalBatch.RecordId()) then
                ItemJnlBatchApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, ItemJournalBatch);
    end;

    procedure GetRequisitionWkshBatchApprovalStatus(RequisitionLine: Record "Requisition Line"; var ReqWkshBatchApprovalStatus: Text[20]; EnabledReqWkshBatchWorkflowsExist: Boolean)
    var
        ApprovalEntry: Record "Approval Entry";
        RequisitionWkshName: Record "Requisition Wksh. Name";
    begin
        Clear(ReqWkshBatchApprovalStatus);
        if not EnabledReqWkshBatchWorkflowsExist then
            exit;

        if not RequisitionWkshName.Get(RequisitionLine."Worksheet Template Name", RequisitionLine."Journal Batch Name") then
            exit;

        if FindLastApprovalEntryForCurrUser(ApprovalEntry, RequisitionWkshName.RecordId()) then
            ReqWkshBatchApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, RequisitionWkshName)
        else
            if FindApprovalEntryByRecordId(ApprovalEntry, RequisitionWkshName.RecordId()) then
                ReqWkshBatchApprovalStatus := GetApprovalStatusFromApprovalEntry(ApprovalEntry, RequisitionWkshName);
    end;

    internal procedure SendForApproval(var JobQueueEntry: Record "Job Queue Entry")
    var
        ApprovalsMgmt: Codeunit "Approvals Mgmt.";
        FeatureTelemetry: Codeunit "Feature Telemetry";
    begin
        if ApprovalsMgmt.CheckJobQueueEntryApprovalEnabled() then begin
            JobQueueEntry.SetStatus(JobQueueEntry.Status::"On Hold");
            Commit();
            ApprovalsMgmt.OnSendJobQueueEntryForApproval(JobQueueEntry);
            FeatureTelemetry.LogUsage('0000JQE', JobQueueDelegatedAdminCategoryTxt, DelegatedAdminSendingApprovalLbl);
        end else begin
            FeatureTelemetry.LogError('0000JQD', JobQueueDelegatedAdminCategoryTxt, DelegatedAdminSendingApprovalLbl, JobQueueWorkflowSetupErr);
            Error(JobQueueWorkflowSetupErr);
        end;
    end;

    local procedure GetApprovalStatusFromApprovalEntry(var ApprovalEntry: Record "Approval Entry"; GenJournalBatch: Record "Gen. Journal Batch"): Text[20]
    var
        RestrictedRecord: Record "Restricted Record";
        GenJournalLine: Record "Gen. Journal Line";
        FieldRef: FieldRef;
        ApprovalStatusName: Text;
    begin
        GetApprovalEntryStatusFieldRef(FieldRef, ApprovalEntry);
        ApprovalStatusName := GetApprovalEntryStatusValueName(FieldRef, ApprovalEntry);
        if ApprovalStatusName = 'Open' then
            exit(CopyStr(PendingApprovalLbl, 1, 20));
        if ApprovalStatusName = 'Approved' then begin
            RestrictedRecord.SetRange(Details, RestrictBatchUsageDetailsLbl);
            if not RestrictedRecord.IsEmpty() then begin
                RestrictedRecord.Reset();
                GenJournalLine.ReadIsolation(IsolationLevel::ReadUncommitted);
                GenJournalLine.SetLoadFields("Journal Template Name", "Journal Batch Name", "Line No.");
                GenJournalLine.SetRange("Journal Template Name", GenJournalBatch."Journal Template Name");
                GenJournalLine.SetRange("Journal Batch Name", GenJournalBatch.Name);
                if GenJournalLine.FindSet() then
                    repeat
                        RestrictedRecord.SetRange("Record ID", GenJournalLine.RecordId);
                        if not RestrictedRecord.IsEmpty() then
                            exit(CopyStr(ImposedRestrictionLbl, 1, 20));
                    until GenJournalLine.Next() = 0;
            end;
        end;
        exit(CopyStr(GetApprovalEntryStatusValueCaption(FieldRef, ApprovalEntry), 1, 20));
    end;

    local procedure GetApprovalStatusFromApprovalEntry(var ApprovalEntry: Record "Approval Entry"; GenJournalLine: Record "Gen. Journal Line"): Text[20]
    var
        RestrictedRecord: Record "Restricted Record";
        FieldRef: FieldRef;
        ApprovalStatusName: Text;
    begin
        GetApprovalEntryStatusFieldRef(FieldRef, ApprovalEntry);
        ApprovalStatusName := GetApprovalEntryStatusValueName(FieldRef, ApprovalEntry);
        if ApprovalStatusName = 'Open' then
            exit(CopyStr(PendingApprovalLbl, 1, 20));
        if ApprovalStatusName = 'Approved' then begin
            RestrictedRecord.SetRange("Record ID", GenJournalLine.RecordId);
            if not RestrictedRecord.IsEmpty() then
                exit(CopyStr(ImposedRestrictionLbl, 1, 20));
        end;
        exit(CopyStr(GetApprovalEntryStatusValueCaption(FieldRef, ApprovalEntry), 1, 20));
    end;

    local procedure GetApprovalStatusFromApprovalEntry(var ApprovalEntry: Record "Approval Entry"; ItemJournalBatch: Record "Item Journal Batch"): Text[20]
    var
        RestrictedRecord: Record "Restricted Record";
        FieldRef: FieldRef;
        ApprovalStatusName: Text;
    begin
        GetApprovalEntryStatusFieldRef(FieldRef, ApprovalEntry);
        ApprovalStatusName := GetApprovalEntryStatusValueName(FieldRef, ApprovalEntry);
        if ApprovalStatusName = 'Open' then
            exit(CopyStr(PendingApprovalLbl, 1, 20));

        if ApprovalStatusName = 'Approved' then begin
            RestrictedRecord.SetRange(Details, RestrictBatchUsageDetailsLbl);
            if not RestrictedRecord.IsEmpty() then begin
                RestrictedRecord.Reset();
                RestrictedRecord.SetRange("Record ID", ItemJournalBatch.RecordId);
                if not RestrictedRecord.IsEmpty() then
                    exit(CopyStr(ImposedRestrictionLbl, 1, 20));
            end;
        end;

        exit(CopyStr(GetApprovalEntryStatusValueCaption(FieldRef, ApprovalEntry), 1, 20));
    end;

    local procedure GetApprovalStatusFromApprovalEntry(var ApprovalEntry: Record "Approval Entry"; RequisitionWkshName: Record "Requisition Wksh. Name"): Text[20]
    var
        RestrictedRecord: Record "Restricted Record";
        FieldRef: FieldRef;
        ApprovalStatusName: Text;
    begin
        GetApprovalEntryStatusFieldRef(FieldRef, ApprovalEntry);
        ApprovalStatusName := GetApprovalEntryStatusValueName(FieldRef, ApprovalEntry);
        if ApprovalStatusName = 'Open' then
            exit(CopyStr(PendingApprovalLbl, 1, 20));

        if ApprovalStatusName = 'Approved' then begin
            RestrictedRecord.SetRange(Details, RestrictBatchUsageDetailsLbl);
            if not RestrictedRecord.IsEmpty() then begin
                RestrictedRecord.Reset();
                RestrictedRecord.SetRange("Record ID", RequisitionWkshName.RecordId);
                if not RestrictedRecord.IsEmpty() then
                    exit(CopyStr(ImposedRestrictionLbl, 1, 20));
            end;
        end;

        exit(CopyStr(GetApprovalEntryStatusValueCaption(FieldRef, ApprovalEntry), 1, 20));
    end;

    local procedure GetApprovalEntryStatusFieldRef(var FieldRef: FieldRef; var ApprovalEntry: Record "Approval Entry")
    var
        RecordRef: RecordRef;
    begin
        RecordRef.GetTable(ApprovalEntry);
        FieldRef := RecordRef.Field(ApprovalEntry.FieldNo(Status));
    end;

    local procedure GetApprovalEntryStatusValueName(var FieldRef: FieldRef; ApprovalEntry: Record "Approval Entry"): Text
    begin
        exit(FieldRef.GetEnumValueName(ApprovalEntry.Status.AsInteger() + 1));
    end;

    local procedure GetApprovalEntryStatusValueCaption(var FieldRef: FieldRef; ApprovalEntry: Record "Approval Entry"): Text
    begin
        exit(FieldRef.GetEnumValueCaption(ApprovalEntry.Status.AsInteger() + 1));
    end;

    procedure CleanGenJournalApprovalStatus(GenJournalLine: Record "Gen. Journal Line"; var GenJnlBatchApprovalStatus: Text[20]; var GenJnlLineApprovalStatus: Text[20])
    var
        GenJournalBatch: Record "Gen. Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        if GenJournalBatch.Get(GenJournalLine."Journal Template Name", GenJournalLine."Journal Batch Name") then
            if IsGeneralJournalBatchApprovalsWorkflowEnabled(GenJournalBatch) then
                if FindLastApprovalEntryForCurrUser(ApprovalEntry, GenJournalBatch.RecordId) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                    GenJnlBatchApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20)
                else
                    if FindApprovalEntryByRecordId(ApprovalEntry, GenJournalBatch.RecordId) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                        GenJnlBatchApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20);

        if IsGeneralJournalLineApprovalsWorkflowEnabled(GenJournalLine) then
            if FindLastApprovalEntryForCurrUser(ApprovalEntry, GenJournalLine.RecordId) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                GenJnlLineApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20)
            else
                if FindApprovalEntryByRecordId(ApprovalEntry, GenJournalLine.RecordId) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                    GenJnlLineApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20);
    end;

    internal procedure CleanItemJournalApprovalStatus(ItemJournalLine: Record "Item Journal Line"; var ItemJnlBatchApprovalStatus: Text[20])
    var
        ItemJournalBatch: Record "Item Journal Batch";
        ApprovalEntry: Record "Approval Entry";
    begin
        if ItemJournalBatch.Get(ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name") then
            if IsItemJournalBatchApprovalsWorkflowEnabled(ItemJournalBatch) then
                if FindLastApprovalEntryForCurrUser(ApprovalEntry, ItemJournalBatch.RecordId()) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                    ItemJnlBatchApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20)
                else
                    if FindApprovalEntryByRecordId(ApprovalEntry, ItemJournalBatch.RecordId) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                        ItemJnlBatchApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20);
    end;

    internal procedure CleanRequisitionWkshApprovalStatus(RequisitionLine: Record "Requisition Line"; var ReqWkshBatchApprovalStatus: Text[20])
    var
        RequisitionWkshName: Record "Requisition Wksh. Name";
        ApprovalEntry: Record "Approval Entry";
    begin
        if RequisitionWkshName.Get(RequisitionLine."Worksheet Template Name", RequisitionLine."Journal Batch Name") then
            if IsRequisitionWkshBatchApprovalsWorkflowEnabled(RequisitionWkshName) then
                if FindLastApprovalEntryForCurrUser(ApprovalEntry, RequisitionWkshName.RecordId()) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                    ReqWkshBatchApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20)
                else
                    if FindApprovalEntryByRecordId(ApprovalEntry, RequisitionWkshName.RecordId) and (ApprovalEntry.Status = ApprovalEntry.Status::Approved) then
                        ReqWkshBatchApprovalStatus := CopyStr(ImposedRestrictionLbl, 1, 20);
    end;

    local procedure FindOpenApprovalEntryForSequenceNo(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance"; SequenceNo: Integer): Boolean
    var
        ApprovalEntry: Record "Approval Entry";
    begin
        ApprovalEntry.SetRange("Table ID", RecRef.Number);
        ApprovalEntry.SetRange("Record ID to Approve", RecRef.RecordId());
        ApprovalEntry.SetRange(Status, ApprovalEntry.Status::Open);
        ApprovalEntry.SetRange("Workflow Step Instance ID", WorkflowStepInstance.ID);
        ApprovalEntry.SetRange("Sequence No.", SequenceNo);

        exit(not ApprovalEntry.IsEmpty());
    end;

    [EventSubscriber(ObjectType::Table, Database::"Job Queue Entry", 'OnBeforeScheduleTask', '', true, true)]
    local procedure SkipScheduleTaskIfWorkflowEnabledOnBeforeScheduleTask(var JobQueueEntry: Record "Job Queue Entry"; var IsHandled: Boolean; var TaskGUID: Guid)
    var
        ApprovalsMgmt: Codeunit "Approvals Mgmt.";
    begin
        if IsHandled then
            exit;

        if not TaskScheduler.CanCreateTask() then
            if ApprovalsMgmt.CheckJobQueueEntryApprovalEnabled() then
                if ApprovalsMgmt.HasApprovalEntries(JobQueueEntry.RecordId()) then begin
                    IsHandled := true;
                    clear(TaskGUID);
                end
    end;


    [IntegrationEvent(false, false)]
    local procedure OnApproveApprovalRequestsForRecordOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance"; RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCanCancelApprovalForRecord(RecID: RecordID; var Result: Boolean; var ApprovalEntry: Record "Approval Entry"; UserSetup: Record "User Setup")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCalcPurchaseDocAmount(PurchaseHeader: Record "Purchase Header"; TotalPurchaseLine: Record "Purchase Line"; TotalPurchaseLineLCY: Record "Purchase Line"; var ApprovalAmount: Decimal; var ApprovalAmountLCY: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckCustomerApprovalsWorkflowEnabled(var Customer: Record Customer; var Result: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckItemApprovalsWorkflowEnabled(var Item: Record Item; var Result: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckSalesApprovalPossible(var SalesHeader: Record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckPurchaseApprovalPossible(var PurchaseHeader: Record "Purchase Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCreateApprReqForApprTypeWorkflowUserGroup(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCreateApprReqForApprTypeSalespersPurchaser(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCreateApprReqForApprTypeApprover(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterIsSufficientApprover(UserSetup: Record "User Setup"; ApprovalEntryArgument: Record "Approval Entry"; var IsSufficient: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterDelegateApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterFindUserSetupBySalesPurchCode(var UserSetup: Record "User Setup"; ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPopulateApprovalEntryArgument(WorkflowStepInstance: Record "Workflow Step Instance"; var ApprovalEntryArgument: Record "Approval Entry"; var IsHandled: Boolean; var RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterRejectSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeApprovalEntryInsert(var ApprovalEntry: Record "Approval Entry"; ApprovalEntryArgument: Record "Approval Entry"; WorkflowStepArgument: Record "Workflow Step Argument"; ApproverId: Code[50]; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckPurchaseApprovalPossible(var PurchaseHeader: Record "Purchase Header"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateApprovalRequests(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateApprovalRequestForUser(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateApprovalRequestForApproverChain(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry"; SufficientApproverOnly: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateApprovalEntryNotification(ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean; WorkflowStepInstance: Record "Workflow Step Instance")
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnBeforeCreateApprReqForApprTypeWorkflowUserGroup(var WorkflowUserGroupMember: Record "Workflow User Group Member"; WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntry: Record "Approval Entry"; SequenceNo: Integer; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDelegateApprovalRequests(var ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckUserAsApprovalAdministrator(ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeHasOpenApprovalEntries(RecordID: RecordID; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeMakeApprovalEntry(var ApprovalEntry: Record "Approval Entry"; ApprovalEntryArgument: Record "Approval Entry"; WorkflowStepArgument: Record "Workflow Step Argument"; ApproverId: Code[50]; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePopulateApprovalEntryArgument(WorkflowStepInstance: Record "Workflow Step Instance"; var ApprovalEntryArgument: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePrePostApprovalCheckPurch(var PurchaseHeader: Record "Purchase Header"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePrePostApprovalCheckSales(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; var Result: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeRunWorkflowEntriesPage(RecordIDInput: RecordID; TableId: Integer; DocumentType: Enum "Approval Document Type"; DocumentNo: Code[20]; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSetStatusToPendingApproval(var Variant: Variant)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSetApproverType(WorkflowStepArgument: Record "Workflow Step Argument"; var ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeShowPurchApprovalStatus(var PurchaseHeader: Record "Purchase Header"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeShowSalesApprovalStatus(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsGeneralJournalBatchApprovalsWorkflowEnabled(var GenJournalBatch: Record "Gen. Journal Batch"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsGeneralJournalLineApprovalsWorkflowEnabled(var GenJournalLine: Record "Gen. Journal Line"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsItemJournalBatchApprovalsWorkflowEnabled(var ItemJournalBatch: Record "Item Journal Batch"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsRequisitionWkshBatchApprovalsWorkflowEnabled(var RequisitionWkshName: Record "Requisition Wksh. Name"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsPurchaseApprovalsWorkflowEnabled(var PurchaseHeader: Record "Purchase Header"; var Result: Boolean; var IsHandled: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsSufficientApprover(var UserSetup: Record "User Setup"; ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsSufficientSalesApprover(UserSetup: Record "User Setup"; DocumentType: Enum "Sales Document Type"; ApprovalAmountLCY: Decimal; var IsSufficient: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsSufficientPurchApprover(UserSetup: Record "User Setup"; DocumentType: Enum "Purchase Document Type"; var ApprovalAmountLCY: Decimal; var IsSufficient: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeRejectApprovalRequestsForRecord(RecRef: RecordRef; WorkflowStepInstance: Record "Workflow Step Instance"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSendApprovalRequestFromApprovalEntry(ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSetCommonApprovalCommentLineFilters(var RecRef: RecordRef; var ApprovalCommentLine: Record "Approval Comment Line"; var IsHandle: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeShowCommonApprovalStatus(var RecRef: RecordRef; var IsHandle: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSubstituteUserIdForApprovalEntry(var ApprovalEntry: Record "Approval Entry"; var IsHandle: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeRunApprovalCommentsPage(var ApprovalCommentLine: Record "Approval Comment Line"; WorkflowStepInstanceID: Guid; var IsHandle: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeTrySendJournalLineApprovalRequests(var GenJournalLine: Record "Gen. Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCancelApprovalRequestsForRecordOnAfterCreateApprovalEntryNotification(var ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance"; OldStatus: Enum "Approval Status");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCancelApprovalRequestsForRecordOnAfterSetApprovalEntryFilters(var ApprovalEntry: Record "Approval Entry"; RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprovalRequestForApproverOnAfterCheckUserSetupUserID(var UserSetup: Record "User Setup"; WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry"; var IsUserAllowedToAproveIfNoApprovalUserExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprReqForApprTypeWorkflowUserGroupOnBeforeMakeApprovalEntry(var WorkflowUserGroupMember: Record "Workflow User Group Member"; var ApprovalEntryArgument: Record "Approval Entry"; WorkflowStepArgument: Record "Workflow Step Argument"; var ApproverId: Code[50]; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprovalRequestForApproverChainOnAfterCheckApprovalEntrySenderID(var UserSetup: Record "User Setup"; WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprovalRequestForApproverChainOnAfterCheckUserSetupSenderID(var UserSetup: Record "User Setup"; WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprovalRequestForApproverChainOnBeforeCheckApproverId(var UserSetup: Record "User Setup"; WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprovalRequestForApproverChainOnAfterSetApprovalEntryFilters(var ApprovalEntry: Record "Approval Entry"; ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckPurchaseApprovalPossibleOnAfterCalcShowNothingToApproveError(var PurchaseHeader: Record "Purchase Header"; var ShowNothingToApproveError: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDelegateSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry"; var CheckCurrentUser: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDelegateSelectedApprovalRequestOnBeforeSubstituteUserIdForApprovalEntry(var ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDeleteApprovalEntriesOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnIsSufficientGenJournalLineApproverOnAfterRecRefSetTable(UserSetup: Record "User Setup"; ApprovalEntryArgument: Record "Approval Entry"; GenJournalLine: Record "Gen. Journal Line"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindOpenApprovalEntryForCurrUserOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnGetLastSequenceNoOnAfterSetApprovalEntryFilters(var ApprovalEntry: Record "Approval Entry"; ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnHasAnyOpenJournalLineApprovalEntriesOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnHasPendingApprovalEntriesForWorkflowOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnHasOpenApprovalEntriesOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostApprovalEntriesOnBeforePostedApprovalEntryInsert(var PostedApprovalEntry: Record "Posted Approval Entry"; ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostApprovalCommentLinesOnBeforePostedApprovalCommentLineInsert(var PostedApprovalCommentLine: Record "Posted Approval Comment Line"; ApprovalCommentLine: Record "Approval Comment Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRejectApprovalRequestsForRecordOnAfterCreateApprovalEntryNotification(var ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance"; OldStatus: Enum "Approval Status");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRejectApprovalRequestsForRecordOnAfterSetApprovalEntryFilters(var ApprovalEntry: Record "Approval Entry"; WorkflowStepInstance: Record "Workflow Step Instance"; RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRejectApprovalRequestsForRecordOnBeforeApprovalEntryToUpdateModify(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSendApprovalRequestFromRecordOnAfterSetApprovalEntryFilters(var ApprovalEntry: Record "Approval Entry"; RecRef: RecordRef; var IsHandled: Boolean; WorkflowStepInstance: Record "Workflow Step Instance")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSendApprovalRequestFromApprovalEntryOnAfterSetApprovalEntry2Filters(var ApprovalEntry2: Record "Approval Entry"; ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSetStatusToPendingApproval(RecRef: RecordRef; var Variant: Variant; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnShowApprovalCommentsOnAfterSetApprovalCommentLineFilters(var ApprovalCommentLine: Record "Approval Comment Line"; ApprovalEntry: Record "Approval Entry"; RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSubstituteUserIdForApprovalEntryOnAfterCheckUserSetupApprovalEntryApproverID(var UserSetup: Record "User Setup"; ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSubstituteUserIdForApprovalEntryOnBeforeAssignApproverID(ApprovalEntry: Record "Approval Entry"; var UserSetup: Record "User Setup")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTrySendJournalLineApprovalRequestsOnBeforeLoopIteration(var GenJournalLine: Record "Gen. Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetLimitType(WorkflowStepArgument: Record "Workflow Step Argument"; var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetApproverType(WorkflowStepArgument: Record "Workflow Step Argument"; var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckStatus(var ApprovalEntry: Record "Approval Entry"; ApprovalAction: Enum "Approval Action"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprovalRequestsOnElseCase(WorkflowStepArgument: Record "Workflow Step Argument"; var ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateApprovalRequestsOnAfterCreateRequests(RecRef: RecordRef; WorkflowStepArgument: Record "Workflow Step Argument"; var ApprovalEntryArgument: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnApproveApprovalRequestsForRecordOnBeforeApprovalEntryToUpdateModify(var ApprovalEntryToUpdate: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeApproveSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeRejectApprovalRequests(var ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeApproveApprovalRequests(var ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckSalesApprovalPossible(var SalesHeader: Record "Sales Header"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeFindUserSetupBySalesPurchCode(var UserSetup: Record "User Setup"; ApprovalEntryArgument: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateApprovalRequestForSalespersPurchaser(WorkflowStepArgument: Record "Workflow Step Argument"; ApprovalEntryArgument: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnHasOpenApprovalEntriesForCurrentUserOnAfterSetApprovalEntryFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeRejectSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterDelegateSelectedApprovalRequest(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostApprovalEntriesOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry"; TableNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostApprovalCommentLinesOnAfterApprovalCommentLineSetFilters(var ApprovalCommentLine: Record "Approval Comment Line"; TableNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDeleteApprovalCommentLinesOnAfterApprovalCommentLineSetFilters(var ApprovalCommentLine: Record "Approval Comment Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnHasOpenApprovalEntriesForCurrentUserOnAfterSetApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCreateApprovalRequestForApproverChain(var ApprovalEntryArgument: Record "Approval Entry"; var ApproverId: Code[50]; var WorkflowStepArgument: Record "Workflow Step Argument"; var UserSetup: Record "User Setup"; var SufficientApproverOnly: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSendApprovalRequestFromRecordOnBeforeFindApprovedApprovalEntryForWorkflowUserGroup(ApprovalEntry: Record "Approval Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCreateApprovalEntryNotification(var ApprovalEntryArgument: Record "Approval Entry"; var WorkflowStepArgument: Record "Workflow Step Argument")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindApprovalEntryForCurrUserOnAfterApprovalEntrySetFilters(var ApprovalEntry: Record "Approval Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSendJournalLinesApprovalRequests(var GenJournalLine: Record "Gen. Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCalcPurchaseDocAmountOnAfterPurchPostGetPurchLines(var TempPurchaseLine: Record "Purchase Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCalcSalesDocAmount(SalesHeader: Record "Sales Header"; TotalSalesLine: Record "Sales Line"; TotalSalesLineLCY: Record "Sales Line"; var ApprovalAmount: Decimal; var ApprovalAmountLCY: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPreventDeletingRecordWithOpenApprovalEntryElseCase(RecRef: RecordRef; Variant: Variant)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPreventInsertRecIfOpenApprovalEntryExistElseCase(RecRef: RecordRef; Variant: Variant)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindOpenApprovalEntriesForWorkflowStepInstanceOnAfterSetApprovalEntry2Filters(var ApprovalEntry2: Record "Approval Entry"; ApprovalEntry: Record "Approval Entry"; WorkflowStepInstanceRecID: RecordId)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSufficientApproverElseCase(UserSetup: Record "User Setup"; ApprovalEntryArgument: Record "Approval Entry"; var IsSufficient: Boolean)
    begin
    end;
}