Codeunit 80 Sales-Post, source in 29

Source29

src/Layers/W1/BaseApp/Sales/Posting/SalesPost.Codeunit.al14025 lines, Copyright (c) Microsoft Corporation. MIT

// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.Sales.Posting;

using Microsoft.Assembly.Document;
using Microsoft.Assembly.History;
using Microsoft.Assembly.Posting;
using Microsoft.CRM.Contact;
using Microsoft.CRM.Opportunity;
using Microsoft.CRM.Outlook;
using Microsoft.CRM.Segment;
using Microsoft.EServices.EDocument;
using Microsoft.Finance.Analysis;
using Microsoft.Finance.Currency;
using Microsoft.Finance.Deferral;
using Microsoft.Finance.Dimension;
using Microsoft.Finance.GeneralLedger.Account;
using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Ledger;
using Microsoft.Finance.GeneralLedger.Posting;
using Microsoft.Finance.GeneralLedger.Preview;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Finance.ReceivablesPayables;
using Microsoft.Finance.VAT.Calculation;
using Microsoft.Finance.VAT.Setup;
using Microsoft.FixedAssets.Depreciation;
using Microsoft.FixedAssets.FixedAsset;
using Microsoft.Foundation.AuditCodes;
using Microsoft.Foundation.BatchProcessing;
using Microsoft.Foundation.ExtendedText;
using Microsoft.Foundation.NoSeries;
using Microsoft.Foundation.Reporting;
using Microsoft.Foundation.UOM;
using Microsoft.Integration.D365Sales;
using Microsoft.Integration.Graph;
using Microsoft.Intercompany;
using Microsoft.Intercompany.GLAccount;
using Microsoft.Intercompany.Inbox;
using Microsoft.Intercompany.Outbox;
using Microsoft.Intercompany.Partner;
using Microsoft.Inventory.Analysis;
using Microsoft.Inventory.Costing;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Journal;
using Microsoft.Inventory.Ledger;
using Microsoft.Inventory.Location;
using Microsoft.Inventory.Posting;
using Microsoft.Inventory.Setup;
using Microsoft.Inventory.Tracking;
using Microsoft.Projects.Project.Archive;
using Microsoft.Projects.Project.Job;
using Microsoft.Projects.Project.Posting;
using Microsoft.Projects.Resources.Journal;
using Microsoft.Purchases.Comment;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.History;
using Microsoft.Purchases.Posting;
using Microsoft.Purchases.Setup;
using Microsoft.Purchases.Vendor;
using Microsoft.Sales.Comment;
using Microsoft.Sales.Customer;
using Microsoft.Sales.Document;
using Microsoft.Sales.History;
using Microsoft.Sales.Receivables;
using Microsoft.Sales.Setup;
using Microsoft.Utilities;
using Microsoft.Warehouse.Activity;
using Microsoft.Warehouse.Availability;
using Microsoft.Warehouse.Document;
using Microsoft.Warehouse.History;
using Microsoft.Warehouse.Journal;
using Microsoft.Warehouse.Request;
using Microsoft.Warehouse.Setup;
using System.Automation;
using System.Email;
using System.Environment.Configuration;
using System.Utilities;

/// <summary>
/// Posts sales documents by creating ledger entries for customers, items, resources, fixed assets, and the general ledger.
/// </summary>
codeunit 80 "Sales-Post"
{
    Permissions = TableData "Sales Header" = rimd,
                  TableData "Sales Line" = rimd,
                  TableData "Purchase Header" = rm,
                  TableData "Purchase Line" = rm,
                  TableData "Sales Shipment Header" = rimd,
                  TableData "Sales Shipment Line" = rimd,
                  TableData "Sales Invoice Header" = rimd,
                  TableData "Sales Invoice Line" = rimd,
                  TableData "Sales Cr.Memo Header" = rimd,
                  TableData "Sales Cr.Memo Line" = rimd,
                  TableData "Purch. Rcpt. Header" = rimd,
                  TableData "Purch. Rcpt. Line" = rimd,
                  TableData "Drop Shpt. Post. Buffer" = rimd,
                  TableData "General Posting Setup" = rimd,
                  TableData "Posted Assemble-to-Order Link" = ri,
                  TableData "Item Entry Relation" = ri,
                  TableData "Value Entry Relation" = rid,
                  TableData "Return Receipt Header" = rimd,
                  TableData "Return Receipt Line" = rimd,
                  TableData "G/L Entry" = r,
                  Tabledata Job = r;
    TableNo = "Sales Header";
    EventSubscriberInstance = Manual;

    trigger OnRun()
    begin
        RunWithCheck(Rec);
    end;

    var
#pragma warning disable AA0470
        PostingLinesMsg: Label 'Posting lines              #2######\', Comment = 'Counter';
        PostingSalesAndVATMsg: Label 'Posting sales and VAT      #3######\', Comment = 'Counter';
        PostingCustomersMsg: Label 'Posting to customers       #4######\', Comment = 'Counter';
        PostingBalAccountMsg: Label 'Posting to bal. account    #5######', Comment = 'Counter';
        PostingLines2Msg: Label 'Posting lines              #2######', Comment = 'Counter';
#pragma warning restore AA0470
        InvoiceNoMsg: Label '%1 %2 -> Invoice %3', Comment = '%1 = Document Type, %2 = Document No, %3 = Invoice No.';
        CreditMemoNoMsg: Label '%1 %2 -> Credit Memo %3', Comment = '%1 = Document Type, %2 = Document No, %3 = Credit Memo No.';
        DropShipmentErr: Label 'You cannot ship sales order line %1. The line is marked as a drop shipment and is not yet associated with a purchase order.', Comment = '%1 = Line No.';
        ShipmentSameSignErr: Label 'must have the same sign as the shipment';
        ShipmentLinesDeletedErr: Label 'The shipment lines have been deleted.';
        InvoiceMoreThanShippedErr: Label 'You cannot invoice more than you have shipped for order %1.', Comment = '%1 = Order No.';
        VATAmountTxt: Label 'VAT Amount';
        VATRateTxt: Label '%1% VAT', Comment = '%1 = VAT Rate';
        BlanketOrderQuantityGreaterThanErr: Label 'in the associated blanket order must not be greater than %1', Comment = '%1 = Quantity';
        BlanketOrderQuantityReducedErr: Label 'in the associated blanket order must not be reduced';
        ShipInvoiceReceiveErr: Label 'Please enter "Yes" in Ship and/or Invoice and/or Receive.';
        WarehouseRequiredErr: Label 'Warehouse handling is required for %1 = %2, %3 = %4, %5 = %6.', Comment = '%1/%2 = Document Type, %3/%4 - Document No.,%5/%6 = Line No.';
        ReturnReceiptSameSignErr: Label 'must have the same sign as the return receipt';
        ReturnReceiptInvoicedErr: Label 'Line %1 of the return receipt %2, which you are attempting to invoice, has already been invoiced.', Comment = '%1 = Line No., %2 = Document No.';
        ShipmentInvoiceErr: Label 'Line %1 of the shipment %2, which you are attempting to invoice, has already been invoiced.', Comment = '%1 = Line No., %2 = Document No.';
        QuantityToInvoiceGreaterErr: Label 'The quantity you are attempting to invoice is greater than the quantity in shipment %1.', Comment = '%1 = Document No.';
        CannotAssignMoreErr: Label 'You cannot assign more than %1 units in %2 = %3, %4 = %5,%6 = %7.', Comment = '%1 = Quantity, %2/%3 = Document Type, %4/%5 - Document No.,%6/%7 = Line No.';
        MustAssignErr: Label 'You must assign all item charges, if you invoice everything.';
        Item: Record Item;
        SalesSetup: Record "Sales & Receivables Setup";
        GLSetup: Record "General Ledger Setup";
        [SecurityFiltering(SecurityFilter::Ignored)]
        GLEntry: Record "G/L Entry";
        TempSalesLineGlobal: Record "Sales Line" temporary;
        xSalesLine: Record "Sales Line";
        SalesLineACY: Record "Sales Line";
        TotalSalesLine: Record "Sales Line";
        TotalSalesLineLCY: Record "Sales Line";
        SalesShptHeader: Record "Sales Shipment Header";
        SalesInvHeader: Record "Sales Invoice Header";
        SalesCrMemoHeader: Record "Sales Cr.Memo Header";
        ReturnRcptHeader: Record "Return Receipt Header";
        PurchRcptHeader: Record "Purch. Rcpt. Header";
        ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)";
        TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary;
        InvoicePostingParameters: Record "Invoice Posting Parameters";
        SourceCodeSetup: Record "Source Code Setup";
        Currency: Record Currency;
        CurrExchRate: Record "Currency Exchange Rate";
        WhseRcptHeader: Record "Warehouse Receipt Header";
        TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary;
        WhseShptHeader: Record "Warehouse Shipment Header";
        TempWhseShptHeader: Record "Warehouse Shipment Header" temporary;
        PostedWhseRcptHeader: Record "Posted Whse. Receipt Header";
        PostedWhseRcptLine: Record "Posted Whse. Receipt Line";
        PostedWhseShptHeader: Record "Posted Whse. Shipment Header";
        PostedWhseShptLine: Record "Posted Whse. Shipment Line";
        Location: Record Location;
        TempHandlingSpecification: Record "Tracking Specification" temporary;
        TempATOTrackingSpecification: Record "Tracking Specification" temporary;
        TempTrackingSpecification: Record "Tracking Specification" temporary;
        TempTrackingSpecificationInv: Record "Tracking Specification" temporary;
        TempWhseSplitSpecification: Record "Tracking Specification" temporary;
        TempValueEntryRelation: Record "Value Entry Relation" temporary;
        JobTaskSalesLine: Record "Sales Line";
        TempICGenJnlLine: Record "Gen. Journal Line" temporary;
        TempPrepmtDeductLCYSalesLine: Record "Sales Line" temporary;
        TempSKU: Record "Stockkeeping Unit" temporary;
        TempDeferralHeader: Record "Deferral Header" temporary;
        TempDeferralLine: Record "Deferral Line" temporary;
        ErrorMessageMgt: Codeunit "Error Message Management";
        GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line";
        ResJnlPostLine: Codeunit "Res. Jnl.-Post Line";
        ItemJnlPostLine: Codeunit "Item Jnl.-Post Line";
        SalesLineReserve: Codeunit "Sales Line-Reserve";
        ApprovalsMgmt: Codeunit "Approvals Mgmt.";
        ItemTrackingMgt: Codeunit "Item Tracking Management";
        WhseJnlPostLine: Codeunit "Whse. Jnl.-Register Line";
        WhsePostRcpt: Codeunit "Whse.-Post Receipt";
        WhsePostShpt: Codeunit "Whse.-Post Shipment";
        PurchPost: Codeunit "Purch.-Post";
        CostCalcMgt: Codeunit "Cost Calculation Management";
        JobPostLine: Codeunit "Job Post-Line";
        DocumentErrorsMgt: Codeunit "Document Errors Mgt.";
        AsmPost: Codeunit "Assembly-Post";
        DeferralUtilities: Codeunit "Deferral Utilities";
        UOMMgt: Codeunit "Unit of Measure Management";
        ApplicationAreaMgmt: Codeunit "Application Area Mgmt.";
        InvoicePostingInterface: Interface "Invoice Posting";
        IsInterfaceInitalized: Boolean;
        Window: Dialog;
        GenJnlLineDocNo: Code[20];
        GenJnlLineExtDocNo: Code[35];
        SrcCode: Code[10];
        GenJnlLineDocType: Enum "Gen. Journal Document Type";
        ItemLedgShptEntryNo: Integer;
        RoundingLineNo: Integer;
        RemQtyToBeInvoiced: Decimal;
        RemQtyToBeInvoicedBase: Decimal;
        RemAmt: Decimal;
        RemDiscAmt: Decimal;
        TotalChargeAmt: Decimal;
        TotalChargeAmtLCY: Decimal;
        RoundedPrevTotalChargeAmt: Decimal;
        PreciseTotalChargeAmt: Decimal;
        LastLineRetrieved: Boolean;
        RoundingLineInserted: Boolean;
        DropShipOrder: Boolean;
        DocumentIsReadyToBeChecked: Boolean;
        PostponedValueEntries: List of [Integer];
        ItemsToAdjust: List of [Code[20]];
        CannotAssignInvoicedErr: Label 'You cannot assign item charges to the %1 %2 = %3,%4 = %5, %6 = %7, because it has been invoiced.', Comment = '%1 = Sales Line, %2/%3 = Document Type, %4/%5 - Document No.,%6/%7 = Line No.';
        InvoiceMoreThanReceivedErr: Label 'You cannot invoice more than you have received for return order %1.', Comment = '%1 = Order No.';
        ReturnReceiptLinesDeletedErr: Label 'The return receipt lines have been deleted.';
        InvoiceGreaterThanReturnReceiptErr: Label 'The quantity you are attempting to invoice is greater than the quantity in return receipt %1.', Comment = '%1 = Receipt No.';
        ItemJnlRollRndg: Boolean;
        RelatedItemLedgEntriesNotFoundErr: Label 'Related item ledger entries cannot be found.';
        ItemTrackingWrongSignErr: Label 'Item Tracking is signed wrongly.';
        ItemTrackingMismatchErr: Label 'Item Tracking does not match.';
        WhseShip: Boolean;
        WhseReceive: Boolean;
        InvtPickPutaway: Boolean;
        PostingDateNotAllowedErr: Label '%1 is not within your range of allowed posting dates.', Comment = '%1 - Posting Date field caption';
        ItemTrackQuantityMismatchErr: Label 'The %1 does not match the quantity defined in item tracking for item %2.', Comment = '%1 = Quantity, %2 = Item No.';
        CannotBeGreaterThanErr: Label 'cannot be more than %1.', Comment = '%1 = Amount';
        CannotBeSmallerThanErr: Label 'must be at least %1.', Comment = '%1 = Amount';
        JobContractLine: Boolean;
        GLSetupRead: Boolean;
        SalesSetupRead: Boolean;
        ItemTrkgAlreadyOverruled: Boolean;
        LogErrorMode: Boolean;
        PrepAmountToDeductToBigErr: Label 'The total %1 cannot be more than %2.', Comment = '%1 = Prepmt Amt to Deduct, %2 = Max Amount';
        PrepAmountToDeductToSmallErr: Label 'The total %1 must be at least %2.', Comment = '%1 = Prepmt Amt to Deduct, %2 = Max Amount';
        MustAssignItemChargeErr: Label 'You must assign item charge %1 if you want to invoice it.', Comment = '%1 = Item Charge No.';
        CannotInvoiceItemChargeErr: Label 'You can not invoice item charge %1 because there is no item ledger entry to assign it to.', Comment = '%1 = Item Charge No.';
        SalesLinesProcessed: Boolean;
        AssemblyCheckProgressMsg: Label '#1#################################\\Checking Assembly #2###########', Comment = '%1 = Text, %2 = Progress bar';
        AssemblyPostProgressMsg: Label '#1#################################\\Posting Assembly #2###########', Comment = '%1 = Text, %2 = Progress bar';
        AssemblyFinalizeProgressMsg: Label '#1#################################\\Finalizing Assembly #2###########', Comment = '%1 = Text, %2 = Progress bar';
        ReassignItemChargeErr: Label 'The order line that the item charge was originally assigned to has been fully posted. You must reassign the item charge to the posted receipt or shipment.';
#pragma warning disable AA0470
        ReservationDisruptedQst: Label 'One or more reservation entries exist for the item with %1 = %2, %3 = %4, %5 = %6 which may be disrupted if you post this negative adjustment. Do you want to continue?', Comment = 'One or more reservation entries exist for the item with No. = 1000, Location Code = SILVER, Variant Code = NEW which may be disrupted if you post this negative adjustment. Do you want to continue?';
#pragma warning restore AA0470
        NotSupportedDocumentTypeErr: Label 'Document type %1 is not supported.', Comment = '%1 = Document Type';
        CalledBy: Integer;
        PreviewMode: Boolean;
        TotalInvoiceAmountNegativeErr: Label 'The total amount for the invoice must be 0 or greater.';
        SendShipmentAlsoQst: Label 'You can take the same actions for the related Sales - Shipment document.\\Do you want to do that now?';
        SuppressCommit: Boolean;
        PostingPreviewNoTok: Label '***', Locked = true;
        PostingPreviewNoFormatTxt: Label '<Integer,6><Filler Character,0>', Comment = 'Previewed document numbers are displayed in the format ***000000', Locked = true;
        InvPickExistsErr: Label 'One or more related inventory picks must be registered before you can post the shipment.';
        InvPutAwayExistsErr: Label 'One or more related inventory put-aways must be registered before you can post the receipt.';
        CheckSalesHeaderMsg: Label 'Check sales document fields.';
        CheckSalesLineMsg: Label 'Check sales document line.';
        PostDocumentLinesMsg: Label 'Post document lines.';
        HideProgressWindow: Boolean;
        OrderArchived: Boolean;
        SetupBlockedErr: Label 'Setup is blocked in %1 for %2 %3 and %4 %5.', Comment = '%1 - General/VAT Posting Setup, %2 %3 %4 %5 - posting groups.';
        SalesReturnRcptHeaderConflictErr: Label 'Cannot post the sales return because its ID, %1, is already assigned to a record. Update the number series and try again.', Comment = '%1 = Return Receipt No.';
        SalesShptHeaderConflictErr: Label 'Cannot post the sales shipment because its ID, %1, is already assigned to a record. Update the number series and try again.', Comment = '%1 = Shipping No.';
        SalesInvHeaderConflictErr: Label 'Cannot post the sales invoice because its ID, %1, is already assigned to a record. Update the number series and try again.', Comment = '%1 = Posting No.';
        SalesCrMemoHeaderConflictErr: Label 'Cannot post the sales credit memo because its ID, %1, is already assigned to a record. Update the number series and try again.', Comment = '%1 = Posting No.';
        SalesLinePostCategoryTok: Label 'Sales Line Post', Locked = true;
        SameIdFoundLbl: Label 'Same line id found.', Locked = true;
        EmptyIdFoundLbl: Label 'Empty line id found.', Locked = true;
        ItemReservDisruptionLbl: Label 'Confirm Item Reservation Disruption', Locked = true;
        ItemChargeZeroAmountErr: Label 'The amount for item charge %1 cannot be 0.', Comment = '%1 = Item Charge No.';
        SuppressCommitErr: Label 'Commit is blocked when %1 %2 is used.', Comment = '%1 = Date Order, %2 = Number Series';
        DateOrderSeriesUsed: Boolean;

    /// <summary>
    /// Verifies and posts the sales document.
    /// As a result, posted documents will be created, dependent on the type of the document, as well as any relevant posting to inventory and finance.
    /// A Quote cannot be posted - it has to be turned into an order or invoice first, which then can be posted.
    /// An Order can be shipped and/or invoiced.
    /// A Return order can be received and/or invoiced.
    /// An Invoice and a Credit memo can be invoiced.
    /// Any document, except quote, can be partly shipped/received/invoiced.
    /// </summary>
    /// <param name="SalesHeader2">The sales header of the document that is being posted.</param>
    internal procedure RunWithCheck(var SalesHeader2: Record "Sales Header")
    var
        SalesHeader: Record "Sales Header";
        CustLedgEntry: Record "Cust. Ledger Entry";
        TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary;
        DisableAggregateTableUpdate: Codeunit "Disable Aggregate Table Update";
        UpdateAnalysisView: Codeunit "Update Analysis View";
        UpdateItemAnalysisView: Codeunit "Update Item Analysis View";
        SequenceNoMgt: Codeunit "Sequence No. Mgt.";
        EverythingInvoiced: Boolean;
        SavedPreviewMode: Boolean;
        SavedSuppressCommit: Boolean;
        SavedCalledBy: Integer;
        SavedHideProgressWindow: Boolean;
        IsHandled: Boolean;
    begin
        SequenceNoMgt.SetPreviewMode(PreviewMode);
        IsHandled := false;
        OnBeforePostSalesDoc(SalesHeader2, SuppressCommit, PreviewMode, HideProgressWindow, IsHandled, CalledBy);
        if IsHandled then
            exit;

        GetSalesHeader(SalesHeader2);

        if not GuiAllowed() then
            LockTimeout(false);

        SetupDisableAggregateTableUpdate(SalesHeader2, DisableAggregateTableUpdate);

        ValidatePostingAndDocumentDate(SalesHeader2);

        SavedPreviewMode := PreviewMode;
        SavedSuppressCommit := SuppressCommit;
        SavedHideProgressWindow := HideProgressWindow;
        SavedCalledBy := CalledBy;
        ClearAllVariables();
        SuppressCommit := SavedSuppressCommit;
        PreviewMode := SavedPreviewMode;
        HideProgressWindow := SavedHideProgressWindow;
        CalledBy := SavedCalledBy;

        GetGLSetup();
        GetSalesSetup();
        GetInvoicePostingSetup();
        GetCurrency(SalesHeader2."Currency Code");

        SalesHeader := SalesHeader2;
        OnCodeOnBeforeFillTempLines(SalesHeader, CalledBy);
        FillTempLines(SalesHeader, TempSalesLineGlobal);

        // Check that the invoice amount is zero or greater
        OnRunOnBeforeCheckTotalInvoiceAmount(SalesHeader, TempSalesLineGlobal);
        if SalesHeader.Invoice then
            CheckTotalInvoiceAmount(SalesHeader);

        OnRunOnBeforeCheckAndUpdate(SalesHeader);
        // Header
        CheckAndUpdate(SalesHeader);

        ProcessPosting(SalesHeader, SalesHeader2, TempDropShptPostBuffer, CustLedgEntry, EverythingInvoiced);

        UpdateLastPostingNos(SalesHeader);

        OnRunOnBeforeFinalizePosting(
          SalesHeader, SalesShptHeader, SalesInvHeader, SalesCrMemoHeader, ReturnRcptHeader, GenJnlPostLine, SuppressCommit,
          GenJnlLineExtDocNo, EverythingInvoiced, GenJnlLineDocNo, SrcCode, PreviewMode);

        if not (SalesHeader."Document Type" in [SalesHeader."Document Type"::Invoice, SalesHeader."Document Type"::"Credit Memo"]) then
            EnableAggregateTableUpdate(DisableAggregateTableUpdate);

        FinalizePosting(SalesHeader, EverythingInvoiced, TempDropShptPostBuffer);

        SalesHeader2 := SalesHeader;

        OnRunWithCheckOnAfterFinalize(SalesHeader);

        // Date-ordered No. Series require that number allocation and the posted document are in the same
        // transaction to prevent gaps. At this point FinalizePosting has completed, so both the allocated
        // number and the posted document exist in the current transaction — committing is safe.
        // Restore SuppressCommit to the caller's original value so that the date-order guard
        // no longer blocks the final commit.
        if DateOrderSeriesUsed and SuppressCommit then
            SuppressCommit := SavedSuppressCommit;

        if not (InvtPickPutaway or SuppressCommit or PreviewMode) then begin
            Commit();
            UpdateAnalysisView.UpdateAll(0, true);
            UpdateItemAnalysisView.UpdateAll(0, true);
        end;

        OnAfterPostSalesDoc(
          SalesHeader2, GenJnlPostLine, SalesShptHeader."No.", ReturnRcptHeader."No.",
          SalesInvHeader."No.", SalesCrMemoHeader."No.", SuppressCommit, InvtPickPutaway,
          CustLedgEntry, WhseShip, WhseReceive, PreviewMode);

        OnAfterPostSalesDocDropShipment(PurchRcptHeader."No.", SuppressCommit);
    end;

    /// <summary>
    /// A wrapper function to delegate to either a function that allows commit or a function that ignores commit
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesHeader2">An unmodified copy of the sales header.</param>
    /// <param name="TempDropShptPostBuffer">An internal temp table holding drop shipment information.</param>
    /// <param name="CustLedgEntry">The customer ledger entry we are creating (='the invoice').</param>
    /// <param name="EverythingInvoiced">A flag telling whether it was a partial invoice and something is still left.</param>
    local procedure ProcessPosting(var SalesHeader: Record "Sales Header"; var SalesHeader2: Record "Sales Header";
                                   var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary;
                                   var CustLedgEntry: Record "Cust. Ledger Entry";
                                   var EverythingInvoiced: Boolean)
    var
        IgnoreCommit: Boolean;
    begin
        IgnoreCommit := true;
        OnSetCommitBehavior(IgnoreCommit);

        if IgnoreCommit then
            ProcessPostingLinesCommitBehaviorIgnore(
                SalesHeader, SalesHeader2, TempDropShptPostBuffer, CustLedgEntry, EverythingInvoiced)
        else
            ProcessPostingLines(
                SalesHeader, SalesHeader2, TempDropShptPostBuffer, CustLedgEntry, EverythingInvoiced);
    end;

    /// <summary>
    /// A wrapper function to delegate to the ProcessPostingLines function in order to ignore commits
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesHeader2">An unmodified copy of the sales header.</param>
    /// <param name="TempDropShptPostBuffer">An internal temp table holding drop shipment information.</param>
    /// <param name="CustLedgEntry">The customer ledger entry we are creating (='the invoice').</param>
    /// <param name="EverythingInvoiced">A flag telling whether it was a partial invoice and something is still left.</param>
    [CommitBehavior(CommitBehavior::Ignore)]
    local procedure ProcessPostingLinesCommitBehaviorIgnore(var SalesHeader: Record "Sales Header"; var SalesHeader2: Record "Sales Header";
                                   var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary;
                                   var CustLedgEntry: Record "Cust. Ledger Entry";
                                   var EverythingInvoiced: Boolean)
    begin
        ProcessPostingLines(SalesHeader, SalesHeader2, TempDropShptPostBuffer, CustLedgEntry, EverythingInvoiced);
    end;

    /// <summary>
    /// The main function that processes the document lines.
    /// Will update inventory, finance, resources, jobs, etc., dependent on what lines are in the document.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesHeader2">An unmodified copy of the sales header.</param>
    /// <param name="TempDropShptPostBuffer">An internal temp table holding drop shipment information.</param>
    /// <param name="CustLedgEntry">The customer ledger entry we are creating (='the invoice').</param>
    /// <param name="EverythingInvoiced">A flag telling whether it was a partial invoice and something is still left.</param>
    local procedure ProcessPostingLines(var SalesHeader: Record "Sales Header"; var SalesHeader2: Record "Sales Header";
                                   var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary;
                                   var CustLedgEntry: Record "Cust. Ledger Entry";
                                   var EverythingInvoiced: Boolean)
    var
        TempItemLedgEntryNotInvoiced: Record "Item Ledger Entry" temporary;
        TempVATAmountLine: Record "VAT Amount Line" temporary;
        TempVATAmountLineRemainder: Record "VAT Amount Line" temporary;
        InventorySetup: Record "Inventory Setup";
        ErrorContextElementProcessLines: Codeunit "Error Context Element";
        ErrorContextElementPostLine: Codeunit "Error Context Element";
        ZeroSalesLineRecID: RecordId;
        ICGenJnlLineNo: Integer;
        LineCount: Integer;
        BiggestLineNo: Integer;
        HasATOShippedNotInvoiced: Boolean;
        SkipInventoryAdjustment: Boolean;
        IsHandled: Boolean;
    begin
        InvoicePostingInterface.ClearBuffers();

        TempDropShptPostBuffer.DeleteAll();
        EverythingInvoiced := true;

        // Lines
        GetZeroSalesLineRecID(SalesHeader, ZeroSalesLineRecID);
        ErrorMessageMgt.PushContext(ErrorContextElementProcessLines, ZeroSalesLineRecID, 0, PostDocumentLinesMsg);
        OnBeforePostLines(TempSalesLineGlobal, SalesHeader, SuppressCommit, PreviewMode, TempWhseShptHeader, ItemJnlPostLine, TempWhseRcptHeader);

        LineCount := 0;
        RoundingLineInserted := false;
        AdjustFinalInvWith100PctPrepmt(TempSalesLineGlobal);

        TempVATAmountLineRemainder.DeleteAll();
        IsHandled := false;
        OnRunOnBeforeCalcVATAmountLines(TempSalesLineGlobal, SalesHeader, TempVATAmountLine, IsHandled);
        if not IsHandled then
            TempSalesLineGlobal.CalcVATAmountLines(1, SalesHeader, TempSalesLineGlobal, TempVATAmountLine);

        OnBeforePostSalesLines(SalesHeader, TempSalesLineGlobal, TempVATAmountLine, EverythingInvoiced);

        Clear(PostponedValueEntries);
        BindSubscription(this); // Start collect value entries for GLPosting

        SalesLinesProcessed := false;
        if not InventorySetup.UseLegacyPosting() then
            TempSalesLineGlobal.SetCurrentKey(Type, "Line No.");
        if TempSalesLineGlobal.FindSet() then
            repeat
                ErrorMessageMgt.PushContext(ErrorContextElementPostLine, TempSalesLineGlobal.RecordId, 0, PostDocumentLinesMsg);
                ItemJnlRollRndg := false;
                LineCount := LineCount + 1;
                if GuiAllowed() and not HideProgressWindow then
                    Window.Update(2, LineCount);

                PostSalesLine(
                  SalesHeader, TempSalesLineGlobal, EverythingInvoiced, TempVATAmountLine, TempVATAmountLineRemainder,
                  TempItemLedgEntryNotInvoiced, HasATOShippedNotInvoiced, TempDropShptPostBuffer, ICGenJnlLineNo);

                UpdateInvoiceRounding(SalesHeader, BiggestLineNo);

                OnRunOnBeforePostSalesLineEndLoop(
                    SalesHeader, TempSalesLineGlobal, LastLineRetrieved, SalesInvHeader, SalesCrMemoHeader, SalesHeader2, xSalesLine, SalesShptHeader, ReturnRcptHeader);
                ErrorMessageMgt.PopContext(ErrorContextElementPostLine);
            until LastLineRetrieved;
        TempSalesLineGlobal.SetCurrentKey("Document Type", "Document No.", "Line No.");

        UnBindSubscription(this); // Stop collecting value entries for GLPosting
        ItemJnlPostLine.PostDeferredValueEntriesToGL(PostponedValueEntries);

        OnAfterPostSalesLines(
          SalesHeader, SalesShptHeader, SalesInvHeader, SalesCrMemoHeader, ReturnRcptHeader, WhseShip, WhseReceive, SalesLinesProcessed,
          SuppressCommit, EverythingInvoiced, TempSalesLineGlobal);
        ErrorMessageMgt.PopContext(ErrorContextElementProcessLines);
        ErrorMessageMgt.Finish(ZeroSalesLineRecID);

        SendICDocument(SalesHeader);
        UpdateHandledICInboxTransaction(SalesHeader);

        if not SalesHeader.IsCreditDocType() then begin
            ReverseAmount(TotalSalesLine);
            ReverseAmount(TotalSalesLineLCY);
            TotalSalesLineLCY."Unit Cost (LCY)" := -TotalSalesLineLCY."Unit Cost (LCY)";
        end;

        OnProcessPostingLinesOnBeforePostDropOrderShipment(SalesHeader, TotalSalesLine, TotalSalesLineLCY);
        PostDropOrderShipment(SalesHeader, TempDropShptPostBuffer);
        if SalesHeader.Invoice then
            PostInvoice(SalesHeader, CustLedgEntry);

        OnRunOnBeforePostICGenJnl(SalesHeader, SalesInvHeader, SalesCrMemoHeader, GenJnlPostLine, SrcCode, GenJnlLineDocType, GenJnlLineDocNo, ReturnRcptHeader, PreviewMode);

        if ICGenJnlLineNo > 0 then
            PostICGenJnl();

        SkipInventoryAdjustment := false;
        OnRunOnBeforeMakeInventoryAdjustment(SalesHeader, SalesInvHeader, GenJnlPostLine, ItemJnlPostLine, PreviewMode, SkipInventoryAdjustment);
        if not SkipInventoryAdjustment then
            MakeInventoryAdjustment();
    end;

    /// <summary>
    /// Generates a record id for an 'empty' line
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLineRecID">Return value: The record ID of the 'empty' line.</param>
    local procedure GetZeroSalesLineRecID(SalesHeader: Record "Sales Header"; var SalesLineRecID: RecordId)
    var
        ZeroSalesLine: Record "Sales Line";
    begin
        ZeroSalesLine."Document Type" := SalesHeader."Document Type";
        ZeroSalesLine."Document No." := SalesHeader."No.";
        ZeroSalesLine."Line No." := 0;
        SalesLineRecID := ZeroSalesLine.RecordId;
    end;

    /// <summary>
    /// Copies all the sales lines to a temporary table to speed up later processing
    /// </summary>
    /// <remarks>
    /// If the item charge exists for an item in sales sine, then gen. prod. posting group of item charge is copied to the sales line.
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="TempSalesLine">Return value: The temp table that holds a copy of all sales lines.</param>
    procedure CopyToTempLines(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    var
        SalesLine: Record "Sales Line";
    begin
        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        OnCopyToTempLinesOnAfterSetFilters(SalesLine, SalesHeader);
        if SalesLine.FindSet() then
            repeat
                UpdateChargeItemSalesLineGenProdPostingGroup(SalesLine);
                TempSalesLine := SalesLine;
                TempSalesLine.Insert();
            until SalesLine.Next() = 0;

        OnAfterCopyToTempLines(TempSalesLine, SalesHeader);
    end;

    /// <summary>
    /// Copies all the sales lines to a temporary table, if they haven't been copied yet, to speed up later processing
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="TempSalesLine">Return value: The temp table that holds a copy of all sales lines.</param>
    procedure FillTempLines(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
        TempSalesLine.Reset();
        if TempSalesLine.IsEmpty() then
            CopyToTempLines(SalesHeader, TempSalesLine);
    end;

    local procedure SetupDisableAggregateTableUpdate(var SalesHeader: Record "Sales Header"; var DisableAggregateTableUpdate: Codeunit "Disable Aggregate Table Update")
    var
        AggregateTableID: Integer;
    begin
        AggregateTableID := DisableAggregateTableUpdate.GetAggregateTableIDFromSalesHeader(SalesHeader);
        if not (AggregateTableID > 0) then
            exit;

        DisableAggregateTableUpdate.SetAggregateTableIDDisabled(AggregateTableID);
        DisableAggregateTableUpdate.SetTableSystemIDDisabled(SalesHeader.SystemId);
        BindSubscription(DisableAggregateTableUpdate);
    end;

    local procedure EnableAggregateTableUpdate(var DisableAggregateTableUpdate: Codeunit "Disable Aggregate Table Update")
    begin
        if UnbindSubscription(DisableAggregateTableUpdate) then;
    end;

    local procedure ModifyTempLine(var TempSalesLineLocal: Record "Sales Line" temporary)
    var
        SalesLine: Record "Sales Line";
    begin
        TempSalesLineLocal.Modify();
        SalesLine.Get(TempSalesLineLocal.RecordId);
        OnModifyTempLineOnBeforeTransferFields(SalesLine, TempSalesLineLocal);
        SalesLine.TransferFields(TempSalesLineLocal, false);
        OnModifyTempLineOnBeforeSalesLineModify(SalesLine);
        SalesLine.Modify();
        OnModifyTempLineOnAfterSalesLineModify(SalesLine);
    end;

    /// <summary>
    /// Deletes the sales line from the temp table and copies them again to account for any changes done to the document lines as part of the posting process
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="TempSalesLine">Return value: The temp table that holds a fresh copy of all sales lines.</param>
    procedure RefreshTempLines(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
        TempSalesLine.Reset();
        TempSalesLine.SetRange("Prepayment Line", false);
        TempSalesLine.DeleteAll();
        TempSalesLine.Reset();
        CopyToTempLines(SalesHeader, TempSalesLine);
    end;

    /// <summary>
    /// Removes any filters on the temp sales line and copies the values from the global temp sales line to the local temp sales line
    /// </summary>
    /// <param name="TempSalesLineLocal">Return value: The local temp table that holds a copy of all sales lines.</param>
    procedure ResetTempLines(var TempSalesLineLocal: Record "Sales Line" temporary)
    begin
        TempSalesLineLocal.Reset();
        TempSalesLineLocal.Copy(TempSalesLineGlobal, true);
        OnAfterResetTempLines(TempSalesLineLocal);
    end;

    /// <summary>
    /// Checks if a new invoice should be created for the document
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <returns>True if a new invoice should be created, false otherwise.</returns>
    local procedure CalcInvoice(SalesHeader: Record "Sales Header") NewInvoice: Boolean
    var
        TempSalesLine: Record "Sales Line" temporary;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCalcInvoice(SalesHeader, TempSalesLineGlobal, NewInvoice, IsHandled);
        if IsHandled then
            exit(NewInvoice);

        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter(Quantity, '<>0');
        if SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::"Return Order"] then
            TempSalesLine.SetFilter("Qty. to Invoice", '<>0');
        OnCalcInvoiceOnAfterTempSalesLineSetFilters(SalesHeader, TempSalesLine);
        NewInvoice := not TempSalesLine.IsEmpty();
        if NewInvoice then
            case SalesHeader."Document Type" of
                SalesHeader."Document Type"::Order:
                    if not SalesHeader.Ship then begin
                        TempSalesLine.SetFilter("Qty. Shipped Not Invoiced", '<>0');
                        NewInvoice := not TempSalesLine.IsEmpty();
                    end;
                SalesHeader."Document Type"::"Return Order":
                    if not SalesHeader.Receive then begin
                        TempSalesLine.SetFilter("Return Qty. Rcd. Not Invd.", '<>0');
                        NewInvoice := not TempSalesLine.IsEmpty();
                    end;
            end;
        OnAfterCalcInvoice(TempSalesLine, NewInvoice, SalesHeader);
        exit(NewInvoice);
    end;

    /// <summary>
    /// Calculates the invoice discount for the document and updates the document and lines accordingly
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    local procedure CalcInvDiscount(var SalesHeader: Record "Sales Header")
    var
        SalesHeaderCopy: Record "Sales Header";
        SalesLine: Record "Sales Line";
    begin
        if not (SalesSetup."Calc. Inv. Discount" and (SalesHeader.Status <> SalesHeader.Status::Open)) then
            exit;

        SalesHeaderCopy := SalesHeader;
        SalesLine.Reset();
        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        OnCalcInvDiscountSetFilter(SalesLine, SalesHeader);
        SalesLine.FindFirst();
        CODEUNIT.Run(CODEUNIT::"Sales-Calc. Discount", SalesLine);
        RefreshTempLines(SalesHeader, TempSalesLineGlobal);
        SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
        RestoreSalesHeader(SalesHeader, SalesHeaderCopy);
        if not (PreviewMode or SuppressCommit) then
            Commit();
    end;

    /// <summary>
    /// Restores postings flags and posting numbers of the document header to their original values.
    /// </summary>
    /// <param name="SalesHeader">Return value: The sales header of the document with the restored values.</param>
    /// <param name="SalesHeaderCopy">The sales header of the document with the original values.</param>
    local procedure RestoreSalesHeader(var SalesHeader: Record "Sales Header"; SalesHeaderCopy: Record "Sales Header")
    begin
        SalesHeader.Invoice := SalesHeaderCopy.Invoice;
        SalesHeader.Receive := SalesHeaderCopy.Receive;
        SalesHeader.Ship := SalesHeaderCopy.Ship;
        SalesHeader."Posting No." := SalesHeaderCopy."Posting No.";
        SalesHeader."Shipping No." := SalesHeaderCopy."Shipping No.";
        SalesHeader."Return Receipt No." := SalesHeaderCopy."Return Receipt No.";

        OnAfterRestoreSalesHeader(SalesHeader, SalesHeaderCopy);
    end;

    /// <summary>
    /// Checks if document header and lines are valid for posting, updates the document and lines and creates posted documents.
    /// Prepayment lines are created for documents that are invoiced.
    /// Unposted document is archived
    /// </summary>
    /// <remarks>
    /// Transaction is commited after updating the document header if posting is not in PreviewMode
    /// Several related tables are locked for update after this procedure.
    /// DocumentIsReadyToBeChecked is set to true, so that PrepareCheckDocument() is not called again in CheckSalesDocument(). Preparation already happened in RunWithCheck() (parent function).
    /// </remarks>
    /// <param name="SalesHeader">Return value: The sales header of the document that is being posted, returned with updated values.</param>
    local procedure CheckAndUpdate(var SalesHeader: Record "Sales Header")
    var
        DummyNoSeries: Record "No. Series";
        ModifyHeader: Boolean;
        RefreshTempLinesNeeded: Boolean;
    begin
        OnBeforeCheckAndUpdate(SalesHeader, ModifyHeader);

        DocumentIsReadyToBeChecked := true; // to avoid re-calling it in CheckSalesDocument()
        CheckSalesDocument(SalesHeader);
        if SalesHeader.Ship then
            InitPostATOs(SalesHeader);

        if GuiAllowed() and not HideProgressWindow then
            InitProgressWindow(SalesHeader);

        // Update
        if SalesHeader.Invoice then begin
            CreatePrepaymentLines(SalesHeader, true);
            CreatePrepaymentLineForCreditMemo(SalesHeader);
        end;

        DateOrderSeriesUsed := false;
        ModifyHeader := UpdatePostingNos(SalesHeader);
        if DateOrderSeriesUsed then
            SuppressCommit := true;

        DropShipOrder := UpdateAssosOrderPostingNos(SalesHeader);

        OnBeforePostCommitSalesDoc(SalesHeader, GenJnlPostLine, PreviewMode, ModifyHeader, SuppressCommit, TempSalesLineGlobal);
        if DateOrderSeriesUsed and (not SuppressCommit) then
            Error(SuppressCommitErr, DummyNoSeries.FieldCaption("Date Order"), DummyNoSeries.TableCaption());

        if not PreviewMode and ModifyHeader then begin
            SalesHeader.Modify();
            if not SuppressCommit then
                Commit();
        end;

        RefreshTempLinesNeeded := false;
        OnCheckAndUpdateOnBeforeCalcInvDiscount(
          SalesHeader, TempWhseRcptHeader, TempWhseShptHeader, WhseReceive, WhseShip, RefreshTempLinesNeeded);
        if RefreshTempLinesNeeded then
            RefreshTempLines(SalesHeader, TempSalesLineGlobal);

        CalcInvDiscount(SalesHeader);
        OnCheckAndUpdateOnAfterCalcInvDiscount(SalesHeader, TempWhseShptHeader, PreviewMode, TempSalesLineGlobal, SuppressCommit, WhseReceive, WhseShip);

        ReleaseSalesDocument(SalesHeader);
        OnCheckAndUpdateOnAfterReleaseSalesDocument(SalesHeader, PreviewMode);

        HandleArchiveUnpostedOrder(SalesHeader);

        CheckICPartnerBlocked(SalesHeader);

        LockTables(SalesHeader);

        SourceCodeSetup.Get();
        SrcCode := SourceCodeSetup.Sales;

        OnCheckAndUpdateOnAfterSetSourceCode(SalesHeader, SourceCodeSetup, SrcCode);

        InsertPostedHeaders(SalesHeader);

        UpdateIncomingDocument(SalesHeader."Incoming Document Entry No.", SalesHeader."Posting Date", GenJnlLineDocNo);

        OnAfterCheckAndUpdate(SalesHeader, SuppressCommit, PreviewMode);
    end;

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

        if SalesHeader.Ship or SalesHeader.Receive then
            ArchiveUnpostedOrder(SalesHeader);
    end;

    /// <summary>
    /// Main function for checking if document header and lines are valid for posting.
    /// Checks for mandatory fields, posting dates, VAT dates, linked documents, posting restrictions, electronic documents, etc.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    procedure CheckSalesDocument(var SalesHeader: Record "Sales Header")
    var
        CheckDimensions: Codeunit "Check Dimensions";
        ErrorContextElement: Codeunit "Error Context Element";
        ForwardLinkMgt: Codeunit "Forward Link Mgt.";
        GenJnlCheckLine: Codeunit "Gen. Jnl.-Check Line";
        ReportDistributionManagement: Codeunit "Report Distribution Management";
        SetupRecID: RecordID;
        ModifyHeader: Boolean;
        ShouldCheckItemCharge: Boolean;
        ShouldCheckDueDate: Boolean;
        IsHandled: Boolean;
    begin
        if not DocumentIsReadyToBeChecked then
            PrepareCheckDocument(SalesHeader);
        ErrorMessageMgt.PushContext(ErrorContextElement, SalesHeader.RecordId, 0, CheckSalesHeaderMsg);
        CheckMandatoryHeaderFields(SalesHeader);
        GetGLSetup();
        if GLSetup."Journal Templ. Name Mandatory" then
            SalesHeader.TestField("Journal Templ. Name", ErrorInfo.Create());
        if GenJnlCheckLine.IsDateNotAllowed(SalesHeader."Posting Date", SetupRecID, SalesHeader."Journal Templ. Name") then
            ErrorMessageMgt.LogContextFieldError(
              SalesHeader.FieldNo(SalesHeader."Posting Date"), StrSubstNo(PostingDateNotAllowedErr, SalesHeader.FieldCaption("Posting Date")),
              SetupRecID, ErrorMessageMgt.GetFieldNo(SetupRecID.TableNo, GLSetup.FieldName("Allow Posting From")),
              ForwardLinkMgt.GetHelpCodeForAllowedPostingDate());

        CheckVATDate(SalesHeader);

        OnCheckAndUpdateOnBeforeSetPostingFlags(SalesHeader, TempSalesLineGlobal, ModifyHeader, HideProgressWindow);

        if LogErrorMode then
            SetLogErrorModePostingFlags(SalesHeader)
        else
            SetPostingFlags(SalesHeader);

        OnCheckAndUpdateOnAfterSetPostingFlags(SalesHeader, TempSalesLineGlobal, ModifyHeader);

        if GuiAllowed() and not HideProgressWindow then
            InitProgressWindow(SalesHeader);

        InvtPickPutaway := SalesHeader."Posting from Whse. Ref." <> 0;
        SalesHeader."Posting from Whse. Ref." := 0;
        OnCheckAndUpdateOnAfterSetPoszingFromWhseRef(SalesHeader, InvtPickPutaway, SalesHeader."Posting from Whse. Ref.");

        IsHandled := false;
        OnCheckSalesDocumentOnBeforeCheckSalesDim(SalesHeader, TempSalesLineGlobal, IsHandled);
        if not IsHandled then
            CheckDimensions.CheckSalesDim(SalesHeader, TempSalesLineGlobal);

        OnCheckAndUpdateOnBeforeCheckPostRestrictions(SalesHeader, PreviewMode);
        CheckPostRestrictions(SalesHeader);

        if SalesHeader.Invoice then
            SalesHeader.Invoice := CalcInvoice(SalesHeader);

        ShouldCheckItemCharge := SalesHeader.Invoice;
        OnCheckSalesDocumentOnAfterCalcShouldCheckItemCharge(SalesHeader, WhseReceive, WhseShip, ShouldCheckItemCharge, ModifyHeader);
        if ShouldCheckItemCharge then
            CopyAndCheckItemCharge(SalesHeader);

        ShouldCheckDueDate := SalesHeader.Invoice and not SalesHeader.IsCreditDocType();
        OnCheckSalesDocumentOnBeforeCheckDueDate(SalesHeader, ShouldCheckDueDate);
        if ShouldCheckDueDate then
            SalesHeader.TestField("Due Date", ErrorInfo.Create());

        UpdateShipAndCheckIfInvPickExists(SalesHeader);

        UpdateReceiveAndCheckIfInvPutawayExists(SalesHeader);

        CheckHeaderPostingType(SalesHeader);

        CheckHeaderShippingAdvice(SalesHeader);

        CheckAssosOrderLines(SalesHeader);

        ReportDistributionManagement.RunDefaultCheckSalesElectronicDocument(SalesHeader);
        ErrorMessageMgt.PopContext(ErrorContextElement);

        CheckSalesLines(SalesHeader);

        OnAfterCheckSalesDoc(SalesHeader, SuppressCommit, WhseShip, WhseReceive, PreviewMode, ErrorMessageMgt);
        if not LogErrorMode then
            ErrorMessageMgt.Finish(SalesHeader.RecordId);
    end;

    /// <summary>
    /// Checks all sales lines of the document if they are valid for posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    local procedure CheckSalesLines(var SalesHeader: Record "Sales Header")
    var
        InventorySetup: Record "Inventory Setup";
        ErrorContextElement: Codeunit "Error Context Element";
        SequenceNoMgt: Codeunit "Sequence No. Mgt.";
        NoOfItemLines: Integer;
    begin
        if TempSalesLineGlobal.FindSet() then
            repeat
                ErrorMessageMgt.PushContext(ErrorContextElement, TempSalesLineGlobal.RecordId(), 0, CheckSalesLineMsg);
                TestSalesLine(SalesHeader, TempSalesLineGlobal);
                if (SalesHeader.Ship or SalesHeader.Receive or SalesHeader.Invoice) and (TempSalesLineGlobal.Type = TempSalesLineGlobal.Type::Item) and (TempSalesLineGlobal."Qty. to Ship" <> 0) then
                    NoOfItemLines += 1;
            until TempSalesLineGlobal.Next() = 0;
        ErrorMessageMgt.PopContext(ErrorContextElement);
        if not InventorySetup.UseLegacyPosting() and (NoOfItemLines > 0) then begin
            if SalesHeader.Ship or SalesHeader.Receive then
                SequenceNoMgt.AllocateSeqNoBuffer(Database::"Item Ledger Entry", NoOfItemLines);
            SequenceNoMgt.AllocateSeqNoBuffer(Database::"Value Entry", NoOfItemLines);
        end;
    end;

    local procedure CheckTotalInvoiceAmount(SalesHeader: Record "Sales Header")
    var
        TempVATAmountLine: Record "VAT Amount Line" temporary;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckTotalInvoiceAmount(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        if SalesHeader."Document Type" in [SalesHeader."Document Type"::Invoice, SalesHeader."Document Type"::Order] then begin
            TempSalesLineGlobal.CalcVATAmountLines(1, SalesHeader, TempSalesLineGlobal, TempVATAmountLine);
            if TempVATAmountLine.GetTotalLineAmount(false, '') < 0 then
                if TempVATAmountLine.GetTotalAmountInclVAT() < 0 then
                    Error(TotalInvoiceAmountNegativeErr);
        end;
    end;

    /// <summary>
    /// Gets all the necessary setup information for the check document process
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    procedure PrepareCheckDocument(var SalesHeader: Record "Sales Header")
    begin
        OnBeforePrepareCheckDocument(SalesHeader);
        GetGLSetup();
        GetSalesSetup();
        GetInvoicePostingSetup();
        GetCurrency(SalesHeader."Currency Code");
        FillTempLines(SalesHeader, TempSalesLineGlobal);
        LogErrorMode := true;
        DocumentIsReadyToBeChecked := true;
    end;

    local procedure SetLogErrorModePostingFlags(var SalesHeader: Record "Sales Header")
    begin
        SalesHeader.Ship := SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice];
        SalesHeader.Receive := SalesHeader."Document Type" in [SalesHeader."Document Type"::"Return Order", SalesHeader."Document Type"::"Credit Memo"];
        SalesHeader.Invoice := true;
    end;

    /// <summary>
    /// Updates sales line quantities and amounts based on the posting type (Ship, Invoice), posts the line and creates a posted document lines.
    /// Deferrals and tracking information are posted for the line.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="EverythingInvoiced">A flag telling whether it was a partial invoice and something is still left.</param>
    /// <param name="TempVATAmountLine">A temp table holding all VAT amounts for the document.</param>
    /// <param name="TempVATAmountLineRemainder">A temp table holding Rounding Reminder Amounts for VAT Amounts used to prevent rounding errors when dividing amounts if Qty to post is not equal to full line Qty.</param>
    /// <param name="TempItemLedgEntryNotInvoiced">A temp table that will be filled in with all Assemble-to-order item ledger entries that have not been invoiced yet. Used when posting Item tracking for Shipment if Tracking Specification doesn't exist</param>
    /// <param name="HasATOShippedNotInvoiced">A flag telling whether there are any Assemble-to-order item ledger entries that have not been invoiced yet. Used when posting Item tracking for Shipment if Tracking Specification doesn't exist</param>
    /// <param name="TempDropShptPostBuffer">Return Variable: A temp table that will get an additional entry with Drop Shipment information if it's an Item line.</param>
    /// <param name="ICGenJnlLineNo">Return Variable: The line number of the Inter Company General Journal Line for that was created, It's only filled if line type is G/L Account.</param>
    local procedure PostSalesLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var EverythingInvoiced: Boolean; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary; var TempItemLedgEntryNotInvoiced: Record "Item Ledger Entry" temporary; HasATOShippedNotInvoiced: Boolean; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var ICGenJnlLineNo: Integer)
    var
        SalesInvLine: Record "Sales Invoice Line";
        SearchSalesInvLine: Record "Sales Invoice Line";
        SalesCrMemoLine: Record "Sales Cr.Memo Line";
        SearchSalesCrMemoLine: Record "Sales Cr.Memo Line";
        TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary;
        CostBaseAmount: Decimal;
        ShouldPostLine: Boolean;
        ShouldInsertInvoiceLine: Boolean;
        IsHandled: Boolean;
    begin
        if SalesLine.Type = SalesLine.Type::Item then begin
            CostBaseAmount := SalesLine."Line Amount";
            IsHandled := false;
            OnPostSalesLineOnBeforeTestUnitOfMeasureCode(SalesHeader, SalesLine, TempSalesLineGlobal, IsHandled);
            // Skip UoM validation for partially shipped/received documents and lines fetch through "Get Shipment Lines"
            if not IsHandled then
                if (SalesLine."No." <> '') and (SalesLine."Qty. Shipped (Base)" = 0) and (SalesLine."Shipment No." = '') and (SalesLine."Return Qty. Received (Base)" = 0) and (SalesLine."Return Receipt No." = '') then
                    SalesLine.TestField("Unit of Measure Code");
        end;
        if SalesLine."Qty. per Unit of Measure" = 0 then
            SalesLine."Qty. per Unit of Measure" := 1;

        OnPostSalesLineOnAfterTestSalesLine(SalesLine, SalesHeader, WhseShptHeader, WhseShip, PreviewMode, CostBaseAmount);

        TempPostedATOLink.Reset();
        TempPostedATOLink.DeleteAll();
        if SalesHeader.Ship then
            PostATO(SalesHeader, SalesLine, TempPostedATOLink);

        OnPostSalesLineOnBeforeUpdateSalesLineBeforePost(SalesLine, SalesHeader, WhseShip, WhseReceive, RoundingLineInserted, SuppressCommit);
        UpdateSalesLineBeforePost(SalesHeader, SalesLine);

        TestUpdatedSalesLine(SalesLine);
        IsHandled := false;
        OnPostSalesLineOnAfterTestUpdatedSalesLine(SalesLine, EverythingInvoiced, SalesHeader, IsHandled);
        if not IsHandled then
            if SalesLine."Qty. to Invoice" + SalesLine."Quantity Invoiced" <> SalesLine.Quantity then
                EverythingInvoiced := false;

        IsHandled := false;
        OnPostSalesLineOnAfterSetEverythingInvoiced(SalesLine, EverythingInvoiced, IsHandled, SalesHeader);
        if not IsHandled then
            if SalesLine.Quantity <> 0 then
                DivideAmount(SalesHeader, SalesLine, 1, SalesLine."Qty. to Invoice", TempVATAmountLine, TempVATAmountLineRemainder);

        CheckItemReservDisruption(SalesLine);
        RoundAmount(SalesHeader, SalesLine, SalesLine."Qty. to Invoice");
        OnPostSalesLineOnAfterRoundAmount(SalesHeader, SalesLine, SalesInvHeader, SalesCrMemoHeader, GenJnlLineDocNo);

        if not SalesLine.IsCreditDocType() then begin
            ReverseAmount(SalesLine);
            ReverseAmount(SalesLineACY);
        end;

        RemQtyToBeInvoiced := SalesLine."Qty. to Invoice";
        RemQtyToBeInvoicedBase := SalesLine."Qty. to Invoice (Base)";

        OnPostSalesLineOnBeforePostItemTrackingLine(
            SalesHeader, SalesLine, WhseShip, WhseReceive, InvtPickPutaway, SalesInvHeader, SalesCrMemoHeader,
            ItemLedgShptEntryNo, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, GenJnlLineDocNo, SrcCode, ItemJnlPostLine);

        PostItemTrackingLine(SalesHeader, SalesLine, TempItemLedgEntryNotInvoiced, HasATOShippedNotInvoiced);

        OnPostSalesLineOnAfterPostItemTrackingLine(SalesHeader, SalesLine, WhseShip, WhseReceive, InvtPickPutaway, TempDropShptPostBuffer, TempPostedATOLink);

        case SalesLine.Type of
            SalesLine.Type::"G/L Account":
                PostGLAccICLine(SalesHeader, SalesLine, ICGenJnlLineNo);
            SalesLine.Type::Item:
                PostItemLine(SalesHeader, SalesLine, TempDropShptPostBuffer, TempPostedATOLink);
            SalesLine.Type::Resource:
                PostResJnlLine(SalesHeader, SalesLine, JobTaskSalesLine);
            SalesLine.Type::"Charge (Item)":
                PostItemChargeLine(SalesHeader, SalesLine);
        end;

        ShouldPostLine := (SalesLine.Type <> SalesLine.Type::" ") and (SalesLine."Qty. to Invoice" <> 0);
        OnPostSalesLineOnBeforePostSalesLine(
            SalesHeader, SalesLine, GenJnlLineDocNo, GenJnlLineExtDocNo, GenJnlLineDocType, SrcCode, GenJnlPostLine, ShouldPostLine, SalesLineACY);
        if ShouldPostLine then begin
            AdjustPrepmtAmountLCY(SalesHeader, SalesLine);
            OnPostSalesLineOnAfterAdjustPrepmtAmountLCY(SalesLine, xSalesLine, TempTrackingSpecification, SalesHeader);
            InvoicePostingInterface.PrepareLine(SalesHeader, SalesLine, SalesLineACY);
        end;

        IsHandled := false;
        OnPostSalesLineOnBeforeTestJobNo(SalesLine, IsHandled);
        if not IsHandled then
            if not (SalesLine."Document Type" in [SalesLine."Document Type"::Invoice, SalesLine."Document Type"::"Credit Memo"]) then
                SalesLine.TestField("Job No.", '');

        IsHandled := false;
        OnPostSalesLineOnBeforeInsertShipmentLine(
          SalesHeader, SalesLine, IsHandled, SalesLineACY, GenJnlLineDocType.AsInteger(), GenJnlLineDocNo, GenJnlLineExtDocNo);
        if not IsHandled then
            if (SalesShptHeader."No." <> '') and (SalesLine."Shipment No." = '') and
               not RoundingLineInserted and not SalesLine."Prepayment Line"
            then
                InsertShipmentLine(SalesHeader, SalesShptHeader, SalesLine, CostBaseAmount);

        IsHandled := false;
        OnPostSalesLineOnBeforeInsertReturnReceiptLine(SalesHeader, SalesLine, IsHandled);
        if not IsHandled then
            if (ReturnRcptHeader."No." <> '') and (SalesLine."Return Receipt No." = '') and not RoundingLineInserted then
                InsertReturnReceiptLine(ReturnRcptHeader, SalesLine, CostBaseAmount, SalesHeader);

        OnPostSalesLineOnAfterInsertReturnReceiptLine(SalesHeader, SalesLine, xSalesLine, ReturnRcptHeader, RoundingLineInserted, TempTrackingSpecification, ItemLedgShptEntryNo, SalesShptHeader);

        IsHandled := false;
        if SalesHeader.Invoice then begin
            ShouldInsertInvoiceLine := SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice];
            OnPostSalesLineOnBeforeInsertInvoiceLine(SalesHeader, SalesLine, IsHandled, xSalesLine, SalesInvHeader, ShouldInsertInvoiceLine);
            if ShouldInsertInvoiceLine and not IsHandled then begin
                if not IsHandled then begin
                    SalesInvLine.InitFromSalesLine(SalesInvHeader, xSalesLine);

                    OnPostSalesLineOnBeforeCollectValueEntryRelation(SalesHeader, SalesLine, SalesInvHeader, SalesInvLine);
                    ItemJnlPostLine.CollectValueEntryRelation(TempValueEntryRelation, SalesInvLine.RowID1());
                    OnPostSalesLineOnAfterCollectValueEntryRelation(SalesHeader, SalesLine, SalesInvHeader, SalesInvLine);
                    SetInvoiceOrderNo(SalesLine, SalesInvLine);
                    IsHandled := false;
                    OnBeforeSalesInvLineInsert(
                        SalesInvLine, SalesInvHeader, xSalesLine, SuppressCommit, IsHandled, SalesLine, SalesShptHeader, SalesHeader, ReturnRcptHeader);
                    if IsHandled then
                        exit;
                    if not IsNullGuid(xSalesLine.SystemId) then begin
                        SearchSalesInvLine.SetRange(SystemId, xSalesLine.SystemId);
                        if SearchSalesInvLine.IsEmpty() then begin
                            SalesInvLine.SystemId := xSalesLine.SystemId;
                            SalesInvLine.Insert(true, true);
                        end else begin
                            Session.LogMessage('0000DD6', SameIdFoundLbl, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', SalesLinePostCategoryTok);
                            SalesInvLine.Insert(true);
                        end;
                    end else begin
                        SalesInvLine.Insert(true);
                        Session.LogMessage('0000DDC', EmptyIdFoundLbl, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', SalesLinePostCategoryTok);
                    end;
                    OnAfterSalesInvLineInsert(
                      SalesInvLine, SalesInvHeader, xSalesLine, ItemLedgShptEntryNo, WhseShip, WhseReceive, SuppressCommit,
                      SalesHeader, TempItemChargeAssgntSales, TempWhseShptHeader, TempWhseRcptHeader, PreviewMode);
                    InvoicePostingInterface.CreatePostedDeferralSchedule(
                        xSalesLine, SalesInvLine.GetDocumentType(),
                        SalesInvHeader."No.", SalesInvLine."Line No.", SalesInvHeader."Posting Date");
                    OnPostSalesLineOnAfterCreatePostedDeferralSchedule(SalesInvLine, SalesInvHeader);
                end;
            end else begin
                OnPostSalesLineOnBeforeInsertCrMemoLine(SalesHeader, SalesLine, IsHandled, xSalesLine, SalesCrMemoHeader);
                if not IsHandled then begin
                    SalesCrMemoLine.InitFromSalesLine(SalesCrMemoHeader, xSalesLine);
                    OnPostSalesLineOnBeforeCollectValueEntryRelationForCrMemo(SalesHeader, SalesLine, SalesInvHeader, SalesInvLine);
                    ItemJnlPostLine.CollectValueEntryRelation(TempValueEntryRelation, SalesCrMemoLine.RowID1());
                    SetCreditMemoOrderNo(SalesLine, SalesCrMemoLine);
                    IsHandled := false;
                    OnBeforeSalesCrMemoLineInsert(
                        SalesCrMemoLine, SalesCrMemoHeader, xSalesLine, SuppressCommit, IsHandled, SalesHeader, SalesShptHeader, ReturnRcptHeader, SalesLine);
                    if IsHandled then
                        exit;
                    if not IsNullGuid(xSalesLine.SystemId) then begin
                        SearchSalesCrMemoLine.SetRange(SystemId, xSalesLine.SystemId);
                        if SearchSalesCrMemoLine.IsEmpty() then begin
                            SalesCrMemoLine.SystemId := xSalesLine.SystemId;
                            SalesCrMemoLine.Insert(true, true);
                        end else begin
                            Session.LogMessage('0000DD7', SameIdFoundLbl, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', SalesLinePostCategoryTok);
                            SalesCrMemoLine.Insert(true);
                        end;
                    end else begin
                        SalesCrMemoLine.Insert(true);
                        Session.LogMessage('0000DDD', SameIdFoundLbl, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', SalesLinePostCategoryTok);
                    end;
                    OnAfterSalesCrMemoLineInsert(
                      SalesCrMemoLine, SalesCrMemoHeader, SalesHeader, xSalesLine, TempItemChargeAssgntSales, SuppressCommit, WhseShip, WhseReceive, TempWhseShptHeader, TempWhseRcptHeader);
                    InvoicePostingInterface.CreatePostedDeferralSchedule(
                        xSalesLine, SalesCrMemoLine.GetDocumentType(),
                        SalesCrMemoHeader."No.", SalesCrMemoLine."Line No.", SalesCrMemoHeader."Posting Date");
                end;
            end;
        end;

        OnAfterPostSalesLine(SalesHeader, SalesLine, SuppressCommit, SalesInvLine, SalesCrMemoLine, xSalesLine);
    end;

    local procedure SetInvoiceOrderNo(SalesLine: Record "Sales Line"; var SalesInvLine: Record "Sales Invoice Line")
    var
        SalesShptLine: Record "Sales Shipment Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSetInvoiceOrderNo(SalesLine, SalesInvLine, IsHandled);
        if IsHandled then
            exit;

        if SalesLine."Document Type" = SalesLine."Document Type"::Order then begin
            SalesInvLine."Order No." := SalesLine."Document No.";
            SalesInvLine."Order Line No." := SalesLine."Line No.";
        end else
            if SalesShptLine.Get(SalesLine."Shipment No.", SalesLine."Shipment Line No.") then begin
                SalesInvLine."Order No." := SalesShptLine."Order No.";
                SalesInvLine."Order Line No." := SalesShptLine."Order Line No.";
            end;
    end;

    local procedure SetCreditMemoOrderNo(SalesLine: Record "Sales Line"; var SalesCrMemoLine: Record "Sales Cr.Memo Line")
    var
        ReturnReceiptLine: Record "Return Receipt Line";
    begin
        if SalesLine."Document Type" = SalesLine."Document Type"::"Return Order" then begin
            SalesCrMemoLine."Order No." := SalesLine."Document No.";
            SalesCrMemoLine."Order Line No." := SalesLine."Line No.";
        end else
            if ReturnReceiptLine.Get(SalesLine."Return Receipt No.", SalesLine."Return Receipt Line No.") then begin
                SalesCrMemoLine."Order No." := ReturnReceiptLine."Return Order No.";
                SalesCrMemoLine."Order Line No." := ReturnReceiptLine."Return Order Line No.";
            end;
    end;

    local procedure UpdateInvoiceRounding(var SalesHeader: Record "Sales Header"; var BiggestLineNo: Integer)
    begin
        if RoundingLineInserted then
            LastLineRetrieved := true
        else begin
            BiggestLineNo := MAX(BiggestLineNo, TempSalesLineGlobal."Line No.");
            LastLineRetrieved := TempSalesLineGlobal.Next() = 0;
            if LastLineRetrieved and SalesSetup."Invoice Rounding" then
                InvoiceRounding(SalesHeader, TempSalesLineGlobal, false, BiggestLineNo);
        end;

        OnAfterUpdateInvoiceRounding(
            SalesHeader, TotalSalesLine, TempSalesLineGlobal, Currency, BiggestLineNo, LastLineRetrieved, RoundingLineInserted, RoundingLineNo, false);
    end;

    /// <summary>
    /// Posts sales and VAT to G/L entries from posting buffer and posts customer entry
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="CustLedgEntry">Return value: The customer ledger entry that was created.</param>
    local procedure PostInvoice(var SalesHeader: Record "Sales Header"; var CustLedgEntry: Record "Cust. Ledger Entry")
    var
        TotalAmount: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostInvoice(SalesHeader, CustLedgEntry, SuppressCommit, PreviewMode, GenJnlPostLine, IsHandled, GenJnlLineDocNo, GenJnlLineExtDocNo, GenJnlLineDocType, SrcCode);
        if IsHandled then
            exit;

        // Post sales and VAT to G/L entries from posting buffer
        GetInvoicePostingParameters();
        InvoicePostingInterface.SetParameters(InvoicePostingParameters);
        InvoicePostingInterface.SetTotalLines(TotalSalesLine, TotalSalesLineLCY);
        InvoicePostingInterface.PostLines(SalesHeader, GenJnlPostLine, Window, TotalAmount);
        OnPostInvoiceOnAfterPostLines(SalesHeader, SrcCode, GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo, GenJnlPostLine);

        // Post customer entry
        if GuiAllowed() and not HideProgressWindow then
            Window.Update(4, 1);

        InvoicePostingInterface.SetParameters(InvoicePostingParameters);
        InvoicePostingInterface.SetTotalLines(TotalSalesLine, TotalSalesLineLCY);
        InvoicePostingInterface.PostLedgerEntry(SalesHeader, GenJnlPostLine);
        UpdateSalesHeader(CustLedgEntry, SalesHeader);

        // Balancing account
        if SalesHeader."Bal. Account No." <> '' then begin
            IsHandled := false;
            OnPostInvoiceOnBeforeBalAccountNoWindowUpdate(HideProgressWindow, IsHandled, SalesHeader);
            if not IsHandled then
                if GuiAllowed() and not HideProgressWindow then
                    Window.Update(5, 1);

            IsHandled := false;
            OnPostInvoiceOnBeforePostBalancingEntry(SalesHeader, IsHandled, TotalSalesLine, TotalSalesLineLCY, PreviewMode, SuppressCommit, InvoicePostingParameters, GenJnlPostLine, SalesInvHeader, SalesCrMemoHeader);
            if not IsHandled then
                InvoicePostingInterface.PostBalancingEntry(SalesHeader, GenJnlPostLine);
        end;

        OnAfterPostGLAndCustomer(
            SalesHeader, GenJnlPostLine, TotalSalesLine, TotalSalesLineLCY, SuppressCommit,
            WhseShptHeader, WhseShip, TempWhseShptHeader, SalesInvHeader, SalesCrMemoHeader, CustLedgEntry,
            SrcCode, GenJnlLineDocNo, GenJnlLineExtDocNo, GenJnlLineDocType, PreviewMode, DropShipOrder);
    end;

    /// <summary>
    /// Creates a General Journal Line for Inter Company posting
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="ICGenJnlLineNo">Return value: The line number of the Inter Company General Journal Line for that was created.</param>
    local procedure PostGLAccICLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var ICGenJnlLineNo: Integer)
    begin
        if (SalesLine."No." <> '') and not SalesLine."System-Created Entry" then begin
            CheckGLAccountDirectPosting(SalesLine);
            if (SalesLine."IC Partner Code" <> '') and SalesHeader.Invoice then
                InsertICGenJnlLine(SalesHeader, xSalesLine, ICGenJnlLineNo);
        end;
    end;

    local procedure CheckGLAccountDirectPosting(SalesLine: Record "Sales Line")
    var
        GLAcc: Record "G/L Account";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckGLAccountDirectPosting(SalesLine, IsHandled);
        if IsHandled then
            exit;

        GLAcc.Get(SalesLine."No.");
        GLAcc.TestField("Direct Posting", true);
    end;

    /// <summary>
    /// Creates and posts (Invoice and Ship) Item Journal Lines for Sales lines of type Item
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted. A line with Type "Item" is expected.</param>
    /// <param name="TempDropShptPostBuffer">Return Variable: A temp table Set that will get an additional entry with Drop Shipment information.</param>
    /// <param name="TempPostedATOLink">A temp table Set containing Posted Assemble-to-Order Links. If a link exists, it posts an item journal line with assembled quantity</param>
    procedure PostItemLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary)
    var
        DummyTrackingSpecification: Record "Tracking Specification";
        SalesLineToShip: Record "Sales Line";
        QtyToInvoice: Decimal;
        QtyToInvoiceBase: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemLine(SalesHeader, SalesLine, IsHandled, TempSalesLineGlobal, TempDropShptPostBuffer, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, ItemJnlPostLine);
        if IsHandled then
            exit;

        ItemLedgShptEntryNo := 0;
        QtyToInvoice := RemQtyToBeInvoiced;
        QtyToInvoiceBase := RemQtyToBeInvoicedBase;

        ProcessAssocItemJnlLine(SalesHeader, SalesLine, TempDropShptPostBuffer);

        Clear(TempPostedATOLink);
        TempPostedATOLink.SetRange("Order No.", SalesLine."Document No.");
        TempPostedATOLink.SetRange("Order Line No.", SalesLine."Line No.");
        if TempPostedATOLink.FindFirst() then
            PostATOAssocItemJnlLine(SalesHeader, SalesLine, TempPostedATOLink, QtyToInvoice, QtyToInvoiceBase);

        OnPostItemLineOnBeforePostItemInvoiceLine(SalesHeader, SalesLine, TempDropShptPostBuffer, TempPostedATOLink, QtyToInvoice, QtyToInvoiceBase);

        if QtyToInvoice <> 0 then
            ItemLedgShptEntryNo :=
              PostItemJnlLine(
                SalesHeader, SalesLine,
                QtyToInvoice, QtyToInvoiceBase,
                QtyToInvoice, QtyToInvoiceBase,
                0, '', DummyTrackingSpecification, false);

        IsHandled := false;
        OnPostItemLineOnBeforeMakeSalesLineToShip(
            SalesHeader, SalesLine, TempPostedATOLink, ItemLedgShptEntryNo, IsHandled, GenJnlLineDocNo, GenJnlLineExtDocNo, ReturnRcptHeader,
            TempHandlingSpecification, TempTrackingSpecificationInv, TempTrackingSpecification);
        if not IsHandled then begin
            // Invoice discount amount is also included in expected sales amount posted for shipment or return receipt.
            MakeSalesLineToShip(SalesLineToShip, SalesLine);
            OnPostItemLineOnAfterMakeSalesLineToShip(SalesHeader, SalesLine, TempDropShptPostBuffer, TempPostedATOLink, QtyToInvoice, QtyToInvoiceBase);

            if SalesLineToShip.IsCreditDocType() then begin
                if Abs(SalesLineToShip."Return Qty. to Receive") > Abs(QtyToInvoice) then
                    ItemLedgShptEntryNo :=
                        PostItemJnlLine(
                            SalesHeader, SalesLineToShip,
                            SalesLineToShip."Return Qty. to Receive" - QtyToInvoice,
                            SalesLineToShip."Return Qty. to Receive (Base)" - QtyToInvoiceBase,
                            0, 0, 0, '', DummyTrackingSpecification, false);
            end else begin
                IsHandled := false;
                OnPostItemLineOnBeforePostItemJnlLineForInvoiceDoc(SalesHeader, SalesLineToShip, SalesHeader.Ship, ItemLedgShptEntryNo, GenJnlLineDocNo, GenJnlLineExtDocNo, SalesShptHeader, TempHandlingSpecification, TempTrackingSpecificationInv, TempTrackingSpecification, IsHandled, QtyToInvoice, TempPostedATOLink);
                if not IsHandled then
                    if Abs(SalesLineToShip."Qty. to Ship") > Abs(QtyToInvoice) + Abs(TempPostedATOLink."Assembled Quantity") then
                        ItemLedgShptEntryNo :=
                            PostItemJnlLine(
                                SalesHeader, SalesLineToShip,
                                SalesLineToShip."Qty. to Ship" - TempPostedATOLink."Assembled Quantity" - QtyToInvoice,
                                SalesLineToShip."Qty. to Ship (Base)" - TempPostedATOLink."Assembled Quantity (Base)" - QtyToInvoiceBase,
                                0, 0, 0, '', DummyTrackingSpecification, false);
            end;
        end;

        OnAfterPostItemLine(SalesHeader, SalesLine, QtyToInvoice, QtyToInvoiceBase, SuppressCommit, ItemJnlPostLine);
    end;

    /// <summary>
    /// Processes associated item journal lines for drop shipment orders.
    /// </summary>
    /// <param name="SalesHeader">Specifies the sales header of the document being posted.</param>
    /// <param name="SalesLine">Specifies the sales line being processed.</param>
    /// <param name="TempDropShptPostBuffer">Returns the drop shipment posting buffer with the associated item entry.</param>
    procedure ProcessAssocItemJnlLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeProcessAssocItemJnlLine(SalesLine, IsHandled, SalesHeader, TempDropShptPostBuffer);
        if IsHandled then
            exit;

        if (SalesLine."Qty. to Ship" <> 0) and (SalesLine."Purch. Order Line No." <> 0) then begin
            TempDropShptPostBuffer."Order No." := SalesLine."Purchase Order No.";
            TempDropShptPostBuffer."Order Line No." := SalesLine."Purch. Order Line No.";
            TempDropShptPostBuffer.Quantity := -SalesLine."Qty. to Ship";
            TempDropShptPostBuffer."Quantity (Base)" := -SalesLine."Qty. to Ship (Base)";
            OnProcessAssocItemJnlLineOnBeforePostAssocItemJnlLine(TempDropShptPostBuffer, SalesLine);
            TempDropShptPostBuffer."Item Shpt. Entry No." :=
                PostAssocItemJnlLine(SalesHeader, SalesLine, TempDropShptPostBuffer.Quantity, TempDropShptPostBuffer."Quantity (Base)");
            OnProcessAssocItemJnlLineOnBeforeTempDropShptPostBufferInsert(TempDropShptPostBuffer, SalesLine);
            TempDropShptPostBuffer.Insert();
            SalesLine."Appl.-to Item Entry" := TempDropShptPostBuffer."Item Shpt. Entry No.";
        end;
    end;

    local procedure PostItemChargeLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    var
        SalesLineBackup: Record "Sales Line";
        IsHandled: Boolean;
    begin
        if not (SalesHeader.Invoice and (SalesLine."Qty. to Invoice" <> 0)) then
            exit;

        IsHandled := false;
        OnBeforePostItemChargeLine(SalesHeader, SalesLine, IsHandled);
        if IsHandled then
            exit;

        ItemJnlRollRndg := true;
        SalesLineBackup.Copy(SalesLine);
        if FindTempItemChargeAssgntSales(SalesLineBackup."Line No.") then
            repeat
                OnPostItemChargeLineOnBeforePostItemCharge(TempItemChargeAssgntSales, SalesHeader, SalesLineBackup);
                case TempItemChargeAssgntSales."Applies-to Doc. Type" of
                    TempItemChargeAssgntSales."Applies-to Doc. Type"::Shipment:
                        begin
                            PostItemChargePerShpt(SalesHeader, SalesLineBackup);
                            TempItemChargeAssgntSales.Mark(true);
                        end;
                    TempItemChargeAssgntSales."Applies-to Doc. Type"::"Return Receipt":
                        begin
                            PostItemChargePerRetRcpt(SalesHeader, SalesLineBackup);
                            TempItemChargeAssgntSales.Mark(true);
                        end;
                    TempItemChargeAssgntSales."Applies-to Doc. Type"::Order,
                    TempItemChargeAssgntSales."Applies-to Doc. Type"::Invoice,
                    TempItemChargeAssgntSales."Applies-to Doc. Type"::"Return Order",
                    TempItemChargeAssgntSales."Applies-to Doc. Type"::"Credit Memo":
                        CheckItemCharge(TempItemChargeAssgntSales);
                end;
                OnPostItemChargeLineOnAfterTempItemChargeAssgntSalesLoop(TempItemChargeAssgntSales, SalesHeader, SalesLineBackup, SalesLine);
            until TempItemChargeAssgntSales.Next() = 0;

        OnAfterPostItemChargeLine(SalesLine, SalesLineACY);
    end;

    /// <summary>
    /// Finds Tracking Specification for the sales line, Posts Item Tracking and saves the Tracking Specification in a temp table
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="TempItemLedgEntryNotInvoiced">A temp table that will be filled in with all Assemble-to-order item ledger entries that have not been invoiced yet. Used when posting Item tracking for Shipment if Tracking Specification doesn't exist</param>
    /// <param name="HasATOShippedNotInvoiced">A flag telling whether there are any Assemble-to-order item ledger entries that have not been invoiced yet. Used when posting Item tracking for Shipment if Tracking Specification doesn't exist</param>
    local procedure PostItemTrackingLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var TempItemLedgEntryNotInvoiced: Record "Item Ledger Entry" temporary; HasATOShippedNotInvoiced: Boolean)
    var
        TempTrackingSpecification: Record "Tracking Specification" temporary;
        TrackingSpecificationExists: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemTrackingLine(SalesHeader, SalesLine, TempItemLedgEntryNotInvoiced, HasATOShippedNotInvoiced, IsHandled, ItemLedgShptEntryNo, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, SalesInvHeader, SalesCrMemoHeader);
        if IsHandled then
            exit;

        if SalesLine."Prepayment Line" then
            exit;

        if SalesHeader.Invoice then
            if SalesLine."Qty. to Invoice" = 0 then
                TrackingSpecificationExists := false
            else
                TrackingSpecificationExists :=
                  SalesLineReserve.RetrieveInvoiceSpecification(SalesLine, TempTrackingSpecification);
        OnPostItemTrackingLineOnAfterRetrieveInvoiceSpecification(SalesLine, TempTrackingSpecification, TrackingSpecificationExists);

        PostItemTracking(
          SalesHeader, SalesLine, TrackingSpecificationExists, TempTrackingSpecification,
          TempItemLedgEntryNotInvoiced, HasATOShippedNotInvoiced);

        if TrackingSpecificationExists then
            SaveInvoiceSpecification(TempTrackingSpecification);
    end;

    /// <summary>
    /// Creates and posts Item Journal Line for a sales line
    /// Creates Tracking Specification entries for the Journal Line
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="QtyToBeShipped">The quantity of the Item to be shipped.</param>
    /// <param name="QtyToBeShippedBase">The base quantity of the Item to be shipped.</param>
    /// <param name="QtyToBeInvoiced">The quantity of the Item to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The base quantity of the Item to be invoiced.</param>
    /// <param name="ItemLedgShptEntryNo">Item Shipment Entry No. to be assigned to the Item Journal Line.</param>
    /// <param name="ItemChargeNo">Item Charge No. to be assigned to the Item Journal Line.</param>
    /// <param name="TrackingSpecification">Tracking Specification for the sales line. This parameter is exposed through events, but isn't directly used in the procedure</param>
    /// <param name="IsATO">A flag indicating whether the Item is Assemble-to-order.</param>
    /// <returns>The Item Shipment Entry No. assigned to the Item Journal Line.</returns>
    procedure PostItemJnlLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; QtyToBeShippedBase: Decimal; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal; ItemLedgShptEntryNo: Integer; ItemChargeNo: Code[20]; TrackingSpecification: Record "Tracking Specification"; IsATO: Boolean) Result: Integer
    var
        ItemJnlLine: Record "Item Journal Line";
        TempWhseJnlLine: Record "Warehouse Journal Line" temporary;
        TempWhseTrackingSpecification: Record "Tracking Specification" temporary;
        OriginalItemJnlLine: Record "Item Journal Line";
        ItemShptEntryNo: Integer;
        PostWhseJnlLine: Boolean;
        IsHandled: Boolean;
        ShouldPostItemJnlLine: Boolean;
        ShouldPostItemJnlLineItemCharges: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemJnlLine(
          SalesHeader, SalesLine, QtyToBeShipped, QtyToBeShippedBase, QtyToBeInvoiced, QtyToBeInvoicedBase,
          ItemLedgShptEntryNo, ItemChargeNo, TrackingSpecification, IsATO, SuppressCommit, IsHandled, Result, TempTrackingSpecification, TempHandlingSpecification, TempValueEntryRelation, ItemJnlPostLine);
        if IsHandled then
            exit(Result);

        PostItemJnlLinePrepareJournalLine(
            ItemJnlLine, SalesHeader, SalesLine, QtyToBeShipped, QtyToBeShippedBase, QtyToBeInvoiced, QtyToBeInvoicedBase,
            ItemLedgShptEntryNo, ItemChargeNo, TrackingSpecification, IsATO);

        ShouldPostItemJnlLine := not JobContractLine;
        OnPostItemJnlLineOnBeforeIsJobContactLineCheck(ItemJnlLine, SalesHeader, SalesLine, ShouldPostItemJnlLine, ItemJnlPostLine, QtyToBeShipped);

        if ShouldPostItemJnlLine then begin
            PostItemJnlLineBeforePost(ItemJnlLine, SalesLine, TempWhseJnlLine, PostWhseJnlLine, QtyToBeShippedBase, TrackingSpecification);

            OriginalItemJnlLine := ItemJnlLine;
            if not IsItemJnlPostLineHandled(ItemJnlLine, SalesLine, SalesHeader) then
                RunItemJnlPostLine(ItemJnlLine);
            OnPostItemJnlLineOnAfterItemJnlPostLineRunWithCheck(ItemJnlPostLine, SalesLine);

            if IsATO then
                PostItemJnlLineTracking(
                  SalesLine, TempWhseTrackingSpecification, PostWhseJnlLine, QtyToBeInvoiced, TempATOTrackingSpecification)
            else
                PostItemJnlLineTracking(SalesLine, TempWhseTrackingSpecification, PostWhseJnlLine, QtyToBeInvoiced, TempHandlingSpecification);

            IsHandled := false;
            OnPostItemJnlLineOnBeforePostItemJnlLineWhseLine(
              ItemJnlLine, TempWhseJnlLine, TempWhseTrackingSpecification, TempTrackingSpecification, IsHandled, SalesLine);
            if not IsHandled then
                PostItemJnlLineWhseLine(TempWhseJnlLine, TempWhseTrackingSpecification);

            OnAfterPostItemJnlLineWhseLine(SalesLine, ItemLedgShptEntryNo, WhseShip, WhseReceive, SuppressCommit);

            ShouldPostItemJnlLineItemCharges := (SalesLine.Type = SalesLine.Type::Item) and SalesHeader.Invoice;
            OnPostItemJnlLineOnAfterCalcShouldPostItemJnlLineItemCharges(SalesLine, SalesHeader, ShouldPostItemJnlLineItemCharges);
            if ShouldPostItemJnlLineItemCharges then
                PostItemJnlLineItemCharges(SalesHeader, SalesLine, OriginalItemJnlLine, ItemJnlLine."Item Shpt. Entry No.");
        end;

        ItemShptEntryNo := ItemJnlLine."Item Shpt. Entry No.";
        OnAfterPostItemJnlLine(ItemJnlLine, SalesLine, SalesHeader, ItemJnlPostLine, WhseJnlPostLine, OriginalItemJnlLine, ItemShptEntryNo, IsATO, TempHandlingSpecification, TempATOTrackingSpecification, TempWhseJnlLine, ShouldPostItemJnlLine, WhseShip, WhseRcptHeader, WhseShptHeader);

        exit(ItemShptEntryNo);
    end;

    /// <summary>
    /// Prepares Item Journal Line for posting with information from sales header, sales line and parameters
    /// </summary>
    /// <param name="ItemJnlLine">Return value: The Item Journal Line that was prepared.</param>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="QtyToBeShipped">The quantity of the Item to be shipped.</param>
    /// <param name="QtyToBeShippedBase">The base quantity of the Item to be shipped.</param>
    /// <param name="QtyToBeInvoiced">The quantity of the Item to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The base quantity of the Item to be invoiced.</param>
    /// <param name="ItemLedgShptEntryNo">Item Shipment Entry No. to be assigned to the Item Journal Line.</param>
    /// <param name="ItemChargeNo">Item Charge No. to be assigned to the Item Journal Line.</param>
    /// <param name="TrackingSpecification">Tracking Specification for the sales line. This parameter is exposed through events, but isn't directly used in the procedure</param>
    /// <param name="IsATO">A flag indicating whether the Item is Assemble-to-order.</param>
    procedure PostItemJnlLinePrepareJournalLine(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; QtyToBeShippedBase: Decimal; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal; ItemLedgShptEntryNo: Integer; ItemChargeNo: Code[20]; TrackingSpecification: Record "Tracking Specification"; IsATO: Boolean)
    var
        DummyItemTrackingSetup: Record "Item Tracking Setup";
        IsHandled: Boolean;
    begin
        ClearRemAmtIfNotItemJnlRollRndg(SalesLine);

        ItemJnlLine.Init();
        ItemJnlLine.CopyFromSalesHeader(SalesHeader);
        ItemJnlLine.CopyFromSalesLine(SalesLine);
        ItemJnlLine."Country/Region Code" := GetCountryCode(SalesLine, SalesHeader);

        OnPostItemJnlLineOnBeforeCopyTrackingFromSpec(
            TrackingSpecification, ItemJnlLine, SalesHeader, SalesLine, SalesInvHeader, SalesCrMemoHeader, IsATO);
        ItemJnlLine.CopyTrackingFromSpec(TrackingSpecification);
        OnPostItemJnlLineOnAfterCopyTrackingFromSpec(ItemJnlLine, SalesLine, QtyToBeShipped, IsATO);

        ItemJnlLine."Item Shpt. Entry No." := ItemLedgShptEntryNo;

        IsHandled := false;
        OnPostItemJnlLinePrepareJournalLineOnBeforeCalcQuantities(
            ItemJnlLine, SalesLine, QtyToBeShipped, QtyToBeShippedBase, QtyToBeInvoiced, QtyToBeInvoicedBase, IsHandled, IsATO);
        if not IsHandled then begin
            ItemJnlLine.Quantity := -QtyToBeShipped;
            ItemJnlLine."Quantity (Base)" := -QtyToBeShippedBase;
            ItemJnlLine."Invoiced Quantity" := -QtyToBeInvoiced;
            ItemJnlLine."Invoiced Qty. (Base)" := -QtyToBeInvoicedBase;
        end;

        PostItemJnlLineCopyDocumentFields(ItemJnlLine, SalesHeader, SalesLine, QtyToBeShipped, QtyToBeInvoiced);

        if QtyToBeInvoiced <> 0 then
            ItemJnlLine."Invoice No." := GenJnlLineDocNo;

        ItemJnlLine."Assemble to Order" := IsATO;
        if ItemJnlLine."Assemble to Order" then
            ItemJnlLine."Applies-to Entry" := SalesLine.FindOpenATOEntry(DummyItemTrackingSetup)
        else
            ItemJnlLine."Applies-to Entry" := SalesLine."Appl.-to Item Entry";

        if ItemChargeNo <> '' then begin
            ItemJnlLine."Item Charge No." := ItemChargeNo;
            SalesLine."Qty. to Invoice" := QtyToBeInvoiced;
            OnPostItemJnlLineOnAfterCopyItemCharge(ItemJnlLine, TempItemChargeAssgntSales);
        end else
            ItemJnlLine."Applies-from Entry" := SalesLine."Appl.-from Item Entry";

        OnPostItemJnlLinePrepareJournalLineOnBeforeCalcItemJnlAmounts(ItemJnlLine, SalesHeader, SalesLine, IsATO);
        if QtyToBeInvoiced <> 0 then
            CalcItemJnlAmountsFromQtyToBeInvoiced(ItemJnlLine, SalesHeader, SalesLine, QtyToBeInvoiced)
        else
            CalcItemJnlAmountsFromQtyToBeShipped(ItemJnlLine, SalesHeader, SalesLine, QtyToBeShipped);

        OnPostItemJnlLineOnAfterPrepareItemJnlLine(
            ItemJnlLine, SalesLine, SalesHeader, WhseShip, ItemJnlPostLine, QtyToBeShipped, TrackingSpecification,
            QtyToBeInvoiced, QtyToBeInvoicedBase, QtyToBeShippedBase, RemAmt, RemDiscAmt);
    end;

    local procedure CalcItemJnlAmountsFromQtyToBeInvoiced(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeInvoiced: Decimal)
    var
        Factor: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCalcItemJnlAmountsFromQtyToBeInvoiced(ItemJnlLine, SalesHeader, SalesLine, QtyToBeInvoiced, IsHandled);
        if IsHandled then
            exit;

        Factor := QtyToBeInvoiced / SalesLine."Qty. to Invoice";
        OnCalcItemJnlAmountsFromQtyToBeInvoicedOnAfterSetFactor(SalesLine, Factor, ItemJnlLine);
        ItemJnlLine.Amount := -(SalesLine.Amount * Factor - RemAmt);
        if SalesHeader."Prices Including VAT" then
            ItemJnlLine."Discount Amount" :=
              -((SalesLine."Line Discount Amount" + SalesLine."Inv. Discount Amount") /
                (1 + SalesLine."VAT %" / 100) * Factor - RemDiscAmt)
        else
            ItemJnlLine."Discount Amount" :=
              -((SalesLine."Line Discount Amount" + SalesLine."Inv. Discount Amount") *
                Factor - RemDiscAmt);
        RemAmt := ItemJnlLine.Amount - Round(ItemJnlLine.Amount);
        RemDiscAmt := ItemJnlLine."Discount Amount" - Round(ItemJnlLine."Discount Amount");
        ItemJnlLine.Amount := Round(ItemJnlLine.Amount);
        ItemJnlLine."Discount Amount" := Round(ItemJnlLine."Discount Amount");
    end;

    local procedure CalcItemJnlAmountsFromQtyToBeShipped(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal)
    var
        InvDiscAmountPerShippedQty: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCalcItemJnlAmountsFromQtyToBeShipped(ItemJnlLine, SalesHeader, SalesLine, QtyToBeShipped, IsHandled, InvDiscAmountPerShippedQty, RemAmt);
        if IsHandled then
            exit;

        InvDiscAmountPerShippedQty := Abs(SalesLine."Inv. Discount Amount") * QtyToBeShipped / SalesLine.Quantity;
        ItemJnlLine.Amount := QtyToBeShipped * SalesLine."Unit Price";
        if SalesHeader."Prices Including VAT" then
            ItemJnlLine.Amount :=
              -((ItemJnlLine.Amount * (1 - SalesLine."Line Discount %" / 100) - InvDiscAmountPerShippedQty) /
                (1 + SalesLine."VAT %" / 100) - RemAmt)
        else
            ItemJnlLine.Amount :=
              -(ItemJnlLine.Amount * (1 - SalesLine."Line Discount %" / 100) - InvDiscAmountPerShippedQty - RemAmt);
        RemAmt := ItemJnlLine.Amount - Round(ItemJnlLine.Amount);
        if SalesHeader."Currency Code" <> '' then
            ItemJnlLine.Amount :=
              Round(
                CurrExchRate.ExchangeAmtFCYToLCY(
                  SalesHeader."Posting Date", SalesHeader."Currency Code",
                  ItemJnlLine.Amount, SalesHeader."Currency Factor"))
        else
            ItemJnlLine.Amount := Round(ItemJnlLine.Amount);
    end;

    /// <summary>
    /// Gets global document headers that were created during posting
    /// </summary>
    /// <param name="NewSalesShptHeader">Return value: Sales Shipment Header</param>
    /// <param name="NewSalesInvHeader">Return value: Sales Invoice Header</param>
    /// <param name="NewSalesCrMemoHeader">Return value: Sales Credit Memo Header</param>
    /// <param name="NewReturnRcptHeader">Return value: Return Receipt Header</param>
    procedure GetGlobaDocumentsHeaders(var NewSalesShptHeader: Record "Sales Shipment Header"; var NewSalesInvHeader: Record "Sales Invoice Header"; var NewSalesCrMemoHeader: Record "Sales Cr.Memo Header"; var NewReturnRcptHeader: Record "Return Receipt Header")
    begin
        NewSalesShptHeader := SalesShptHeader;
        NewSalesInvHeader := SalesInvHeader;
        NewReturnRcptHeader := ReturnRcptHeader;
        NewSalesCrMemoHeader := SalesCrMemoHeader;
    end;

    /// <summary>
    /// Gets global warehouse posting flags that were set during posting
    /// </summary>
    /// <param name="NewWhseShip">Return value: Warehouse Shipment</param>
    /// <param name="NewWhseReceive">Return value: Warehouse Receipt</param>
    /// <param name="NewInvtPickPutaway">Return value: Inventory Pick/Put-Away</param>
    procedure GetGlobalWhseFlags(var NewWhseShip: Boolean; var NewWhseReceive: Boolean; var NewInvtPickPutaway: Boolean)
    begin
        NewWhseShip := WhseShip;
        NewWhseReceive := WhseReceive;
        NewInvtPickPutaway := InvtPickPutaway;
    end;

    /// <summary>
    /// Gets the Temp Set of Invoiced Tracking Specification lines
    /// </summary>
    /// <remarks>
    /// When Tracking Specification is posted for the line, if line is invoiced (Qty. to Invoice is not 0), the line's tracking information is stored in this buffer
    /// </remarks>
    /// <param name="NewTempTrackingSpecificationInv">Return value: Temp Tracking Specification lines that were Invoiced</param>
    procedure GetGlobalTempTrackingSpecificationInv(var NewTempTrackingSpecificationInv: Record "Tracking Specification" temporary)
    begin
        NewTempTrackingSpecificationInv.Copy(TempTrackingSpecificationInv, true);
    end;

    /// <summary>
    /// Gets the Temp Set of Posted Tracking Specification lines that were posted for the document
    /// </summary>
    /// <param name="NewTempTrackingSpecification">Return value: Temp Tracking Specification lines that were Posted</param>
    procedure GetGlobalTempTrackingSpecification(var NewTempTrackingSpecification: Record "Tracking Specification" temporary)
    begin
        NewTempTrackingSpecification.Copy(TempTrackingSpecification, true);
    end;

    /// <summary>
    /// Gets the Source Code that was used during posting
    /// </summary>
    /// <param name="NewSrcCode">Return value: Source Code</param>
    procedure GetGlobalSrcCode(var NewSrcCode: Code[10])
    begin
        NewSrcCode := SrcCode;
    end;

    local procedure ClearRemAmtIfNotItemJnlRollRndg(SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeClearRemAmtIfNotItemJnlRollRndg(SalesLine, ItemJnlRollRndg, RemAmt, RemDiscAmt, IsHandled);
        if IsHandled then
            exit;

        if not ItemJnlRollRndg then begin
            RemAmt := 0;
            RemDiscAmt := 0;
        end;
    end;

    local procedure PostItemJnlLineCopyDocumentFields(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; QtyToBeInvoiced: Decimal)
    var
        QtyToBeShippedIsZero: Boolean;
    begin
        QtyToBeShippedIsZero := QtyToBeShipped = 0;
        OnBeforePostItemJnlLineCopyDocumentFields(SalesHeader, QtyToBeShipped, QtyToBeShippedIsZero);

        if QtyToBeShippedIsZero then
            if SalesLine.IsCreditDocType() then
                ItemJnlLine.CopyDocumentFields(
                  ItemJnlLine."Document Type"::"Sales Credit Memo", GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode, SalesHeader."Posting No. Series")
            else
                ItemJnlLine.CopyDocumentFields(
                  ItemJnlLine."Document Type"::"Sales Invoice", GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode, SalesHeader."Posting No. Series")
        else begin
            if SalesLine.IsCreditDocType() then
                ItemJnlLine.CopyDocumentFields(
                  ItemJnlLine."Document Type"::"Sales Return Receipt",
                  ReturnRcptHeader."No.", ReturnRcptHeader."External Document No.", SrcCode, ReturnRcptHeader."No. Series")
            else
                ItemJnlLine.CopyDocumentFields(
                  ItemJnlLine."Document Type"::"Sales Shipment", SalesShptHeader."No.", SalesShptHeader."External Document No.", SrcCode,
                  SalesShptHeader."No. Series");
            if QtyToBeInvoiced <> 0 then begin
                if ItemJnlLine."Document No." = '' then
                    if SalesLine."Document Type" = SalesLine."Document Type"::"Credit Memo" then
                        ItemJnlLine.CopyDocumentFields(
                          ItemJnlLine."Document Type"::"Sales Credit Memo", GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode, SalesHeader."Posting No. Series")
                    else
                        ItemJnlLine.CopyDocumentFields(
                          ItemJnlLine."Document Type"::"Sales Invoice", GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode, SalesHeader."Posting No. Series");
                ItemJnlLine."Posting No. Series" := SalesHeader."Posting No. Series";
            end;
        end;

        OnPostItemJnlLineOnAfterCopyDocumentFields(ItemJnlLine, SalesLine, TempWhseRcptHeader, TempWhseShptHeader);
    end;

    /// <summary>
    /// Posts Item Charges for a sales line
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="OriginalItemJnlLine">The original Item Journal Line that was posted for the sales line. It servers as the basis for Item Journal Lines that are created for Item Charges.</param>
    /// <param name="ItemShptEntryNo">Item Shipment Entry No. that is assigned to journal lines for Item Charges.</param>
    procedure PostItemJnlLineItemCharges(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var OriginalItemJnlLine: Record "Item Journal Line"; ItemShptEntryNo: Integer)
    var
        ItemChargeSalesLine: Record "Sales Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemJnlLineItemCharges(SalesLine, IsHandled);
        if IsHandled then
            exit;

        ClearItemChargeAssgntFilter();
        TempItemChargeAssgntSales.SetCurrentKey(
          "Applies-to Doc. Type", "Applies-to Doc. No.", "Applies-to Doc. Line No.");
        TempItemChargeAssgntSales.SetRange("Applies-to Doc. Type", SalesLine."Document Type");
        TempItemChargeAssgntSales.SetRange("Applies-to Doc. No.", SalesLine."Document No.");
        TempItemChargeAssgntSales.SetRange("Applies-to Doc. Line No.", SalesLine."Line No.");
        if TempItemChargeAssgntSales.FindSet() then
            repeat
                SalesLine.TestField("Allow Item Charge Assignment");
                GetItemChargeLine(SalesHeader, ItemChargeSalesLine);
                OnPostItemJnlLineItemChargesOnAfterGetItemChargeLine(ItemChargeSalesLine, SalesLine);
                ItemChargeSalesLine.CalcFields("Qty. Assigned");
                if (ItemChargeSalesLine."Qty. to Invoice" <> 0) or
                   (Abs(ItemChargeSalesLine."Qty. Assigned") < Abs(ItemChargeSalesLine."Quantity Invoiced"))
                then begin
                    OriginalItemJnlLine."Item Shpt. Entry No." := ItemShptEntryNo;
                    PostItemChargePerOrder(SalesHeader, SalesLine, OriginalItemJnlLine, ItemChargeSalesLine);
                    TempItemChargeAssgntSales.Mark(true);
                end;
            until TempItemChargeAssgntSales.Next() = 0;
    end;

    /// <summary>
    /// Adds Tracking Specification for a sales line to the global temp tables where it will later be posted from
    /// </summary>
    /// <remarks>
    /// If line is being invoiced, it's additionally stored in TempTrackingSpecificationInv,
    /// and if Warehouse Journal Lines are being posted, it's also stored in TempWhseTrackingSpecification
    /// </remarks>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="TempWhseTrackingSpecification">Return value: Temp Tracking Specification lines realted to Warehouse Journal Lines</param>
    /// <param name="PostWhseJnlLine">A flag indicating whether Warehouse Journal Lines should be posted for the sales line.</param>
    /// <param name="QtyToBeInvoiced">The quantity of the Item to be invoiced.</param>
    /// <param name="TempTrackingSpec">Return value: Temp Tracking Specification lines related to the Item Journal Line</param>
    procedure PostItemJnlLineTracking(SalesLine: Record "Sales Line"; var TempWhseTrackingSpecification: Record "Tracking Specification" temporary; PostWhseJnlLine: Boolean; QtyToBeInvoiced: Decimal; var TempTrackingSpec: Record "Tracking Specification" temporary)
    var
        ShouldInsertTrkgSpecInv: Boolean;
    begin
        if ItemJnlPostLine.CollectTrackingSpecification(TempTrackingSpec) then
            if TempTrackingSpec.FindSet() then
                repeat
                    TempTrackingSpecification := TempTrackingSpec;
                    TempTrackingSpecification.SetSourceFromSalesLine(SalesLine);
                    OnPostItemJnlLineTrackingOnBeforeInsertTempTrkgSpec(TempTrackingSpecification, TempTrackingSpec, SalesLine);
                    if TempTrackingSpecification.Insert() then;
                    ShouldInsertTrkgSpecInv := QtyToBeInvoiced <> 0;
                    OnPostItemJnlLineTrackingOnAfterCalcShouldInsertTrkgSpecInv(SalesLine, QtyToBeInvoiced, ShouldInsertTrkgSpecInv); // <-- NEW EVENT
                    if ShouldInsertTrkgSpecInv then begin
                        TempTrackingSpecificationInv := TempTrackingSpecification;
                        if TempTrackingSpecificationInv.Insert() then;
                    end;
                    if PostWhseJnlLine then begin
                        TempWhseTrackingSpecification := TempTrackingSpecification;
                        if TempWhseTrackingSpecification.Insert() then;
                    end;
                until TempTrackingSpec.Next() = 0;
    end;

    /// <summary>
    /// Splits the incoming Warehouse Journal Line into more lines if tracking is required and posts them
    /// </summary>
    /// <param name="TempWhseJnlLine">The Warehouse Journal Line to be posted.</param>
    /// <param name="TempWhseTrackingSpecification">The Tracking Specification Record Set for the Warehouse Journal Line.</param>
    procedure PostItemJnlLineWhseLine(var TempWhseJnlLine: Record "Warehouse Journal Line" temporary; var TempWhseTrackingSpecification: Record "Tracking Specification" temporary)
    var
        TempWhseJnlLine2: Record "Warehouse Journal Line" temporary;
        WMSMgt: Codeunit "WMS Management";
    begin
        OnBeforePostItemJournalLineWarehouseLine(TempWhseJnlLine, TempWhseTrackingSpecification);
        ItemTrackingMgt.SplitWhseJnlLine(TempWhseJnlLine, TempWhseJnlLine2, TempWhseTrackingSpecification, false);
        if TempWhseJnlLine2.FindSet() then
            repeat
                OnPostItemJnlLineWhseLineOnBeforePostTempWhseJnlLine2(TempWhseJnlLine2, WhseShip, WhseReceive, InvtPickPutaway);
                if TempWhseJnlLine2."Location Code" <> '' then
                    WMSMgt.CheckWhseJnlLine(TempWhseJnlLine2, 1, 0, false);
                WhseJnlPostLine.Run(TempWhseJnlLine2);
            until TempWhseJnlLine2.Next() = 0;
        TempWhseTrackingSpecification.DeleteAll();
        OnAfterPostItemJournalLineWarehouseLine(TempWhseJnlLine, TempWhseTrackingSpecification);
    end;

    /// <summary>
    /// Prepares Warehouse Journal Line and Reservation Entries for later posting
    /// </summary>
    /// <param name="ItemJnlLine">The Item Journal Line to be posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="TempWhseJnlLine">Return value: The Warehouse Journal Line information that gets populated if the sales line requires Warehouse Journal Line to be posted.</param>
    /// <param name="PostWhseJnlLine">Return value: A flag indicating whether Warehouse Journal Lines should be posted for the sales line.</param>
    /// <param name="QtyToBeShippedBase">The base quantity of the Item to be shipped.</param>
    /// <param name="TrackingSpecification">Tracking Specification for the sales line. This parameter is exposed through events, but isn't directly used in the procedure</param>
    procedure PostItemJnlLineBeforePost(var ItemJnlLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; var TempWhseJnlLine: Record "Warehouse Journal Line" temporary; var PostWhseJnlLine: Boolean; QtyToBeShippedBase: Decimal; TrackingSpecification: Record "Tracking Specification")
    var
        CheckApplFromItemEntry: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemJnlLineBeforePost(SalesLine, ItemJnlLine, TempWhseJnlLine, Location, PostWhseJnlLine, QtyToBeShippedBase, IsHandled, TrackingSpecification);
        if IsHandled then
            exit;

        if SalesSetup."Exact Cost Reversing Mandatory" and (SalesLine.Type = SalesLine.Type::Item) then
            if SalesLine.IsCreditDocType() then
                CheckApplFromItemEntry := SalesLine.Quantity > 0
            else
                CheckApplFromItemEntry := SalesLine.Quantity < 0;

        if (SalesLine."Location Code" <> '') and (SalesLine.Type = SalesLine.Type::Item) and (ItemJnlLine.Quantity <> 0) then
            if ShouldPostWhseJnlLine(SalesLine) then begin
                CreateWhseJnlLine(ItemJnlLine, SalesLine, TempWhseJnlLine);
                PostWhseJnlLine := true;
            end;

        OnPostItemJnlLineOnBeforeTransferReservToItemJnlLine(SalesLine, ItemJnlLine, CheckApplFromItemEntry, TrackingSpecification, QtyToBeShippedBase);

        if QtyToBeShippedBase <> 0 then begin
            if SalesLine.IsCreditDocType() then
                SalesLineReserve.TransferSalesLineToItemJnlLine(SalesLine, ItemJnlLine, QtyToBeShippedBase, CheckApplFromItemEntry, false)
            else
                TransferReservToItemJnlLine(
                  SalesLine, ItemJnlLine, -QtyToBeShippedBase, TempTrackingSpecification, CheckApplFromItemEntry);

            if CheckApplFromItemEntry and SalesLine.IsInventoriableItem() then
                SalesLine.TestField("Appl.-from Item Entry");
        end;

        OnAfterPostItemJnlLineBeforePost(ItemJnlLine, SalesLine, QtyToBeShippedBase, ItemJnlPostLine, CheckApplFromItemEntry, TrackingSpecification);
    end;

    /// <summary>
    /// Checks wheter a Warehouse Journal Line should be posted for a sales line
    /// </summary>
    /// <param name="SalesLine">The sales line for which the check is performed.</param>
    /// <returns>true if a Warehouse Journal Line should be posted for the sales line; otherwise, false.</returns>
    procedure ShouldPostWhseJnlLine(SalesLine: Record "Sales Line") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        OnBeforeShouldPostWhseJnlLine(SalesLine, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if SalesLine.IsInventoriableItem() then begin
            GetLocation(SalesLine."Location Code");
            if ((SalesLine."Document Type" in [SalesLine."Document Type"::Invoice, SalesLine."Document Type"::"Credit Memo"]) and
                Location."Directed Put-away and Pick") or
               (Location."Bin Mandatory" and not (WhseShip or WhseReceive or InvtPickPutaway or SalesLine."Drop Shipment"))
            then
                exit(true);
        end;
        exit(false);
    end;

    local procedure PostItemChargePerOrder(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; ItemJnlLine2: Record "Item Journal Line"; ItemChargeSalesLine: Record "Sales Line")
    var
        NonDistrItemJnlLine: Record "Item Journal Line";
        QtyToInvoice: Decimal;
        Factor: Decimal;
        OriginalAmt: Decimal;
        OriginalDiscountAmt: Decimal;
        OriginalQty: Decimal;
        SignFactor: Integer;
        IsHandled: Boolean;
    begin
        OnBeforePostItemChargePerOrder(SalesHeader, SalesLine, ItemJnlLine2, ItemChargeSalesLine, SuppressCommit);

        IsHandled := false;
        OnPostItemChargePerOrderOnBeforeTestJobNo(SalesLine, IsHandled);
        if not IsHandled then
            SalesLine.TestField("Job No.", '');
        SalesLine.TestField("Allow Item Charge Assignment", true);

        ItemJnlLine2."Document No." := GenJnlLineDocNo;
        ItemJnlLine2."External Document No." := GenJnlLineExtDocNo;
        ItemJnlLine2."Item Charge No." := TempItemChargeAssgntSales."Item Charge No.";
        ItemJnlLine2.Description := ItemChargeSalesLine.Description;
        ItemJnlLine2."Unit of Measure Code" := '';
        ItemJnlLine2."Qty. per Unit of Measure" := 1;
        ItemJnlLine2."Applies-from Entry" := 0;
        if TempItemChargeAssgntSales."Document Type" in [TempItemChargeAssgntSales."Document Type"::"Return Order", TempItemChargeAssgntSales."Document Type"::"Credit Memo"] then
            QtyToInvoice :=
              CalcQtyToInvoice(SalesLine."Return Qty. to Receive (Base)", SalesLine."Qty. to Invoice (Base)")
        else
            QtyToInvoice :=
              CalcQtyToInvoice(SalesLine."Qty. to Ship (Base)", SalesLine."Qty. to Invoice (Base)");
        if ItemJnlLine2."Invoiced Quantity" = 0 then begin
            ItemJnlLine2."Invoiced Quantity" := ItemJnlLine2.Quantity;
            ItemJnlLine2."Invoiced Qty. (Base)" := ItemJnlLine2."Quantity (Base)";
        end;
        ItemJnlLine2."Document Line No." := ItemChargeSalesLine."Line No.";

        ItemJnlLine2.Amount := TempItemChargeAssgntSales."Amount to Handle" * ItemJnlLine2."Invoiced Qty. (Base)" / QtyToInvoice;
        if TempItemChargeAssgntSales."Document Type" in [TempItemChargeAssgntSales."Document Type"::"Return Order", TempItemChargeAssgntSales."Document Type"::"Credit Memo"] then
            ItemJnlLine2.Amount := -ItemJnlLine2.Amount;
        ItemJnlLine2."Unit Cost (ACY)" :=
          Round(ItemJnlLine2.Amount / ItemJnlLine2."Invoiced Qty. (Base)",
            Currency."Unit-Amount Rounding Precision");

        PreciseTotalChargeAmt += ItemJnlLine2.Amount;

        if SalesHeader."Currency Code" <> '' then
            ItemJnlLine2.Amount :=
              CurrExchRate.ExchangeAmtFCYToLCY(
                SalesHeader.GetUseDate(), SalesHeader."Currency Code", PreciseTotalChargeAmt + TotalSalesLine.Amount, SalesHeader."Currency Factor") -
              RoundedPrevTotalChargeAmt - TotalSalesLineLCY.Amount
        else
            ItemJnlLine2.Amount := PreciseTotalChargeAmt - RoundedPrevTotalChargeAmt;

        RoundedPrevTotalChargeAmt += Round(ItemJnlLine2.Amount, GLSetup."Amount Rounding Precision");

        ItemJnlLine2."Unit Cost" := Round(
            ItemJnlLine2.Amount / ItemJnlLine2."Invoiced Qty. (Base)", GLSetup."Unit-Amount Rounding Precision");
        ItemJnlLine2."Applies-to Entry" := ItemJnlLine2."Item Shpt. Entry No.";

        if SalesHeader."Currency Code" <> '' then
            ItemJnlLine2."Discount Amount" := Round(
                CurrExchRate.ExchangeAmtFCYToLCY(
                  SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                  (ItemChargeSalesLine."Inv. Discount Amount" + ItemChargeSalesLine."Line Discount Amount") *
                  ItemJnlLine2."Invoiced Qty. (Base)" / ItemChargeSalesLine."Quantity (Base)" *
                  TempItemChargeAssgntSales."Qty. to Handle" / QtyToInvoice,
                  SalesHeader."Currency Factor"),
                GLSetup."Amount Rounding Precision")
        else
            ItemJnlLine2."Discount Amount" := Round(
                (ItemChargeSalesLine."Inv. Discount Amount" + ItemChargeSalesLine."Line Discount Amount") *
                ItemJnlLine2."Invoiced Qty. (Base)" / ItemChargeSalesLine."Quantity (Base)" *
                TempItemChargeAssgntSales."Qty. to Handle" / QtyToInvoice,
                GLSetup."Amount Rounding Precision");

        if SalesLine.IsCreditDocType() then
            ItemJnlLine2."Discount Amount" := -ItemJnlLine2."Discount Amount";
        ItemJnlLine2."Shortcut Dimension 1 Code" := ItemChargeSalesLine."Shortcut Dimension 1 Code";
        ItemJnlLine2."Shortcut Dimension 2 Code" := ItemChargeSalesLine."Shortcut Dimension 2 Code";
        ItemJnlLine2."Dimension Set ID" := ItemChargeSalesLine."Dimension Set ID";
        UpdateItemJnlLineDimSetIDFromAppliedShipmentEntry(ItemJnlLine2);
        ItemJnlLine2."Gen. Prod. Posting Group" := ItemChargeSalesLine."Gen. Prod. Posting Group";

        OnPostItemChargePerOrderOnAfterCopyToItemJnlLine(
          ItemJnlLine2, ItemChargeSalesLine, GLSetup, QtyToInvoice, TempItemChargeAssgntSales);

        TempTrackingSpecificationInv.Reset();
        TempTrackingSpecificationInv.SetRange("Source Type", DATABASE::"Sales Line");
        TempTrackingSpecificationInv.SetRange("Source ID", TempItemChargeAssgntSales."Applies-to Doc. No.");
        TempTrackingSpecificationInv.SetRange("Source Ref. No.", TempItemChargeAssgntSales."Applies-to Doc. Line No.");
        IsHandled := false;
        OnPostItemChargePerOrderOnAfterTempTrackingSpecificationInvSetFilters(SalesHeader, ItemJnlLine2, TempTrackingSpecificationInv, SalesLine, IsHandled, TotalSalesLineLCY, TotalSalesLine);
        if not IsHandled then
            if TempTrackingSpecificationInv.IsEmpty() then
                RunItemJnlPostLine(ItemJnlLine2)
            else begin
                TempTrackingSpecificationInv.FindSet();
                NonDistrItemJnlLine := ItemJnlLine2;
                OriginalAmt := NonDistrItemJnlLine.Amount;
                OriginalDiscountAmt := NonDistrItemJnlLine."Discount Amount";
                OriginalQty := NonDistrItemJnlLine."Quantity (Base)";
                if (TempTrackingSpecificationInv."Quantity (Base)" / OriginalQty) > 0 then
                    SignFactor := 1
                else
                    SignFactor := -1;
                repeat
                    Factor := TempTrackingSpecificationInv."Quantity (Base)" / OriginalQty * SignFactor;
                    if Abs(TempTrackingSpecificationInv."Quantity (Base)") < Abs(NonDistrItemJnlLine."Quantity (Base)") then begin
                        ItemJnlLine2."Quantity (Base)" := -TempTrackingSpecificationInv."Quantity (Base)";
                        ItemJnlLine2."Invoiced Qty. (Base)" := ItemJnlLine2."Quantity (Base)";

                        if SalesHeader."Currency Code" <> '' then begin
                            PreciseTotalChargeAmt +=
                              CurrExchRate.ExchangeAmtLCYToFCY(
                                SalesHeader.GetUseDate(), SalesHeader."Currency Code", OriginalAmt * Factor, SalesHeader."Currency Factor");
                            ItemJnlLine2.Amount :=
                              CurrExchRate.ExchangeAmtFCYToLCY(
                                SalesHeader.GetUseDate(), SalesHeader."Currency Code", PreciseTotalChargeAmt + TotalSalesLine.Amount, SalesHeader."Currency Factor") -
                              RoundedPrevTotalChargeAmt - TotalSalesLineLCY.Amount;
                        end else begin
                            PreciseTotalChargeAmt += OriginalAmt * Factor;
                            ItemJnlLine2.Amount := PreciseTotalChargeAmt - RoundedPrevTotalChargeAmt;
                        end;

                        ItemJnlLine2.Amount :=
                            Round(ItemJnlLine2.Amount, GLSetup."Amount Rounding Precision");

                        RoundedPrevTotalChargeAmt += ItemJnlLine2.Amount;

                        ItemJnlLine2."Discount Amount" :=
                          Round(OriginalDiscountAmt * Factor, GLSetup."Amount Rounding Precision");
                        ItemJnlLine2."Unit Cost" :=
                          Round(ItemJnlLine2.Amount / ItemJnlLine2."Invoiced Qty. (Base)",
                            GLSetup."Unit-Amount Rounding Precision") * SignFactor;
                        ItemJnlLine2."Item Shpt. Entry No." := TempTrackingSpecificationInv."Item Ledger Entry No.";
                        ItemJnlLine2."Applies-to Entry" := TempTrackingSpecificationInv."Item Ledger Entry No.";
                        ItemJnlLine2.CopyTrackingFromSpec(TempTrackingSpecificationInv);
                        IsHandled := false;
                        OnPostItemChargePerOrderOnBeforeRunWithCheck(ItemJnlLine2, IsHandled, SalesLine);
                        if not IsHandled then
                            RunItemJnlPostLine(ItemJnlLine2);
                        ItemJnlLine2."Location Code" := NonDistrItemJnlLine."Location Code";
                        NonDistrItemJnlLine."Quantity (Base)" -= ItemJnlLine2."Quantity (Base)";
                        NonDistrItemJnlLine.Amount -= ItemJnlLine2.Amount;
                        NonDistrItemJnlLine."Discount Amount" -= ItemJnlLine2."Discount Amount";
                    end else begin // the last time
                        NonDistrItemJnlLine."Quantity (Base)" := -TempTrackingSpecificationInv."Quantity (Base)";
                        NonDistrItemJnlLine."Invoiced Qty. (Base)" := -TempTrackingSpecificationInv."Quantity (Base)";
                        NonDistrItemJnlLine."Unit Cost" :=
                          Round(NonDistrItemJnlLine.Amount / NonDistrItemJnlLine."Invoiced Qty. (Base)",
                            GLSetup."Unit-Amount Rounding Precision");
                        NonDistrItemJnlLine."Item Shpt. Entry No." := TempTrackingSpecificationInv."Item Ledger Entry No.";
                        NonDistrItemJnlLine."Applies-to Entry" := TempTrackingSpecificationInv."Item Ledger Entry No.";
                        NonDistrItemJnlLine.CopyTrackingFromSpec(TempTrackingSpecificationInv);
                        IsHandled := false;
                        OnPostItemChargePerOrderOnBeforeLastRunWithCheck(NonDistrItemJnlLine, SalesLine, IsHandled);
                        if not IsHandled then
                            RunItemJnlPostLine(NonDistrItemJnlLine);
                        NonDistrItemJnlLine."Location Code" := ItemJnlLine2."Location Code";
                    end;
                until TempTrackingSpecificationInv.Next() = 0;
            end;
    end;

    /// <summary>
    /// Checks if Item Charge should be distributed across multiple Item Ledger Entries and posts the charges
    /// </summary>
    /// <remarks>
    /// If Sales Shipment Line doesn't exist for the Item Charge Line of the sales line, an error is raised within CheckItemChargePerShpt().
    /// If no related Item Ledger Entries are found for the sales line, an error is raised.
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    procedure PostItemChargePerShpt(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    var
        SalesShptLine: Record "Sales Shipment Line";
        TempItemLedgEntry: Record "Item Ledger Entry" temporary;
        ItemTrackingMgt: Codeunit "Item Tracking Management";
        DistributeCharge: Boolean;
        IsHandled: Boolean;
    begin
        CheckItemChargePerShpt(SalesShptLine, SalesLine);
        IsHandled := false;
        OnPostItemChargePerShptOnAfterCheckItemChargePerShpt(SalesShptLine, TempItemChargeAssgntSales, DistributeCharge, IsHandled, SalesHeader, SalesLine);
        if IsHandled then
            exit;

        if SalesShptLine."Item Shpt. Entry No." <> 0 then
            DistributeCharge :=
              CostCalcMgt.SplitItemLedgerEntriesExist(
                TempItemLedgEntry, -SalesShptLine."Quantity (Base)", SalesShptLine."Item Shpt. Entry No.")
        else begin
            DistributeCharge := true;
            if not ItemTrackingMgt.CollectItemEntryRelation(TempItemLedgEntry,
                 DATABASE::"Sales Shipment Line", 0, SalesShptLine."Document No.",
                 '', 0, SalesShptLine."Line No.", -SalesShptLine."Quantity (Base)")
            then
                Error(RelatedItemLedgEntriesNotFoundErr);
        end;

        IsHandled := false;
        OnPostItemChargePerShptOnAfterCalcDistributeCharge(SalesHeader, SalesLine, SalesShptLine, TempItemLedgEntry, TempItemChargeAssgntSales, DistributeCharge, IsHandled);
        if not IsHandled then
            if DistributeCharge then
                PostDistributeItemCharge(
                    SalesHeader, SalesLine, TempItemLedgEntry, SalesShptLine."Quantity (Base)",
                    TempItemChargeAssgntSales."Qty. to Handle", TempItemChargeAssgntSales."Amount to Handle")
            else
                PostItemCharge(
                    SalesHeader, SalesLine, SalesShptLine."Item Shpt. Entry No.", SalesShptLine."Quantity (Base)",
                    TempItemChargeAssgntSales."Amount to Handle", TempItemChargeAssgntSales."Qty. to Handle");
    end;

    local procedure CheckItemChargePerShpt(var SalesShptLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        if not SalesShptLine.Get(
            TempItemChargeAssgntSales."Applies-to Doc. No.", TempItemChargeAssgntSales."Applies-to Doc. Line No.")
        then
            Error(ShipmentLinesDeletedErr);

        IsHandled := false;
        OnPostItemChargePerShptOnBeforeTestJobNo(SalesShptLine, IsHandled, SalesLine);
        if not IsHandled then
            SalesShptLine.TestField("Job No.", '');
    end;

    local procedure PostItemChargePerRetRcpt(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    var
        ReturnRcptLine: Record "Return Receipt Line";
        TempItemLedgEntry: Record "Item Ledger Entry" temporary;
        ItemTrackingMgt: Codeunit "Item Tracking Management";
        DistributeCharge: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemChargePerRetRcpt(SalesHeader, SalesLine, TempItemChargeAssgntSales, IsHandled);
        if IsHandled then
            exit;

        if not ReturnRcptLine.Get(
             TempItemChargeAssgntSales."Applies-to Doc. No.", TempItemChargeAssgntSales."Applies-to Doc. Line No.")
        then
            Error(ShipmentLinesDeletedErr);

        IsHandled := false;
        OnPostItemChargePerRetRcptOnBeforeTestFieldJobNo(ReturnRcptLine, IsHandled, SalesLine);
        if not IsHandled then
            ReturnRcptLine.TestField("Job No.", '');

        if ReturnRcptLine."Item Rcpt. Entry No." <> 0 then
            DistributeCharge :=
              CostCalcMgt.SplitItemLedgerEntriesExist(
                TempItemLedgEntry, ReturnRcptLine."Quantity (Base)", ReturnRcptLine."Item Rcpt. Entry No.")
        else begin
            DistributeCharge := true;
            if not ItemTrackingMgt.CollectItemEntryRelation(TempItemLedgEntry,
                 DATABASE::"Return Receipt Line", 0, ReturnRcptLine."Document No.",
                 '', 0, ReturnRcptLine."Line No.", ReturnRcptLine."Quantity (Base)")
            then
                Error(RelatedItemLedgEntriesNotFoundErr);
        end;

        IsHandled := false;
        OnPostItemChargePerRetRcptOnAfterCalcDistributeCharge(SalesHeader, SalesLine, ReturnRcptLine, TempItemLedgEntry, TempItemChargeAssgntSales, DistributeCharge, IsHandled);
        if not IsHandled then
            if DistributeCharge then
                PostDistributeItemCharge(
                    SalesHeader, SalesLine, TempItemLedgEntry, ReturnRcptLine."Quantity (Base)",
                    TempItemChargeAssgntSales."Qty. to Handle", TempItemChargeAssgntSales."Amount to Handle")
            else
                PostItemCharge(
                    SalesHeader, SalesLine, ReturnRcptLine."Item Rcpt. Entry No.", ReturnRcptLine."Quantity (Base)",
                    TempItemChargeAssgntSales."Amount to Handle", TempItemChargeAssgntSales."Qty. to Handle")
    end;

    /// <summary>
    /// Distributes the item charge across Item Ledger Entries and posts the charges
    /// </summary>
    /// <remarks>
    /// Throws an error if no Item Ledger Entries are found in the TempItemLedgerEntry Record Set
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being posted.</param>
    /// <param name="TempItemLedgEntry">Temp Set of Item Ledger Entries to distribute the charge across</param>
    /// <param name="NonDistrQuantity">The full quantity, used for calculating the factor for individual Item Ledger Entries</param>
    /// <param name="NonDistrQtyToAssign">The full quantity to assign to be distributed</param>
    /// <param name="NonDistrAmountToAssign">The full amount to be distributed</param>
    procedure PostDistributeItemCharge(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var TempItemLedgEntry: Record "Item Ledger Entry" temporary; NonDistrQuantity: Decimal; NonDistrQtyToAssign: Decimal; NonDistrAmountToAssign: Decimal)
    var
        Factor: Decimal;
        QtyToAssign: Decimal;
        AmountToAssign: Decimal;
        IsHandled: Boolean;
    begin
        OnBeforePostDistributeItemCharge(SalesHeader, SalesLine, TempItemLedgEntry, NonDistrQuantity, NonDistrQtyToAssign, NonDistrAmountToAssign, IsHandled);
        if IsHandled then
            exit;

        if TempItemLedgEntry.FindSet() then
            repeat
                Factor := Abs(TempItemLedgEntry.Quantity / NonDistrQuantity);
                OnPostDistributeItemChargeOnAfterSetFactor(TempItemLedgEntry, Factor);
                QtyToAssign := NonDistrQtyToAssign * Factor;
                AmountToAssign := Round(NonDistrAmountToAssign * Factor, GLSetup."Amount Rounding Precision");
                if Factor < 1 then begin
                    PostItemCharge(SalesHeader, SalesLine,
                      TempItemLedgEntry."Entry No.", -TempItemLedgEntry.Quantity,
                      AmountToAssign, QtyToAssign);
                    NonDistrQuantity := NonDistrQuantity + TempItemLedgEntry.Quantity;
                    NonDistrQtyToAssign := NonDistrQtyToAssign - QtyToAssign;
                    NonDistrAmountToAssign := NonDistrAmountToAssign - AmountToAssign;
                end else // the last time
                    PostItemCharge(SalesHeader, SalesLine,
                      TempItemLedgEntry."Entry No.", -TempItemLedgEntry.Quantity,
                      NonDistrAmountToAssign, NonDistrQtyToAssign);
            until TempItemLedgEntry.Next() = 0
        else
            Error(RelatedItemLedgEntriesNotFoundErr);
    end;

    /// <summary>
    /// Posts an associated item journal line for drop shipment or special order transactions.
    /// </summary>
    /// <param name="SalesHeader">The sales header record.</param>
    /// <param name="SalesLine">The sales line record.</param>
    /// <param name="QtyToBeShipped">The quantity to be shipped.</param>
    /// <param name="QtyToBeShippedBase">The quantity to be shipped in base unit of measure.</param>
    /// <returns>The item shipment entry number, or 0 if tracking was handled.</returns>
    procedure PostAssocItemJnlLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; QtyToBeShippedBase: Decimal): Integer
    var
        ItemJnlLine: Record "Item Journal Line";
        TempHandlingSpecification2: Record "Tracking Specification" temporary;
        ItemEntryRelation: Record "Item Entry Relation";
        PurchOrderHeader: Record "Purchase Header";
        PurchOrderLine: Record "Purchase Line";
        IsHandled: Boolean;
    begin
        PurchOrderHeader.Get(
          PurchOrderHeader."Document Type"::Order, SalesLine."Purchase Order No.");
        PurchOrderLine.Get(
          PurchOrderLine."Document Type"::Order, SalesLine."Purchase Order No.", SalesLine."Purch. Order Line No.");

        InitAssocItemJnlLine(ItemJnlLine, PurchOrderHeader, PurchOrderLine, SalesHeader, SalesLine, QtyToBeShipped, QtyToBeShippedBase);

        IsHandled := false;
        OnPostAssocItemJnlLineOnBeforePost(ItemJnlLine, PurchOrderLine, IsHandled);
        if (PurchOrderLine."Job No." = '') or IsHandled then begin
            TransferReservFromPurchLine(PurchOrderLine, ItemJnlLine, SalesLine, QtyToBeShippedBase);
            IsHandled := false;
            OnBeforePostAssocItemJnlLine(ItemJnlLine, PurchOrderLine, SuppressCommit, SalesLine, IsHandled);
            if not IsHandled then
                RunItemJnlPostLine(ItemJnlLine);

            // Handle Item Tracking
            if ItemJnlPostLine.CollectTrackingSpecification(TempHandlingSpecification2) then begin
                if TempHandlingSpecification2.FindSet() then
                    repeat
                        TempTrackingSpecification := TempHandlingSpecification2;
                        TempTrackingSpecification.SetSourceFromPurchLine(PurchOrderLine);
                        if TempTrackingSpecification.Insert() then;
                        ItemEntryRelation.InitFromTrackingSpec(TempHandlingSpecification2);
                        ItemEntryRelation.SetSource(DATABASE::"Purch. Rcpt. Line", 0, PurchOrderHeader."Receiving No.", PurchOrderLine."Line No.");
                        ItemEntryRelation.SetOrderInfo(PurchOrderLine."Document No.", PurchOrderLine."Line No.");
                        ItemEntryRelation.Insert();
                    until TempHandlingSpecification2.Next() = 0;
                exit(0);
            end;
        end;

        exit(ItemJnlLine."Item Shpt. Entry No.");
    end;

    /// <summary>
    /// Initializes an item journal line for associated purchase order posting.
    /// </summary>
    /// <param name="ItemJnlLine">The item journal line to initialize.</param>
    /// <param name="PurchOrderHeader">The purchase order header.</param>
    /// <param name="PurchOrderLine">The purchase order line.</param>
    /// <param name="SalesHeader">The sales header record.</param>
    /// <param name="SalesLine">The sales line record.</param>
    /// <param name="QtyToBeShipped">The quantity to be shipped.</param>
    /// <param name="QtyToBeShippedBase">The quantity to be shipped in base unit of measure.</param>
    procedure InitAssocItemJnlLine(var ItemJnlLine: Record "Item Journal Line"; PurchOrderHeader: Record "Purchase Header"; PurchOrderLine: Record "Purchase Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; QtyToBeShippedBase: Decimal)
    begin
        OnBeforeInitAssocItemJnlLine(ItemJnlLine, PurchOrderHeader, PurchOrderLine, SalesHeader, SalesLine);

        ItemJnlLine.Init();
        ItemJnlLine."Entry Type" := ItemJnlLine."Entry Type"::Purchase;
        ItemJnlLine.CopyDocumentFields(
          ItemJnlLine."Document Type"::"Purchase Receipt", PurchOrderHeader."Receiving No.", PurchOrderHeader."No.", SrcCode,
          PurchOrderHeader."Posting No. Series");

        ItemJnlLine.CopyFromPurchHeader(PurchOrderHeader);
        ItemJnlLine."Posting Date" := SalesHeader."Posting Date";
        ItemJnlLine."Document Date" := SalesHeader."Document Date";
        ItemJnlLine.CopyFromPurchLine(PurchOrderLine);

        ItemJnlLine.Quantity := QtyToBeShipped;
        ItemJnlLine."Quantity (Base)" := QtyToBeShippedBase;
        ItemJnlLine."Invoiced Quantity" := 0;
        ItemJnlLine."Invoiced Qty. (Base)" := 0;
        ItemJnlLine."Source Currency Code" := SalesHeader."Currency Code";
        ItemJnlLine.Amount := Round(PurchOrderLine.Amount * QtyToBeShipped / PurchOrderLine.Quantity);
        ItemJnlLine."Discount Amount" := PurchOrderLine."Line Discount Amount";

        ItemJnlLine."Applies-to Entry" := 0;

        OnAfterInitAssocItemJnlLine(ItemJnlLine, PurchOrderHeader, PurchOrderLine, SalesHeader, SalesLine, QtyToBeShipped, QtyToBeShippedBase);
    end;

    /// <summary>
    /// Executes various checks and updates for an Open or Pending Prepayment document and releases it
    /// </summary>
    /// <remarks>
    /// Changes are committed to the database if the PreviewMode flag is not set
    /// Open Linked ATOs (Assembly-to-Order documents) are reopened after the document is released
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document that is being released.</param>
    procedure ReleaseSalesDocument(var SalesHeader: Record "Sales Header")
    var
        SalesHeaderCopy: Record "Sales Header";
        TempAsmHeader: Record "Assembly Header" temporary;
        ReleaseSalesDocument: Codeunit "Release Sales Document";
        LinesWereModified: Boolean;
        SavedStatus: Enum "Sales Document Status";
        IsHandled: Boolean;
    begin
        OnBeforeReleaseSalesDocument(SalesHeader, PreviewMode);

        if not (SalesHeader.Status = SalesHeader.Status::Open) or (SalesHeader.Status = SalesHeader.Status::"Pending Prepayment") then
            exit;

        SalesHeaderCopy := SalesHeader;
        SavedStatus := SalesHeader.Status;
        GetOpenLinkedATOs(TempAsmHeader);
        OnBeforeReleaseSalesDoc(SalesHeader);
        LinesWereModified := ReleaseSalesDocument.ReleaseSalesHeader(SalesHeader, PreviewMode);
        if LinesWereModified then
            RefreshTempLines(SalesHeader, TempSalesLineGlobal);
        TestStatusRelease(SalesHeader);
        SalesHeader.Status := SavedStatus;
        RestoreSalesHeader(SalesHeader, SalesHeaderCopy);
        ReopenAsmOrders(TempAsmHeader);
        OnAfterReleaseSalesDoc(SalesHeader);
        if not (PreviewMode or SuppressCommit) then begin
            SalesHeader.Modify();
            Commit();
        end;
        IsHandled := false;
        OnReleaseSalesDocumentOnBeforeSetStatus(SalesHeader, IsHandled, SavedStatus, PreviewMode, SuppressCommit);
        if not IsHandled then
            SalesHeader.Status := SalesHeader.Status::Released;
    end;

    /// <summary>
    /// Checks if status of the document is Released
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document whose status is being checked.</param>
    local procedure TestStatusRelease(SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestStatusRelease(SalesHeader, IsHandled);
        if not IsHandled then
            SalesHeader.TestField(Status, SalesHeader.Status::Released);
    end;

    /// <summary>
    /// Checks varous sales line fields (quantities, tracking, posting groups) depending on the Type of the Line, to ensure it is valid for posting
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that is being posted.</param>
    /// <param name="SalesLine">The sales line of the document line that is being tested.</param>
    procedure TestSalesLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestSalesLine(SalesHeader, SalesLine, SuppressCommit, IsHandled);
        if IsHandled then
            exit;

        case SalesLine.Type of
            SalesLine.Type::Item:
                CheckItemTrackingQuantity(SalesLine, SalesHeader);
            SalesLine.Type::"Charge (Item)":
                TestSalesLineItemCharge(SalesLine);
            SalesLine.Type::"Fixed Asset":
                TestSalesLineFixedAsset(SalesLine)
            else
                TestSalesLineOthers(SalesLine);
        end;
        TestSalesLineJob(SalesLine);
        OnTestSalesLineOnAfterTestSalesLineJob(SalesLine);
        TestFieldsByDocType(SalesHeader, SalesLine);

        CheckBlockedPostingGroups(SalesLine);

        OnAfterTestSalesLine(SalesHeader, SalesLine, WhseShip, WhseReceive, SuppressCommit);
    end;

    local procedure TestFieldsByDocType(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    var
        ShouldTestQtyToShip: Boolean;
        ShouldTestReturnQty: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestFieldsByDocType(SalesHeader, SalesLine, IsHandled);
        if IsHandled then
            exit;

        case SalesLine."Document Type" of
            SalesLine."Document Type"::Order:
                SalesLine.TestField("Return Qty. to Receive", 0, ErrorInfo.Create());
            SalesLine."Document Type"::Invoice:
                begin
                    ShouldTestQtyToShip := SalesLine."Shipment No." = '';
                    OnTestSalesLineOnBeforeTestFieldQtyToShip(SalesLine, ShouldTestQtyToShip);
                    if ShouldTestQtyToShip then
                        SalesLine.TestField("Qty. to Ship", SalesLine.Quantity, ErrorInfo.Create());
                    SalesLine.TestField("Return Qty. to Receive", 0, ErrorInfo.Create());
                    SalesLine.TestField("Qty. to Invoice", SalesLine.Quantity, ErrorInfo.Create());
                end;
            SalesLine."Document Type"::"Return Order":
                SalesLine.TestField("Qty. to Ship", 0, ErrorInfo.Create());
            SalesLine."Document Type"::"Credit Memo":
                begin
                    ShouldTestReturnQty := SalesLine."Return Receipt No." = '';
                    OnTestSalesLineOnAfterCalcShouldTestReturnQty(SalesLine, ShouldTestReturnQty);
                    if ShouldTestReturnQty then
                        SalesLine.TestField("Return Qty. to Receive", SalesLine.Quantity, ErrorInfo.Create());
                    SalesLine.TestField("Qty. to Ship", 0, ErrorInfo.Create());
                    SalesLine.TestField("Qty. to Invoice", SalesLine.Quantity, ErrorInfo.Create());
                end;
        end;
    end;

    local procedure CheckBlockedPostingGroups(SalesLine: Record "Sales Line")
    var
        GeneralPostingSetup: Record "General Posting Setup";
        VATPostingSetup: Record "VAT Posting Setup";
        ForwardLinkMgt: Codeunit "Forward Link Mgt.";
    begin
        if not SalesLine.HasTypeToFillMandatoryFields() then
            exit;

        if GeneralPostingSetup.Get(SalesLine."Gen. Bus. Posting Group", SalesLine."Gen. Prod. Posting Group") then
            if GeneralPostingSetup.Blocked then
                ErrorMessageMgt.LogContextFieldError(
                SalesLine.FieldNo("Gen. Prod. Posting Group"),
                StrSubstNo(
                    SetupBlockedErr, GeneralPostingSetup.TableCaption(),
                    GeneralPostingSetup.FieldCaption("Gen. Bus. Posting Group"), GeneralPostingSetup."Gen. Bus. Posting Group",
                    GeneralPostingSetup.FieldCaption("Gen. Prod. Posting Group"), GeneralPostingSetup."Gen. Prod. Posting Group"),
                GeneralPostingSetup.RecordId(), GeneralPostingSetup.FieldNo(Blocked),
                ForwardLinkMgt.GetHelpCodeForFinancePostingGroups());

        if VATPostingSetup.Get(SalesLine."VAT Bus. Posting Group", SalesLine."VAT Prod. Posting Group") then
            if VATPostingSetup.Blocked then
                ErrorMessageMgt.LogContextFieldError(
                    SalesLine.FieldNo("VAT Prod. Posting Group"),
                    StrSubstNo(
                        SetupBlockedErr, VATPostingSetup.TableCaption(),
                        VATPostingSetup.FieldCaption("VAT Bus. Posting Group"), VATPostingSetup."VAT Bus. Posting Group",
                        VATPostingSetup.FieldCaption("VAT Prod. Posting Group"), VATPostingSetup."VAT Prod. Posting Group"),
                    VATPostingSetup.RecordId(), VATPostingSetup.FieldNo(Blocked),
                    ForwardLinkMgt.GetHelpCodeForFinanceSetupVAT());
    end;

    local procedure CheckItemTrackingQuantity(var SalesLine: Record "Sales Line"; var SalesHeader: Record "Sales Header")
    var
        TrackingSpecification: Record "Tracking Specification";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckItemTrackingQuantity(SalesLine, IsHandled, SalesHeader);
        if IsHandled then
            exit;
        SyncSurPlusItemTracking(SalesHeader, SalesLine);
        case SalesHeader."Document Type" of
            SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice:
                TrackingSpecification.CheckItemTrackingQuantity(DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.", SalesLine."Qty. to Ship (Base)", SalesLine."Qty. to Invoice (Base)", SalesHeader.Ship, SalesHeader.Invoice);
            SalesHeader."Document Type"::"Credit Memo", SalesHeader."Document Type"::"Return Order":
                TrackingSpecification.CheckItemTrackingQuantity(DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.", SalesLine."Return Qty. to Receive (Base)", SalesLine."Qty. to Invoice (Base)", SalesHeader.Receive, SalesHeader.Invoice);
            else
                OnCheckItemTrackingQuantityOnDocumentTypeCaseElse(SalesHeader, SalesLine);
        end;
    end;

    local procedure TestSalesLineItemCharge(SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestSalesLineItemCharge(SalesLine, IsHandled);
        if IsHandled then
            exit;

        if (SalesLine.Amount = 0) and (SalesLine.Quantity <> 0) then
            Error(ItemChargeZeroAmountErr, SalesLine."No.");
        SalesLine.TestField("Job No.", '', ErrorInfo.Create());
        SalesLine.TestField("Job Contract Entry No.", 0, ErrorInfo.Create());
    end;

    local procedure TestSalesLineFixedAsset(SalesLine: Record "Sales Line")
    var
        FixedAsset: Record "Fixed Asset";
        DeprBook: Record "Depreciation Book";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestSalesLineFixedAsset(SalesLine, IsHandled);
        if IsHandled then
            exit;

        SalesLine.TestField("Job No.", '', ErrorInfo.Create());
        SalesLine.TestField("Depreciation Book Code", ErrorInfo.Create());
        DeprBook.Get(SalesLine."Depreciation Book Code");
        DeprBook.TestField("G/L Integration - Disposal", true, ErrorInfo.Create());
        FixedAsset.Get(SalesLine."No.");
        FixedAsset.TestField("Budgeted Asset", false, ErrorInfo.Create());
    end;

    local procedure TestSalesLineJob(SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestSalesLineJob(SalesLine, IsHandled);
        if IsHandled then
            exit;

        if not (SalesLine."Document Type" in [SalesLine."Document Type"::Invoice, SalesLine."Document Type"::"Credit Memo"]) then
            SalesLine.TestField("Job No.", '', ErrorInfo.Create());
    end;

    local procedure TestSalesLineOthers(SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestSalesLineOthers(SalesLine, IsHandled);
        if IsHandled then
            exit;

        SalesLine.TestField("Depreciation Book Code", '', ErrorInfo.Create());
        SalesLine.TestField("Depr. until FA Posting Date", false, ErrorInfo.Create());
        SalesLine.TestField("FA Posting Date", 0D, ErrorInfo.Create());
        SalesLine.TestField("Duplicate in Depreciation Book", '', ErrorInfo.Create());
        SalesLine.TestField("Use Duplication List", false, ErrorInfo.Create());
    end;

    local procedure TestUpdatedSalesLine(SalesLine: Record "Sales Line")
    var
        ForwardLinkMgt: Codeunit "Forward Link Mgt.";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestUpdatedSalesLine(SalesLine, IsHandled, ErrorMessageMgt);
        if IsHandled then
            exit;

        if SalesLine."Drop Shipment" then begin
            if SalesLine.Type <> SalesLine.Type::Item then
                SalesLine.TestField("Drop Shipment", false);
            if (SalesLine."Qty. to Ship" <> 0) and (SalesLine."Purch. Order Line No." = 0) then
                ErrorMessageMgt.LogErrorMessage(SalesLine.FieldNo("Purchasing Code"), StrSubstNo(DropShipmentErr, SalesLine."Line No."),
                    0, 0, ForwardLinkMgt.GetHelpCodeForSalesLineDropShipmentErr());
        end;

        if SalesLine.Quantity = 0 then
            SalesLine.TestField(Amount, 0)
        else begin
            SalesLine.TestField("No.");
            SalesLine.TestField(Type);
            if not ApplicationAreaMgmt.IsSalesTaxEnabled() then
                TestGenPostingGroups(SalesLine);
        end;
    end;

    local procedure TestGenPostingGroups(var SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTestGenPostingGroups(SalesLine, IsHandled);
        if IsHandled then
            exit;

        SalesLine.TestField("Gen. Bus. Posting Group");
        SalesLine.TestField("Gen. Prod. Posting Group");
    end;

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

        if SalesHeader.Receive then begin
            SalesHeader.Receive := CheckTrackingAndWarehouseForReceive(SalesHeader);
            if not InvtPickPutaway then
                if CheckIfInvPutawayExists() then
                    Error(ErrorInfo.Create(InvPutAwayExistsErr, true, SalesHeader));
        end;
    end;

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

        if SalesHeader.Ship then begin
            SalesHeader.Ship := CheckTrackingAndWarehouseForShip(SalesHeader);
            if not InvtPickPutaway then
                if CheckIfInvPickExists(SalesHeader) then
                    Error(ErrorInfo.Create(InvPickExistsErr, true, SalesHeader));
        end;
    end;

    local procedure UpdatePostingNos(var SalesHeader: Record "Sales Header") ModifyHeader: Boolean
    begin
        OnBeforeUpdatePostingNos(SalesHeader, SuppressCommit, ModifyHeader);

        UpdateShippingNo(SalesHeader, ModifyHeader);

        UpdateReturnReceiptNo(SalesHeader, ModifyHeader);

        UpdatePostingNo(SalesHeader, ModifyHeader);

        OnAfterUpdatePostingNos(SalesHeader, SuppressCommit);
    end;

    local procedure UpdateShippingNo(var SalesHeader: Record "Sales Header"; var ModifyHeader: Boolean)
    var
        NoSeries: Codeunit "No. Series";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateShippingNo(SalesHeader, WhseShip, WhseReceive, InvtPickPutaway, PreviewMode, ModifyHeader, IsHandled);
        UpdateShippingNoTelemetry(SalesHeader);
        if IsHandled then
            exit;

        if SalesHeader.Ship and (SalesHeader."Shipping No." = '') then
            if (SalesHeader."Document Type" = SalesHeader."Document Type"::Order) or
               ((SalesHeader."Document Type" = SalesHeader."Document Type"::Invoice) and SalesSetup."Shipment on Invoice")
            then
                if not PreviewMode then begin
                    ResetPostingNoSeriesFromSetup(SalesHeader."Shipping No. Series", SalesSetup."Posted Shipment Nos.");
                    SalesHeader.TestField("Shipping No. Series");
                    SalesHeader."Shipping No." := NoSeries.GetNextNo(SalesHeader."Shipping No. Series", SalesHeader."Posting Date");
                    ModifyHeader := true;
                    if NoSeries.IsNoSeriesInDateOrder(SalesHeader."Shipping No. Series") then
                        DateOrderSeriesUsed := true;
                    // Check for posting conflicts.
                    if SalesShptHeader.Get(SalesHeader."Shipping No.") then
                        Error(SalesShptHeaderConflictErr, SalesHeader."Shipping No.");
                end;

        OnAfterUpdateShippingNo(SalesHeader, PreviewMode, ModifyHeader);
    end;

    local procedure UpdateShippingNoTelemetry(var SalesHeader: Record "Sales Header")
    var
        TelemetryCustomDimensions: Dictionary of [Text, Text];
        PreviewTokenFoundLbl: Label 'Preview token %1 found on fields.', Locked = true;
        PreviewToken: Text;
    begin
        if not Format(SalesHeader."Shipping No.").StartsWith(PostingPreviewNoTok) and
           not Format(SalesHeader."Return Receipt No.").StartsWith(PostingPreviewNoTok) and
           not Format(SalesHeader."Posting No.").StartsWith(PostingPreviewNoTok)
        then
            exit;

        TelemetryCustomDimensions.Add(SalesHeader.FieldCaption(SystemId), SalesHeader.SystemId);
        TelemetryCustomDimensions.Add(SalesHeader.FieldCaption("Document Type"), Format(SalesHeader."Document Type"));

        if Format(SalesHeader."Shipping No.").StartsWith(PostingPreviewNoTok) then begin
            PreviewToken := SalesHeader."Shipping No.";
            TelemetryCustomDimensions.Add(SalesHeader.FieldCaption("Shipping No."), SalesHeader."Shipping No.");
            SalesHeader."Shipping No." := '';
        end;
        if Format(SalesHeader."Return Receipt No.").StartsWith(PostingPreviewNoTok) then begin
            PreviewToken := SalesHeader."Return Receipt No.";
            TelemetryCustomDimensions.Add(SalesHeader.FieldCaption("Return Receipt No."), SalesHeader."Return Receipt No.");
            SalesHeader."Return Receipt No." := '';
        end;
        if Format(SalesHeader."Posting No.").StartsWith(PostingPreviewNoTok) then begin
            PreviewToken := SalesHeader."Posting No.";
            TelemetryCustomDimensions.Add(SalesHeader.FieldCaption("Posting No."), SalesHeader."Posting No.");
            SalesHeader."Posting No." := '';
        end;

        Session.LogMessage('0000CUV', StrSubstNo(PreviewTokenFoundLbl, PreviewToken), Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::All, TelemetryCustomDimensions);
    end;

    local procedure UpdatePostingNo(var SalesHeader: Record "Sales Header"; var ModifyHeader: Boolean)
    var
        NoSeries: Codeunit "No. Series";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdatePostingNo(SalesHeader, PreviewMode, ModifyHeader, IsHandled, DateOrderSeriesUsed);
        if IsHandled then
            exit;

        if SalesHeader.Invoice and (SalesHeader."Posting No." = '') then begin
            if (SalesHeader."No. Series" <> '') or
                (SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::"Return Order"])
            then begin
                if SalesHeader."Document Type" in [SalesHeader."Document Type"::"Return Order"] then
                    ResetPostingNoSeriesFromSetup(SalesHeader."Posting No. Series", SalesSetup."Posted Credit Memo Nos.")
                else
                    if (SalesHeader."Document Type" <> SalesHeader."Document Type"::"Credit Memo") then
                        ResetPostingNoSeriesFromSetup(SalesHeader."Posting No. Series", SalesSetup."Posted Invoice Nos.");
                if SalesHeader."Document Type" = SalesHeader."Document Type"::"Credit Memo" then
                    if (SalesSetup."Posted Credit Memo Nos." <> '') and (SalesHeader."Posting No. Series" = '') then
                        CheckDefaultNoSeries(SalesSetup."Posted Credit Memo Nos.");
                SalesHeader.TestField("Posting No. Series");
            end;
            if (SalesHeader."No. Series" <> SalesHeader."Posting No. Series") or
                (SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::"Return Order"])
            then
                if not PreviewMode then begin
                    SalesHeader."Posting No." := NoSeries.GetNextNo(SalesHeader."Posting No. Series", SalesHeader."Posting Date");
                    if NoSeries.IsNoSeriesInDateOrder(SalesHeader."Posting No. Series") then
                        DateOrderSeriesUsed := true;
                    ModifyHeader := true;
                end;

            // Check for posting conflicts.
            if not PreviewMode then
                if SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice] then begin
                    if SalesInvHeader.Get(SalesHeader."Posting No.") then
                        Error(SalesInvHeaderConflictErr, SalesHeader."Posting No.");
                end else
                    if SalesCrMemoHeader.Get(SalesHeader."Posting No.") then
                        Error(SalesCrMemoHeaderConflictErr, SalesHeader."Posting No.");
        end;
    end;

    local procedure UpdateReturnReceiptNo(var SalesHeader: Record "Sales Header"; var ModifyHeader: Boolean)
    var
        NoSeries: Codeunit "No. Series";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateReturnReceiptNo(SalesHeader, ModifyHeader, IsHandled, PreviewMode);
        if IsHandled then
            exit;

        if SalesHeader.Receive and (SalesHeader."Return Receipt No." = '') then
            if (SalesHeader."Document Type" = SalesHeader."Document Type"::"Return Order") or
               ((SalesHeader."Document Type" = SalesHeader."Document Type"::"Credit Memo") and SalesSetup."Return Receipt on Credit Memo")
            then
                if not PreviewMode then begin
                    ResetPostingNoSeriesFromSetup(SalesHeader."Return Receipt No. Series", SalesSetup."Posted Return Receipt Nos.");
                    SalesHeader.TestField("Return Receipt No. Series");
                    SalesHeader."Return Receipt No." := NoSeries.GetNextNo(SalesHeader."Return Receipt No. Series", SalesHeader."Posting Date");
                    ModifyHeader := true;
                    if NoSeries.IsNoSeriesInDateOrder(SalesHeader."Return Receipt No. Series") then
                        DateOrderSeriesUsed := true;
                    // Check for posting conflicts.
                    if ReturnRcptHeader.Get(SalesHeader."Return Receipt No.") then
                        Error(SalesReturnRcptHeaderConflictErr, SalesHeader."Return Receipt No.")
                end;

        OnAfterUpdateReturnReceiptNo(SalesHeader);
    end;

    local procedure ResetPostingNoSeriesFromSetup(var PostingNoSeries: Code[20]; SetupNoSeries: Code[20])
    begin
        if (PostingNoSeries = '') and (SetupNoSeries <> '') then
            PostingNoSeries := SetupNoSeries;
    end;

    local procedure UpdateAssociatedPurchaseOrder(var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; SalesHeader: Record "Sales Header")
    var
        PurchOrderHeader: Record "Purchase Header";
        PurchOrderLine: Record "Purchase Line";
        PurchLineReserve: Codeunit "Purch. Line-Reserve";
    begin
        TempDropShptPostBuffer.Reset();
        if TempDropShptPostBuffer.IsEmpty() then
            exit;
        Clear(PurchOrderHeader);
        TempDropShptPostBuffer.FindSet();
        repeat
            if PurchOrderHeader."No." <> TempDropShptPostBuffer."Order No." then begin
                PurchOrderHeader.Get(PurchOrderHeader."Document Type"::Order, TempDropShptPostBuffer."Order No.");
                CheckAndUpdateAssocOrderPostingDate(PurchOrderHeader, SalesHeader."Posting Date");
                PurchOrderHeader."Last Receiving No." := PurchOrderHeader."Receiving No.";
                PurchOrderHeader."Receiving No." := '';
                PurchOrderHeader.Modify();
                OnUpdateAssosOrderOnAfterPurchOrderHeaderModify(PurchOrderHeader);
                PurchLineReserve.UpdateItemTrackingAfterPosting(PurchOrderHeader);
            end;
            PurchOrderLine.Get(
              PurchOrderLine."Document Type"::Order,
              TempDropShptPostBuffer."Order No.", TempDropShptPostBuffer."Order Line No.");
            PurchOrderLine."Quantity Received" := PurchOrderLine."Quantity Received" + TempDropShptPostBuffer.Quantity;
            PurchOrderLine."Qty. Received (Base)" := PurchOrderLine."Qty. Received (Base)" + TempDropShptPostBuffer."Quantity (Base)";
            PurchOrderLine.InitOutstanding();
            PurchOrderLine.ClearQtyIfBlank();
            PurchOrderLine.InitQtyToReceive();
            OnUpdateAssocOrderOnBeforeModifyPurchLine(PurchOrderLine, TempDropShptPostBuffer);
            PurchOrderLine.Modify();
            OnUpdateAssocOrderOnAfterModifyPurchLine(PurchOrderLine, TempDropShptPostBuffer);
        until TempDropShptPostBuffer.Next() = 0;

        TempDropShptPostBuffer.DeleteAll();
    end;

    /// <summary>
    /// Removes the association between the sales line and the Purchase Line
    /// </summary>
    /// <param name="SalesOrderLine">The sales line for which the association is being removed.</param>
    procedure UpdateAssocLines(var SalesOrderLine: Record "Sales Line")
    var
        PurchOrderLine: Record "Purchase Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateAssocLines(SalesOrderLine, IsHandled);
        if IsHandled then
            exit;

        if not PurchOrderLine.Get(
                PurchOrderLine."Document Type"::Order,
                SalesOrderLine."Purchase Order No.", SalesOrderLine."Purch. Order Line No.")
        then
            exit;

        PurchOrderLine."Sales Order No." := '';
        PurchOrderLine."Sales Order Line No." := 0;
        PurchOrderLine.Modify();
        SalesOrderLine."Purchase Order No." := '';
        SalesOrderLine."Purch. Order Line No." := 0;
    end;

    local procedure UpdateAssosOrderPostingNos(SalesHeader: Record "Sales Header") DropShipment: Boolean
    var
        TempSalesLine: Record "Sales Line" temporary;
        PurchOrderHeader: Record "Purchase Header";
        NoSeries: Codeunit "No. Series";
        ReleasePurchaseDocument: Codeunit "Release Purchase Document";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateAssosOrderPostingNos(SalesHeader, TempSalesLineGlobal, PreviewMode, DropShipment, IsHandled);
        if IsHandled then
            exit(DropShipment);

        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter("Purch. Order Line No.", '<>0');
        OnUpdateAssosOrderPostingNosOnAfterSetFilterTempSalesLine(SalesHeader, TempSalesLine);
        DropShipment := not TempSalesLine.IsEmpty();
        TempSalesLine.SetFilter("Qty. to Ship", '<>0');
        if DropShipment and SalesHeader.Ship then
            if TempSalesLine.FindSet() then
                repeat
                    if PurchOrderHeader."No." <> TempSalesLine."Purchase Order No." then begin
                        PurchOrderHeader.Get(PurchOrderHeader."Document Type"::Order, TempSalesLine."Purchase Order No.");
                        PurchOrderHeader.TestField("Pay-to Vendor No.");
                        PurchOrderHeader.Receive := true;
                        OnUpdateAssosOrderPostingNosOnBeforeReleasePurchaseDocument(PurchOrderHeader, SalesHeader);
                        ReleasePurchaseDocument.ReleasePurchaseHeader(PurchOrderHeader, PreviewMode);
                        if PurchOrderHeader."Receiving No." = '' then begin
                            PurchOrderHeader.TestField("Receiving No. Series");
                            PurchOrderHeader."Receiving No." :=
                              NoSeries.GetNextNo(PurchOrderHeader."Receiving No. Series", SalesHeader."Posting Date");
                            OnUpdateAssosOrderPostingNosOnBeforeModifyPurchOrderHeader(PurchOrderHeader, SalesHeader);
                            PurchOrderHeader.Modify();
                        end;
                        OnUpdateAssosOrderPostingNosOnAfterReleasePurchaseDocument(PurchOrderHeader, SalesHeader);
                    end;
                until TempSalesLine.Next() = 0;

        OnAfterUpdateAssosOrderPostingNos(SalesHeader, TempSalesLine, DropShipment);
        exit(DropShipment);
    end;

    local procedure CheckAndUpdateAssocOrderPostingDate(var PurchaseHeader: Record "Purchase Header"; PostingDate: Date)
    var
        PurchasesPayablesSetup: Record "Purchases & Payables Setup";
        ReleasePurchaseDocument: Codeunit "Release Purchase Document";
        OriginalDocumentDate: Date;
    begin
        if (PostingDate <> 0D) and (PurchaseHeader."Posting Date" <> PostingDate) then begin
            ReleasePurchaseDocument.Reopen(PurchaseHeader);
            ReleasePurchaseDocument.SetSkipCheckReleaseRestrictions();

            OriginalDocumentDate := PurchaseHeader."Document Date";
            PurchaseHeader.SetHideValidationDialog(true);
            PurchaseHeader.Validate("Posting Date", PostingDate);

            PurchasesPayablesSetup.SetLoadFields("Link Doc. Date To Posting Date");
            PurchasesPayablesSetup.GetRecordOnce();
            if PurchasesPayablesSetup."Link Doc. Date To Posting Date" then
                PurchaseHeader.Validate("Document Date", PostingDate)
            else
                PurchaseHeader.Validate("Document Date", OriginalDocumentDate);

            ReleasePurchaseDocument.Run(PurchaseHeader);
        end;
    end;

    local procedure UpdateAfterPosting(SalesHeader: Record "Sales Header")
    var
        TempSalesLine: Record "Sales Line" temporary;
    begin
        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter("Qty. to Assemble to Order", '<>0');
        if TempSalesLine.FindSet() then
            repeat
                FinalizePostATO(TempSalesLine);
            until TempSalesLine.Next() = 0;

        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter("Blanket Order Line No.", '<>0');
        OnUpdateAfterPostingOnBeforeFindSetForUpdate(TempSalesLine, SalesHeader);
        if TempSalesLine.FindSet() then
            repeat
                UpdateBlanketOrderLine(TempSalesLine, SalesHeader.Ship, SalesHeader.Receive, SalesHeader.Invoice);
            until TempSalesLine.Next() = 0;

        OnAfterUpdateAfterPosting(SalesHeader, TempSalesLine);
    end;

    local procedure UpdateLastPostingNos(var SalesHeader: Record "Sales Header")
    begin
        if SalesHeader.Ship then begin
            SalesHeader."Last Shipping No." := SalesHeader."Shipping No.";
            SalesHeader."Shipping No." := '';
        end;
        if SalesHeader.Invoice then begin
            SalesHeader."Last Posting No." := SalesHeader."Posting No.";
            SalesHeader."Posting No." := '';
        end;
        if SalesHeader.Receive then begin
            SalesHeader."Last Return Receipt No." := SalesHeader."Return Receipt No.";
            SalesHeader."Return Receipt No." := '';
        end;

        OnAfterUpdateLastPostingNos(SalesHeader);
    end;

    local procedure UpdateSalesLineBeforePost(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        OnBeforeUpdateSalesLineBeforePost(SalesLine, SalesHeader, WhseShip, WhseReceive, RoundingLineInserted, SuppressCommit);

        if not (SalesHeader.Ship or RoundingLineInserted) then begin
            SalesLine."Qty. to Ship" := 0;
            SalesLine."Qty. to Ship (Base)" := 0;
        end;
        if not (SalesHeader.Receive or RoundingLineInserted) then begin
            SalesLine."Return Qty. to Receive" := 0;
            SalesLine."Return Qty. to Receive (Base)" := 0;
        end;

        JobContractLine := false;
        if (SalesLine.Type = SalesLine.Type::Item) or (SalesLine.Type = SalesLine.Type::"G/L Account") or (SalesLine.Type = SalesLine.Type::" ") then
            if SalesLine."Job Contract Entry No." > 0 then
                PostJobContractLine(SalesHeader, SalesLine);
        OnUpdateSalesLineBeforePostOnAfterPostJobContractLine(SalesInvHeader, SalesCrMemoHeader, SalesHeader, SalesLine);
        if SalesLine.Type = SalesLine.Type::Resource then
            JobTaskSalesLine := SalesLine;

        if (SalesHeader."Document Type" = SalesHeader."Document Type"::Invoice) and (SalesLine."Shipment No." <> '') then begin
            SalesLine."Quantity Shipped" := SalesLine.Quantity;
            SalesLine."Qty. Shipped (Base)" := SalesLine."Quantity (Base)";
            SalesLine."Qty. to Ship" := 0;
            SalesLine."Qty. to Ship (Base)" := 0;
        end;

        if (SalesHeader."Document Type" = SalesHeader."Document Type"::"Credit Memo") and (SalesLine."Return Receipt No." <> '') then begin
            SalesLine."Return Qty. Received" := SalesLine.Quantity;
            SalesLine."Return Qty. Received (Base)" := SalesLine."Quantity (Base)";
            SalesLine."Return Qty. to Receive" := 0;
            SalesLine."Return Qty. to Receive (Base)" := 0;
        end;

        InitSalesLineQtyToInvoice(SalesHeader, SalesLine);

        IsHandled := false;
        OnUpdateSalesLineBeforePostOnBeforeGetUnitCost(SalesLine, IsHandled);
        if not IsHandled then
            if (SalesLine.Type = SalesLine.Type::Item) and (SalesLine."No." <> '') then begin
                SalesLine.GetItem(Item);
                if (Item."Costing Method" = Item."Costing Method"::Standard) and not SalesLine.IsShipment() and not IsCreatedFromJob(SalesLine) then
                    SalesLine.GetUnitCost();
            end;

        OnAfterUpdateSalesLineBeforePost(SalesLine, SalesHeader, WhseShip, WhseReceive, SuppressCommit);
    end;

    local procedure IsCreatedFromJob(var SalesLine: Record "Sales Line"): Boolean
    begin
        if (SalesLine."Job No." <> '') and (SalesLine."Job Task No." <> '') and (SalesLine."Job Contract Entry No." <> 0) then
            exit(true);
    end;

    local procedure InitSalesLineQtyToInvoice(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInitSalesLineQtyToInvoice(SalesHeader, SalesLine, IsHandled);
        if IsHandled then
            exit;

        if SalesHeader.Invoice then begin
            if Abs(SalesLine."Qty. to Invoice") > Abs(SalesLine.MaxQtyToInvoice()) then
                SalesLine.InitQtyToInvoice();
        end else begin
            SalesLine."Qty. to Invoice" := 0;
            SalesLine."Qty. to Invoice (Base)" := 0;
        end;
    end;

    local procedure UpdateWhseDocuments(SalesHeader: Record "Sales Header"; EverythingInvoiced: Boolean)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateWhseDocuments(SalesHeader, IsHandled, WhseReceive, WhseShip, WhseRcptHeader, WhseShptHeader, TempWhseRcptHeader, TempWhseShptHeader);
        if IsHandled then
            exit;

        if WhseReceive then begin
            WhsePostRcpt.PostUpdateWhseDocuments(WhseRcptHeader);
            TempWhseRcptHeader.Delete();
        end;
        if WhseShip then begin
            WhsePostShpt.PostUpdateWhseDocuments(WhseShptHeader);
            TempWhseShptHeader.Delete();
        end;

        OnAfterUpdateWhseDocuments(SalesHeader, WhseShip, WhseReceive, WhseShptHeader, WhseRcptHeader, EverythingInvoiced);
    end;

    /// <summary>
    /// Deletes the document, lines and records related to the sales header after posting, unless the SkipDelete parameter is set.
    /// This is only run if everything was invoiced and the posting is not in PreviewMode
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document that was posted.</param>
    /// <param name="EverythingInvoiced">A flag indicating whether everything was invoiced. Only used in events, serves no functional purpose.</param>
    procedure DeleteAfterPosting(var SalesHeader: Record "Sales Header"; EverythingInvoiced: Boolean)
    var
        SalesCommentLine: Record "Sales Comment Line";
        SalesLine: Record "Sales Line";
        TempSalesLine: Record "Sales Line" temporary;
        WarehouseRequest: Record "Warehouse Request";
        IsHandled: Boolean;
        SkipDelete: Boolean;
    begin
        OnBeforeDeleteAfterPosting(SalesHeader, SalesInvHeader, SalesCrMemoHeader, SkipDelete, SuppressCommit, EverythingInvoiced, TempSalesLineGlobal);
        if SkipDelete then
            exit;

        IsHandled := false;
        OnDeleteAfterPostingOnBeforeDeleteLinks(SalesHeader, IsHandled);
        if not IsHandled then
            if SalesHeader.HasLinks() then
                SalesHeader.DeleteLinks();
        WarehouseRequest.DeleteRequest(DATABASE::"Sales Line", SalesHeader."Document Type".AsInteger(), SalesHeader."No.");

        OnDeleteAfterPostingOnBeforeDeleteSalesHeader(SalesHeader);
        SalesHeader.Delete();

        SalesLineReserve.DeleteInvoiceSpecFromHeader(SalesHeader);
        DeleteATOLinks(SalesHeader);

        ResetTempLines(TempSalesLine);
        OnDeleteAfterPostingOnAfterSetupSalesHeader(SalesHeader, TempSalesLine);
        if TempSalesLine.FindFirst() then
            repeat
                if TempSalesLine."Deferral Code" <> '' then
                    DeferralUtilities.RemoveOrSetDeferralSchedule(
                        '', Enum::"Deferral Document Type"::Sales.AsInteger(), '', '', TempSalesLine."Document Type".AsInteger(),
                        TempSalesLine."Document No.", TempSalesLine."Line No.", 0, 0D, TempSalesLine.Description, '', true);
                if TempSalesLine.HasLinks() then
                    TempSalesLine.DeleteLinks();
                OnDeleteAfterPostingOnAfterDeleteLinks(TempSalesLine);
            until TempSalesLine.Next() = 0;

        SalesLine.SetCurrentKey("Document Type", "Document No.", "Line No.");
        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        OnBeforeSalesLineDeleteAll(SalesLine, SuppressCommit, SalesHeader);
        SalesLine.DeleteAll();
        OnDeleteAfterPostingOnAfterSalesLineDeleteAll(SalesHeader, SalesInvHeader, SalesCrMemoHeader, SuppressCommit, EverythingInvoiced);

        DeleteItemChargeAssgnt(SalesHeader);
        SalesCommentLine.DeleteComments(SalesHeader."Document Type".AsInteger(), SalesHeader."No.");

        OnAfterDeleteAfterPosting(SalesHeader, SalesInvHeader, SalesCrMemoHeader, SuppressCommit);
    end;

    local procedure FinalizePosting(var SalesHeader: Record "Sales Header"; EverythingInvoiced: Boolean; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    var
        CRMConnectionSetup: Record "CRM Connection Setup";
        TempSalesLine: Record "Sales Line" temporary;
        GenJnlPostPreview: Codeunit "Gen. Jnl.-Post Preview";
        ICInboxOutboxMgt: Codeunit ICInboxOutboxMgt;
        WhseSalesRelease: Codeunit "Whse.-Sales Release";
        ArchiveManagement: Codeunit ArchiveManagement;
        IsHandled: Boolean;
    begin
        OnBeforeFinalizePosting(SalesHeader, TempSalesLineGlobal, EverythingInvoiced, SuppressCommit, GenJnlPostLine);

        if (SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::"Return Order"]) and
            (not EverythingInvoiced)
        then begin
            SalesHeader.Modify();
            InsertTrackingSpecification(SalesHeader);
            PostUpdateOrderLine(SalesHeader);
            UpdateAssociatedPurchaseOrder(TempDropShptPostBuffer, SalesHeader);
            if not PreviewMode then
                UpdateWhseDocuments(SalesHeader, EverythingInvoiced);
            WhseSalesRelease.Release(SalesHeader);
            UpdateItemChargeAssgnt(SalesHeader);
            OnFinalizePostingOnAfterUpdateItemChargeAssgnt(SalesHeader, TempDropShptPostBuffer, GenJnlPostLine);
        end else begin
            OnFinalizePostingOnBeforeInsertTrackingSpecification(TempDropShptPostBuffer, TempItemChargeAssgntSales, SalesHeader, TempTrackingSpecification, EverythingInvoiced, TempSalesLine, TempSalesLineGlobal, this);
            case SalesHeader."Document Type" of
                SalesHeader."Document Type"::Invoice:
                    begin
                        PostUpdateInvoiceLine(SalesHeader);
                        InsertTrackingSpecification(SalesHeader);
                        PostUpdateOrderNo(SalesInvHeader);
                        ArchiveRelatedJob(SalesHeader);
                    end;
                SalesHeader."Document Type"::"Credit Memo":
                    begin
                        PostUpdateReturnReceiptLine();
                        InsertTrackingSpecification(SalesHeader);
                        PostUpdateOrderNo(SalesCrMemoHeader);
                    end;
                else begin
                    UpdateAssociatedPurchaseOrder(TempDropShptPostBuffer, SalesHeader);
                    if DropShipOrder then
                        InsertTrackingSpecification(SalesHeader);

                    ResetTempLines(TempSalesLine);
                    TempSalesLine.SetFilter("Purch. Order Line No.", '<>0');
                    if TempSalesLine.FindSet() then
                        repeat
                            UpdateAssocLines(TempSalesLine);
                            TempSalesLine.Modify();
                        until TempSalesLine.Next() = 0;

                    ResetTempLines(TempSalesLine);
                    TempSalesLine.SetFilter("Prepayment %", '<>0');
                    if TempSalesLine.FindSet() then
                        repeat
                            DecrementPrepmtAmtInvLCY(
                                SalesHeader, TempSalesLine, TempSalesLine."Prepmt. Amount Inv. (LCY)", TempSalesLine."Prepmt. VAT Amount Inv. (LCY)");
                            TempSalesLine.Modify();
                        until TempSalesLine.Next() = 0;
                    if (SalesHeader."Document Type" = SalesHeader."Document Type"::Order) and SalesSetup."Archive Orders" then begin
                        PostUpdateOrderLine(SalesHeader);
                        if (not OrderArchived) or (OrderArchived and CRMConnectionSetup.IsBidirectionalSalesOrderIntEnabled()) then begin
                            ArchiveManagement.AutoArchiveSalesDocument(SalesHeader);
                            OrderArchived := true;
                        end;
                    end;
                end;
            end;
            UpdateAfterPosting(SalesHeader);
            UpdateEmailParameters(SalesHeader);
            if not PreviewMode then
                UpdateWhseDocuments(SalesHeader, EverythingInvoiced);
            if not OrderArchived then begin
                ArchiveManagement.AutoArchiveSalesDocument(SalesHeader);
                OrderArchived := true;
            end;

            OnFinalizePostingOnBeforeDeleteApprovalEntries(SalesHeader, EverythingInvoiced);
            DeleteApprovalEntries(SalesHeader);
            if not PreviewMode then
                DeleteAfterPosting(SalesHeader, EverythingInvoiced);
        end;

        InsertValueEntryRelation();

        OnAfterFinalizePostingOnBeforeCommit(
          SalesHeader, SalesShptHeader, SalesInvHeader, SalesCrMemoHeader, ReturnRcptHeader, GenJnlPostLine,
          SuppressCommit, PreviewMode, WhseShip, WhseReceive, EverythingInvoiced);

        if PreviewMode and (CalledBy = 0) then begin
            if GuiAllowed() and not HideProgressWindow then
                Window.Close();
            IsHandled := false;
            OnFinalizePostingOnBeforeGenJnlPostPreviewThrowError(SalesHeader, SalesInvHeader, SalesCrMemoHeader, IsHandled);
            if not IsHandled then
                GenJnlPostPreview.ThrowError();
        end;

        ICInboxOutboxMgt.CheckPermissionToSendICTransaction(SalesHeader);

        if not (InvtPickPutaway or SuppressCommit or PreviewMode) then
            Commit();

        if GuiAllowed() and not HideProgressWindow then
            Window.Close();

        IsHandled := false;
        OnFinalizePostingOnBeforeCreateOutboxSalesTrans(SalesHeader, IsHandled, EverythingInvoiced, SalesInvHeader, SalesCrMemoHeader);
        if not IsHandled then
            if SalesHeader.Invoice and SalesHeader."Send IC Document" then
                if SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice] then
                    ICInboxOutboxMgt.CreateOutboxSalesInvTrans(SalesInvHeader)
                else
                    ICInboxOutboxMgt.CreateOutboxSalesCrMemoTrans(SalesCrMemoHeader);

        OnAfterFinalizePosting(
          SalesHeader, SalesShptHeader, SalesInvHeader, SalesCrMemoHeader, ReturnRcptHeader,
          GenJnlPostLine, SuppressCommit, PreviewMode);

        ClearPostBuffers();

        if SalesHeader."Document Type" = SalesHeader."Document Type"::"Return Order" then
            UpdateSalesOrderLineIfExist(SalesHeader."No.");
    end;

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

        ApprovalsMgmt.DeleteApprovalEntries(SalesHeader.RecordId());

        OnAfterDeleteApprovalEntries(SalesHeader, SalesInvHeader, SalesCrMemoHeader, SalesShptHeader, ReturnRcptHeader);
    end;

    /// <summary>
    /// Initializes the global Currency variable with the currency code passed as a parameter.
    /// </summary>
    /// <param name="CurrencyCode">The currency code to initialize the global Currency variable with.</param>
    procedure GetCurrency(CurrencyCode: Code[10])
    begin
        Currency.Initialize(CurrencyCode, true);

        OnAfterGetCurrency(CurrencyCode, Currency);
    end;

    local procedure DivideAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; SalesLineQty: Decimal; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary)
    begin
        DivideAmount(SalesHeader, SalesLine, QtyType, SalesLineQty, TempVATAmountLine, TempVATAmountLineRemainder, true);
    end;

    local procedure DivideAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; SalesLineQty: Decimal; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary; IncludePrepayments: Boolean)
    var
        OriginalDeferralAmount: Decimal;
        IsHandled: Boolean;
    begin
        if RoundingLineInserted and (RoundingLineNo = SalesLine."Line No.") then
            exit;

        IsHandled := false;
        OnBeforeDivideAmount(
            SalesHeader, SalesLine, QtyType, SalesLineQty, TempVATAmountLine, TempVATAmountLineRemainder, IsHandled, TempPrepmtDeductLCYSalesLine);
        if IsHandled then
            exit;

        if (SalesLineQty = 0) or (SalesLine."Unit Price" = 0) then begin
            SalesLine."Line Amount" := 0;
            SalesLine."Line Discount Amount" := 0;
            SalesLine."Inv. Discount Amount" := 0;
            SalesLine."VAT Base Amount" := 0;
            SalesLine.Amount := 0;
            SalesLine."Amount Including VAT" := 0;
            OnDivideAmountOnAfterInitAmount(SalesHeader, SalesLine, SalesLineQty);
        end else begin
            OriginalDeferralAmount := SalesLine.GetDeferralAmount();
            IsHandled := false;
            OnDivideAmountOnBeforeTempVATAmountLineGet(SalesLine, TempVATAmountLine, IsHandled);
            if not IsHandled then
                TempVATAmountLine.Get(SalesLine."VAT Identifier", SalesLine."VAT Calculation Type", SalesLine."Tax Group Code", false, SalesLine."Line Amount" >= 0);
            if SalesLine."VAT Calculation Type" = SalesLine."VAT Calculation Type"::"Sales Tax" then
                SalesLine."VAT %" := TempVATAmountLine."VAT %";
            TempVATAmountLineRemainder := TempVATAmountLine;
            if not TempVATAmountLineRemainder.Find() then begin
                TempVATAmountLineRemainder.Init();
                TempVATAmountLineRemainder.Insert();
            end;

            DivideAmountInitLineAmountAndLineDiscountAmount(SalesHeader, SalesLine, SalesLineQty, IncludePrepayments, TempVATAmountLine);

            OnDivideAmountOnAfterInitLineDiscountAmount(SalesHeader, SalesLine, SalesLineQty);

            if SalesLine."Allow Invoice Disc." and (TempVATAmountLine."Inv. Disc. Base Amount" <> 0) then
                if QtyType = QtyType::Invoicing then
                    SalesLine."Inv. Discount Amount" := SalesLine."Inv. Disc. Amount to Invoice"
                else begin
                    TempVATAmountLineRemainder."Invoice Discount Amount" :=
                      TempVATAmountLineRemainder."Invoice Discount Amount" +
                      TempVATAmountLine."Invoice Discount Amount" * SalesLine."Line Amount" /
                      TempVATAmountLine."Inv. Disc. Base Amount";
                    SalesLine."Inv. Discount Amount" :=
                      Round(
                        TempVATAmountLineRemainder."Invoice Discount Amount", Currency."Amount Rounding Precision");
                    TempVATAmountLineRemainder."Invoice Discount Amount" :=
                      TempVATAmountLineRemainder."Invoice Discount Amount" - SalesLine."Inv. Discount Amount";
                end;

            IsHandled := false;
            OnDivideAmountOnBeforeUpdateTempVATAmountLineRemainder(SalesLine, SalesHeader, TempVATAmountLine, TempVATAmountLineRemainder, Currency, IsHandled);
            if not IsHandled then
                if SalesHeader."Prices Including VAT" then begin
                    if (TempVATAmountLine.CalcLineAmount() = 0) or (SalesLine."Line Amount" = 0) then begin
                        TempVATAmountLineRemainder."VAT Amount" := 0;
                        TempVATAmountLineRemainder."Amount Including VAT" := 0;
                    end else begin
                        TempVATAmountLineRemainder."VAT Amount" +=
                            TempVATAmountLine."VAT Amount" * SalesLine.CalcLineAmount() / TempVATAmountLine.CalcLineAmount();
                        TempVATAmountLineRemainder."Amount Including VAT" +=
                            TempVATAmountLine."Amount Including VAT" * SalesLine.CalcLineAmount() / TempVATAmountLine.CalcLineAmount();
                    end;
                    if SalesLine."Line Discount %" <> 100 then
                        SalesLine."Amount Including VAT" :=
                            Round(TempVATAmountLineRemainder."Amount Including VAT", Currency."Amount Rounding Precision")
                    else
                        SalesLine."Amount Including VAT" := 0;
                    SalesLine.Amount :=
                        Round(SalesLine."Amount Including VAT", Currency."Amount Rounding Precision") -
                        Round(TempVATAmountLineRemainder."VAT Amount", Currency."Amount Rounding Precision");
                    CalcVATBaseAmount(SalesHeader, SalesLine, TempVATAmountLine, TempVATAmountLineRemainder);
                    TempVATAmountLineRemainder."Amount Including VAT" :=
                        TempVATAmountLineRemainder."Amount Including VAT" - SalesLine."Amount Including VAT";
                    TempVATAmountLineRemainder."VAT Amount" :=
                        TempVATAmountLineRemainder."VAT Amount" - SalesLine."Amount Including VAT" + SalesLine.Amount;
                end else
                    if SalesLine."VAT Calculation Type" = SalesLine."VAT Calculation Type"::"Full VAT" then begin
                        if SalesLine."Line Discount %" <> 100 then
                            SalesLine."Amount Including VAT" := SalesLine.CalcLineAmount()
                        else
                            SalesLine."Amount Including VAT" := 0;
                        SalesLine.Amount := 0;
                        SalesLine."VAT Base Amount" := 0;
                    end else begin
                        SalesLine.Amount := SalesLine.CalcLineAmount();
                        CalcVATBaseAmount(SalesHeader, SalesLine, TempVATAmountLine, TempVATAmountLineRemainder);
                        if TempVATAmountLine."VAT Base" = 0 then
                            TempVATAmountLineRemainder."VAT Amount" := 0
                        else
                            TempVATAmountLineRemainder."VAT Amount" +=
                                TempVATAmountLine."VAT Amount" * SalesLine.CalcLineAmount() / TempVATAmountLine.CalcLineAmount();
                        if SalesLine."Line Discount %" <> 100 then
                            SalesLine."Amount Including VAT" :=
                                SalesLine.Amount + Round(TempVATAmountLineRemainder."VAT Amount", Currency."Amount Rounding Precision")
                        else
                            SalesLine."Amount Including VAT" := 0;
                        TempVATAmountLineRemainder."VAT Amount" :=
                            TempVATAmountLineRemainder."VAT Amount" - SalesLine."Amount Including VAT" + SalesLine.Amount;
                    end;

            OnDivideAmountOnBeforeTempVATAmountLineRemainderModify(SalesHeader, SalesLine, TempVATAmountLine, TempVATAmountLineRemainder, Currency);
            TempVATAmountLineRemainder.Modify();
#pragma warning disable AA0005
            if SalesLine."Deferral Code" <> '' then begin
                GetInvoicePostingSetup();
                InvoicePostingInterface.CalcDeferralAmounts(SalesHeader, SalesLine, OriginalDeferralAmount);
            end;
#pragma warning restore AA0005
        end;

        OnAfterDivideAmount(SalesHeader, SalesLine, QtyType, SalesLineQty, TempVATAmountLine, TempVATAmountLineRemainder);
    end;

    local procedure DivideAmountInitLineAmountAndLineDiscountAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesLineQty: Decimal; IncludePrepayments: Boolean; var TempVATAmountLine: Record "VAT Amount Line" temporary)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeDivideAmountInitLineAmountAndLineDiscountAmount(SalesHeader, SalesLine, SalesLineQty, IncludePrepayments, IsHandled, TempPrepmtDeductLCYSalesLine, TempVATAmountLine);
        if IsHandled then
            exit;

        if IncludePrepayments then
            SalesLine."Line Amount" := SalesLine.GetLineAmountToHandleInclPrepmt(SalesLineQty) + GetPrepmtDiffToLineAmount(SalesLine)
        else
            SalesLine."Line Amount" := SalesLine.GetLineAmountToHandle(SalesLineQty);

        if SalesLineQty <> SalesLine.Quantity then
            SalesLine."Line Discount Amount" :=
                Round(SalesLine."Line Discount Amount" * SalesLineQty / SalesLine.Quantity, Currency."Amount Rounding Precision");
    end;

    local procedure RoundAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesLineQty: Decimal)
    var
        NoVAT: Boolean;
        IsHandled: Boolean;
    begin
        OnBeforeRoundAmount(SalesHeader, SalesLine, SalesLineQty, CurrExchRate);

        IncrAmount(SalesHeader, SalesLine, TotalSalesLine);
        TotalSalesLine."Net Weight" += Round(SalesLineQty * SalesLine."Net Weight", UOMMgt.WeightRndPrecision());
        TotalSalesLine."Gross Weight" += Round(SalesLineQty * SalesLine."Gross Weight", UOMMgt.WeightRndPrecision());
        TotalSalesLine."Unit Volume" += Round(SalesLineQty * SalesLine."Unit Volume", UOMMgt.CubageRndPrecision());
        TotalSalesLine.Quantity += SalesLineQty;
        if SalesLine."Units per Parcel" > 0 then
            TotalSalesLine."Units per Parcel" += Round(SalesLineQty / SalesLine."Units per Parcel", 1, '>');

        xSalesLine := SalesLine;
        SalesLineACY := SalesLine;
        IsHandled := false;
        OnRoundAmountOnAfterAssignSalesLines(xSalesLine, SalesLineACY, SalesHeader, IsHandled, TotalSalesLine, TotalSalesLineLCY, SalesLine);
        if not IsHandled then
            if (SalesHeader."Currency Code" <> '') and (SalesLine.Type <> SalesLine.Type::" ") then begin
                NoVAT := SalesLine.Amount = SalesLine."Amount Including VAT";
                SalesLine."Amount Including VAT" :=
                  Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                      TotalSalesLine."Amount Including VAT", SalesHeader."Currency Factor")) -
                  TotalSalesLineLCY."Amount Including VAT";
                if NoVAT then
                    SalesLine.Amount := SalesLine."Amount Including VAT"
                else
                    SalesLine.Amount :=
                      Round(
                        CurrExchRate.ExchangeAmtFCYToLCY(
                          SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                          TotalSalesLine.Amount, SalesHeader."Currency Factor")) -
                      TotalSalesLineLCY.Amount;
                SalesLine."Line Amount" :=
                  Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                      TotalSalesLine."Line Amount", SalesHeader."Currency Factor")) -
                  TotalSalesLineLCY."Line Amount";
                SalesLine."Line Discount Amount" :=
                  Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                      TotalSalesLine."Line Discount Amount", SalesHeader."Currency Factor")) -
                  TotalSalesLineLCY."Line Discount Amount";
                SalesLine."Inv. Discount Amount" :=
                  Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                      TotalSalesLine."Inv. Discount Amount", SalesHeader."Currency Factor")) -
                  TotalSalesLineLCY."Inv. Discount Amount";
                SalesLine."VAT Difference" :=
                  Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                      TotalSalesLine."VAT Difference", SalesHeader."Currency Factor")) -
                  TotalSalesLineLCY."VAT Difference";
                SalesLine."VAT Base Amount" :=
                  Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader.GetUseDate(), SalesHeader."Currency Code",
                      TotalSalesLine."VAT Base Amount", SalesHeader."Currency Factor")) -
                  TotalSalesLineLCY."VAT Base Amount";
            end;
        IsHandled := false;
        OnRoundAmountOnBeforeIncrAmount(SalesHeader, SalesLine, SalesLineQty, TotalSalesLine, TotalSalesLineLCY, xSalesLine, IsHandled);
        if not IsHandled then begin
            IncrAmount(SalesHeader, SalesLine, TotalSalesLineLCY);
            TotalSalesLineLCY."Unit Cost (LCY)" += Round(SalesLineQty * SalesLine."Unit Cost (LCY)");
        end;

        OnAfterRoundAmount(SalesHeader, SalesLine, SalesLineQty);
    end;

    /// <summary>
    /// Reverses the amounts and quantities of a sales line.
    /// </summary>
    /// <param name="SalesLine">The sales line for which to reverse the amounts and quantities.</param>
    procedure ReverseAmount(var SalesLine: Record "Sales Line")
    begin
        SalesLine."Qty. to Ship" := -SalesLine."Qty. to Ship";
        SalesLine."Qty. to Ship (Base)" := -SalesLine."Qty. to Ship (Base)";
        SalesLine."Return Qty. to Receive" := -SalesLine."Return Qty. to Receive";
        SalesLine."Return Qty. to Receive (Base)" := -SalesLine."Return Qty. to Receive (Base)";
        SalesLine."Qty. to Invoice" := -SalesLine."Qty. to Invoice";
        SalesLine."Qty. to Invoice (Base)" := -SalesLine."Qty. to Invoice (Base)";
        SalesLine."Line Amount" := -SalesLine."Line Amount";
        SalesLine.Amount := -SalesLine.Amount;
        SalesLine."VAT Base Amount" := -SalesLine."VAT Base Amount";
        SalesLine."VAT Difference" := -SalesLine."VAT Difference";
        SalesLine."Amount Including VAT" := -SalesLine."Amount Including VAT";
        SalesLine."Line Discount Amount" := -SalesLine."Line Discount Amount";
        SalesLine."Inv. Discount Amount" := -SalesLine."Inv. Discount Amount";
        OnAfterReverseAmount(SalesLine);
    end;

    local procedure InvoiceRounding(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; UseTempData: Boolean; BiggestLineNo: Integer)
    var
        CustPostingGr: Record "Customer Posting Group";
        InvoiceRoundingAmount: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInvoiceRounding(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        Currency.TestField("Invoice Rounding Precision");
        InvoiceRoundingAmount :=
          -Round(
            TotalSalesLine."Amount Including VAT" -
            Round(
              TotalSalesLine."Amount Including VAT", Currency."Invoice Rounding Precision", Currency.InvoiceRoundingDirection()),
            Currency."Amount Rounding Precision");

        OnBeforeInvoiceRoundingAmount(
          SalesHeader, TotalSalesLine."Amount Including VAT", UseTempData, InvoiceRoundingAmount, SuppressCommit, TotalSalesLine, Currency);
        if InvoiceRoundingAmount <> 0 then begin
            CustPostingGr.Get(SalesHeader."Customer Posting Group");
            SalesLine.Init();
            BiggestLineNo := BiggestLineNo + 10000;
            SalesLine."System-Created Entry" := true;
            if UseTempData then begin
                SalesLine."Line No." := 0;
                SalesLine.Type := SalesLine.Type::"G/L Account";
                SalesLine.SetHideValidationDialog(true);
            end else begin
                SalesLine."Line No." := BiggestLineNo;
                SalesLine.Validate(Type, SalesLine.Type::"G/L Account");
            end;
            SalesLine.Validate("No.", CustPostingGr.GetInvRoundingAccount());
            SalesLine.Validate(Quantity, 1);
            OnInvoiceRoundingOnAfterValidateQuantity(SalesHeader, SalesLine);
            if SalesLine.IsCreditDocType() then
                SalesLine.Validate("Return Qty. to Receive", SalesLine.Quantity)
            else
                SalesLine.Validate("Qty. to Ship", SalesLine.Quantity);
            if SalesHeader."Prices Including VAT" then
                SalesLine.Validate("Unit Price", InvoiceRoundingAmount)
            else
                SalesLine.Validate(
                  "Unit Price",
                  Round(
                    InvoiceRoundingAmount /
                    (1 + (1 - SalesLine.GetVatBaseDiscountPct(SalesHeader) / 100) * SalesLine."VAT %" / 100),
                    Currency."Amount Rounding Precision"));
            SalesLine.Validate("Amount Including VAT", InvoiceRoundingAmount);
            SalesLine."Line No." := BiggestLineNo;
            OnInvoiceRoundingOnAfterSetLineNo(SalesHeader, SalesLine);
            LastLineRetrieved := false;
            RoundingLineInserted := true;
            RoundingLineNo := SalesLine."Line No.";
        end;

        OnAfterInvoiceRoundingAmount(
            SalesHeader, SalesLine, TotalSalesLine, UseTempData, InvoiceRoundingAmount, SuppressCommit, Currency,
            BiggestLineNo, LastLineRetrieved, RoundingLineInserted, RoundingLineNo);
    end;

    /// <summary>
    /// Adds the amounts from sales line to the TotalSalesLine record.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document.</param>
    /// <param name="SalesLine">The sales line to add the amounts from.</param>
    /// <param name="TotalSalesLine">Return Variable: The TotalSalesLine record to which the amounts are added.</param>
    procedure IncrAmount(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var TotalSalesLine: Record "Sales Line")
    begin
        if SalesHeader."Prices Including VAT" or
           (SalesLine."VAT Calculation Type" <> SalesLine."VAT Calculation Type"::"Full VAT")
        then
            TotalSalesLine."Line Amount" += SalesLine."Line Amount";
        TotalSalesLine.Amount += SalesLine.Amount;
        TotalSalesLine."VAT Base Amount" += SalesLine."VAT Base Amount";
        TotalSalesLine."VAT Difference" += SalesLine."VAT Difference";
        TotalSalesLine."Amount Including VAT" += SalesLine."Amount Including VAT";
        TotalSalesLine."Line Discount Amount" += SalesLine."Line Discount Amount";
        TotalSalesLine."Inv. Discount Amount" += SalesLine."Inv. Discount Amount";
        TotalSalesLine."Inv. Disc. Amount to Invoice" += SalesLine."Inv. Disc. Amount to Invoice";
        TotalSalesLine."Prepmt. Line Amount" += SalesLine."Prepmt. Line Amount";
        TotalSalesLine."Prepmt. Amt. Inv." += SalesLine."Prepmt. Amt. Inv.";
        TotalSalesLine."Prepmt Amt to Deduct" += SalesLine."Prepmt Amt to Deduct";
        TotalSalesLine."Prepmt Amt Deducted" += SalesLine."Prepmt Amt Deducted";
        TotalSalesLine."Prepayment VAT Difference" += SalesLine."Prepayment VAT Difference";
        TotalSalesLine."Prepmt VAT Diff. to Deduct" += SalesLine."Prepmt VAT Diff. to Deduct";
        TotalSalesLine."Prepmt VAT Diff. Deducted" += SalesLine."Prepmt VAT Diff. Deducted";

        OnAfterIncrAmount(TotalSalesLine, SalesLine, SalesHeader);
    end;

    local procedure GetSalesHeader(var SalesHeader: Record "Sales Header")
    var
        SalesHeaderCopy: Record "Sales Header";
    begin
        SalesHeaderCopy := SalesHeader;
        SalesHeader.ReadIsolation := IsolationLevel::ReadCommitted;
        SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
        SalesHeader := SalesHeaderCopy;
    end;

    /// <summary>
    /// Collects the sales lines for the specified sales header and stores them in the NewSalesLine record set.
    /// Collected lines will have the amounts divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <remarks>
    /// An overload for GetSalesLines that always includes prepayments (if QtyType is set to Invoicing).
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document.</param>
    /// <param name="NewSalesLine">Return Variable: The NewSalesLine record set to store the collected sales lines in. This should be a temporary variable as new records will be inserted.</param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    procedure GetSalesLines(var SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping)
    begin
        GetSalesLines(SalesHeader, NewSalesLine, QtyType, true);
    end;

    /// <summary>
    /// Collects and divides amounts of the sales lines for the specified sales header and stores them in the NewSalesLine record set.
    /// Collected lines will have the amounts divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document.</param>
    /// <param name="NewSalesLine">Return Variable: The NewSalesLine record set to store the collected sales lines in. This should be a temporary variable as new records will be inserted.</param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    /// <param name="IncludePrepayments">A flag indicating whether prepayments should be included in the collected lines. Only applies if QtyType is set to Invoicing.</param>
    procedure GetSalesLines(var SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; IncludePrepayments: Boolean)
    var
        TotalAdjCostLCY: Decimal;
    begin
        OnBeforeGetSalesLines(SalesHeader, NewSalesLine, QtyType, IncludePrepayments);
        FillTempLines(SalesHeader, TempSalesLineGlobal);
        OnGetSalesLinesOnAfterFillTempLines(SalesHeader, TempSalesLineGlobal);
        if (QtyType = QtyType::Invoicing) and IncludePrepayments then
            CreatePrepaymentLines(SalesHeader, false);
        SumSalesLines2(SalesHeader, NewSalesLine, TempSalesLineGlobal, QtyType, true, false, TotalAdjCostLCY, IncludePrepayments, false);

        OnAfterGetSalesLines(SalesHeader, TempSalesLineGlobal, NewSalesLine);
    end;

    /// <summary>
    /// Collects and divides amounts of the sales lines for the specified sales header and stores them in the NewSalesLine record set.
    /// Collected lines will have the amounts divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document.</param>
    /// <param name="NewSalesLine">Return Variable: The NewSalesLine record set to store the collected sales lines in. This should be a temporary variable as new records will be inserted.</param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    /// <param name="IncludePrepayments">A flag indicating whether prepayments should be included in the collected lines. Only applies if QtyType is set to Invoicing.</param>
    /// <param name="CalledFromStatistics">A flag indicating whether the procedure is called from statistics.</param>
    procedure GetSalesLines(var SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; IncludePrepayments: Boolean; CalledFromStatistics: Boolean)
    var
        TotalAdjCostLCY: Decimal;
    begin
        OnBeforeGetSalesLines(SalesHeader, NewSalesLine, QtyType, IncludePrepayments);
        FillTempLines(SalesHeader, TempSalesLineGlobal);
        OnGetSalesLinesOnAfterFillTempLines(SalesHeader, TempSalesLineGlobal);
        if (QtyType = QtyType::Invoicing) and IncludePrepayments then
            CreatePrepaymentLines(SalesHeader, false);
        SumSalesLines2(SalesHeader, NewSalesLine, TempSalesLineGlobal, QtyType, true, false, TotalAdjCostLCY, IncludePrepayments, CalledFromStatistics);

        OnAfterGetSalesLines(SalesHeader, TempSalesLineGlobal, NewSalesLine);
    end;

    /// <summary>
    /// Divides amounts of the sales lines passed as OldSalesLine parameter and stores them in the NewSalesLine record set.
    /// Lines will have the amounts divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <remarks>
    /// Behaves similarly to GetSalesLines with the exception that GetSalesLines collects all the lines for the specified sales header,
    /// while this method only divides the amounts of the lines passed as OldSalesLine parameter.
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document.</param>
    /// <param name="NewSalesLine">Return Variable: The NewSalesLine record set to store the collected sales lines in. This should be a temporary variable as new records will be inserted.</param>
    /// <param name="OldSalesLine">The sales line record set to copy the lines from and divide the amounts.</param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    procedure GetSalesLinesTemp(var SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; var OldSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping)
    var
        TotalAdjCostLCY: Decimal;
    begin
        OnBeforeGetSalesLinesTemp(SalesHeader, NewSalesLine, OldSalesLine, QtyType);
        OldSalesLine.SetSalesHeader(SalesHeader);
        SumSalesLines2(SalesHeader, NewSalesLine, OldSalesLine, QtyType, true, false, TotalAdjCostLCY);
    end;

    /// <summary>
    /// Sums the sales lines for the specified sales header (within the filters that are already set on OldSalesLine) and stores the results in the NewTotalSalesLine and NewTotalSalesLineLCY record variables.
    /// The amounts will be divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <remarks>
    /// This is an overload for SumSalesLineTemp that always includes prepayments in amount calculations
    /// it always takes the lines for the specified sales header (doesn't support a parameter for filtered or temp sales lines).
    /// </remarks>
    /// <param name="NewSalesHeader">The sales header of the document.</param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    /// <param name="NewTotalSalesLine">Return Variable: The NewTotalSalesLine record to store the summed amounts in.</param>
    /// <param name="NewTotalSalesLineLCY">Return Variable: The NewTotalSalesLineLCY record to store the summed amounts in LCY in.</param>
    /// <param name="VATAmount">Return Variable: The total VAT amount.</param>
    /// <param name="VATAmountText">Return Variable: The text to display for the VAT amount. This will include the VAT rate if the VAT rate is the same for all lines.</param>
    /// <param name="ProfitLCY">Return Variable: The total profit in LCY.</param>
    /// <param name="ProfitPct">Return Variable: The total profit percentage.</param>
    /// <param name="TotalAdjCostLCY">Return Variable: The total adjusted cost in LCY.</param>
    procedure SumSalesLines(var NewSalesHeader: Record "Sales Header"; QtyType: Option General,Invoicing,Shipping; var NewTotalSalesLine: Record "Sales Line"; var NewTotalSalesLineLCY: Record "Sales Line"; var VATAmount: Decimal; var VATAmountText: Text[30]; var ProfitLCY: Decimal; var ProfitPct: Decimal; var TotalAdjCostLCY: Decimal)
    var
        OldSalesLine: Record "Sales Line";
    begin
        SumSalesLinesTemp(
          NewSalesHeader, OldSalesLine, QtyType, NewTotalSalesLine, NewTotalSalesLineLCY,
          VATAmount, VATAmountText, ProfitLCY, ProfitPct, TotalAdjCostLCY);
    end;

    /// <summary>
    /// Sums the sales lines for the specified sales header (within the filters that are already set on OldSalesLine) and stores the results in the NewTotalSalesLine and NewTotalSalesLineLCY record variables.
    /// The amounts will be divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <remarks>
    /// OldSalesLine can be a temporary variable
    /// This is an overload for SumSalesLineTemp that always includes prepayments in amount calculations
    /// </remarks>
    /// <param name="SalesHeader"></param>
    /// <param name="OldSalesLine"></param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    /// <param name="NewTotalSalesLine">Return Variable: The NewTotalSalesLine record to store the summed amounts in.</param>
    /// <param name="NewTotalSalesLineLCY">Return Variable: The NewTotalSalesLineLCY record to store the summed amounts in LCY in.</param>
    /// <param name="VATAmount">Return Variable: The total VAT amount.</param>
    /// <param name="VATAmountText">Return Variable: The text to display for the VAT amount. This will include the VAT rate if the VAT rate is the same for all lines.</param>
    /// <param name="ProfitLCY">Return Variable: The total profit in LCY.</param>
    /// <param name="ProfitPct">Return Variable: The total profit percentage.</param>
    /// <param name="TotalAdjCostLCY">Return Variable: The total adjusted cost in LCY.</param>
    procedure SumSalesLinesTemp(var SalesHeader: Record "Sales Header"; var OldSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; var NewTotalSalesLine: Record "Sales Line"; var NewTotalSalesLineLCY: Record "Sales Line"; var VATAmount: Decimal; var VATAmountText: Text[30]; var ProfitLCY: Decimal; var ProfitPct: Decimal; var TotalAdjCostLCY: Decimal)
    begin
        SumSalesLinesTemp(SalesHeader, OldSalesLine, QtyType, NewTotalSalesLine, NewTotalSalesLineLCY, VATAmount, VATAmountText, ProfitLCY, ProfitPct, TotalAdjCostLCY, true);
    end;

    /// <summary>
    /// Sums the sales lines for the specified sales header (within the filters that are already set on OldSalesLine) and stores the results in the NewTotalSalesLine and NewTotalSalesLineLCY record variables.
    /// The amounts will be divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <remarks>
    /// OldSalesLine can be a temporary variable
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document.</param>
    /// <param name="OldSalesLine">The sales lines to sum.</param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    /// <param name="NewTotalSalesLine">Return Variable: The NewTotalSalesLine record to store the summed amounts in.</param>
    /// <param name="NewTotalSalesLineLCY">Return Variable: The NewTotalSalesLineLCY record to store the summed amounts in LCY in.</param>
    /// <param name="VATAmount">Return Variable: The total VAT amount.</param>
    /// <param name="VATAmountText">Return Variable: The text to display for the VAT amount. This will include the VAT rate if the VAT rate is the same for all lines.</param>
    /// <param name="ProfitLCY">Return Variable: The total profit in LCY.</param>
    /// <param name="ProfitPct">Return Variable: The total profit percentage.</param>
    /// <param name="TotalAdjCostLCY">Return Variable: The total adjusted cost in LCY.</param>
    /// <param name="IncludePrepayments">A flag indicating whether prepayments should be included when calculating Line Amounts.</param>
    procedure SumSalesLinesTemp(var SalesHeader: Record "Sales Header"; var OldSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; var NewTotalSalesLine: Record "Sales Line"; var NewTotalSalesLineLCY: Record "Sales Line"; var VATAmount: Decimal; var VATAmountText: Text[30]; var ProfitLCY: Decimal; var ProfitPct: Decimal; var TotalAdjCostLCY: Decimal; IncludePrepayments: Boolean)
    var
        SalesLine: Record "Sales Line";
    begin
        OnBeforeSumSalesLinesTemp(SalesHeader, OldSalesLine);
        SumSalesLines2(SalesHeader, SalesLine, OldSalesLine, QtyType, false, true, TotalAdjCostLCY, IncludePrepayments, false);
        ProfitLCY := TotalSalesLineLCY.Amount - TotalSalesLineLCY."Unit Cost (LCY)";
        if TotalSalesLineLCY.Amount = 0 then
            ProfitPct := 0
        else
            ProfitPct := Round(ProfitLCY / TotalSalesLineLCY.Amount * 100, 0.1);
        VATAmount := TotalSalesLine."Amount Including VAT" - TotalSalesLine.Amount;
        OnSumSalesLinesTempOnAfterVatAmountSet(VATAmount, TotalSalesLine);
        if TotalSalesLine."VAT %" = 0 then
            VATAmountText := VATAmountTxt
        else
            VATAmountText := StrSubstNo(VATRateTxt, TotalSalesLine.GetVATPct());
        NewTotalSalesLine := TotalSalesLine;
        NewTotalSalesLineLCY := TotalSalesLineLCY;
    end;

    /// <summary>
    /// Sums the sales lines for the specified sales header (within the filters that are already set on OldSalesLine) and stores the results in the NewTotalSalesLine and NewTotalSalesLineLCY record variables.
    /// The amounts will be divided by quantity the same way as they are divided during the posting process, depending on the selected QtyType.
    /// </summary>
    /// <remarks>
    /// OldSalesLine can be a temporary variable
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document.</param>
    /// <param name="OldSalesLine">The sales lines to sum.</param>
    /// <param name="QtyType">The QtyType to use when dividing the amounts by quantity. General = Quantity, Invoicing = Qty. to Invoice, Shipping = Qty. to Ship.</param>
    /// <param name="NewTotalSalesLine">Return Variable: The NewTotalSalesLine record to store the summed amounts in.</param>
    /// <param name="NewTotalSalesLineLCY">Return Variable: The NewTotalSalesLineLCY record to store the summed amounts in LCY in.</param>
    /// <param name="VATAmount">Return Variable: The total VAT amount.</param>
    /// <param name="VATAmountText">Return Variable: The text to display for the VAT amount. This will include the VAT rate if the VAT rate is the same for all lines.</param>
    /// <param name="ProfitLCY">Return Variable: The total profit in LCY.</param>
    /// <param name="ProfitPct">Return Variable: The total profit percentage.</param>
    /// <param name="TotalAdjCostLCY">Return Variable: The total adjusted cost in LCY.</param>
    /// <param name="IncludePrepayments">A flag indicating whether prepayments should be included when calculating Line Amounts.</param>
    /// <param name="CalledFromStatistics">A flag indicating whether the procedure is called from statistics.</param>
    procedure SumSalesLinesTemp(var SalesHeader: Record "Sales Header"; var OldSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; var NewTotalSalesLine: Record "Sales Line"; var NewTotalSalesLineLCY: Record "Sales Line"; var VATAmount: Decimal; var VATAmountText: Text[30]; var ProfitLCY: Decimal; var ProfitPct: Decimal; var TotalAdjCostLCY: Decimal; IncludePrepayments: Boolean; CalledfromStatistics: Boolean)
    var
        SalesLine: Record "Sales Line";
    begin
        OnBeforeSumSalesLinesTemp(SalesHeader, OldSalesLine);
        SumSalesLines2(SalesHeader, SalesLine, OldSalesLine, QtyType, false, true, TotalAdjCostLCY, IncludePrepayments, CalledfromStatistics);
        ProfitLCY := TotalSalesLineLCY.Amount - TotalSalesLineLCY."Unit Cost (LCY)";
        if TotalSalesLineLCY.Amount = 0 then
            ProfitPct := 0
        else
            ProfitPct := Round(ProfitLCY / TotalSalesLineLCY.Amount * 100, 0.1);
        VATAmount := TotalSalesLine."Amount Including VAT" - TotalSalesLine.Amount;
        OnSumSalesLinesTempOnAfterVatAmountSet(VATAmount, TotalSalesLine);
        if TotalSalesLine."VAT %" = 0 then
            VATAmountText := VATAmountTxt
        else
            VATAmountText := StrSubstNo(VATRateTxt, TotalSalesLine.GetVATPct());
        NewTotalSalesLine := TotalSalesLine;
        NewTotalSalesLineLCY := TotalSalesLineLCY;
    end;

    local procedure SumSalesLines2(SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; var OldSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; InsertSalesLine: Boolean; CalcAdCostLCY: Boolean; var TotalAdjCostLCY: Decimal)
    begin
        SumSalesLines2(SalesHeader, NewSalesLine, OldSalesLine, QtyType, InsertSalesLine, CalcAdCostLCY, TotalAdjCostLCY, true, false);
    end;

    local procedure SumSalesLines2(SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; var OldSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; InsertSalesLine: Boolean; CalcAdCostLCY: Boolean; var TotalAdjCostLCY: Decimal; IncludePrepayments: Boolean; CalledfromStatistics: Boolean)
    var
        SalesLine: Record "Sales Line";
        TempVATAmountLine: Record "VAT Amount Line" temporary;
        TempVATAmountLineRemainder: Record "VAT Amount Line" temporary;
        SalesLineQty: Decimal;
        AdjCostLCY: Decimal;
        BiggestLineNo: Integer;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSumSalesLines2(SalesHeader, NewSalesLine, OldSalesLine, QtyType, InsertSalesLine, CalcAdCostLCY, TotalAdjCostLCY, IncludePrepayments, IsHandled);
        if IsHandled then
            exit;

        TotalAdjCostLCY := 0;
        TempVATAmountLineRemainder.DeleteAll();
        IsHandled := false;
        OnSumSalesLines2OnBeforeCalcVATAmountLines(OldSalesLine, SalesHeader, InsertSalesLine, TempVATAmountLine, QtyType, IsHandled);
        if not IsHandled then
            OldSalesLine.CalcVATAmountLines(QtyType, SalesHeader, OldSalesLine, TempVATAmountLine, IncludePrepayments);
        GetGLSetup();
        GetSalesSetup();
        GetCurrency(SalesHeader."Currency Code");
        OldSalesLine.SetRange("Document Type", SalesHeader."Document Type");
        OldSalesLine.SetRange("Document No.", SalesHeader."No.");
        OnSumSalesLines2SetFilter(OldSalesLine, SalesHeader, InsertSalesLine, QtyType);
        RoundingLineInserted := false;
        if OldSalesLine.FindSet() then
            repeat
                if not RoundingLineInserted then
                    SalesLine := OldSalesLine;
                SalesLineQty := GetSalesLineQty(SalesHeader, SalesLine, QtyType, CalledfromStatistics);
                IsHandled := false;
                OnSumSalesLines2OnBeforeDivideAmount(
                    OldSalesLine, IsHandled, SalesHeader, SalesLine, QtyType, SalesLineQty, TempVATAmountLine, TempVATAmountLineRemainder,
                    IncludePrepayments, RoundingLineInserted);
                if not IsHandled then
                    DivideAmount(SalesHeader, SalesLine, QtyType, SalesLineQty, TempVATAmountLine, TempVATAmountLineRemainder, IncludePrepayments);
                OnSumSalesLines2OnAfterDivideAmount(OldSalesLine, SalesLineQty, QtyType);
                SalesLine.Quantity := SalesLineQty;
                if SalesLineQty <> 0 then begin
                    if (SalesLine.Amount <> 0) and not RoundingLineInserted then
                        if TotalSalesLine.Amount = 0 then
                            TotalSalesLine."VAT %" := SalesLine."VAT %"
                        else
                            if TotalSalesLine."VAT %" <> SalesLine."VAT %" then
                                TotalSalesLine."VAT %" := 0;
                    RoundAmount(SalesHeader, SalesLine, SalesLineQty);

                    if (QtyType in [QtyType::General, QtyType::Invoicing]) and
                       not InsertSalesLine and CalcAdCostLCY
                    then begin
                        AdjCostLCY := CostCalcMgt.CalcSalesLineCostLCY(SalesLine, QtyType);
                        TotalAdjCostLCY := TotalAdjCostLCY + GetSalesLineAdjCostLCY(SalesLine, QtyType, AdjCostLCY);
                        OnSumSalesLines2OnAfterCalcTotalAdjCostLCY(TotalAdjCostLCY, SalesLine);
                    end;

                    SalesLine := xSalesLine;
                end;
                if InsertSalesLine then begin
                    NewSalesLine := SalesLine;
                    IsHandled := false;
                    OnSumSalesLines2OnBeforeNewSalesLineInsert(NewSalesLine, IsHandled);
                    if not IsHandled then
                        NewSalesLine.Insert();
                end;
                if RoundingLineInserted then
                    LastLineRetrieved := true
                else begin
                    BiggestLineNo := MAX(BiggestLineNo, OldSalesLine."Line No.");
                    LastLineRetrieved := OldSalesLine.Next() = 0;
                    if LastLineRetrieved and SalesSetup."Invoice Rounding" then
                        InvoiceRounding(SalesHeader, SalesLine, true, BiggestLineNo);
                end;
                OnAfterUpdateInvoiceRounding(
                    SalesHeader, TotalSalesLine, SalesLine, Currency, BiggestLineNo, LastLineRetrieved, RoundingLineInserted, RoundingLineNo, true);
            until LastLineRetrieved;

        OnAfterSumSalesLines2(SalesHeader, OldSalesLine, NewSalesLine);
    end;

    local procedure GetSalesLineQty(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; CalledFromStatistics: Boolean) SalesLineQty: Decimal;
    var
        IsHandled: Boolean;
    begin
        if (CalledFromStatistics) and (not RoundingLineInserted) and (IsInvoiceRoundingLine(SalesHeader, SalesLine)) and (SalesLine."System-Created Entry") then
            exit;

        IsHandled := false;
        OnBeforeGetSalesLineQty(SalesLine, QtyType, SalesLineQty, IsHandled);
        if IsHandled then
            exit(SalesLineQty);

        case QtyType of
            QtyType::General:
                SalesLineQty := SalesLine.Quantity;
            QtyType::Invoicing:
                SalesLineQty := SalesLine."Qty. to Invoice";
            QtyType::Shipping:
                if SalesHeader.IsCreditDocType() then
                    SalesLineQty := SalesLine."Return Qty. to Receive"
                else
                    SalesLineQty := SalesLine."Qty. to Ship";
        end;
    end;

    local procedure GetSalesLineAdjCostLCY(SalesLine2: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; AdjCostLCY: Decimal): Decimal
    var
        IsHandled: Boolean;
        Result: Decimal;
    begin
        IsHandled := false;
        OnBeforeGetSalesLineAdjCostLCY(SalesLine2, QtyType, AdjCostLCY, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if SalesLine2."Document Type" in [SalesLine2."Document Type"::Order, SalesLine2."Document Type"::Invoice] then
            AdjCostLCY := -AdjCostLCY;

        case true of
            SalesLine2."Shipment No." <> '', SalesLine2."Return Receipt No." <> '':
                exit(AdjCostLCY);
            QtyType = QtyType::General:
                exit(Round(SalesLine2."Outstanding Quantity" * SalesLine2."Unit Cost (LCY)") + AdjCostLCY);
            SalesLine2."Document Type" in [SalesLine2."Document Type"::Order, SalesLine2."Document Type"::Invoice]:
                begin
                    if SalesLine2."Qty. to Invoice" > SalesLine2."Qty. to Ship" then
                        exit(Round(SalesLine2."Qty. to Ship" * SalesLine2."Unit Cost (LCY)") + AdjCostLCY);
                    exit(Round(SalesLine2."Qty. to Invoice" * SalesLine2."Unit Cost (LCY)"));
                end;
            SalesLine2.IsCreditDocType():
                begin
                    if SalesLine2."Qty. to Invoice" > SalesLine2."Return Qty. to Receive" then
                        exit(Round(SalesLine2."Return Qty. to Receive" * SalesLine2."Unit Cost (LCY)") + AdjCostLCY);
                    exit(Round(SalesLine2."Qty. to Invoice" * SalesLine2."Unit Cost (LCY)"));
                end;
        end;
    end;

    /// <summary>
    /// Updated the related blanket order line for the quantities that are shipped, received or invoiced with the specified sales line.
    /// </summary>
    /// <param name="SalesLine">The sales line to update the blanket order line for.</param>
    /// <param name="Ship">A flag indicating whether the sales line is being shipped.</param>
    /// <param name="Receive">A flag indicating whether the sales line is being received (Return Orders).</param>
    /// <param name="Invoice">A flag indicating whether the sales line is being invoiced.</param>
    procedure UpdateBlanketOrderLine(SalesLine: Record "Sales Line"; Ship: Boolean; Receive: Boolean; Invoice: Boolean)
    var
        BlanketOrderSalesLine: Record "Sales Line";
        xBlanketOrderSalesLine: Record "Sales Line";
        ModifyLine: Boolean;
        Sign: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateBlanketOrderLine(SalesLine, Ship, Receive, Invoice, IsHandled);
        if IsHandled then
            exit;

        if (SalesLine."Blanket Order No." <> '') and (SalesLine."Blanket Order Line No." <> 0) and
           ((Ship and (SalesLine."Qty. to Ship" <> 0)) or
            (Receive and (SalesLine."Return Qty. to Receive" <> 0)) or
            (Invoice and (SalesLine."Qty. to Invoice" <> 0)))
        then
            if BlanketOrderSalesLine.Get(
                 BlanketOrderSalesLine."Document Type"::"Blanket Order", SalesLine."Blanket Order No.",
                 SalesLine."Blanket Order Line No.")
            then begin
                BlanketOrderSalesLine.TestField(Type, SalesLine.Type);
                BlanketOrderSalesLine.TestField("No.", SalesLine."No.");
                IsHandled := false;
                OnUpdateBlanketOrderLineOnBeforeCheckSellToCustomerNo(BlanketOrderSalesLine, SalesLine, IsHandled);
                if not IsHandled then
                    BlanketOrderSalesLine.TestField("Sell-to Customer No.", SalesLine."Sell-to Customer No.");

                ModifyLine := false;
                case SalesLine."Document Type" of
                    SalesLine."Document Type"::Order,
                  SalesLine."Document Type"::Invoice:
                        Sign := 1;
                    SalesLine."Document Type"::"Return Order",
                  SalesLine."Document Type"::"Credit Memo":
                        Sign := -1;
                end;
                if Ship and (SalesLine."Shipment No." = '') then begin
                    xBlanketOrderSalesLine := BlanketOrderSalesLine;

                    if BlanketOrderSalesLine."Qty. per Unit of Measure" = SalesLine."Qty. per Unit of Measure" then
                        BlanketOrderSalesLine."Quantity Shipped" += Sign * SalesLine."Qty. to Ship"
                    else
                        BlanketOrderSalesLine."Quantity Shipped" +=
                          Sign *
                          Round(
                            (SalesLine."Qty. per Unit of Measure" /
                             BlanketOrderSalesLine."Qty. per Unit of Measure") * SalesLine."Qty. to Ship",
                            UOMMgt.QtyRndPrecision());
                    BlanketOrderSalesLine."Qty. Shipped (Base)" += Sign * SalesLine."Qty. to Ship (Base)";
                    ModifyLine := true;

                    AsmPost.UpdateBlanketATO(xBlanketOrderSalesLine, BlanketOrderSalesLine);
                end;
                if Receive and (SalesLine."Return Receipt No." = '') then begin
                    if BlanketOrderSalesLine."Qty. per Unit of Measure" =
                       SalesLine."Qty. per Unit of Measure"
                    then
                        BlanketOrderSalesLine."Quantity Shipped" += Sign * SalesLine."Return Qty. to Receive"
                    else
                        BlanketOrderSalesLine."Quantity Shipped" +=
                          Sign *
                          Round(
                            (SalesLine."Qty. per Unit of Measure" /
                             BlanketOrderSalesLine."Qty. per Unit of Measure") * SalesLine."Return Qty. to Receive",
                            UOMMgt.QtyRndPrecision());
                    BlanketOrderSalesLine."Qty. Shipped (Base)" += Sign * SalesLine."Return Qty. to Receive (Base)";
                    ModifyLine := true;
                end;
                if Invoice then begin
                    if BlanketOrderSalesLine."Qty. per Unit of Measure" =
                       SalesLine."Qty. per Unit of Measure"
                    then
                        BlanketOrderSalesLine."Quantity Invoiced" += Sign * SalesLine."Qty. to Invoice"
                    else
                        BlanketOrderSalesLine."Quantity Invoiced" +=
                          Sign *
                          Round(
                            (SalesLine."Qty. per Unit of Measure" /
                             BlanketOrderSalesLine."Qty. per Unit of Measure") * SalesLine."Qty. to Invoice",
                            UOMMgt.QtyRndPrecision());
                    BlanketOrderSalesLine."Qty. Invoiced (Base)" += Sign * SalesLine."Qty. to Invoice (Base)";
                    ModifyLine := true;
                end;

                if ModifyLine then begin
                    OnUpdateBlanketOrderLineOnBeforeInitOutstanding(BlanketOrderSalesLine, SalesLine, Ship, Receive, Invoice);
                    BlanketOrderSalesLine.InitOutstanding();

                    IsHandled := false;
                    OnUpdateBlanketOrderLineOnBeforeCheck(BlanketOrderSalesLine, SalesLine, IsHandled);
                    if not IsHandled then begin
                        if (BlanketOrderSalesLine.Quantity * BlanketOrderSalesLine."Quantity Shipped" < 0) or
                           (Abs(BlanketOrderSalesLine.Quantity) < Abs(BlanketOrderSalesLine."Quantity Shipped"))
                        then
                            BlanketOrderSalesLine.FieldError(
                              "Quantity Shipped", StrSubstNo(BlanketOrderQuantityGreaterThanErr, BlanketOrderSalesLine.FieldCaption(Quantity)));
                        if (BlanketOrderSalesLine."Quantity (Base)" * BlanketOrderSalesLine."Qty. Shipped (Base)" < 0) or
                           (Abs(BlanketOrderSalesLine."Quantity (Base)") < Abs(BlanketOrderSalesLine."Qty. Shipped (Base)"))
                        then
                            BlanketOrderSalesLine.FieldError(
                              "Qty. Shipped (Base)",
                              StrSubstNo(BlanketOrderQuantityGreaterThanErr, BlanketOrderSalesLine.FieldCaption("Quantity (Base)")));
                        BlanketOrderSalesLine.CalcFields("Reserved Qty. (Base)");
                        if Abs(BlanketOrderSalesLine."Outstanding Qty. (Base)") < Abs(BlanketOrderSalesLine."Reserved Qty. (Base)") then
                            BlanketOrderSalesLine.FieldError(
                              "Reserved Qty. (Base)", BlanketOrderQuantityReducedErr);
                    end;

                    BlanketOrderSalesLine."Qty. to Invoice" :=
                        BlanketOrderSalesLine.Quantity - BlanketOrderSalesLine."Quantity Invoiced";
                    if (SalesLine.Quantity = SalesLine."Quantity Shipped") or (SalesLine."Quantity Shipped" = 0) then
                        BlanketOrderSalesLine."Qty. to Ship" :=
                            BlanketOrderSalesLine.Quantity - BlanketOrderSalesLine."Quantity Shipped";
                    BlanketOrderSalesLine."Qty. to Invoice (Base)" :=
                        BlanketOrderSalesLine."Quantity (Base)" - BlanketOrderSalesLine."Qty. Invoiced (Base)";
                    if (SalesLine."Quantity (Base)" = SalesLine."Qty. Shipped (Base)") or (SalesLine."Qty. Shipped (Base)" = 0) then
                        BlanketOrderSalesLine."Qty. to Ship (Base)" :=
                            BlanketOrderSalesLine."Quantity (Base)" - BlanketOrderSalesLine."Qty. Shipped (Base)";

                    OnBeforeBlanketOrderSalesLineModify(BlanketOrderSalesLine, SalesLine);
                    BlanketOrderSalesLine.Modify();
                    OnAfterUpdateBlanketOrderLine(BlanketOrderSalesLine, SalesLine, Ship, Receive, Invoice);
                end;
            end;
    end;

    local procedure DeleteItemChargeAssgnt(SalesHeader: Record "Sales Header")
    var
        ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)";
    begin
        ItemChargeAssgntSales.SetRange("Document Type", SalesHeader."Document Type");
        ItemChargeAssgntSales.SetRange("Document No.", SalesHeader."No.");
        if not ItemChargeAssgntSales.IsEmpty() then
            ItemChargeAssgntSales.DeleteAll();
    end;

    local procedure UpdateItemChargeAssgnt(var SalesHeader: Record "Sales Header")
    var
        ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)";
    begin
        ClearItemChargeAssgntFilter();
        TempItemChargeAssgntSales.MarkedOnly(true);
        if TempItemChargeAssgntSales.FindSet() then
            repeat
                ItemChargeAssgntSales.Get(TempItemChargeAssgntSales."Document Type", TempItemChargeAssgntSales."Document No.", TempItemChargeAssgntSales."Document Line No.", TempItemChargeAssgntSales."Line No.");
                ItemChargeAssgntSales."Qty. Assigned" += ItemChargeAssgntSales."Qty. to Handle";
                ItemChargeAssgntSales."Qty. to Assign" -= ItemChargeAssgntSales."Qty. to Handle";
                ItemChargeAssgntSales."Amount to Assign" -= ItemChargeAssgntSales."Amount to Handle";
                ItemChargeAssgntSales."Qty. to Handle" := 0;
                ItemChargeAssgntSales."Amount to Handle" := 0;
                ItemChargeAssgntSales.Modify();
            until TempItemChargeAssgntSales.Next() = 0;

        OnAfterUpdateItemChargeAssgnt(SalesHeader);
    end;

    /// <summary>
    /// Updates the Item Charge Assignment (Sales) lines quantities for the quantity that was posted for the specified sales line.
    /// </summary>
    /// <param name="SalesOrderInvLine">sales line of type Charge (Item) for the document being posted which is of type Invoice or Credit Memo</param>
    /// <param name="SalesOrderLine">sales line of  document type Order or Return Order that is related to the SalesOrderInvLine</param>
    procedure UpdateSalesOrderChargeAssgnt(SalesOrderInvLine: Record "Sales Line"; SalesOrderLine: Record "Sales Line")
    var
        SalesOrderLine2: Record "Sales Line";
        SalesOrderInvLine2: Record "Sales Line";
        SalesShptLine: Record "Sales Shipment Line";
        ReturnRcptLine: Record "Return Receipt Line";
    begin
        ClearItemChargeAssgntFilter();
        TempItemChargeAssgntSales.SetRange("Document Type", SalesOrderInvLine."Document Type");
        TempItemChargeAssgntSales.SetRange("Document No.", SalesOrderInvLine."Document No.");
        TempItemChargeAssgntSales.SetRange("Document Line No.", SalesOrderInvLine."Line No.");
        TempItemChargeAssgntSales.MarkedOnly(true);
        if TempItemChargeAssgntSales.FindSet() then
            repeat
                if TempItemChargeAssgntSales."Applies-to Doc. Type" = SalesOrderInvLine."Document Type" then begin
                    SalesOrderInvLine2.Get(
                      TempItemChargeAssgntSales."Applies-to Doc. Type",
                      TempItemChargeAssgntSales."Applies-to Doc. No.",
                      TempItemChargeAssgntSales."Applies-to Doc. Line No.");
                    if SalesOrderLine."Document Type" = SalesOrderLine."Document Type"::Order then begin
                        if not
                           SalesShptLine.Get(SalesOrderInvLine2."Shipment No.", SalesOrderInvLine2."Shipment Line No.")
                        then
                            Error(ShipmentLinesDeletedErr);
                        SalesOrderLine2.Get(
                          SalesOrderLine2."Document Type"::Order,
                          SalesShptLine."Order No.", SalesShptLine."Order Line No.");
                    end else begin
                        if not
                           ReturnRcptLine.Get(SalesOrderInvLine2."Return Receipt No.", SalesOrderInvLine2."Return Receipt Line No.")
                        then
                            Error(ReturnReceiptLinesDeletedErr);
                        SalesOrderLine2.Get(
                          SalesOrderLine2."Document Type"::"Return Order",
                          ReturnRcptLine."Return Order No.", ReturnRcptLine."Return Order Line No.");
                    end;
                    UpdateSalesChargeAssgntLines(
                      SalesOrderLine,
                      SalesOrderLine2."Document Type",
                      SalesOrderLine2."Document No.",
                      SalesOrderLine2."Line No.",
                      TempItemChargeAssgntSales."Qty. to Handle");
                end else
                    UpdateSalesChargeAssgntLines(
                      SalesOrderLine,
                      TempItemChargeAssgntSales."Applies-to Doc. Type",
                      TempItemChargeAssgntSales."Applies-to Doc. No.",
                      TempItemChargeAssgntSales."Applies-to Doc. Line No.",
                      TempItemChargeAssgntSales."Qty. to Handle");
            until TempItemChargeAssgntSales.Next() = 0;
    end;

    local procedure UpdateSalesChargeAssgntLines(SalesOrderLine: Record "Sales Line"; ApplToDocType: Enum "Sales Applies-to Document Type"; ApplToDocNo: Code[20]; ApplToDocLineNo: Integer; QtyToHandle: Decimal)
    var
        ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)";
        TempItemChargeAssgntSales2: Record "Item Charge Assignment (Sales)";
        LastLineNo: Integer;
        TotalToAssign: Decimal;
    begin
        ItemChargeAssgntSales.SetRange("Document Type", SalesOrderLine."Document Type");
        ItemChargeAssgntSales.SetRange("Document No.", SalesOrderLine."Document No.");
        ItemChargeAssgntSales.SetRange("Document Line No.", SalesOrderLine."Line No.");
        ItemChargeAssgntSales.SetRange("Applies-to Doc. Type", ApplToDocType);
        ItemChargeAssgntSales.SetRange("Applies-to Doc. No.", ApplToDocNo);
        ItemChargeAssgntSales.SetRange("Applies-to Doc. Line No.", ApplToDocLineNo);
        if ItemChargeAssgntSales.FindFirst() then begin
            ItemChargeAssgntSales."Qty. Assigned" += QtyToHandle;
            ItemChargeAssgntSales."Qty. to Assign" -= QtyToHandle;
            ItemChargeAssgntSales."Qty. to Handle" -= QtyToHandle;
            if ItemChargeAssgntSales."Qty. to Assign" < 0 then
                ItemChargeAssgntSales."Qty. to Assign" := 0;
            ItemChargeAssgntSales."Amount to Assign" :=
              Round(ItemChargeAssgntSales."Qty. to Assign" * ItemChargeAssgntSales."Unit Cost", Currency."Amount Rounding Precision");
            if ItemChargeAssgntSales."Qty. to Handle" < 0 then
                ItemChargeAssgntSales."Qty. to Handle" := 0;
            ItemChargeAssgntSales."Amount to Handle" :=
              Round(ItemChargeAssgntSales."Qty. to Handle" * ItemChargeAssgntSales."Unit Cost", Currency."Amount Rounding Precision");
            ItemChargeAssgntSales.Modify();
        end else begin
            ItemChargeAssgntSales.SetRange("Applies-to Doc. Type");
            ItemChargeAssgntSales.SetRange("Applies-to Doc. No.");
            ItemChargeAssgntSales.SetRange("Applies-to Doc. Line No.");
            ItemChargeAssgntSales.CalcSums("Qty. to Assign", "Qty. to Handle");

            // calculate total qty. to assign of the invoice charge line
            TempItemChargeAssgntSales2.SetRange("Document Type", TempItemChargeAssgntSales."Document Type");
            TempItemChargeAssgntSales2.SetRange("Document No.", TempItemChargeAssgntSales."Document No.");
            TempItemChargeAssgntSales2.SetRange("Document Line No.", TempItemChargeAssgntSales."Document Line No.");
            TempItemChargeAssgntSales2.CalcSums("Qty. to Assign", "Qty. to Handle");

            TotalToAssign := ItemChargeAssgntSales."Qty. to Handle" + TempItemChargeAssgntSales2."Qty. to Handle";

            if ItemChargeAssgntSales.FindLast() then
                LastLineNo := ItemChargeAssgntSales."Line No.";

            if SalesOrderLine.Quantity < TotalToAssign then
                repeat
                    TotalToAssign -= ItemChargeAssgntSales."Qty. to Handle";
                    ItemChargeAssgntSales."Qty. to Assign" -= ItemChargeAssgntSales."Qty. to Handle";
                    ItemChargeAssgntSales."Amount to Assign" -= ItemChargeAssgntSales."Amount to Handle";
                    ItemChargeAssgntSales."Qty. to Handle" := 0;
                    ItemChargeAssgntSales."Amount to Handle" := 0;
                    ItemChargeAssgntSales.Modify();
                until (ItemChargeAssgntSales.Next(-1) = 0) or (TotalToAssign = SalesOrderLine.Quantity);

            InsertAssocOrderCharge(
              SalesOrderLine, ApplToDocType, ApplToDocNo, ApplToDocLineNo, LastLineNo,
              TempItemChargeAssgntSales."Applies-to Doc. Line Amount");
        end;
    end;

    local procedure InsertAssocOrderCharge(SalesOrderLine: Record "Sales Line"; ApplToDocType: Enum "Sales Applies-to Document Type"; ApplToDocNo: Code[20]; ApplToDocLineNo: Integer; LastLineNo: Integer; ApplToDocLineAmt: Decimal)
    var
        NewItemChargeAssgntSales: Record "Item Charge Assignment (Sales)";
    begin
        NewItemChargeAssgntSales.Init();
        NewItemChargeAssgntSales."Document Type" := SalesOrderLine."Document Type";
        NewItemChargeAssgntSales."Document No." := SalesOrderLine."Document No.";
        NewItemChargeAssgntSales."Document Line No." := SalesOrderLine."Line No.";
        NewItemChargeAssgntSales."Line No." := LastLineNo + 10000;
        NewItemChargeAssgntSales."Item Charge No." := TempItemChargeAssgntSales."Item Charge No.";
        NewItemChargeAssgntSales."Item No." := TempItemChargeAssgntSales."Item No.";
        NewItemChargeAssgntSales."Qty. Assigned" := TempItemChargeAssgntSales."Qty. to Handle";
        NewItemChargeAssgntSales."Qty. to Handle" := 0;
        NewItemChargeAssgntSales."Amount to Handle" := 0;
        NewItemChargeAssgntSales.Description := TempItemChargeAssgntSales.Description;
        NewItemChargeAssgntSales."Unit Cost" := TempItemChargeAssgntSales."Unit Cost";
        NewItemChargeAssgntSales."Applies-to Doc. Type" := ApplToDocType;
        NewItemChargeAssgntSales."Applies-to Doc. No." := ApplToDocNo;
        NewItemChargeAssgntSales."Applies-to Doc. Line No." := ApplToDocLineNo;
        NewItemChargeAssgntSales."Applies-to Doc. Line Amount" := ApplToDocLineAmt;
        OnInsertAssocOrderChargeOnBeforeNewItemChargeAssgntSalesInsert(TempItemChargeAssgntSales, NewItemChargeAssgntSales);
        NewItemChargeAssgntSales.Insert();
    end;

    /// <summary>
    /// Copies and validates item charge assignments for posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header record to process item charges for.</param>
    procedure CopyAndCheckItemCharge(SalesHeader: Record "Sales Header")
    var
        TempSalesLine: Record "Sales Line" temporary;
        SalesLine: Record "Sales Line";
        InvoiceEverything: Boolean;
        AssignError: Boolean;
        SkipTestJobNo: Boolean;
        QtyNeeded: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCopyAndCheckItemCharge(
            SalesHeader, TempSalesLine, SalesLine, InvoiceEverything, AssignError, QtyNeeded, TempItemChargeAssgntSales, ItemChargeAssgntSales, TempSalesLineGlobal, IsHandled);
        if IsHandled then
            exit;

        TempItemChargeAssgntSales.Reset();
        TempItemChargeAssgntSales.DeleteAll();

        // Check for max qty posting
        ResetTempLines(TempSalesLine);
        TempSalesLine.SetRange(Type, TempSalesLine.Type::"Charge (Item)");
        if TempSalesLine.IsEmpty() then
            exit;

        CopyItemChargeForSalesLine(TempItemChargeAssgntSales, TempSalesLine);

        TempSalesLine.SetFilter("Qty. to Invoice", '<>0');
        if TempSalesLine.FindSet() then
            repeat
                SkipTestJobNo := false;
                OnCopyAndCheckItemChargeOnBeforeLoop(TempSalesLine, SalesHeader, SkipTestJobNo);
                if not SkipTestJobNo then begin
                    TempSalesLine.TestField("Job No.", '', ErrorInfo.Create());
                    TempSalesLine.TestField("Job Contract Entry No.", 0, ErrorInfo.Create());
                end;
                if (TempSalesLine."Qty. to Ship" + TempSalesLine."Return Qty. to Receive" <> 0) and
                   ((SalesHeader.Ship or SalesHeader.Receive) or
                    (Abs(TempSalesLine."Qty. to Invoice") >
                     Abs(TempSalesLine."Qty. Shipped Not Invoiced" + TempSalesLine."Qty. to Ship") +
                     Abs(TempSalesLine."Ret. Qty. Rcd. Not Invd.(Base)" + TempSalesLine."Return Qty. to Receive")))
                then
                    TempSalesLine.TestField("Line Amount", ErrorInfo.Create());

                if not SalesHeader.Ship then
                    TempSalesLine."Qty. to Ship" := 0;
                if not SalesHeader.Receive then
                    TempSalesLine."Return Qty. to Receive" := 0;

                IsHandled := false;
                OnCopyAndCheckItemChargeOnBeforeAssignQtyToInvoice(TempSalesLine, IsHandled);
                if not IsHandled then
                    if Abs(TempSalesLine."Qty. to Invoice") >
                        Abs(TempSalesLine."Quantity Shipped" + TempSalesLine."Qty. to Ship" + TempSalesLine."Return Qty. Received" + TempSalesLine."Return Qty. to Receive" - TempSalesLine."Quantity Invoiced")
                    then
                        TempSalesLine."Qty. to Invoice" :=
                        TempSalesLine."Quantity Shipped" + TempSalesLine."Qty. to Ship" + TempSalesLine."Return Qty. Received" + TempSalesLine."Return Qty. to Receive" - TempSalesLine."Quantity Invoiced";

                TempSalesLine.CalcFields("Qty. to Assign", "Qty. Assigned", "Item Charge Qty. to Handle");
                if Abs(TempSalesLine."Item Charge Qty. to Handle" + TempSalesLine."Qty. Assigned") > Abs(TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced") then begin
                    AdjustQtyToAssignForSalesLine(TempSalesLine);

                    TempSalesLine.CalcFields("Qty. to Assign", "Qty. Assigned", "Item Charge Qty. to Handle");
                    if Abs(TempSalesLine."Item Charge Qty. to Handle" + TempSalesLine."Qty. Assigned") > Abs(TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced") then
                        Error(CannotAssignMoreErr,
                          TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced" - TempSalesLine."Qty. Assigned",
                          TempSalesLine.FieldCaption("Document Type"), TempSalesLine."Document Type",
                          TempSalesLine.FieldCaption("Document No."), TempSalesLine."Document No.",
                          TempSalesLine.FieldCaption("Line No."), TempSalesLine."Line No.");

                    CopyItemChargeForSalesLine(TempItemChargeAssgntSales, TempSalesLine);
                end;

                if TempSalesLine.Quantity = TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced" then begin
                    if TempSalesLine."Item Charge Qty. to Handle" <> 0 then
                        if TempSalesLine.Quantity = TempSalesLine."Quantity Invoiced" then begin
                            TempItemChargeAssgntSales.SetRange("Document Line No.", TempSalesLine."Line No.");
                            TempItemChargeAssgntSales.SetRange("Applies-to Doc. Type", TempSalesLine."Document Type");
                            if TempItemChargeAssgntSales.FindSet() then
                                repeat
                                    SalesLine.Get(
                                      TempItemChargeAssgntSales."Applies-to Doc. Type",
                                      TempItemChargeAssgntSales."Applies-to Doc. No.",
                                      TempItemChargeAssgntSales."Applies-to Doc. Line No.");
                                    if SalesLine.Quantity = SalesLine."Quantity Invoiced" then
                                        Error(CannotAssignInvoicedErr, SalesLine.TableCaption(),
                                          SalesLine.FieldCaption("Document Type"), SalesLine."Document Type",
                                          SalesLine.FieldCaption("Document No."), SalesLine."Document No.",
                                          SalesLine.FieldCaption("Line No."), SalesLine."Line No.");
                                until TempItemChargeAssgntSales.Next() = 0;
                        end;
                    if TempSalesLine.Quantity <> TempSalesLine."Item Charge Qty. to Handle" + TempSalesLine."Qty. Assigned" then
                        AssignError := true;
                end;

                if (TempSalesLine."Item Charge Qty. to Handle" + TempSalesLine."Qty. Assigned") < (TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced") then
                    Error(MustAssignItemChargeErr, TempSalesLine."No.");

                // check if all ILEs exist
                QtyNeeded := TempSalesLine."Item Charge Qty. to Handle";
                TempItemChargeAssgntSales.SetRange("Document Line No.", TempSalesLine."Line No.");
                if TempItemChargeAssgntSales.FindSet() then
                    repeat
                        if (TempItemChargeAssgntSales."Applies-to Doc. Type" <> TempSalesLine."Document Type") or
                           (TempItemChargeAssgntSales."Applies-to Doc. No." <> TempSalesLine."Document No.")
                        then
                            QtyNeeded := QtyNeeded - TempItemChargeAssgntSales."Qty. to Handle"
                        else begin
                            SalesLine.Get(
                              TempItemChargeAssgntSales."Applies-to Doc. Type",
                              TempItemChargeAssgntSales."Applies-to Doc. No.",
                              TempItemChargeAssgntSales."Applies-to Doc. Line No.");
                            if ItemLedgerEntryExist(SalesLine, SalesHeader.Ship or SalesHeader.Receive) then
                                QtyNeeded := QtyNeeded - TempItemChargeAssgntSales."Qty. to Handle";
                        end;
                    until TempItemChargeAssgntSales.Next() = 0;

                if QtyNeeded <> 0 then
                    Error(CannotInvoiceItemChargeErr, TempSalesLine."No.");
            until TempSalesLine.Next() = 0;
        // Check saleslines
        if AssignError then
            if SalesHeader."Document Type" in
               [SalesHeader."Document Type"::Invoice, SalesHeader."Document Type"::"Credit Memo"]
            then
                InvoiceEverything := true
            else begin
                TempSalesLine.Reset();
                TempSalesLine.SetFilter(Type, '%1|%2', TempSalesLine.Type::Item, TempSalesLine.Type::"Charge (Item)");
                if TempSalesLine.FindSet() then
                    repeat
                        if SalesHeader.Ship or SalesHeader.Receive then
                            InvoiceEverything :=
                              TempSalesLine.Quantity = TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced"
                        else
                            InvoiceEverything :=
                              (TempSalesLine.Quantity = TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced") and
                              (TempSalesLine."Qty. to Invoice" =
                               TempSalesLine."Qty. Shipped Not Invoiced" + TempSalesLine."Ret. Qty. Rcd. Not Invd.(Base)");
                    until (TempSalesLine.Next() = 0) or (not InvoiceEverything);
            end;

        OnCopyAndCheckItemChargeOnBeforeError(SalesHeader, TempSalesLine, InvoiceEverything);

        if InvoiceEverything and AssignError then
            Error(MustAssignErr);
    end;

    local procedure CopyItemChargeForSalesLine(var TempItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)" temporary; SalesLine: Record "Sales Line")
    var
        ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)";
    begin
        TempItemChargeAssignmentSales.Reset();
        TempItemChargeAssignmentSales.SetRange("Document Type", SalesLine."Document Type");
        TempItemChargeAssignmentSales.SetRange("Document No.", SalesLine."Document No.");
        if not TempItemChargeAssignmentSales.IsEmpty() then
            TempItemChargeAssignmentSales.DeleteAll();

        ItemChargeAssignmentSales.CopyFilters(TempItemChargeAssignmentSales);
        ItemChargeAssignmentSales.SetFilter("Qty. to Handle", '<>0');
        if ItemChargeAssignmentSales.FindSet() then
            repeat
                TempItemChargeAssignmentSales.Init();
                TempItemChargeAssignmentSales := ItemChargeAssignmentSales;
                TempItemChargeAssignmentSales.Insert();
            until ItemChargeAssignmentSales.Next() = 0;
    end;

    local procedure AdjustQtyToAssignForSalesLine(var TempSalesLine: Record "Sales Line" temporary)
    var
        ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)";
        Delta: Decimal;
        QtyToHandle: Decimal;
    begin
        TempSalesLine.CalcFields("Qty. to Assign");

        ItemChargeAssignmentSales.Reset();
        ItemChargeAssignmentSales.SetRange("Document Type", TempSalesLine."Document Type");
        ItemChargeAssignmentSales.SetRange("Document No.", TempSalesLine."Document No.");
        ItemChargeAssignmentSales.SetRange("Document Line No.", TempSalesLine."Line No.");
        ItemChargeAssignmentSales.SetFilter("Qty. to Assign", '<>0');
        if ItemChargeAssignmentSales.FindSet() then
            repeat
                QtyToHandle := ItemChargeAssignmentSales."Qty. to Handle";
                ItemChargeAssignmentSales.Validate("Qty. to Assign",
                  TempSalesLine."Qty. to Invoice" * Round(ItemChargeAssignmentSales."Qty. to Assign" / TempSalesLine."Qty. to Assign",
                    UOMMgt.QtyRndPrecision()));
                if QtyToHandle = 0 then
                    ItemChargeAssignmentSales.Validate("Qty. to Handle", 0);
                ItemChargeAssignmentSales.Modify();
            until ItemChargeAssignmentSales.Next() = 0;

        TempSalesLine.CalcFields("Qty. to Assign");
        Delta := TempSalesLine."Qty. to Invoice" - TempSalesLine."Qty. to Assign";
        if Delta <> 0 then begin
            QtyToHandle := ItemChargeAssignmentSales."Qty. to Handle";
            ItemChargeAssignmentSales.Validate("Qty. to Assign", ItemChargeAssignmentSales."Qty. to Assign" + Delta);
            if QtyToHandle = 0 then
                ItemChargeAssignmentSales.Validate("Qty. to Handle", 0);
            ItemChargeAssignmentSales.Modify();
        end;
    end;

    local procedure ClearItemChargeAssgntFilter()
    begin
        TempItemChargeAssgntSales.SetRange("Document Line No.");
        TempItemChargeAssgntSales.SetRange("Applies-to Doc. Type");
        TempItemChargeAssgntSales.SetRange("Applies-to Doc. No.");
        TempItemChargeAssgntSales.SetRange("Applies-to Doc. Line No.");
        TempItemChargeAssgntSales.MarkedOnly(false);
    end;

    local procedure GetItemChargeLine(SalesHeader: Record "Sales Header"; var ItemChargeSalesLine: Record "Sales Line")
    var
        SalesShptLine: Record "Sales Shipment Line";
        ReturnReceiptLine: Record "Return Receipt Line";
        QtyShippedNotInvd: Decimal;
        QtyReceivedNotInvd: Decimal;
    begin
        if (ItemChargeSalesLine."Document Type" <> TempItemChargeAssgntSales."Document Type") or
            (ItemChargeSalesLine."Document No." <> TempItemChargeAssgntSales."Document No.") or
            (ItemChargeSalesLine."Line No." <> TempItemChargeAssgntSales."Document Line No.")
        then begin
            ItemChargeSalesLine.Get(TempItemChargeAssgntSales."Document Type", TempItemChargeAssgntSales."Document No.", TempItemChargeAssgntSales."Document Line No.");
            if not SalesHeader.Ship then
                ItemChargeSalesLine."Qty. to Ship" := 0;
            if not SalesHeader.Receive then
                ItemChargeSalesLine."Return Qty. to Receive" := 0;
            if ItemChargeSalesLine."Shipment No." <> '' then begin
                SalesShptLine.Get(ItemChargeSalesLine."Shipment No.", ItemChargeSalesLine."Shipment Line No.");
                QtyShippedNotInvd := TempItemChargeAssgntSales."Qty. to Handle" - TempItemChargeAssgntSales."Qty. Assigned";
            end else
                QtyShippedNotInvd := ItemChargeSalesLine."Quantity Shipped";
            if ItemChargeSalesLine."Return Receipt No." <> '' then begin
                ReturnReceiptLine.Get(ItemChargeSalesLine."Return Receipt No.", ItemChargeSalesLine."Return Receipt Line No.");
                QtyReceivedNotInvd := TempItemChargeAssgntSales."Qty. to Handle" - TempItemChargeAssgntSales."Qty. Assigned";
            end else
                QtyReceivedNotInvd := ItemChargeSalesLine."Return Qty. Received";
            if Abs(ItemChargeSalesLine."Qty. to Invoice") >
               Abs(QtyShippedNotInvd + ItemChargeSalesLine."Qty. to Ship" +
                 QtyReceivedNotInvd + ItemChargeSalesLine."Return Qty. to Receive" -
                 ItemChargeSalesLine."Quantity Invoiced")
            then
                ItemChargeSalesLine."Qty. to Invoice" :=
                  QtyShippedNotInvd + ItemChargeSalesLine."Qty. to Ship" +
                  QtyReceivedNotInvd + ItemChargeSalesLine."Return Qty. to Receive" -
                  ItemChargeSalesLine."Quantity Invoiced";
        end;
    end;

    local procedure CalcQtyToInvoice(QtyToHandle: Decimal; QtyToInvoice: Decimal): Decimal
    begin
        if Abs(QtyToHandle) > Abs(QtyToInvoice) then
            exit(-QtyToHandle);

        exit(-QtyToInvoice);
    end;

    local procedure CheckWarehouse(var TempItemSalesLine: Record "Sales Line" temporary)
    var
        ShowError: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckWarehouse(TempItemSalesLine, IsHandled);
        if IsHandled then
            exit;

        TempItemSalesLine.SetRange(Type, TempItemSalesLine.Type::Item);
        TempItemSalesLine.SetRange("Drop Shipment", false);
        if TempItemSalesLine.FindSet() then
            repeat
                if TempItemSalesLine.IsInventoriableItem() then begin
                    GetLocation(TempItemSalesLine."Location Code");
                    case TempItemSalesLine."Document Type" of
                        TempItemSalesLine."Document Type"::Order:
                            if ((Location."Require Receive" or Location."Require Put-away") and (TempItemSalesLine.Quantity < 0)) or
                               ((Location."Require Shipment" or Location."Require Pick") and (TempItemSalesLine.Quantity >= 0))
                            then
                                ShowError := GetShowErrorOnWarehouseCheck(TempItemSalesLine, Location);
                        TempItemSalesLine."Document Type"::"Return Order":
                            if ((Location."Require Receive" or Location."Require Put-away") and (TempItemSalesLine.Quantity >= 0)) or
                               ((Location."Require Shipment" or Location."Require Pick") and (TempItemSalesLine.Quantity < 0))
                            then
                                ShowError := GetShowErrorOnWarehouseCheck(TempItemSalesLine, Location);
                        TempItemSalesLine."Document Type"::Invoice, TempItemSalesLine."Document Type"::"Credit Memo":
                            if Location."Directed Put-away and Pick" then
                                Location.TestField("Adjustment Bin Code");
                    end;
                    if ShowError then
                        Error(
                          WarehouseRequiredErr,
                          TempItemSalesLine.FieldCaption("Document Type"), TempItemSalesLine."Document Type",
                          TempItemSalesLine.FieldCaption("Document No."), TempItemSalesLine."Document No.",
                          TempItemSalesLine.FieldCaption("Line No."), TempItemSalesLine."Line No.");
                end;
            until TempItemSalesLine.Next() = 0;
    end;

    local procedure GetShowErrorOnWarehouseCheck(var SalesLine: Record "Sales Line"; Location: Record Location) ShowError: Boolean;
    var
        WhseValidateSourceLine: Codeunit "Whse. Validate Source Line";
    begin
        if Location."Directed Put-away and Pick" then
            ShowError := true
        else
            if WhseValidateSourceLine.WhseLinesExist(
                 DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(),
                 SalesLine."Document No.", SalesLine."Line No.", 0, SalesLine.Quantity)
            then begin
                ShowError := true;
                OnAfterWhseLinesExist(WhseValidateSourceLine, SalesLine, ShowError);
            end;
    end;

    /// <summary>
    /// Creates a Warehouse Journal Line for the specified sales line.
    /// </summary>
    /// <remarks>
    /// Error can be raised if the Adjustment Bin of the Location has Movement Block.
    /// </remarks>
    /// <param name="ItemJnlLine">The Item Journal Line to create the Warehouse Journal Line for.</param>
    /// <param name="SalesLine">The sales line to create the Warehouse Journal Line for.</param>
    /// <param name="TempWhseJnlLine">Return Variable: The created Warehouse Journal Line.</param>
    procedure CreateWhseJnlLine(ItemJnlLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; var TempWhseJnlLine: Record "Warehouse Journal Line" temporary)
    var
        WhseMgt: Codeunit "Whse. Management";
        WMSMgt: Codeunit "WMS Management";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateWhseJnlLine(ItemJnlLine, IsHandled);
        if IsHandled then
            exit;

        WMSMgt.CheckAdjmtBin(Location, ItemJnlLine.Quantity, true);
        WMSMgt.CreateWhseJnlLine(ItemJnlLine, 0, TempWhseJnlLine, false);
        TempWhseJnlLine."Source Type" := DATABASE::"Sales Line";
        TempWhseJnlLine."Source Subtype" := SalesLine."Document Type".AsInteger();
        TempWhseJnlLine."Source Code" := SrcCode;
        TempWhseJnlLine."Source Document" := WhseMgt.GetWhseJnlSourceDocument(TempWhseJnlLine."Source Type", TempWhseJnlLine."Source Subtype");
        TempWhseJnlLine."Source No." := SalesLine."Document No.";
        TempWhseJnlLine."Source Line No." := SalesLine."Line No.";
        case SalesLine."Document Type" of
            SalesLine."Document Type"::Order:
                TempWhseJnlLine."Reference Document" :=
                    TempWhseJnlLine."Reference Document"::"Posted Shipment";
            SalesLine."Document Type"::Invoice:
                TempWhseJnlLine."Reference Document" :=
                    TempWhseJnlLine."Reference Document"::"Posted S. Inv.";
            SalesLine."Document Type"::"Credit Memo":
                TempWhseJnlLine."Reference Document" :=
                    TempWhseJnlLine."Reference Document"::"Posted S. Cr. Memo";
            SalesLine."Document Type"::"Return Order":
                TempWhseJnlLine."Reference Document" :=
                    TempWhseJnlLine."Reference Document"::"Posted Rtrn. Rcpt.";
        end;
        TempWhseJnlLine."Reference No." := ItemJnlLine."Document No.";

        OnAfterCreateWhseJnlLine(SalesLine, TempWhseJnlLine);
    end;

    /// <summary>
    /// Checks if warehouse handling (warehouse shipment or receipt) is required for the specified sales line.
    /// Warehouse handling is relevant for sales lines for inventoriable item. Warehouse setup or location (if specified) determines if Warehouse Handling is required.
    /// Drop shipments do not require Warehouse Handling.
    /// </summary>
    /// <param name="SalesLine">The sales line to check.</param>
    /// <returns>Returns true if Warehouse Handling is required, otherwise false.</returns>
    procedure WhseHandlingRequiredExternal(SalesLine: Record "Sales Line"): Boolean
    begin
        exit(WhseHandlingRequired(SalesLine));
    end;

    local procedure WhseHandlingRequired(SalesLine: Record "Sales Line") Required: Boolean
    var
        WhseSetup: Record "Warehouse Setup";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeWhseHandlingRequired(SalesLine, Required, IsHandled);
        if IsHandled then
            exit(Required);

        if SalesLine.IsInventoriableItem() and (not SalesLine."Drop Shipment") then begin
            if SalesLine."Location Code" = '' then begin
                WhseSetup.Get();
                if SalesLine."Document Type" = SalesLine."Document Type"::"Return Order" then
                    exit(WhseSetup."Require Receive");

                exit(WhseSetup."Require Shipment");
            end;

            GetLocation(SalesLine."Location Code");
            if SalesLine."Document Type" = SalesLine."Document Type"::"Return Order" then
                exit(Location."Require Receive");

            exit(Location."Require Shipment");
        end;
        exit(false);
    end;

    local procedure GetLocation(LocationCode: Code[10])
    begin
        if LocationCode = '' then
            Location.GetLocationSetup(LocationCode, Location)
        else
            if Location.Code <> LocationCode then
                Location.Get(LocationCode);
    end;

    local procedure InsertShptEntryRelation(SalesHeader: Record "Sales Header"; var SalesShptLine: Record "Sales Shipment Line") ItemShptEntryNo: Integer
    var
        ItemEntryRelation: Record "Item Entry Relation";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertShptEntryRelation(SalesHeader, SalesShptLine, ItemShptEntryNo, IsHandled);
        if IsHandled then
            exit(ItemShptEntryNo);

        TempHandlingSpecification.CopySpecification(TempTrackingSpecificationInv);
        TempHandlingSpecification.CopySpecification(TempATOTrackingSpecification);
        TempHandlingSpecification.Reset();
        if TempHandlingSpecification.FindSet() then begin
            repeat
                ItemEntryRelation.InitFromTrackingSpec(TempHandlingSpecification);
                ItemEntryRelation.TransferFieldsSalesShptLine(SalesShptLine);
                ItemEntryRelation.Insert();
                OnInsertShptEntryRelationOnAfterItemEntryRelationInsert(SalesShptLine, ItemEntryRelation, xSalesLine);
            until TempHandlingSpecification.Next() = 0;

            OnInsertShptEntryRelationOnBeforeDeleteTempHandlingSpecification(TempHandlingSpecification);
            TempHandlingSpecification.DeleteAll();
            exit(0);
        end;
        exit(ItemLedgShptEntryNo);
    end;

    local procedure InsertReturnEntryRelation(var ReturnRcptLine: Record "Return Receipt Line") EntryNo: Integer
    var
        ItemEntryRelation: Record "Item Entry Relation";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertReturnEntryRelation(ReturnRcptLine, EntryNo, IsHandled);
        if IsHandled then
            exit;

        TempHandlingSpecification.CopySpecification(TempTrackingSpecificationInv);
        TempHandlingSpecification.CopySpecification(TempATOTrackingSpecification);
        TempHandlingSpecification.Reset();
        if TempHandlingSpecification.FindSet() then begin
            repeat
                ItemEntryRelation.InitFromTrackingSpec(TempHandlingSpecification);
                ItemEntryRelation.TransferFieldsReturnRcptLine(ReturnRcptLine);
                ItemEntryRelation.Insert();
            until TempHandlingSpecification.Next() = 0;
            TempHandlingSpecification.DeleteAll();
            exit(0);
        end;
        exit(ItemLedgShptEntryNo);
    end;

    /// <summary>
    /// Checks if the sales line is posted with Item Tracking, then tracked quantity must be equal to posted quantity.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document. Only Orders and Return Orders are relevant.</param>
    /// <param name="TempItemSalesLine">Temp sales lines to Check.</param>
    procedure CheckTrackingSpecification(SalesHeader: Record "Sales Header"; var TempItemSalesLine: Record "Sales Line" temporary)
    var
        ReservationEntry: Record "Reservation Entry";
        ItemTrackingCode: Record "Item Tracking Code";
        ItemTrackingSetup: Record "Item Tracking Setup";
        ItemJnlLine: Record "Item Journal Line";
        CreateReservEntry: Codeunit "Create Reserv. Entry";
        ItemTrackingManagement: Codeunit "Item Tracking Management";
        ErrorFieldCaption: Text;
        SignFactor: Integer;
        SalesLineQtyToHandle: Decimal;
        TrackingQtyToHandle: Decimal;
        Inbound: Boolean;
        CheckSalesLine: Boolean;
        IsHandled: Boolean;
    begin
        OnBeforeCheckTrackingSpecification(SalesHeader, TempItemSalesLine);
        // if a SalesLine is posted with ItemTracking then tracked quantity must be equal to posted quantity
        if not (SalesHeader."Document Type" in
                [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::"Return Order"])
        then
            exit;

        TrackingQtyToHandle := 0;

        TempItemSalesLine.SetRange(Type, TempItemSalesLine.Type::Item);
        if SalesHeader.Ship then begin
            TempItemSalesLine.SetFilter("Quantity Shipped", '<>%1', 0);
            ErrorFieldCaption := TempItemSalesLine.FieldCaption("Qty. to Ship");
        end else begin
            TempItemSalesLine.SetFilter("Return Qty. Received", '<>%1', 0);
            ErrorFieldCaption := TempItemSalesLine.FieldCaption("Return Qty. to Receive");
        end;

        if TempItemSalesLine.FindSet() then begin
            ReservationEntry."Source Type" := DATABASE::"Sales Line";
            ReservationEntry."Source Subtype" := SalesHeader."Document Type".AsInteger();
            SignFactor := CreateReservEntry.SignFactor(ReservationEntry);
            repeat
                // Only Item where no SerialNo or LotNo is required
                TempItemSalesLine.GetItem(Item);
                if Item."Item Tracking Code" <> '' then begin
                    Inbound := (TempItemSalesLine.Quantity * SignFactor) > 0;
                    ItemTrackingCode.Code := Item."Item Tracking Code";
                    IsHandled := false;
                    OnCheckTrackingSpecificationOnBeforeGetItemTrackingSettings(TempItemSalesLine, ItemTrackingSetup, IsHandled);
                    if not IsHandled then
                        ItemTrackingManagement.GetItemTrackingSetup(
                            ItemTrackingCode, ItemJnlLine."Entry Type"::Sale, Inbound, ItemTrackingSetup);
                    CheckSalesLine := not ItemTrackingSetup.TrackingRequired();
                    if CheckSalesLine then
                        CheckSalesLine := CheckTrackingExists(TempItemSalesLine);
                end else
                    CheckSalesLine := false;

                TrackingQtyToHandle := 0;

                if CheckSalesLine then begin
                    TrackingQtyToHandle := GetTrackingQuantities(TempItemSalesLine) * SignFactor;
                    if SalesHeader.Ship then
                        SalesLineQtyToHandle := TempItemSalesLine."Qty. to Ship (Base)"
                    else
                        SalesLineQtyToHandle := TempItemSalesLine."Return Qty. to Receive (Base)";
                    if TrackingQtyToHandle <> SalesLineQtyToHandle then
                        Error(ItemTrackQuantityMismatchErr, ErrorFieldCaption, TempItemSalesLine."No.");
                end;

                OnCheckTrackingSpecificationOnAfterTempItemSalesLineLoop(TempItemSalesLine);
            until TempItemSalesLine.Next() = 0;
        end;
        if SalesHeader.Ship then
            TempItemSalesLine.SetRange("Quantity Shipped")
        else
            TempItemSalesLine.SetRange("Return Qty. Received");
    end;

    local procedure CheckTrackingExists(SalesLine: Record "Sales Line"): Boolean
    begin
        exit(
          ItemTrackingMgt.ItemTrackingExistsOnDocumentLine(
            DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No."));
    end;

    local procedure GetTrackingQuantities(SalesLine: Record "Sales Line"): Decimal
    begin
        exit(
          ItemTrackingMgt.CalcQtyToHandleForTrackedQtyOnDocumentLine(
            DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No."));
    end;

    local procedure SaveInvoiceSpecification(var TempInvoicingSpecification: Record "Tracking Specification" temporary)
    begin
        TempInvoicingSpecification.Reset();
        if TempInvoicingSpecification.FindSet() then begin
            repeat
                TempInvoicingSpecification."Quantity Invoiced (Base)" += TempInvoicingSpecification."Quantity actual Handled (Base)";
                TempInvoicingSpecification."Quantity actual Handled (Base)" := 0;
                OnSaveInvoiceSpecificationOnBeforeAssignTempInvoicingSpecification(TempInvoicingSpecification);
                TempTrackingSpecification := TempInvoicingSpecification;
                TempTrackingSpecification."Buffer Status" := TempTrackingSpecification."Buffer Status"::MODIFY;
                if not TempTrackingSpecification.Insert() then begin
                    TempTrackingSpecification.Get(TempInvoicingSpecification."Entry No.");
                    TempTrackingSpecification."Qty. to Invoice (Base)" += TempInvoicingSpecification."Qty. to Invoice (Base)";
                    TempTrackingSpecification."Quantity Invoiced (Base)" += TempInvoicingSpecification."Qty. to Invoice (Base)";
                    TempTrackingSpecification."Qty. to Invoice" += TempInvoicingSpecification."Qty. to Invoice";
                    TempTrackingSpecification.Modify();
                end;
                OnSaveInvoiceSpecificationOnAfterUpdateTempTrackingSpecification(TempTrackingSpecification, TempInvoicingSpecification);
            until TempInvoicingSpecification.Next() = 0;
            TempInvoicingSpecification.DeleteAll();
        end;
    end;

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

        TempTrackingSpecification.Reset();
        if not TempTrackingSpecification.IsEmpty() then begin
            TempTrackingSpecification.InsertSpecification();
            SalesLineReserve.UpdateItemTrackingAfterPosting(SalesHeader);
        end;
    end;

    /// <summary>
    /// Stores Value Entry Relations from a global temp table TempValueEntryRelation to the Value Entry Relation table.
    /// The global temp table is then cleared.
    /// </summary>
    procedure InsertValueEntryRelation()
    var
        ValueEntryRelation: Record "Value Entry Relation";
    begin
        TempValueEntryRelation.Reset();
        if TempValueEntryRelation.FindSet() then begin
            repeat
                ValueEntryRelation := TempValueEntryRelation;
                ValueEntryRelation.Insert();
            until TempValueEntryRelation.Next() = 0;
            TempValueEntryRelation.DeleteAll();
        end;
    end;

    /// <summary>
    /// Posts an item charge to the specified item ledger entry.
    /// </summary>
    /// <param name="SalesHeader">The sales header record.</param>
    /// <param name="SalesLine">The sales line with the item charge.</param>
    /// <param name="ItemLedgEntryNo">The item ledger entry number to apply the charge to.</param>
    /// <param name="QuantityBase">The quantity in base unit of measure.</param>
    /// <param name="AmountToAssign">The amount to assign.</param>
    /// <param name="QtyToAssign">The quantity to assign.</param>
    procedure PostItemCharge(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; ItemLedgEntryNo: Integer; QuantityBase: Decimal; AmountToAssign: Decimal; QtyToAssign: Decimal)
    var
        DummyTrackingSpecification: Record "Tracking Specification";
        SalesLineToPost: Record "Sales Line";
    begin
        OnBeforePostItemCharge(SalesHeader, SalesLine, TempItemChargeAssgntSales, ItemLedgEntryNo);

        SalesLineToPost := SalesLine;
        SalesLineToPost."No." := TempItemChargeAssgntSales."Item No.";
        SalesLineToPost."Appl.-to Item Entry" := ItemLedgEntryNo;
        if not (TempItemChargeAssgntSales."Document Type" in [TempItemChargeAssgntSales."Document Type"::"Return Order", TempItemChargeAssgntSales."Document Type"::"Credit Memo"]) then
            SalesLineToPost.Amount := -AmountToAssign
        else
            SalesLineToPost.Amount := AmountToAssign;

        if SalesLineToPost."Currency Code" <> '' then
            SalesLineToPost."Unit Cost" := Round(
                SalesLineToPost.Amount / QuantityBase, Currency."Unit-Amount Rounding Precision")
        else
            SalesLineToPost."Unit Cost" := Round(
                SalesLineToPost.Amount / QuantityBase, GLSetup."Unit-Amount Rounding Precision");

        TotalChargeAmt := TotalChargeAmt + SalesLineToPost.Amount;
        OnPostItemChargeOnAfterCalcTotalChargeAmt(SalesLineToPost, QtyToAssign, SalesLine, xSalesLine);

        if SalesHeader."Currency Code" <> '' then
            SalesLineToPost.Amount :=
              CurrExchRate.ExchangeAmtFCYToLCY(
                SalesHeader.GetUseDate(), SalesHeader."Currency Code", TotalChargeAmt, SalesHeader."Currency Factor");
        SalesLineToPost."Inv. Discount Amount" := Round(
            SalesLine."Inv. Discount Amount" / SalesLine.Quantity * QtyToAssign,
            GLSetup."Amount Rounding Precision");
        SalesLineToPost."Line Discount Amount" := Round(
            SalesLine."Line Discount Amount" / SalesLine.Quantity * QtyToAssign,
            GLSetup."Amount Rounding Precision");
        SalesLineToPost."Line Amount" := Round(
            SalesLine."Line Amount" / SalesLine.Quantity * QtyToAssign,
            GLSetup."Amount Rounding Precision");
        SalesLine."Inv. Discount Amount" := SalesLine."Inv. Discount Amount" - SalesLineToPost."Inv. Discount Amount";
        SalesLine."Line Discount Amount" := SalesLine."Line Discount Amount" - SalesLineToPost."Line Discount Amount";
        SalesLine."Line Amount" := SalesLine."Line Amount" - SalesLineToPost."Line Amount";
        SalesLine.Quantity := SalesLine.Quantity - QtyToAssign;
        SalesLineToPost.Amount := Round(SalesLineToPost.Amount, GLSetup."Amount Rounding Precision") - TotalChargeAmtLCY;
        if SalesHeader."Currency Code" <> '' then
            TotalChargeAmtLCY := TotalChargeAmtLCY + SalesLineToPost.Amount;
        SalesLineToPost."Unit Cost (LCY)" := Round(
            SalesLineToPost.Amount / QuantityBase, GLSetup."Unit-Amount Rounding Precision");
        UpdateSalesLineDimSetIDFromAppliedEntry(SalesLineToPost, SalesLine);
        SalesLineToPost."Line No." := TempItemChargeAssgntSales."Document Line No.";

        OnPostItemChargeOnBeforePostItemJnlLine(SalesLineToPost, SalesLine, QtyToAssign, TempItemChargeAssgntSales);

        PostItemJnlLine(
          SalesHeader, SalesLineToPost, 0, 0, -QuantityBase, -QuantityBase,
          SalesLineToPost."Appl.-to Item Entry", TempItemChargeAssgntSales."Item Charge No.", DummyTrackingSpecification, false);

        OnPostItemChargeOnAfterPostItemJnlLine(SalesHeader, SalesLineToPost);

        OnAfterPostItemCharge(SalesHeader, SalesLine, TempItemChargeAssgntSales, ItemLedgEntryNo);
    end;

    local procedure SaveTempWhseSplitSpec(var SalesLine3: Record "Sales Line"; var TempSrcTrackingSpec: Record "Tracking Specification" temporary)
    begin
        TempWhseSplitSpecification.Reset();
        TempWhseSplitSpecification.DeleteAll();
        if TempSrcTrackingSpec.FindSet() then
            repeat
                TempWhseSplitSpecification := TempSrcTrackingSpec;
                TempWhseSplitSpecification.SetSource(
                  DATABASE::"Sales Line", SalesLine3."Document Type".AsInteger(), SalesLine3."Document No.", SalesLine3."Line No.", '', 0);
                TempWhseSplitSpecification.Insert();
            until TempSrcTrackingSpec.Next() = 0;
    end;

    /// <summary>
    /// Transfers reservation entries from a sales line to an item journal line.
    /// </summary>
    /// <param name="SalesOrderLine">The sales order line with reservations.</param>
    /// <param name="ItemJnlLine">The item journal line to transfer reservations to.</param>
    /// <param name="QtyToBeShippedBase">The base quantity to be shipped.</param>
    /// <param name="TempTrackingSpecification2">Temporary tracking specifications.</param>
    /// <param name="CheckApplFromItemEntry">Returns whether to check application from item entry.</param>
    procedure TransferReservToItemJnlLine(var SalesOrderLine: Record "Sales Line"; var ItemJnlLine: Record "Item Journal Line"; QtyToBeShippedBase: Decimal; var TempTrackingSpecification2: Record "Tracking Specification" temporary; var CheckApplFromItemEntry: Boolean)
    var
        RemainingQuantity: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTransferReservToItemJnlLine(SalesOrderLine, QtyToBeShippedBase, IsHandled);
        if IsHandled then
            exit;

        // Handle Item Tracking and reservations, also on drop shipment
        if QtyToBeShippedBase = 0 then
            exit;

        Clear(SalesLineReserve);
        if not SalesOrderLine."Drop Shipment" then
            SalesLineReserve.TransferSalesLineToItemJnlLine(
              SalesOrderLine, ItemJnlLine, QtyToBeShippedBase, CheckApplFromItemEntry, false)
        else begin
            SalesLineReserve.SetApplySpecificItemTracking(true);
            TempTrackingSpecification2.Reset();
            TempTrackingSpecification2.SetSourceFilter(
              DATABASE::"Purchase Line", 1, SalesOrderLine."Purchase Order No.", SalesOrderLine."Purch. Order Line No.", false);
            TempTrackingSpecification2.SetSourceFilter('', 0);
            if TempTrackingSpecification2.IsEmpty() then
                SalesLineReserve.TransferSalesLineToItemJnlLine(
                  SalesOrderLine, ItemJnlLine, QtyToBeShippedBase, CheckApplFromItemEntry, false)
            else begin
                SalesLineReserve.SetOverruleItemTracking(true);
                SalesLineReserve.SetItemTrkgAlreadyOverruled(ItemTrkgAlreadyOverruled);
                TempTrackingSpecification2.FindSet();
                if TempTrackingSpecification2."Quantity (Base)" / QtyToBeShippedBase < 0 then
                    Error(ItemTrackingWrongSignErr);
                repeat
                    ItemJnlLine.CopyTrackingFromSpec(TempTrackingSpecification2);
                    ItemJnlLine."Applies-to Entry" := TempTrackingSpecification2."Item Ledger Entry No.";
                    RemainingQuantity :=
                      SalesLineReserve.TransferSalesLineToItemJnlLine(
                        SalesOrderLine, ItemJnlLine, TempTrackingSpecification2."Quantity (Base)", CheckApplFromItemEntry, false);
                    if RemainingQuantity <> 0 then
                        Error(ItemTrackingMismatchErr);
                until TempTrackingSpecification2.Next() = 0;
                ItemJnlLine.ClearTracking();
                ItemJnlLine."Applies-to Entry" := 0;
            end;
        end;
    end;

    /// <summary>
    /// Transfers reservation entries from a purchase line to an item journal line for drop shipments.
    /// </summary>
    /// <param name="PurchOrderLine">The purchase order line with reservations.</param>
    /// <param name="ItemJnlLine">The item journal line to transfer reservations to.</param>
    /// <param name="SalesLine">The related sales line.</param>
    /// <param name="QtyToBeShippedBase">The base quantity to be shipped.</param>
    procedure TransferReservFromPurchLine(var PurchOrderLine: Record "Purchase Line"; var ItemJnlLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; QtyToBeShippedBase: Decimal)
    var
        ReservEntry: Record "Reservation Entry";
        TempTrackingSpecification2: Record "Tracking Specification" temporary;
        PurchLineReserve: Codeunit "Purch. Line-Reserve";
        RemainingQuantity: Decimal;
        CheckApplToItemEntry: Boolean;
    begin
        // Handle Item Tracking on Drop Shipment
        ItemTrkgAlreadyOverruled := false;
        if QtyToBeShippedBase = 0 then
            exit;

        ReservEntry.SetSourceFilter(
          DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.", true);
        ReservEntry.SetSourceFilter('', 0);
        ReservEntry.SetFilter("Qty. to Handle (Base)", '<>0');
        if not ReservEntry.IsEmpty() then
            ItemTrackingMgt.SumUpItemTracking(ReservEntry, TempTrackingSpecification2, false, true);
        TempTrackingSpecification2.SetFilter("Qty. to Handle (Base)", '<>0');
        if TempTrackingSpecification2.IsEmpty() then begin
            SalesLineReserve.SetApplySpecificItemTracking(true);
            PurchLineReserve.TransferPurchLineToItemJnlLine(
              PurchOrderLine, ItemJnlLine, QtyToBeShippedBase, CheckApplToItemEntry)
        end else begin
            PurchLineReserve.SetOverruleItemTracking(true);
            ItemTrkgAlreadyOverruled := true;
            TempTrackingSpecification2.FindSet();
            if -TempTrackingSpecification2."Quantity (Base)" / QtyToBeShippedBase < 0 then
                Error(ItemTrackingWrongSignErr);
            if PurchOrderLine.ReservEntryExist() then
                repeat
                    ItemJnlLine.CopyTrackingFromSpec(TempTrackingSpecification2);
                    RemainingQuantity :=
                      PurchLineReserve.TransferPurchLineToItemJnlLine(
                        PurchOrderLine, ItemJnlLine,
                        -TempTrackingSpecification2."Qty. to Handle (Base)", CheckApplToItemEntry);
                    if RemainingQuantity <> 0 then
                        Error(ItemTrackingMismatchErr);
                until TempTrackingSpecification2.Next() = 0;
            ItemJnlLine.ClearTracking();
            ItemJnlLine."Applies-to Entry" := 0;
        end;
    end;

    /// <summary>
    /// Sets the incoming Warehouse Receipt Header record to the global variable and inserts it to the global Temp table for Warehouse Receipt Header.
    /// </summary>
    /// <param name="WhseRcptHeader2"></param>
    procedure SetWhseRcptHeader(var WhseRcptHeader2: Record "Warehouse Receipt Header")
    begin
        WhseRcptHeader := WhseRcptHeader2;
        TempWhseRcptHeader := WhseRcptHeader;
        TempWhseRcptHeader.Insert();
    end;

    /// <summary>
    /// Sets the incoming Warehouse Shipment Header record to the global variable and inserts it to the global Temp table for Warehouse Shipment Header.
    /// </summary>
    /// <param name="WhseShptHeader2"></param>
    procedure SetWhseShptHeader(var WhseShptHeader2: Record "Warehouse Shipment Header")
    begin
        WhseShptHeader := WhseShptHeader2;
        TempWhseShptHeader := WhseShptHeader;
        TempWhseShptHeader.Insert();
    end;

    /// <summary>
    /// Creates Prepayment lines for the specified sales header and adds them to the global sales line temp table.
    /// </summary>
    /// <remarks>
    /// If CompleteFunctionality is true, then the following is additionally done:
    ///     - Prepayment Amount to deduct is tested using information from Sales Shipment Lines.
    ///     - Validates Qty. to Invoice with Qty. Shipped Not Invoiced if the Qty. to Invoice is larger than shipped Qty.
    ///     - Checks that Prepayment Amount to deduct is not greater than the remaining amount to invoice for each line
    ///     - Prepayment Line Type is Validated (otherwise it's only assigned).
    /// If "Compress Prepayments" is enabled for the sales header, only one prepayment line is created.
    /// </remarks>
    /// <param name="SalesHeader">The sales header to create the prepayment lines for.</param>
    /// <param name="CompleteFunctionality">Specifies if the complete functionality of the procedure should be used.</param>
    procedure CreatePrepaymentLines(SalesHeader: Record "Sales Header"; CompleteFunctionality: Boolean)
    var
        GLAcc: Record "G/L Account";
        TempSalesLine: Record "Sales Line" temporary;
        TempExtTextLine: Record "Extended Text Line" temporary;
        GenPostingSetup: Record "General Posting Setup";
        TempPrepmtSalesLine: Record "Sales Line" temporary;
        TransferExtText: Codeunit "Transfer Extended Text";
        NextLineNo: Integer;
        Fraction: Decimal;
        VATDifference: Decimal;
        TempLineFound: Boolean;
        PrepmtAmtToDeduct: Decimal;
        IsHandled: Boolean;
        ShouldValidateQtyToInvoice: Boolean;
        ShouldTestGetShipmentPPmtAmtToDeduct: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreatePrepaymentLines(SalesHeader, TempPrepmtSalesLine, CompleteFunctionality, IsHandled, TempSalesLineGlobal);
        if IsHandled then
            exit;

        GetGLSetup();
        FillTempLines(SalesHeader, TempSalesLineGlobal);
        ResetTempLines(TempSalesLine);

        if not TempSalesLine.FindLast() then
            exit;

        NextLineNo := TempSalesLine."Line No." + 10000;
        TempSalesLine.SetFilter(Quantity, '>0');
        TempSalesLine.SetFilter("Qty. to Invoice", '>0');
        OnCreatePrepaymentLinesOnAfterTempSalesLineSetFilters(TempSalesLine, SalesHeader, TempPrepmtSalesLine, NextLineNo);
        TempPrepmtSalesLine.SetHasBeenShown();

        // Get all sales lines
        if TempSalesLine.FindSet() then begin
            ShouldTestGetShipmentPPmtAmtToDeduct := CompleteFunctionality and (TempSalesLine."Document Type" = TempSalesLine."Document Type"::Invoice);
            OnCreatePrepaymentLinesOnBeforeShouldTestGetShipmentPPmtAmtToDeduct(SalesHeader, CompleteFunctionality, ShouldTestGetShipmentPPmtAmtToDeduct);
            if ShouldTestGetShipmentPPmtAmtToDeduct then
                TestGetShipmentPPmtAmtToDeduct();
            repeat
                if CompleteFunctionality then begin
                    ShouldValidateQtyToInvoice := SalesHeader."Document Type" <> SalesHeader."Document Type"::Invoice;
                    OnCreatePrepaymentLinesOnBeforeValidateQtyToInvoice(SalesHeader, ShouldValidateQtyToInvoice, TempSalesLine);
                    if ShouldValidateQtyToInvoice then begin
                        if not SalesHeader.Ship and (TempSalesLine."Qty. to Invoice" = TempSalesLine.Quantity - TempSalesLine."Quantity Invoiced") then
                            if TempSalesLine."Qty. Shipped Not Invoiced" < TempSalesLine."Qty. to Invoice" then
                                TempSalesLine.Validate("Qty. to Invoice", TempSalesLine."Qty. Shipped Not Invoiced");
                        Fraction := (TempSalesLine."Qty. to Invoice" + TempSalesLine."Quantity Invoiced") / TempSalesLine.Quantity;
                        CheckPrepmtAmtToDeduct(SalesHeader, TempSalesLine, Fraction);
                    end;
                end;
                if TempSalesLine."Prepmt Amt to Deduct" <> 0 then begin
                    if (TempSalesLine."Gen. Bus. Posting Group" <> GenPostingSetup."Gen. Bus. Posting Group") or
                       (TempSalesLine."Gen. Prod. Posting Group" <> GenPostingSetup."Gen. Prod. Posting Group")
                    then
                        GetGeneralPostingSetup(GenPostingSetup, TempSalesLine);

                    IsHandled := false;
                    OnCreatePrepaymentLinesOnBeforeGetSalesPrepmtAccount(GLAcc, TempSalesLine, SalesHeader, GenPostingSetup, CompleteFunctionality, IsHandled);
                    if not IsHandled then
                        GLAcc.Get(GenPostingSetup.GetSalesPrepmtAccount());
                    OnCreatePrepaymentLinesOnAfterGetSalesPrepmtAccount(GLAcc, TempSalesLine, SalesHeader, CompleteFunctionality);
                    TempLineFound := false;
                    if SalesHeader."Compress Prepayment" then begin
                        TempPrepmtSalesLine.SetRange("No.", GLAcc."No.");
                        TempPrepmtSalesLine.SetRange("Dimension Set ID", TempSalesLine."Dimension Set ID");
                        OnCreatePrepaymentLinesOnAfterTempPrepmtSalesLineSetFilters(TempPrepmtSalesLine, TempSalesLine);
                        TempLineFound := TempPrepmtSalesLine.FindFirst();
                    end;
                    if TempLineFound then begin
                        PrepmtAmtToDeduct :=
                          TempPrepmtSalesLine."Prepmt Amt to Deduct" +
                          InsertedPrepmtVATBaseToDeduct(
                            SalesHeader, TempSalesLine, TempPrepmtSalesLine."Line No.", TempPrepmtSalesLine."Unit Price");
                        VATDifference := TempPrepmtSalesLine."VAT Difference";
                        TempPrepmtSalesLine.Validate(
                          "Unit Price", TempPrepmtSalesLine."Unit Price" + TempSalesLine."Prepmt Amt to Deduct");
                        TempPrepmtSalesLine.Validate("VAT Difference", VATDifference - TempSalesLine."Prepmt VAT Diff. to Deduct");
                        TempPrepmtSalesLine."Prepmt Amt to Deduct" := PrepmtAmtToDeduct;
                        if TempSalesLine."Prepayment %" < TempPrepmtSalesLine."Prepayment %" then
                            TempPrepmtSalesLine."Prepayment %" := TempSalesLine."Prepayment %";
                        OnBeforeTempPrepmtSalesLineModify(TempPrepmtSalesLine, TempSalesLine, SalesHeader, CompleteFunctionality);
                        TempPrepmtSalesLine.Modify();
                        OnCreatePrepaymentLinesOnAfterTempPrepmtSalesLineModify(TempPrepmtSalesLine, TempSalesLine, SalesHeader);
                    end else begin
                        TempPrepmtSalesLine.Init();
                        TempPrepmtSalesLine."Document Type" := SalesHeader."Document Type";
                        TempPrepmtSalesLine."Document No." := SalesHeader."No.";
                        TempPrepmtSalesLine."Line No." := 0;
                        TempPrepmtSalesLine."System-Created Entry" := true;
                        OnCreatePrepaymentLinesOnBeforeValidateType(TempPrepmtSalesLine, SalesHeader, TempSalesLine);
                        if CompleteFunctionality then
                            TempPrepmtSalesLine.Validate(Type, TempPrepmtSalesLine.Type::"G/L Account")
                        else
                            TempPrepmtSalesLine.Type := TempPrepmtSalesLine.Type::"G/L Account";
                        // deduct from prepayment
                        TempPrepmtSalesLine.Validate("No.", GLAcc."No.");
                        TempPrepmtSalesLine.Validate(Quantity, -1);
                        TempPrepmtSalesLine."Qty. to Ship" := TempPrepmtSalesLine.Quantity;
                        TempPrepmtSalesLine."Qty. to Invoice" := TempPrepmtSalesLine.Quantity;
                        OnCreatePrepaymentLinesOnBeforeInsertedPrepmtVATBaseToDeduct(TempPrepmtSalesLine, SalesHeader, TempSalesLine);
                        PrepmtAmtToDeduct := InsertedPrepmtVATBaseToDeduct(SalesHeader, TempSalesLine, NextLineNo, 0);
                        TempPrepmtSalesLine.Validate("Unit Price", TempSalesLine."Prepmt Amt to Deduct");
                        TempPrepmtSalesLine.Validate("VAT Difference", -TempSalesLine."Prepmt VAT Diff. to Deduct");
                        TempPrepmtSalesLine."Prepmt Amt to Deduct" := PrepmtAmtToDeduct;
                        TempPrepmtSalesLine."Prepayment %" := TempSalesLine."Prepayment %";
                        TempPrepmtSalesLine."Prepayment Line" := true;
                        TempPrepmtSalesLine."Shortcut Dimension 1 Code" := TempSalesLine."Shortcut Dimension 1 Code";
                        TempPrepmtSalesLine."Shortcut Dimension 2 Code" := TempSalesLine."Shortcut Dimension 2 Code";
                        TempPrepmtSalesLine."Gen. Bus. Posting Group" := TempSalesLine."Gen. Bus. Posting Group";
                        TempPrepmtSalesLine."Gen. Prod. Posting Group" := TempSalesLine."Gen. Prod. Posting Group";
                        TempPrepmtSalesLine."Dimension Set ID" := TempSalesLine."Dimension Set ID";
                        TempPrepmtSalesLine."Line No." := NextLineNo;
                        NextLineNo := NextLineNo + 10000;
                        OnBeforeTempPrepmtSalesLineInsert(TempPrepmtSalesLine, TempSalesLine, SalesHeader, CompleteFunctionality);
                        TempPrepmtSalesLine.Insert();
                        OnCreatePrepaymentLinesOnAfterTempPrepmtSalesLineInsert(TempPrepmtSalesLine, TempSalesLine, SalesHeader);

                        IsHandled := false;
                        OnBeforeCreatePrepaymentTextLines(TempPrepmtSalesLine, TempSalesLine, SalesHeader, CompleteFunctionality, IsHandled);
                        if not IsHandled then
                            TransferExtText.PrepmtGetAnyExtText(
                                TempPrepmtSalesLine."No.", DATABASE::"Sales Invoice Line",
                                SalesHeader."Document Date", SalesHeader."Language Code", TempExtTextLine);
                        if TempExtTextLine.Find('-') then
                            repeat
                                TempPrepmtSalesLine.Init();
                                TempPrepmtSalesLine.Description := TempExtTextLine.Text;
                                TempPrepmtSalesLine."System-Created Entry" := true;
                                TempPrepmtSalesLine."Prepayment Line" := true;
                                TempPrepmtSalesLine."Line No." := NextLineNo;
                                NextLineNo := NextLineNo + 10000;
                                OnCreatePrepaymentLinesOnBeforeInsertTempLineForExtText(TempPrepmtSalesLine, TempSalesLine, TempExtTextLine, SalesHeader);
                                TempPrepmtSalesLine.Insert();
                            until TempExtTextLine.Next() = 0;
                    end;
                end;
            until TempSalesLine.Next() = 0;
            OnCreatePrepaymentLinesOnAfterProcessSalesLines(SalesHeader, TempPrepmtSalesLine, NextLineNo);
        end;
        DividePrepmtAmountLCY(TempPrepmtSalesLine, SalesHeader);
        if TempPrepmtSalesLine.FindSet() then
            repeat
                TempSalesLineGlobal := TempPrepmtSalesLine;
                TempSalesLineGlobal.Insert();
            until TempPrepmtSalesLine.Next() = 0;
    end;

    /// <summary>
    /// Checks that the Prepayment amount to deduct of the sales line is within limits
    /// </summary>
    /// <remarks>
    /// First condition checks that the Prepayment amount to deduct is not greater than the amount being posted.
    /// Second condition checks that the remaining Prepayment amount to deduct is not greater than the remaining amount to invoice.
    /// </remarks>
    /// <param name="SalesHeader">The sales header of the document being posted.</param>
    /// <param name="TempSalesLine">The sales line to check.</param>
    /// <param name="Fraction">The fraction of the sales line to be invoiced.</param>
    procedure CheckPrepmtAmtToDeduct(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary; Fraction: Decimal)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckPrepmtAmtToDeduct(TempSalesLine, SalesHeader, IsHandled, Fraction);
        if IsHandled then
            exit;

        if TempSalesLine."Prepayment %" <> 100 then
            case true of
                (TempSalesLine."Prepmt Amt to Deduct" <> 0) and
              (TempSalesLine."Prepmt Amt to Deduct" > Round(Fraction * TempSalesLine."Line Amount", Currency."Amount Rounding Precision")):
                    TempSalesLine.FieldError(
                      TempSalesLine."Prepmt Amt to Deduct",
                      StrSubstNo(CannotBeGreaterThanErr,
                        Round(Fraction * TempSalesLine."Line Amount", Currency."Amount Rounding Precision")));
                (TempSalesLine."Prepmt. Amt. Inv." <> 0) and
              (Round((1 - Fraction) * TempSalesLine."Line Amount", Currency."Amount Rounding Precision") <
               Round(
                 Round(
                   Round(TempSalesLine."Unit Price" * (TempSalesLine.Quantity - TempSalesLine."Quantity Invoiced" - TempSalesLine."Qty. to Invoice"),
                     Currency."Amount Rounding Precision") *
                   (1 - (TempSalesLine."Line Discount %" / 100)), Currency."Amount Rounding Precision") *
                 TempSalesLine."Prepayment %" / 100, Currency."Amount Rounding Precision")):
                    TempSalesLine.FieldError(
                      TempSalesLine."Prepmt Amt to Deduct",
                      StrSubstNo(CannotBeSmallerThanErr,
                        Round(
                          TempSalesLine."Prepmt. Amt. Inv." - TempSalesLine."Prepmt Amt Deducted" - (1 - Fraction) * TempSalesLine."Line Amount",
                          Currency."Amount Rounding Precision")));
            end;

    end;

    /// <summary>
    /// Calculates the prepayment VAT Base amount to deduct and inserts a prepayment line for it in a global temp table TempPrepmtDeductLCYSalesLine.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document being posted.</param>
    /// <param name="SalesLine">The sales line of the document for which the prepayment VAT Base amount is being calculated.</param>
    /// <param name="PrepmtLineNo">The Line No. of the prepayment line to which this VAT Base Prepayment line is attached to.</param>
    /// <param name="TotalPrepmtAmtToDeduct">The running total of the prepayment amount to deduct. Used when compressing prepayments to a single line.</param>
    /// <returns>Prepayment VAT Base amount to deduct</returns>
    procedure InsertedPrepmtVATBaseToDeduct(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; PrepmtLineNo: Integer; TotalPrepmtAmtToDeduct: Decimal): Decimal
    var
        PrepmtVATBaseToDeduct: Decimal;
    begin
        if SalesHeader."Prices Including VAT" then
            PrepmtVATBaseToDeduct :=
              Round(
                (TotalPrepmtAmtToDeduct + SalesLine."Prepmt Amt to Deduct") / (1 + SalesLine.GetPrepaymentVATPct() / 100),
                Currency."Amount Rounding Precision") -
              Round(
                TotalPrepmtAmtToDeduct / (1 + SalesLine.GetPrepaymentVATPct() / 100),
                Currency."Amount Rounding Precision")
        else
            PrepmtVATBaseToDeduct := SalesLine."Prepmt Amt to Deduct";
        TempPrepmtDeductLCYSalesLine := SalesLine;
        if TempPrepmtDeductLCYSalesLine."Document Type" = TempPrepmtDeductLCYSalesLine."Document Type"::Order then
            TempPrepmtDeductLCYSalesLine."Qty. to Invoice" := GetQtyToInvoice(SalesLine, SalesHeader.Ship)
        else
            GetLineDataFromOrder(TempPrepmtDeductLCYSalesLine);
        if (TempPrepmtDeductLCYSalesLine."Prepmt Amt to Deduct" = 0) or (TempPrepmtDeductLCYSalesLine."Document Type" = TempPrepmtDeductLCYSalesLine."Document Type"::Invoice) then
            TempPrepmtDeductLCYSalesLine.CalcPrepaymentToDeduct();
        TempPrepmtDeductLCYSalesLine."Line Amount" := TempPrepmtDeductLCYSalesLine.GetLineAmountToHandleInclPrepmt(TempPrepmtDeductLCYSalesLine."Qty. to Invoice");
        TempPrepmtDeductLCYSalesLine."Attached to Line No." := PrepmtLineNo;
        TempPrepmtDeductLCYSalesLine."VAT Base Amount" := PrepmtVATBaseToDeduct;
        TempPrepmtDeductLCYSalesLine.Insert();

        OnAfterInsertedPrepmtVATBaseToDeduct(
          SalesHeader, SalesLine, PrepmtLineNo, TotalPrepmtAmtToDeduct, TempPrepmtDeductLCYSalesLine, PrepmtVATBaseToDeduct);

        exit(PrepmtVATBaseToDeduct);
    end;

    /// <summary>
    /// Calculates the LCY Amount of Prepayment VAT Base Amount for each prepayment line and updates the global temp table TempPrepmtDeductLCYSalesLine with it.
    /// </summary>
    /// <param name="PrepmtSalesLine">Temp tables with prepayment sales lines.</param>
    /// <param name="SalesHeader">The sales header of the document being posted.</param>
    procedure DividePrepmtAmountLCY(var PrepmtSalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
    var
        ActualCurrencyFactor: Decimal;
    begin
        PrepmtSalesLine.Reset();
        PrepmtSalesLine.SetFilter(Type, '<>%1', PrepmtSalesLine.Type::" ");
        if PrepmtSalesLine.FindSet() then
            repeat
                if SalesHeader."Currency Code" <> '' then
                    ActualCurrencyFactor :=
                      Round(
                        CurrExchRate.ExchangeAmtFCYToLCY(
                          SalesHeader."Posting Date",
                          SalesHeader."Currency Code",
                          PrepmtSalesLine."Prepmt Amt to Deduct",
                          SalesHeader."Currency Factor")) /
                      PrepmtSalesLine."Prepmt Amt to Deduct"
                else
                    ActualCurrencyFactor := 1;

                UpdatePrepmtAmountInvBuf(PrepmtSalesLine."Line No.", ActualCurrencyFactor);
            until PrepmtSalesLine.Next() = 0;
        PrepmtSalesLine.Reset();
    end;

    local procedure UpdatePrepmtAmountInvBuf(PrepmtSalesLineNo: Integer; CurrencyFactor: Decimal)
    var
        PrepmtAmtRemainder: Decimal;
    begin
        TempPrepmtDeductLCYSalesLine.Reset();
        TempPrepmtDeductLCYSalesLine.SetRange("Attached to Line No.", PrepmtSalesLineNo);
        if TempPrepmtDeductLCYSalesLine.FindSet(true) then
            repeat
                TempPrepmtDeductLCYSalesLine."Prepmt. Amount Inv. (LCY)" :=
                  CalcRoundedAmount(CurrencyFactor * TempPrepmtDeductLCYSalesLine."VAT Base Amount", PrepmtAmtRemainder);
                TempPrepmtDeductLCYSalesLine.Modify();
            until TempPrepmtDeductLCYSalesLine.Next() = 0;
    end;

    local procedure AdjustPrepmtAmountLCY(SalesHeader: Record "Sales Header"; var PrepmtSalesLine: Record "Sales Line")
    var
        SalesLine: Record "Sales Line";
        SalesInvoiceLine: Record "Sales Line";
        TempSalesLineShipmentBuffer: Record "Sales Line" temporary;
        DeductionFactor: Decimal;
        PrepmtVATPart: Decimal;
        PrepmtVATAmtRemainder: Decimal;
        TotalRoundingAmount: array[2] of Decimal;
        TotalPrepmtAmount: array[2] of Decimal;
        FinalInvoice: Boolean;
        PricesInclVATRoundingAmount: array[2] of Decimal;
        CurrentLineFinalInvoice: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeAdjustPrepmtAmountLCY(SalesHeader, PrepmtSalesLine, IsHandled);
        if IsHandled then
            exit;

        if PrepmtSalesLine."Prepayment Line" then begin
            PrepmtVATPart :=
              (PrepmtSalesLine."Amount Including VAT" - PrepmtSalesLine.Amount) / PrepmtSalesLine."Unit Price";
            OnAdjustPrepmtAmountLCYOnAfterCalcPrepmtVATPart(PrepmtVATPart, SalesHeader, PrepmtSalesLine);

            TempPrepmtDeductLCYSalesLine.Reset();
            TempPrepmtDeductLCYSalesLine.SetRange("Attached to Line No.", PrepmtSalesLine."Line No.");
            if TempPrepmtDeductLCYSalesLine.FindSet(true) then begin
                FinalInvoice := true;
                repeat
                    SalesLine := TempPrepmtDeductLCYSalesLine;
                    SalesLine.Find();

                    if TempPrepmtDeductLCYSalesLine."Document Type" = TempPrepmtDeductLCYSalesLine."Document Type"::Invoice then begin
                        SalesInvoiceLine := SalesLine;
                        GetSalesOrderLine(SalesLine, SalesInvoiceLine);
                        SalesLine."Qty. to Invoice" := SalesInvoiceLine."Qty. to Invoice";
                        OnAdjustPrepmtAmountLCYOnAfterGetOrderLine(SalesLine, SalesInvoiceLine);

                        TempSalesLineShipmentBuffer := SalesLine;
                        if TempSalesLineShipmentBuffer.Find() then begin
                            TempSalesLineShipmentBuffer."Qty. to Invoice" += TempPrepmtDeductLCYSalesLine."Qty. to Invoice";
                            TempSalesLineShipmentBuffer.Modify();
                        end else begin
                            TempSalesLineShipmentBuffer.Quantity := TempPrepmtDeductLCYSalesLine.Quantity;
                            TempSalesLineShipmentBuffer."Qty. to Invoice" := TempPrepmtDeductLCYSalesLine."Qty. to Invoice";
                            TempSalesLineShipmentBuffer.Insert();
                        end;
                        CurrentLineFinalInvoice := TempSalesLineShipmentBuffer.IsFinalInvoice();
                    end else begin
                        CurrentLineFinalInvoice := TempPrepmtDeductLCYSalesLine.IsFinalInvoice();
                        FinalInvoice := FinalInvoice and CurrentLineFinalInvoice;
                    end;

                    if SalesLine."Qty. to Invoice" <> TempPrepmtDeductLCYSalesLine."Qty. to Invoice" then
                        SalesLine."Prepmt Amt to Deduct" := CalcPrepmtAmtToDeduct(SalesLine, SalesHeader.Ship);
                    DeductionFactor :=
                      SalesLine."Prepmt Amt to Deduct" /
                      (SalesLine."Prepmt. Amt. Inv." - SalesLine."Prepmt Amt Deducted");

                    TempPrepmtDeductLCYSalesLine."Prepmt. VAT Amount Inv. (LCY)" :=
                      CalcRoundedAmount(SalesLine."Prepmt Amt to Deduct" * PrepmtVATPart, PrepmtVATAmtRemainder);
                    if (TempPrepmtDeductLCYSalesLine."Prepayment %" <> 100) or CurrentLineFinalInvoice or (TempPrepmtDeductLCYSalesLine."Currency Code" <> '') then
                        CalcPrepmtRoundingAmounts(TempPrepmtDeductLCYSalesLine, SalesLine, DeductionFactor, TotalRoundingAmount);
                    TempPrepmtDeductLCYSalesLine.Modify();

                    if SalesHeader."Prices Including VAT" then
                        if ((TempPrepmtDeductLCYSalesLine."Prepayment %" <> 100) or CurrentLineFinalInvoice) and (DeductionFactor = 1) then begin
                            PricesInclVATRoundingAmount[1] := TotalRoundingAmount[1];
                            PricesInclVATRoundingAmount[2] := TotalRoundingAmount[2];
                        end;

                    if TempPrepmtDeductLCYSalesLine."VAT Calculation Type" <> TempPrepmtDeductLCYSalesLine."VAT Calculation Type"::"Full VAT" then
                        TotalPrepmtAmount[1] += TempPrepmtDeductLCYSalesLine."Prepmt. Amount Inv. (LCY)";
                    TotalPrepmtAmount[2] += TempPrepmtDeductLCYSalesLine."Prepmt. VAT Amount Inv. (LCY)";
                until TempPrepmtDeductLCYSalesLine.Next() = 0;
            end;

            if FinalInvoice then
                if TempSalesLineShipmentBuffer.FindSet() then
                    repeat
                        if not TempSalesLineShipmentBuffer.IsFinalInvoice() then
                            FinalInvoice := false;
                    until not FinalInvoice or (TempSalesLineShipmentBuffer.Next() = 0);

            if SalesHeader."Document Type" <> SalesHeader."Document Type"::"Credit Memo" then
                UpdatePrepmtSalesLineWithRounding(
                  PrepmtSalesLine, TotalRoundingAmount, TotalPrepmtAmount,
                  FinalInvoice, PricesInclVATRoundingAmount);
        end;
    end;

    local procedure CalcPrepmtAmtToDeduct(SalesLine: Record "Sales Line"; Ship: Boolean): Decimal
    var
        IsHandled: Boolean;
        PrepmtAmtToDeduct: Decimal;
    begin
        OnBeforeCalcPrepmtAmtToDeduct(SalesLine, Ship, IsHandled, PrepmtAmtToDeduct);
        if IsHandled then
            exit(PrepmtAmtToDeduct);
        SalesLine."Qty. to Invoice" := GetQtyToInvoice(SalesLine, Ship);
        SalesLine.CalcPrepaymentToDeduct();
        exit(SalesLine."Prepmt Amt to Deduct");
    end;

    local procedure GetQtyToInvoice(SalesLine: Record "Sales Line"; Ship: Boolean): Decimal
    var
        AllowedQtyToInvoice: Decimal;
        QtyToInvoice: Decimal;
        IsHandled: Boolean;
    begin
        OnBeforeGetQtyToInvoice(SalesLine, Ship, IsHandled, QtyToInvoice);
        if IsHandled then
            exit(QtyToInvoice);
        AllowedQtyToInvoice := SalesLine."Qty. Shipped Not Invoiced";
        if Ship then
            AllowedQtyToInvoice := AllowedQtyToInvoice + SalesLine."Qty. to Ship";
        if SalesLine."Qty. to Invoice" > AllowedQtyToInvoice then
            exit(AllowedQtyToInvoice);
        exit(SalesLine."Qty. to Invoice");
    end;

    local procedure GetLineDataFromOrder(var SalesLine: Record "Sales Line")
    var
        SalesShptLine: Record "Sales Shipment Line";
        SalesOrderLine: Record "Sales Line";
    begin
        SalesShptLine.Get(SalesLine."Shipment No.", SalesLine."Shipment Line No.");
        SalesOrderLine.Get(SalesLine."Document Type"::Order, SalesShptLine."Order No.", SalesShptLine."Order Line No.");

        SalesLine.Quantity := SalesOrderLine.Quantity;
        SalesLine."Qty. Shipped Not Invoiced" := SalesOrderLine."Qty. Shipped Not Invoiced";
        SalesLine."Quantity Invoiced" := SalesOrderLine."Quantity Invoiced";
        SalesLine."Prepmt Amt Deducted" := SalesOrderLine."Prepmt Amt Deducted";
        SalesLine."Prepmt. Amt. Inv." := SalesOrderLine."Prepmt. Amt. Inv.";
        SalesLine."Line Discount Amount" := SalesOrderLine."Line Discount Amount";
        OnAfterGetLineDataFromOrder(SalesLine, SalesOrderLine);
    end;

    local procedure CalcPrepmtRoundingAmounts(var PrepmtSalesLineBuf: Record "Sales Line"; SalesLine: Record "Sales Line"; DeductionFactor: Decimal; var TotalRoundingAmount: array[2] of Decimal)
    var
        RoundingAmount: array[2] of Decimal;
    begin
        if PrepmtSalesLineBuf."VAT Calculation Type" <> PrepmtSalesLineBuf."VAT Calculation Type"::"Full VAT" then begin
            RoundingAmount[1] :=
              PrepmtSalesLineBuf."Prepmt. Amount Inv. (LCY)" - Round(DeductionFactor * SalesLine."Prepmt. Amount Inv. (LCY)");
            PrepmtSalesLineBuf."Prepmt. Amount Inv. (LCY)" := PrepmtSalesLineBuf."Prepmt. Amount Inv. (LCY)" - RoundingAmount[1];
            TotalRoundingAmount[1] += RoundingAmount[1];
        end;
        RoundingAmount[2] :=
          PrepmtSalesLineBuf."Prepmt. VAT Amount Inv. (LCY)" - Round(DeductionFactor * SalesLine."Prepmt. VAT Amount Inv. (LCY)");
        PrepmtSalesLineBuf."Prepmt. VAT Amount Inv. (LCY)" := PrepmtSalesLineBuf."Prepmt. VAT Amount Inv. (LCY)" - RoundingAmount[2];
        TotalRoundingAmount[2] += RoundingAmount[2];
    end;

    /// <summary>
    /// Updates the prepayment sales line with rounding adjustments.
    /// </summary>
    /// <param name="PrepmtSalesLine">The prepayment sales line to update.</param>
    /// <param name="TotalRoundingAmount">Array with the total rounding amount to add. First value is the amount excluding VAT, second value is the VAT amount.</param>
    /// <param name="TotalPrepmtAmount">Array with the total prepayment amount to deduct. First value is the amount excluding VAT, second value is the VAT amount.</param>
    /// <param name="FinalInvoice">Indicates if the current invoice is the final invoice.</param>
    /// <param name="PricesInclVATRoundingAmount">Array with the rounding amount to add to the prices including VAT. First value is the amount excluding VAT, second value is the VAT amount.</param>
    procedure UpdatePrepmtSalesLineWithRounding(var PrepmtSalesLine: Record "Sales Line"; TotalRoundingAmount: array[2] of Decimal; TotalPrepmtAmount: array[2] of Decimal; FinalInvoice: Boolean; PricesInclVATRoundingAmount: array[2] of Decimal)
    var
        NewAmountIncludingVAT: Decimal;
        Prepmt100PctVATRoundingAmt: Decimal;
        AmountRoundingPrecision: Decimal;
    begin
        OnBeforeUpdatePrepmtSalesLineWithRounding(
          PrepmtSalesLine, TotalRoundingAmount, TotalPrepmtAmount, FinalInvoice, PricesInclVATRoundingAmount,
          TotalSalesLine, TotalSalesLineLCY);

        NewAmountIncludingVAT := TotalPrepmtAmount[1] + TotalPrepmtAmount[2] + TotalRoundingAmount[1] + TotalRoundingAmount[2];
        if PrepmtSalesLine."Prepayment %" = 100 then
            TotalRoundingAmount[1] += PrepmtSalesLine."Amount Including VAT" - NewAmountIncludingVAT;

        AmountRoundingPrecision :=
          GetAmountRoundingPrecisionInLCY(PrepmtSalesLine."Document Type", PrepmtSalesLine."Document No.", PrepmtSalesLine."Currency Code");

        if (Abs(TotalRoundingAmount[1]) <= AmountRoundingPrecision) and
           (Abs(TotalRoundingAmount[2]) <= AmountRoundingPrecision) and
           (PrepmtSalesLine."Prepayment %" = 100)
        then begin
            Prepmt100PctVATRoundingAmt := TotalRoundingAmount[1];
            TotalRoundingAmount[1] := 0;
        end;

        if (PricesInclVATRoundingAmount[1] <> 0) and (PricesInclVATRoundingAmount[1] = TotalRoundingAmount[1]) and
           (PricesInclVATRoundingAmount[2] = 0) and (PricesInclVATRoundingAmount[2] = TotalRoundingAmount[2])
           and FinalInvoice and (PrepmtSalesLine."Prepayment %" <> 100)
        then begin
            PricesInclVATRoundingAmount[1] := 0;
            TotalRoundingAmount[1] := 0;
        end;

        PrepmtSalesLine."Prepmt. Amount Inv. (LCY)" := TotalRoundingAmount[1];
        PrepmtSalesLine.Amount := TotalPrepmtAmount[1] + TotalRoundingAmount[1];

        if (PricesInclVATRoundingAmount[1] <> 0) and (TotalRoundingAmount[1] = 0) then begin
            if (PrepmtSalesLine."Prepayment %" = 100) and FinalInvoice and
               (PrepmtSalesLine.Amount + TotalPrepmtAmount[2] = PrepmtSalesLine."Amount Including VAT")
            then
                Prepmt100PctVATRoundingAmt := 0;
            PricesInclVATRoundingAmount[1] := 0;
        end;

        if ((TotalRoundingAmount[2] <> 0) or FinalInvoice) and (TotalRoundingAmount[1] = 0) then begin
            if (PrepmtSalesLine."Prepayment %" = 100) and (PrepmtSalesLine."Prepmt. Amount Inv. (LCY)" = 0) then
                Prepmt100PctVATRoundingAmt += TotalRoundingAmount[2];
            if (PrepmtSalesLine."Prepayment %" = 100) or FinalInvoice then
                TotalRoundingAmount[2] := 0;
        end;

        if (PricesInclVATRoundingAmount[2] <> 0) and (TotalRoundingAmount[2] = 0) then begin
            if Abs(Prepmt100PctVATRoundingAmt) <= AmountRoundingPrecision then
                Prepmt100PctVATRoundingAmt := 0;
            PricesInclVATRoundingAmount[2] := 0;
        end;

        PrepmtSalesLine."Prepmt. VAT Amount Inv. (LCY)" := TotalRoundingAmount[2] + Prepmt100PctVATRoundingAmt;
        NewAmountIncludingVAT := PrepmtSalesLine.Amount + TotalPrepmtAmount[2] + TotalRoundingAmount[2];
        if (PricesInclVATRoundingAmount[1] = 0) and (PricesInclVATRoundingAmount[2] = 0) or
           (PrepmtSalesLine."Currency Code" <> '') and FinalInvoice
        then
            TotalSalesLineLCY."Amount Including VAT" += PrepmtSalesLine."Amount Including VAT" - NewAmountIncludingVAT - Prepmt100PctVATRoundingAmt;
        if PrepmtSalesLine."Currency Code" = '' then
            TotalSalesLine."Amount Including VAT" := TotalSalesLineLCY."Amount Including VAT";
        PrepmtSalesLine."Amount Including VAT" := NewAmountIncludingVAT;

        if FinalInvoice and (TotalSalesLine.Amount = 0) and (TotalSalesLine."Amount Including VAT" <> 0) and
           (Abs(TotalSalesLine."Amount Including VAT") <= Currency."Amount Rounding Precision")
        then begin
            PrepmtSalesLine."Amount Including VAT" += TotalSalesLineLCY."Amount Including VAT";
            TotalSalesLine."Amount Including VAT" := 0;
            TotalSalesLineLCY."Amount Including VAT" := 0;
        end;

        OnAfterUpdatePrepmtSalesLineWithRounding(
          PrepmtSalesLine, TotalRoundingAmount, TotalPrepmtAmount, FinalInvoice, PricesInclVATRoundingAmount,
          TotalSalesLine, TotalSalesLineLCY);
    end;

    local procedure CalcRoundedAmount(Amount: Decimal; var Remainder: Decimal): Decimal
    var
        AmountRnded: Decimal;
    begin
        Amount := Amount + Remainder;
        AmountRnded := Round(Amount, GLSetup."Amount Rounding Precision");
        Remainder := Amount - AmountRnded;
        exit(AmountRnded);
    end;

    local procedure GetSalesOrderLine(var SalesOrderLine: Record "Sales Line"; SalesLine: Record "Sales Line")
    var
        SalesShptLine: Record "Sales Shipment Line";
    begin
        SalesShptLine.Get(SalesLine."Shipment No.", SalesLine."Shipment Line No.");
        SalesOrderLine.Get(
          SalesOrderLine."Document Type"::Order,
          SalesShptLine."Order No.", SalesShptLine."Order Line No.");
        SalesOrderLine."Prepmt Amt to Deduct" := SalesLine."Prepmt Amt to Deduct";
    end;

    /// <summary>
    ///  Decrements the prepayment amount invoiced in LCY and the prepayment VAT amount invoiced in LCY for a given sales line.
    /// </summary>
    /// <param name="SalesHeader">The sales header of the document being posted.</param>
    /// <param name="SalesLine">The sales line of the document for which the prepayment amount is being calculated.</param>
    /// <param name="PrepmtAmountInvLCY">The invoiced prepayment amount of a sales line. The amount passed in gets reduced by the amount to be deducted.</param>
    /// <param name="PrepmtVATAmountInvLCY">The invoiced prepayment VAT amount of a sales line. The amount passed in gets reduced by the amount to be deducted.</param>
    procedure DecrementPrepmtAmtInvLCY(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var PrepmtAmountInvLCY: Decimal; var PrepmtVATAmountInvLCY: Decimal)
    begin
        TempPrepmtDeductLCYSalesLine.Reset();
        if TempPrepmtDeductLCYSalesLine.Get(SalesLine."Document Type", SalesLine."Document No.", SalesLine."Line No.") then begin
            PrepmtAmountInvLCY := PrepmtAmountInvLCY - TempPrepmtDeductLCYSalesLine."Prepmt. Amount Inv. (LCY)";
            PrepmtVATAmountInvLCY := PrepmtVATAmountInvLCY - TempPrepmtDeductLCYSalesLine."Prepmt. VAT Amount Inv. (LCY)";
        end;

        OnAfterDecrementPrepmtAmtInvLCY(SalesHeader, SalesLine, PrepmtAmountInvLCY, PrepmtVATAmountInvLCY);
    end;

    local procedure AdjustFinalInvWith100PctPrepmt(var CombinedSalesLine: Record "Sales Line")
    var
        DiffToLineDiscAmt: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeAdjustFinalInvWith100PctPrepmt(TempPrepmtDeductLCYSalesLine, CombinedSalesLine, IsHandled);
        if IsHandled then
            exit;
        TempPrepmtDeductLCYSalesLine.Reset();
        TempPrepmtDeductLCYSalesLine.SetRange(TempPrepmtDeductLCYSalesLine."Prepayment %", 100);
        if TempPrepmtDeductLCYSalesLine.FindSet(true) then
            repeat
                if TempPrepmtDeductLCYSalesLine.IsFinalInvoice() then begin
                    DiffToLineDiscAmt := TempPrepmtDeductLCYSalesLine."Prepmt Amt to Deduct" - TempPrepmtDeductLCYSalesLine."Line Amount";
                    if TempPrepmtDeductLCYSalesLine."Document Type" = TempPrepmtDeductLCYSalesLine."Document Type"::Order then
                        DiffToLineDiscAmt := DiffToLineDiscAmt * TempPrepmtDeductLCYSalesLine.Quantity / TempPrepmtDeductLCYSalesLine."Qty. to Invoice";
                    if DiffToLineDiscAmt <> 0 then begin
                        CombinedSalesLine.Get(TempPrepmtDeductLCYSalesLine."Document Type", TempPrepmtDeductLCYSalesLine."Document No.", TempPrepmtDeductLCYSalesLine."Line No.");
                        TempPrepmtDeductLCYSalesLine."Line Discount Amount" := CombinedSalesLine."Line Discount Amount" - DiffToLineDiscAmt;
                        TempPrepmtDeductLCYSalesLine.Modify();
                    end;
                end;
            until TempPrepmtDeductLCYSalesLine.Next() = 0;
        TempPrepmtDeductLCYSalesLine.Reset();
    end;

    local procedure GetPrepmtDiffToLineAmount(SalesLine: Record "Sales Line"): Decimal
    begin
        if SalesLine."Prepayment %" = 100 then
            if TempPrepmtDeductLCYSalesLine.Get(SalesLine."Document Type", SalesLine."Document No.", SalesLine."Line No.") then
                exit(TempPrepmtDeductLCYSalesLine."Prepmt Amt to Deduct" + TempPrepmtDeductLCYSalesLine."Inv. Disc. Amount to Invoice" - TempPrepmtDeductLCYSalesLine."Line Amount");
        exit(0);
    end;

    local procedure PostJobContractLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostJobContractLine(
            SalesHeader, SalesLine, IsHandled, JobContractLine, InvoicePostingInterface, SalesLineACY, SalesInvHeader, SalesCrMemoHeader);
        if not IsHandled then begin
            if SalesLine."Job Contract Entry No." = 0 then
                exit;

            IsHandled := false;
            OnPostJobContractLineBeforeTestFields(SalesHeader, SalesLine, IsHandled);
            if not IsHandled then begin
                if (SalesHeader."Document Type" <> SalesHeader."Document Type"::Invoice) and
                   (SalesHeader."Document Type" <> SalesHeader."Document Type"::"Credit Memo")
                then
                    SalesLine.TestField("Job Contract Entry No.", 0);

                SalesLine.TestField("Job No.");
                SalesLine.TestField("Job Task No.");
            end;

            if SalesHeader."Document Type" = SalesHeader."Document Type"::Invoice then
                SalesLine."Document No." := SalesInvHeader."No.";
            if SalesHeader."Document Type" = SalesHeader."Document Type"::"Credit Memo" then
                SalesLine."Document No." := SalesCrMemoHeader."No.";
            JobContractLine := true;
            InvoicePostingInterface.PrepareJobLine(SalesHeader, SalesLine, SalesLineACY);
        end;
        OnAfterPostJobContractLine(SalesHeader, SalesLine, GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode);
    end;

    local procedure InsertICGenJnlLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var ICGenJnlLineNo: Integer)
    var
        ICGLAccount: Record "IC G/L Account";
        ICPartner: Record "IC Partner";
        GenJnlLine: Record "Gen. Journal Line";
    begin
        SalesHeader.TestField("Sell-to IC Partner Code", '');
        SalesHeader.TestField("Bill-to IC Partner Code", '');
        SalesLine.TestField("IC Partner Ref. Type", SalesLine."IC Partner Ref. Type"::"G/L Account");
        ICGLAccount.Get(SalesLine."IC Partner Reference");
        ICGenJnlLineNo := ICGenJnlLineNo + 1;

        TempICGenJnlLine.InitNewLine(
            SalesHeader."Posting Date", SalesHeader."Document Date", SalesHeader."VAT Reporting Date", SalesHeader."Posting Description",
            SalesLine."Shortcut Dimension 1 Code", SalesLine."Shortcut Dimension 2 Code", SalesLine."Dimension Set ID",
            SalesHeader."Reason Code");
        TempICGenJnlLine."Line No." := ICGenJnlLineNo;

        TempICGenJnlLine.CopyDocumentFields(GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode, SalesHeader."Posting No. Series");

        TempICGenJnlLine."Account Type" := TempICGenJnlLine."Account Type"::"IC Partner";
        TempICGenJnlLine.Validate(TempICGenJnlLine."Account No.", SalesLine."IC Partner Code");
        TempICGenJnlLine."Source Currency Code" := SalesHeader."Currency Code";
        TempICGenJnlLine."Source Currency Amount" := TempICGenJnlLine.Amount;
        TempICGenJnlLine.Correction := SalesHeader.Correction;
        TempICGenJnlLine."Country/Region Code" := SalesHeader."VAT Country/Region Code";
        TempICGenJnlLine."Source Type" := GenJnlLine."Source Type"::Customer;
        TempICGenJnlLine."Source No." := SalesHeader."Bill-to Customer No.";
        TempICGenJnlLine."Source Line No." := SalesLine."Line No.";
        TempICGenJnlLine.Validate("Bal. Account Type", TempICGenJnlLine."Bal. Account Type"::"G/L Account");
        TempICGenJnlLine.Validate("Bal. Account No.", SalesLine."No.");
        TempICGenJnlLine."Shortcut Dimension 1 Code" := SalesLine."Shortcut Dimension 1 Code";
        TempICGenJnlLine."Shortcut Dimension 2 Code" := SalesLine."Shortcut Dimension 2 Code";
        TempICGenJnlLine."Dimension Set ID" := SalesLine."Dimension Set ID";

        ValidateICPartnerBusPostingGroups(SalesLine);
        TempICGenJnlLine.Validate("Bal. VAT Prod. Posting Group", SalesLine."VAT Prod. Posting Group");
        TempICGenJnlLine."IC Partner Code" := SalesLine."IC Partner Code";
        TempICGenJnlLine."IC Account Type" := TempICGenJnlLine."IC Account Type"::"G/L Account";
        TempICGenJnlLine."IC Account No." := SalesLine."IC Partner Reference";
        TempICGenJnlLine."IC Direction" := TempICGenJnlLine."IC Direction"::Outgoing;
        ICPartner.Get(SalesLine."IC Partner Code");
        if ICPartner."Cost Distribution in LCY" and (SalesLine."Currency Code" <> '') then begin
            TempICGenJnlLine."Currency Code" := '';
            TempICGenJnlLine."Currency Factor" := 0;
            Currency.Get(SalesLine."Currency Code");
            if SalesHeader.IsCreditDocType() then
                TempICGenJnlLine.Amount :=
                  Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader."Posting Date", SalesLine."Currency Code",
                      SalesLine.Amount, SalesHeader."Currency Factor"))
            else
                TempICGenJnlLine.Amount :=
                  -Round(
                    CurrExchRate.ExchangeAmtFCYToLCY(
                      SalesHeader."Posting Date", SalesLine."Currency Code",
                      SalesLine.Amount, SalesHeader."Currency Factor"));
        end else begin
            Currency.InitRoundingPrecision();
            TempICGenJnlLine."Currency Code" := SalesHeader."Currency Code";
            TempICGenJnlLine."Currency Factor" := SalesHeader."Currency Factor";
            if SalesHeader.IsCreditDocType() then
                TempICGenJnlLine.Amount := SalesLine.Amount
            else
                TempICGenJnlLine.Amount := -SalesLine.Amount;
        end;
        if TempICGenJnlLine."Bal. VAT %" <> 0 then
            TempICGenJnlLine.Amount := Round(TempICGenJnlLine.Amount * (1 + TempICGenJnlLine."Bal. VAT %" / 100), Currency."Amount Rounding Precision");
        TempICGenJnlLine.Validate(Amount);
        TempICGenJnlLine."Journal Template Name" := SalesLine.GetJnlTemplateName();
        OnBeforeInsertICGenJnlLine(TempICGenJnlLine, SalesHeader, SalesLine, SuppressCommit);
        TempICGenJnlLine.Insert();
    end;

    local procedure ValidateICPartnerBusPostingGroups(SalesLine: Record "Sales Line")
    var
        Vendor: Record Vendor;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeValidateICPartnerBusPostingGroups(TempICGenJnlLine, SalesLine, IsHandled);
        if IsHandled then
            exit;

        Vendor.SetCurrentKey("IC Partner Code");
        Vendor.SetRange("IC Partner Code", SalesLine."IC Partner Code");
        if Vendor.FindFirst() then begin
            TempICGenJnlLine.Validate("Bal. Gen. Bus. Posting Group", Vendor."Gen. Bus. Posting Group");
            TempICGenJnlLine.Validate("Bal. VAT Bus. Posting Group", Vendor."VAT Bus. Posting Group");
        end;
    end;

    local procedure PostICGenJnl()
    var
        ICInOutBoxMgt: Codeunit ICInboxOutboxMgt;
        ICOutboxExport: Codeunit "IC Outbox Export";
        ICTransactionNo: Integer;
    begin
        TempICGenJnlLine.Reset();
        TempICGenJnlLine.SetFilter(Amount, '<>%1', 0);
        if TempICGenJnlLine.Find('-') then
            repeat
                ICTransactionNo := ICInOutBoxMgt.CreateOutboxJnlTransaction(TempICGenJnlLine, false);
                ICInOutBoxMgt.CreateOutboxJnlLine(ICTransactionNo, 1, TempICGenJnlLine);
                ICOutboxExport.ProcessAutoSendOutboxTransactionNo(ICTransactionNo);
                if TempICGenJnlLine.Amount <> 0 then
                    GenJnlPostLine.RunWithCheck(TempICGenJnlLine);
            until TempICGenJnlLine.Next() = 0;
    end;

    /// <summary>
    /// Checks if the prepayment amount for the sales lines is too big or too small using information from the related sales order lines.
    /// It throws an error if it is.
    /// </summary>
    /// <remarks>
    /// It is too big if the prepayment amount is bigger than the remaining prepayment amount on the sales order line.
    /// It is too small if the prepayment amount is smaller than the remaining prepayment amount on the sales order line and the sales order line is fully invoiced.
    /// If this is the last invoice and the sales line has 100% prepayment, then the actual (non-temp) invoice line is adjusted so that prepayment amount to deduct equals the line amount.
    /// </remarks>
    procedure TestGetShipmentPPmtAmtToDeduct()
    var
        TempSalesLine: Record "Sales Line" temporary;
        TempShippedSalesLine: Record "Sales Line" temporary;
        TempTotalSalesLine: Record "Sales Line" temporary;
        TempSalesShptLine: Record "Sales Shipment Line" temporary;
        SalesShptLine: Record "Sales Shipment Line";
        SalesOrderLine: Record "Sales Line";
        MaxAmtToDeduct: Decimal;
    begin
        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter(Quantity, '>0');
        TempSalesLine.SetFilter("Qty. to Invoice", '>0');
        TempSalesLine.SetFilter("Shipment No.", '<>%1', '');
        TempSalesLine.SetFilter("Prepmt Amt to Deduct", '<>0');
        if TempSalesLine.IsEmpty() then
            exit;

        TempSalesLine.SetRange("Prepmt Amt to Deduct");
        if TempSalesLine.FindSet() then
            repeat
                if SalesShptLine.Get(TempSalesLine."Shipment No.", TempSalesLine."Shipment Line No.") then begin
                    TempShippedSalesLine := TempSalesLine;
                    TempShippedSalesLine.Insert();
                    TempSalesShptLine := SalesShptLine;
                    if TempSalesShptLine.Insert() then;

                    if not TempTotalSalesLine.Get(TempSalesLine."Document Type"::Order, SalesShptLine."Order No.", SalesShptLine."Order Line No.") then begin
                        TempTotalSalesLine.Init();
                        TempTotalSalesLine."Document Type" := TempSalesLine."Document Type"::Order;
                        TempTotalSalesLine."Document No." := SalesShptLine."Order No.";
                        TempTotalSalesLine."Line No." := SalesShptLine."Order Line No.";
                        TempTotalSalesLine.Insert();
                    end;
                    TempTotalSalesLine."Qty. to Invoice" := TempTotalSalesLine."Qty. to Invoice" + TempSalesLine."Qty. to Invoice";
                    TempTotalSalesLine."Prepmt Amt to Deduct" := TempTotalSalesLine."Prepmt Amt to Deduct" + TempSalesLine."Prepmt Amt to Deduct";
                    AdjustInvLineWith100PctPrepmt(TempSalesLine, TempTotalSalesLine);
                    TempTotalSalesLine.Modify();
                end;
            until TempSalesLine.Next() = 0;

        if TempShippedSalesLine.FindSet() then
            repeat
                if TempSalesShptLine.Get(TempShippedSalesLine."Shipment No.", TempShippedSalesLine."Shipment Line No.") then
                    if SalesOrderLine.Get(
                         TempShippedSalesLine."Document Type"::Order, TempSalesShptLine."Order No.", TempSalesShptLine."Order Line No.")
                    then
                        if TempTotalSalesLine.Get(
                             TempShippedSalesLine."Document Type"::Order, TempSalesShptLine."Order No.", TempSalesShptLine."Order Line No.")
                        then begin
                            MaxAmtToDeduct := SalesOrderLine."Prepmt. Amt. Inv." - SalesOrderLine."Prepmt Amt Deducted";

                            CheckTotalPrepmtAmtToDeduct(TempSalesLine, TempTotalSalesLine, MaxAmtToDeduct);

                            if (TempTotalSalesLine."Qty. to Invoice" = SalesOrderLine.Quantity - SalesOrderLine."Quantity Invoiced") and
                               (SalesOrderLine."Prepmt Amt to Deduct" <> MaxAmtToDeduct)
                            then
                                Error(PrepAmountToDeductToSmallErr, TempSalesLine.FieldCaption(TempSalesLine."Prepmt Amt to Deduct"), MaxAmtToDeduct);
                        end;
            until TempShippedSalesLine.Next() = 0;
    end;

    local procedure CheckTotalPrepmtAmtToDeduct(var TempSalesLine: Record "Sales Line" temporary; var TempTotalSalesLine: Record "Sales Line" temporary; MaxAmtToDeduct: Decimal)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckTotalPrepmtAmtToDeduct(TempSalesLine, TempTotalSalesLine, MaxAmtToDeduct, IsHandled);
        if IsHandled then
            exit;

        if TempTotalSalesLine."Prepmt Amt to Deduct" > MaxAmtToDeduct then
            Error(PrepAmountToDeductToBigErr, TempSalesLine.FieldCaption("Prepmt Amt to Deduct"), MaxAmtToDeduct);
    end;

    local procedure AdjustInvLineWith100PctPrepmt(var SalesInvoiceLine: Record "Sales Line"; var TempTotalSalesLine: Record "Sales Line" temporary)
    var
        SalesOrderLine: Record "Sales Line";
        DiffAmtToDeduct: Decimal;
    begin
        if SalesInvoiceLine."Prepayment %" = 100 then begin
            SalesOrderLine.Get(TempTotalSalesLine."Document Type", TempTotalSalesLine."Document No.", TempTotalSalesLine."Line No.");
            if TempTotalSalesLine."Qty. to Invoice" = SalesOrderLine.Quantity - SalesOrderLine."Quantity Invoiced" then begin
                DiffAmtToDeduct :=
                  SalesOrderLine."Prepmt. Amt. Inv." - SalesOrderLine."Prepmt Amt Deducted" - TempTotalSalesLine."Prepmt Amt to Deduct";
                if DiffAmtToDeduct <> 0 then begin
                    SalesInvoiceLine."Prepmt Amt to Deduct" := SalesInvoiceLine."Prepmt Amt to Deduct" + DiffAmtToDeduct;
                    SalesInvoiceLine."Line Amount" := SalesInvoiceLine."Prepmt Amt to Deduct";
                    SalesInvoiceLine."Line Discount Amount" := SalesInvoiceLine."Line Discount Amount" - DiffAmtToDeduct;
                    ModifyTempLine(SalesInvoiceLine);
                    TempTotalSalesLine."Prepmt Amt to Deduct" := TempTotalSalesLine."Prepmt Amt to Deduct" + DiffAmtToDeduct;
                end;
            end;
        end;
    end;

    /// <summary>
    /// Archives unposted orders and return orders if archiving is enabled in the Sales Setup.
    /// </summary>
    /// <remarks>
    /// Order isn't archived if there are no lines to archive or PreviewMode is true.
    /// </remarks>
    /// <param name="SalesHeader"></param>
    procedure ArchiveUnpostedOrder(var SalesHeader: Record "Sales Header")
    var
        SalesLine: Record "Sales Line";
        ArchiveManagement: Codeunit ArchiveManagement;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeArchiveUnpostedOrder(SalesHeader, IsHandled, PreviewMode, OrderArchived);
        if IsHandled then
            exit;

        GetSalesSetup();
        if not (SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::"Return Order"]) then
            exit;
        if (SalesHeader."Document Type" = SalesHeader."Document Type"::Order) and not SalesSetup."Archive Orders" then
            exit;
        if (SalesHeader."Document Type" = SalesHeader."Document Type"::"Return Order") and not SalesSetup."Archive Return Orders" then
            exit;

        SalesLine.Reset();
        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        SalesLine.SetFilter(Quantity, '<>0');
        if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then
            SalesLine.SetFilter("Qty. to Ship", '<>0')
        else
            SalesLine.SetFilter("Return Qty. to Receive", '<>0');
        if not SalesLine.IsEmpty() and not PreviewMode then begin
            ArchiveManagement.RoundSalesDeferralsForArchive(SalesHeader, SalesLine);
            ArchiveManagement.ArchSalesDocumentNoConfirm(SalesHeader);
            OrderArchived := true;
        end;
        OnAfterArchiveUnpostedOrder(SalesHeader, SalesLine, OrderArchived);
    end;

    /// <summary>
    /// Retrieves the G/L Setup record if it hasn't been read before.
    /// </summary>
    procedure GetGLSetup()
    begin
        if not GLSetupRead then
            GLSetup.Get();

        GLSetupRead := true;

        OnAfterGetGLSetup(GLSetup);
    end;

    local procedure GetSalesSetup()
    begin
        if not SalesSetupRead then
            SalesSetup.Get();

        SalesSetupRead := true;

        OnAfterGetSalesSetup(SalesSetup);
    end;

    local procedure GetInvoicePostingSetup()
    var
        IsHandled: Boolean;
    begin
        if IsInterfaceInitalized then
            exit;

        IsHandled := false;
        OnBeforeGetInvoicePostingSetup(InvoicePostingInterface, IsHandled);
        if not IsHandled then
            InvoicePostingInterface := Enum::"Sales Invoice Posting"::"Invoice Posting (v.19)";

        InvoicePostingInterface.Check(Database::"Sales Header");
        IsInterfaceInitalized := true;

        InvoicePostingInterface.SetHideProgressWindow(HideProgressWindow);
        InvoicePostingInterface.SetPreviewMode(PreviewMode);
        InvoicePostingInterface.SetSuppressCommit(SuppressCommit);
    end;

    local procedure GetInvoicePostingParameters()
    begin
        InvoicePostingParameters."Document Type" := GenJnlLineDocType;
        InvoicePostingParameters."Document No." := GenJnlLineDocNo;
        InvoicePostingParameters."External Document No." := GenJnlLineExtDocNo;
        InvoicePostingParameters."Source Code" := SrcCode;
        InvoicePostingParameters."Auto Document No." := '';
    end;

    local procedure LockTables(var SalesHeader: Record "Sales Header")
    var
        SalesLine: Record "Sales Line";
        PurchOrderHeader: Record "Purchase Header";
        PurchOrderLine: Record "Purchase Line";
        InventorySetup: Record "Inventory Setup";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeLockTables(SalesHeader, PreviewMode, SuppressCommit, IsHandled);
        if IsHandled then
            exit;

        SalesLine.LockTable();
        ItemChargeAssgntSales.LockTable();
        PurchOrderLine.LockTable();
        PurchOrderHeader.LockTable();
        GetGLSetup();
        if InventorySetup.UseLegacyPosting() and not InventorySetup.OptimGLEntLockForMultiuserEnv() then begin
            GLEntry.LockTable();
            GLEntry.GetLastEntryNo();
        end;
    end;

    local procedure UpdateSalesHeader(var CustLedgerEntry: Record "Cust. Ledger Entry"; var SalesHeader: Record "Sales Header")
    var
        GenJnlLine: Record "Gen. Journal Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateSalesHeader(CustLedgerEntry, SalesInvHeader, SalesCrMemoHeader, GenJnlLineDocType.AsInteger(), IsHandled, GenJnlLineDocNo, PreviewMode, SalesHeader);
        if IsHandled then
            exit;

        case GenJnlLineDocType of
            GenJnlLine."Document Type"::Invoice:
                begin
                    FindCustLedgEntry(GenJnlLineDocType, GenJnlLineDocNo, CustLedgerEntry);
                    SalesInvHeader."Cust. Ledger Entry No." := CustLedgerEntry."Entry No.";
                    SalesInvHeader.Modify();
                end;
            GenJnlLine."Document Type"::"Credit Memo":
                begin
                    FindCustLedgEntry(GenJnlLineDocType, GenJnlLineDocNo, CustLedgerEntry);
                    SalesCrMemoHeader."Cust. Ledger Entry No." := CustLedgerEntry."Entry No.";
                    SalesCrMemoHeader.Modify();
                end;
        end;

        OnAfterUpdateSalesHeader(CustLedgerEntry, SalesInvHeader, SalesCrMemoHeader, GenJnlLineDocType.AsInteger(), GenJnlLineDocNo, PreviewMode, SalesHeader);
    end;

    local procedure MakeSalesLineToShip(var SalesLineToShip: Record "Sales Line"; SalesLineInvoiced: Record "Sales Line")
    var
        TempSalesLine: Record "Sales Line" temporary;
    begin
        ResetTempLines(TempSalesLine);
        TempSalesLine := SalesLineInvoiced;
        TempSalesLine.Find();

        SalesLineToShip := SalesLineInvoiced;
        SalesLineToShip."Inv. Discount Amount" := TempSalesLine."Inv. Discount Amount";
    end;

    local procedure "MAX"(number1: Integer; number2: Integer): Integer
    begin
        if number1 > number2 then
            exit(number1);
        exit(number2);
    end;

    local procedure FindCustLedgEntry(DocType: Enum "Gen. Journal Document Type"; DocNo: Code[20]; var CustLedgEntry: Record "Cust. Ledger Entry")
    begin
        OnBeforeFindCustLedgEntry(CustLedgEntry);
        CustLedgEntry.SetRange("Document Type", DocType);
        CustLedgEntry.SetRange("Document No.", DocNo);
        CustLedgEntry.FindLast();
    end;

    local procedure ItemLedgerEntryExist(SalesLine2: Record "Sales Line"; ShipOrReceive: Boolean): Boolean
    var
        HasItemLedgerEntry: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeItemLedgerEntryExist(SalesLine2, ShipOrReceive, HasItemLedgerEntry, IsHandled);
        if IsHandled then
            exit(HasItemLedgerEntry);

        if ShipOrReceive then
            // item ledger entry will be created during posting in this transaction
            HasItemLedgerEntry :=
            ((SalesLine2."Qty. to Ship" + SalesLine2."Quantity Shipped") <> 0) or
            ((SalesLine2."Qty. to Invoice" + SalesLine2."Quantity Invoiced") <> 0) or
            ((SalesLine2."Return Qty. to Receive" + SalesLine2."Return Qty. Received") <> 0)
        else
            // item ledger entry must already exist
            HasItemLedgerEntry :=
            (SalesLine2."Quantity Shipped" <> 0) or
            (SalesLine2."Return Qty. Received" <> 0);

        exit(HasItemLedgerEntry);
    end;

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

        if not PreviewMode then
            SalesHeader.CheckSalesPostRestrictions();

        CheckCustBlockage(SalesHeader, SalesHeader."Sell-to Customer No.", true);
        SalesHeader.ValidateSalesPersonOnSalesHeader(SalesHeader, true, true);

        if SalesHeader."Bill-to Customer No." <> SalesHeader."Sell-to Customer No." then
            CheckCustBlockage(SalesHeader, SalesHeader."Bill-to Customer No.", false);

        if SalesHeader."Sell-to Contact No." <> '' then
            if Contact.Get(SalesHeader."Sell-to Contact No.") then
                Contact.CheckIfPrivacyBlocked(true);
        if SalesHeader."Bill-to Contact No." <> '' then
            if Contact.Get(SalesHeader."Bill-to Contact No.") then
                Contact.CheckIfPrivacyBlocked(true);
    end;

    local procedure CheckCustBlockage(SalesHeader: Record "Sales Header"; CustCode: Code[20]; ExecuteDocCheck: Boolean)
    var
        Cust: Record Customer;
        TempSalesLine: Record "Sales Line" temporary;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckCustBlockage(SalesHeader, CustCode, ExecuteDocCheck, IsHandled, TempSalesLineGlobal);
        if IsHandled then
            exit;

        Cust.Get(CustCode);
        if SalesHeader.Receive then
            Cust.CheckBlockedCustOnDocs(Cust, SalesHeader."Document Type", false, true)
        else
            if SalesHeader.Ship and CheckDocumentType(SalesHeader, ExecuteDocCheck) then begin
                ResetTempLines(TempSalesLine);
                TempSalesLine.SetFilter("Qty. to Ship", '<>0');
                TempSalesLine.SetRange("Shipment No.", '');
                OnCheckCustBlockageOnAfterTempLinesSetFilters(SalesHeader, TempSalesLine);
                if not TempSalesLine.IsEmpty() then
                    Cust.CheckBlockedCustOnDocs(Cust, SalesHeader."Document Type", true, true);
            end else
                Cust.CheckBlockedCustOnDocs(Cust, SalesHeader."Document Type", false, true);
    end;

    /// <summary>
    /// Retrieves the General Posting Setup record for the specified sales line.
    /// </summary>
    /// <param name="GenPostingSetup">Return Variable: General Posting Setup record</param>
    /// <param name="SalesLine">sales line for which to retrieve the Gen. Posting Setup</param>
    procedure GetGeneralPostingSetup(var GenPostingSetup: Record "General Posting Setup"; SalesLine: Record "Sales Line")
    begin
        GenPostingSetup.Get(SalesLine."Gen. Bus. Posting Group", SalesLine."Gen. Prod. Posting Group");

        OnAfterGetGeneralPostingSetup(GenPostingSetup, SalesLine);
    end;

    local procedure CheckDocumentType(SalesHeader: Record "Sales Header"; ExecuteDocCheck: Boolean): Boolean
    begin
        if ExecuteDocCheck then
            exit(
              (SalesHeader."Document Type" = SalesHeader."Document Type"::Order) or
              ((SalesHeader."Document Type" = SalesHeader."Document Type"::Invoice) and SalesSetup."Shipment on Invoice"));
        exit(true);
    end;

    local procedure UpdateWonOpportunities(var SalesHeader: Record "Sales Header")
    var
        Opp: Record Opportunity;
        OpportunityEntry: Record "Opportunity Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateWonOpportunities(SalesHeader, SalesInvHeader, IsHandled);
        if not IsHandled then
            if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then begin
                Opp.Reset();
                Opp.SetCurrentKey("Sales Document Type", "Sales Document No.");
                Opp.SetRange("Sales Document Type", Opp."Sales Document Type"::Order);
                Opp.SetRange("Sales Document No.", SalesHeader."No.");
                Opp.SetRange(Status, Opp.Status::Won);
                if Opp.FindFirst() then begin
                    Opp."Sales Document Type" := Opp."Sales Document Type"::"Posted Invoice";
                    Opp."Sales Document No." := SalesInvHeader."No.";
                    OnUpdateWonOpportunitiesOnBeforeOpportunityModify(SalesHeader, SalesInvHeader, Opp);
                    Opp.Modify();
                    OpportunityEntry.Reset();
                    OpportunityEntry.SetCurrentKey(Active, "Opportunity No.");
                    OpportunityEntry.SetRange(Active, true);
                    OpportunityEntry.SetRange("Opportunity No.", Opp."No.");
                    if OpportunityEntry.FindFirst() then begin
                        OpportunityEntry."Calcd. Current Value (LCY)" := OpportunityEntry.GetSalesDocValue(SalesHeader);
                        OpportunityEntry.Modify();
                    end;
                end;
            end;

        OnAfterUpdateWonOpportunities(SalesHeader, SalesInvHeader);
    end;

    local procedure UpdateQtyToBeInvoicedForShipment(var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; TrackingSpecificationExists: Boolean; HasATOShippedNotInvoiced: Boolean; SalesLine: Record "Sales Line"; SalesShptLine: Record "Sales Shipment Line"; InvoicingTrackingSpecification: Record "Tracking Specification"; ItemLedgEntryNotInvoiced: Record "Item Ledger Entry")
    begin
        OnBeforeUpdateQtyToBeInvoicedForShipment(
            QtyToBeInvoiced, QtyToBeInvoicedBase, TrackingSpecificationExists, HasATOShippedNotInvoiced,
            SalesLine, SalesShptLine, InvoicingTrackingSpecification);
        if TrackingSpecificationExists then begin
            QtyToBeInvoiced := InvoicingTrackingSpecification."Qty. to Invoice";
            QtyToBeInvoicedBase := InvoicingTrackingSpecification."Qty. to Invoice (Base)";
        end else
            if HasATOShippedNotInvoiced then begin
                QtyToBeInvoicedBase := ItemLedgEntryNotInvoiced.Quantity - ItemLedgEntryNotInvoiced."Invoiced Quantity";
                if Abs(QtyToBeInvoicedBase) > Abs(RemQtyToBeInvoicedBase) then
                    QtyToBeInvoicedBase := RemQtyToBeInvoicedBase - SalesLine."Qty. to Ship (Base)";
                QtyToBeInvoiced := Round(QtyToBeInvoicedBase / SalesShptLine."Qty. per Unit of Measure", UOMMgt.QtyRndPrecision());
            end else begin
                QtyToBeInvoiced := RemQtyToBeInvoiced - SalesLine."Qty. to Ship";
                QtyToBeInvoicedBase := RemQtyToBeInvoicedBase - SalesLine."Qty. to Ship (Base)";
            end;

        OnUpdateQtyToBeInvoicedForShipmentOnAfterSetQtyToBeInvoiced(
            TrackingSpecificationExists, HasATOShippedNotInvoiced, QtyToBeInvoiced, QtyToBeInvoicedBase, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, SalesLine);

        if Abs(QtyToBeInvoiced) > Abs(SalesShptLine.Quantity - SalesShptLine."Quantity Invoiced") then begin
            QtyToBeInvoiced := -(SalesShptLine.Quantity - SalesShptLine."Quantity Invoiced");
            QtyToBeInvoicedBase := -(SalesShptLine."Quantity (Base)" - SalesShptLine."Qty. Invoiced (Base)");
        end;
    end;

    local procedure UpdateQtyToBeInvoicedForReturnReceipt(var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; TrackingSpecificationExists: Boolean; SalesLine: Record "Sales Line"; ReturnReceiptLine: Record "Return Receipt Line"; InvoicingTrackingSpecification: Record "Tracking Specification")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateQtyToBeInvoicedForReturnReceipt(
            QtyToBeInvoiced, QtyToBeInvoicedBase, TrackingSpecificationExists, SalesLine, ReturnReceiptLine,
            InvoicingTrackingSpecification, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, IsHandled);
        if IsHandled then
            exit;

        if TrackingSpecificationExists then begin
            QtyToBeInvoiced := InvoicingTrackingSpecification."Qty. to Invoice";
            QtyToBeInvoicedBase := InvoicingTrackingSpecification."Qty. to Invoice (Base)";
        end else begin
            QtyToBeInvoiced := RemQtyToBeInvoiced - SalesLine."Return Qty. to Receive";
            QtyToBeInvoicedBase := RemQtyToBeInvoicedBase - SalesLine."Return Qty. to Receive (Base)";
        end;
        OnUpdateQtyToBeInvoicedForReturnReceiptOnAfterSetQtyToBeInvoiced(TrackingSpecificationExists, QtyToBeInvoiced, QtyToBeInvoicedBase, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, SalesLine);

        if Abs(QtyToBeInvoiced) >
           Abs(ReturnReceiptLine.Quantity - ReturnReceiptLine."Quantity Invoiced")
        then begin
            QtyToBeInvoiced := ReturnReceiptLine.Quantity - ReturnReceiptLine."Quantity Invoiced";
            QtyToBeInvoicedBase := ReturnReceiptLine."Quantity (Base)" - ReturnReceiptLine."Qty. Invoiced (Base)";
        end;
    end;

    local procedure UpdateRemainingQtyToBeInvoiced(SalesShptLine: Record "Sales Shipment Line"; var RemQtyToInvoiceCurrLine: Decimal; var RemQtyToInvoiceCurrLineBase: Decimal)
    var
        IsHandled: Boolean;
    begin
        OnBeforeUpdateRemainingQtyToBeInvoiced(SalesShptLine, RemQtyToInvoiceCurrLine, RemQtyToInvoiceCurrLineBase, IsHandled);
        if IsHandled then
            exit;

        RemQtyToInvoiceCurrLine := -SalesShptLine.Quantity + SalesShptLine."Quantity Invoiced";
        RemQtyToInvoiceCurrLineBase := -SalesShptLine."Quantity (Base)" + SalesShptLine."Qty. Invoiced (Base)";
        if RemQtyToInvoiceCurrLine < RemQtyToBeInvoiced then begin
            RemQtyToInvoiceCurrLine := RemQtyToBeInvoiced;
            RemQtyToInvoiceCurrLineBase := RemQtyToBeInvoicedBase;
        end;
    end;

    local procedure IsEndLoopForShippedNotInvoiced(RemQtyToBeInvoiced: Decimal; TrackingSpecificationExists: Boolean; var HasATOShippedNotInvoiced: Boolean; var SalesShptLine: Record "Sales Shipment Line"; var InvoicingTrackingSpecification: Record "Tracking Specification"; var ItemLedgEntryNotInvoiced: Record "Item Ledger Entry"; SalesLine: Record "Sales Line") Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsEndLoopForShippedNotInvoiced(
            RemQtyToBeInvoiced, TrackingSpecificationExists, HasATOShippedNotInvoiced, SalesShptLine,
            InvoicingTrackingSpecification, ItemLedgEntryNotInvoiced, SalesLine, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if TrackingSpecificationExists then
            exit((InvoicingTrackingSpecification.Next() = 0) or (RemQtyToBeInvoiced = 0));

        if HasATOShippedNotInvoiced then begin
            HasATOShippedNotInvoiced := ItemLedgEntryNotInvoiced.Next() <> 0;
            if not HasATOShippedNotInvoiced then
                exit(not SalesShptLine.FindSet() or (Abs(RemQtyToBeInvoiced) <= Abs(SalesLine."Qty. to Ship")));
            exit(Abs(RemQtyToBeInvoiced) <= Abs(SalesLine."Qty. to Ship"));
        end;

        IsHandled := false;
        OnIsEndLoopForShippedNotInvoicedOnBeforeExit(SalesLine, SalesShptLine, RemQtyToBeInvoiced, Result, IsHandled);
        if IsHandled then
            exit(Result);

        exit((SalesShptLine.Next() = 0) or (Abs(RemQtyToBeInvoiced) <= Abs(SalesLine."Qty. to Ship")));
    end;

    /// <summary>
    /// Retrieves the Item Entry Relation and Sales Shipment Line that are related to the item entry
    /// If tracking specification exists, they are retrieved from the tracking specification information
    /// If there are assembly-to-order shipped not invoiced lines, they are retrieved from the assembly-to-order shipped not invoiced item ledger entry information
    /// </summary>
    /// <remarks>
    /// If tracking specification doesn't exist, and there are no assembly-to-order shipped not invoiced lines, Item Entry Relation is assigned the Item Shipment Entry No. from the incoming Sales Shipment Line
    /// </remarks>
    /// <param name="ItemEntryRelation">Return value: Item Entry Relation related to the Item Entry</param>
    /// <param name="SalesShptLine">Return value: Sales Shipment Line related to the Item Entry</param>
    /// <param name="InvoicingTrackingSpecification">Tracking Specification for the Item Ledger Entry</param>
    /// <param name="ItemLedgEntryNotInvoiced">An assemble-to-order Item Ledger Entry that is shipped, but not invoiced.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether the Item Ledger Entry has a Tracking Specification</param>
    /// <param name="HasATOShippedNotInvoiced">Indicates whether there are Assembly-to-order Shipped Not Invoiced lines</param>
    procedure SetItemEntryRelation(var ItemEntryRelation: Record "Item Entry Relation"; var SalesShptLine: Record "Sales Shipment Line"; var InvoicingTrackingSpecification: Record "Tracking Specification"; var ItemLedgEntryNotInvoiced: Record "Item Ledger Entry"; TrackingSpecificationExists: Boolean; HasATOShippedNotInvoiced: Boolean)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSetItemEntryRelation(ItemEntryRelation, SalesShptLine, InvoicingTrackingSpecification, IsHandled);
        if IsHandled then
            exit;

        if TrackingSpecificationExists then begin
            ItemEntryRelation.Get(InvoicingTrackingSpecification."Item Ledger Entry No.");
            SalesShptLine.Get(ItemEntryRelation."Source ID", ItemEntryRelation."Source Ref. No.");
        end else
            if HasATOShippedNotInvoiced then begin
                ItemEntryRelation."Item Entry No." := ItemLedgEntryNotInvoiced."Entry No.";
                SalesShptLine.Get(ItemLedgEntryNotInvoiced."Document No.", ItemLedgEntryNotInvoiced."Document Line No.");
            end else
                ItemEntryRelation."Item Entry No." := SalesShptLine."Item Shpt. Entry No.";
    end;

    local procedure PostATOAssocItemJnlLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var PostedATOLink: Record "Posted Assemble-to-Order Link"; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal)
    var
        DummyTrackingSpecification: Record "Tracking Specification";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostATOAssocItemJnlLine(SalesHeader, SalesLine, PostedATOLink, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, ItemLedgShptEntryNo, IsHandled);
        if IsHandled then
            exit;

        DummyTrackingSpecification.Init();
        if SalesLine."Document Type" = SalesLine."Document Type"::Order then begin
            PostedATOLink."Assembled Quantity" := -PostedATOLink."Assembled Quantity";
            PostedATOLink."Assembled Quantity (Base)" := -PostedATOLink."Assembled Quantity (Base)";
            if Abs(RemQtyToBeInvoiced) >= Abs(PostedATOLink."Assembled Quantity") then begin
                ItemLedgShptEntryNo :=
                  PostItemJnlLine(
                    SalesHeader, SalesLine,
                    PostedATOLink."Assembled Quantity", PostedATOLink."Assembled Quantity (Base)",
                    PostedATOLink."Assembled Quantity", PostedATOLink."Assembled Quantity (Base)",
                    0, '', DummyTrackingSpecification, true);
                RemQtyToBeInvoiced -= PostedATOLink."Assembled Quantity";
                RemQtyToBeInvoicedBase -= PostedATOLink."Assembled Quantity (Base)";
            end else begin
                if RemQtyToBeInvoiced <> 0 then
                    ItemLedgShptEntryNo :=
                      PostItemJnlLine(
                        SalesHeader, SalesLine,
                        RemQtyToBeInvoiced,
                        RemQtyToBeInvoicedBase,
                        RemQtyToBeInvoiced,
                        RemQtyToBeInvoicedBase,
                        0, '', DummyTrackingSpecification, true);

                OnPostATOAssocItemJnlLineOnBeforeRemainingPost(
                    SalesHeader, SalesLine, PostedATOLink, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, ItemLedgShptEntryNo);

                ItemLedgShptEntryNo :=
                  PostItemJnlLine(
                    SalesHeader, SalesLine,
                    PostedATOLink."Assembled Quantity" - RemQtyToBeInvoiced,
                    PostedATOLink."Assembled Quantity (Base)" - RemQtyToBeInvoicedBase,
                    0, 0,
                    0, '', DummyTrackingSpecification, true);

                RemQtyToBeInvoiced := 0;
                RemQtyToBeInvoicedBase := 0;
            end;
        end;
    end;

    local procedure GetOpenLinkedATOs(var TempAsmHeader: Record "Assembly Header" temporary)
    var
        TempSalesLine: Record "Sales Line" temporary;
        AsmHeader: Record "Assembly Header";
    begin
        ResetTempLines(TempSalesLine);
        if TempSalesLine.FindSet() then
            repeat
                if TempSalesLine.AsmToOrderExists(AsmHeader) then
                    if AsmHeader.Status = AsmHeader.Status::Open then begin
                        TempAsmHeader.TransferFields(AsmHeader);
                        TempAsmHeader.Insert();
                    end;
            until TempSalesLine.Next() = 0;
    end;

    local procedure ReopenAsmOrders(var TempAsmHeader: Record "Assembly Header" temporary)
    var
        AsmHeader: Record "Assembly Header";
    begin
        if TempAsmHeader.Find('-') then
            repeat
                AsmHeader.Get(TempAsmHeader."Document Type", TempAsmHeader."No.");
                AsmHeader.Status := AsmHeader.Status::Open;
                AsmHeader.Modify();
            until TempAsmHeader.Next() = 0;
    end;

    local procedure InitPostATO(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    var
        AsmHeader: Record "Assembly Header";
        Window: Dialog;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInitPostATO(SalesHeader, SalesLine, AsmPost, HideProgressWindow, IsHandled);
        if IsHandled then
            exit;

        if SalesLine.AsmToOrderExists(AsmHeader) then begin
            if GuiAllowed() and not HideProgressWindow then begin
                Window.Open(AssemblyCheckProgressMsg);
                Window.Update(1,
                  StrSubstNo('%1 %2 %3 %4',
                    SalesLine."Document Type", SalesLine."Document No.", SalesLine.FieldCaption("Line No."), SalesLine."Line No."));
                Window.Update(2, StrSubstNo('%1 %2', AsmHeader."Document Type", AsmHeader."No."));
            end;

            SalesLine.CheckAsmToOrder(AsmHeader);
            if not HasQtyToAsm(SalesLine, AsmHeader) then
                exit;

            AsmPost.SetSuppressCommit(SuppressCommit);
            AsmPost.SetPostingDate(true, SalesHeader."Posting Date");
            AsmPost.InitPostATO(AsmHeader);

            if GuiAllowed() and not HideProgressWindow then
                Window.Close();
        end;
    end;

    local procedure InitPostATOs(SalesHeader: Record "Sales Header")
    var
        TempSalesLine: Record "Sales Line" temporary;
    begin
        FindNotShippedLines(SalesHeader, TempSalesLine);
        TempSalesLine.SetFilter("Qty. to Assemble to Order", '<>0');
        if TempSalesLine.FindSet() then
            repeat
                InitPostATO(SalesHeader, TempSalesLine);
            until TempSalesLine.Next() = 0;
    end;

    local procedure PostATO(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary)
    var
        AsmHeader: Record "Assembly Header";
        PostedATOLink: Record "Posted Assemble-to-Order Link";
        Window: Dialog;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostATO(SalesHeader, SalesLine, TempPostedATOLink, AsmPost, ItemJnlPostLine, ResJnlPostLine, WhseJnlPostLine, HideProgressWindow, IsHandled);
        if IsHandled then
            exit;

        if SalesLine.AsmToOrderExists(AsmHeader) then begin
            if GuiAllowed() and not HideProgressWindow then begin
                Window.Open(AssemblyPostProgressMsg);
                Window.Update(1,
                  StrSubstNo('%1 %2 %3 %4',
                    SalesLine."Document Type", SalesLine."Document No.", SalesLine.FieldCaption("Line No."), SalesLine."Line No."));
                Window.Update(2, StrSubstNo('%1 %2', AsmHeader."Document Type", AsmHeader."No."));
            end;

            SalesLine.CheckAsmToOrder(AsmHeader);
            if not HasQtyToAsm(SalesLine, AsmHeader) then
                exit;
            if AsmHeader."Remaining Quantity (Base)" = 0 then
                exit;

            PostedATOLink.Init();
            PostedATOLink."Assembly Document Type" := PostedATOLink."Assembly Document Type"::Assembly;
            PostedATOLink."Assembly Document No." := AsmHeader."Posting No.";
            PostedATOLink."Document Type" := PostedATOLink."Document Type"::"Sales Shipment";
            PostedATOLink."Document No." := SalesHeader."Shipping No.";
            PostedATOLink."Document Line No." := SalesLine."Line No.";

            PostedATOLink."Assembly Order No." := AsmHeader."No.";
            PostedATOLink."Order No." := SalesLine."Document No.";
            PostedATOLink."Order Line No." := SalesLine."Line No.";

            PostedATOLink."Assembled Quantity" := AsmHeader."Quantity to Assemble";
            PostedATOLink."Assembled Quantity (Base)" := AsmHeader."Quantity to Assemble (Base)";

            OnPostATOOnBeforePostedATOLinkInsert(PostedATOLink, AsmHeader, SalesLine);
            PostedATOLink.Insert();

            TempPostedATOLink := PostedATOLink;
            TempPostedATOLink.Insert();

            AsmPost.PostATO(AsmHeader, ItemJnlPostLine, ResJnlPostLine, WhseJnlPostLine);

            if GuiAllowed() and not HideProgressWindow then
                Window.Close();
        end;
    end;

    local procedure FinalizePostATO(var SalesLine: Record "Sales Line")
    var
        ATOLink: Record "Assemble-to-Order Link";
        AsmHeader: Record "Assembly Header";
        Window: Dialog;
        IsHandled: Boolean;
    begin
        OnBeforeFinalizePostATO(SalesLine, IsHandled);
        if IsHandled then
            exit;

        if SalesLine.AsmToOrderExists(AsmHeader) then begin
            if GuiAllowed() and not HideProgressWindow then begin
                Window.Open(AssemblyFinalizeProgressMsg);
                Window.Update(1,
                  StrSubstNo('%1 %2 %3 %4',
                    SalesLine."Document Type", SalesLine."Document No.", SalesLine.FieldCaption("Line No."), SalesLine."Line No."));
                Window.Update(2, StrSubstNo('%1 %2', AsmHeader."Document Type", AsmHeader."No."));
            end;

            SalesLine.CheckAsmToOrder(AsmHeader);
            AsmHeader.TestField("Remaining Quantity (Base)", 0);
            AsmPost.FinalizePostATO(AsmHeader);
            ATOLink.Get(AsmHeader."Document Type", AsmHeader."No.");
            ATOLink.Delete();

            if GuiAllowed() and not HideProgressWindow then
                Window.Close();
        end;
    end;

    local procedure CheckATOLink(SalesLine: Record "Sales Line")
    var
        AsmHeader: Record "Assembly Header";
        IsHandled: Boolean;
    begin
        OnBeforeCheckATOLink(SalesLine, IsHandled);
        if IsHandled then
            exit;

        if SalesLine."Qty. to Asm. to Order (Base)" = 0 then
            exit;
        if SalesLine.AsmToOrderExists(AsmHeader) then
            SalesLine.CheckAsmToOrder(AsmHeader);
    end;

    local procedure DeleteATOLinks(SalesHeader: Record "Sales Header")
    var
        ATOLink: Record "Assemble-to-Order Link";
        IsHandled: Boolean;
    begin
        OnBeforeDeleteATOLinks(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        ATOLink.SetCurrentKey(ATOLink.Type, ATOLink."Document Type", ATOLink."Document No.");
        ATOLink.SetRange(ATOLink.Type, ATOLink.Type::Sale);
        ATOLink.SetRange(ATOLink."Document Type", SalesHeader."Document Type");
        ATOLink.SetRange(ATOLink."Document No.", SalesHeader."No.");
        if not ATOLink.IsEmpty() then
            ATOLink.DeleteAll();
    end;

    local procedure HasQtyToAsm(SalesLine: Record "Sales Line"; AsmHeader: Record "Assembly Header"): Boolean
    begin
        if SalesLine."Qty. to Asm. to Order (Base)" = 0 then
            exit(false);
        if SalesLine."Qty. to Ship (Base)" = 0 then
            exit(false);
        if AsmHeader."Quantity to Assemble (Base)" = 0 then
            exit(false);
        exit(true);
    end;

    local procedure GetATOItemLedgEntriesNotInvoiced(SalesLine: Record "Sales Line"; var ItemLedgEntryNotInvoiced: Record "Item Ledger Entry"): Boolean
    var
        PostedATOLink: Record "Posted Assemble-to-Order Link";
        ItemLedgEntry: Record "Item Ledger Entry";
    begin
        ItemLedgEntryNotInvoiced.Reset();
        ItemLedgEntryNotInvoiced.DeleteAll();
        if PostedATOLink.FindLinksFromSalesLine(SalesLine) then
            repeat
                ItemLedgEntry.SetCurrentKey("Document No.", "Document Type", "Document Line No.");
                ItemLedgEntry.SetRange("Document Type", ItemLedgEntry."Document Type"::"Sales Shipment");
                ItemLedgEntry.SetRange("Document No.", PostedATOLink."Document No.");
                ItemLedgEntry.SetRange("Document Line No.", PostedATOLink."Document Line No.");
                ItemLedgEntry.SetRange("Assemble to Order", true);
                ItemLedgEntry.SetRange("Completely Invoiced", false);
                if ItemLedgEntry.FindSet() then
                    repeat
                        if ItemLedgEntry.Quantity <> ItemLedgEntry."Invoiced Quantity" then begin
                            ItemLedgEntryNotInvoiced := ItemLedgEntry;
                            OnGetATOItemLedgEntriesNotInvoicedOnBeforeItemLedgEntryNotInvoicedInsert(ItemLedgEntryNotInvoiced);
                            ItemLedgEntryNotInvoiced.Insert();
                        end;
                    until ItemLedgEntry.Next() = 0;
            until PostedATOLink.Next() = 0;

        exit(ItemLedgEntryNotInvoiced.FindSet());
    end;

    /// <summary>
    /// Sets the Warehouse Journal Register Line codeunit to the global variable
    /// The codeunit is used when posting Warehouse Journal Lines, Assembly Orders and Warehouse Shipments
    /// </summary>
    /// <param name="WhseJnlRegisterLine">Warehouse Journal Register Line codeunit to be set</param>
    procedure SetWhseJnlRegisterCU(var WhseJnlRegisterLine: Codeunit "Whse. Jnl.-Register Line")
    begin
        WhseJnlPostLine := WhseJnlRegisterLine;
    end;

    local procedure CheckPostWhseShptLines(var SalesShipmentLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line")
    var
        WarehouseShipmentLine: Record "Warehouse Shipment Line";
        IsHandled: Boolean;
        WhseShptLinesFound: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckPostWhseShptLines(SalesShipmentLine, SalesLine, IsHandled, WhseShptHeader, WhseRcptHeader, WhseShip, WhseReceive);
        if IsHandled then
            exit;

        if WhseShip then begin
            WhseShptLinesFound :=
                WarehouseShipmentLine.GetWhseShptLine(
                    WhseShptHeader."No.", DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.");
            OnCheckPostWhseShptLinesOnAfterWhseShptLinesFound(SalesShipmentLine, SalesLine, WhseShptLinesFound, WhseShptHeader, WhseRcptHeader, WhseShip, WhseReceive, WarehouseShipmentLine);
            if WhseShptLinesFound then
                PostWhseShptLines(WarehouseShipmentLine, SalesShipmentLine, SalesLine);
        end;
    end;

    local procedure PostWhseShptLines(var WhseShptLine2: Record "Warehouse Shipment Line"; SalesShptLine2: Record "Sales Shipment Line"; var SalesLine2: Record "Sales Line")
    var
        ATOWhseShptLine: Record "Warehouse Shipment Line";
        NonATOWhseShptLine: Record "Warehouse Shipment Line";
        ATOLineFound: Boolean;
        NonATOLineFound: Boolean;
        TotalSalesShptLineQty: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostWhseShptLines(WhseShptLine2, SalesShptLine2, SalesLine2, IsHandled, PostedWhseShptHeader);
        if IsHandled then
            exit;

        WhseShptLine2.GetATOAndNonATOLines(ATOWhseShptLine, NonATOWhseShptLine, ATOLineFound, NonATOLineFound);
        if ATOLineFound then
            TotalSalesShptLineQty += ATOWhseShptLine."Qty. to Ship";
        if NonATOLineFound then
            TotalSalesShptLineQty += NonATOWhseShptLine."Qty. to Ship";
        SalesShptLine2.TestField(Quantity, TotalSalesShptLineQty);

        SaveTempWhseSplitSpec(SalesLine2, TempATOTrackingSpecification);
        WhsePostShpt.SetWhseJnlRegisterCU(WhseJnlPostLine);
        if ATOLineFound and (ATOWhseShptLine."Qty. to Ship (Base)" > 0) then
            WhsePostShpt.CreatePostedShptLine(
              ATOWhseShptLine, PostedWhseShptHeader, PostedWhseShptLine, TempWhseSplitSpecification);

        SaveTempWhseSplitSpec(SalesLine2, TempHandlingSpecification);
        if NonATOLineFound and (NonATOWhseShptLine."Qty. to Ship (Base)" > 0) then
            WhsePostShpt.CreatePostedShptLine(
              NonATOWhseShptLine, PostedWhseShptHeader, PostedWhseShptLine, TempWhseSplitSpecification);
    end;

    local procedure GetCountryCode(SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"): Code[10]
    var
        SalesShipmentHeader: Record "Sales Shipment Header";
        CountryRegionCode: Code[10];
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetCountryCode(SalesHeader, SalesLine, CountryRegionCode, IsHandled);
        if IsHandled then
            exit(CountryRegionCode);

        if SalesLine."Shipment No." <> '' then begin
            SalesShipmentHeader.Get(SalesLine."Shipment No.");
            exit(
              GetCountryRegionCode(
                SalesLine."Sell-to Customer No.",
                SalesShipmentHeader."Ship-to Code",
                SalesShipmentHeader."Sell-to Country/Region Code"));
        end;

        if SalesHeader.IsCreditDocType() then begin
            if not SalesHeader.Receive then begin
                if (SalesHeader."Ship-to Country/Region Code" <> '') then
                    exit(SalesHeader."Ship-to Country/Region Code")
                else
                    exit(SalesHeader."Sell-to Country/Region Code");
            end else begin
                if (SalesHeader."Ship-to Country/Region Code" = '') and (SalesHeader."Rcvd.-from Count./Region Code" = '') then
                    exit(SalesHeader."Sell-to Country/Region Code");
                if SalesHeader."Rcvd.-from Count./Region Code" <> '' then
                    exit(SalesHeader."Rcvd.-from Count./Region Code");
                exit(SalesHeader."Ship-to Country/Region Code");
            end;
        end else begin
            CountryRegionCode := SalesHeader."Ship-to Country/Region Code";

            exit(
              GetCountryRegionCode(
                SalesLine."Sell-to Customer No.",
                SalesHeader."Ship-to Code",
                CountryRegionCode));
        end;
    end;

    local procedure GetCountryRegionCode(CustNo: Code[20]; ShipToCode: Code[10]; SellToCountryRegionCode: Code[10]) Result: Code[10]
    var
        ShipToAddress: Record "Ship-to Address";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetCountryRegionCode(CustNo, ShipToCode, SellToCountryRegionCode, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if ShipToCode <> '' then begin
            ShipToAddress.Get(CustNo, ShipToCode);
            exit(ShipToAddress."Country/Region Code");
        end;
        exit(SellToCountryRegionCode);
    end;

    local procedure UpdateIncomingDocument(IncomingDocNo: Integer; PostingDate: Date; GenJnlLineDocNo: Code[20])
    var
        IncomingDocument: Record "Incoming Document";
    begin
        IncomingDocument.UpdateIncomingDocumentFromPosting(IncomingDocNo, PostingDate, GenJnlLineDocNo);
    end;

    local procedure CheckItemCharge(ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)")
    var
        SalesLineForCharge: Record "Sales Line";
    begin
        case ItemChargeAssgntSales."Applies-to Doc. Type" of
            ItemChargeAssgntSales."Applies-to Doc. Type"::Order,
              ItemChargeAssgntSales."Applies-to Doc. Type"::Invoice:
                if SalesLineForCharge.Get(
                     ItemChargeAssgntSales."Applies-to Doc. Type",
                     ItemChargeAssgntSales."Applies-to Doc. No.",
                     ItemChargeAssgntSales."Applies-to Doc. Line No.")
                then
                    if (SalesLineForCharge."Quantity (Base)" = SalesLineForCharge."Qty. Shipped (Base)") and
                       (SalesLineForCharge."Qty. Shipped Not Invd. (Base)" = 0)
                    then
                        Error(ReassignItemChargeErr);
            ItemChargeAssgntSales."Applies-to Doc. Type"::"Return Order",
              ItemChargeAssgntSales."Applies-to Doc. Type"::"Credit Memo":
                if SalesLineForCharge.Get(
                     ItemChargeAssgntSales."Applies-to Doc. Type",
                     ItemChargeAssgntSales."Applies-to Doc. No.",
                     ItemChargeAssgntSales."Applies-to Doc. Line No.")
                then
                    if (SalesLineForCharge."Quantity (Base)" = SalesLineForCharge."Return Qty. Received (Base)") and
                       (SalesLineForCharge."Ret. Qty. Rcd. Not Invd.(Base)" = 0)
                    then
                        Error(ReassignItemChargeErr);
        end;
    end;

    local procedure CheckItemReservDisruption(SalesLine: Record "Sales Line")
    var
        ConfirmManagement: Codeunit "Confirm Management";
        AvailableQty: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckItemReservDisruption(SalesLine, IsHandled);
        if IsHandled then
            exit;

        if not (SalesLine."Document Type" in [SalesLine."Document Type"::Order, SalesLine."Document Type"::Invoice]) or
           (SalesLine.Type <> SalesLine.Type::Item) or not (SalesLine."Qty. to Ship (Base)" > 0)
        then
            exit;
        if (SalesLine."Job Contract Entry No." <> 0) or
           SalesLine.Nonstock or SalesLine."Special Order" or SalesLine."Drop Shipment" or
           SalesLine.FullQtyIsForAsmToOrder() or
           TempSKU.Get(SalesLine."Location Code", SalesLine."No.", SalesLine."Variant Code")
        then
            exit;

        if SalesLine.IsNonInventoriableItem() then
            exit;

        // For muliple sales order lines, the transaction acquires a lock on the reservation entry table while transfering reservervation entry for the first sales line to the item journal line. This locks the corresponding reserveration entries that are being modified.
        // Therefore, using ReadUncommitted to calculate "Reserved Qty. on Inventory" will prevent unnecessary locking all the reservation entries for the item at a given location.
        Item.SetRange("Location Filter", SalesLine."Location Code");
        Item.SetRange("Variant Filter", SalesLine."Variant Code");
        Item.ReadIsolation := IsolationLevel::ReadUncommitted;
        Item.CalcFields("Reserved Qty. on Inventory");
        if Item."Reserved Qty. on Inventory" <= 0 then
            exit;

        Item.ReadIsolation := IsolationLevel::Default;
        Item.CalcFields("Net Change");
        SalesLine.CalcFields("Reserved Qty. (Base)");
        AvailableQty := Item."Net Change" - (Item."Reserved Qty. on Inventory" - SalesLine."Reserved Qty. (Base)");

        if (AvailableQty < SalesLine."Qty. to Ship (Base)") and
           (Item."Reserved Qty. on Inventory" > SalesLine."Reserved Qty. (Base)")
        then begin
            InsertTempSKU(SalesLine."Location Code", SalesLine."No.", SalesLine."Variant Code");
            if Location.BinMandatory(SalesLine."Location Code") then begin
                Session.LogMessage('0000GKN', ItemReservDisruptionLbl, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', SalesLinePostCategoryTok);
                if not ConfirmManagement.GetResponseOrDefault(
                 StrSubstNo(
                   ReservationDisruptedQst, SalesLine.FieldCaption("No."), Item."No.", SalesLine.FieldCaption("Location Code"),
                   SalesLine."Location Code", SalesLine.FieldCaption("Variant Code"), SalesLine."Variant Code"), true)
            then
                    Error('');
            end;
        end;
    end;

    local procedure InsertTempSKU(LocationCode: Code[10]; ItemNo: Code[20]; VariantCode: Code[10])
    begin
        TempSKU.Init();
        TempSKU."Location Code" := LocationCode;
        TempSKU."Item No." := ItemNo;
        TempSKU."Variant Code" := VariantCode;
        TempSKU.Insert();
    end;

    /// <summary>
    /// Initializes the progress window for posting with information about the sales header.
    /// </summary>
    /// <param name="SalesHeader">The sales header record for which the progress window is being initialized.</param>
    procedure InitProgressWindow(SalesHeader: Record "Sales Header")
    begin
        if SalesHeader.Invoice then
            Window.Open(
              '#1#################################\\' +
              PostingLinesMsg +
              PostingSalesAndVATMsg +
              PostingCustomersMsg +
              PostingBalAccountMsg)
        else
            Window.Open(
              '#1#################################\\' +
              PostingLines2Msg);

        Window.Update(1, StrSubstNo('%1 %2', SalesHeader."Document Type", SalesHeader."No."));
    end;

    local procedure CheckCertificateOfSupplyStatus(SalesShptHeader: Record "Sales Shipment Header"; SalesShptLine: Record "Sales Shipment Line")
    var
        CertificateOfSupply: Record "Certificate of Supply";
        VATPostingSetup: Record "VAT Posting Setup";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckCertificateOfSupplyStatus(SalesShptHeader, SalesShptLine, IsHandled);
        if IsHandled then
            exit;

        if SalesShptLine.Quantity <> 0 then
            if VATPostingSetup.Get(SalesShptHeader."VAT Bus. Posting Group", SalesShptLine."VAT Prod. Posting Group") and
               VATPostingSetup."Certificate of Supply Required"
            then begin
                CertificateOfSupply.InitFromSales(SalesShptHeader);
                CertificateOfSupply.SetRequired(SalesShptHeader."No.");
            end;
    end;

    local procedure InsertPostedHeaders(var SalesHeader: Record "Sales Header")
    var
        SalesShptLine: Record "Sales Shipment Line";
        PurchRcptLine: Record "Purch. Rcpt. Line";
        GenJnlLine: Record "Gen. Journal Line";
        PostingPreviewEventHandler: Codeunit "Posting Preview Event Handler";
        InsertShipmentHeaderNeeded: Boolean;
        ShouldInsertInvoiceHeader: Boolean;
        IsHandled: Boolean;
    begin
        if PreviewMode then
            PostingPreviewEventHandler.PreventCommit();

        OnBeforeInsertPostedHeaders(SalesHeader, TempWhseShptHeader, TempWhseRcptHeader);

        // Insert shipment header
        InsertShipmentHeaderNeeded := SalesHeader.Ship;
        OnInsertPostedHeadersOnAfterCalcInsertShipmentHeaderNeeded(SalesHeader, TempWhseShptHeader, TempWhseRcptHeader, InsertShipmentHeaderNeeded);
        if InsertShipmentHeaderNeeded then begin
            if (SalesHeader."Document Type" = SalesHeader."Document Type"::Order) or
                ((SalesHeader."Document Type" = SalesHeader."Document Type"::Invoice) and SalesSetup."Shipment on Invoice")
            then begin
                if DropShipOrder then begin
                    PurchRcptHeader.LockTable();
                    PurchRcptLine.LockTable();
                    SalesShptHeader.LockTable();
                    SalesShptLine.LockTable();
                end;
                InsertShipmentHeader(SalesHeader, SalesShptHeader);
            end;
            OnInsertPostedHeadersOnAfterInsertShipmentHeader(SalesHeader);
        end;

        IsHandled := false;
        OnInsertPostedHeadersOnBeforeDeleteServItemOnSaleCreditMemo(SalesHeader, SalesShptHeader, IsHandled);
        if not IsHandled then
            OnInsertPostedHeadersDeleteServItemOnSaleCreditMemo(SalesHeader);

        // Insert return receipt header
        CheckInsertReturnReceiptHeader(SalesHeader, ReturnRcptHeader);

        IsHandled := false;
        OnInsertPostedHeadersOnBeforeInsertInvoiceHeader(SalesHeader, IsHandled, SalesInvHeader, GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo, InvoicePostingInterface);
        if not IsHandled then
            // Insert invoice header or credit memo header
            if SalesHeader.Invoice then begin
                ShouldInsertInvoiceHeader := SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice];
                OnInsertPostedHeadersOnAfterCalcShouldInsertInvoiceHeader(SalesHeader, ShouldInsertInvoiceHeader);
                if ShouldInsertInvoiceHeader then begin
                    InsertInvoiceHeader(SalesHeader, SalesInvHeader);
                    GenJnlLineDocType := GenJnlLine."Document Type"::Invoice;
                    GenJnlLineDocNo := SalesInvHeader."No.";
                    GenJnlLineExtDocNo := SalesInvHeader."External Document No.";
                    OnInsertPostedHeadersOnAfterInsertInvoiceHeader(SalesHeader, SalesInvHeader);
                end else begin // Credit Memo
                    InsertCrMemoHeader(SalesHeader, SalesCrMemoHeader);
                    GenJnlLineDocType := GenJnlLine."Document Type"::"Credit Memo";
                    GenJnlLineDocNo := SalesCrMemoHeader."No.";
                    GenJnlLineExtDocNo := SalesCrMemoHeader."External Document No.";
                    OnInsertPostedHeadersOnAfterInsertCrMemoHeader(SalesHeader, SalesCrMemoHeader);
                end;
                GetInvoicePostingParameters();
                InvoicePostingInterface.SetParameters(InvoicePostingParameters);
            end;

        OnAfterInsertPostedHeaders(SalesHeader, SalesShptHeader, SalesInvHeader, SalesCrMemoHeader, ReturnRcptHeader, GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo);
    end;

    local procedure InsertShipmentHeader(var SalesHeader: Record "Sales Header"; var SalesShptHeader: Record "Sales Shipment Header")
    var
        SalesCommentLine: Record "Sales Comment Line";
        RecordLinkManagement: Codeunit "Record Link Management";
    begin
        SalesShptHeader.Init();
        SalesHeader.CalcFields("Work Description");
        OnInsertShipmentHeaderOnBeforeTransferfieldsToSalesShptHeader(SalesHeader);
        SalesShptHeader.TransferFields(SalesHeader);
        OnInsertShipmentHeaderOnAfterTransferfieldsToSalesShptHeader(SalesHeader, SalesShptHeader);

        AssignPostedDocumentNo(SalesShptHeader."No.", SalesHeader."Shipping No.");
        if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then begin
            SalesShptHeader."Order No. Series" := SalesHeader."No. Series";
            SalesShptHeader."Order No." := SalesHeader."No.";
            if SalesSetup."Ext. Doc. No. Mandatory" then
                SalesHeader.TestField("External Document No.");
        end;
        SalesShptHeader."Source Code" := SrcCode;
        SalesShptHeader."User ID" := CopyStr(UserId(), 1, MaxStrLen(SalesShptHeader."User ID"));
        SalesShptHeader."No. Printed" := 0;
        SalesShptHeaderInsert(SalesShptHeader, SalesHeader);

        ApprovalsMgmt.PostApprovalEntries(SalesHeader.RecordId, SalesShptHeader.RecordId, SalesShptHeader."No.");

        if SalesSetup."Copy Comments Order to Shpt." then begin
            SalesCommentLine.CopyComments(
              SalesHeader."Document Type".AsInteger(), SalesCommentLine."Document Type"::Shipment.AsInteger(), SalesHeader."No.", SalesShptHeader."No.");
            RecordLinkManagement.CopyLinks(SalesHeader, SalesShptHeader);
        end;
        if WhseShip then begin
            WhseShptHeader.Get(TempWhseShptHeader."No.");
            OnBeforeCreatePostedWhseShptHeader(PostedWhseShptHeader, WhseShptHeader, SalesHeader);
            WhsePostShpt.CreatePostedShptHeader(PostedWhseShptHeader, WhseShptHeader, SalesHeader."Shipping No.", SalesHeader."Posting Date");
        end;
        if WhseReceive then begin
            WhseRcptHeader.Get(TempWhseRcptHeader."No.");
            OnBeforeCreatePostedWhseRcptHeader(PostedWhseRcptHeader, WhseRcptHeader, SalesHeader);
            WhsePostRcpt.CreatePostedRcptHeader(PostedWhseRcptHeader, WhseRcptHeader, SalesHeader."Shipping No.", SalesHeader."Posting Date");
        end;

        OnAfterInsertShipmentHeader(SalesHeader, SalesShptHeader);
    end;

    local procedure CheckInsertReturnReceiptHeader(var SalesHeader: Record "Sales Header"; var ReturnRcptHeader: Record "Return Receipt Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckInsertReturnReceiptHeader(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        if SalesHeader.Receive then
            if (SalesHeader."Document Type" = SalesHeader."Document Type"::"Return Order") or
               ((SalesHeader."Document Type" = SalesHeader."Document Type"::"Credit Memo") and SalesSetup."Return Receipt on Credit Memo")
            then
                InsertReturnReceiptHeader(SalesHeader, ReturnRcptHeader);
    end;

    local procedure InsertReturnReceiptHeader(var SalesHeader: Record "Sales Header"; var ReturnRcptHeader: Record "Return Receipt Header")
    var
        SalesCommentLine: Record "Sales Comment Line";
        RecordLinkManagement: Codeunit "Record Link Management";
        IsHandled: Boolean;
    begin
        OnBeforeInsertReturnReceiptHeader(SalesHeader, ReturnRcptHeader, IsHandled, SuppressCommit);
        if not IsHandled then begin
            ReturnRcptHeader.Init();
            OnInsertReturnReceiptHeaderOnBeforeReturnReceiptHeaderTransferFields(SalesHeader);
            ReturnRcptHeader.TransferFields(SalesHeader);
            AssignPostedDocumentNo(ReturnRcptHeader."No.", SalesHeader."Return Receipt No.");
            if SalesHeader."Document Type" = SalesHeader."Document Type"::"Return Order" then begin
                ReturnRcptHeader."Return Order No. Series" := SalesHeader."No. Series";
                ReturnRcptHeader."Return Order No." := SalesHeader."No.";
                if SalesSetup."Ext. Doc. No. Mandatory" then
                    SalesHeader.TestField("External Document No.");
            end;
            ReturnRcptHeader."No. Series" := SalesHeader."Return Receipt No. Series";
            ReturnRcptHeader."Source Code" := SrcCode;
            ReturnRcptHeader."User ID" := CopyStr(UserId(), 1, MaxStrLen(ReturnRcptHeader."User ID"));
            ReturnRcptHeader."No. Printed" := 0;
            OnBeforeReturnRcptHeaderInsert(ReturnRcptHeader, SalesHeader, SuppressCommit, TempWhseRcptHeader, WhseReceive, TempWhseShptHeader, WhseShip);
            ReturnRcptHeader.Insert(true);
            OnAfterReturnRcptHeaderInsert(ReturnRcptHeader, SalesHeader, SuppressCommit, WhseShip, WhseReceive, TempWhseShptHeader, TempWhseRcptHeader);

            ApprovalsMgmt.PostApprovalEntries(SalesHeader.RecordId, ReturnRcptHeader.RecordId, ReturnRcptHeader."No.");

            if SalesSetup."Copy Cmts Ret.Ord. to Ret.Rcpt" then begin
                SalesCommentLine.CopyComments(
                  SalesHeader."Document Type".AsInteger(), SalesCommentLine."Document Type"::"Posted Return Receipt".AsInteger(), SalesHeader."No.", ReturnRcptHeader."No.");
                RecordLinkManagement.CopyLinks(SalesHeader, ReturnRcptHeader);
            end;
        end;

        if WhseReceive then begin
            WhseRcptHeader.Get(TempWhseRcptHeader."No.");
            OnBeforeCreatePostedWhseRcptHeader(PostedWhseRcptHeader, WhseRcptHeader, SalesHeader);
            WhsePostRcpt.CreatePostedRcptHeader(PostedWhseRcptHeader, WhseRcptHeader, SalesHeader."Return Receipt No.", SalesHeader."Posting Date");
        end;
        if WhseShip then begin
            WhseShptHeader.Get(TempWhseShptHeader."No.");
            OnBeforeCreatePostedWhseShptHeader(PostedWhseShptHeader, WhseShptHeader, SalesHeader);
            WhsePostShpt.CreatePostedShptHeader(PostedWhseShptHeader, WhseShptHeader, SalesHeader."Return Receipt No.", SalesHeader."Posting Date");
        end;

        OnAfterInsertReturnReceiptHeader(SalesHeader, ReturnRcptHeader);
    end;

    local procedure InsertInvoiceHeader(var SalesHeader: Record "Sales Header"; var SalesInvHeader: Record "Sales Invoice Header")
    var
        SalesCommentLine: Record "Sales Comment Line";
        RecordLinkManagement: Codeunit "Record Link Management";
        SegManagement: Codeunit SegManagement;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertInvoiceHeader(SalesHeader, SalesInvHeader, IsHandled);
        if IsHandled then
            exit;

        SalesInvHeader.Init();
        SalesHeader.CalcFields("Work Description");
        OnInsertInvoiceHeaderOnBeforeSalesInvHeaderTransferFields(SalesHeader);
        SalesInvHeader.TransferFields(SalesHeader);
        OnInsertInvoiceHeaderOnAfterSalesInvHeaderTransferFields(SalesHeader, SalesInvHeader);

        AssignPostedDocumentNo(SalesInvHeader."No.", SalesHeader."Posting No.");

        IsHandled := false;
        OnInsertInvoiceHeaderOnBeforeCheckDocumentType(SalesHeader, SalesInvHeader, SalesSetup, IsHandled);
        if not IsHandled then
            if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then begin
                if SalesSetup."Ext. Doc. No. Mandatory" then
                    SalesHeader.TestField("External Document No.");
                SalesInvHeader."Pre-Assigned No. Series" := '';
                SalesInvHeader."Order No. Series" := SalesHeader."No. Series";
                SalesInvHeader."Order No." := SalesHeader."No.";
            end else begin
                if SalesHeader."Posting No." = '' then
                    AssignPostedDocumentNo(SalesInvHeader."No.", SalesHeader."No.");
                SalesInvHeader."Pre-Assigned No. Series" := SalesHeader."No. Series";
                SalesInvHeader."Pre-Assigned No." := SalesHeader."No.";
            end;

        if GuiAllowed() and not HideProgressWindow then
            Window.Update(1, StrSubstNo(InvoiceNoMsg, SalesHeader."Document Type", SalesHeader."No.", SalesInvHeader."No."));
        SalesInvHeader."Source Code" := SrcCode;
        SalesInvHeader."User ID" := CopyStr(UserId(), 1, MaxStrLen(SalesInvHeader."User ID"));
        SalesInvHeader."No. Printed" := 0;

        if SalesHeader."Document Type" = SalesHeader."Document Type"::Invoice then
            SalesInvHeader."Draft Invoice SystemId" := SalesHeader.SystemId;

        SalesInvHeaderInsert(SalesInvHeader, SalesHeader);

        UpdateWonOpportunities(SalesHeader);
        SegManagement.CreateCampaignEntryOnSalesInvoicePosting(SalesInvHeader);

        ApprovalsMgmt.PostApprovalEntries(SalesHeader.RecordId, SalesInvHeader.RecordId, SalesInvHeader."No.");

        if SalesSetup."Copy Comments Order to Invoice" then begin
            SalesCommentLine.CopyComments(
              SalesHeader."Document Type".AsInteger(), SalesCommentLine."Document Type"::"Posted Invoice".AsInteger(), SalesHeader."No.", SalesInvHeader."No.");
            RecordLinkManagement.CopyLinks(SalesHeader, SalesInvHeader);
        end;

        OnAfterInsertInvoiceHeader(SalesHeader, SalesInvHeader);
    end;

    local procedure InsertCrMemoHeader(var SalesHeader: Record "Sales Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    var
        SalesCommentLine: Record "Sales Comment Line";
        RecordLinkManagement: Codeunit "Record Link Management";
        ShouldProcessAsReturnOrder: Boolean;
    begin
        SalesCrMemoHeader.Init();
        SalesHeader.CalcFields("Work Description");
        OnInsertCrMemoHeaderOnBeforeSalesCrMemoHeaderTransferFields(SalesHeader);
        SalesCrMemoHeader.TransferFields(SalesHeader);
        AssignPostedDocumentNo(SalesCrMemoHeader."No.", SalesHeader."No.");
        OnInsertCrMemoHeaderOnAfterSalesCrMemoHeaderTransferFields(SalesHeader, SalesCrMemoHeader);

        ShouldProcessAsReturnOrder := SalesHeader."Document Type" = SalesHeader."Document Type"::"Return Order";
        OnInsertCrMemoHeaderOnAfterCalcShouldProcessAsReturnOrder(SalesHeader, ShouldProcessAsReturnOrder);
        if ShouldProcessAsReturnOrder then begin
            AssignPostedDocumentNo(SalesCrMemoHeader."No.", SalesHeader."Posting No.");
            if SalesSetup."Ext. Doc. No. Mandatory" then
                SalesHeader.TestField("External Document No.");
            SalesCrMemoHeader."Pre-Assigned No. Series" := '';
            SalesCrMemoHeader."Return Order No. Series" := SalesHeader."No. Series";
            SalesCrMemoHeader."Return Order No." := SalesHeader."No.";
            if GuiAllowed() and not HideProgressWindow then
                Window.Update(1, StrSubstNo(CreditMemoNoMsg, SalesHeader."Document Type", SalesHeader."No.", SalesCrMemoHeader."No."));
        end else begin
            SalesCrMemoHeader."Pre-Assigned No. Series" := SalesHeader."No. Series";
            SalesCrMemoHeader."Pre-Assigned No." := SalesHeader."No.";
            if SalesHeader."Posting No." <> '' then begin
                AssignPostedDocumentNo(SalesCrMemoHeader."No.", SalesHeader."Posting No.");
                if GuiAllowed() and not HideProgressWindow then
                    Window.Update(1, StrSubstNo(CreditMemoNoMsg, SalesHeader."Document Type", SalesHeader."No.", SalesCrMemoHeader."No."));
            end;
        end;
        SalesCrMemoHeader."Source Code" := SrcCode;
        SalesCrMemoHeader."User ID" := CopyStr(UserId(), 1, MaxStrLen(SalesCrMemoHeader."User ID"));
        SalesCrMemoHeader."No. Printed" := 0;
        SalesCrMemoHeader."Draft Cr. Memo SystemId" := SalesCrMemoHeader.SystemId;
        SalesCrMemoHeaderInsert(SalesCrMemoHeader, SalesHeader);

        ApprovalsMgmt.PostApprovalEntries(SalesHeader.RecordId, SalesCrMemoHeader.RecordId, SalesCrMemoHeader."No.");

        if SalesSetup."Copy Cmts Ret.Ord. to Cr. Memo" then begin
            SalesCommentLine.CopyComments(
              SalesHeader."Document Type".AsInteger(), SalesCommentLine."Document Type"::"Posted Credit Memo".AsInteger(), SalesHeader."No.", SalesCrMemoHeader."No.");
            RecordLinkManagement.CopyLinks(SalesHeader, SalesCrMemoHeader);
        end;

        OnAfterInsertCrMemoHeader(SalesHeader, SalesCrMemoHeader);
    end;

    local procedure InsertPurchRcptHeader(var PurchaseHeader: Record "Purchase Header"; var SalesHeader: Record "Sales Header"; var PurchRcptHeader: Record "Purch. Rcpt. Header")
    var
        RunOnInsert: Boolean;
    begin
        PurchRcptHeader.Init();
        PurchRcptHeader.TransferFields(PurchaseHeader);
        AssignPostedDocumentNo(PurchRcptHeader."No.", PurchaseHeader."Receiving No.");
        PurchRcptHeader."Order No." := PurchaseHeader."No.";
        PurchRcptHeader."Posting Date" := SalesHeader."Posting Date";
        PurchRcptHeader."Document Date" := SalesHeader."Document Date";
        PurchRcptHeader."No. Printed" := 0;
        RunOnInsert := false;
        OnBeforePurchRcptHeaderInsert(PurchRcptHeader, PurchaseHeader, SalesHeader, SuppressCommit, RunOnInsert);
        PurchRcptHeader.Insert(RunOnInsert);
        OnAfterPurchRcptHeaderInsert(PurchRcptHeader, PurchaseHeader, SalesHeader, SuppressCommit);
    end;

    local procedure InsertPurchRcptLine(PurchRcptHeader: Record "Purch. Rcpt. Header"; PurchOrderLine: Record "Purchase Line"; DropShptPostBuffer: Record "Drop Shpt. Post. Buffer")
    var
        PurchRcptLine: Record "Purch. Rcpt. Line";
    begin
        PurchRcptLine.Init();
        PurchRcptLine.TransferFields(PurchOrderLine);
        PurchRcptLine."Posting Date" := PurchRcptHeader."Posting Date";
        PurchRcptLine."Document No." := PurchRcptHeader."No.";
        PurchRcptLine.Quantity := DropShptPostBuffer.Quantity;
        PurchRcptLine."Quantity (Base)" := DropShptPostBuffer."Quantity (Base)";
        PurchRcptLine."Quantity Invoiced" := 0;
        PurchRcptLine."Qty. Invoiced (Base)" := 0;
        PurchRcptLine."Order No." := PurchOrderLine."Document No.";
        PurchRcptLine."Order Line No." := PurchOrderLine."Line No.";
        PurchRcptLine."Qty. Rcd. Not Invoiced" := PurchRcptLine.Quantity - PurchRcptLine."Quantity Invoiced";
        if PurchRcptLine.Quantity <> 0 then begin
            PurchRcptLine."Item Rcpt. Entry No." := DropShptPostBuffer."Item Shpt. Entry No.";
            PurchRcptLine."Item Charge Base Amount" := PurchOrderLine."Line Amount"
        end;
        PurchRcptLineInsert(PurchRcptLine, PurchRcptHeader, PurchOrderLine, DropShptPostBuffer);
    end;

    local procedure PurchRcptLineInsert(var PurchRcptLine: Record "Purch. Rcpt. Line"; PurchRcptHeader: Record "Purch. Rcpt. Header"; PurchOrderLine: Record "Purchase Line"; DropShptPostBuffer: Record "Drop Shpt. Post. Buffer")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePurchRcptLineInsert(PurchRcptLine, PurchRcptHeader, PurchOrderLine, DropShptPostBuffer, SuppressCommit, TempSalesLineGlobal, IsHandled);
        if IsHandled then
            exit;

        PurchRcptLine.Insert();
        OnAfterPurchRcptLineInsert(PurchRcptLine, PurchRcptHeader, PurchOrderLine, DropShptPostBuffer, SuppressCommit, TempSalesLineGlobal);
    end;

    local procedure InsertShipmentLine(var SalesHeader: Record "Sales Header"; SalesShptHeader: Record "Sales Shipment Header"; SalesLine: Record "Sales Line"; CostBaseAmount: Decimal)
    var
        SalesShptLine: Record "Sales Shipment Line";
        IsHandled: Boolean;
        ShouldProcessShipmentRelation: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertShipmentLine(SalesHeader, SalesLine, IsHandled);
        if IsHandled then
            exit;

        SalesShptLine.InitFromSalesLine(SalesShptHeader, xSalesLine);
        SalesShptLine."Quantity Invoiced" := -RemQtyToBeInvoiced;
        SalesShptLine."Qty. Invoiced (Base)" := -RemQtyToBeInvoicedBase;
        SalesShptLine."Qty. Shipped Not Invoiced" := SalesShptLine.Quantity - SalesShptLine."Quantity Invoiced";
        OnInsertShipmentLineOnAfterInitQuantityFields(SalesLine, xSalesLine, SalesShptLine);
        ShouldProcessShipmentRelation := (SalesLine.Type = SalesLine.Type::Item) and (SalesLine."Qty. to Ship" <> 0);
        OnInsertShipmentLineOnAfterCalcShouldProcessShipmentRelation(SalesLine, ShouldProcessShipmentRelation);
        if ShouldProcessShipmentRelation then begin
            CheckPostWhseShptLines(SalesShptLine, SalesLine);

            CheckPostWhseRcptLineFromShipmentLine(SalesLine, SalesShptLine);

            SalesShptLine."Item Shpt. Entry No." :=
              InsertShptEntryRelation(SalesHeader, SalesShptLine); // ItemLedgShptEntryNo
            SalesShptLine."Item Charge Base Amount" :=
              Round(CostBaseAmount / SalesLine.Quantity * SalesShptLine.Quantity);
        end;
        SalesShptLineInsert(SalesShptLine, SalesShptHeader, SalesLine, SalesHeader);

        CheckCertificateOfSupplyStatus(SalesShptHeader, SalesShptLine);

        OnInvoiceSalesShptLine(SalesShptLine, SalesInvHeader."No.", xSalesLine."Line No.", xSalesLine."Qty. to Invoice", SuppressCommit);

        OnAfterInsertShipmentLine(SalesHeader, SalesLine, SalesShptLine, PreviewMode, xSalesLine);
    end;

    local procedure CheckPostWhseRcptLineFromShipmentLine(var SalesLine: Record "Sales Line"; var SalesShptLine: Record "Sales Shipment Line")
    var
        WhseRcptLine: Record "Warehouse Receipt Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckPostWhseRcptLineFromShipmentLine(SalesShptLine, SalesLine, IsHandled);
        if IsHandled then
            exit;

        if WhseReceive then
            if WhseRcptLine.GetWhseRcptLine(
                 WhseRcptHeader."No.", DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.")
            then
                PostWhseRcptLineFromShipmentLine(WhseRcptLine, SalesLine, SalesShptLine);
    end;

    local procedure PostWhseRcptLineFromShipmentLine(var WhseRcptLine: Record "Warehouse Receipt Line"; var SalesLine: Record "Sales Line"; var SalesShptLine: Record "Sales Shipment Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostWhseRcptLineFromShipmentLine(WhseRcptLine, SalesShptLine, SalesLine, IsHandled, PostedWhseRcptHeader);
        if IsHandled then
            exit;

        WhseRcptLine.TestField("Qty. to Receive", -SalesShptLine.Quantity);
        SaveTempWhseSplitSpec(SalesLine, TempHandlingSpecification);
        WhsePostRcpt.CreatePostedRcptLine(
          WhseRcptLine, PostedWhseRcptHeader, PostedWhseRcptLine, TempWhseSplitSpecification);
    end;

    local procedure InsertReturnReceiptLine(ReturnRcptHeader: Record "Return Receipt Header"; SalesLine: Record "Sales Line"; CostBaseAmount: Decimal; var SalesHeader: Record "Sales Header")
    var
        ReturnRcptLine: Record "Return Receipt Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertReturnReceiptLine(SalesLine, ReturnRcptLine, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase, IsHandled);
        if not IsHandled then begin
            ReturnRcptLine.InitFromSalesLine(ReturnRcptHeader, xSalesLine);
            ReturnRcptLine."Quantity Invoiced" := RemQtyToBeInvoiced;
            ReturnRcptLine."Qty. Invoiced (Base)" := RemQtyToBeInvoicedBase;
            ReturnRcptLine."Return Qty. Rcd. Not Invd." := ReturnRcptLine.Quantity - ReturnRcptLine."Quantity Invoiced";

            InsertReturnReceiptLineWhsePost(SalesLine, ReturnRcptHeader, ReturnRcptLine, CostBaseAmount);

            OnBeforeReturnRcptLineInsert(ReturnRcptLine, ReturnRcptHeader, SalesLine, SuppressCommit, xSalesLine, TempSalesLineGlobal, SalesHeader);
            ReturnRcptLine.Insert(true);
        end;

        OnAfterReturnRcptLineInsert(
          ReturnRcptLine, ReturnRcptHeader, SalesLine, ItemLedgShptEntryNo, WhseShip, WhseReceive, SuppressCommit, SalesCrMemoHeader, TempWhseShptHeader, TempWhseRcptHeader, SalesHeader);
    end;

    local procedure InsertReturnReceiptLineWhsePost(var SalesLine: Record "Sales Line"; ReturnRcptHeader: Record "Return Receipt Header"; var ReturnRcptLine: Record "Return Receipt Line"; CostBaseAmount: Decimal)
    var
        WhseShptLine: Record "Warehouse Shipment Line";
        WhseRcptLine: Record "Warehouse Receipt Line";
        ShouldGetWhseRcptLine: Boolean;
        ShouldGetWhseShptLine: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertReturnReceiptLineWhsePost(SalesLine, ReturnRcptHeader, WhseShip, WhseReceive, TempWhseRcptHeader, IsHandled,
            ReturnRcptLine, xSalesLine, PostedWhseRcptHeader, WhseRcptHeader, CostBaseAmount);
        if IsHandled then
            exit;

        if (SalesLine.Type = SalesLine.Type::Item) and (SalesLine."Return Qty. to Receive" <> 0) then begin
            ShouldGetWhseRcptLine := WhseReceive and SalesLine.IsInventoriableItem();
            OnInsertReturnReceiptLineWhsePostOnAfterCalcShouldGetWhseRcptLine(ReturnRcptLine, SalesLine, WhseShip, WhseReceive, ReturnRcptHeader, ShouldGetWhseRcptLine);
            if ShouldGetWhseRcptLine then
                if WhseRcptLine.GetWhseRcptLine(
                     WhseRcptHeader."No.", DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.")
                then begin
                    WhseRcptLine.TestField("Qty. to Receive", ReturnRcptLine.Quantity);
                    SaveTempWhseSplitSpec(SalesLine, TempHandlingSpecification);
                    OnInsertReturnReceiptLineOnBeforeCreatePostedRcptLine(SalesLine, ReturnRcptLine, WhseRcptLine, PostedWhseRcptHeader);
                    WhsePostRcpt.CreatePostedRcptLine(
                      WhseRcptLine, PostedWhseRcptHeader, PostedWhseRcptLine, TempWhseSplitSpecification);
                end;

            ShouldGetWhseShptLine := WhseShip and SalesLine.IsInventoriableItem();
            OnInsertReturnReceiptLineWhsePostOnAfterCalcShouldGetWhseShptLine(ReturnRcptLine, SalesLine, WhseShip, WhseReceive, ReturnRcptHeader, ShouldGetWhseShptLine);
            if ShouldGetWhseShptLine then
                if WhseShptLine.GetWhseShptLine(
                     WhseShptHeader."No.", DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.")
                then begin
                    WhseShptLine.TestField("Qty. to Ship", -ReturnRcptLine.Quantity);
                    SaveTempWhseSplitSpec(SalesLine, TempHandlingSpecification);
                    WhsePostShpt.SetWhseJnlRegisterCU(WhseJnlPostLine);
                    OnInsertReturnReceiptLineWhsePostOnBeforeCreatePostedShptLine(ReturnRcptLine, WhseShptLine, PostedWhseShptHeader);
                    WhsePostShpt.CreatePostedShptLine(
                      WhseShptLine, PostedWhseShptHeader, PostedWhseShptLine, TempWhseSplitSpecification);
                end;

            ReturnRcptLine."Item Rcpt. Entry No." :=
              InsertReturnEntryRelation(ReturnRcptLine); // ItemLedgShptEntryNo;
            ReturnRcptLine."Item Charge Base Amount" :=
              Round(CostBaseAmount / SalesLine.Quantity * ReturnRcptLine.Quantity);
        end;

        OnAfterInsertReturnReceiptLineWhsePost(SalesLine, xSalesLine, ReturnRcptLine);
    end;

    local procedure CheckICPartnerBlocked(SalesHeader: Record "Sales Header")
    var
        ICPartner: Record "IC Partner";
    begin
        if SalesHeader."Sell-to IC Partner Code" <> '' then
            if ICPartner.Get(SalesHeader."Sell-to IC Partner Code") then
                ICPartner.TestField(Blocked, false);
        if SalesHeader."Bill-to IC Partner Code" <> '' then
            if ICPartner.Get(SalesHeader."Bill-to IC Partner Code") then
                ICPartner.TestField(Blocked, false);
    end;

    local procedure SendICDocument(var SalesHeader: Record "Sales Header")
    var
        ICInboxOutboxMgt: Codeunit ICInboxOutboxMgt;
        IsHandled: Boolean;
        ModifyHeader: Boolean;
    begin
        IsHandled := false;
        OnBeforeSendICDocument(SalesHeader, ModifyHeader, IsHandled);
        if IsHandled then
            exit;

        if SalesHeader."Send IC Document" and (SalesHeader."IC Status" = SalesHeader."IC Status"::New) and (SalesHeader."IC Direction" = SalesHeader."IC Direction"::Outgoing) and
            (SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::"Return Order"])
        then begin
            SalesHeader.Modify();
            ICInboxOutboxMgt.SendSalesDoc(SalesHeader, true);
            SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
            IsHandled := false;
            OnSendICDocumentOnBeforeSetICStatus(SalesHeader, IsHandled);
            if not IsHandled then
                SalesHeader."IC Status" := SalesHeader."IC Status"::Pending;
            ModifyHeader := true;
        end;
    end;

    local procedure UpdateHandledICInboxTransaction(SalesHeader: Record "Sales Header")
    var
        HandledICInboxTrans: Record "Handled IC Inbox Trans.";
        Customer: Record Customer;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateHandledICInboxTransaction(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        if SalesHeader."IC Direction" = SalesHeader."IC Direction"::Incoming then begin
            HandledICInboxTrans.SetRange("Document No.", SalesHeader."IC Reference Document No.");
            Customer.Get(SalesHeader."Sell-to Customer No.");
            HandledICInboxTrans.SetRange("IC Partner Code", Customer."IC Partner Code");
            HandledICInboxTrans.LockTable();
            if HandledICInboxTrans.FindFirst() then begin
                HandledICInboxTrans.Status := HandledICInboxTrans.Status::Posted;
                HandledICInboxTrans.Modify();
            end;
        end;
    end;

    local procedure RunItemJnlPostLine(var ItemJnlLineToPost: Record "Item Journal Line")
    begin
        ItemJnlPostLine.RunWithCheck(ItemJnlLineToPost);
    end;

    /// <summary>
    /// Gets the posted document that was created from the specified sales header.
    /// </summary>
    /// <remarks>
    /// Orders and Return Orders return Invoice or Credit Memo. If the Invoice or Credit Memo was not posted, the function does not return a value.
    /// </remarks>
    /// <param name="SalesHeader">The sales header for which to get the posted document.</param>
    /// <param name="PostedSalesDocumentVariant">Return Variable: The posted document that was created from the specified sales header.</param>
    procedure GetPostedDocumentRecord(SalesHeader: Record "Sales Header"; var PostedSalesDocumentVariant: Variant)
    var
        SalesShipmentHeader: Record "Sales Shipment Header";
        SalesInvHeader: Record "Sales Invoice Header";
        SalesCrMemoHeader: Record "Sales Cr.Memo Header";
        ReturnReceiptHeader: Record "Return Receipt Header";
        IsHandled: Boolean;
    begin
        case SalesHeader."Document Type" of
            SalesHeader."Document Type"::Order:
                begin
                    if (not SalesHeader.Invoice) and (SalesHeader.Ship) then begin
                        SalesShipmentHeader.Get(SalesHeader."Last Shipping No.");
                        SalesShipmentHeader.SetRecFilter();
                        PostedSalesDocumentVariant := SalesShipmentHeader;
                    end;

                    if SalesHeader.Invoice then begin
                        SalesInvHeader.Get(SalesHeader."Last Posting No.");
                        SalesInvHeader.SetRecFilter();
                        PostedSalesDocumentVariant := SalesInvHeader;
                    end;
                end;
            SalesHeader."Document Type"::Invoice:
                begin
                    if SalesHeader."Last Posting No." = '' then
                        SalesInvHeader.Get(SalesHeader."No.")
                    else
                        SalesInvHeader.Get(SalesHeader."Last Posting No.");

                    SalesInvHeader.SetRecFilter();
                    PostedSalesDocumentVariant := SalesInvHeader;
                end;
            SalesHeader."Document Type"::"Credit Memo":
                begin
                    if SalesHeader."Last Posting No." = '' then
                        SalesCrMemoHeader.Get(SalesHeader."No.")
                    else
                        SalesCrMemoHeader.Get(SalesHeader."Last Posting No.");
                    SalesCrMemoHeader.SetRecFilter();
                    PostedSalesDocumentVariant := SalesCrMemoHeader;
                end;
            SalesHeader."Document Type"::"Return Order":
                begin
                    if (not SalesHeader.Invoice) and (SalesHeader.Receive) then begin
                        ReturnReceiptHeader.Get(SalesHeader."Last Return Receipt No.");
                        ReturnReceiptHeader.SetRecFilter();
                        PostedSalesDocumentVariant := ReturnReceiptHeader;
                    end;

                    if SalesHeader.Invoice then begin
                        if SalesHeader."Last Posting No." = '' then
                            SalesCrMemoHeader.Get(SalesHeader."No.")
                        else
                            SalesCrMemoHeader.Get(SalesHeader."Last Posting No.");
                        SalesCrMemoHeader.SetRecFilter();
                        PostedSalesDocumentVariant := SalesCrMemoHeader;
                    end;
                end;
            else begin
                IsHandled := false;
                OnGetPostedDocumentRecordElseCase(SalesHeader, PostedSalesDocumentVariant, IsHandled);
                if not IsHandled then
                    Error(NotSupportedDocumentTypeErr, SalesHeader."Document Type");
            end;
        end;
    end;

    /// <summary>
    /// Sends the posted document(s) that were created during posting to the specified Document Sending Profile.
    /// </summary>
    /// <remarks>
    /// Send function in Document Sending Profile commits the transaction after it successfully sends the document.
    /// </remarks>
    /// <param name="SalesHeader">The sales header for which to find the documents to send.</param>
    /// <param name="DocumentSendingProfile">The Document Sending Profile to use for sending the documents.</param>
    procedure SendPostedDocumentRecord(SalesHeader: Record "Sales Header"; var DocumentSendingProfile: Record "Document Sending Profile")
    var
        SalesInvHeader: Record "Sales Invoice Header";
        SalesCrMemoHeader: Record "Sales Cr.Memo Header";
        SalesShipmentHeader: Record "Sales Shipment Header";
        OfficeManagement: Codeunit "Office Management";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSendPostedDocumentRecord(SalesHeader, IsHandled, DocumentSendingProfile);
        if IsHandled then
            exit;

        case SalesHeader."Document Type" of
            SalesHeader."Document Type"::Order:
                begin
                    OnSendSalesDocument(SalesHeader.Invoice and SalesHeader.Ship, SuppressCommit);
                    if SalesHeader.Invoice then begin
                        SalesInvHeader.Get(SalesHeader."Last Posting No.");
                        SalesInvHeader.SetRecFilter();
                        SalesInvHeader.SendProfile(DocumentSendingProfile);
                    end;
                    if SalesHeader.Ship and SalesHeader.Invoice and not OfficeManagement.IsAvailable() then
                        if not ConfirmDownloadShipment(SalesHeader) then
                            exit;
                    if SalesHeader.Ship then begin
                        SalesShipmentHeader.Get(SalesHeader."Last Shipping No.");
                        SalesShipmentHeader.SetRecFilter();
                        SalesShipmentHeader.SendProfile(DocumentSendingProfile);
                    end;
                end;
            SalesHeader."Document Type"::Invoice:
                begin
                    if SalesHeader."Last Posting No." = '' then
                        SalesInvHeader.Get(SalesHeader."No.")
                    else
                        SalesInvHeader.Get(SalesHeader."Last Posting No.");

                    SalesInvHeader.SetRecFilter();
                    SalesInvHeader.SendProfile(DocumentSendingProfile);
                end;
            SalesHeader."Document Type"::"Credit Memo":
                begin
                    if SalesHeader."Last Posting No." = '' then
                        SalesCrMemoHeader.Get(SalesHeader."No.")
                    else
                        SalesCrMemoHeader.Get(SalesHeader."Last Posting No.");
                    SalesCrMemoHeader.SetRecFilter();
                    SalesCrMemoHeader.SendProfile(DocumentSendingProfile);
                end;
            SalesHeader."Document Type"::"Return Order":
                if SalesHeader.Invoice then begin
                    if SalesHeader."Last Posting No." = '' then
                        SalesCrMemoHeader.Get(SalesHeader."No.")
                    else
                        SalesCrMemoHeader.Get(SalesHeader."Last Posting No.");
                    SalesCrMemoHeader.SetRecFilter();
                    SalesCrMemoHeader.SendProfile(DocumentSendingProfile);
                end;
            else begin
                IsHandled := false;
                OnSendPostedDocumentRecordElseCase(SalesHeader, DocumentSendingProfile, IsHandled);
                if not IsHandled then
                    Error(NotSupportedDocumentTypeErr, SalesHeader."Document Type");
            end;
        end;
    end;

    local procedure ConfirmDownloadShipment(SalesHeader: Record "Sales Header") Result: Boolean
    var
        ConfirmManagement: Codeunit "Confirm Management";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeConfirmDownloadShipment(SalesHeader, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if ConfirmManagement.GetResponseOrDefault(SendShipmentAlsoQst, true) then
            exit(true);

        exit(false);
    end;

    local procedure MakeInventoryAdjustment()
    var
        InvtSetup: Record "Inventory Setup";
        InvtAdjmtHandler: Codeunit "Inventory Adjustment Handler";
        IsHandled: Boolean;
    begin
        InvtSetup.Get();
        if InvtSetup.AutomaticCostAdjmtRequired() then begin
            IsHandled := false;
            OnBeforeMakeInventoryAdjustment(InvtSetup, InvtAdjmtHandler, IsHandled);
            if not IsHandled then
                InvtAdjmtHandler.MakeAutomaticInventoryAdjustment(ItemsToAdjust);
        end;
    end;

    local procedure FindNotShippedLines(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeFindNotShippedLines(SalesHeader, TempSalesLine, IsHandled);
        if IsHandled then
            exit;

        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter(Quantity, '<>0');
        if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then
            TempSalesLine.SetFilter("Qty. to Ship", '<>0');
        TempSalesLine.SetRange("Shipment No.", '');
        OnAfterFindNotShippedLines(SalesHeader, TempSalesLine);
    end;

    local procedure CheckTrackingAndWarehouseForShip(SalesHeader: Record "Sales Header") Ship: Boolean
    var
        TempSalesLine: Record "Sales Line" temporary;
    begin
        FindNotShippedLines(SalesHeader, TempSalesLine);
        Ship := TempSalesLine.FindFirst();
        WhseShip := TempWhseShptHeader.FindFirst();
        WhseReceive := TempWhseRcptHeader.FindFirst();
        OnCheckTrackingAndWarehouseForShipOnBeforeCheck(SalesHeader, TempWhseShptHeader, TempWhseRcptHeader, Ship, TempSalesLine);
        if Ship then begin
            CheckTrackingSpecification(SalesHeader, TempSalesLine);
            if not (WhseShip or WhseReceive or InvtPickPutaway) then
                CheckWarehouse(TempSalesLine);
        end;
        OnAfterCheckTrackingAndWarehouseForShip(SalesHeader, Ship, SuppressCommit, TempWhseShptHeader, TempWhseRcptHeader, TempSalesLine);
        exit(Ship);
    end;

    local procedure CheckTrackingAndWarehouseForReceive(SalesHeader: Record "Sales Header") Receive: Boolean
    var
        TempSalesLine: Record "Sales Line" temporary;
    begin
        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter(Quantity, '<>0');
        TempSalesLine.SetFilter("Return Qty. to Receive", '<>0');
        TempSalesLine.SetRange("Return Receipt No.", '');
        OnCheckTrackingAndWarehouseForReceiveOnAfterSetFilters(SalesHeader, TempSalesLine);
        Receive := TempSalesLine.FindFirst();
        WhseShip := TempWhseShptHeader.FindFirst();
        WhseReceive := TempWhseRcptHeader.FindFirst();
        OnCheckTrackingAndWarehouseForReceiveOnBeforeCheck(SalesHeader, TempWhseShptHeader, TempWhseRcptHeader, Receive);
        if Receive then begin
            CheckTrackingSpecification(SalesHeader, TempSalesLine);
            if not (WhseReceive or WhseShip or InvtPickPutaway) then
                CheckWarehouse(TempSalesLine);
        end;
        OnAfterCheckTrackingAndWarehouseForReceive(SalesHeader, Receive, SuppressCommit, TempWhseShptHeader, TempWhseRcptHeader, TempSalesLine);
        exit(Receive);
    end;

    local procedure CheckIfInvPickExists(SalesHeader: Record "Sales Header"): Boolean
    var
        TempSalesLine: Record "Sales Line" temporary;
        WarehouseActivityLine: Record "Warehouse Activity Line";
    begin
        FindNotShippedLines(SalesHeader, TempSalesLine);
        if TempSalesLine.IsEmpty() then
            exit(false);
        TempSalesLine.FindSet();
        repeat
            if WarehouseActivityLine.ActivityExists(
                    DATABASE::"Sales Line", TempSalesLine."Document Type".AsInteger(), TempSalesLine."Document No.", TempSalesLine."Line No.", 0,
                    WarehouseActivityLine."Activity Type"::"Invt. Pick".AsInteger())
            then
                exit(true);
        until TempSalesLine.Next() = 0;
        exit(false);
    end;

    local procedure CheckIfInvPutawayExists(): Boolean
    var
        TempSalesLine: Record "Sales Line" temporary;
        WarehouseActivityLine: Record "Warehouse Activity Line";
    begin
        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter(Quantity, '<>0');
        TempSalesLine.SetFilter("Return Qty. to Receive", '<>0');
        TempSalesLine.SetRange("Return Receipt No.", '');
        if TempSalesLine.IsEmpty() then
            exit(false);
        TempSalesLine.FindSet();
        repeat
            if WarehouseActivityLine.ActivityExists(
                    DATABASE::"Sales Line", TempSalesLine."Document Type".AsInteger(), TempSalesLine."Document No.", TempSalesLine."Line No.", 0,
                    WarehouseActivityLine."Activity Type"::"Invt. Put-away".AsInteger())
            then
                exit(true);
        until TempSalesLine.Next() = 0;
        exit(false);
    end;

    local procedure FindTempItemChargeAssgntSales(SalesLineNo: Integer): Boolean
    begin
        ClearItemChargeAssgntFilter();
        TempItemChargeAssgntSales.SetCurrentKey("Applies-to Doc. Type");
        TempItemChargeAssgntSales.SetRange("Document Line No.", SalesLineNo);
        exit(TempItemChargeAssgntSales.FindSet());
    end;

    local procedure UpdateInvoicedQtyOnShipmentLine(var SalesShptLine: Record "Sales Shipment Line"; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal)
    begin
        OnBeforeUpdateInvoicedQtyOnShipmentLineProcedure(SalesShptLine, QtyToBeInvoiced, QtyToBeInvoicedBase);
        SalesShptLine."Quantity Invoiced" := SalesShptLine."Quantity Invoiced" - QtyToBeInvoiced;
        SalesShptLine."Qty. Invoiced (Base)" := SalesShptLine."Qty. Invoiced (Base)" - QtyToBeInvoicedBase;
        SalesShptLine."Qty. Shipped Not Invoiced" := SalesShptLine.Quantity - SalesShptLine."Quantity Invoiced";
        OnUpdateInvoicedQtyOnShipmentLineOnBeforeModifySalesShptLine(SalesShptLine, QtyToBeInvoiced, QtyToBeInvoicedBase);
        SalesShptLine.Modify();
    end;

    /// <summary>
    /// Sets the CalledBy global variable.
    /// </summary>
    /// <param name="NewCalledBy"></param>
    procedure SetCalledBy(NewCalledBy: Integer)
    begin
        CalledBy := NewCalledBy;
    end;

    /// <summary>
    /// Sets the Preview Mode for the current instance of the codeunit.
    /// Preview Mode ensures no transactions are commited to the database and no documents are sent.
    /// </summary>
    /// <param name="NewPreviewMode">The new value for the Preview Mode.</param>
    procedure SetPreviewMode(NewPreviewMode: Boolean)
    begin
        PreviewMode := NewPreviewMode;
    end;

    local procedure PostDropOrderShipment(var SalesHeader: Record "Sales Header"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    var
        PurchSetup: Record "Purchases & Payables Setup";
        PurchCommentLine: Record "Purch. Comment Line";
        PurchOrderHeader: Record "Purchase Header";
        PurchOrderLine: Record "Purchase Line";
        RecordLinkManagement: Codeunit "Record Link Management";
    begin
        OnBeforePostDropOrderShipment(SalesHeader, TempDropShptPostBuffer);

        ArchivePurchaseOrders(TempDropShptPostBuffer);
        if TempDropShptPostBuffer.FindSet() then begin
            PurchSetup.Get();
            repeat
                PurchOrderHeader.Get(PurchOrderHeader."Document Type"::Order, TempDropShptPostBuffer."Order No.");
                InsertPurchRcptHeader(PurchOrderHeader, SalesHeader, PurchRcptHeader);
                ApprovalsMgmt.PostApprovalEntries(SalesHeader.RecordId, PurchRcptHeader.RecordId, PurchRcptHeader."No.");
                if PurchSetup."Copy Comments Order to Receipt" then begin
                    PurchCommentLine.CopyComments(
                      PurchOrderHeader."Document Type".AsInteger(), PurchCommentLine."Document Type"::Receipt.AsInteger(),
                      PurchOrderHeader."No.", PurchRcptHeader."No.");
                    RecordLinkManagement.CopyLinks(PurchOrderHeader, PurchRcptHeader);
                end;
                TempDropShptPostBuffer.SetRange("Order No.", TempDropShptPostBuffer."Order No.");
                repeat
                    PurchOrderLine.Get(
                      PurchOrderLine."Document Type"::Order,
                      TempDropShptPostBuffer."Order No.", TempDropShptPostBuffer."Order Line No.");
                    InsertPurchRcptLine(PurchRcptHeader, PurchOrderLine, TempDropShptPostBuffer);
                    PurchPost.UpdateBlanketOrderLine(PurchOrderLine, true, false, false);
                    OnPostDropOrderShipmentOnAfterUpdateBlanketOrderLine(
                        PurchOrderHeader, PurchOrderLine, TempDropShptPostBuffer, SalesShptHeader, SalesHeader, PurchRcptHeader, TempTrackingSpecification, SrcCode);
                until TempDropShptPostBuffer.Next() = 0;
                TempDropShptPostBuffer.SetRange("Order No.");
                OnAfterInsertDropOrderPurchRcptHeader(PurchRcptHeader);
            until TempDropShptPostBuffer.Next() = 0;
        end;
        OnAfterPostDropOrderShipment(TempDropShptPostBuffer);
    end;

    local procedure PostItemTracking(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; TrackingSpecificationExists: Boolean; var TempTrackingSpecification: Record "Tracking Specification" temporary; var TempItemLedgEntryNotInvoiced: Record "Item Ledger Entry" temporary; HasATOShippedNotInvoiced: Boolean)
    var
        QtyToInvoiceBaseInTrackingSpec: Decimal;
        ShouldPostItemTrackingForReceipt: Boolean;
        ShouldPostItemTrackingForShipment: Boolean;
        ShouldProcessReceipt: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemTracking(SalesHeader, SalesLine, TrackingSpecificationExists, TempTrackingSpecification, IsHandled, TempItemLedgEntryNotInvoiced, HasATOShippedNotInvoiced, PreciseTotalChargeAmt, RoundedPrevTotalChargeAmt, RemQtyToBeInvoiced, ItemJnlRollRndg);
        if IsHandled then
            exit;

        if TrackingSpecificationExists then begin
            TempTrackingSpecification.CalcSums("Qty. to Invoice (Base)");
            QtyToInvoiceBaseInTrackingSpec := TempTrackingSpecification."Qty. to Invoice (Base)";
            if not TempTrackingSpecification.FindFirst() then
                TempTrackingSpecification.Init();
        end;

        ShouldProcessReceipt := SalesLine.IsCreditDocType();
        OnPostItemTrackingOnAfterCalcShouldProcessReceipt(SalesHeader, SalesLine, ShouldProcessReceipt, ItemJnlRollRndg);
        if ShouldProcessReceipt then begin
            ShouldPostItemTrackingForReceipt :=
                (Abs(RemQtyToBeInvoiced) > Abs(SalesLine."Return Qty. to Receive")) or
                (Abs(RemQtyToBeInvoiced) >= Abs(QtyToInvoiceBaseInTrackingSpec)) and
                (QtyToInvoiceBaseInTrackingSpec <> 0);
            OnPostItemTrackingOnAfterCalcShouldPostItemTrackingForReceipt(
                SalesHeader, SalesLine, RemQtyToBeInvoiced, QtyToInvoiceBaseInTrackingSpec, ShouldPostItemTrackingForReceipt);
            if ShouldPostItemTrackingForReceipt then
                PostItemTrackingForReceipt(
                  SalesHeader, SalesLine, TrackingSpecificationExists, TempTrackingSpecification);

            PostItemTrackingCheckReturnReceipt(SalesLine, RemQtyToBeInvoiced);
        end else begin
            ShouldPostItemTrackingForShipment :=
                (Abs(RemQtyToBeInvoiced) > Abs(SalesLine."Qty. to Ship")) or
                (Abs(RemQtyToBeInvoiced) >= Abs(QtyToInvoiceBaseInTrackingSpec)) and
                (QtyToInvoiceBaseInTrackingSpec <> 0);
            OnPostItemTrackingOnAfterCalcShouldPostItemTrackingForShipment(
                SalesHeader, SalesLine, RemQtyToBeInvoiced, QtyToInvoiceBaseInTrackingSpec, ShouldPostItemTrackingForShipment);
            if ShouldPostItemTrackingForShipment then
                PostItemTrackingForShipment(
                  SalesHeader, SalesLine, TrackingSpecificationExists, TempTrackingSpecification,
                  TempItemLedgEntryNotInvoiced, HasATOShippedNotInvoiced);

            PostItemTrackingCheckShipment(SalesLine, RemQtyToBeInvoiced);
        end;
    end;

    /// <summary>
    /// Checks if remaining quantity to be invoiced is greater than the return quantity to be received. Throws an error if it is.
    /// </summary>
    /// <param name="SalesLine">The sales line to check.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    procedure PostItemTrackingCheckReturnReceipt(SalesLine: Record "Sales Line"; RemQtyToBeInvoiced: Decimal)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemTrackingCheckReturnReceipt(SalesLine, RemQtyToBeInvoiced, IsHandled);
        if IsHandled then
            exit;

        if Abs(RemQtyToBeInvoiced) > Abs(SalesLine."Return Qty. to Receive") then begin
            if SalesLine."Document Type" = SalesLine."Document Type"::"Credit Memo" then
                Error(InvoiceGreaterThanReturnReceiptErr, SalesLine."Return Receipt No.");
            Error(ReturnReceiptLinesDeletedErr);
        end;
    end;

    /// <summary>
    /// Checks if remaining quantity to be invoiced is greater than the quantity to be shipped. Throws an error if it is
    /// </summary>
    /// <param name="SalesLine">The sales line to check.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    procedure PostItemTrackingCheckShipment(SalesLine: Record "Sales Line"; RemQtyToBeInvoiced: Decimal)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemTrackingCheckShipment(SalesLine, RemQtyToBeInvoiced, IsHandled);
        if IsHandled then
            exit;

        if Abs(RemQtyToBeInvoiced) > Abs(SalesLine."Qty. to Ship") then begin
            if SalesLine."Document Type" = SalesLine."Document Type"::Invoice then
                Error(QuantityToInvoiceGreaterErr, SalesLine."Shipment No.");
            Error(ShipmentLinesDeletedErr);
        end;
    end;

    /// <summary>
    /// Posts item tracking for return receipt lines during invoicing.
    /// </summary>
    /// <param name="SalesHeader">The sales header record.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="TrackingSpecificationExists">Indicates if tracking specification exists.</param>
    /// <param name="TempTrackingSpecification">Temporary tracking specification records.</param>
    procedure PostItemTrackingForReceipt(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; TrackingSpecificationExists: Boolean; var TempTrackingSpecification: Record "Tracking Specification" temporary)
    var
        ItemEntryRelation: Record "Item Entry Relation";
        ReturnRcptLine: Record "Return Receipt Line";
        SalesShptLine: Record "Sales Shipment Line";
        EndLoop: Boolean;
        QtyToBeInvoiced: Decimal;
        QtyToBeInvoicedBase: Decimal;
        ShouldAdjustQuantityRounding: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostItemTrackingForReceipt(SalesLine, IsHandled);
        if IsHandled then
            exit;

        EndLoop := false;
        ReturnRcptLine.Reset();
        case SalesHeader."Document Type" of
            SalesHeader."Document Type"::"Return Order":
                begin
                    ReturnRcptLine.SetCurrentKey("Return Order No.", "Return Order Line No.");
                    ReturnRcptLine.SetRange("Return Order No.", SalesLine."Document No.");
                    ReturnRcptLine.SetRange("Return Order Line No.", SalesLine."Line No.");
                end;
            SalesHeader."Document Type"::"Credit Memo":
                begin
                    ReturnRcptLine.SetRange("Document No.", SalesLine."Return Receipt No.");
                    ReturnRcptLine.SetRange("Line No.", SalesLine."Return Receipt Line No.");
                end;
        end;
        ReturnRcptLine.SetFilter("Return Qty. Rcd. Not Invd.", '<>0');
        OnPostItemTrackingForReceiptOnAfterSetFilters(ReturnRcptLine, SalesHeader, SalesLine);
        if ReturnRcptLine.FindSet() then begin
            ItemJnlRollRndg := true;
            repeat
                GetReturnRcptLineFromTrackingOrUpdateItemEntryRelation(
                    SalesHeader, TrackingSpecificationExists, ItemEntryRelation, TempTrackingSpecification, ReturnRcptLine);

                UpdateChargeItemReturnRcptLineGenProdPostingGroup(ReturnRcptLine);
                CheckReturnRcptLine(ReturnRcptLine, SalesLine);

                if SalesLine."Qty. to Invoice" * ReturnRcptLine.Quantity < 0 then
                    SalesLine.FieldError("Qty. to Invoice", ReturnReceiptSameSignErr);
                UpdateQtyToBeInvoicedForReturnReceipt(
                  QtyToBeInvoiced, QtyToBeInvoicedBase,
                  TrackingSpecificationExists, SalesLine, ReturnRcptLine, TempTrackingSpecification);

                if TrackingSpecificationExists then begin
                    TempTrackingSpecification."Quantity actual Handled (Base)" := QtyToBeInvoicedBase;
                    TempTrackingSpecification.Modify();
                end;

                ShouldAdjustQuantityRounding := TrackingSpecificationExists;
                OnPostItemTrackingForReceiptOnBeforeAdjustQuantityRounding(
                    ReturnRcptLine, RemQtyToBeInvoiced, QtyToBeInvoiced, RemQtyToBeInvoicedBase, QtyToBeInvoicedBase,
                    TrackingSpecificationExists, ShouldAdjustQuantityRounding);
                if ShouldAdjustQuantityRounding then
                    ItemTrackingMgt.AdjustQuantityRounding(
                      RemQtyToBeInvoiced, QtyToBeInvoiced,
                      RemQtyToBeInvoicedBase, QtyToBeInvoicedBase);

                RemQtyToBeInvoiced := RemQtyToBeInvoiced - QtyToBeInvoiced;
                RemQtyToBeInvoicedBase := RemQtyToBeInvoicedBase - QtyToBeInvoicedBase;
                ReturnRcptLine."Quantity Invoiced" :=
                  ReturnRcptLine."Quantity Invoiced" + QtyToBeInvoiced;
                ReturnRcptLine."Qty. Invoiced (Base)" :=
                  ReturnRcptLine."Qty. Invoiced (Base)" + QtyToBeInvoicedBase;
                ReturnRcptLine."Return Qty. Rcd. Not Invd." :=
                  ReturnRcptLine.Quantity - ReturnRcptLine."Quantity Invoiced";

                IsHandled := false;
                OnPostItemTrackingForReceiptOnBeforeReturnRcptLineModify(SalesHeader, ReturnRcptLine, SalesLine, IsHandled);
                if not IsHandled then
                    ReturnRcptLine.Modify();

                OnBeforePostItemTrackingReturnRcpt(
                  SalesInvHeader, SalesShptLine, TempTrackingSpecification, TrackingSpecificationExists,
                  SalesCrMemoHeader, ReturnRcptLine, SalesLine, QtyToBeInvoiced, QtyToBeInvoicedBase);

                if PostItemTrackingForReceiptCondition(SalesLine, ReturnRcptLine) then
                    PostItemJnlLine(
                      SalesHeader, SalesLine, 0, 0, QtyToBeInvoiced, QtyToBeInvoicedBase,
                      ItemEntryRelation."Item Entry No.", '', TempTrackingSpecification, false);

                OnAfterPostItemTrackingReturnRcpt(
                  SalesInvHeader, SalesShptLine, TempTrackingSpecification, TrackingSpecificationExists,
                  SalesCrMemoHeader, ReturnRcptLine, SalesLine, QtyToBeInvoiced, QtyToBeInvoicedBase);

                EndLoop := IsEndLoopForReceivedNotInvoiced(RemQtyToBeInvoiced, TrackingSpecificationExists, ReturnRcptLine, TempTrackingSpecification, SalesLine);
            until EndLoop;
        end else begin
            IsHandled := false;
            OnPostItemTrackingForShipmentOnBeforeReturnReceiptInvoiceErr(SalesLine, IsHandled, SalesHeader, ItemJnlRollRndg, TrackingSpecificationExists, TempTrackingSpecification, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase);
            if not IsHandled then
                Error(
                  ReturnReceiptInvoicedErr,
                  SalesLine."Return Receipt Line No.", SalesLine."Return Receipt No.");
        end;
    end;

    local procedure CheckReturnRcptLine(var ReturnReceiptLine: Record "Return Receipt Line"; SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckReturnRcptLine(ReturnReceiptLine, SalesLine, IsHandled);
        if IsHandled then
            exit;

        ReturnReceiptLine.TestField("Sell-to Customer No.", SalesLine."Sell-to Customer No.");
        ReturnReceiptLine.TestField(Type, SalesLine.Type);
        ReturnReceiptLine.TestField("No.", SalesLine."No.");
        ReturnReceiptLine.TestField("Gen. Bus. Posting Group", SalesLine."Gen. Bus. Posting Group");
        ReturnReceiptLine.TestField("Gen. Prod. Posting Group", SalesLine."Gen. Prod. Posting Group");
        ReturnReceiptLine.TestField("Job No.", SalesLine."Job No.");
        ReturnReceiptLine.TestField("Unit of Measure Code", SalesLine."Unit of Measure Code");
        ReturnReceiptLine.TestField("Variant Code", SalesLine."Variant Code");
    end;

    local procedure IsEndLoopForReceivedNotInvoiced(RemQtyToBeInvoiced: Decimal; TrackingSpecificationExists: Boolean; var ReturnReceiptLine: Record "Return Receipt Line"; var TempTrackingSpecification: Record "Tracking Specification"; SalesLine: Record "Sales Line") EndLoop: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsEndLoopForReceivedNotInvoiced(RemQtyToBeInvoiced, TrackingSpecificationExists, ReturnReceiptLine, TempTrackingSpecification, SalesLine, EndLoop, IsHandled);
        if IsHandled then
            exit;

        if TrackingSpecificationExists then
            exit((TempTrackingSpecification.Next() = 0) or (RemQtyToBeInvoiced = 0));

        exit((ReturnReceiptLine.Next() = 0) or (Abs(RemQtyToBeInvoiced) <= Abs(SalesLine."Return Qty. to Receive")));
    end;

    local procedure GetItemEntryRelation(var SalesHeader: Record "Sales Header"; var ItemEntryRelation: Record "Item Entry Relation"; var TempTrackingSpecification: Record "Tracking Specification" temporary)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetItemEntryRelation(SalesHeader, ItemEntryRelation, TempTrackingSpecification, IsHandled);
        if IsHandled then
            exit;

        ItemEntryRelation.Get(TempTrackingSpecification."Item Ledger Entry No.");
    end;

    local procedure GetReturnRcptLineFromTrackingOrUpdateItemEntryRelation(SalesHeader: Record "Sales Header"; TrackingSpecificationExists: Boolean; var ItemEntryRelation: Record "Item Entry Relation"; var TempTrackingSpecification: Record "Tracking Specification" temporary; var ReturnRcptLine: Record "Return Receipt Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetReturnRcptLineFromTrackingOrUpdateItemEntryRelation(TempTrackingSpecification, ReturnRcptLine, ItemEntryRelation, IsHandled, TrackingSpecificationExists);
        if IsHandled then
            exit;

        if TrackingSpecificationExists then begin  // Item Tracking
            GetItemEntryRelation(SalesHeader, ItemEntryRelation, TempTrackingSpecification);
            ReturnRcptLine.Get(ItemEntryRelation."Source ID", ItemEntryRelation."Source Ref. No.");
        end else
            ItemEntryRelation."Item Entry No." := ReturnRcptLine."Item Rcpt. Entry No.";
    end;

    local procedure PostItemTrackingForReceiptCondition(SalesLine: Record "Sales Line"; ReturnRcptLine: Record "Return Receipt Line"): Boolean
    var
        Condition: Boolean;
    begin
        Condition := SalesLine.Type = SalesLine.Type::Item;
        OnBeforePostItemTrackingForReceiptCondition(SalesLine, ReturnRcptLine, Condition);
        exit(Condition);
    end;

    /// <summary>
    /// Posts item tracking entries for shipments during invoice posting.
    /// Processes shipment lines that have been shipped but not yet invoiced, applying item tracking and updating invoiced quantities.
    /// </summary>
    /// <param name="SalesHeader">The sales header record.</param>
    /// <param name="SalesLine">The sales line record being invoiced.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists for the line.</param>
    /// <param name="TempTrackingSpecification">Temporary tracking specification records.</param>
    /// <param name="TempItemLedgEntryNotInvoiced">Temporary item ledger entries that have not been invoiced.</param>
    /// <param name="HasATOShippedNotInvoiced">Indicates whether there are assemble-to-order items shipped but not invoiced.</param>
    procedure PostItemTrackingForShipment(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; TrackingSpecificationExists: Boolean; var TempTrackingSpecification: Record "Tracking Specification" temporary; var TempItemLedgEntryNotInvoiced: Record "Item Ledger Entry" temporary; HasATOShippedNotInvoiced: Boolean)
    var
        ItemEntryRelation: Record "Item Entry Relation";
        SalesShptLine: Record "Sales Shipment Line";
        RemQtyToInvoiceCurrLine: Decimal;
        RemQtyToInvoiceCurrLineBase: Decimal;
        QtyToBeInvoiced: Decimal;
        QtyToBeInvoicedBase: Decimal;
        ShouldAdjustQuantityRounding: Boolean;
        IsHandled: Boolean;
    begin
        SalesShptLine.Reset();
        case SalesHeader."Document Type" of
            SalesHeader."Document Type"::Order:
                begin
                    SalesShptLine.SetCurrentKey("Order No.", "Order Line No.");
                    SalesShptLine.SetRange("Order No.", SalesLine."Document No.");
                    SalesShptLine.SetRange("Order Line No.", SalesLine."Line No.");
                end;
            SalesHeader."Document Type"::Invoice:
                begin
                    SalesShptLine.SetRange("Document No.", SalesLine."Shipment No.");
                    SalesShptLine.SetRange("Line No.", SalesLine."Shipment Line No.");
                end;
        end;

        IsHandled := false;
        OnPostItemTrackingForShipmentOnBeforeGetATOItemLedgEntriesNotInvoiced(SalesHeader, IsHandled);
        if not IsHandled then
            if not TrackingSpecificationExists then
                HasATOShippedNotInvoiced := GetATOItemLedgEntriesNotInvoiced(SalesLine, TempItemLedgEntryNotInvoiced);

        SalesShptLine.SetFilter("Qty. Shipped Not Invoiced", '<>0');
        OnPostItemTrackingForShipmentOnAfterSetFilters(SalesShptLine, SalesHeader, SalesLine);
        if SalesShptLine.FindFirst() then begin
            ItemJnlRollRndg := true;
            repeat
                SetItemEntryRelation(
                  ItemEntryRelation, SalesShptLine,
                  TempTrackingSpecification, TempItemLedgEntryNotInvoiced,
                  TrackingSpecificationExists, HasATOShippedNotInvoiced);

                UpdateRemainingQtyToBeInvoiced(SalesShptLine, RemQtyToInvoiceCurrLine, RemQtyToInvoiceCurrLineBase);
                UpdateChargeItemSalesShptLineGenProdPostingGroup(SalesShptLine);
                OnPostItemTrackingForShipmentOnAfterUpdateSalesShptLineFields(SalesShptLine, SalesLine);
                IsHandled := false;
                OnPostItemTrackingForShipmentOnBeforeTestLineFields(SalesShptLine, SalesLine, IsHandled);
                if not IsHandled then begin
                    SalesShptLine.TestField("Sell-to Customer No.", SalesLine."Sell-to Customer No.");
                    SalesShptLine.TestField(Type, SalesLine.Type);
                    SalesShptLine.TestField("No.", SalesLine."No.");
                    SalesShptLine.TestField("Gen. Bus. Posting Group", SalesLine."Gen. Bus. Posting Group");
                    SalesShptLine.TestField("Gen. Prod. Posting Group", SalesLine."Gen. Prod. Posting Group");
                    CheckJobNoOnShptLineEqualToSales(SalesShptLine, SalesLine);
                    SalesShptLine.TestField("Unit of Measure Code", SalesLine."Unit of Measure Code");
                    SalesShptLine.TestField("Variant Code", SalesLine."Variant Code");
                end;
                if -SalesLine."Qty. to Invoice" * SalesShptLine.Quantity < 0 then
                    SalesLine.FieldError("Qty. to Invoice", ShipmentSameSignErr);

                UpdateQtyToBeInvoicedForShipment(
                  QtyToBeInvoiced, QtyToBeInvoicedBase,
                  TrackingSpecificationExists, HasATOShippedNotInvoiced,
                  SalesLine, SalesShptLine,
                  TempTrackingSpecification, TempItemLedgEntryNotInvoiced);

                if TrackingSpecificationExists then begin
                    TempTrackingSpecification."Quantity actual Handled (Base)" := QtyToBeInvoicedBase;
                    TempTrackingSpecification.Modify();
                end;

                ShouldAdjustQuantityRounding := TrackingSpecificationExists or HasATOShippedNotInvoiced;
                OnPostItemTrackingForShipmentOnBeforeAdjustQuantityRounding(
                    SalesShptLine, RemQtyToInvoiceCurrLine, QtyToBeInvoiced, RemQtyToInvoiceCurrLineBase, QtyToBeInvoicedBase,
                    TrackingSpecificationExists, HasATOShippedNotInvoiced, ShouldAdjustQuantityRounding);
                if ShouldAdjustQuantityRounding then
                    ItemTrackingMgt.AdjustQuantityRounding(
                      RemQtyToInvoiceCurrLine, QtyToBeInvoiced,
                      RemQtyToInvoiceCurrLineBase, QtyToBeInvoicedBase);

                RemQtyToBeInvoiced := RemQtyToBeInvoiced - QtyToBeInvoiced;
                RemQtyToBeInvoicedBase := RemQtyToBeInvoicedBase - QtyToBeInvoicedBase;
                OnBeforeUpdateInvoicedQtyOnShipmentLine(SalesShptLine, SalesLine, SalesHeader, SalesInvHeader, SuppressCommit);
                UpdateInvoicedQtyOnShipmentLine(SalesShptLine, QtyToBeInvoiced, QtyToBeInvoicedBase);
                OnInvoiceSalesShptLine(SalesShptLine, SalesInvHeader."No.", SalesLine."Line No.", -QtyToBeInvoiced, SuppressCommit);

                OnBeforePostItemTrackingForShipment(
                  SalesInvHeader, SalesShptLine, TempTrackingSpecification, TrackingSpecificationExists, SalesLine,
                  QtyToBeInvoiced, QtyToBeInvoicedBase);

                if PostItemTrackingForShipmentCondition(SalesLine, SalesShptLine) then
                    PostItemJnlLine(
                      SalesHeader, SalesLine, 0, 0, QtyToBeInvoiced, QtyToBeInvoicedBase,
                      ItemEntryRelation."Item Entry No.", '', TempTrackingSpecification, false);

                OnAfterPostItemTrackingForShipment(
                  SalesInvHeader, SalesShptLine, TempTrackingSpecification, TrackingSpecificationExists, SalesLine,
                  QtyToBeInvoiced, QtyToBeInvoicedBase);
            until IsEndLoopForShippedNotInvoiced(
                    RemQtyToBeInvoiced, TrackingSpecificationExists, HasATOShippedNotInvoiced,
                    SalesShptLine, TempTrackingSpecification, TempItemLedgEntryNotInvoiced, SalesLine);
        end else begin
            IsHandled := false;
            OnPostItemTrackingForShipmentOnBeforeShipmentInvoiceErr(SalesLine, IsHandled, SalesHeader, ItemJnlRollRndg, TrackingSpecificationExists, TempTrackingSpecification, RemQtyToBeInvoiced, RemQtyToBeInvoicedBase);
            if not IsHandled then
                Error(
                  ShipmentInvoiceErr, SalesLine."Shipment Line No.", SalesLine."Shipment No.");
        end;
    end;

    local procedure CheckJobNoOnShptLineEqualToSales(SalesShipmentLine: Record "Sales Shipment Line"; SalesLine: Record "Sales Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckJobNoOnShptLineEqualToSales(SalesShipmentLine, SalesLine, IsHandled);
        if IsHandled then
            exit;

        SalesShipmentLine.TestField("Job No.", SalesLine."Job No.");
    end;

    local procedure PostItemTrackingForShipmentCondition(SalesLine: Record "Sales Line"; SalesShptLine: Record "Sales Shipment Line"): Boolean
    var
        Condition: Boolean;
    begin
        Condition := SalesLine.Type = SalesLine.Type::Item;
        OnBeforePostItemTrackingForShipmentCondition(SalesLine, SalesShptLine, Condition);
        exit(Condition);
    end;

    /// <summary>
    /// Updates order lines after posting by adjusting shipped, received, and invoiced quantities.
    /// Also handles prepayment deductions, blanket order updates, and resets quantities for the next posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header record that was posted.</param>
    procedure PostUpdateOrderLine(SalesHeader: Record "Sales Header")
    var
        TempSalesLine: Record "Sales Line" temporary;
        SetDefaultQtyBlank: Boolean;
        IsHandled: Boolean;
        ShouldCalcPrepmtAmounts: Boolean;
        ShouldSetInvoiceFields: Boolean;
    begin
        OnBeforePostUpdateOrderLine(SalesHeader, TempSalesLineGlobal, SuppressCommit, SalesSetup);

        ResetTempLines(TempSalesLine);
        TempSalesLine.SetRange("Prepayment Line", false);
        TempSalesLine.SetFilter(Quantity, '<>0');
        OnPostUpdateOrderLineOnAfterSetFilters(TempSalesLine);
        if TempSalesLine.FindSet() then
            repeat
                OnPostUpdateOrderLineOnBeforeInitTempSalesLineQuantities(SalesHeader, TempSalesLine);
                if SalesHeader.Ship then begin
                    IsHandled := false;
                    OnPostUpdateOrderLineOnBeforeGetQuantityShipped(TempSalesLine, IsHandled, SalesHeader);
                    if not IsHandled then begin
                        TempSalesLine."Quantity Shipped" += TempSalesLine."Qty. to Ship";
                        TempSalesLine."Qty. Shipped (Base)" += TempSalesLine."Qty. to Ship (Base)";
                    end;
                end;
                if SalesHeader.Receive then begin
                    IsHandled := false;
                    OnPostUpdateOrderLineOnBeforeGetReturnQtyReceived(TempSalesLine, IsHandled, SalesHeader);
                    if not IsHandled then begin
                        TempSalesLine."Return Qty. Received" += TempSalesLine."Return Qty. to Receive";
                        TempSalesLine."Return Qty. Received (Base)" += TempSalesLine."Return Qty. to Receive (Base)";
                    end;
                end;
                ShouldSetInvoiceFields := SalesHeader.Invoice;
                OnPostUpdateOrderLineOnBeforeSetInvoiceFields(SalesHeader, TempSalesLine, ShouldSetInvoiceFields);
                if ShouldSetInvoiceFields then begin
                    IsHandled := false;
                    OnPostUpdateOrderLineOnBeforeUpdateInvoicedValues(SalesHeader, TempSalesLine, IsHandled);
                    if not IsHandled then begin
                        if TempSalesLine."Document Type" = TempSalesLine."Document Type"::Order then begin
                            if Abs(TempSalesLine."Quantity Invoiced" + TempSalesLine."Qty. to Invoice") > Abs(TempSalesLine."Quantity Shipped") then begin
                                TempSalesLine.Validate(TempSalesLine."Qty. to Invoice", TempSalesLine."Quantity Shipped" - TempSalesLine."Quantity Invoiced");
                                TempSalesLine."Qty. to Invoice (Base)" := TempSalesLine."Qty. Shipped (Base)" - TempSalesLine."Qty. Invoiced (Base)";
                            end
                        end else
                            if Abs(TempSalesLine."Quantity Invoiced" + TempSalesLine."Qty. to Invoice") > Abs(TempSalesLine."Return Qty. Received") then begin
                                TempSalesLine.Validate(TempSalesLine."Qty. to Invoice", TempSalesLine."Return Qty. Received" - TempSalesLine."Quantity Invoiced");
                                TempSalesLine."Qty. to Invoice (Base)" := TempSalesLine."Return Qty. Received (Base)" - TempSalesLine."Qty. Invoiced (Base)";
                            end;

                        TempSalesLine."Quantity Invoiced" += TempSalesLine."Qty. to Invoice";
                        TempSalesLine."Qty. Invoiced (Base)" += TempSalesLine."Qty. to Invoice (Base)";

                        ShouldCalcPrepmtAmounts := TempSalesLine."Qty. to Invoice" <> 0;
                        OnPostUpdateOrderLineOnAfterCalcShouldCalcPrepmtAmounts(TempSalesLine, ShouldCalcPrepmtAmounts);
                        if ShouldCalcPrepmtAmounts then begin
                            TempSalesLine."Prepmt Amt Deducted" += TempSalesLine."Prepmt Amt to Deduct";
                            TempSalesLine."Prepmt VAT Diff. Deducted" += TempSalesLine."Prepmt VAT Diff. to Deduct";
                            DecrementPrepmtAmtInvLCY(SalesHeader, TempSalesLine, TempSalesLine."Prepmt. Amount Inv. (LCY)", TempSalesLine."Prepmt. VAT Amount Inv. (LCY)");
                            TempSalesLine."Prepmt Amt to Deduct" := TempSalesLine."Prepmt. Amt. Inv." - TempSalesLine."Prepmt Amt Deducted";
                            TempSalesLine."Prepmt VAT Diff. to Deduct" := 0;
                        end;
                    end;
                    OnPostUpdateOrderLineOnAfterUpdateInvoicedValues(TempSalesLine, SalesHeader);
                end;

                OnPostItemTrackingForShipmentConditionOnBeforeUpdateBlanketOrderLine(TempSalesLine, SalesHeader);
                UpdateBlanketOrderLine(TempSalesLine, SalesHeader.Ship, SalesHeader.Receive, SalesHeader.Invoice);

                IsHandled := false;
                OnPostUpdateOrderLineOnBeforeInitOutstanding(SalesHeader, TempSalesLine, IsHandled);
                if not IsHandled then begin
                    TempSalesLine.InitOutstanding();
                    CheckATOLink(TempSalesLine);

                    SetDefaultQtyBlank := SalesSetup."Default Quantity to Ship" = SalesSetup."Default Quantity to Ship"::Blank;
                    OnPostUpdateOrderLineOnSetDefaultQtyBlank(SalesHeader, TempSalesLine, SalesSetup, SetDefaultQtyBlank);
                    if WhseHandlingRequiredExternal(TempSalesLine) or SetDefaultQtyBlank then begin
                        if TempSalesLine."Document Type" = TempSalesLine."Document Type"::"Return Order" then begin
                            TempSalesLine."Return Qty. to Receive" := 0;
                            TempSalesLine."Return Qty. to Receive (Base)" := 0;
                        end else begin
                            TempSalesLine."Qty. to Ship" := 0;
                            TempSalesLine."Qty. to Ship (Base)" := 0;
                        end;
                        OnPostUpdateOrderLineBeforeInitQtyToInvoice(TempSalesLine, WhseShip, WhseReceive);
                        TempSalesLine.InitQtyToInvoice();
                    end else begin
                        if TempSalesLine."Document Type" = TempSalesLine."Document Type"::"Return Order" then
                            TempSalesLine.InitQtyToReceive()
                        else
                            TempSalesLine.InitQtyToShip2();
                        OnPostUpdateOrderLineOnAfterInitQtyToReceiveOrShip(SalesHeader, TempSalesLine, WhseShip, WhseReceive);
                    end;

                    if (TempSalesLine."Purch. Order Line No." <> 0) and (TempSalesLine.Quantity = TempSalesLine."Quantity Invoiced") then
                        UpdateAssocLines(TempSalesLine);

                    TempSalesLine.SetDefaultQuantity();
                    IsHandled := false;
                    OnBeforePostUpdateOrderLineModifyTempLine(TempSalesLine, WhseShip, WhseReceive, SuppressCommit, IsHandled, SalesHeader);
                    if not IsHandled then
                        ModifyTempLine(TempSalesLine);
                    OnAfterPostUpdateOrderLineModifyTempLine(TempSalesLine, WhseShip, WhseReceive, SuppressCommit, SalesHeader);
                end;
            until TempSalesLine.Next() = 0;
        OnAfterPostUpdateOrderLine(TempSalesLine);
    end;

    local procedure PostUpdateInvoiceLine(var SalesHeader: Record "Sales Header")
    var
        SalesOrderLine: Record "Sales Line";
        SalesShptLine: Record "Sales Shipment Line";
        TempSalesLine: Record "Sales Line" temporary;
        TempSalesOrderHeader: Record "Sales Header" temporary;
        CRMSalesDocumentPostingMgt: Codeunit "CRM Sales Document Posting Mgt";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostUpdateInvoiceLine(TempSalesLineGlobal, IsHandled);
        if IsHandled then
            exit;

        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter("Shipment No.", '<>%1', '');
        TempSalesLine.SetFilter(Type, '<>%1', TempSalesLine.Type::" ");
        if TempSalesLine.FindSet() then
            repeat
                SalesShptLine.Get(TempSalesLine."Shipment No.", TempSalesLine."Shipment Line No.");
                SalesOrderLine.Get(
                  SalesOrderLine."Document Type"::Order,
                  SalesShptLine."Order No.", SalesShptLine."Order Line No.");
                OnPostUpdateInvoiceLineOnAfterGetSalesOrderLine(TempSalesLine, SalesShptLine, SalesOrderLine);
                if TempSalesLine.Type = TempSalesLine.Type::"Charge (Item)" then
                    UpdateSalesOrderChargeAssgnt(TempSalesLine, SalesOrderLine);
                IsHandled := false;
                OnPostUpdateInvoiceLineOnBeforeCalcQuantityInvoiced(SalesOrderLine, TempSalesLine, IsHandled);
                if not IsHandled then begin
                    SalesOrderLine."Quantity Invoiced" += TempSalesLine."Qty. to Invoice";
                    SalesOrderLine."Qty. Invoiced (Base)" += TempSalesLine."Qty. to Invoice (Base)";
                end;
                CheckSalesLineInvoiceMoreThanShipped(SalesOrderLine, TempSalesLine, SalesShptLine);
                OnPostUpdateInvoiceLineOnBeforeInitQtyToInvoice(SalesOrderLine, TempSalesLine);
                SalesOrderLine.InitQtyToInvoice();
                if SalesOrderLine."Prepayment %" <> 0 then begin
                    SalesOrderLine."Prepmt Amt Deducted" += TempSalesLine."Prepmt Amt to Deduct";
                    SalesOrderLine."Prepmt VAT Diff. Deducted" += TempSalesLine."Prepmt VAT Diff. to Deduct";
                    DecrementPrepmtAmtInvLCY(
                      SalesHeader, TempSalesLine, SalesOrderLine."Prepmt. Amount Inv. (LCY)", SalesOrderLine."Prepmt. VAT Amount Inv. (LCY)");
                    SalesOrderLine."Prepmt Amt to Deduct" :=
                      SalesOrderLine."Prepmt. Amt. Inv." - SalesOrderLine."Prepmt Amt Deducted";
                    SalesOrderLine."Prepmt VAT Diff. to Deduct" := 0;
                end;
                IsHandled := false;
                OnPostUpdateInvoiceLineOnBeforeInitOutstanding(SalesOrderLine, IsHandled);
                if not IsHandled then
                    SalesOrderLine.InitOutstanding();
                OnPostUpdateInvoiceLineOnBeforeModifySalesOrderLine(SalesOrderLine, TempSalesLine);
                SalesOrderLine.Modify();
                OnPostUpdateInvoiceLineOnAfterModifySalesOrderLine(SalesOrderLine, TempSalesLine);

                if not TempSalesOrderHeader.Get(SalesOrderLine."Document Type", SalesOrderLine."Document No.") then begin
                    TempSalesOrderHeader."Document Type" := SalesOrderLine."Document Type";
                    TempSalesOrderHeader."No." := SalesOrderLine."Document No.";
                    TempSalesOrderHeader.Insert();
                end;
                OnPostUpdateInvoiceLineOnAfterInsertSalesOrderHeader(SalesOrderLine, TempSalesLine);
            until TempSalesLine.Next() = 0;
        CRMSalesDocumentPostingMgt.CheckShippedOrders(TempSalesOrderHeader);

        OnAfterPostUpdateInvoiceLine(TempSalesLine, SalesHeader, TempSalesOrderHeader);
    end;

    local procedure PostUpdateOrderNo(var SalesInvoiceHeader: Record "Sales Invoice Header")
    var
        SalesInvoiceLine: Record "Sales Invoice Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostUpdateOrderNo(SalesInvoiceHeader, IsHandled);
        if IsHandled then
            exit;

        if SalesInvoiceHeader."No." = '' then
            exit;


        // Do not change 'Order No.' if already set
        if SalesInvoiceHeader."Order No." <> '' then
            exit;

        // Get a line where 'Order No.' is set
        SalesInvoiceLine.SetLoadFields("Order No.");

        SalesInvoiceLine.SetRange("Document No.", SalesInvoiceHeader."No.");
        SalesInvoiceLine.SetFilter(Type, '<>%1', SalesInvoiceLine.Type::" "); // Ignore comment lines
        SalesInvoiceLine.SetFilter("Order No.", '<>%1', '');
        if not SalesInvoiceLine.FindFirst() then
            exit;

        // If all the lines have the same 'Order No.' then set 'Order No.' field on the header
        SalesInvoiceLine.SetFilter("Order No.", '<>%1', SalesInvoiceLine."Order No.");
        if SalesInvoiceLine.IsEmpty() then begin
            SalesInvoiceHeader.Validate("Order No.", SalesInvoiceLine."Order No.");
            SalesInvoiceHeader.Modify(true);
        end;
    end;

    local procedure CheckSalesLineInvoiceMoreThanShipped(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary; var SalesShptLine: Record "Sales Shipment Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckSalesLineInvoiceMoreThanShipped(SalesOrderLine, TempSalesLine, SalesShptLine, IsHandled);
        if IsHandled then
            exit;

        if Abs(SalesOrderLine."Quantity Invoiced") > Abs(SalesOrderLine."Quantity Shipped") then
            Error(InvoiceMoreThanShippedErr, SalesOrderLine."Document No.");
    end;

    /// <summary>
    /// Updates return order lines after posting credit memos that reference return receipts.
    /// Adjusts invoiced quantities and validates that invoiced quantity does not exceed received quantity.
    /// </summary>
    procedure PostUpdateReturnReceiptLine()
    var
        SalesOrderLine: Record "Sales Line";
        ReturnRcptLine: Record "Return Receipt Line";
        TempSalesLine: Record "Sales Line" temporary;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostUpdateReturnReceiptLine(TempSalesLineGlobal, IsHandled);
        if IsHandled then
            exit;

        ResetTempLines(TempSalesLine);
        TempSalesLine.SetFilter("Return Receipt No.", '<>%1', '');
        TempSalesLine.SetFilter(Type, '<>%1', TempSalesLine.Type::" ");
        if TempSalesLine.FindSet() then
            repeat
                ReturnRcptLine.Get(TempSalesLine."Return Receipt No.", TempSalesLine."Return Receipt Line No.");
                SalesOrderLine.Get(
                  SalesOrderLine."Document Type"::"Return Order",
                  ReturnRcptLine."Return Order No.", ReturnRcptLine."Return Order Line No.");
                OnPostUpdateReturnReceiptLineOnAfterGetSalesOrderLine(TempSalesLine, ReturnRcptLine, SalesOrderLine);
                if TempSalesLine.Type = TempSalesLine.Type::"Charge (Item)" then
                    UpdateSalesOrderChargeAssgnt(TempSalesLine, SalesOrderLine);
                IsHandled := false;
                OnPostUpdateReturnReceiptLineOnBeforeCalcQuantityInvoiced(SalesOrderLine, TempSalesLine, IsHandled);
                if not IsHandled then begin
                    SalesOrderLine."Quantity Invoiced" += TempSalesLine."Qty. to Invoice";
                    SalesOrderLine."Qty. Invoiced (Base)" += TempSalesLine."Qty. to Invoice (Base)";
                end;
                if Abs(SalesOrderLine."Quantity Invoiced") > Abs(SalesOrderLine."Return Qty. Received") then
                    Error(InvoiceMoreThanReceivedErr, SalesOrderLine."Document No.");
                OnPostUpdateReturnReceiptLineOnBeforeInitQtyToInvoice(SalesOrderLine, TempSalesLine);
                SalesOrderLine.InitQtyToInvoice();

                IsHandled := false;
                OnPostUpdateReturnReceiptLineOnBeforeInitOutstanding(SalesOrderLine, IsHandled);
                if not IsHandled then
                    SalesOrderLine.InitOutstanding();
                OnPostUpdateReturnReceiptLineOnBeforeModifySalesOrderLine(SalesOrderLine, TempSalesLine);
                SalesOrderLine.Modify();
                OnPostUpdateReturnReceiptLineOnAfterModifySalesOrderLine(SalesOrderLine, TempSalesLine);
            until TempSalesLine.Next() = 0;

        OnAfterPostUpdateReturnReceiptLine(TempSalesLine);
    end;

    local procedure PostUpdateOrderNo(var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    var
        SalesCrMemoLine: Record "Sales Cr.Memo Line";
        NoOfLines: Integer;
        NoOfLinesWithOrderNo: Integer;
        NoOfLinesWithParticularOrderNo: Integer;
    begin
        // Do not change 'Return Order No.' if already set
        if SalesCrMemoHeader."Return Order No." <> '' then
            exit;

        SalesCrMemoLine.SetLoadFields("Order No.");

        // Get number of lines. Ignore comment lines
        SalesCrMemoLine.SetRange("Document No.", SalesCrMemoHeader."No.");
        SalesCrMemoLine.SetFilter(Type, '<>%1', SalesCrMemoLine.Type::" "); // Ignore Comment lines
        NoOfLines := SalesCrMemoLine.Count();

        if NoOfLines = 0 then
            exit;

        // Get number of lines with filled in 'Order No.'
        SalesCrMemoLine.SetFilter("Order No.", '<>%1', '');
        NoOfLinesWithOrderNo := SalesCrMemoLine.Count();
        if not SalesCrMemoLine.FindFirst() then
            exit;

        // Get number of lines with filled with a 'Order No.'
        SalesCrMemoLine.SetRange("Order No.", SalesCrMemoLine."Order No.");
        NoOfLinesWithParticularOrderNo := SalesCrMemoLine.Count();

        SalesCrMemoLine.SetRange("Order No.");
        if (NoOfLines = NoOfLinesWithOrderNo) and (NoOfLinesWithOrderNo = NoOfLinesWithParticularOrderNo) then begin
            SalesCrMemoHeader.Validate("Return Order No.", SalesCrMemoLine."Order No.");
            SalesCrMemoHeader.Modify(true);
        end;
    end;

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

        SalesHeader.TestField("Document Type", ErrorInfo.Create());
        SalesHeader.TestField("Sell-to Customer No.", ErrorInfo.Create());
        SalesHeader.TestField("Bill-to Customer No.", ErrorInfo.Create());
        SalesHeader.TestField("Posting Date", ErrorInfo.Create());
        SalesHeader.TestField("Document Date", ErrorInfo.Create());

        OnAfterCheckMandatoryFields(SalesHeader, SuppressCommit);
    end;

    local procedure ClearPostBuffers()
    begin
        Clear(WhsePostRcpt);
        Clear(WhsePostShpt);
        Clear(GenJnlPostLine);
        Clear(ResJnlPostLine);
        Clear(JobPostLine);
        Clear(ItemJnlPostLine);
        Clear(WhseJnlPostLine);
    end;

    /// <summary>
    /// Sets the posting flags (Ship, Invoice, Receive) on the sales header based on the document type.
    /// </summary>
    /// <param name="SalesHeader">The sales header for which to set the posting flags.</param>
    procedure SetPostingFlags(var SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSetPostingFlags(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        case SalesHeader."Document Type" of
            SalesHeader."Document Type"::Order:
                SalesHeader.Receive := false;
            SalesHeader."Document Type"::Invoice:
                begin
                    SalesHeader.Ship := true;
                    SalesHeader.Invoice := true;
                    SalesHeader.Receive := false;
                end;
            SalesHeader."Document Type"::"Return Order":
                SalesHeader.Ship := false;
            SalesHeader."Document Type"::"Credit Memo":
                begin
                    SalesHeader.Ship := false;
                    SalesHeader.Invoice := true;
                    SalesHeader.Receive := true;
                end;
        end;
        CheckPostingFlags(SalesHeader);
    end;

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

        if not (SalesHeader.Ship or SalesHeader.Invoice or SalesHeader.Receive) then
            Error(ShipInvoiceReceiveErr);
    end;

    /// <summary>
    /// Sets the Supress Commit flag.
    /// </summary>
    /// <param name="NewSuppressCommit">The new value of the Supress Commit flag.</param>
    procedure SetSuppressCommit(NewSuppressCommit: Boolean)
    begin
        SuppressCommit := NewSuppressCommit;
    end;

    local procedure ClearAllVariables()
    begin
        ClearAll();
        TempSalesLineGlobal.DeleteAll();
        TempItemChargeAssgntSales.DeleteAll();
        TempHandlingSpecification.DeleteAll();
        TempATOTrackingSpecification.DeleteAll();
        TempTrackingSpecification.DeleteAll();
        TempTrackingSpecificationInv.DeleteAll();
        TempWhseSplitSpecification.DeleteAll();
        TempValueEntryRelation.DeleteAll();
        TempICGenJnlLine.DeleteAll();
        TempPrepmtDeductLCYSalesLine.DeleteAll();
        TempSKU.DeleteAll();
        TempDeferralHeader.DeleteAll();
        TempDeferralLine.DeleteAll();
        OrderArchived := false;
    end;

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

        if (SalesHeader."Shipping Advice" = SalesHeader."Shipping Advice"::Complete) and SalesHeader.Ship then
            SalesHeader.CheckShippingAdvice();
    end;

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

        if not (SalesHeader.Ship or SalesHeader.Invoice or SalesHeader.Receive) then
            Error(ErrorInfo.Create(DocumentErrorsMgt.GetNothingToPostErrorMsg(), true, SalesHeader));
    end;

    local procedure CheckAssosOrderLines(SalesHeader: Record "Sales Header")
    var
        SalesLine: Record "Sales Line";
        PurchaseOrderLine: Record "Purchase Line";
        PurchaseHeader: Record "Purchase Header";
        TempPurchaseHeader: Record "Purchase Header" temporary;
        TempPurchaseLine: Record "Purchase Line" temporary;
        CheckDimensions: Codeunit "Check Dimensions";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckAssosOrderLines(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        SalesLine.Reset();
        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        SalesLine.SetFilter("Purch. Order Line No.", '<>0');
        SalesLine.SetFilter("Qty. to Ship", '<>0');
        OnCheckAssosOrderLinesOnAfterSetFilters(SalesLine, SalesHeader);
        if SalesLine.FindSet() then
            repeat
                PurchaseOrderLine.Get(
                  PurchaseOrderLine."Document Type"::Order, SalesLine."Purchase Order No.", SalesLine."Purch. Order Line No.");
                TempPurchaseLine := PurchaseOrderLine;
                TempPurchaseLine.Insert();

                TempPurchaseHeader."Document Type" := TempPurchaseHeader."Document Type"::Order;
                TempPurchaseHeader."No." := SalesLine."Purchase Order No.";
                if TempPurchaseHeader.Insert() then;
            until SalesLine.Next() = 0;

        if TempPurchaseHeader.FindSet() then
            repeat
                PurchaseHeader.Get(PurchaseHeader."Document Type"::Order, TempPurchaseHeader."No.");
                TempPurchaseLine.SetRange("Document No.", TempPurchaseHeader."No.");
                CheckDimensions.CheckPurchDim(PurchaseHeader, TempPurchaseLine);
            until TempPurchaseHeader.Next() = 0;
    end;

    local procedure NeedUpdateGenProdPostingGroupOnItemChargeOnSalesLine(SalesLine: Record "Sales Line"): Boolean
    var
        NeedUpdate: Boolean;
        IsHandled: Boolean;
    begin
        NeedUpdate := true;
        IsHandled := false;
        OnNeedUpdateGenProdPostingGroupOnItemChargeOnSalesLine(SalesLine, NeedUpdate, IsHandled);
        if IsHandled then
            exit(NeedUpdate);

        if SalesLine.Type <> SalesLine.Type::"Charge (Item)" then
            exit(false);
        if SalesLine."No." = '' then
            exit(false);
        if ((SalesLine.Type = SalesLine.Type::"Charge (Item)") and (SalesLine."Gen. Prod. Posting Group" <> '')) then
            exit(false);

        exit(true);
    end;

    local procedure NeedUpdateGenProdPostingGroupOnItemChargeOnSalesShipmentLine(SalesShipmentLine: Record "Sales Shipment Line"): Boolean
    var
        NeedUpdate: Boolean;
        IsHandled: Boolean;
    begin
        NeedUpdate := true;
        IsHandled := false;
        OnNeedUpdateGenProdPostingGroupOnItemChargeOnSalesShipmentLine(SalesShipmentLine, NeedUpdate, IsHandled);
        if IsHandled then
            exit(NeedUpdate);

        if SalesShipmentLine.Type <> SalesShipmentLine.Type::"Charge (Item)" then
            exit(false);
        if SalesShipmentLine."No." = '' then
            exit(false);
        if ((SalesShipmentLine.Type = SalesShipmentLine.Type::"Charge (Item)") and (SalesShipmentLine."Gen. Prod. Posting Group" <> '')) then
            exit(false);

        exit(true);
    end;

    local procedure NeedUpdateGenProdPostingGroupOnItemChargeOnReturnRecepitLine(ReturnReceiptLine: Record "Return Receipt Line"): Boolean
    var
        NeedUpdate: Boolean;
        IsHandled: Boolean;
    begin
        NeedUpdate := true;
        IsHandled := false;
        OnNeedUpdateGenProdPostingGroupOnItemChargeOnReturnReceiptLine(ReturnReceiptLine, NeedUpdate, IsHandled);
        if IsHandled then
            exit(NeedUpdate);

        if ReturnReceiptLine.Type <> ReturnReceiptLine.Type::"Charge (Item)" then
            exit(false);
        if ReturnReceiptLine."No." = '' then
            exit(false);
        if ((ReturnReceiptLine.Type = ReturnReceiptLine.Type::"Charge (Item)") and (ReturnReceiptLine."Gen. Prod. Posting Group" <> '')) then
            exit(false);

        exit(true);
    end;

    local procedure CheckDefaultNoSeries(NoSeriesCode: Code[20])
    var
        NoSeries: Record "No. Series";
    begin
        if NoSeries.Get(NoSeriesCode) then
            NoSeries.TestField("Default Nos.", true);
    end;

    local procedure CheckVATDate(var SalesHeader: Record "Sales Header")
    begin
        // ensure VAT Date is filled in
        if SalesHeader."VAT Reporting Date" = 0D then begin
            SalesHeader."VAT Reporting Date" := GLSetup.GetVATDate(SalesHeader."Posting Date", SalesHeader."Document Date");
            SalesHeader.Modify();
        end;
    end;

    local procedure ArchiveRelatedJob(SalesHeader: Record "Sales Header")
    var
        Job: Record Job;
        SalesLine: Record "Sales Line";
        JobArchiveManagement: Codeunit "Job Archive Management";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeArchiveRelatedJob(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        SalesLine.SetFilter("Job No.", '<>%1', '');
        if not SalesLine.FindFirst() then
            exit;

        if Job.Get(SalesLine."Job No.") then
            JobArchiveManagement.AutoArchiveJob(Job);
    end;

    local procedure IsInvoiceRoundingLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"): Boolean
    var
        CustomerPostingGroup: Record "Customer Posting Group";
    begin
        if SalesLine.Type <> SalesLine.Type::"G/L Account" then
            exit(false);

        CustomerPostingGroup.Get(SalesHeader."Customer Posting Group");
        if SalesLine."No." = CustomerPostingGroup."Invoice Rounding Account" then
            exit(true);

        exit(false);
    end;

    local procedure UpdateSalesOrderLineIfExist(DocumentNo: Code[20])
    var
        SalesCreditMemoHeader: Record "Sales Cr.Memo Header";
        CorrectPostedSalesInvoice: Codeunit "Correct Posted Sales Invoice";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateSalesOrderLineIfExist(DocumentNo, IsHandled);
        if IsHandled then
            exit;

        SalesCreditMemoHeader.SetLoadFields("Return Order No.", "No.");
        SalesCreditMemoHeader.SetRange("Return Order No.", DocumentNo);
        if SalesCreditMemoHeader.FindFirst() then
            CorrectPostedSalesInvoice.UpdateSalesOrderLineIfExist(SalesCreditMemoHeader."No.");
    end;

    /// <summary>
    /// Raised before updating a sales order line from a posted sales return order.
    /// </summary>
    /// <param name="DocumentNo">The number of the sales return order.</param>
    /// <param name="IsHandled">Set to true to skip the default sales order line update.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateSalesOrderLineIfExist(DocumentNo: Code[20]; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting sales lines.
    /// </summary>
    /// <param name="SalesLine">The sales line to be posted.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="ItemJnlPostLine">The item journal post line codeunit instance.</param>
    /// <param name="TempWarehouseReceiptHeader">The temporary warehouse receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostLines(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; PreviewMode: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; var TempWarehouseReceiptHeader: Record "Warehouse Receipt Header" temporary)
    begin
    end;

    /// <summary>
    /// Raised before posting a sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header to be posted.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="HideProgressWindow">Indicates whether to hide the progress window.</param>
    /// <param name="IsHandled">Set to true to skip the default posting logic.</param>
    /// <param name="CalledBy">Identifies the caller of the posting routine.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforePostSalesDoc(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; PreviewMode: Boolean; var HideProgressWindow: Boolean; var IsHandled: Boolean; var CalledBy: Integer)
    begin
    end;

    /// <summary>
    /// Raised before checking item tracking quantity on a sales line.
    /// </summary>
    /// <param name="SalesLine">The sales line to check.</param>
    /// <param name="IsHandled">Set to true to skip the default quantity check.</param>
    /// <param name="SalesHeader">The sales header of the document being posted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckItemTrackingQuantity(SalesLine: Record "Sales Line"; var IsHandled: Boolean; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before checking the tracking specification for a sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="TempItemSalesLine">The temporary sales line with item tracking.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckTrackingSpecification(SalesHeader: Record "Sales Header"; var TempItemSalesLine: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised before checking the certificate of supply status for a shipment.
    /// </summary>
    /// <param name="SalesShipmentHeader">The sales shipment header.</param>
    /// <param name="SalesShipmentLine">The sales shipment line.</param>
    /// <param name="IsHandled">Set to true to skip the default status check.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckCertificateOfSupplyStatus(SalesShipmentHeader: Record "Sales Shipment Header"; SalesShipmentLine: Record "Sales Shipment Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before committing the posted sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="ModifyHeader">Indicates whether the header should be modified.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="TempSalesLineGlobal">The temporary sales lines being posted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostCommitSalesDoc(var SalesHeader: Record "Sales Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; PreviewMode: Boolean; var ModifyHeader: Boolean; var CommitIsSuppressed: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised before determining end loop condition for received but not invoiced items.
    /// </summary>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="ReturnReceiptLine">The return receipt line being processed.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="EndLoop">Indicates whether to end the loop.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsEndLoopForReceivedNotInvoiced(RemQtyToBeInvoiced: Decimal; TrackingSpecificationExists: Boolean; var ReturnReceiptLine: Record "Return Receipt Line"; var TempTrackingSpecification: Record "Tracking Specification"; SalesLine: Record "Sales Line"; var EndLoop: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after calculating the prepayment VAT portion during prepayment amount adjustment.
    /// </summary>
    /// <param name="PrepmtVATPart">The calculated prepayment VAT portion.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAdjustPrepmtAmountLCYOnAfterCalcPrepmtVATPart(var PrepmtVATPart: Decimal; SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised after calculating whether a new invoice is required.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales lines being processed.</param>
    /// <param name="NewInvoice">Indicates whether a new invoice will be created.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCalcInvoice(var TempSalesLine: Record "Sales Line" temporary; var NewInvoice: Boolean; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after checking the sales document for posting readiness.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was checked.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is required.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is required.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="ErrorMessageMgt">The error message management codeunit for handling errors.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckSalesDoc(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; WhseShip: Boolean; WhseReceive: Boolean; PreviewMode: Boolean; var ErrorMessageMgt: Codeunit "Error Message Management")
    begin
    end;

    /// <summary>
    /// Raised after checking and updating the sales header for posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was checked and updated.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckAndUpdate(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after checking tracking and warehouse requirements for receiving.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="Receive">Indicates whether receiving is required.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="TempSalesLine">The temporary sales lines being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckTrackingAndWarehouseForReceive(var SalesHeader: Record "Sales Header"; var Receive: Boolean; CommitIsSuppressed: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; var TempSalesLine: record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after checking tracking and warehouse requirements for shipping.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="Ship">Indicates whether shipping is required.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="TempSalesLine">The temporary sales lines being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckTrackingAndWarehouseForShip(var SalesHeader: Record "Sales Header"; var Ship: Boolean; CommitIsSuppressed: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;


    /// <summary>
    /// Raised after creating a warehouse journal line.
    /// </summary>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="TempWhseJnlLine">The temporary warehouse journal line that was created.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCreateWhseJnlLine(var SalesLine: Record "Sales Line"; var TempWhseJnlLine: Record "Warehouse Journal Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after copying sales lines to temporary lines.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales lines that were populated.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyToTempLines(var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after deleting documents after posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was posted.</param>
    /// <param name="SalesInvoiceHeader">The posted sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The posted sales credit memo header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterDeleteAfterPosting(SalesHeader: Record "Sales Header"; SalesInvoiceHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after retrieving the general ledger setup.
    /// </summary>
    /// <param name="GLSetup">The general ledger setup that was retrieved.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterGetGLSetup(var GLSetup: Record "General Ledger Setup")
    begin
    end;

    /// <summary>
    /// Raised after retrieving sales lines for posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="NewSalesLine">The new sales line record.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterGetSalesLines(var SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: record "Sales Line"; var NewSalesLine: record "Sales Line");
    begin
    end;

    /// <summary>
    /// Raised after retrieving line data from the sales order.
    /// </summary>
    /// <param name="SalesLine">The sales line being populated.</param>
    /// <param name="SalesOrderLine">The source sales order line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterGetLineDataFromOrder(var SalesLine: Record "Sales Line"; SalesOrderLine: Record "Sales Line")
    begin
    end;


    /// <summary>
    /// Raised after retrieving the sales and receivables setup.
    /// </summary>
    /// <param name="SalesSetup">The sales and receivables setup that was retrieved.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterGetSalesSetup(var SalesSetup: Record "Sales & Receivables Setup")
    begin
    end;

    /// <summary>
    /// Raised before retrieving sales lines for posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="NewSalesLine">The sales line record to be populated.</param>
    /// <param name="QtyType">The quantity type to retrieve.</param>
    /// <param name="IncludePrepayments">Indicates whether to include prepayments.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetSalesLines(var SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; QtyType: Option; IncludePrepayments: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before retrieving sales lines into temporary records.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="NewSalesLine">The new sales line record.</param>
    /// <param name="OldSalesLine">The original sales line record.</param>
    /// <param name="QtyType">The quantity type to retrieve.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetSalesLinesTemp(var SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; var OldSalesLine: Record "Sales Line"; QtyType: Option)
    begin
    end;


    /// <summary>
    /// Raised after incrementing the total amount with a sales line.
    /// </summary>
    /// <param name="TotalSalesLine">The total sales line being accumulated.</param>
    /// <param name="SalesLine">The sales line being added to the total.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterIncrAmount(var TotalSalesLine: Record "Sales Line"; SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after initializing an associated item journal line for drop shipment.
    /// </summary>
    /// <param name="ItemJournalLine">The item journal line that was initialized.</param>
    /// <param name="PurchaseHeader">The associated purchase header.</param>
    /// <param name="PurchaseLine">The associated purchase line.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="QtyToBeShipped">The quantity to be shipped.</param>
    /// <param name="QtyToBeShippedBase">The quantity to be shipped in base unit of measure.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInitAssocItemJnlLine(var ItemJournalLine: Record "Item Journal Line"; PurchaseHeader: Record "Purchase Header"; PurchaseLine: Record "Purchase Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; QtyToBeShippedBase: Decimal)
    begin
    end;

    /// <summary>
    /// Raised after calculating the invoice rounding amount.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line for invoice rounding.</param>
    /// <param name="TotalSalesLine">The total sales line amounts.</param>
    /// <param name="UseTempData">Indicates whether to use temporary data.</param>
    /// <param name="InvoiceRoundingAmount">The calculated invoice rounding amount.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="Currency">The currency used for rounding.</param>
    /// <param name="BiggestLineNo">The biggest line number in the document.</param>
    /// <param name="LastLineRetrieved">Indicates whether the last line was retrieved.</param>
    /// <param name="RoundingLineInserted">Indicates whether a rounding line was inserted.</param>
    /// <param name="RoundingLineNo">The line number of the rounding line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInvoiceRoundingAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TotalSalesLine: Record "Sales Line"; UseTempData: Boolean; InvoiceRoundingAmount: Decimal; CommitIsSuppressed: Boolean; Currency: Record Currency; var BiggestLineNo: Integer; var LastLineRetrieved: Boolean; var RoundingLineInserted: Boolean; var RoundingLineNo: Integer)
    begin
    end;

    /// <summary>
    /// Raised after inserting a drop shipment purchase receipt header.
    /// </summary>
    /// <param name="PurchRcptHeader">The purchase receipt header that was inserted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertDropOrderPurchRcptHeader(var PurchRcptHeader: Record "Purch. Rcpt. Header")
    begin
    end;

    /// <summary>
    /// Raised after inserting a sales credit memo header.
    /// </summary>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header that was inserted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertCrMemoHeader(var SalesHeader: Record "Sales Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

    /// <summary>
    /// Raised after inserting a sales invoice header.
    /// </summary>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SalesInvHeader">The sales invoice header that was inserted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertInvoiceHeader(var SalesHeader: Record "Sales Header"; var SalesInvHeader: Record "Sales Invoice Header")
    begin
    end;

    /// <summary>
    /// Raised after inserting the prepayment VAT base to deduct.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="PrepmtLineNo">The prepayment line number.</param>
    /// <param name="TotalPrepmtAmtToDeduct">The total prepayment amount to deduct.</param>
    /// <param name="TempPrepmtDeductLCYSalesLine">The temporary prepayment deduction line in LCY.</param>
    /// <param name="PrepmtVATBaseToDeduct">The prepayment VAT base amount to deduct.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertedPrepmtVATBaseToDeduct(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; PrepmtLineNo: Integer; TotalPrepmtAmtToDeduct: Decimal; var TempPrepmtDeductLCYSalesLine: Record "Sales Line" temporary; var PrepmtVATBaseToDeduct: Decimal)
    begin
    end;

    /// <summary>
    /// Raised after inserting all posted headers (shipment, invoice, credit memo, receipt).
    /// </summary>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SalesShipmentHeader">The posted sales shipment header.</param>
    /// <param name="SalesInvoiceHeader">The posted sales invoice header.</param>
    /// <param name="SalesCrMemoHdr">The posted sales credit memo header.</param>
    /// <param name="ReceiptHeader">The posted return receipt header.</param>
    /// <param name="GenJournalDocumentType">The general journal document type.</param>
    /// <param name="GenJnlLineDocNo">The general journal line document number.</param>
    /// <param name="GenJnlLineExtDocNo">The general journal line external document number.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertPostedHeaders(var SalesHeader: Record "Sales Header"; var SalesShipmentHeader: Record "Sales Shipment Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHdr: Record "Sales Cr.Memo Header"; var ReceiptHeader: Record "Return Receipt Header"; var GenJournalDocumentType: Enum "Gen. Journal Document Type"; var GenJnlLineDocNo: Code[20]; var GenJnlLineExtDocNo: Code[35])
    begin
    end;

    /// <summary>
    /// Raised after inserting a sales shipment header.
    /// </summary>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SalesShipmentHeader">The sales shipment header that was inserted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertShipmentHeader(var SalesHeader: Record "Sales Header"; var SalesShipmentHeader: Record "Sales Shipment Header")
    begin
    end;

    /// <summary>
    /// Raised after inserting a sales shipment line.
    /// </summary>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="SalesShptLine">The sales shipment line that was inserted.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="xSalesLine">The original sales line before modification.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertShipmentLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var SalesShptLine: record "Sales Shipment Line"; PreviewMode: Boolean; xSalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised after inserting a return receipt line for warehouse posting.
    /// </summary>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="xSalesLine">The original sales line before modification.</param>
    /// <param name="ReturnReceiptLine">The return receipt line that was inserted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertReturnReceiptLineWhsePost(var SalesLine: Record "Sales Line"; xSalesLine: Record "Sales Line"; var ReturnReceiptLine: Record "Return Receipt Line")
    begin
    end;

    /// <summary>
    /// Raised after posting a drop shipment order.
    /// </summary>
    /// <param name="TempDropShptPostBuffer">The temporary drop shipment posting buffer.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostDropOrderShipment(var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    begin
    end;

    /// <summary>
    /// Raised after posting a sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was posted.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="SalesShptHdrNo">The posted sales shipment header number.</param>
    /// <param name="RetRcpHdrNo">The posted return receipt header number.</param>
    /// <param name="SalesInvHdrNo">The posted sales invoice header number.</param>
    /// <param name="SalesCrMemoHdrNo">The posted sales credit memo header number.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="InvtPickPutaway">Indicates whether inventory pick/put-away is involved.</param>
    /// <param name="CustLedgerEntry">The customer ledger entry that was created.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment was processed.</param>
    /// <param name="WhseReceiv">Indicates whether warehouse receipt was processed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostSalesDoc(var SalesHeader: Record "Sales Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; SalesShptHdrNo: Code[20]; RetRcpHdrNo: Code[20]; SalesInvHdrNo: Code[20]; SalesCrMemoHdrNo: Code[20]; CommitIsSuppressed: Boolean; InvtPickPutaway: Boolean; var CustLedgerEntry: Record "Cust. Ledger Entry"; WhseShip: Boolean; WhseReceiv: Boolean; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after updating the order line after posting.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales line that was updated.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostUpdateOrderLine(var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after posting a sales document with drop shipment.
    /// </summary>
    /// <param name="PurchRcptNo">The purchase receipt number for the drop shipment.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostSalesDocDropShipment(PurchRcptNo: Code[20]; CommitIsSuppressed: Boolean)
    begin
    end;


    /// <summary>
    /// Raised after posting an item journal line for a sales line.
    /// </summary>
    /// <param name="ItemJournalLine">The item journal line that was posted.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="ItemJnlPostLine">The item journal post line codeunit instance.</param>
    /// <param name="WhseJnlPostLine">The warehouse journal register line codeunit instance.</param>
    /// <param name="OriginalItemJnlLine">The original item journal line before posting.</param>
    /// <param name="ItemShptEntryNo">The item shipment entry number.</param>
    /// <param name="IsATO">Indicates whether this is an assemble-to-order transaction.</param>
    /// <param name="TempHandlingSpecification">The temporary handling tracking specification.</param>
    /// <param name="TempATOTrackingSpecification">The temporary ATO tracking specification.</param>
    /// <param name="TempWarehouseJournalLine">The temporary warehouse journal line.</param>
    /// <param name="ShouldPostItemJnlLine">Indicates whether the item journal line should be posted.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseRcptHeader">The warehouse receipt header.</param>
    [IntegrationEvent(true, false)]
    local procedure OnAfterPostItemJnlLine(var ItemJournalLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; var WhseJnlPostLine: Codeunit "Whse. Jnl.-Register Line"; OriginalItemJnlLine: Record "Item Journal Line"; var ItemShptEntryNo: Integer; IsATO: Boolean; var TempHandlingSpecification: Record "Tracking Specification"; var TempATOTrackingSpecification: Record "Tracking Specification"; TempWarehouseJournalLine: Record "Warehouse Journal Line" temporary; ShouldPostItemJnlLine: Boolean; WhseShip: Boolean; WhseRcptHeader: Record "Warehouse Receipt Header"; WarehouseShipmentHeader: Record "Warehouse Shipment Header")
    begin
    end;

    /// <summary>
    /// Raised after posting all sales lines.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesShipmentHeader">The sales shipment header.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="ReturnReceiptHeader">The return receipt header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment was processed.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt was processed.</param>
    /// <param name="SalesLinesProcessed">Indicates whether sales lines were processed.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="EverythingInvoiced">Indicates whether all lines were invoiced.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostSalesLines(var SalesHeader: Record "Sales Header"; var SalesShipmentHeader: Record "Sales Shipment Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var ReturnReceiptHeader: Record "Return Receipt Header"; WhseShip: Boolean; WhseReceive: Boolean; var SalesLinesProcessed: Boolean; CommitIsSuppressed: Boolean; EverythingInvoiced: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after posting a sales line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line that was posted.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesInvLine">The sales invoice line that was created.</param>
    /// <param name="SalesCrMemoLine">The sales credit memo line that was created.</param>
    /// <param name="xSalesLine">The original sales line before posting.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostSalesLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean; var SalesInvLine: Record "Sales Invoice Line"; var SalesCrMemoLine: Record "Sales Cr.Memo Line"; var xSalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised after updating the invoice line during post update processing.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales line that was updated.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TempSalesOrderHeader">The temporary sales order header.</param>
    [IntegrationEvent(true, false)]
    local procedure OnAfterPostUpdateInvoiceLine(var TempSalesLine: Record "Sales Line" temporary; var SalesHeader: Record "Sales Header"; var TempSalesOrderHeader: Record "Sales Header" temporary)
    begin
    end;

    /// <summary>
    /// Raised after updating the return receipt line during post update processing.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales line that was updated.</param>
    [IntegrationEvent(true, false)]
    local procedure OnAfterPostUpdateReturnReceiptLine(var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after updating item charge assignments.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was updated.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateItemChargeAssgnt(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after updating posting numbers.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was updated.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdatePostingNos(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after updating the return receipt number.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was updated.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateReturnReceiptNo(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after updating the shipping number.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was updated.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="ModifyHeader">Indicates whether the header should be modified.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateShippingNo(var SalesHeader: Record "Sales Header"; PreviewMode: Boolean; var ModifyHeader: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after updating won opportunities.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was posted.</param>
    /// <param name="SalesInvoiceHeader">The posted sales invoice header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateWonOpportunities(var SalesHeader: Record "Sales Header"; var SalesInvoiceHeader: Record "Sales Invoice Header")
    begin
    end;

    /// <summary>
    /// Raised after checking mandatory fields.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was checked.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckMandatoryFields(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after inserting the sales invoice header.
    /// </summary>
    /// <param name="SalesInvHeader">The sales invoice header that was inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterSalesInvHeaderInsert(var SalesInvHeader: Record "Sales Invoice Header"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; WhseShip: Boolean; WhseReceive: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header"; var TempWhseRcptHeader: Record "Warehouse Receipt Header"; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after inserting a sales invoice line.
    /// </summary>
    /// <param name="SalesInvLine">The sales invoice line that was inserted.</param>
    /// <param name="SalesInvHeader">The sales invoice header.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="ItemLedgShptEntryNo">The item ledger shipment entry number.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="TempItemChargeAssgntSales">The temporary item charge assignment records.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterSalesInvLineInsert(var SalesInvLine: Record "Sales Invoice Line"; SalesInvHeader: Record "Sales Invoice Header"; SalesLine: Record "Sales Line"; ItemLedgShptEntryNo: Integer; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean; var SalesHeader: Record "Sales Header"; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after inserting the sales credit memo header.
    /// </summary>
    /// <param name="SalesCrMemoHeader">The sales credit memo header that was inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterSalesCrMemoHeaderInsert(var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; WhseShip: Boolean; WhseReceive: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header"; var TempWhseRcptHeader: Record "Warehouse Receipt Header")
    begin
    end;

    /// <summary>
    /// Raised after inserting a sales credit memo line.
    /// </summary>
    /// <param name="SalesCrMemoLine">The sales credit memo line that was inserted.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="TempItemChargeAssgntSales">The temporary item charge assignment records.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterSalesCrMemoLineInsert(var SalesCrMemoLine: Record "Sales Cr.Memo Line"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; CommitIsSuppressed: Boolean; WhseShip: Boolean; WhseReceive: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary)
    begin
    end;

    /// <summary>
    /// Raised after inserting the sales shipment header.
    /// </summary>
    /// <param name="SalesShipmentHeader">The sales shipment header that was inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SuppressCommit">Indicates whether database commits are suppressed.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterSalesShptHeaderInsert(var SalesShipmentHeader: Record "Sales Shipment Header"; SalesHeader: Record "Sales Header"; SuppressCommit: Boolean; WhseShip: Boolean; WhseReceive: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header"; var TempWhseRcptHeader: Record "Warehouse Receipt Header"; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after inserting a sales shipment line.
    /// </summary>
    /// <param name="SalesShipmentLine">The sales shipment line that was inserted.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="ItemShptLedEntryNo">The item shipment ledger entry number.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="SalesShptHeader">The sales shipment header.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterSalesShptLineInsert(var SalesShipmentLine: Record "Sales Shipment Line"; SalesLine: Record "Sales Line"; ItemShptLedEntryNo: Integer; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean; SalesInvoiceHeader: Record "Sales Invoice Header"; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; SalesShptHeader: Record "Sales Shipment Header"; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after inserting the purchase receipt header for a drop shipment.
    /// </summary>
    /// <param name="PurchRcptHeader">The purchase receipt header that was inserted.</param>
    /// <param name="PurchaseHeader">The source purchase header.</param>
    /// <param name="SalesHeader">The related sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPurchRcptHeaderInsert(var PurchRcptHeader: Record "Purch. Rcpt. Header"; PurchaseHeader: Record "Purchase Header"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after inserting a purchase receipt line for a drop shipment.
    /// </summary>
    /// <param name="PurchRcptLine">The purchase receipt line that was inserted.</param>
    /// <param name="PurchRcptHeader">The purchase receipt header.</param>
    /// <param name="PurchOrderLine">The source purchase order line.</param>
    /// <param name="DropShptPostBuffer">The drop shipment posting buffer.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPurchRcptLineInsert(var PurchRcptLine: Record "Purch. Rcpt. Line"; PurchRcptHeader: Record "Purch. Rcpt. Header"; PurchOrderLine: Record "Purchase Line"; DropShptPostBuffer: Record "Drop Shpt. Post. Buffer"; CommitIsSuppressed: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after inserting the return receipt header.
    /// </summary>
    /// <param name="ReturnReceiptHeader">The return receipt header that was inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SuppressCommit">Indicates whether database commits are suppressed.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterReturnRcptHeaderInsert(var ReturnReceiptHeader: Record "Return Receipt Header"; SalesHeader: Record "Sales Header"; SuppressCommit: Boolean; WhseShip: Boolean; WhseReceive: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header"; var TempWhseRcptHeader: Record "Warehouse Receipt Header")
    begin
    end;

    /// <summary>
    /// Raised after inserting a return receipt line.
    /// </summary>
    /// <param name="ReturnRcptLine">The return receipt line that was inserted.</param>
    /// <param name="ReturnRcptHeader">The return receipt header.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="ItemShptLedEntryNo">The item shipment ledger entry number.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterReturnRcptLineInsert(var ReturnRcptLine: Record "Return Receipt Line"; ReturnRcptHeader: Record "Return Receipt Header"; SalesLine: Record "Sales Line"; ItemShptLedEntryNo: Integer; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after finalizing the posting process.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was posted.</param>
    /// <param name="SalesShipmentHeader">The sales shipment header that was created.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header that was created.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header that was created.</param>
    /// <param name="ReturnReceiptHeader">The return receipt header that was created.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterFinalizePosting(var SalesHeader: Record "Sales Header"; var SalesShipmentHeader: Record "Sales Shipment Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var ReturnReceiptHeader: Record "Return Receipt Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; CommitIsSuppressed: Boolean; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after finalizing posting but before the database commit.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was posted.</param>
    /// <param name="SalesShipmentHeader">The sales shipment header that was created.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header that was created.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header that was created.</param>
    /// <param name="ReturnReceiptHeader">The return receipt header that was created.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment was processed.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt was processed.</param>
    /// <param name="EverythingInvoiced">Indicates whether all lines were invoiced.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterFinalizePostingOnBeforeCommit(var SalesHeader: Record "Sales Header"; var SalesShipmentHeader: Record "Sales Shipment Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var ReturnReceiptHeader: Record "Return Receipt Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var CommitIsSuppressed: Boolean; var PreviewMode: Boolean; WhseShip: Boolean; WhseReceive: Boolean; var EverythingInvoiced: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after finding lines that have not been shipped.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TempSalesLine">The temporary sales lines that have not been shipped.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterFindNotShippedLines(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after resetting temporary sales lines.
    /// </summary>
    /// <param name="TempSalesLineLocal">The temporary sales lines that were reset.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterResetTempLines(var TempSalesLineLocal: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after restoring the sales header from a copy.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was restored.</param>
    /// <param name="SalesHeaderCopy">The copy of the sales header used for restoration.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterRestoreSalesHeader(var SalesHeader: Record "Sales Header"; SalesHeaderCopy: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after updating the sales header after posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was updated.</param>
    /// <param name="TempSalesLine">The temporary sales lines.</param>
    [IntegrationEvent(true, false)]
    local procedure OnAfterUpdateAfterPosting(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after updating the last posting numbers.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was updated.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateLastPostingNos(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after updating the sales header with posting information.
    /// </summary>
    /// <param name="CustLedgerEntry">The customer ledger entry that was created.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="GenJnlLineDocType">The general journal line document type.</param>
    /// <param name="GenJnlLineDocNo">The general journal line document number.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="SalesHeader">The sales header that was updated.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateSalesHeader(var CustLedgerEntry: Record "Cust. Ledger Entry"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; GenJnlLineDocType: Integer; GenJnlLineDocNo: Code[20]; PreviewMode: Boolean; var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after updating the sales line before posting.
    /// </summary>
    /// <param name="SalesLine">The sales line that was updated.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateSalesLineBeforePost(var SalesLine: Record "Sales Line"; var SalesHeader: Record "Sales Header"; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after checking if warehouse lines exist.
    /// </summary>
    /// <param name="WhseValidateSourceLine">The warehouse validate source line codeunit instance.</param>
    /// <param name="SalesLine">The sales line being checked.</param>
    /// <param name="ShowError">Indicates whether to show an error.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterWhseLinesExist(var WhseValidateSourceLine: Codeunit "Whse. Validate Source Line"; SalesLine: Record "Sales Line"; var ShowError: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before archiving the unposted order.
    /// </summary>
    /// <param name="SalesHeader">The sales header to be archived.</param>
    /// <param name="IsHandled">Set to true to skip the default archiving logic.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="OrderArchived">Indicates whether the order was archived.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeArchiveUnpostedOrder(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; PreviewMode: Boolean; var OrderArchived: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before confirming the download of a shipment.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="Result">The result of the confirmation.</param>
    /// <param name="IsHandled">Set to true to skip the default confirmation logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeConfirmDownloadShipment(var SalesHeader: Record "Sales Header"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before creating the posted warehouse receipt header.
    /// </summary>
    /// <param name="PostedWhseReceiptHeader">The posted warehouse receipt header to be created.</param>
    /// <param name="WarehouseReceiptHeader">The source warehouse receipt header.</param>
    /// <param name="SalesHeader">The related sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreatePostedWhseRcptHeader(var PostedWhseReceiptHeader: Record "Posted Whse. Receipt Header"; WarehouseReceiptHeader: Record "Warehouse Receipt Header"; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before creating prepayment lines.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TempPrepmtSalesLine">The temporary prepayment sales lines to be created.</param>
    /// <param name="CompleteFunctionality">Indicates whether complete functionality is enabled.</param>
    /// <param name="IsHandled">Set to true to skip the default prepayment line creation.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforeCreatePrepaymentLines(var SalesHeader: Record "Sales Header"; var TempPrepmtSalesLine: Record "Sales Line" temporary; CompleteFunctionality: Boolean; var IsHandled: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised before modifying the blanket order sales line.
    /// </summary>
    /// <param name="BlanketOrderSalesLine">The blanket order sales line to be modified.</param>
    /// <param name="SalesLine">The source sales line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeBlanketOrderSalesLineModify(var BlanketOrderSalesLine: Record "Sales Line"; SalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised before creating the posted warehouse shipment header.
    /// </summary>
    /// <param name="PostedWhseShipmentHeader">The posted warehouse shipment header to be created.</param>
    /// <param name="WarehouseShipmentHeader">The source warehouse shipment header.</param>
    /// <param name="SalesHeader">The related sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreatePostedWhseShptHeader(var PostedWhseShipmentHeader: Record "Posted Whse. Shipment Header"; WarehouseShipmentHeader: Record "Warehouse Shipment Header"; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before creating a warehouse journal line.
    /// </summary>
    /// <param name="ItemJnlLine">The item journal line being processed.</param>
    /// <param name="IsHandled">Set to true to skip the default warehouse journal line creation.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateWhseJnlLine(ItemJnlLine: Record "Item Journal Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before finalizing the posting process.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="EverythingInvoiced">Indicates whether all lines were invoiced.</param>
    /// <param name="SuppressCommit">Indicates whether database commits are suppressed.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforeFinalizePosting(var SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: Record "Sales Line" temporary; var EverythingInvoiced: Boolean; SuppressCommit: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line")
    begin
    end;

    /// <summary>
    /// Raised before initializing an associated item journal line for drop shipment.
    /// </summary>
    /// <param name="ItemJournalLine">The item journal line to be initialized.</param>
    /// <param name="PurchaseHeader">The associated purchase header.</param>
    /// <param name="PurchaseLine">The associated purchase line.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInitAssocItemJnlLine(var ItemJournalLine: Record "Item Journal Line"; PurchaseHeader: Record "Purchase Header"; PurchaseLine: Record "Purchase Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised before inserting an intercompany general journal line.
    /// </summary>
    /// <param name="ICGenJournalLine">The intercompany general journal line to be inserted.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertICGenJnlLine(var ICGenJournalLine: Record "Gen. Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting posted document headers.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="TempWarehouseShipmentHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWarehouseReceiptHeader">The temporary warehouse receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertPostedHeaders(var SalesHeader: Record "Sales Header"; var TempWarehouseShipmentHeader: Record "Warehouse Shipment Header" temporary; var TempWarehouseReceiptHeader: Record "Warehouse Receipt Header" temporary)
    begin
    end;

    /// <summary>
    /// Raised before inserting the return receipt header.
    /// </summary>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="ReturnReceiptHeader">The return receipt header to be inserted.</param>
    /// <param name="Handled">Set to true to skip the default insertion logic.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertReturnReceiptHeader(SalesHeader: Record "Sales Header"; var ReturnReceiptHeader: Record "Return Receipt Header"; var Handled: Boolean; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting a return receipt line during warehouse posting.
    /// </summary>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="ReturnRcptHeader">The return receipt header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    /// <param name="ReturnRcptLine">The return receipt line to be inserted.</param>
    /// <param name="xSalesLine">The original sales line before modification.</param>
    /// <param name="PostedWhseRcptHeader">The posted warehouse receipt header.</param>
    /// <param name="WhseRcptHeader">The warehouse receipt header.</param>
    /// <param name="CostBaseAmount">The cost base amount.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertReturnReceiptLineWhsePost(SalesLine: Record "Sales Line"; ReturnRcptHeader: Record "Return Receipt Header"; WhseShip: Boolean; WhseReceive: Boolean; TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; var IsHandled: Boolean; var ReturnRcptLine: Record "Return Receipt Line"; var xSalesLine: Record "Sales Line"; PostedWhseRcptHeader: Record "Posted Whse. Receipt Header"; WhseRcptHeader: Record "Warehouse Receipt Header"; var CostBaseAmount: Decimal)
    begin
    end;

    /// <summary>
    /// Raised before inserting the return entry relation.
    /// </summary>
    /// <param name="ReturnRcptLine">The return receipt line.</param>
    /// <param name="EntryNo">The entry number.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertReturnEntryRelation(var ReturnRcptLine: Record "Return Receipt Line"; var EntryNo: Integer; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting the shipment entry relation.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="ItemShptEntryNo">The item shipment entry number.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertShptEntryRelation(SalesHeader: Record "Sales Header"; var SalesShptLine: Record "Sales Shipment Line"; var ItemShptEntryNo: Integer; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting the sales invoice header.
    /// </summary>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="SalesInvHeader">The sales invoice header to be inserted.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertInvoiceHeader(SalesHeader: Record "Sales Header"; var SalesInvHeader: Record "Sales Invoice Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before calculating the invoice rounding amount.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TotalAmountIncludingVAT">The total amount including VAT.</param>
    /// <param name="UseTempData">Indicates whether temporary data is being used.</param>
    /// <param name="InvoiceRoundingAmount">The invoice rounding amount.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="TotalSalesLine">The total sales line record.</param>
    /// <param name="Currency">The currency record.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInvoiceRoundingAmount(SalesHeader: Record "Sales Header"; TotalAmountIncludingVAT: Decimal; UseTempData: Boolean; var InvoiceRoundingAmount: Decimal; CommitIsSuppressed: Boolean; var TotalSalesLine: Record "Sales Line"; var Currency: Record Currency)
    begin
    end;

    /// <summary>
    /// Raised before determining if the loop should end for shipped but not invoiced items.
    /// </summary>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="HasATOShippedNotInvoiced">Indicates whether there are assemble-to-order items shipped but not invoiced.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="InvoicingTrackingSpecification">The invoicing tracking specification.</param>
    /// <param name="ItemLedgEntryNotInvoiced">The item ledger entry not invoiced.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="Result">The result indicating whether to end the loop.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsEndLoopForShippedNotInvoiced(RemQtyToBeInvoiced: Decimal; TrackingSpecificationExists: Boolean; var HasATOShippedNotInvoiced: Boolean; var SalesShptLine: Record "Sales Shipment Line"; var InvoicingTrackingSpecification: Record "Tracking Specification"; var ItemLedgEntryNotInvoiced: Record "Item Ledger Entry"; SalesLine: Record "Sales Line"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting the item journal line.
    /// </summary>
    /// <param name="ItemJournalLine">The item journal line to be posted.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default posting logic.</param>
    /// <param name="TempItemChargeAssgntSales">The temporary item charge assignment records.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeItemJnlPostLine(var ItemJournalLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var IsHandled: Boolean; TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary)
    begin
    end;

    /// <summary>
    /// Raised before handling the archiving of an unposted order.
    /// </summary>
    /// <param name="SalesHeader">The sales header to be archived.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="IsHandled">Set to true to skip the default archiving logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeHandleArchiveUnpostedOrder(var SalesHeader: Record "Sales Header"; PreviewMode: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before locking database tables.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default table locking logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeLockTables(var SalesHeader: Record "Sales Header"; PreviewMode: Boolean; CommitIsSuppressed: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before making inventory adjustment during the Run procedure.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesInvHeader">The sales invoice header.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="ItemJnlPostLine">The item journal post line codeunit instance.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="SkipInventoryAdjustment">Indicates whether to skip the inventory adjustment.</param>
    [IntegrationEvent(false, false)]
    local procedure OnRunOnBeforeMakeInventoryAdjustment(var SalesHeader: Record "Sales Header"; SalesInvHeader: Record "Sales Invoice Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; PreviewMode: Boolean; var SkipInventoryAdjustment: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting the intercompany general journal during the Run procedure.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="SrcCode">The source code.</param>
    /// <param name="GenJnlLineDocType">The general journal line document type.</param>
    /// <param name="GenJnlLineDocNo">The general journal line document number.</param>
    /// <param name="ReturnReceiptHeader">The return receipt header.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnRunOnBeforePostICGenJnl(var SalesHeader: Record "Sales Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var SrcCode: Code[10]; var GenJnlLineDocType: Enum "Gen. Journal Document Type"; GenJnlLineDocNo: Code[20]; var ReturnReceiptHeader: Record "Return Receipt Header"; var PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before preparing to check the document.
    /// </summary>
    /// <param name="SalesHeader">The sales header to be checked.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePrepareCheckDocument(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before processing the associated item journal line for drop shipment.
    /// </summary>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="IsHandled">Set to true to skip the default processing logic.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="TempDropShptPostBuffer">The temporary drop shipment posting buffer.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeProcessAssocItemJnlLine(var SalesLine: Record "Sales Line"; var IsHandled: Boolean; var SalesHeader: Record "Sales Header"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    begin
    end;

    /// <summary>
    /// Raised before deleting all sales lines.
    /// </summary>
    /// <param name="SalesLine">The sales line record set to be deleted.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSalesLineDeleteAll(var SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean; var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before inserting the sales shipment header.
    /// </summary>
    /// <param name="SalesShptHeader">The sales shipment header to be inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="InvtPickPutaway">Indicates whether inventory pick/put-away is involved.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSalesShptHeaderInsert(var SalesShptHeader: Record "Sales Shipment Header"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var IsHandled: Boolean; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; WhseReceive: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; WhseShip: Boolean; InvtPickPutaway: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting a sales shipment line.
    /// </summary>
    /// <param name="SalesShptLine">The sales shipment line to be inserted.</param>
    /// <param name="SalesShptHeader">The sales shipment header.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PostedWhseShipmentLine">The posted warehouse shipment line.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="ItemLedgShptEntryNo">The item ledger shipment entry number.</param>
    /// <param name="xSalesLine">The original sales line before modification.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSalesShptLineInsert(var SalesShptLine: Record "Sales Shipment Line"; SalesShptHeader: Record "Sales Shipment Header"; SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean; PostedWhseShipmentLine: Record "Posted Whse. Shipment Line"; SalesHeader: Record "Sales Header"; WhseShip: Boolean; WhseReceive: Boolean; ItemLedgShptEntryNo: Integer; xSalesLine: record "Sales Line"; var TempSalesLineGlobal: record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting the sales invoice header.
    /// </summary>
    /// <param name="SalesInvHeader">The sales invoice header to be inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseShptHeader">The warehouse shipment header.</param>
    /// <param name="InvtPickPutaway">Indicates whether inventory pick/put-away is involved.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSalesInvHeaderInsert(var SalesInvHeader: Record "Sales Invoice Header"; var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var IsHandled: Boolean; WhseShip: Boolean; WhseShptHeader: Record "Warehouse Shipment Header"; InvtPickPutaway: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting a sales invoice line.
    /// </summary>
    /// <param name="SalesInvLine">The sales invoice line to be inserted.</param>
    /// <param name="SalesInvHeader">The sales invoice header.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    /// <param name="PostingSalesLine">The posting sales line.</param>
    /// <param name="SalesShipmentHeader">The sales shipment header.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="ReturnReceiptHeader">The return receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSalesInvLineInsert(var SalesInvLine: Record "Sales Invoice Line"; SalesInvHeader: Record "Sales Invoice Header"; SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean; var IsHandled: Boolean; PostingSalesLine: Record "Sales Line"; SalesShipmentHeader: Record "Sales Shipment Header"; SalesHeader: Record "Sales Header"; var ReturnReceiptHeader: Record "Return Receipt Header")
    begin
    end;

    /// <summary>
    /// Raised before inserting the sales credit memo header.
    /// </summary>
    /// <param name="SalesCrMemoHeader">The sales credit memo header to be inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    /// <param name="SalesInvHeader">The sales invoice header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSalesCrMemoHeaderInsert(var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var IsHandled: Boolean; var SalesInvHeader: Record "Sales Invoice Header")
    begin
    end;

    /// <summary>
    /// Raised before inserting a sales credit memo line.
    /// </summary>
    /// <param name="SalesCrMemoLine">The sales credit memo line to be inserted.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesShptHeader">The sales shipment header.</param>
    /// <param name="ReturnRcptHeader">The return receipt header.</param>
    /// <param name="PostingSalesLine">The posting sales line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSalesCrMemoLineInsert(var SalesCrMemoLine: Record "Sales Cr.Memo Line"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean; var IsHandled: Boolean; var SalesHeader: Record "Sales Header"; var SalesShptHeader: Record "Sales Shipment Header"; var ReturnRcptHeader: Record "Return Receipt Header"; var PostingSalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised before inserting the purchase receipt header for a drop shipment.
    /// </summary>
    /// <param name="PurchRcptHeader">The purchase receipt header to be inserted.</param>
    /// <param name="PurchaseHeader">The source purchase header.</param>
    /// <param name="SalesHeader">The related sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="RunOnInsert">Indicates whether to run the OnInsert trigger.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePurchRcptHeaderInsert(var PurchRcptHeader: Record "Purch. Rcpt. Header"; PurchaseHeader: Record "Purchase Header"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var RunOnInsert: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting a purchase receipt line for a drop shipment.
    /// </summary>
    /// <param name="PurchRcptLine">The purchase receipt line to be inserted.</param>
    /// <param name="PurchRcptHeader">The purchase receipt header.</param>
    /// <param name="PurchOrderLine">The source purchase order line.</param>
    /// <param name="DropShptPostBuffer">The drop shipment posting buffer.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="IsHandled">Set to true to skip the default insertion logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePurchRcptLineInsert(var PurchRcptLine: Record "Purch. Rcpt. Line"; PurchRcptHeader: Record "Purch. Rcpt. Header"; PurchOrderLine: Record "Purchase Line"; DropShptPostBuffer: Record "Drop Shpt. Post. Buffer"; CommitIsSuppressed: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before releasing the sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header to be released.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeReleaseSalesDocument(SalesHeader: Record "Sales Header"; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting the return receipt header.
    /// </summary>
    /// <param name="ReturnRcptHeader">The return receipt header to be inserted.</param>
    /// <param name="SalesHeader">The source sales header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeReturnRcptHeaderInsert(var ReturnRcptHeader: Record "Return Receipt Header"; SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; WhseReceive: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; WhseShip: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting a return receipt line.
    /// </summary>
    /// <param name="ReturnRcptLine">The return receipt line to be inserted.</param>
    /// <param name="ReturnRcptHeader">The return receipt header.</param>
    /// <param name="SalesLine">The source sales line.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="xSalesLine">The original sales line before modification.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="SalesHeader">The sales header being posted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeReturnRcptLineInsert(var ReturnRcptLine: Record "Return Receipt Line"; ReturnRcptHeader: Record "Return Receipt Header"; SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean; xSalesLine: record "Sales Line"; var TempSalesLineGlobal: record "Sales Line" temporary; var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before posting the job contract line for a sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="IsHandled">Set to true to skip the default job contract line posting.</param>
    /// <param name="JobContractLine">Indicates whether this is a job contract line.</param>
    /// <param name="InvoicePostingInterface">The invoice posting interface.</param>
    /// <param name="SalesLineACY">The sales line in additional currency.</param>
    /// <param name="SalesInvHeader">The posted sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The posted sales credit memo header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostJobContractLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var IsHandled: Boolean; var JobContractLine: Boolean; var InvoicePostingInterface: Interface "Invoice Posting"; SalesLineACY: Record "Sales Line"; SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

    /// <summary>
    /// Raised before posting the associated item journal line for drop shipments.
    /// </summary>
    /// <param name="ItemJournalLine">The item journal line to be posted.</param>
    /// <param name="PurchaseLine">The associated purchase line.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="IsHandled">Set to true to skip the default posting logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostAssocItemJnlLine(var ItemJournalLine: Record "Item Journal Line"; var PurchaseLine: Record "Purchase Line"; CommitIsSuppressed: Boolean; var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting the item journal line for a sales line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="QtyToBeShipped">The quantity to be shipped.</param>
    /// <param name="QtyToBeShippedBase">The quantity to be shipped in base unit of measure.</param>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    /// <param name="ItemLedgShptEntryNo">The item ledger shipment entry number.</param>
    /// <param name="ItemChargeNo">The item charge number.</param>
    /// <param name="TrackingSpecification">The tracking specification.</param>
    /// <param name="IsATO">Indicates whether this is an assemble-to-order line.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default posting logic.</param>
    /// <param name="Result">The result of the posting operation.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="TempHandlingSpecification">The temporary handling specification.</param>
    /// <param name="TempValueEntryRelation">The temporary value entry relation.</param>
    /// <param name="ItemJnlPostLine">The item journal post line codeunit instance.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforePostItemJnlLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var QtyToBeShipped: Decimal; var QtyToBeShippedBase: Decimal; var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; var ItemLedgShptEntryNo: Integer; var ItemChargeNo: Code[20]; var TrackingSpecification: Record "Tracking Specification"; var IsATO: Boolean; CommitIsSuppressed: Boolean; var IsHandled: Boolean; var Result: Integer; var TempTrackingSpecification: Record "Tracking Specification" temporary; var TempHandlingSpecification: Record "Tracking Specification" temporary; var TempValueEntryRelation: Record "Value Entry Relation" temporary; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line")
    begin
    end;

    /// <summary>
    /// Raised before copying document fields to the item journal line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="QtyToBeShipped">The quantity to be shipped.</param>
    /// <param name="QtyToBeShippedIsZero">Indicates whether the quantity to be shipped is zero.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforePostItemJnlLineCopyDocumentFields(SalesHeader: Record "Sales Header"; QtyToBeShipped: Decimal; var QtyToBeShippedIsZero: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting item charges per order.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="ItemJnlLine2">The item journal line for the item charge.</param>
    /// <param name="ItemChargeSalesLine">The sales line containing the item charge.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemChargePerOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var ItemJnlLine2: Record "Item Journal Line"; var ItemChargeSalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating posting numbers for the sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header to update.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="ModifyHeader">Indicates whether the header should be modified.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdatePostingNos(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var ModifyHeader: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after preparing the item journal line but before posting it.
    /// </summary>
    /// <param name="ItemJournalLine">The item journal line to be posted.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="QtyToBeShippedBase">The quantity to be shipped in base unit of measure.</param>
    /// <param name="ItemJnlPostLine">The item journal post line codeunit instance.</param>
    /// <param name="CheckApplFromItemEntry">Indicates whether to check application from item entry.</param>
    /// <param name="TrackingSpecification">The tracking specification.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemJnlLineBeforePost(var ItemJournalLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; QtyToBeShippedBase: Decimal; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; var CheckApplFromItemEntry: Boolean; var TrackingSpecification: Record "Tracking Specification")
    begin
    end;

    /// <summary>
    /// Raised after posting the item journal line warehouse line.
    /// </summary>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="ItemLedgEntryNo">The item ledger entry number.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemJnlLineWhseLine(SalesLine: Record "Sales Line"; ItemLedgEntryNo: Integer; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after posting item tracking for return receipt.
    /// </summary>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesShipmentLine">The sales shipment line.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="ReturnReceiptLine">The return receipt line.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemTrackingReturnRcpt(var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesShipmentLine: Record "Sales Shipment Line"; var TempTrackingSpecification: Record "Tracking Specification" temporary; var TrackingSpecificationExists: Boolean; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var ReturnReceiptLine: Record "Return Receipt Line"; SalesLine: Record "Sales Line"; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal)
    begin
    end;

    /// <summary>
    /// Raised after posting item tracking for shipment.
    /// </summary>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesShipmentLine">The sales shipment line.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemTrackingForShipment(var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesShipmentLine: Record "Sales Shipment Line"; var TempTrackingSpecification: Record "Tracking Specification" temporary; var TrackingSpecificationExists: Boolean; SalesLine: Record "Sales Line"; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal)
    begin
    end;

    /// <summary>
    /// Raised after posting the item line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="QtyToInvoice">The quantity to invoice.</param>
    /// <param name="QtyToInvoiceBase">The quantity to invoice in base unit of measure.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="ItemJnlPostLine">The item journal post line codeunit instance.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; QtyToInvoice: Decimal; QtyToInvoiceBase: Decimal; CommitIsSuppressed: Boolean; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line")
    begin
    end;

    /// <summary>
    /// Raised after posting an item charge.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="TempItemChargeAssignmentSales">The temporary item charge assignment.</param>
    /// <param name="ItemLedgEntryNo">The item ledger entry number.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemCharge(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; TempItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)" temporary; ItemLedgEntryNo: Integer)
    begin
    end;

    /// <summary>
    /// Raised after testing the sales line for posting readiness.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line that was tested.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterTestSalesLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after updating and modifying the temporary order line during post update.
    /// </summary>
    /// <param name="SalesLine">The sales line that was modified.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostUpdateOrderLineModifyTempLine(SalesLine: Record "Sales Line"; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean; var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after posting G/L entries and customer ledger entries.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="TotalSalesLine">The total sales line amounts.</param>
    /// <param name="TotalSalesLineLCY">The total sales line amounts in local currency.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="WhseShptHeader">The warehouse shipment header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    /// <param name="SalesInvHeader">The posted sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The posted sales credit memo header.</param>
    /// <param name="CustLedgEntry">The customer ledger entry that was created.</param>
    /// <param name="SrcCode">The source code.</param>
    /// <param name="GenJnlLineDocNo">The general journal line document number.</param>
    /// <param name="GenJnlLineExtDocNo">The general journal line external document number.</param>
    /// <param name="GenJnlLineDocType">The general journal line document type.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="DropShipOrder">Indicates whether this is a drop shipment order.</param>
    [IntegrationEvent(true, false)]
    local procedure OnAfterPostGLAndCustomer(var SalesHeader: Record "Sales Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; TotalSalesLine: Record "Sales Line"; TotalSalesLineLCY: Record "Sales Line"; CommitIsSuppressed: Boolean;
        WhseShptHeader: Record "Warehouse Shipment Header"; WhseShip: Boolean; var TempWhseShptHeader: Record "Warehouse Shipment Header"; var SalesInvHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header";
        var CustLedgEntry: Record "Cust. Ledger Entry"; var SrcCode: Code[10]; GenJnlLineDocNo: Code[20]; GenJnlLineExtDocNo: Code[35]; var GenJnlLineDocType: Enum "Gen. Journal Document Type"; PreviewMode: Boolean; DropShipOrder: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after posting the resource journal line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="JobTaskSalesLine">The job task sales line.</param>
    /// <param name="ResJnlLine">The resource journal line that was posted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterPostResJnlLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; JobTaskSalesLine: Record "Sales Line"; ResJnlLine: Record "Res. Journal Line")
    begin
    end;

    /// <summary>
    /// Raised after reversing the amount on a sales line.
    /// </summary>
    /// <param name="SalesLine">The sales line with reversed amounts.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterReverseAmount(var SalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised after dividing amounts on a sales line for VAT calculation.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line with divided amounts.</param>
    /// <param name="QtyType">The quantity type (General, Invoicing, or Shipping).</param>
    /// <param name="SalesLineQty">The sales line quantity.</param>
    /// <param name="TempVATAmountLine">The temporary VAT amount line.</param>
    /// <param name="TempVATAmountLineRemainder">The temporary VAT amount line remainder.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterDivideAmount(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; SalesLineQty: Decimal; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised after rounding amounts on a sales line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line with rounded amounts.</param>
    /// <param name="SalesLineQty">The sales line quantity.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterRoundAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesLineQty: Decimal)
    begin
    end;

    /// <summary>
    /// Raised after updating the blanket order line.
    /// </summary>
    /// <param name="BlanketOrderSalesLine">The blanket order sales line that was updated.</param>
    /// <param name="SalesLine">The sales line used to update the blanket order.</param>
    /// <param name="Ship">Indicates whether the document is being shipped.</param>
    /// <param name="Receive">Indicates whether the document is being received.</param>
    /// <param name="Invoice">Indicates whether the document is being invoiced.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateBlanketOrderLine(var BlanketOrderSalesLine: Record "Sales Line"; SalesLine: Record "Sales Line"; Ship: Boolean; Receive: Boolean; Invoice: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after updating the prepayment sales line with rounding.
    /// </summary>
    /// <param name="PrepmtSalesLine">The prepayment sales line that was updated.</param>
    /// <param name="TotalRoundingAmount">The total rounding amounts.</param>
    /// <param name="TotalPrepmtAmount">The total prepayment amounts.</param>
    /// <param name="FinalInvoice">Indicates whether this is the final invoice.</param>
    /// <param name="PricesInclVATRoundingAmount">The prices including VAT rounding amounts.</param>
    /// <param name="TotalSalesLine">The total sales line amounts.</param>
    /// <param name="TotalSalesLineLCY">The total sales line amounts in local currency.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdatePrepmtSalesLineWithRounding(var PrepmtSalesLine: Record "Sales Line"; TotalRoundingAmount: array[2] of Decimal; TotalPrepmtAmount: array[2] of Decimal; FinalInvoice: Boolean; PricesInclVATRoundingAmount: array[2] of Decimal; var TotalSalesLine: Record "Sales Line"; var TotalSalesLineLCY: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised after updating warehouse documents.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="WhseShptHeader">The warehouse shipment header.</param>
    /// <param name="WhseRcptHeader">The warehouse receipt header.</param>
    /// <param name="EverythingInvoiced">Indicates whether everything has been invoiced.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateWhseDocuments(SalesHeader: Record "Sales Header"; WhseShip: Boolean; WhseReceive: Boolean; WhseShptHeader: Record "Warehouse Shipment Header"; WhseRcptHeader: Record "Warehouse Receipt Header"; EverythingInvoiced: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after updating associated order posting numbers.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TempSalesLine">The temporary sales lines.</param>
    /// <param name="DropShipment">Indicates whether this is a drop shipment.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateAssosOrderPostingNos(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary; var DropShipment: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after releasing the sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was released.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterReleaseSalesDoc(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after validating the posting and document dates.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was validated.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="ReplacePostingDate">Indicates whether the posting date should be replaced.</param>
    /// <param name="ReplaceDocumentDate">Indicates whether the document date should be replaced.</param>
    [IntegrationEvent(false, false)]
    local procedure OnAfterValidatePostingAndDocumentDate(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; PreviewMode: Boolean; ReplacePostingDate: Boolean; ReplaceDocumentDate: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before calculating the invoice.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="NewInvoice">Indicates whether a new invoice will be created.</param>
    /// <param name="IsHandled">Set to true to skip the default calculation logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalcInvoice(SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: Record "Sales Line" temporary; var NewInvoice: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before calculating item journal line amounts from quantity to be shipped.
    /// </summary>
    /// <param name="ItemJnlLine">The item journal line.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="QtyToBeShipped">The quantity to be shipped.</param>
    /// <param name="IsHandled">Set to true to skip the default calculation logic.</param>
    /// <param name="InvDiscAmountPerShippedQty">The invoice discount amount per shipped quantity.</param>
    /// <param name="RemAmt">The remaining amount.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalcItemJnlAmountsFromQtyToBeShipped(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; var IsHandled: Boolean; var InvDiscAmountPerShippedQty: Decimal; RemAmt: Decimal)
    begin
    end;

    /// <summary>
    /// Raised before checking associated order lines.
    /// </summary>
    /// <param name="SalesHeader">The sales header being checked.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckAssosOrderLines(SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking customer blockage.
    /// </summary>
    /// <param name="SalesHeader">The sales header being checked.</param>
    /// <param name="CustCode">The customer code to check.</param>
    /// <param name="ExecuteDocCheck">Indicates whether to execute document check.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    /// <param name="TempSalesLine">The temporary sales lines.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckCustBlockage(SalesHeader: Record "Sales Header"; CustCode: Code[20]; var ExecuteDocCheck: Boolean; var IsHandled: Boolean; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised before checking if job number on shipment line equals sales line.
    /// </summary>
    /// <param name="SalesShipmentLine">The sales shipment line.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckJobNoOnShptLineEqualToSales(SalesShipmentLine: Record "Sales Shipment Line"; SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking G/L account direct posting settings.
    /// </summary>
    /// <param name="SalesLine">The sales line to check.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckGLAccountDirectPosting(SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking whether to insert the return receipt header.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckInsertReturnReceiptHeader(SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking item reservation disruption.
    /// </summary>
    /// <param name="SalesLine">The sales line to check.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckItemReservDisruption(SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking mandatory header fields.
    /// </summary>
    /// <param name="SalesHeader">The sales header to check.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckMandatoryHeaderFields(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking whether to post warehouse receipt line from shipment line.
    /// </summary>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckPostWhseRcptLineFromShipmentLine(var SalesShptLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking whether to post warehouse shipment lines.
    /// </summary>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    /// <param name="WhseShptHeader">The warehouse shipment header.</param>
    /// <param name="WhseRcptHeader">The warehouse receipt header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckPostWhseShptLines(var SalesShptLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean; WhseShptHeader: Record "Warehouse Shipment Header"; WhseRcptHeader: Record "Warehouse Receipt Header"; WhseShip: Boolean; WhseReceive: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking posting flags.
    /// </summary>
    /// <param name="SalesHeader">The sales header to check.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckPostingFlags(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking prepayment amount to deduct.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales lines.</param>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    /// <param name="Fraction">The fraction for calculation.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckPrepmtAmtToDeduct(var TempSalesLine: Record "Sales Line" temporary; var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; Fraction: Decimal)
    begin
    end;

    /// <summary>
    /// Raised before checking header shipping advice.
    /// </summary>
    /// <param name="SalesHeader">The sales header to check.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckHeaderShippingAdvice(SalesHeader: Record "Sales Header"; WhseShip: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking header posting type.
    /// </summary>
    /// <param name="SalesHeader">The sales header to check.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckHeaderPostingType(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking if sales line is invoiced more than shipped.
    /// </summary>
    /// <param name="SalesOrderLine">The sales order line.</param>
    /// <param name="TempSalesLine">The temporary sales line.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckSalesLineInvoiceMoreThanShipped(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary; var SalesShptLine: Record "Sales Shipment Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking the total invoice amount.
    /// </summary>
    /// <param name="SalesHeader">The sales header to check.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckTotalInvoiceAmount(SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking the total prepayment amount to deduct.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales line.</param>
    /// <param name="TempTotalSalesLine">The temporary total sales line.</param>
    /// <param name="MaxAmtToDeduct">The maximum amount to deduct.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckTotalPrepmtAmtToDeduct(var TempSalesLine: Record "Sales Line" temporary; var TempTotalSalesLine: Record "Sales Line" temporary; var MaxAmtToDeduct: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking warehouse requirements.
    /// </summary>
    /// <param name="TempItemSalesLine">The temporary item sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckWarehouse(var TempItemSalesLine: Record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before clearing remaining amount if not item journal roll rounding.
    /// </summary>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="ItemJnlRollRndg">Indicates whether item journal roll rounding is used.</param>
    /// <param name="RemAmt">The remaining amount.</param>
    /// <param name="RemDiscAmt">The remaining discount amount.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeClearRemAmtIfNotItemJnlRollRndg(SalesLine: Record "Sales Line"; ItemJnlRollRndg: Boolean; var RemAmt: Decimal; var RemDiscAmt: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before dividing amounts on a sales line for VAT calculation.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line to process.</param>
    /// <param name="QtyType">The quantity type (General, Invoicing, or Shipping).</param>
    /// <param name="SalesLineQty">The sales line quantity.</param>
    /// <param name="TempVATAmountLine">The temporary VAT amount line.</param>
    /// <param name="TempVATAmountLineRemainder">The temporary VAT amount line remainder.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="TempPrepmtDeductLCYSalesLine">The temporary prepayment deduct LCY sales line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeDivideAmount(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; var SalesLineQty: Decimal; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary; var IsHandled: Boolean; var TempPrepmtDeductLCYSalesLine: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised before initializing line amount and line discount amount during divide amount.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line to process.</param>
    /// <param name="SalesLineQty">The sales line quantity.</param>
    /// <param name="IncludePrepayments">Indicates whether to include prepayments.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="TempPrepmtDeductLCYSalesLine">The temporary prepayment deduct LCY sales line.</param>
    /// <param name="TempVATAmountLine">The temporary VAT amount line.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforeDivideAmountInitLineAmountAndLineDiscountAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var SalesLineQty: Decimal; IncludePrepayments: Boolean; var IsHandled: Boolean; var TempPrepmtDeductLCYSalesLine: Record "Sales Line" temporary; var TempVATAmountLine: Record "VAT Amount Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised before getting the invoice posting setup.
    /// </summary>
    /// <param name="InvoicePostingInterface">The invoice posting interface.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetInvoicePostingSetup(var InvoicePostingInterface: Interface "Invoice Posting"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before rounding amounts on a sales line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="SalesLine">The sales line to round.</param>
    /// <param name="SalesLineQty">The sales line quantity.</param>
    /// <param name="CurrExchRate">The currency exchange rate.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeRoundAmount(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var SalesLineQty: Decimal; var CurrExchRate: Record "Currency Exchange Rate")
    begin
    end;

    /// <summary>
    /// Raised before posting assemble-to-order.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="TempPostedATOLink">The temporary posted assemble-to-order link.</param>
    /// <param name="AsmPost">The assembly post codeunit instance.</param>
    /// <param name="ItemJnlPostLine">The item journal post line codeunit instance.</param>
    /// <param name="ResJnlPostLine">The resource journal post line codeunit instance.</param>
    /// <param name="WhseJnlPostLine">The warehouse journal register line codeunit instance.</param>
    /// <param name="HideProgressWindow">Indicates whether to hide the progress window.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostATO(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary; var AsmPost: Codeunit "Assembly-Post"; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; var ResJnlPostLine: Codeunit "Res. Jnl.-Post Line"; var WhseJnlPostLine: Codeunit "Whse. Jnl.-Register Line"; HideProgressWindow: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting the drop shipment order.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="TempDropShptPostBuffer">The temporary drop shipment post buffer.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostDropOrderShipment(var SalesHeader: Record "Sales Header"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    begin
    end;

    /// <summary>
    /// Raised before posting the invoice.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="CustLedgerEntry">The customer ledger entry to be created.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="GenJnlPostLine">The general journal post line codeunit instance.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="GenJnlLineDocNo">The general journal line document number.</param>
    /// <param name="GenJnlLineExtDocNo">The general journal line external document number.</param>
    /// <param name="GenJnlLineDocType">The general journal line document type.</param>
    /// <param name="SrcCode">The source code.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostInvoice(var SalesHeader: Record "Sales Header"; var CustLedgerEntry: Record "Cust. Ledger Entry"; CommitIsSuppressed: Boolean; PreviewMode: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean; GenJnlLineDocNo: Code[20]; GenJnlLineExtDocNo: Code[35]; GenJnlLineDocType: Enum "Gen. Journal Document Type"; SrcCode: Code[10])
    begin
    end;

    /// <summary>
    /// Raised before posting an item charge.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line containing the item charge.</param>
    /// <param name="TempItemChargeAssignmentSales">The temporary item charge assignment.</param>
    /// <param name="ItemLedgEntryNo">The item ledger entry number.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemCharge(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)" temporary; ItemLedgEntryNo: Integer)
    begin
    end;

    /// <summary>
    /// Raised before posting item tracking.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="TempItemLedgEntryNotInvoiced">The temporary item ledger entries not invoiced.</param>
    /// <param name="HasATOShippedNotInvoiced">Indicates whether ATO has been shipped but not invoiced.</param>
    /// <param name="PreciseTotalChargeAmt">The precise total charge amount.</param>
    /// <param name="RoundedPrevTotalChargeAmt">The rounded previous total charge amount.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="ItemJnlRollRndg">Indicates whether item journal roll rounding is used.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforePostItemTracking(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TrackingSpecificationExists: Boolean; var TempTrackingSpecification: Record "Tracking Specification" temporary; var IsHandled: Boolean; TempItemLedgEntryNotInvoiced: Record "Item Ledger Entry" temporary; HasATOShippedNotInvoiced: Boolean; var PreciseTotalChargeAmt: Decimal; var RoundedPrevTotalChargeAmt: Decimal; RemQtyToBeInvoiced: Decimal; var ItemJnlRollRndg: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking item tracking for return receipt posting.
    /// </summary>
    /// <param name="SalesLine">The sales line being checked.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforePostItemTrackingCheckReturnReceipt(SalesLine: Record "Sales Line"; RemQtyToBeInvoiced: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before checking item tracking for shipment posting.
    /// </summary>
    /// <param name="SalesLine">The sales line being checked.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="IsHandled">Set to true to skip the default check logic.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforePostItemTrackingCheckShipment(SalesLine: Record "Sales Line"; RemQtyToBeInvoiced: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting item tracking for return receipt.
    /// </summary>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesShipmentLine">The sales shipment line.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="ReturnReceiptLine">The return receipt line.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemTrackingReturnRcpt(var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesShipmentLine: Record "Sales Shipment Line"; var TempTrackingSpecification: Record "Tracking Specification" temporary; var TrackingSpecificationExists: Boolean; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var ReturnReceiptLine: Record "Return Receipt Line"; SalesLine: Record "Sales Line"; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal)
    begin
    end;

    /// <summary>
    /// Raised before posting item tracking for shipment.
    /// </summary>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesShipmentLine">The sales shipment line.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemTrackingForShipment(var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesShipmentLine: Record "Sales Shipment Line"; var TempTrackingSpecification: Record "Tracking Specification" temporary; var TrackingSpecificationExists: Boolean; SalesLine: Record "Sales Line"; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal)
    begin
    end;

    /// <summary>
    /// Raised before posting the resource journal line.
    /// </summary>
    /// <param name="SalesHeader">The sales header being posted.</param>
    /// <param name="SalesLine">The sales line being posted.</param>
    /// <param name="JobTaskSalesLine">The job task sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="DocNo">The document number.</param>
    /// <param name="ExtDocNo">The external document number.</param>
    /// <param name="SourceCode">The source code.</param>
    /// <param name="SalesShptHeader">The sales shipment header.</param>
    /// <param name="ReturnRcptHeader">The return receipt header.</param>
    /// <param name="ResJnlPostLine">The resource journal post line codeunit instance.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostResJnlLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var JobTaskSalesLine: Record "Sales Line"; var IsHandled: Boolean; DocNo: Code[20]; ExtDocNo: Code[35]; SourceCode: Code[10]; SalesShptHeader: Record "Sales Shipment Header"; ReturnRcptHeader: Record "Return Receipt Header"; var ResJnlPostLine: Codeunit "Res. Jnl.-Post Line")
    begin
    end;

    /// <summary>
    /// Raised before updating the order line during post processing.
    /// </summary>
    /// <param name="SalesHeader">The sales header being processed.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="SalesSetup">The sales and receivables setup.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostUpdateOrderLine(SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: Record "Sales Line" temporary; CommitIsSuppressed: Boolean; var SalesSetup: Record "Sales & Receivables Setup")
    begin
    end;

    /// <summary>
    /// Raised before modifying the temporary order line during post update.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales line.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="SalesHeader">The sales header being processed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostUpdateOrderLineModifyTempLine(var TempSalesLine: Record "Sales Line" temporary; WhseShip: Boolean; WhseReceive: Boolean; CommitIsSuppressed: Boolean; var IsHandled: Boolean; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before posting warehouse receipt line from shipment line.
    /// </summary>
    /// <param name="WhseRcptLine">The warehouse receipt line.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="PostedWhseRcptHeader">The posted warehouse receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostWhseRcptLineFromShipmentLine(var WhseRcptLine: Record "Warehouse Receipt Line"; SalesShptLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean; PostedWhseRcptHeader: Record "Posted Whse. Receipt Header")
    begin
    end;

    /// <summary>
    /// Raised before validating posting and document dates.
    /// </summary>
    /// <param name="SalesHeader">The sales header to validate.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default validation logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidatePostingAndDocumentDate(var SalesHeader: Record "Sales Header"; CommitIsSuppressed: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating invoiced quantity on shipment line.
    /// </summary>
    /// <param name="SalesShipmentLine">The sales shipment line to update.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateInvoicedQtyOnShipmentLine(var SalesShipmentLine: Record "Sales Shipment Line"; SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; SalesInvoiceHeader: Record "Sales Invoice Header"; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before the update invoiced quantity on shipment line procedure.
    /// </summary>
    /// <param name="SalesShptLine">The sales shipment line to update.</param>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateInvoicedQtyOnShipmentLineProcedure(var SalesShptLine: Record "Sales Shipment Line"; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal)
    begin
    end;

    /// <summary>
    /// Raised before sending the intercompany document.
    /// </summary>
    /// <param name="SalesHeader">The sales header to send.</param>
    /// <param name="ModifyHeader">Indicates whether the header should be modified.</param>
    /// <param name="IsHandled">Set to true to skip the default send logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSendICDocument(var SalesHeader: Record "Sales Header"; var ModifyHeader: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before setting posting flags.
    /// </summary>
    /// <param name="SalesHeader">The sales header to set flags for.</param>
    /// <param name="IsHandled">Set to true to skip the default flag setting logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSetPostingFlags(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before testing fields by document type.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line to test.</param>
    /// <param name="IsHandled">Set to true to skip the default test logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestFieldsByDocType(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before testing the sales line for posting readiness.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line to test.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="IsHandled">Set to true to skip the default test logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestSalesLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; CommitIsSuppressed: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before testing the sales line for fixed asset posting.
    /// </summary>
    /// <param name="SalesLine">The sales line to test.</param>
    /// <param name="IsHandled">Set to true to skip the default test logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestSalesLineFixedAsset(SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before testing the sales line for item charge posting.
    /// </summary>
    /// <param name="SalesLine">The sales line to test.</param>
    /// <param name="IsHandled">Set to true to skip the default test logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestSalesLineItemCharge(SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before testing the sales line for job posting.
    /// </summary>
    /// <param name="SalesLine">The sales line to test.</param>
    /// <param name="SkipTestJobNo">Set to true to skip the job number test.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestSalesLineJob(SalesLine: Record "Sales Line"; var SkipTestJobNo: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before testing the updated sales line.
    /// </summary>
    /// <param name="SalesLine">The sales line to test.</param>
    /// <param name="IsHandled">Set to true to skip the default test logic.</param>
    /// <param name="ErrorMessageManagement">The error message management codeunit for handling errors.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestUpdatedSalesLine(SalesLine: Record "Sales Line"; var IsHandled: Boolean; var ErrorMessageManagement: Codeunit "Error Message Management")
    begin
    end;

    /// <summary>
    /// Raised before testing the sales line for other posting scenarios.
    /// </summary>
    /// <param name="SalesLine">The sales line to test.</param>
    /// <param name="SkipTestJobNo">Set to true to skip the job number test.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestSalesLineOthers(SalesLine: Record "Sales Line"; var SkipTestJobNo: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before testing the status for release.
    /// </summary>
    /// <param name="SalesHeader">The sales header to test.</param>
    /// <param name="IsHandled">Set to true to skip the default status test logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestStatusRelease(SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting the temporary prepayment sales line.
    /// </summary>
    /// <param name="TempPrepmtSalesLine">The temporary prepayment sales line to insert.</param>
    /// <param name="TempSalesLine">The temporary sales line.</param>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="CompleteFunctionality">Indicates whether to use complete functionality.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTempPrepmtSalesLineInsert(var TempPrepmtSalesLine: Record "Sales Line" temporary; var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header"; CompleteFunctionality: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before modifying the temporary prepayment sales line.
    /// </summary>
    /// <param name="TempPrepmtSalesLine">The temporary prepayment sales line to modify.</param>
    /// <param name="TempSalesLine">The temporary sales line.</param>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="CompleteFunctionality">Indicates whether to use complete functionality.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTempPrepmtSalesLineModify(var TempPrepmtSalesLine: Record "Sales Line" temporary; var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header"; CompleteFunctionality: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before transferring reservation to item journal line.
    /// </summary>
    /// <param name="SalesOrderLine">The sales order line.</param>
    /// <param name="QtyToBeShippedBase">The quantity to be shipped in base unit of measure.</param>
    /// <param name="IsHandled">Set to true to skip the default transfer logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTransferReservToItemJnlLine(var SalesOrderLine: Record "Sales Line"; var QtyToBeShippedBase: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before releasing the sales document.
    /// </summary>
    /// <param name="SalesHeader">The sales header to release.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeReleaseSalesDoc(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before updating associated order posting numbers.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="DropShipment">Indicates whether this is a drop shipment.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateAssosOrderPostingNos(var SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: Record "Sales Line" temporary; PreviewMode: Boolean; var DropShipment: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating associated lines.
    /// </summary>
    /// <param name="SalesOrderLine">The sales order line.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateAssocLines(var SalesOrderLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating the blanket order line.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="Ship">Indicates whether the document is being shipped.</param>
    /// <param name="Receive">Indicates whether the document is being received.</param>
    /// <param name="Invoice">Indicates whether the document is being invoiced.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateBlanketOrderLine(SalesLine: Record "Sales Line"; Ship: Boolean; Receive: Boolean; Invoice: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating the handled intercompany inbox transaction.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateHandledICInboxTransaction(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating the posting number.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="ModifyHeader">Indicates whether the header should be modified.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    /// <param name="DateOrderSeriesUsed">Indicates whether date order series is used.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdatePostingNo(var SalesHeader: Record "Sales Header"; PreviewMode: Boolean; var ModifyHeader: Boolean; var IsHandled: Boolean; var DateOrderSeriesUsed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating the prepayment sales line with rounding.
    /// </summary>
    /// <param name="PrepmtSalesLine">The prepayment sales line.</param>
    /// <param name="TotalRoundingAmount">The total rounding amounts.</param>
    /// <param name="TotalPrepmtAmount">The total prepayment amounts.</param>
    /// <param name="FinalInvoice">Indicates whether this is the final invoice.</param>
    /// <param name="PricesInclVATRoundingAmount">The prices including VAT rounding amounts.</param>
    /// <param name="TotalSalesLine">The total sales line amounts.</param>
    /// <param name="TotalSalesLineLCY">The total sales line amounts in local currency.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdatePrepmtSalesLineWithRounding(var PrepmtSalesLine: Record "Sales Line"; TotalRoundingAmount: array[2] of Decimal; TotalPrepmtAmount: array[2] of Decimal; FinalInvoice: Boolean; PricesInclVATRoundingAmount: array[2] of Decimal; var TotalSalesLine: Record "Sales Line"; var TotalSalesLineLCY: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised before updating quantity to be invoiced for shipment.
    /// </summary>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="HasATOShippedNotInvoiced">Indicates whether ATO has been shipped but not invoiced.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="InvoicingTrackingSpecification">The invoicing tracking specification.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateQtyToBeInvoicedForShipment(var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; TrackingSpecificationExists: Boolean; HasATOShippedNotInvoiced: Boolean; SalesLine: Record "Sales Line"; SalesShptLine: Record "Sales Shipment Line"; InvoicingTrackingSpecification: Record "Tracking Specification")
    begin
    end;

    /// <summary>
    /// Raised before updating quantity to be invoiced for return receipt.
    /// </summary>
    /// <param name="QtyToBeInvoiced">The quantity to be invoiced.</param>
    /// <param name="QtyToBeInvoicedBase">The quantity to be invoiced in base unit of measure.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="ReturnReceiptLine">The return receipt line.</param>
    /// <param name="InvoicingTrackingSpecification">The invoicing tracking specification.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="RemQtyToBeInvoicedBase">The remaining quantity to be invoiced in base unit of measure.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateQtyToBeInvoicedForReturnReceipt(var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; TrackingSpecificationExists: Boolean; SalesLine: Record "Sales Line"; ReturnReceiptLine: Record "Return Receipt Line"; InvoicingTrackingSpecification: Record "Tracking Specification"; RemQtyToBeInvoiced: Decimal; RemQtyToBeInvoicedBase: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating the return receipt number.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="ModifyHeader">Indicates whether the header should be modified.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateReturnReceiptNo(var SalesHeader: Record "Sales Header"; var ModifyHeader: Boolean; var IsHandled: Boolean; PreviewMode: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating the sales header.
    /// </summary>
    /// <param name="CustLedgerEntry">The customer ledger entry.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    /// <param name="GenJnlLineDocType">The general journal line document type.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    /// <param name="GenJnlLineDocNo">The general journal line document number.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="SalesHeader">The sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateSalesHeader(var CustLedgerEntry: Record "Cust. Ledger Entry"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; GenJnlLineDocType: Option; var IsHandled: Boolean; GenJnlLineDocNo: Code[20]; PreviewMode: Boolean; var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before updating the sales line before posting.
    /// </summary>
    /// <param name="SalesLine">The sales line to update.</param>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="RoundingLineInserted">Indicates whether a rounding line was inserted.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateSalesLineBeforePost(var SalesLine: Record "Sales Line"; var SalesHeader: Record "Sales Header"; WhseShip: Boolean; WhseReceive: Boolean; RoundingLineInserted: Boolean; CommitIsSuppressed: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating the shipping number.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="InvtPickPutaway">Indicates whether inventory pick/put-away is involved.</param>
    /// <param name="PreviewMode">Indicates whether the posting is in preview mode.</param>
    /// <param name="ModifyHeader">Indicates whether the header should be modified.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateShippingNo(var SalesHeader: Record "Sales Header"; WhseShip: Boolean; WhseReceive: Boolean; InvtPickPutaway: Boolean; PreviewMode: Boolean; var ModifyHeader: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before updating warehouse documents.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="IsHandled">Set to true to skip the default update logic.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseRcptHeader">The warehouse receipt header.</param>
    /// <param name="WhseShptHeader">The warehouse shipment header.</param>
    /// <param name="TempWhseRcptHeader">The temporary warehouse receipt header.</param>
    /// <param name="TempWhseShptHeader">The temporary warehouse shipment header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateWhseDocuments(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; WhseReceive: Boolean; WhseShip: Boolean; WhseRcptHeader: Record "Warehouse Receipt Header"; WhseShptHeader: Record "Warehouse Shipment Header"; var TempWhseRcptHeader: Record "Warehouse Receipt Header" temporary; var TempWhseShptHeader: Record "Warehouse Shipment Header" temporary)
    begin
    end;

    /// <summary>
    /// Raised before determining if warehouse handling is required.
    /// </summary>
    /// <param name="SalesLine">The sales line to check.</param>
    /// <param name="Required">Indicates whether warehouse handling is required.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeWhseHandlingRequired(SalesLine: Record "Sales Line"; var Required: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised when invoicing a sales shipment line.
    /// </summary>
    /// <param name="SalesShipmentLine">The sales shipment line being invoiced.</param>
    /// <param name="InvoiceNo">The invoice number.</param>
    /// <param name="InvoiceLineNo">The invoice line number.</param>
    /// <param name="QtyToInvoice">The quantity to invoice.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInvoiceSalesShptLine(SalesShipmentLine: Record "Sales Shipment Line"; InvoiceNo: Code[20]; InvoiceLineNo: Integer; QtyToInvoice: Decimal; CommitIsSuppressed: Boolean)
    begin
    end;

    local procedure PostResJnlLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var JobTaskSalesLine2: Record "Sales Line")
    var
        ResJnlLine: Record "Res. Journal Line";
        IsHandled: Boolean;
        ShouldExit: Boolean;
    begin
        IsHandled := false;
        OnBeforePostResJnlLine(SalesHeader, SalesLine, JobTaskSalesLine2, IsHandled, GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode, SalesShptHeader, ReturnRcptHeader, ResJnlPostLine);
        if IsHandled then
            exit;

        ShouldExit := SalesLine."Qty. to Invoice" = 0;
        OnPostResJnlLineOnShouldExit(SalesLine, ShouldExit);
        if ShouldExit then
            exit;

        ResJnlLine.Init();
        ResJnlLine.CopyFromSalesHeader(SalesHeader);
        ResJnlLine.CopyDocumentFields(GenJnlLineDocNo, GenJnlLineExtDocNo, SrcCode, SalesHeader."Posting No. Series");
        ResJnlLine.CopyFromSalesLine(SalesLine);
        OnPostResJnlLineOnAfterInit(ResJnlLine, SalesLine);

        ResJnlPostLine.RunWithCheck(ResJnlLine);
        if JobTaskSalesLine2."Job Contract Entry No." > 0 then
            PostJobContractLine(SalesHeader, JobTaskSalesLine2);

        OnAfterPostResJnlLine(SalesHeader, SalesLine, JobTaskSalesLine2, ResJnlLine);
    end;

    local procedure ValidatePostingAndDocumentDate(var SalesHeader: Record "Sales Header")
    var
        BatchProcessingMgt: Codeunit "Batch Processing Mgt.";
        PostingDate, VATDate : Date;
        ModifyHeader: Boolean;
        PostingDateExists, VATDateExists : Boolean;
        ReplacePostingDate: Boolean;
        ReplaceDocumentDate: Boolean;
        ReplaceVATDate: Boolean;
        SkipTestPostingDate: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeValidatePostingAndDocumentDate(SalesHeader, SuppressCommit, IsHandled);
        if IsHandled then
            exit;

        PostingDateExists :=
          BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Replace Posting Date", ReplacePostingDate) and
          BatchProcessingMgt.GetBooleanParameter(
            SalesHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Replace Document Date", ReplaceDocumentDate) and
          BatchProcessingMgt.GetDateParameter(SalesHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Posting Date", PostingDate);

        VATDateExists := BatchProcessingMgt.GetBooleanParameter(SalesHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Replace VAT Date", ReplaceVATDate);
        BatchProcessingMgt.GetDateParameter(SalesHeader.RecordId, Enum::"Batch Posting Parameter Type"::"VAT Date", VATDate);

        OnValidatePostingAndDocumentDateOnAfterCalcPostingDateExists(PostingDateExists, ReplacePostingDate, ReplaceDocumentDate, PostingDate, SalesHeader, ModifyHeader, VATDateExists, ReplaceVATDate, VATDate);

        if PostingDateExists and (ReplacePostingDate or (SalesHeader."Posting Date" = 0D)) then begin
            SalesHeader."Posting Date" := PostingDate;
            SalesHeader.SynchronizeAsmHeader();
            SalesHeader.Validate("Currency Code");
            ModifyHeader := true;
        end;

        OnValidatePostingAndDocumentDateOnBeforeValidateDocumentDate(PostingDateExists, ReplaceDocumentDate, PostingDate, SalesHeader);
        if PostingDateExists and (ReplaceDocumentDate or (SalesHeader."Document Date" = 0D)) then begin
            SalesHeader.Validate("Document Date", PostingDate);
            ModifyHeader := true;
        end;

        if VATDateExists and (ReplaceVATDate) then begin
            SalesHeader."VAT Reporting Date" := VATDate;
            ModifyHeader := true;
        end;

        if not ReplacePostingDate then begin
            SkipTestPostingDate := false;
            OnValidatePostingAndDocumentDateOnBeforeTestPostingDate(SalesHeader, PostingDateExists, SkipTestPostingDate);
            if not SkipTestPostingDate then
                SalesHeader.TestPostingDate(PostingDateExists);
        end;

        OnValidatePostingAndDocumentDateOnBeforeSalesHeaderModify(SalesHeader, ModifyHeader);
        if ModifyHeader then
            SalesHeader.Modify();

        OnAfterValidatePostingAndDocumentDate(SalesHeader, SuppressCommit, PreviewMode, ReplacePostingDate, ReplaceDocumentDate);
    end;

    local procedure UpdateItemJnlLineDimSetIDFromAppliedShipmentEntry(var ItemJnlLine2: Record "Item Journal Line")
    var
        ItemLedgerEntry: Record "Item Ledger Entry";
        DimensionMgt: Codeunit DimensionManagement;
        DimSetID: array[10] of Integer;
    begin
        if ItemJnlLine2."Item Shpt. Entry No." <> 0 then begin
            ItemLedgerEntry.SetLoadFields("Dimension Set ID");
            ItemLedgerEntry.Get(ItemJnlLine2."Item Shpt. Entry No.");
            DimSetID[1] := ItemLedgerEntry."Dimension Set ID";
            DimSetID[2] := ItemJnlLine2."Dimension Set ID";

            ItemJnlLine2."Dimension Set ID" :=
                DimensionMgt.GetCombinedDimensionSetID(DimSetID, ItemJnlLine2."Shortcut Dimension 1 Code", ItemJnlLine2."Shortcut Dimension 2 Code");
        end;
    end;

    local procedure UpdateSalesLineDimSetIDFromAppliedEntry(var SalesLineToPost: Record "Sales Line"; SalesLine: Record "Sales Line")
    var
        ItemLedgEntry: Record "Item Ledger Entry";
        DimensionMgt: Codeunit DimensionManagement;
        DimSetID: array[10] of Integer;
    begin
        DimSetID[1] := SalesLine."Dimension Set ID";
        if SalesLineToPost."Appl.-to Item Entry" <> 0 then begin
            ItemLedgEntry.Get(SalesLineToPost."Appl.-to Item Entry");
            DimSetID[2] := ItemLedgEntry."Dimension Set ID";
        end;
        SalesLineToPost."Dimension Set ID" :=
          DimensionMgt.GetCombinedDimensionSetID(DimSetID, SalesLineToPost."Shortcut Dimension 1 Code", SalesLineToPost."Shortcut Dimension 2 Code");
        OnAfterUpdateSalesLineDimSetIDFromAppliedEntry(SalesLineToPost, ItemLedgEntry, DimSetID);
    end;

    /// <summary>
    /// Raised when sending the sales document.
    /// </summary>
    /// <param name="ShipAndInvoice">Indicates whether to ship and invoice.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnSendSalesDocument(ShipAndInvoice: Boolean; CommitIsSuppressed: Boolean)
    begin
    end;

    local procedure GetAmountRoundingPrecisionInLCY(DocType: Enum "Sales Document Type"; DocNo: Code[20]; CurrencyCode: Code[10]) AmountRoundingPrecision: Decimal
    var
        SalesHeader: Record "Sales Header";
    begin
        if CurrencyCode = '' then
            exit(GLSetup."Amount Rounding Precision");
        SalesHeader.Get(DocType, DocNo);
        AmountRoundingPrecision := Currency."Amount Rounding Precision" / SalesHeader."Currency Factor";
        if AmountRoundingPrecision < GLSetup."Amount Rounding Precision" then
            exit(GLSetup."Amount Rounding Precision");
        exit(AmountRoundingPrecision);
    end;

    local procedure UpdateEmailParameters(SalesHeader: Record "Sales Header")
    var
        FindEmailParameter: Record "Email Parameter";
        RenameEmailParameter: Record "Email Parameter";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateEmailParameters(SalesHeader, IsHandled);
        if IsHandled then
            exit;

        if SalesHeader."Last Posting No." = '' then
            exit;
        FindEmailParameter.SetRange("Document No", SalesHeader."No.");
        FindEmailParameter.SetRange("Document Type", SalesHeader."Document Type");
        if FindEmailParameter.FindSet() then
            repeat
                RenameEmailParameter.Copy(FindEmailParameter);
                RenameEmailParameter.Rename(
                  SalesHeader."Last Posting No.", FindEmailParameter."Document Type", FindEmailParameter."Parameter Type");
            until FindEmailParameter.Next() = 0;
    end;

    local procedure ArchivePurchaseOrders(var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    var
        PurchOrderHeader: Record "Purchase Header";
        PurchOrderLine: Record "Purchase Line";
    begin
        if TempDropShptPostBuffer.FindSet() then
            repeat
                PurchOrderHeader.Get(PurchOrderHeader."Document Type"::Order, TempDropShptPostBuffer."Order No.");
                TempDropShptPostBuffer.SetRange("Order No.", TempDropShptPostBuffer."Order No.");
                repeat
                    PurchOrderLine.Get(
                      PurchOrderLine."Document Type"::Order,
                      TempDropShptPostBuffer."Order No.", TempDropShptPostBuffer."Order Line No.");
                    PurchOrderLine."Qty. to Receive" := TempDropShptPostBuffer.Quantity;
                    PurchOrderLine."Qty. to Receive (Base)" := TempDropShptPostBuffer."Quantity (Base)";
                    OnArchivePurchaseOrdersOnBeforePurchOrderLineModify(PurchOrderLine, TempDropShptPostBuffer);
                    PurchOrderLine.Modify();
                until TempDropShptPostBuffer.Next() = 0;
                PurchPost.ArchiveUnpostedOrder(PurchOrderHeader);
                TempDropShptPostBuffer.SetRange("Order No.");
            until TempDropShptPostBuffer.Next() = 0;
    end;

    /// <summary>
    /// Raises the OnBeforePostResJnlLine event.
    /// </summary>
    /// <param name="ItemJnlLine">The item journal line that is posted.</param>
    /// <param name="SalesLine">The sales line of the document that is posted.</param>
    /// <param name="SalesHeader">The sales header of the document that is posted.</param>
    /// <returns>Value of the IsHandled variable that is exposed by the event. False by default</returns>
    procedure IsItemJnlPostLineHandled(var ItemJnlLine: Record "Item Journal Line"; var SalesLine: Record "Sales Line"; var SalesHeader: Record "Sales Header") IsHandled: Boolean
    begin
        IsHandled := false;
        OnBeforeItemJnlPostLine(ItemJnlLine, SalesLine, SalesHeader, SuppressCommit, IsHandled, TempItemChargeAssgntSales);
        exit(IsHandled);
    end;

    local procedure CalcVATBaseAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCalcVATBaseAmount(SalesHeader, SalesLine, TempVATAmountLine, TempVATAmountLineRemainder, Currency, IsHandled);
        if IsHandled then
            exit;

        SalesLine."VAT Base Amount" :=
          Round(
            SalesLine.Amount * (1 - SalesLine.GetVatBaseDiscountPct(SalesHeader) / 100), Currency."Amount Rounding Precision");
    end;

    local procedure SalesShptLineInsert(var SalesShptLine: Record "Sales Shipment Line"; SalesShptHeader: Record "Sales Shipment Header"; SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSalesShptLineInsert(
            SalesShptLine, SalesShptHeader, SalesLine, SuppressCommit, PostedWhseShptLine, SalesHeader, WhseShip, WhseReceive,
            ItemLedgShptEntryNo, xSalesLine, TempSalesLineGlobal, IsHandled);
        if IsHandled then
            exit;

        SalesShptLine.Insert(true);

        OnAfterSalesShptLineInsert(SalesShptLine, SalesLine, ItemLedgShptEntryNo, WhseShip, WhseReceive, SuppressCommit, SalesInvHeader, TempWhseShptHeader, TempWhseRcptHeader, SalesShptHeader, SalesHeader);
    end;

    local procedure SalesInvHeaderInsert(var SalesInvHeader: Record "Sales Invoice Header"; var SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSalesInvHeaderInsert(SalesInvHeader, SalesHeader, SuppressCommit, IsHandled, WhseShip, WhseShptHeader, InvtPickPutaway);
        if IsHandled then
            exit;

        SalesInvHeader.Insert(true);

        OnAfterSalesInvHeaderInsert(SalesInvHeader, SalesHeader, SuppressCommit, WhseShip, WhseReceive, TempWhseShptHeader, TempWhseRcptHeader, PreviewMode);
    end;

    local procedure SalesShptHeaderInsert(var SalesShptHeader: Record "Sales Shipment Header"; var SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSalesShptHeaderInsert(SalesShptHeader, SalesHeader, SuppressCommit, IsHandled, TempWhseRcptHeader, WhseReceive, TempWhseShptHeader, WhseShip, InvtPickPutaway);
        if IsHandled then
            exit;

        SalesShptHeader.Insert(true);

        OnAfterSalesShptHeaderInsert(SalesShptHeader, SalesHeader, SuppressCommit, WhseShip, WhseReceive, TempWhseShptHeader, TempWhseRcptHeader, PreviewMode);
    end;

    local procedure SalesCrMemoHeaderInsert(var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSalesCrMemoHeaderInsert(SalesCrMemoHeader, SalesHeader, SuppressCommit, IsHandled, SalesInvHeader);
        if IsHandled then
            exit;

        SalesCrMemoHeader.Insert(true);

        OnAfterSalesCrMemoHeaderInsert(SalesCrMemoHeader, SalesHeader, SuppressCommit, WhseShip, WhseReceive, TempWhseShptHeader, TempWhseRcptHeader);
    end;

    /// <summary>
    /// Updates the Gen. Prod. Posting Group on the return receipt line with the value from the item charge.
    /// Only lines for item charges that don't have a Gen. Prod. Posting Group are updated.
    /// </summary>
    /// <param name="ReturnReceiptLine">The return receipt line that is updated.</param>
    procedure UpdateChargeItemReturnRcptLineGenProdPostingGroup(var ReturnReceiptLine: Record "Return Receipt Line");
    var
        ItemCharge: Record "Item Charge";
    begin
        if not NeedUpdateGenProdPostingGroupOnItemChargeOnReturnRecepitLine(ReturnReceiptLine) then
            exit;

        ItemCharge.Get(ReturnReceiptLine."No.");
        ItemCharge.TestField("Gen. Prod. Posting Group");

        ReturnReceiptLine."Gen. Prod. Posting Group" := ItemCharge."Gen. Prod. Posting Group";
        ReturnReceiptLine.Modify(false);
    end;

    /// <summary>
    /// Updates the Gen. Prod. Posting Group on the sales shipment line with the value from the item charge.
    /// </summary>
    /// <param name="SalesShipmentLine">The sales shipment line that is updated.</param>
    procedure UpdateChargeItemSalesShptLineGenProdPostingGroup(var SalesShipmentLine: Record "Sales Shipment Line");
    var
        ItemCharge: Record "Item Charge";
    begin
        if not NeedUpdateGenProdPostingGroupOnItemChargeOnSalesShipmentLine(SalesShipmentLine) then
            exit;

        ItemCharge.Get(SalesShipmentLine."No.");
        ItemCharge.TestField("Gen. Prod. Posting Group");

        SalesShipmentLine."Gen. Prod. Posting Group" := ItemCharge."Gen. Prod. Posting Group";
        SalesShipmentLine.Modify(false);
    end;

    /// <summary>
    /// Updates the Gen. Prod. Posting Group on the sales line with the value from the item charge.
    /// </summary>
    /// <param name="SalesLine">The sales line that is updated.</param>
    procedure UpdateChargeItemSalesLineGenProdPostingGroup(var SalesLine: Record "Sales Line");
    var
        ItemCharge: Record "Item Charge";
    begin
        if not NeedUpdateGenProdPostingGroupOnItemChargeOnSalesLine(SalesLine) then
            exit;

        ItemCharge.Get(SalesLine."No.");
        ItemCharge.TestField("Gen. Prod. Posting Group");

        SalesLine."Gen. Prod. Posting Group" := ItemCharge."Gen. Prod. Posting Group";
        SalesLine.Modify(false);
    end;

    local procedure CreatePrepaymentLineForCreditMemo(var SalesHeader: Record "Sales Header")
    var
        GLAccount: Record "G/L Account";
        SalesLine: Record "Sales Line";
        SalesInvoiceLine: Record "Sales Invoice Line";
        GeneralPostingSetup: Record "General Posting Setup";
        TempPrepmtSalesLine: Record "Sales Line" temporary;
        TempExtendedTextLine: Record "Extended Text Line" temporary;
        TransferExtendedText: Codeunit "Transfer Extended Text";
        LineNo: Integer;
        IsHandled: Boolean;
    begin
        if not CheckApplicationExistForCreditMemo(SalesHeader) then
            exit;

        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        if SalesLine.FindLast() then
            LineNo := SalesLine."Line No." + 10000
        else
            LineNo := 10000;

        TempPrepmtSalesLine.SetHasBeenShown();
        SalesInvoiceLine.SetRange("Document No.", SalesHeader."Applies-to Doc. No.");
        SalesInvoiceLine.SetRange("Prepayment Line", true);
        if SalesInvoiceLine.FindSet() then
            repeat
                IsHandled := false;
                GeneralPostingSetup.Get(SalesInvoiceLine."Gen. Bus. Posting Group", SalesInvoiceLine."Gen. Prod. Posting Group");
                OnCreatePrepaymentLineForCreditMemoOnBeforeGetSalesPrepmtAccount(GLAccount, SalesInvoiceLine, IsHandled);
                if not IsHandled then
                    GLAccount.Get(GeneralPostingSetup.GetSalesPrepmtAccount());

                TempPrepmtSalesLine.Init();
                TempPrepmtSalesLine."Document Type" := SalesHeader."Document Type";
                TempPrepmtSalesLine."Document No." := SalesHeader."No.";
                TempPrepmtSalesLine."Line No." := LineNo;
                TempPrepmtSalesLine."System-Created Entry" := true;
                TempPrepmtSalesLine.Validate(Type, TempPrepmtSalesLine.Type::"G/L Account");
                TempPrepmtSalesLine.Validate("No.", GLAccount."No.");
                TempPrepmtSalesLine.Validate(Quantity, -1);
                TempPrepmtSalesLine.Validate("Qty. to Ship", TempPrepmtSalesLine.Quantity);
                TempPrepmtSalesLine.Validate("Qty. to Invoice", TempPrepmtSalesLine.Quantity);
                TempPrepmtSalesLine.Validate("Unit Price", SalesInvoiceLine."Unit Price");
                TempPrepmtSalesLine.Validate("Prepayment Line", true);
                TempPrepmtSalesLine.Validate("Shortcut Dimension 1 Code", SalesInvoiceLine."Shortcut Dimension 1 Code");
                TempPrepmtSalesLine.Validate("Shortcut Dimension 2 Code", SalesInvoiceLine."Shortcut Dimension 2 Code");
                TempPrepmtSalesLine.Validate("Dimension Set ID", SalesInvoiceLine."Dimension Set ID");
                LineNo := LineNo + 10000;
                TempPrepmtSalesLine.Insert(true);

                TransferExtendedText.PrepmtGetAnyExtText(
                    TempPrepmtSalesLine."No.",
                    DATABASE::"Sales Cr.Memo Line",
                    SalesHeader."Document Date",
                    SalesHeader."Language Code",
                    TempExtendedTextLine);

                if TempExtendedTextLine.FindSet() then
                    repeat
                        TempPrepmtSalesLine.Init();
                        TempPrepmtSalesLine.Validate(Description, TempExtendedTextLine.Text);
                        TempPrepmtSalesLine.Validate("System-Created Entry", true);
                        TempPrepmtSalesLine.Validate("Prepayment Line", true);
                        TempPrepmtSalesLine.Validate("Line No.", LineNo);
                        LineNo := LineNo + 10000;
                        TempPrepmtSalesLine.Insert(true);
                    until TempExtendedTextLine.Next() = 0;
            until SalesInvoiceLine.Next() = 0;

        if TempPrepmtSalesLine.FindSet() then
            repeat
                TempSalesLineGlobal := TempPrepmtSalesLine;
                TempSalesLineGlobal.Insert(true);
            until TempPrepmtSalesLine.Next() = 0;
    end;

    local procedure CheckApplicationExistForCreditMemo(SalesHeader: Record "Sales Header"): Boolean
    begin
        if not (SalesHeader."Document Type" = SalesHeader."Document Type"::"Credit Memo") then
            exit(false);

        if (SalesHeader."Applies-to Doc. Type" <> SalesHeader."Applies-to Doc. Type"::" ") and
           (SalesHeader."Applies-to Doc. No." <> '')
        then
            exit(true);
    end;

    local procedure AssignPostedDocumentNo(var PostedDocumentNo: Code[20]; DocumentNo: Code[20])
    begin
        if PreviewMode then
            PostedDocumentNo := PostingPreviewNoTok + Format(Random(999999), 0, PostingPreviewNoFormatTxt)
        else
            PostedDocumentNo := DocumentNo;
    end;

    local procedure SyncSurPlusItemTracking(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    var
        Location2: Record Location;
        ReservEntry: Record "Reservation Entry";
        TempTrackingSpecification2: Record "Tracking Specification" temporary;
        TempWarehouseActivityLine: Record "Warehouse Activity Line" temporary;
        WarehouseAvailabilityMgt: Codeunit "Warehouse Availability Mgt.";
        QtyReservedForCurrLine: Decimal;
        SurplusQtyToHandle: Decimal;
        IsHandled: Boolean;
    begin
        if not SalesHeader.Ship then
            exit;
        if not (SalesHeader."Document Type" in [SalesHeader."Document Type"::Invoice, SalesHeader."Document Type"::Order]) then
            exit;

        if (SalesLine."Location Code" = '') or
           not Location2.Get(SalesLine."Location Code") or
           not Location2."Require Shipment"
        then
            exit;

        TempTrackingSpecification2.SetSourceFromSalesLine(SalesLine);
        QtyReservedForCurrLine := Abs(WarehouseAvailabilityMgt.CalcLineReservedQtyOnInvt(
            TempTrackingSpecification2."Source Type", TempTrackingSpecification2."Source Subtype", TempTrackingSpecification2."Source ID", TempTrackingSpecification2."Source Ref. No.",
            0, false, TempWarehouseActivityLine));

        if QtyReservedForCurrLine = 0 then
            exit;

        ReservEntry.SetSourceFilter(
                                 TempTrackingSpecification2."Source Type", TempTrackingSpecification2."Source Subtype",
                                 TempTrackingSpecification2."Source ID", TempTrackingSpecification2."Source Ref. No.", true);
        ReservEntry.SetSourceFilter('', TempTrackingSpecification2."Source Prod. Order Line");
        ReservEntry.SetRange("Reservation Status", ReservEntry."Reservation Status"::Surplus);
        if not ReservEntry.FindSet() then
            exit;

        ReservEntry.CalcSums("Qty. to Handle (Base)");
        SurplusQtyToHandle := Abs(ReservEntry."Qty. to Handle (Base)");
        if (QtyReservedForCurrLine + SurplusQtyToHandle) <= SalesLine."Qty. to Ship (Base)" then
            exit;

        IsHandled := false;
        OnSyncSurPlusItemTrackingOnBeforeModifyQtyToHandleInvoice(SalesLine, SalesHeader, IsHandled, ReservEntry);
        if IsHandled then
            exit;

        ReservEntry.ModifyAll("Qty. to Handle (Base)", 0);
        ReservEntry.ModifyAll("Qty. to Invoice (Base)", 0);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnBeforePostValueEntryToGL', '', false, false)]
    local procedure OnBeforePostValueEntryToGL(var ValueEntry: Record "Value Entry"; var IsHandled: Boolean; PostToGL: Boolean)
    var
        InventorySetup: Record "Inventory Setup";
    begin
        if not PostToGL then
            exit;
        if InventorySetup.UseLegacyPosting() then
            exit;
        PostponedValueEntries.Add(ValueEntry."Entry No.");
        IsHandled := true;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnSetItemAdjmtPropertiesOnBeforeCheckModifyItem', '', false, false)]
    local procedure OnSetItemAdjmtPropertiesOnBeforeCheckModifyItem(var Item2: Record Item)
    var
        InventorySetup: Record "Inventory Setup";
    begin
        if InventorySetup.UseLegacyPosting() then
            exit;

        if not ItemsToAdjust.Contains(Item2."No.") then
            ItemsToAdjust.Add(Item2."No.");
    end;

    /// <summary>
    /// Raised before modifying the purchase order line during archive purchase orders.
    /// </summary>
    /// <param name="PurchOrderLine">The purchase order line.</param>
    /// <param name="TempDropShptPostBuffer">The temporary drop shipment post buffer.</param>
    [IntegrationEvent(false, false)]
    local procedure OnArchivePurchaseOrdersOnBeforePurchOrderLineModify(var PurchOrderLine: Record "Purchase Line"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    begin
    end;

    /// <summary>
    /// Raised before posting the item journal line before post.
    /// </summary>
    /// <param name="SalesLine">The sales line being processed.</param>
    /// <param name="ItemJnlLine">The item journal line.</param>
    /// <param name="TempWhseJnlLine">The temporary warehouse journal line.</param>
    /// <param name="Location">The location record.</param>
    /// <param name="PostWhseJnlLine">Indicates whether to post warehouse journal line.</param>
    /// <param name="QtyToBeShippedBase">The quantity to be shipped in base unit of measure.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="TrackingSpecification">The tracking specification.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemJnlLineBeforePost(SalesLine: Record "Sales Line"; var ItemJnlLine: Record "Item Journal Line"; var TempWhseJnlLine: Record "Warehouse Journal Line" temporary; Location: Record Location; var PostWhseJnlLine: Boolean; QtyToBeShippedBase: Decimal; var IsHandled: Boolean; TrackingSpecification: Record "Tracking Specification")
    begin
    end;

    /// <summary>
    /// Raised before deleting the sales document after posting.
    /// </summary>
    /// <param name="SalesHeader">The sales header to delete.</param>
    /// <param name="SalesInvoiceHeader">The posted sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The posted sales credit memo header.</param>
    /// <param name="SkipDelete">Set to true to skip the delete operation.</param>
    /// <param name="CommitIsSuppressed">Indicates whether database commits are suppressed.</param>
    /// <param name="EverythingInvoiced">Indicates whether everything has been invoiced.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeDeleteAfterPosting(var SalesHeader: Record "Sales Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var SkipDelete: Boolean; CommitIsSuppressed: Boolean; EverythingInvoiced: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary)
    begin
    end;

    /// <summary>
    /// Raised before deleting approval entries.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="IsHandled">Set to true to skip the default delete logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeDeleteApprovalEntries(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before finding the customer ledger entry.
    /// </summary>
    /// <param name="CustLedgEntry">The customer ledger entry to find.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeFindCustLedgEntry(var CustLedgEntry: Record "Cust. Ledger Entry")
    begin
    end;

    /// <summary>
    /// Raised before getting the country code.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="CountryRegionCode">The country/region code to return.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetCountryCode(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var CountryRegionCode: Code[10]; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before getting the country/region code.
    /// </summary>
    /// <param name="CustNo">The customer number.</param>
    /// <param name="ShipToCode">The ship-to code.</param>
    /// <param name="SellToCountryRegionCode">The sell-to country/region code.</param>
    /// <param name="Result">The result country/region code.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetCountryRegionCode(CustNo: Code[20]; ShipToCode: Code[10]; SellToCountryRegionCode: Code[10]; var Result: Code[10]; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before getting the item entry relation.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="ItemEntryRelation">The item entry relation.</param>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetItemEntryRelation(var SalesHeader: Record "Sales Header"; var ItemEntryRelation: Record "Item Entry Relation"; var TempTrackingSpecification: Record "Tracking Specification" temporary; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before getting the sales line quantity.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="QtyType">The quantity type (General, Invoicing, or Shipping).</param>
    /// <param name="SalesLineQty">The sales line quantity to return.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetSalesLineQty(SalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; var SalesLineQty: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before getting return receipt line from tracking or updating item entry relation.
    /// </summary>
    /// <param name="TempTrackingSpecification">The temporary tracking specification.</param>
    /// <param name="ReturnRcptLine">The return receipt line.</param>
    /// <param name="ItemEntryRelation">The item entry relation.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="TrackingSpecificationExists">Indicates whether tracking specification exists.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetReturnRcptLineFromTrackingOrUpdateItemEntryRelation(var TempTrackingSpecification: Record "Tracking Specification" temporary; var ReturnRcptLine: Record "Return Receipt Line"; var ItemEntryRelation: Record "Item Entry Relation"; var IsHandled: Boolean; TrackingSpecificationExists: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before initializing sales line quantity to invoice.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line to initialize.</param>
    /// <param name="IsHandled">Set to true to skip the default initialization logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInitSalesLineQtyToInvoice(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before initializing post assemble-to-order.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="AsmPost">The assembly post codeunit instance.</param>
    /// <param name="HideProgressWindow">Indicates whether to hide the progress window.</param>
    /// <param name="IsHandled">Set to true to skip the default initialization logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInitPostATO(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var AsmPost: Codeunit "Assembly-Post"; HideProgressWindow: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting the return receipt line.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="ReturnRcptLine">The return receipt line to insert.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="RemQtyToBeInvoicedBase">The remaining quantity to be invoiced in base unit of measure.</param>
    /// <param name="IsHandled">Set to true to skip the default insert logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertReturnReceiptLine(SalesLine: Record "Sales Line"; ReturnRcptLine: Record "Return Receipt Line"; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting ATO associated item journal line.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="PostedATOLink">The posted assemble-to-order link.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="RemQtyToBeInvoicedBase">The remaining quantity to be invoiced in base unit of measure.</param>
    /// <param name="ItemLedgShptEntryNo">The item ledger shipment entry number.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostATOAssocItemJnlLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var PostedATOLink: Record "Posted Assemble-to-Order Link"; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal; var ItemLedgShptEntryNo: Integer; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before evaluating the condition for posting item tracking for receipt.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="ReturnRcptLine">The return receipt line.</param>
    /// <param name="Condition">The condition result.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemTrackingForReceiptCondition(SalesLine: Record "Sales Line"; ReturnRcptLine: Record "Return Receipt Line"; var Condition: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before evaluating the condition for posting item tracking for shipment.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="Condition">The condition result.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemTrackingForShipmentCondition(SalesLine: Record "Sales Line"; SalesShptLine: Record "Sales Shipment Line"; var Condition: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before posting the item tracking line.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="TempItemLedgEntryNotInvoiced">The temporary item ledger entries not invoiced.</param>
    /// <param name="HasATOShippedNotInvoiced">Indicates whether ATO has been shipped but not invoiced.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="ItemLedgShptEntryNo">The item ledger shipment entry number.</param>
    /// <param name="RemQtyToBeInvoiced">The remaining quantity to be invoiced.</param>
    /// <param name="RemQtyToBeInvoicedBase">The remaining quantity to be invoiced in base unit of measure.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    [IntegrationEvent(true, false)]
    local procedure OnBeforePostItemTrackingLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var TempItemLedgEntryNotInvoiced: Record "Item Ledger Entry" temporary; HasATOShippedNotInvoiced: Boolean; var IsHandled: Boolean; var ItemLedgShptEntryNo: Integer; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal; SalesInvoiceHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

    /// <summary>
    /// Raised before posting the sales lines.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="TempSalesLineGlobal">The temporary global sales lines.</param>
    /// <param name="TempVATAmountLine">The temporary VAT amount line.</param>
    /// <param name="EverythingInvoiced">Indicates whether everything has been invoiced.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostSalesLines(var SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: Record "Sales Line" temporary; var TempVATAmountLine: Record "VAT Amount Line" temporary; var EverythingInvoiced: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before setting the item entry relation.
    /// </summary>
    /// <param name="ItemEntryRelation">The item entry relation to set.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    /// <param name="InvoicingTrackingSpecification">The invoicing tracking specification.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSetItemEntryRelation(var ItemEntryRelation: Record "Item Entry Relation"; var SalesShptLine: Record "Sales Shipment Line"; var InvoicingTrackingSpecification: Record "Tracking Specification"; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before determining if warehouse journal line should be posted.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="Result">The result of the determination.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeShouldPostWhseJnlLine(SalesLine: Record "Sales Line"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before summing sales lines (variant 2).
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="NewSalesLine">The new sales line for totals.</param>
    /// <param name="OldSalesLine">The old sales line being processed.</param>
    /// <param name="QtyType">The quantity type (General, Invoicing, or Shipping).</param>
    /// <param name="InsertSalesLine">Indicates whether to insert the sales line.</param>
    /// <param name="CalcAdCostLCY">Indicates whether to calculate adjusted cost in LCY.</param>
    /// <param name="TotalAdjCostLCY">The total adjusted cost in LCY.</param>
    /// <param name="IncludePrepayments">Indicates whether to include prepayments.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSumSalesLines2(SalesHeader: Record "Sales Header"; var NewSalesLine: Record "Sales Line"; var OldSalesLine: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; InsertSalesLine: Boolean; CalcAdCostLCY: Boolean; var TotalAdjCostLCY: Decimal; IncludePrepayments: Boolean; var IsHandled: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before summing temporary sales lines.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="OldSalesLine">The old sales line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSumSalesLinesTemp(var SalesHeader: Record "Sales Header"; var OldSalesLine: Record "Sales Line")
    begin
    end;

    /// <summary>
    /// Raised before posting warehouse shipment lines.
    /// </summary>
    /// <param name="WhseShptLine2">The warehouse shipment line.</param>
    /// <param name="SalesShptLine2">The sales shipment line.</param>
    /// <param name="SalesLine2">The sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="PostedWhseShptHeader">The posted warehouse shipment header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforePostWhseShptLines(var WhseShptLine2: Record "Warehouse Shipment Line"; SalesShptLine2: Record "Sales Shipment Line"; var SalesLine2: Record "Sales Line"; var IsHandled: Boolean; PostedWhseShptHeader: Record "Posted Whse. Shipment Header")
    begin
    end;

    /// <summary>
    /// Raised when setting filters for calculating invoice discount.
    /// </summary>
    /// <param name="SalesLine">The sales line to set filters on.</param>
    /// <param name="SalesHeader">The sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnCalcInvDiscountSetFilter(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after setting factor during calculation of item journal amounts from quantity to be invoiced.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="Factor">The calculated factor.</param>
    /// <param name="ItemJournalLine">The item journal line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnCalcItemJnlAmountsFromQtyToBeInvoicedOnAfterSetFactor(SalesLine: Record "Sales Line"; var Factor: Decimal; var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    /// <summary>
    /// Raised after processing sales lines during create prepayment lines.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="TempPrepmtSalesLine">The temporary prepayment sales line.</param>
    /// <param name="NextLineNo">The next line number.</param>
    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnAfterProcessSalesLines(SalesHeader: Record "Sales Header"; var TempPrepmtSalesLine: Record "Sales Line" temporary; var NextLineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnAfterTempPrepmtSalesLineModify(var TempPrepmtSalesLine: Record "Sales Line" temporary; var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnAfterTempPrepmtSalesLineInsert(var TempPrepmtSalesLine: Record "Sales Line" temporary; var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before inserting temporary line for extended text during create prepayment lines.
    /// </summary>
    /// <param name="TempPrepmtSalesLine">The temporary prepayment sales line.</param>
    /// <param name="TempSalesLine">The temporary sales line.</param>
    /// <param name="TempExtTextLine">The temporary extended text line.</param>
    /// <param name="SalesHeader">The sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnBeforeInsertTempLineForExtText(var TempPrepmtSalesLine: Record "Sales Line" temporary; var TempSalesLine: Record "Sales Line" temporary; var TempExtTextLine: Record "Extended Text Line" temporary; var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before filling temporary lines in the main code procedure.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="CalledBy">Identifies the caller of the posting routine.</param>
    [IntegrationEvent(false, false)]
    local procedure OnCodeOnBeforeFillTempLines(var SalesHeader: Record "Sales Header"; CalledBy: Integer)
    begin
    end;

    /// <summary>
    /// Raised before loop during copy and check item charge.
    /// </summary>
    /// <param name="TempSalesLine">The temporary sales line.</param>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SkipTestJobNo">Set to true to skip the job number test.</param>
    [IntegrationEvent(false, false)]
    local procedure OnCopyAndCheckItemChargeOnBeforeLoop(var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header"; var SkipTestJobNo: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after setting filters during copy to temporary lines.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="SalesHeader">The sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnCopyToTempLinesOnAfterSetFilters(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised before inserting new item charge assignment during insert associated order charge.
    /// </summary>
    /// <param name="TempItemChargeAssgntSales">The temporary item charge assignment.</param>
    /// <param name="NewItemChargeAssgntSales">The new item charge assignment to insert.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertAssocOrderChargeOnBeforeNewItemChargeAssgntSalesInsert(TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)"; var NewItemChargeAssgntSales: Record "Item Charge Assignment (Sales)")
    begin
    end;

    /// <summary>
    /// Raised after transferring fields to sales credit memo header during insert credit memo header.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertCrMemoHeaderOnAfterSalesCrMemoHeaderTransferFields(var SalesHeader: Record "Sales Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

    /// <summary>
    /// Raised before transferring fields to sales credit memo header during insert credit memo header.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertCrMemoHeaderOnBeforeSalesCrMemoHeaderTransferFields(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after calculating whether to insert shipment header during insert posted headers.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="TempWarehouseShipmentHeader">The temporary warehouse shipment header.</param>
    /// <param name="TempWarehouseReceiptHeader">The temporary warehouse receipt header.</param>
    /// <param name="InsertShipmentHeaderNeeded">Indicates whether inserting shipment header is needed.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertPostedHeadersOnAfterCalcInsertShipmentHeaderNeeded(var SalesHeader: Record "Sales Header"; var TempWarehouseShipmentHeader: Record "Warehouse Shipment Header" temporary; var TempWarehouseReceiptHeader: Record "Warehouse Receipt Header" temporary; var InsertShipmentHeaderNeeded: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before inserting the invoice header during insert posted headers.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="IsHandled">Set to true to skip the default insert logic.</param>
    /// <param name="SalesInvHeader">The sales invoice header.</param>
    /// <param name="GenJnlLineDocType">The general journal line document type.</param>
    /// <param name="GenJnlLineDocNo">The general journal line document number.</param>
    /// <param name="GenJnlLineExtDocNo">The general journal line external document number.</param>
    /// <param name="InvoicePostingInterface">The invoice posting interface.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertPostedHeadersOnBeforeInsertInvoiceHeader(SalesHeader: Record "Sales Header"; var IsHandled: Boolean; SalesInvHeader: Record "Sales Invoice Header"; var GenJnlLineDocType: Enum "Gen. Journal Document Type"; var GenJnlLineDocNo: Code[20]; var GenJnlLineExtDocNo: Code[35]; var InvoicePostingInterface: Interface "Invoice Posting")
    begin
    end;

    /// <summary>
    /// Raised before creating posted receipt line during insert return receipt line.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="ReturnRcptLine">The return receipt line.</param>
    /// <param name="WhseRcptLine">The warehouse receipt line.</param>
    /// <param name="PostedWhseRcptHeader">The posted warehouse receipt header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertReturnReceiptLineOnBeforeCreatePostedRcptLine(SalesLine: record "Sales Line"; var ReturnRcptLine: record "Return Receipt Line"; var WhseRcptLine: Record "Warehouse Receipt Line"; PostedWhseRcptHeader: Record "Posted Whse. Receipt Header")
    begin
    end;

    /// <summary>
    /// Raised after calculating whether to get warehouse receipt line during insert return receipt line warehouse post.
    /// </summary>
    /// <param name="ReturnRcptLine">The return receipt line.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="ReturnRcptHeader">The return receipt header.</param>
    /// <param name="ShouldGetWhseRcptLine">Indicates whether to get warehouse receipt line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertReturnReceiptLineWhsePostOnAfterCalcShouldGetWhseRcptLine(var ReturnRcptLine: Record "Return Receipt Line"; SalesLine: Record "Sales line"; WhseShip: Boolean; WhseReceive: Boolean; ReturnRcptHeader: Record "Return Receipt Header"; var ShouldGetWhseRcptLine: Boolean)
    begin
    end;

    /// <summary>
    /// Raised after calculating whether to get warehouse shipment line during insert return receipt line warehouse post.
    /// </summary>
    /// <param name="ReturnRcptLine">The return receipt line.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="WhseShip">Indicates whether warehouse shipment is involved.</param>
    /// <param name="WhseReceive">Indicates whether warehouse receipt is involved.</param>
    /// <param name="ReturnRcptHeader">The return receipt header.</param>
    /// <param name="ShouldGetWhseShptLine">Indicates whether to get warehouse shipment line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertReturnReceiptLineWhsePostOnAfterCalcShouldGetWhseShptLine(var ReturnRcptLine: Record "Return Receipt Line"; SalesLine: Record "Sales line"; WhseShip: Boolean; WhseReceive: Boolean; ReturnRcptHeader: Record "Return Receipt Header"; var ShouldGetWhseShptLine: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before creating posted shipment line during insert return receipt line warehouse post.
    /// </summary>
    /// <param name="ReturnRcptLine">The return receipt line.</param>
    /// <param name="WhseShptLine">The warehouse shipment line.</param>
    /// <param name="PostedWhseShptHeader">The posted warehouse shipment header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertReturnReceiptLineWhsePostOnBeforeCreatePostedShptLine(var ReturnRcptLine: Record "Return Receipt Line"; var WhseShptLine: Record "Warehouse Shipment Line"; PostedWhseShptHeader: Record "Posted Whse. Shipment Header")
    begin
    end;

    /// <summary>
    /// Raised after transferring fields to sales shipment header during insert shipment header.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesShptHeader">The sales shipment header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertShipmentHeaderOnAfterTransferfieldsToSalesShptHeader(SalesHeader: Record "Sales Header"; var SalesShptHeader: Record "Sales Shipment Header")
    begin
    end;

    /// <summary>
    /// Raised before transferring fields to sales shipment header during insert shipment header.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertShipmentHeaderOnBeforeTransferfieldsToSalesShptHeader(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after initializing quantity fields during insert shipment line.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="xSalesLine">The previous sales line.</param>
    /// <param name="SalesShptLine">The sales shipment line.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertShipmentLineOnAfterInitQuantityFields(var SalesLine: Record "Sales Line"; var xSalesLine: Record "Sales Line"; var SalesShptLine: Record "Sales Shipment Line")
    begin
    end;

    /// <summary>
    /// Raised after calculating whether to process shipment relation during insert shipment line.
    /// </summary>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="ShouldProcessShipmentRelation">Indicates whether to process shipment relation.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertShipmentLineOnAfterCalcShouldProcessShipmentRelation(var SalesLine: Record "Sales Line"; var ShouldProcessShipmentRelation: Boolean)
    begin
    end;

    /// <summary>
    /// Raised before transferring fields to sales invoice header during insert invoice header.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertInvoiceHeaderOnBeforeSalesInvHeaderTransferFields(var SalesHeader: Record "Sales Header")
    begin
    end;

    /// <summary>
    /// Raised after transferring fields to sales invoice header during insert invoice header.
    /// </summary>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    [IntegrationEvent(false, false)]
    local procedure OnInsertInvoiceHeaderOnAfterSalesInvHeaderTransferFields(var SalesHeader: Record "Sales Header"; var SalesInvoiceHeader: Record "Sales Invoice Header")
    begin
    end;

    /// <summary>
    /// Raised before dividing amount during sum sales lines 2.
    /// </summary>
    /// <param name="OldSalesLine">The old sales line.</param>
    /// <param name="IsHandled">Set to true to skip the default logic.</param>
    /// <param name="SalesHeader">The sales header.</param>
    /// <param name="SalesLine">The sales line.</param>
    /// <param name="QtyType">The quantity type.</param>
    /// <param name="SalesLineQty">The sales line quantity.</param>
    /// <param name="TempVATAmountLine">The temporary VAT amount line.</param>
    /// <param name="TempVATAmountLineRemainder">The temporary VAT amount line remainder.</param>
    /// <param name="IncludePrepayments">Indicates whether to include prepayments.</param>
    /// <param name="RoundingLineInserted">Indicates whether a rounding line was inserted.</param>
    [IntegrationEvent(false, false)]
    local procedure OnSumSalesLines2OnBeforeDivideAmount(var OldSalesLine: Record "Sales Line"; var IsHandled: Boolean; SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; QtyType: Option; var SalesLineQty: Decimal; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary; IncludePrepayments: Boolean; RoundingLineInserted: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSumSalesLines2OnAfterDivideAmount(var OldSalesLine: Record "Sales Line"; var SalesLineQty: Decimal; QtyType: Option General,Invoicing,Shipping)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSumSalesLines2OnAfterCalcTotalAdjCostLCY(var TotalAdjCostLCY: decimal; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSumSalesLines2OnBeforeCalcVATAmountLines(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; InsertSalesLine: Boolean; var TempVATAmountLine: Record "VAT Amount Line" temporary; QtyType: Option General,Invoicing,Shipping; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSumSalesLines2OnBeforeNewSalesLineInsert(var NewSalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSumSalesLines2SetFilter(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; InsertSalesLine: Boolean; var QtyType: Option)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineWhseLineOnBeforePostTempWhseJnlLine2(var TempWarehouseJournalLine: Record "Warehouse Journal Line" temporary; WhseShip: Boolean; WhseReceive: Boolean; InvtPickPutaway: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateOrderLineBeforeInitQtyToInvoice(var TempSalesLine: Record "Sales Line" temporary; WhseShip: Boolean; WhseReceive: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateOrderLineOnBeforeInitTempSalesLineQuantities(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateOrderLineOnAfterUpdateInvoicedValues(var TempSalesLine: Record "Sales Line" temporary; var SalesHeader: Record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateInvoiceLineOnAfterModifySalesOrderLine(var SalesOrderLine: Record "Sales Line"; TempSalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateInvoiceLineOnBeforeModifySalesOrderLine(var SalesOrderLine: Record "Sales Line"; TempSalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateInvoiceLineOnAfterInsertSalesOrderHeader(var SalesOrderLine: Record "Sales Line"; TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateOrderLineOnAfterInitQtyToReceiveOrShip(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary; WhseShip: Boolean; WhseReceive: Boolean)
    begin
    end;

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

    [IntegrationEvent(true, false)]
    local procedure OnPostUpdateOrderLineOnSetDefaultQtyBlank(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary; SalesSetup: Record "Sales & Receivables Setup"; var SetDefaultQtyBlank: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCalcInvoiceOnAfterTempSalesLineSetFilters(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnCheckAndUpdateOnAfterCalcInvDiscount(SalesHeader: Record "Sales Header"; TempWhseShptHeader: Record "Warehouse Shipment Header" temporary; PreviewMode: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary; SuppressCommit: Boolean; WhseReceive: Boolean; WhseShip: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckAndUpdateOnAfterReleaseSalesDocument(SalesHeader: Record "Sales Header"; PreviewMode: Boolean)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnCheckAndUpdateOnBeforeSetPostingFlags(var SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: Record "Sales Line" temporary; var ModifyHeader: Boolean; var HideProgressWindow: Boolean);
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnCheckAndUpdateOnAfterSetPostingFlags(var SalesHeader: Record "Sales Header"; var TempSalesLineGlobal: Record "Sales Line" temporary; var ModifyHeader: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckAndUpdateOnAfterSetSourceCode(var SalesHeader: Record "Sales Header"; SourceCodeSetup: Record "Source Code Setup"; var SrcCode: Code[10]);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckAndUpdateOnAfterSetPoszingFromWhseRef(var SalesHeader: Record "Sales Header"; var InvtPickPutaway: Boolean; var PostingFromWhseRef: Integer);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckAndUpdateOnBeforeCalcInvDiscount(var SalesHeader: Record "Sales Header"; WarehouseReceiptHeader: Record "Warehouse Receipt Header"; WarehouseShipmentHeader: Record "Warehouse Shipment Header"; WhseReceive: Boolean; WhseShip: Boolean; var RefreshNeeded: Boolean)
    begin
    end;

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

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

    [IntegrationEvent(true, false)]
    local procedure OnCheckSalesDocumentOnAfterCalcShouldCheckItemCharge(var SalesHeader: Record "Sales Header"; WhseReceive: Boolean; WhseShip: Boolean; var ShouldCheckItemCharge: Boolean; var ModifyHeader: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckTrackingAndWarehouseForShipOnBeforeCheck(var SalesHeader: Record "Sales Header"; var TempWhseShipmentHeader: Record "Warehouse Shipment Header" temporary; var TempWhseReceiptHeader: Record "Warehouse Receipt Header" temporary; var Ship: Boolean; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnCheckTrackingAndWarehouseForReceiveOnBeforeCheck(var SalesHeader: Record "Sales Header"; var TempWhseShipmentHeader: Record "Warehouse Shipment Header" temporary; var TempWhseReceiptHeader: Record "Warehouse Receipt Header" temporary; var Receive: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckTrackingSpecificationOnAfterTempItemSalesLineLoop(var TempItemSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckCustBlockageOnAfterTempLinesSetFilters(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnAfterTempPrepmtSalesLineSetFilters(var TempPrepmtSalesLine: Record "Sales Line" temporary; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnAfterGetSalesPrepmtAccount(var GLAcc: Record "G/L Account"; var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header"; CompleteFunctionality: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnBeforeGetSalesPrepmtAccount(var GLAcc: Record "G/L Account"; var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header"; var GenPostingSetup: Record "General Posting Setup"; CompleteFunctionality: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnAfterTempSalesLineSetFilters(var TempSalesLine: Record "Sales Line" temporary; var SalesHeader: Record "Sales Header"; var TempPrepmtSalesLine: Record "Sales Line" temporary; var NextLineNo: Integer)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnFinalizePostingOnAfterUpdateItemChargeAssgnt(var SalesHeader: Record "Sales Header"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFinalizePostingOnBeforeInsertTrackingSpecification(var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var TempItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)" temporary; SalesHeader: Record "Sales Header"; var TempTrackingSpecification: Record "Tracking Specification" temporary; EverythingInvoiced: Boolean; var TempSalesLine: Record "Sales Line" temporary; var TempSalesLineGlobal: Record "Sales Line" temporary; SalesPost: Codeunit "Sales-Post")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFinalizePostingOnBeforeCreateOutboxSalesTrans(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; EverythingInvoiced: Boolean; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnFinalizePostingOnBeforeGenJnlPostPreviewThrowError(SalesHeader: Record "Sales Header"; SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostAssocItemJnlLineOnBeforePost(var ItemJournalLine: Record "Item Journal Line"; PurchOrderLine: Record "Purchase Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostATOOnBeforePostedATOLinkInsert(var PostedATOLink: Record "Posted Assemble-to-Order Link"; var AssemblyHeader: Record "Assembly Header"; var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostATOAssocItemJnlLineOnBeforeRemainingPost(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var PostedATOLink: Record "Posted Assemble-to-Order Link"; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal; var ItemLedgShptEntryNo: Integer)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnPostDropOrderShipmentOnAfterUpdateBlanketOrderLine(PurchOrderHeader: Record "Purchase Header"; PurchOrderLine: Record "Purchase Line"; TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; SalesShptHeader: Record "Sales Shipment Header"; SalesHeader: Record "Sales Header"; PurchRcptHeader: Record "Purch. Rcpt. Header"; var TempTrackingSpecification: Record "Tracking Specification" temporary; SrcCode: Code[10])
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnAfterCopyDocumentFields(var ItemJournalLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; WarehouseReceiptHeader: Record "Warehouse Receipt Header"; WarehouseShipmentHeader: Record "Warehouse Shipment Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnAfterCalcShouldPostItemJnlLineItemCharges(SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; var ShouldPostItemJnlLineItemCharges: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnAfterPrepareItemJnlLine(var ItemJournalLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; WhseShip: Boolean; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; var QtyToBeShipped: Decimal; TrackingSpecification: Record "Tracking Specification"; var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; var QtyToBeShippedBase: Decimal; var RemAmt: Decimal; var RemDiscAmt: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnAfterCopyItemCharge(var ItemJournalLine: Record "Item Journal Line"; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnBeforeIsJobContactLineCheck(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var ShouldPostItemJnlLine: Boolean; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; QtyToBeShipped: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnAfterItemJnlPostLineRunWithCheck(var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnBeforePostItemJnlLineWhseLine(var ItemJnlLine: Record "Item Journal Line"; var TempWhseJnlLine: Record "Warehouse Journal Line" temporary; var TempWhseTrackingSpecification: Record "Tracking Specification" temporary; var TempTrackingSpecification: Record "Tracking Specification" temporary; var IsHandled: Boolean; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnBeforeTransferReservToItemJnlLine(SalesLine: Record "Sales Line"; ItemJnlLine: Record "Item Journal Line"; var CheckApplFromItemEntry: Boolean; var TrackingSpecification: Record "Tracking Specification"; QtyToBeShippedBase: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnBeforeCopyTrackingFromSpec(TrackingSpecification: Record "Tracking Specification"; var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; IsATO: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineItemChargesOnAfterGetItemChargeLine(var ItemChargeSalesLine: Record "Sales Line"; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLinePrepareJournalLineOnBeforeCalcItemJnlAmounts(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; IsATO: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargeOnBeforePostItemJnlLine(var SalesLineToPost: Record "Sales Line"; var SalesLine: Record "Sales Line"; QtyToAssign: Decimal; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerOrderOnAfterCopyToItemJnlLine(var ItemJournalLine: Record "Item Journal Line"; var SalesLine: Record "Sales Line"; GeneralLedgerSetup: Record "General Ledger Setup"; QtyToInvoice: Decimal; var TempItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerOrderOnAfterTempTrackingSpecificationInvSetFilters(SalesHeader: record "Sales Header"; var ItemJnlLine2: record "Item Journal Line"; var TempTrackingSpecificationInv: Record "Tracking Specification" temporary; SalesLine: Record "Sales Line"; var IsHandled: Boolean; var TotalSalesLineLCY: Record "Sales Line"; var TotalSalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerOrderOnBeforeTestJobNo(SalesLine: Record "Sales Line"; var SkipTestJobNo: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerOrderOnBeforeLastRunWithCheck(NonDistrItemJnlLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerOrderOnBeforeRunWithCheck(ItemJnlLine2: Record "Item Journal Line"; var IsHandled: Boolean; var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerShptOnBeforeTestJobNo(SalesShipmentLine: Record "Sales Shipment Line"; var SkipTestJobNo: Boolean; var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerShptOnAfterCheckItemChargePerShpt(SalesShipmentLine: Record "Sales Shipment Line"; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; DistributeCharge: Boolean; var IsHandled: Boolean; SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerShptOnAfterCalcDistributeCharge(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesShptLine: Record "Sales Shipment Line"; TempItemLedgEntry: Record "Item Ledger Entry" temporary; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; var DistributeCharge: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerRetRcptOnAfterCalcDistributeCharge(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; ReturnRcptLine: Record "Return Receipt Line"; TempItemLedgEntry: Record "Item Ledger Entry" temporary; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; var DistributeCharge: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargePerRetRcptOnBeforeTestFieldJobNo(ReturnReceiptLine: Record "Return Receipt Line"; var IsHandled: Boolean; var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingLineOnAfterRetrieveInvoiceSpecification(var SalesLine: Record "Sales Line"; var TempInvoicingSpecification: Record "Tracking Specification" temporary; var TrackingSpecificationExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingForShipmentOnAfterSetFilters(var SalesShipmentLine: Record "Sales Shipment Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingForShipmentOnAfterUpdateSalesShptLineFields(var SalesShipmentLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingForShipmentOnBeforeAdjustQuantityRounding(SalesShptLine: Record "Sales Shipment Line"; RemQtyToInvoiceCurrLine: Decimal; var QtyToBeInvoiced: Decimal; RemQtyToInvoiceCurrLineBase: Decimal; QtyToBeInvoicedBase: Decimal; TrackingSpecificationExists: Boolean; HasATOShippedNotInvoiced: Boolean; var ShouldAdjustQuantityRounding: Boolean)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnPostItemTrackingForShipmentOnBeforeShipmentInvoiceErr(SalesLine: Record "Sales Line"; var IsHandled: Boolean; SalesHeader: Record "Sales Header"; var ItemJnlRollRndg: Boolean; TrackingSpecificationExists: Boolean; var TempTrackingSpecification: Record "Tracking Specification" temporary; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnPostItemTrackingForShipmentOnBeforeReturnReceiptInvoiceErr(SalesLine: Record "Sales Line"; var IsHandled: Boolean; SalesHeader: Record "Sales Header"; var ItemJnlRollRndg: Boolean; TrackingSpecificationExists: Boolean; var TempTrackingSpecification: Record "Tracking Specification" temporary; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingForReceiptOnAfterSetFilters(var ReturnReceiptLine: Record "Return Receipt Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeInsertCrMemoLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var IsHandled: Boolean; xSalesLine: Record "Sales Line"; SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeInsertInvoiceLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var IsHandled: Boolean; xSalesLine: Record "Sales Line"; SalesInvHeader: Record "Sales Invoice Header"; var ShouldInsertInvoiceLine: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeInsertShipmentLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var IsHandled: Boolean; SalesLineACY: Record "Sales Line"; DocType: Option; DocNo: Code[20]; ExtDocNo: Code[35])
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnAfterRoundAmount(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; GenJnlLineDocNo: Code[20])
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeTestJobNo(SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnPostSalesLineOnAfterPostItemTrackingLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; WhseShip: Boolean; WhseReceive: Boolean; InvtPickPutaway: Boolean; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnAfterTestSalesLine(var SalesLine: Record "Sales Line"; var SalesHeader: Record "Sales Header"; var WhseShptHeader: Record "Warehouse Shipment Header"; WhseShip: Boolean; PreviewMode: Boolean; var CostBaseAmount: Decimal)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnPostSalesLineOnBeforePostItemTrackingLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; WhseShip: Boolean; WhseReceive: Boolean; InvtPickPutaway: Boolean; SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var ItemLedgShptEntryNo: Integer; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal; GenJnlLineDocNo: Code[20]; SrcCode: Code[10]; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeTestUnitOfMeasureCode(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempSalesLineGlobal: Record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnAfterAdjustPrepmtAmountLCY(var SalesLine: record "Sales Line"; var xSalesLine: record "Sales Line"; TempTrackingSpecification: record "Tracking Specification" temporary; SalesHeader: record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnAfterInsertReturnReceiptLine(var SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var xSalesLine: Record "Sales Line"; ReturnRcptHeader: Record "Return Receipt Header"; RoundingLineInserted: Boolean; var TempTrackingSpecification: Record "Tracking Specification" temporary; var ItemLedgShptEntryNo: Integer; SalesShipmentHeader: Record "Sales Shipment Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateInvoiceLineOnAfterGetSalesOrderLine(var TempSalesLine: Record "Sales Line" temporary; SalesShptLine: Record "Sales Shipment Line"; SalesOrderLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateInvoiceLineOnBeforeInitQtyToInvoice(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateInvoiceLineOnBeforeCalcQuantityInvoiced(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateReturnReceiptLineOnAfterGetSalesOrderLine(var TempSalesLine: Record "Sales Line" temporary; ReturnRcptLine: Record "Return Receipt Line"; SalesOrderLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateReturnReceiptLineOnBeforeInitQtyToInvoice(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateReturnReceiptLineOnAfterModifySalesOrderLine(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateReturnReceiptLineOnBeforeModifySalesOrderLine(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateReturnReceiptLineOnBeforeCalcQuantityInvoiced(var SalesOrderLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnProcessAssocItemJnlLineOnBeforeTempDropShptPostBufferInsert(var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnProcessAssocItemJnlLineOnBeforePostAssocItemJnlLine(var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRoundAmountOnBeforeIncrAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesLineQty: Decimal; var TotalSalesLine: Record "Sales Line"; var TotalSalesLineLCY: Record "Sales Line"; var xSalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnBeforeCheckTotalInvoiceAmount(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnBeforeFinalizePosting(var SalesHeader: Record "Sales Header"; var SalesShipmentHeader: Record "Sales Shipment Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var ReturnReceiptHeader: Record "Return Receipt Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; CommitIsSuppressed: Boolean; GenJnlLineExtDocNo: Code[35]; var EverythingInvoiced: Boolean; GenJnlLineDocNo: Code[20]; SrcCode: Code[10]; PreviewMode: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnBeforePostSalesLineEndLoop(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var LastLineRetrieved: Boolean; SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; RecSalesHeader: Record "Sales Header"; xSalesLine: Record "Sales Line"; var SalesShipmentHeader: Record "Sales Shipment Header"; var ReturnReceiptHeader: Record "Return Receipt Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnGetATOItemLedgEntriesNotInvoicedOnBeforeItemLedgEntryNotInvoicedInsert(var ItemLedgEntry: Record "Item Ledger Entry")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnGetSalesLinesOnAfterFillTempLines(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemLineOnAfterMakeSalesLineToShip(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemLineOnBeforeMakeSalesLineToShip(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary; var ItemLedgShptEntryNo: Integer; var IsHandled: Boolean; var GenJnlLineDocNo: Code[20]; var GenJnlLineExtDocNo: Code[35]; ReturnReceiptHeader: Record "Return Receipt Header"; var TempHandlingSpecification: Record "Tracking Specification" temporary; var TempHandlingSpecificationInv: Record "Tracking Specification" temporary; var TempTrackingSpecification: Record "Tracking Specification" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemLineOnBeforePostItemInvoiceLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var TempPostedATOLink: Record "Posted Assemble-to-Order Link" temporary; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargeOnAfterPostItemJnlLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnPostItemChargeLineOnAfterTempItemChargeAssgntSalesLoop(var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesLineParam: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargeLineOnBeforePostItemCharge(var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingForReceiptOnBeforeReturnRcptLineModify(SalesHeader: Record "Sales Header"; var ReturnRcptLine: Record "Return Receipt Line"; SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingForReceiptOnBeforeAdjustQuantityRounding(ReturnRcptLine: Record "Return Receipt Line"; RemQtyToInvoiceCurrLine: Decimal; var QtyToBeInvoiced: Decimal; RemQtyToInvoiceCurrLineBase: Decimal; QtyToBeInvoicedBase: Decimal; TrackingSpecificationExists: Boolean; var ShouldAdjustQuantityRounding: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnReleaseSalesDocumentOnBeforeSetStatus(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; SavedStatus: Enum "Sales Document Status"; PreviewMode: Boolean; SuppressCommit: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRoundAmountOnAfterAssignSalesLines(var xSalesLine: Record "Sales Line"; var SalesLineACY: Record "Sales Line"; SalesHeader: Record "Sales Header"; var IsHandled: Boolean; var TotalSalesLines: Record "Sales Line"; var TotalSalesLineLCY: Record "Sales Line"; var SalesLine: Record "Sales Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSaveInvoiceSpecificationOnAfterUpdateTempTrackingSpecification(var TempTrackingSpecification: Record "Tracking Specification" temporary; var TempInvoicingSpecification: Record "Tracking Specification" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSaveInvoiceSpecificationOnBeforeAssignTempInvoicingSpecification(var TempInvoicingSpecification: Record "Tracking Specification" temporary)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnSendPostedDocumentRecordElseCase(SalesHeader: Record "Sales Header"; var DocumentSendingProfile: Record "Document Sending Profile"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTestSalesLineOnAfterTestSalesLineJob(var SalesLine: record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTestSalesLineOnAfterCalcShouldTestReturnQty(SalesLine: Record "Sales Line"; var ShouldTestReturnQty: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeTestGenPostingGroups(var SalesLine: record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateSalesLineBeforePostOnAfterPostJobContractLine(SalesInvoiceHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnUpdateAssocOrderOnAfterModifyPurchLine(var PurchOrderLine: Record "Purchase Line"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateAssocOrderOnBeforeModifyPurchLine(var PurchOrderLine: Record "Purchase Line"; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary)
    begin
    end;

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

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

    [IntegrationEvent(false, false)]
    local procedure OnUpdateAfterPostingOnBeforeFindSetForUpdate(var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateBlanketOrderLineOnBeforeCheck(var BlanketOrderSalesLine: Record "Sales Line"; SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateBlanketOrderLineOnBeforeCheckSellToCustomerNo(var BlanketOrderSalesLine: Record "Sales Line"; SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateBlanketOrderLineOnBeforeInitOutstanding(var BlanketOrderSalesLine: Record "Sales Line"; SalesLine: Record "Sales Line"; Ship: Boolean; Receive: Boolean; Invoice: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateInvoicedQtyOnShipmentLineOnBeforeModifySalesShptLine(var SalesShptLine: Record "Sales Shipment Line"; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDivideAmountOnAfterInitAmount(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesLineQty: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDivideAmountOnAfterInitLineDiscountAmount(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; SalesLineQty: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDivideAmountOnBeforeTempVATAmountLineRemainderModify(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary; Currency: Record Currency)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalcVATBaseAmount(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary; Currency: Record Currency; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostUpdateInvoiceLine(var TempSalesLineGlobal: Record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnBeforePostUpdateReturnReceiptLine(var TempSalesLineGlobal: Record "Sales Line" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertTrackingSpecification(SalesHeader: Record "Sales Header"; var TempTrackingSpecification: Record "Tracking Specification" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSendPostedDocumentRecord(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; var DocumentSendingProfile: Record "Document Sending Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemChargeLine(var SalesLine: Record "Sales Line"; SalesLineACY: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDeleteAfterPostingOnAfterDeleteLinks(var SalesLine: Record "Sales Line")
    begin
    end;

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

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

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

    [IntegrationEvent(false, false)]
    local procedure OnUpdateWonOpportunitiesOnBeforeOpportunityModify(var SalesHeader: Record "Sales Header"; SalesInvoiceHeader: Record "Sales Invoice Header"; var Opportunity: Record Opportunity)
    begin
    end;

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

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

    [IntegrationEvent(false, false)]
    local procedure OnModifyTempLineOnAfterSalesLineModify(var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnModifyTempLineOnBeforeTransferFields(var SalesLine: Record "Sales Line"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnModifyTempLineOnBeforeSalesLineModify(var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnNeedUpdateGenProdPostingGroupOnItemChargeOnSalesLine(SalesLine: Record "Sales Line"; var NeedUpdate: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnNeedUpdateGenProdPostingGroupOnItemChargeOnSalesShipmentLine(SalesShipmentLine: Record "Sales Shipment Line"; var NeedUpdate: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnNeedUpdateGenProdPostingGroupOnItemChargeOnReturnReceiptLine(ReturnReceiptLine: Record "Return Receipt Line"; var NeedUpdate: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateSalesLineDimSetIDFromAppliedEntry(var SalesLineToPost: Record "Sales Line"; var ItemLedgEntry: Record "Item Ledger Entry"; DimSetID: array[10] of Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDeleteAfterPostingOnAfterSetupSalesHeader(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDeleteAfterPostingOnAfterSalesLineDeleteAll(SalesHeader: Record "Sales Header"; SalesInvoiceHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header"; CommitIsSuppressed: Boolean; EverythingInvoiced: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostResJnlLineOnAfterInit(var ResJnlLine: Record "Res. Journal Line"; var SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnValidatePostingAndDocumentDateOnAfterCalcPostingDateExists(var PostingDateExists: Boolean; var ReplacePostingDate: Boolean; var ReplaceDocumentDate: Boolean; var PostingDate: Date; var SalesHeader: Record "Sales Header"; var ModifyHeader: Boolean; var VATDateExists: Boolean; var ReplaceVATDate: Boolean; var VATDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateICPartnerBusPostingGroups(var TempICGenJnlLine: Record "Gen. Journal Line" temporary; SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterGetCurrency(CurrencyCode: Code[10]; var Currency: Record Currency)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean; var TempSalesLineGlobal: Record "Sales Line" temporary; var TempDropShptPostBuffer: Record "Drop Shpt. Post. Buffer" temporary; var RemQtyToBeInvoiced: Decimal; var RemQtyToBeInvoicedBase: Decimal; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnBeforeInsertedPrepmtVATBaseToDeduct(var TempPrepmtSalesLine: Record "Sales Line" temporary; var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertReturnReceiptHeader(var SalesHeader: Record "Sales Header"; var ReturnReceiptHeader: Record "Return Receipt Header")
    begin
    end;

#if not CLEAN27
    [Obsolete('This event is never raised.', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnAfterGetAmountsForDeferral(SalesLine: Record "Sales Line"; var AmtToDefer: Decimal; var AmtToDeferACY: Decimal; var DeferralAccount: Code[20])
    begin
    end;
#endif
    [IntegrationEvent(false, false)]
    local procedure OnPostJobContractLineBeforeTestFields(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnUpdateQtyToBeInvoicedForShipmentOnAfterSetQtyToBeInvoiced(TrackingSpecificationExists: Boolean; HasATOShippedNotInvoiced: Boolean; var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; RemQtyToBeInvoiced: Decimal; RemQtyToBeInvoicedBase: Decimal; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemJnlLineItemCharges(var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateReturnReceiptLineOnBeforeInitOutstanding(var SalesOrderLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

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

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

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineTrackingOnAfterCalcShouldInsertTrkgSpecInv(var SalesLine: Record "Sales Line"; QtyToBeInvoiced: Decimal; var ShouldInsertTrkgSpecInv: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateSalesLineBeforePostOnBeforeGetUnitCost(var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalcItemJnlAmountsFromQtyToBeInvoiced(var ItemJnlLine: Record "Item Journal Line"; SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; QtyToBeInvoiced: Decimal; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckTrackingAndWarehouseForReceiveOnAfterSetFilters(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnBeforeCalcVATAmountLines(var TempSalesLineGlobal: Record "Sales Line" temporary; var SalesHeader: Record "Sales Header"; var TempVATAmountLine: Record "VAT Amount Line" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTestSalesLineOnBeforeTestFieldQtyToShip(SalesLine: Record "Sales Line"; var ShouldTestQtyToShip: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnIsEndLoopForShippedNotInvoicedOnBeforeExit(SalesLine: Record "Sales Line"; SalesShptLine: Record "Sales Shipment Line"; RemQtyToBeInvoiced: Decimal; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLinePrepareJournalLineOnBeforeCalcQuantities(var ItemJnlLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; QtyToBeShippedBase: Decimal; QtyToBeInvoiced: Decimal; QtyToBeInvoicedBase: Decimal; var IsHandled: Boolean; IsATO: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineOnAfterCopyTrackingFromSpec(var ItemJnlLine: Record "Item Journal Line"; SalesLine: Record "Sales Line"; QtyToBeShipped: Decimal; IsATO: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnBeforeValidateQtyToInvoice(var SalesHeader: Record "Sales Header"; var ShouldValidateQtyToInvoice: Boolean; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateAssosOrderPostingNosOnAfterSetFilterTempSalesLine(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckTrackingSpecificationOnBeforeGetItemTrackingSettings(var TempItemSalesLine: Record "Sales Line" temporary; var ItemTrackingSetup: Record "Item Tracking Setup"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemTrackingForReceipt(var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemJnlLineTrackingOnBeforeInsertTempTrkgSpec(var TempTrackingSpecification: Record "Tracking Specification" temporary; var TempTrackingSpec: Record "Tracking Specification" temporary; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertInvoiceHeaderOnBeforeCheckDocumentType(SalesHeader: Record "Sales Header"; var SalesInvHeader: Record "Sales Invoice Header"; SalesSetup: Record "Sales & Receivables Setup"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostInvoiceOnBeforePostBalancingEntry(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; var TotalSalesLine: Record "Sales Line"; var TotalSalesLineLCY: Record "Sales Line"; SuppressCommit: Boolean; PreviewMode: Boolean; InvoicePostingParameters: Record "Invoice Posting Parameters"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforePostSalesLine(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; GenJnlLineDocNo: Code[20]; GenJnlLineExtDocNo: Code[35]; GenJnlLineDocType: Enum "Gen. Journal Document Type"; SrcCode: Code[10]; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean; SalesLineACY: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateInvoiceRounding(var SalesHeader: Record "Sales Header"; var TotalSalesLine: Record "Sales Line"; var SalesLine: Record "Sales Line"; var Currency: Record Currency; var BiggestLineNo: Integer; var LastLineRetrieved: Boolean; var RoundingLineInserted: Boolean; var RoundingLineNo: Integer; UseTempData: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateOrderLineOnAfterSetFilters(var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnPostItemLineOnBeforePostItemJnlLineForInvoiceDoc(SalesHeader: Record "Sales Header"; var SalesLineToShip: Record "Sales Line"; Ship: Boolean; var ItemLedgShptEntryNo: Integer; var GenJnlLineDocNo: Code[20]; var GenJnlLineExtDocNo: Code[35]; SalesShptHeader: Record "Sales Shipment Header"; var TempHandlingSpecification: Record "Tracking Specification" temporary; var TempTrackingSpecificationInv: Record "Tracking Specification" temporary; var TempTrackingSpecification: Record "Tracking Specification" temporary; var IsHandled: Boolean; QtyToInvoice: Decimal; TempAssembletoOrderLink: Record "Posted Assemble-to-Order Link" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingOnAfterCalcShouldPostItemTrackingForReceipt(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; RemQtyToBeInvoiced: Decimal; QtyToInvoiceBaseInTrackingSpec: Decimal; var ShouldPostItemTrackingForReceipt: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingOnAfterCalcShouldPostItemTrackingForShipment(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; RemQtyToBeInvoiced: Decimal; QtyToInvoiceBaseInTrackingSpec: Decimal; var ShouldPostItemTrackingForShipment: Boolean)
    begin
    end;

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

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

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingOnAfterCalcShouldProcessReceipt(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var ShouldProcessReceipt: Boolean; var ItemJnlRollRndg: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateInvoiceLineOnBeforeInitOutstanding(var SalesOrderLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateOrderLineOnAfterCalcShouldCalcPrepmtAmounts(var TempSalesLine: Record "Sales Line" temporary; var ShouldCalcPrepmtAmounts: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterGetGeneralPostingSetup(var GeneralPostingSetup: Record "General Posting Setup"; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckItemTrackingQuantityOnDocumentTypeCaseElse(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSetCommitBehavior(var ErrorOnCommit: Boolean)
    begin
    end;

#if not CLEAN27
    [IntegrationEvent(false, false)]
    [Obsolete('This event is no longer used.', '27.0')]
    local procedure OnSetPostingPreviewDocumentNo(var PreviewDocumentNo: Code[20]; var SalesHeader: Record "Sales Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    [Obsolete('This event is no longer used.', '27.0')]
    local procedure OnGetPostingPreviewDocumentNos(var PreviewDocumentNos: List of [Code[20]])
    begin
    end;
#endif
    [IntegrationEvent(false, false)]
    local procedure OnPostInvoiceOnAfterPostLines(var SalesHeader: Record "Sales Header"; SrcCode: Code[10]; GenJnlLineDocType: Enum "Gen. Journal Document Type"; GenJnlLineDocNo: Code[20]; GenJnlLineExtDocNo: Code[35]; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCopyAndCheckItemChargeOnBeforeAssignQtyToInvoice(var TempSalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeItemLedgerEntryExist(var SalesLine: Record "Sales Line"; ShipOrReceive: Boolean; var HasItemLedgerEntry: Boolean; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnInsertShptEntryRelationOnAfterItemEntryRelationInsert(SalesShipmentLine: Record "Sales Shipment Line"; var ItemEntryRelation: Record "Item Entry Relation"; xSalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemChargePerRetRcpt(SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostUpdateOrderLineOnBeforeSetInvoiceFields(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line"; var ShouldSetInvoiceFields: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCopyAndCheckItemChargeOnBeforeError(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary; var InvoiceEverything: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetSalesLineAdjCostLCY(SalesLine2: Record "Sales Line"; QtyType: Option General,Invoicing,Shipping; AdjCostLCY: Decimal; var Result: Decimal; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnAfterDeleteApprovalEntries(var SalesHeader: Record "Sales Header"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var SalesShipmentHeader: Record "Sales Shipment Header"; var ReturnReceiptHeader: Record "Return Receipt Header")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeUpdateSalesLineBeforePost(var SalesLine: Record "Sales Line"; var SalesHeader: Record "Sales Header"; WhseShip: Boolean; WhseReceive: Boolean; RoundingLineInserted: Boolean; CommitIsSuppressed: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSumSalesLines2(var SalesHeader: Record "Sales Header"; var OldSalesLine: Record "Sales Line"; var NewSalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckPostWhseShptLinesOnAfterWhseShptLinesFound(var SalesShipmentLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line"; var WhseShptLinesFound: Boolean; WarehouseShipmentHeader: Record "Warehouse Shipment Header"; WarehouseReceiptHeader: Record "Warehouse Receipt Header"; WhseShip: Boolean; WhseReceive: Boolean; var WarehouseShipmentLine: Record "Warehouse Shipment Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterDecrementPrepmtAmtInvLCY(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; var PrepmtAmountInvLCY: Decimal; var PrepmtVATAmountInvLCY: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDivideAmountOnBeforeTempVATAmountLineGet(SalesLine: Record "Sales Line"; var TempVATAmountLine: Record "VAT Amount Line" temporary; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostResJnlLineOnShouldExit(var SalesLine: Record "Sales Line"; var ShouldExit: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDivideAmountOnBeforeUpdateTempVATAmountLineRemainder(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; var TempVATAmountLine: Record "VAT Amount Line" temporary; var TempVATAmountLineRemainder: Record "VAT Amount Line" temporary; Currency: Record Currency; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostItemChargeOnAfterCalcTotalChargeAmt(var SalesLineToPost: Record "Sales Line"; QtyToAssign: Decimal; var SalesLine: Record "Sales Line"; xSalesLine: Record "Sales Line")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLinesOnBeforeValidateType(var TempPrepmtSalesLine: Record "Sales Line" temporary; var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnValidatePostingAndDocumentDateOnBeforeValidateDocumentDate(var PostingDateExists: Boolean; var ReplaceDocumentDate: Boolean; var PostingDate: Date; var SalesHeader: Record "Sales Header")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreatePrepaymentTextLines(var TempPrepmtSalesLine: Record "Sales Line" temporary; var TempSalesLine: Record "Sales Line" temporary; SalesHeader: Record "Sales Header"; CompleteFunctionality: Boolean; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeCollectValueEntryRelation(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesInvoiceLine: Record "Sales Invoice Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnBeforeCollectValueEntryRelationForCrMemo(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesInvoiceLine: Record "Sales Invoice Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnAfterCollectValueEntryRelation(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesInvoiceLine: Record "Sales Invoice Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostSalesLineOnAfterCreatePostedDeferralSchedule(var SalesInvLine: Record "Sales Invoice Line"; SalesInvHeader: Record "Sales Invoice Header")
    begin
    end;

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

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

    /// <summary>
    /// Raised before updating won opportunities after posting a sales invoice.
    /// </summary>
    /// <param name="SalesHeader">The sales header that was posted.</param>
    /// <param name="SalesInvHeader">The posted sales invoice header.</param>
    /// <param name="IsHandled">Set to true to skip the default opportunity update logic.</param>
    [IntegrationEvent(false, false)]
    procedure OnBeforeUpdateWonOpportunities(var SalesHeader: Record "Sales Header"; SalesInvHeader: Record "Sales Invoice Header"; var IsHandled: Boolean);
    begin
    end;

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

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

    [IntegrationEvent(false, false)]
    local procedure OnInsertPostedHeadersOnAfterInsertCrMemoHeader(var SalesHeader: Record "Sales Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    begin
    end;

    /// <summary>
    /// Raised before making inventory adjustments after posting.
    /// </summary>
    /// <param name="InvtSetup">The inventory setup record.</param>
    /// <param name="InvtAdjmtHandler">The inventory adjustment handler codeunit.</param>
    /// <param name="IsHandled">Set to true to skip the default inventory adjustment logic.</param>
    [IntegrationEvent(false, false)]
    procedure OnBeforeMakeInventoryAdjustment(var InvtSetup: Record "Inventory Setup"; var InvtAdjmtHandler: Codeunit "Inventory Adjustment Handler"; var IsHandled: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnProcessPostingLinesOnBeforePostDropOrderShipment(SalesHeader: Record "Sales Header"; TotalSalesLine: Record "Sales Line"; TotalSalesLineLCY: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterArchiveUnpostedOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; OrderArchived: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckReturnRcptLine(var ReturnReceiptLine: Record "Return Receipt Line"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCopyAndCheckItemCharge(var SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary; var SalesLine: Record "Sales Line"; var InvoiceEverything: Boolean; var AssignError: Boolean; var QtyNeeded: Decimal; var TempItemChargeAssgntSales: Record "Item Charge Assignment (Sales)" temporary; var ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)"; var TempSalesLineGlobal: Record "Sales Line" temporary; var IsHandled: Boolean);
    begin
    end;

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

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

    [IntegrationEvent(false, false)]
    local procedure OnPostItemTrackingForShipmentOnBeforeTestLineFields(var SalesShipmentLine: Record "Sales Shipment Line"; var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateQtyToBeInvoicedForReturnReceiptOnAfterSetQtyToBeInvoiced(TrackingSpecificationExists: Boolean; var QtyToBeInvoiced: Decimal; var QtyToBeInvoicedBase: Decimal; RemQtyToBeInvoiced: Decimal; RemQtyToBeInvoicedBase: Decimal; var SalesLine: Record "Sales Line")
    begin
    end;

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

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

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

    [IntegrationEvent(false, false)]
    local procedure OnBeforeFinalizePostATO(var SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckATOLink(SalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSumSalesLinesTempOnAfterVatAmountSet(var VATAmount: Decimal; var TotalSalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertShptEntryRelationOnBeforeDeleteTempHandlingSpecification(var TempHandlingTrackingSpecification: Record "Tracking Specification" temporary)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnAfterPostJobContractLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var GenJnlLineDocType: Enum "Gen. Journal Document Type"; var GenJnlLineDocNo: Code[20]; var GenJnlLineExtDocNo: Code[35]; var SrcCode: Code[10])
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostDistributeItemCharge(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var TempItemLedgerEntry: Record "Item Ledger Entry"; NonDistrQuantity: Decimal; NonDistrQtyToAssign: Decimal; NonDistrAmountToAssign: Decimal; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostDistributeItemChargeOnAfterSetFactor(TempItemLedgerEntry: Record "Item Ledger Entry"; var Factor: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalcPrepmtAmtToDeduct(var SalesLine: Record "Sales Line"; Ship: Boolean; var IsHandled: Boolean; var PrepmtAmtToDeduct: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostItemJournalLineWarehouseLine(var TempWarehouseJournalLine: Record "Warehouse Journal Line" temporary; var TempWhseTrackingSpecification: Record "Tracking Specification" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPostItemJournalLineWarehouseLine(var TempWarehouseJournalLine: Record "Warehouse Journal Line" temporary; var TempWhseTrackingSpecification: Record "Tracking Specification" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAdjustPrepmtAmountLCYOnAfterGetOrderLine(var SalesLine: Record "Sales Line"; var SalesInvoiceLine: Record "Sales Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetQtyToInvoice(SalesLine: Record "Sales Line"; Ship: Boolean; var IsHandled: Boolean; var QtyToInvoice: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeAdjustFinalInvWith100PctPrepmt(var TempPrepmtDeductLCYSalesLine: Record "Sales Line" temporary; var CombinedSalesLine: Record "Sales Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateRemainingQtyToBeInvoiced(SalesShptLine: Record "Sales Shipment Line"; var RemQtyToInvoiceCurrLine: Decimal; var RemQtyToInvoiceCurrLineBase: Decimal; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreatePrepaymentLineForCreditMemoOnBeforeGetSalesPrepmtAccount(var GLAccount: Record "G/L Account"; var SalesInvoiceLine: Record "Sales Invoice Line"; var IsHandled: Boolean)
    begin
    end;

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

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

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSetInvoiceOrderNo(SalesLine: Record "Sales Line"; var SalesInvLine: Record "Sales Invoice Line"; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnSyncSurPlusItemTrackingOnBeforeModifyQtyToHandleInvoice(var SalesLine: Record "Sales Line"; var SalesHeader: Record "Sales Header"; var IsHandled: Boolean; var ReservationEntry: Record "Reservation Entry")
    begin
    end;
}