Codeunit 99000822 Mfg. Item Jnl.-Post Line

App
Base Application
Namespace
Microsoft.Inventory.Posting
Versions
27-28

Procedures, 1Events, 61

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/Manufacturing/Inventory/Posting/MfgItemJnlPostLine.Codeunit.al1584 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.Inventory.Posting;

using Microsoft.Finance.Currency;
using Microsoft.Finance.Dimension;
using Microsoft.Foundation.AuditCodes;
using Microsoft.Foundation.UOM;
using Microsoft.Inventory.Costing;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Journal;
using Microsoft.Inventory.Ledger;
using Microsoft.Inventory.Location;
using Microsoft.Inventory.Tracking;
using Microsoft.Manufacturing.Capacity;
using Microsoft.Manufacturing.Document;
using Microsoft.Manufacturing.MachineCenter;
using Microsoft.Manufacturing.Setup;
using Microsoft.Manufacturing.WorkCenter;
using Microsoft.Warehouse.Journal;
using System.Reflection;

codeunit 99000822 "Mfg. Item Jnl.-Post Line"
{
    Permissions = tabledata "Prod. Order Capacity Need" = rm,
                  tabledata "Capacity Ledger Entry" = rm;

    var
        Item: Record Item;
        Location: Record Location;
        ManufacturingSetup: Record "Manufacturing Setup";
        WhseJnlLine: Record "Warehouse Journal Line";
#if not CLEAN27
        ItemJnlPostLine: Codeunit "Item Jnl.-Post Line";
#endif
        ProdOrderCompReserve: Codeunit "Prod. Order Comp.-Reserve";
        ProdOrderLineReserve: Codeunit "Prod. Order Line-Reserve";
        ProdOrderWarehouseMgt: Codeunit "Prod. Order Warehouse Mgt.";
        ACYMgt: Codeunit "Additional-Currency Management";
        UOMMgt: Codeunit "Unit of Measure Management";
        WMSManagement: Codeunit "WMS Management";
        CannotBeLessThanZeroErr: Label 'cannot be less than zero';
        ItemTrackingSignErr: Label 'Item Tracking is signed wrongly.';
        MustNotDefineItemTrackingErr: Label 'You must not define item tracking on %1 %2.';

    // Consumption Posting

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnPostConsumption', '', true, false)]
    local procedure OnPostConsumption(
        var ItemJnlLine: Record "Item Journal Line"; GlobalItemTrackingSetup: Record "Item Tracking Setup"; var TempSplitItemJnlLine: Record "Item Journal Line" temporary;
        var ProdOrderCompModified: Boolean; ItemLedgEntryNo: Integer; var sender: Codeunit "Item Jnl.-Post Line")
    begin
        PostConsumption(ItemJnlLine, GlobalItemTrackingSetup, TempSplitItemJnlLine, ProdOrderCompModified, ItemLedgEntryNo, sender);
    end;

    local procedure PostConsumption(var ItemJnlLine: Record "Item Journal Line"; GlobalItemTrackingSetup: Record "Item Tracking Setup"; var TempSplitItemJnlLine: Record "Item Journal Line" temporary; var ProdOrderCompModified: Boolean; ItemLedgEntryNo: Integer; var sender: Codeunit "Item Jnl.-Post Line")
    var
        ProdOrderComp: Record "Prod. Order Component";
        TempHandlingSpecification: Record "Tracking Specification" temporary;
        MfgItemTrackingMgt: Codeunit "Mfg. Item Tracking Mgt.";
        RemQtyToPost: Decimal;
        RemQtyToPostThisLine: Decimal;
        QtyToPost: Decimal;
        UseItemTrackingApplication: Boolean;
        LastLoop: Boolean;
        EndLoop: Boolean;
        NewRemainingQty: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnPostConsumptionOnBeforeCheckOrderType(ProdOrderComp, ItemJnlLine, IsHandled);
#if not CLEAN27
        sender.RunOnPostConsumptionOnBeforeCheckOrderType(ProdOrderComp, ItemJnlLine, IsHandled);
#endif
        if not IsHandled then
            ItemJnlLine.TestField("Order Type", ItemJnlLine."Order Type"::Production);
        ProdOrderComp.SetCurrentKey(Status, "Prod. Order No.", "Prod. Order Line No.", "Item No.", "Line No.");
        ProdOrderComp.SetRange(Status, ProdOrderComp.Status::Released);
        ProdOrderComp.SetRange("Prod. Order No.", ItemJnlLine."Order No.");
        ProdOrderComp.SetRange("Prod. Order Line No.", ItemJnlLine."Order Line No.");
        ProdOrderComp.SetRange("Item No.", ItemJnlLine."Item No.");
        if ItemJnlLine."Prod. Order Comp. Line No." <> 0 then
            ProdOrderComp.SetRange("Line No.", ItemJnlLine."Prod. Order Comp. Line No.");
        if ItemJnlLine."Variant Code" <> '' then
            ProdOrderComp.SetRange("Variant Code", ItemJnlLine."Variant Code");

        ProdOrderComp.LockTable();

        RemQtyToPost := ItemJnlLine.Quantity;

        OnPostConsumptionOnBeforeFindSetProdOrderComp(ProdOrderComp, ItemJnlLine);
#if not CLEAN27
        sender.RunOnPostConsumptionOnBeforeFindSetProdOrderComp(ProdOrderComp, ItemJnlLine);
#endif
        if ProdOrderComp.FindSet() then begin
            OnPostConsumptionOnAfterFindProdOrderComp(ProdOrderComp);
#if not CLEAN27
            sender.RunOnPostConsumptionOnAfterFindProdOrderComp(ProdOrderComp);
#endif
            if ItemJnlLine.TrackingExists() and not sender.GetSkipRetrieveItemTracking() then
                UseItemTrackingApplication :=
                  MfgItemTrackingMgt.RetrieveConsumpItemTracking(ItemJnlLine, TempHandlingSpecification);

            if UseItemTrackingApplication then begin
                TempHandlingSpecification.SetTrackingFilterFromItemJnlLine(ItemJnlLine);
                LastLoop := false;
            end else
                if ReservationExists(ItemJnlLine) then
                    ItemJnlLine.CheckTrackingIfRequiredNotBlank(GlobalItemTrackingSetup);

            repeat
                IsHandled := false;
                OnPostConsumptionOnBeforeCalcRemQtyToPostThisLine(ProdOrderComp, ItemJnlLine, TempHandlingSpecification, RemQtyToPost, UseItemTrackingApplication, LastLoop, IsHandled);
#if not CLEAN27
                sender.RunOnPostConsumptionOnBeforeCalcRemQtyToPostThisLine(ProdOrderComp, ItemJnlLine, TempHandlingSpecification, RemQtyToPost, UseItemTrackingApplication, LastLoop, IsHandled);
#endif
                if not IsHandled then
                    if UseItemTrackingApplication then begin
                        TempHandlingSpecification.SetRange("Source Ref. No.", ProdOrderComp."Line No.");
                        if LastLoop then begin
                            RemQtyToPostThisLine := ProdOrderComp."Remaining Qty. (Base)";
                            if TempHandlingSpecification.FindSet() then
                                repeat
                                    CheckItemTrackingOfComp(GlobalItemTrackingSetup, TempHandlingSpecification, ItemJnlLine);
                                    RemQtyToPostThisLine += TempHandlingSpecification."Qty. to Handle (Base)";
                                until TempHandlingSpecification.Next() = 0;
                            if RemQtyToPostThisLine * RemQtyToPost < 0 then
                                Error(ItemTrackingSignErr);
                        end else
                            if TempHandlingSpecification.FindFirst() then begin
                                RemQtyToPostThisLine := -TempHandlingSpecification."Qty. to Handle (Base)";
                                TempHandlingSpecification.Delete();
                            end else begin
                                TempHandlingSpecification.ClearTrackingFilter();
                                TempHandlingSpecification.FindFirst();
                                CheckItemTrackingOfComp(GlobalItemTrackingSetup, TempHandlingSpecification, ItemJnlLine);
                                RemQtyToPostThisLine := 0;
                            end;
                        if RemQtyToPostThisLine > RemQtyToPost then
                            RemQtyToPostThisLine := RemQtyToPost;
                    end else begin
                        RemQtyToPostThisLine := RemQtyToPost;
                        LastLoop := true;
                    end;

                QtyToPost := RemQtyToPostThisLine;
                ProdOrderComp.CalcFields("Act. Consumption (Qty)");
                NewRemainingQty := ProdOrderComp."Expected Qty. (Base)" - ProdOrderComp."Act. Consumption (Qty)" - QtyToPost;
                OnPostConsumptionOnAfterCalcNewRemainingQty(ProdOrderComp, NewRemainingQty, QtyToPost);
#if not CLEAN27
                sender.RunOnPostConsumptionOnAfterCalcNewRemainingQty(ProdOrderComp, NewRemainingQty, QtyToPost);
#endif
                NewRemainingQty := Round(NewRemainingQty, UOMMgt.QtyRndPrecision());
                if (NewRemainingQty * ProdOrderComp."Expected Qty. (Base)") <= 0 then begin
                    QtyToPost := ProdOrderComp."Remaining Qty. (Base)";
                    ProdOrderComp."Remaining Qty. (Base)" := 0;
                end else begin
                    if (ProdOrderComp."Remaining Qty. (Base)" * ProdOrderComp."Expected Qty. (Base)") >= 0 then
                        QtyToPost := ProdOrderComp."Remaining Qty. (Base)" - NewRemainingQty
                    else
                        QtyToPost := NewRemainingQty;
                    ProdOrderComp."Remaining Qty. (Base)" := NewRemainingQty;
                end;

                IsHandled := false;
                OnPostConsumptionOnBeforeCalcRemainingQuantity(ProdOrderComp, ItemJnlLine, NewRemainingQty, QtyToPost, IsHandled, RemQtyToPost);
#if not CLEAN27
                sender.RunOnPostConsumptionOnBeforeCalcRemainingQuantity(ProdOrderComp, ItemJnlLine, NewRemainingQty, QtyToPost, IsHandled, RemQtyToPost);
#endif
                if not IsHandled then
                    ProdOrderComp."Remaining Quantity" := Round(ProdOrderComp."Remaining Qty. (Base)" / ProdOrderComp."Qty. per Unit of Measure", UOMMgt.QtyRndPrecision());

                UpdateQtyPickedForOptionalWhsePick(ProdOrderComp, QtyToPost + ProdOrderComp."Act. Consumption (Qty)");

                if QtyToPost <> 0 then begin
                    RemQtyToPost := RemQtyToPost - QtyToPost;
                    ProdOrderComp.Modify();
                    if ProdOrderCompModified then
                        InsertConsumpEntry(
                            ItemJnlLine, ProdOrderComp, ProdOrderComp."Line No.", QtyToPost, false, ItemLedgEntryNo,
                            TempSplitItemJnlLine, sender)
                    else
                        InsertConsumpEntry(
                            ItemJnlLine, ProdOrderComp, ProdOrderComp."Line No.", QtyToPost, true, ItemLedgEntryNo,
                            TempSplitItemJnlLine, sender);
                    OnPostConsumptionOnAfterInsertEntry(ProdOrderComp);
#if not CLEAN27
                    sender.RunOnPostConsumptionOnAfterInsertEntry(ProdOrderComp);
#endif
                end;

                if UseItemTrackingApplication then begin
                    if ProdOrderComp.Next() = 0 then begin
                        EndLoop := LastLoop;
                        LastLoop := true;
                        ProdOrderComp.Find('-');
                        TempHandlingSpecification.Reset();
                    end;
                end else
                    EndLoop := ProdOrderComp.Next() = 0;

            until EndLoop or (RemQtyToPost = 0);
        end;

        OnPostConsumptionOnRemQtyToPostOnBeforeInsertConsumpEntry(ItemJnlLine, ProdOrderComp);
#if not CLEAN27
        sender.RunOnPostConsumptionOnRemQtyToPostOnBeforeInsertConsumpEntry(ItemJnlLine, ProdOrderComp);
#endif
        IsHandled := false;
        OnPostConsumptionOnBeforeInsertRemainingConsumpEntry(ItemJnlLine, ProdOrderComp, IsHandled);
        if not IsHandled then
            if RemQtyToPost <> 0 then
                InsertConsumpEntry(
                    ItemJnlLine, ProdOrderComp, ItemJnlLine."Prod. Order Comp. Line No.", RemQtyToPost, false,
                    ItemLedgEntryNo, TempSplitItemJnlLine, sender);

        ProdOrderCompModified := false;

        OnAfterPostConsumption(ProdOrderComp, ItemJnlLine);
#if not CLEAN27
        sender.RunOnAfterPostConsumption(ProdOrderComp, ItemJnlLine);
#endif
    end;

    local procedure CheckItemTrackingOfComp(GlobalItemTrackingSetup: Record "Item Tracking Setup"; TempHandlingSpecification: Record "Tracking Specification"; ItemJnlLine: Record "Item Journal Line")
    var
        ItemTrackingSetup2: Record "Item Tracking Setup";
    begin
        ItemTrackingSetup2 := GlobalItemTrackingSetup;
        ItemTrackingSetup2.CopyTrackingFromTrackingSpec(TempHandlingSpecification);
        ItemJnlLine.CheckTrackingIfRequired(ItemTrackingSetup2);

        OnAfterCheckItemTrackingOfComp(TempHandlingSpecification, ItemJnlLine);
#if not CLEAN27
        ItemJnlPostLine.RunOnAfterCheckItemTrackingOfComp(TempHandlingSpecification, ItemJnlLine);
#endif
    end;

    local procedure InsertConsumpEntry(var ItemJnlLine: Record "Item Journal Line"; var ProdOrderComp: Record "Prod. Order Component"; ProdOrderCompLineNo: Integer; QtyBase: Decimal; ModifyProdOrderComp: Boolean; ItemLedgEntryNo: Integer; var TempSplitItemJnlLine: Record "Item Journal Line" temporary; var sender: Codeunit "Item Jnl.-Post Line")
    var
        PostWhseJnlLine: Boolean;
    begin
        OnBeforeInsertConsumpEntry(ProdOrderComp, QtyBase, ModifyProdOrderComp, ItemJnlLine, TempSplitItemJnlLine);
#if not CLEAN27
        sender.RunOnBeforeInsertConsumpEntry(ProdOrderComp, QtyBase, ModifyProdOrderComp, ItemJnlLine, TempSplitItemJnlLine);
#endif

        ItemJnlLine.Quantity := QtyBase;
        ItemJnlLine."Quantity (Base)" := QtyBase;
        ItemJnlLine."Invoiced Quantity" := QtyBase;
        ItemJnlLine."Invoiced Qty. (Base)" := QtyBase;
        ItemJnlLine."Prod. Order Comp. Line No." := ProdOrderCompLineNo;
        if ModifyProdOrderComp then begin
            if not sender.GetCalledFromInvtPutawayPick() then
                ProdOrderCompReserve.TransferPOCompToItemJnlLine(ProdOrderComp, ItemJnlLine, QtyBase);
            OnBeforeProdOrderCompModify(ProdOrderComp, ItemJnlLine);
#if not CLEAN27
            sender.RunOnBeforeProdOrderCompModify(ProdOrderComp, ItemJnlLine);
#endif
            ProdOrderComp.Modify();
        end;

        if ItemJnlLine."Value Entry Type" <> ItemJnlLine."Value Entry Type"::Revaluation then begin
            GetLocation(ItemJnlLine."Location Code");
            if Location."Bin Mandatory" and (not sender.GetCalledFromInvtPutawayPick()) then
                if Item.Get(ItemJnlLine."Item No.") and Item.IsInventoriableType() then begin
                    ProdOrderWarehouseMgt.CreateWhseJnlLineFromConsumptionJournal(ItemJnlLine, WhseJnlLine);
                    WMSManagement.CheckWhseJnlLine(WhseJnlLine, 3, 0, false);
                    PostWhseJnlLine := true;
                end;
        end;

        OnInsertConsumpEntryOnBeforePostItem(ItemJnlLine, ProdOrderComp, PostWhseJnlLine, WhseJnlLine);
#if not CLEAN27
        sender.RunOnInsertConsumpEntryOnBeforePostItem(ItemJnlLine, ProdOrderComp, PostWhseJnlLine, WhseJnlLine);
#endif

        sender.PostItem(ItemJnlLine);
        if PostWhseJnlLine then
            sender.RegisterWhseJnlLine(WhseJnlLine);

        OnAfterInsertConsumpEntry(WhseJnlLine, ProdOrderComp, QtyBase, PostWhseJnlLine, ItemJnlLine, ItemLedgEntryNo);
#if not CLEAN27
        sender.RunOnAfterInsertConsumpEntry(WhseJnlLine, ProdOrderComp, QtyBase, PostWhseJnlLine, ItemJnlLine, ItemLedgEntryNo);
#endif
    end;

    local procedure ReservationExists(ItemJnlLine: Record "Item Journal Line"): Boolean
    var
        ReservEntry: Record "Reservation Entry";
        ProductionOrder: Record "Production Order";
        IsHandled: Boolean;
        Result: Boolean;
    begin
        IsHandled := false;
        OnBeforeReservationExists(ItemJnlLine, Result, IsHandled);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeReservationExists(ItemJnlLine, Result, IsHandled);
#endif
        if IsHandled then
            exit(Result);

        ReservEntry.SetRange("Source ID", ItemJnlLine."Order No.");
        if ItemJnlLine."Prod. Order Comp. Line No." <> 0 then
            ReservEntry.SetRange("Source Ref. No.", ItemJnlLine."Prod. Order Comp. Line No.");
        ReservEntry.SetRange("Source Type", DATABASE::"Prod. Order Component");
        ReservEntry.SetRange("Source Subtype", ProductionOrder.Status::Released);
        ReservEntry.SetRange("Source Batch Name", '');
        ReservEntry.SetRange("Source Prod. Order Line", ItemJnlLine."Order Line No.");
        ReservEntry.SetFilter("Qty. to Handle (Base)", '<>0');
        exit(not ReservEntry.IsEmpty);
    end;

    local procedure UpdateQtyPickedForOptionalWhsePick(var ProdOrderComp: Record "Prod. Order Component"; QtyPosted: Decimal)
    begin
        GetLocation(ProdOrderComp."Location Code");
        if Location."Prod. Consump. Whse. Handling" <> Location."Prod. Consump. Whse. Handling"::"Warehouse Pick (mandatory)" then
            if ProdOrderComp."Qty. Picked (Base)" < QtyPosted then
                ProdOrderComp.Validate("Qty. Picked (Base)", QtyPosted);
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckItemTrackingOfComp(TempHandlingSpecification: Record "Tracking Specification"; ItemJnlLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnBeforeCheckOrderType(var ProdOrderComponent: Record "Prod. Order Component"; var ItemJournalLine: Record "Item Journal Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnBeforeFindSetProdOrderComp(var ProdOrderComponent: Record "Prod. Order Component"; var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeProdOrderCompModify(var ProdOrderComponent: Record "Prod. Order Component"; ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertConsumpEntryOnBeforePostItem(var ItemJournalLine: Record "Item Journal Line"; ProdOrderComponent: Record "Prod. Order Component"; PostWhseJnlLine: Boolean; var WarehouseJournalLine: Record "Warehouse Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeReservationExists(ItemJnlLine: Record "Item Journal Line"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnAfterFindProdOrderComp(var ProdOrderComp: Record "Prod. Order Component")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertConsumpEntry(var WarehouseJournalLine: Record "Warehouse Journal Line"; var ProdOrderComponent: Record "Prod. Order Component"; QtyBase: Decimal; PostWhseJnlLine: Boolean; var ItemJnlLine: Record "Item Journal Line"; ItemLedgEntryNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnRemQtyToPostOnBeforeInsertConsumpEntry(var ItemJnlLine: Record "Item Journal Line"; var ProdOrderComponent: Record "Prod. Order Component")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnBeforeInsertRemainingConsumpEntry(var ItemJournalLine: Record "Item Journal Line"; var ProdOrderComponent: Record "Prod. Order Component"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnBeforeCalcRemQtyToPostThisLine(var ProdOrderComp: Record "Prod. Order Component"; var ItemJnlLine: Record "Item Journal Line"; var TempHandlingSpecification: Record "Tracking Specification"; RemQtyToPost: Decimal; UseItemTrackingApplication: Boolean; LastLoop: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnBeforeCalcRemainingQuantity(var ProdOrderComp: Record "Prod. Order Component"; var ItemJnlLine: Record "Item Journal Line"; var NewRemainingQty: Decimal; var QtyToPost: Decimal; var IsHandled: Boolean; var RemQtyToPost: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnAfterInsertEntry(var ProdOrderComponent: Record "Prod. Order Component")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPostConsumption(var ProdOrderComp: Record "Prod. Order Component"; var ItemJnlLine: Record "Item Journal Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertConsumpEntry(var ProdOrderComponent: Record "Prod. Order Component"; QtyBase: Decimal; var ModifyProdOrderComp: Boolean; var ItemJnlLine: Record "Item Journal Line"; var TempSplitItemJnlLine: Record "Item Journal Line" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostConsumptionOnAfterCalcNewRemainingQty(ProdOrderComponent: Record "Prod. Order Component"; var NewRemainingQuantity: Decimal; QtyToPost: Decimal)
    begin
    end;

    // Output Posting

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnPostOutput', '', true, false)]
    local procedure OnPostOutput(
        var ItemJnlLine: Record "Item Journal Line"; GlobalItemTrackingSetup: Record "Item Tracking Setup"; GlobalItemTrackingCode: Record "Item Tracking Code";
        var GlobalItemLedgerEntry: Record "Item Ledger Entry"; var LastOperation: Boolean; var sender: Codeunit "Item Jnl.-Post Line")
    begin
        PostOutput(ItemJnlLine, GlobalItemTrackingSetup, GlobalItemTrackingCode, GlobalItemLedgerEntry, LastOperation, sender);
    end;

    local procedure PostOutput(
        var ItemJnlLine: Record "Item Journal Line"; GlobalItemTrackingSetup: Record "Item Tracking Setup"; GlobalItemTrackingCode: Record "Item Tracking Code";
        var GlobalItemLedgerEntry: Record "Item Ledger Entry"; var LastOperation: Boolean; var sender: Codeunit "Item Jnl.-Post Line")
    var
        MfgItem: Record Item;
        MfgSKU: Record "Stockkeeping Unit";
        CapLedgEntry: Record "Capacity Ledger Entry";
        ItemLedgerEntry: Record "Item Ledger Entry";
        ProdOrder: Record "Production Order";
        ProdOrderLine: Record "Prod. Order Line";
        ItemJnlLineSubContracting: Record "Item Journal Line";
        DirCostAmt: Decimal;
        IndirCostAmt: Decimal;
        ValuedQty: Decimal;
        MfgUnitCost: Decimal;
        ReTrack: Boolean;
        PostWhseJnlLine: Boolean;
        SkipPost: Boolean;
        IsHandled: Boolean;
        SkipInventoryValueZeroCheck: Boolean;
    begin
        OnBeforePostOutput(ItemJnlLine, SkipInventoryValueZeroCheck);
#if not CLEAN27
        sender.RunOnBeforePostOutput(ItemJnlLine);
#endif

        if ItemJnlLine."Stop Time" <> 0 then begin
            sender.InsertCapLedgEntry(ItemJnlLine, CapLedgEntry, ItemJnlLine."Stop Time", ItemJnlLine."Stop Time");
            SkipPost := ItemJnlLine.OnlyStopTime();
            OnPostOutputOnAfterInsertCapLedgEntry(ItemJnlLine, SkipPost);
#if not CLEAN27
            sender.RunOnPostOutputOnAfterInsertCapLedgEntry(ItemJnlLine, SkipPost);
#endif
            if SkipPost then
                exit;
        end;

        if ItemJnlLine.OutputValuePosting() then begin
            sender.PostItem(ItemJnlLine);
            exit;
        end;

        if ItemJnlLine.Subcontracting then
            ValuedQty := ItemJnlLine."Invoiced Quantity"
        else
            ValuedQty := CalcCapQty(ItemJnlLine);

        if GetItem(ItemJnlLine."Item No.", false) then
            if not sender.GetCalledFromAdjustment() then
                if not SkipInventoryValueZeroCheck then
                    Item.TestField("Inventory Value Zero", false);

        if ItemJnlLine."Item Shpt. Entry No." <> 0 then
            CapLedgEntry.Get(ItemJnlLine."Item Shpt. Entry No.")
        else
            PostOutputForProdOrder(
                ItemJnlLine, ProdOrder, ProdOrderLine, CapLedgEntry, ValuedQty, LastOperation,
                GlobalItemTrackingSetup, GlobalItemTrackingCode, sender);

        sender.CalcDirAndIndirCostAmts(DirCostAmt, IndirCostAmt, ValuedQty, ItemJnlLine);

        OnPostOutputOnBeforeInsertCostValueEntries(ItemJnlLine, CapLedgEntry, ValuedQty, DirCostAmt, IndirCostAmt, sender);
#if not CLEAN27
        sender.RunOnPostOutputOnBeforeInsertCostValueEntries(ItemJnlLine, CapLedgEntry, ValuedQty, DirCostAmt, IndirCostAmt);
#endif
        sender.InsertCapValueEntry(ItemJnlLine, CapLedgEntry, ItemJnlLine."Value Entry Type"::"Direct Cost", ValuedQty, ValuedQty, DirCostAmt);
        sender.InsertCapValueEntry(ItemJnlLine, CapLedgEntry, ItemJnlLine."Value Entry Type"::"Indirect Cost", ValuedQty, 0, IndirCostAmt);

        OnPostOutputOnAfterInsertCostValueEntries(ItemJnlLine, CapLedgEntry, sender.GetCalledFromAdjustment(), sender.GetPostToGL(), sender);
#if not CLEAN27
        sender.RunOnPostOutputOnAfterInsertCostValueEntries(ItemJnlLine, CapLedgEntry, sender.GetCalledFromAdjustment(), sender.GetPostToGL());
#endif

        if LastOperation and (ItemJnlLine."Output Quantity" <> 0) then begin
            sender.CheckItemTracking(ItemJnlLine);
            if (ItemJnlLine."Output Quantity" < 0) and not ItemJnlLine.Adjustment then begin
                if ItemJnlLine."Applies-to Entry" = 0 then
                    ItemJnlLine."Applies-to Entry" := FindOpenOutputEntryNoToApply(ItemJnlLine);
                ItemJnlLine.TestField("Applies-to Entry");
                ItemLedgerEntry.Get(ItemJnlLine."Applies-to Entry");
                ItemJnlLine.CheckTrackingEqualItemLedgEntry(ItemLedgerEntry);
            end;

            IsHandled := false;
            OnPostOutputOnBeforeGetMfgAmounts(ItemJnlLine, ProdOrder, IsHandled);
#if not CLEAN27
            sender.RunOnPostOutputOnBeforeGetMfgAmounts(ItemJnlLine, ProdOrder, IsHandled);
#endif
            if not IsHandled then begin
                MfgItem.Get(ProdOrderLine."Item No.");
                MfgItem.TestField("Gen. Prod. Posting Group");
                if ItemJnlLine.Subcontracting then
                    MfgUnitCost := ProdOrderLine."Unit Cost" / ProdOrderLine."Qty. per Unit of Measure"
                else
                    if MfgSKU.Get(ProdOrderLine."Location Code", ProdOrderLine."Item No.", ProdOrderLine."Variant Code") then
                        MfgUnitCost := MfgSKU."Unit Cost"
                    else
                        MfgUnitCost := MfgItem."Unit Cost";
                OnPostOutputOnAfterSetMfgUnitCost(ItemJnlLine, MfgUnitCost, ProdOrderLine);
#if not CLEAN27
                sender.RunOnPostOutputOnAfterSetMfgUnitCost(ItemJnlLine, MfgUnitCost, ProdOrderLine);
#endif

                ItemJnlLine.Amount := ItemJnlLine."Output Quantity" * MfgUnitCost;
                ItemJnlLine."Amount (ACY)" := ACYMgt.CalcACYAmt(ItemJnlLine.Amount, ItemJnlLine."Posting Date", false);
                OnPostOutputOnAfterUpdateAmounts(ItemJnlLine);
#if not CLEAN27
                sender.RUnOnPostOutputOnAfterUpdateAmounts(ItemJnlLine);
#endif

                ItemJnlLine."Gen. Bus. Posting Group" := ProdOrder."Gen. Bus. Posting Group";
                ItemJnlLine."Gen. Prod. Posting Group" := MfgItem."Gen. Prod. Posting Group";
                if ItemJnlLine."Output Quantity (Base)" * ProdOrderLine."Remaining Qty. (Base)" <= 0 then
                    ReTrack := true
                else
                    if not sender.GetCalledFromInvtPutawayPick() then
                        ProdOrderLineReserve.TransferPOLineToItemJnlLine(
                        ProdOrderLine, ItemJnlLine, ItemJnlLine."Output Quantity (Base)");
            end;

            PostWhseJnlLine := true;
            OnPostOutputOnBeforeCreateWhseJnlLine(ItemJnlLine, PostWhseJnlLine);
#if not CLEAN27
            sender.RunOnPostOutputOnBeforeCreateWhseJnlLine(ItemJnlLine, PostWhseJnlLine);
#endif
            if PostWhseJnlLine then begin
                GetLocation(ItemJnlLine."Location Code");
                if Location."Bin Mandatory" and (not sender.GetCalledFromInvtPutawayPick()) then
                    if not Item.Get(ItemJnlLine."Item No.") or Item.IsInventoriableType() then begin
                        ProdOrderWarehouseMgt.CreateWhseJnlLineFromOutputJournal(ItemJnlLine, WhseJnlLine);
                        WMSManagement.CheckWhseJnlLine(WhseJnlLine, 2, 0, false);
                    end;
            end;
            OnPostOutputOnAfterCreateWhseJnlLine(ItemJnlLine);
#if not CLEAN27
            sender.RunOnPostOutputOnAfterCreateWhseJnlLine(ItemJnlLine);
#endif

            if ItemJnlLine.Subcontracting and ItemJnlLine.Correction then
                ItemJnlLineSubContracting := ItemJnlLine;

            ItemJnlLine.Description := ProdOrderLine.Description;
            if ItemJnlLine.Subcontracting then begin
                ItemJnlLine."Document Type" := ItemJnlLine."Document Type"::" ";
                ItemJnlLine."Document No." := ItemJnlLine."Order No.";
                ItemJnlLine."Document Line No." := 0;
                ItemJnlLine."Invoiced Quantity" := 0;
            end;

            IsHandled := false;
            OnPostOutputOnBeforePostItem(ItemJnlLine, ProdOrderLine, IsHandled);
#if not CLEAN27
            sender.RunOnPostOutputOnBeforePostItem(ItemJnlLine, ProdOrderLine, IsHandled);
#endif
            if not IsHandled then
                sender.PostItem(ItemJnlLine);

            IsHandled := false;
            OnPostOutputOnBeforeUpdateProdOrderLine(ItemJnlLine, IsHandled);
#if not CLEAN27
            sender.RunOnPostOutputOnBeforeUpdateProdOrderLine(ItemJnlLine, IsHandled);
#endif
            if not IsHandled then begin
                UpdateProdOrderLine(ItemJnlLine, ProdOrderLine, ReTrack, sender.GetItemLedgerEntryNo());
                OnPostOutputOnAfterUpdateProdOrderLine(ItemJnlLine, WhseJnlLine, GlobalItemLedgerEntry);
#if not CLEAN27
                sender.RunOnPostOutputOnAfterUpdateProdOrderLine(ItemJnlLine, WhseJnlLine, GlobalItemLedgerEntry);
#endif
            end;

            if PostWhseJnlLine then
                if Location."Bin Mandatory" and (not sender.GetCalledFromInvtPutawayPick()) then
                    sender.RegisterWhseJnlLine(WhseJnlLine);

            if ItemJnlLine.Subcontracting and ItemJnlLine.Correction then begin
                ItemJnlLine."Document Type" := ItemJnlLineSubContracting."Document Type";
                ItemJnlLine."Document No." := ItemJnlLineSubContracting."Document No.";
                ItemJnlLine."Document Line No." := ItemJnlLineSubContracting."Document Line No.";
                ItemJnlLine.Description := ItemJnlLineSubContracting.Description;
            end;
        end;

        OnAfterPostOutput(GlobalItemLedgerEntry, ProdOrderLine, ItemJnlLine);
#if not CLEAN27
        sender.RunOnAfterPostOutput(GlobalItemLedgerEntry, ProdOrderLine, ItemJnlLine);
#endif
    end;

    local procedure GetItem(ItemNo: Code[20]; ForceGetItem: Boolean): Boolean
    var
        HasGotItem: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetItem(Item, ItemNo, ForceGetItem, HasGotItem, IsHandled);
        if IsHandled then
            exit(HasGotItem);

        Item.ReadIsolation(IsolationLevel::ReadUncommitted);
        if not ForceGetItem then
            exit(Item.Get(ItemNo));

        Item.Get(ItemNo);
        exit(true);
    end;

    local procedure PostOutputForProdOrder(
        var ItemJnlLine: Record "Item Journal Line"; var ProdOrder: Record "Production Order"; var ProdOrderLine: Record "Prod. Order Line";
        var CapLedgEntry: Record "Capacity Ledger Entry"; ValuedQty: Decimal; var LastOperation: Boolean;
        GlobalItemTrackingSetup: Record "Item Tracking Setup"; GlobalItemTrackingCode: Record "Item Tracking Code";
        var sender: Codeunit "Item Jnl.-Post Line")
    var
        MachCenter: Record "Machine Center";
        WorkCenter: Record "Work Center";
        ProdOrderRtngLine: Record "Prod. Order Routing Line";
        ShouldFlushOperation: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostOutputForProdOrder(ItemJnlLine, LastOperation, IsHandled);
#if not CLEAN27
        sender.RunOnBeforePostOutputForProdOrder(ItemJnlLine, LastOperation, IsHandled);
#endif
        if IsHandled then
            exit;

        ItemJnlLine.TestField("Order Type", ItemJnlLine."Order Type"::Production);
        GetOutputProdOrder(ItemJnlLine, ProdOrder);
        ProdOrder.TestField(Blocked, false);
        ProdOrderLine.LockTable();
        GetOutputProdOrderLine(ItemJnlLine, ProdOrderLine);

        ItemJnlLine."Inventory Posting Group" := ProdOrderLine."Inventory Posting Group";

        ProdOrderRtngLine.SetRange(Status, ProdOrderRtngLine.Status::Released);
        ProdOrderRtngLine.SetRange("Prod. Order No.", ItemJnlLine."Order No.");
        ProdOrderRtngLine.SetRange("Routing Reference No.", ItemJnlLine."Routing Reference No.");
        ProdOrderRtngLine.SetRange("Routing No.", ItemJnlLine."Routing No.");
        OnPostOutputOnAfterProdOrderRtngLineSetFilters(ProdOrderRtngLine);
#if not CLEAN27
        sender.RunOnPostOutputOnAfterProdOrderRtngLineSetFilters(ProdOrderRtngLine);
#endif
        if not ProdOrderRtngLine.IsEmpty() then begin
            ItemJnlLine.TestField("Operation No.");
            ItemJnlLine.TestField("No.");

            if ItemJnlLine.Type = "Capacity Type Journal"::"Machine Center" then begin
                MachCenter.Get(ItemJnlLine."No.");
                MachCenter.TestField(Blocked, false);
            end;
            WorkCenter.Get(ItemJnlLine."Work Center No.");
            WorkCenter.TestField(Blocked, false);

            ApplyCapNeed(ItemJnlLine, ItemJnlLine."Setup Time (Base)", ItemJnlLine."Run Time (Base)");
            OnPostOutputForProdOrderOnAfterApplyCapNeed(ItemJnlLine, ValuedQty);
#if not CLEAN27
            sender.RunOnPostOutputForProdOrderOnAfterApplyCapNeed(ItemJnlLine, ValuedQty);
#endif
        end;

        if ItemJnlLine."Operation No." <> '' then
            PostOutputUpdateProdOrderRtngLine(ItemJnlLine, ProdOrderLine, LastOperation)
        else
            LastOperation := true;

        if ItemJnlLine.Subcontracting then
            sender.InsertCapLedgEntry(ItemJnlLine, CapLedgEntry, ItemJnlLine.Quantity, ItemJnlLine."Invoiced Quantity")
        else
            sender.InsertCapLedgEntry(ItemJnlLine, CapLedgEntry, ValuedQty, ValuedQty);

        ShouldFlushOperation := ItemJnlLine."Output Quantity" >= 0;
        OnBeforeCallFlushOperation(ItemJnlLine, ShouldFlushOperation);
#if not CLEAN27
        sender.RunOnBeforeCallFlushOperation(ItemJnlLine, ShouldFlushOperation);
#endif
        if ShouldFlushOperation then
            FlushOperation(
                ItemJnlLine, ProdOrder, ProdOrderLine, GlobalItemTrackingSetup, GlobalItemTrackingCode, LastOperation, sender);
    end;

    local procedure GetOutputProdOrder(var ItemJnlLine: Record "Item Journal Line"; var ProdOrder: Record "Production Order")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetOutputProdOrder(ProdOrder, ItemJnlLine, IsHandled);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeGetOutputProdOrder(ProdOrder, ItemJnlLine, IsHandled);
#endif
        if IsHandled then
            exit;

        ProdOrder.Get(ProdOrder.Status::Released, ItemJnlLine."Order No.");
    end;

    local procedure GetOutputProdOrderLine(var ItemJnlLine: Record "Item Journal Line"; var ProdOrderLine: Record "Prod. Order Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetOutputProdOrderLine(ProdOrderLine, ItemJnlLine, IsHandled);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeGetOutputProdOrderLine(ProdOrderLine, ItemJnlLine, IsHandled);
#endif
        if IsHandled then
            exit;

        ProdOrderLine.Get(ProdOrderLine.Status::Released, ItemJnlLine."Order No.", ItemJnlLine."Order Line No.");
    end;

    local procedure GetProdOrderRoutingLine(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; OldItemJnlLine: Record "Item Journal Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetProdOrderRoutingLine(ProdOrderRoutingLine, OldItemJnlLine, IsHandled);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeGetProdOrderRoutingLine(ProdOrderRoutingLine, OldItemJnlLine, IsHandled);
#endif
        if IsHandled then
            exit;

        ProdOrderRoutingLine.Get(
          ProdOrderRoutingLine.Status::Released, OldItemJnlLine."Order No.",
          OldItemJnlLine."Routing Reference No.", OldItemJnlLine."Routing No.", OldItemJnlLine."Operation No.");
    end;

    local procedure PostOutputUpdateProdOrderRtngLine(var ItemJnlLine: Record "Item Journal Line"; ProdOrderLine: Record "Prod. Order Line"; var LastOperation: Boolean)
    var
        ProdOrderRtngLine: Record "Prod. Order Routing Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostOutputUpdateProdOrderRtngLine(ProdOrderRtngLine, ItemJnlLine, IsHandled);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforePostOutputUpdateProdOrderRtngLine(ProdOrderRtngLine, ItemJnlLine, IsHandled);
#endif
        if IsHandled then
            exit;

        GetProdOrderRoutingLine(ProdOrderRtngLine, ItemJnlLine);
        if ItemJnlLine.Finished then
            ProdOrderRtngLine."Routing Status" := ProdOrderRtngLine."Routing Status"::Finished
        else
            ProdOrderRtngLine."Routing Status" := ProdOrderRtngLine."Routing Status"::"In Progress";
        LastOperation := (not NextOperationExist(ProdOrderRtngLine));
        OnPostOutputOnBeforeProdOrderRtngLineModify(ProdOrderRtngLine, ProdOrderLine, ItemJnlLine, LastOperation);
#if not CLEAN27
        ItemJnlPostLine.RunOnPostOutputOnBeforeProdOrderRtngLineModify(ProdOrderRtngLine, ProdOrderLine, ItemJnlLine, LastOperation);
#endif 
        ProdOrderRtngLine.Modify();
    end;

    local procedure NextOperationExist(var ProdOrderRtngLine: Record "Prod. Order Routing Line"): Boolean
    begin
        OnBeforeNextOperationExist(ProdOrderRtngLine);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeNextOperationExist(ProdOrderRtngLine);
#endif
        exit(ProdOrderRtngLine."Next Operation No." <> '');
    end;

    local procedure CalcCapQty(var ItemJnlLine: Record "Item Journal Line") CapQty: Decimal
    begin
        ManufacturingSetup.Get();

        if ItemJnlLine."Unit Cost Calculation" = ItemJnlLine."Unit Cost Calculation"::Time then begin
            if ManufacturingSetup."Cost Incl. Setup" then
                CapQty := ItemJnlLine."Setup Time" + ItemJnlLine."Run Time"
            else
                CapQty := ItemJnlLine."Run Time";
        end else
            CapQty := ItemJnlLine.Quantity + ItemJnlLine."Scrap Quantity";

        OnAfterCalcCapQty(ItemJnlLine, CapQty);
#if not CLEAN27
        ItemJnlPostLine.RunOnAfterCalcCapQty(ItemJnlLine, CapQty);
#endif
    end;

    local procedure ApplyCapNeed(var ItemJnlLine: Record "Item Journal Line"; PostedSetupTime: Decimal; PostedRunTime: Decimal)
    var
        ProdOrderCapNeed: Record "Prod. Order Capacity Need";
        TypeHelper: Codeunit "Type Helper";
        TimeToAllocate: Decimal;
        PrevSetupTime: Decimal;
        PrevRunTime: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeOnApplyCapNeed(ItemJnlLine, PostedSetupTime, PostedRunTime, IsHandled);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeOnApplyCapNeed(ItemJnlLine, PostedSetupTime, PostedRunTime, IsHandled);
#endif
        if IsHandled then
            exit;

        ProdOrderCapNeed.LockTable();
        ProdOrderCapNeed.Reset();
        ProdOrderCapNeed.SetCurrentKey(
          Status, "Prod. Order No.", "Routing Reference No.", "Operation No.", Date, "Starting Time");
        ProdOrderCapNeed.SetRange(Status, ProdOrderCapNeed.Status::Released);
        ProdOrderCapNeed.SetRange("Prod. Order No.", ItemJnlLine."Order No.");
        ProdOrderCapNeed.SetRange("Requested Only", false);
        ProdOrderCapNeed.SetRange("Routing No.", ItemJnlLine."Routing No.");
        ProdOrderCapNeed.SetRange("Routing Reference No.", ItemJnlLine."Routing Reference No.");
        ProdOrderCapNeed.SetRange("Operation No.", ItemJnlLine."Operation No.");

        if ItemJnlLine.Finished then
            ProdOrderCapNeed.ModifyAll("Allocated Time", 0)
        else begin
            OnApplyCapNeedOnAfterSetFilters(ProdOrderCapNeed, ItemJnlLine);
#if not CLEAN27
            ItemJnlPostLine.RunOnApplyCapNeedOnAfterSetFilters(ProdOrderCapNeed, ItemJnlLine);
#endif
            CalcCapLedgerEntriesSetupRunTime(ItemJnlLine, PrevSetupTime, PrevRunTime);

            if PostedSetupTime <> 0 then begin
                ProdOrderCapNeed.SetRange("Time Type", ProdOrderCapNeed."Time Type"::"Setup Time");
                PostedSetupTime += PrevSetupTime;
                if ProdOrderCapNeed.FindSet() then
                    repeat
                        TimeToAllocate := TypeHelper.Minimum(ProdOrderCapNeed."Needed Time", PostedSetupTime);
                        ProdOrderCapNeed."Allocated Time" := ProdOrderCapNeed."Needed Time" - TimeToAllocate;
                        ProdOrderCapNeed.Modify();
                        PostedSetupTime -= TimeToAllocate;
                    until ProdOrderCapNeed.Next() = 0;
            end;

            if PostedRunTime <> 0 then begin
                ProdOrderCapNeed.SetRange("Time Type", ProdOrderCapNeed."Time Type"::"Run Time");
                PostedRunTime += PrevRunTime;
                if ProdOrderCapNeed.FindSet() then
                    repeat
                        TimeToAllocate := TypeHelper.Minimum(ProdOrderCapNeed."Needed Time", PostedRunTime);
                        ProdOrderCapNeed."Allocated Time" := ProdOrderCapNeed."Needed Time" - TimeToAllocate;
                        ProdOrderCapNeed.Modify();
                        PostedRunTime -= TimeToAllocate;
                    until ProdOrderCapNeed.Next() = 0;
            end;
        end;
    end;

    local procedure CalcCapLedgerEntriesSetupRunTime(var ItemJnlLine: Record "Item Journal Line"; var TotalSetupTime: Decimal; var TotalRunTime: Decimal)
    var
        CapLedgerEntry: Record "Capacity Ledger Entry";
    begin
        CapLedgerEntry.SetCurrentKey(
          "Order Type", "Order No.", "Order Line No.", "Routing No.", "Routing Reference No.", "Operation No.", "Last Output Line");
        CapLedgerEntry.SetRange("Order Type", CapLedgerEntry."Order Type"::Production);
        CapLedgerEntry.SetRange("Order No.", ItemJnlLine."Order No.");
        CapLedgerEntry.SetRange("Order Line No.", ItemJnlLine."Order Line No.");
        CapLedgerEntry.SetRange("Routing No.", ItemJnlLine."Routing No.");
        CapLedgerEntry.SetRange("Routing Reference No.", ItemJnlLine."Routing Reference No.");
        CapLedgerEntry.SetRange("Operation No.", ItemJnlLine."Operation No.");
        OnCalcCapLedgerEntriesSetupRunTimeOnAfterCapLedgerEntrySetFilters(CapLedgerEntry, ItemJnlLine);
#if not CLEAN27
        ItemJnlPostLine.RunOnCalcCapLedgerEntriesSetupRunTimeOnAfterCapLedgerEntrySetFilters(CapLedgerEntry, ItemJnlLine);
#endif

        CapLedgerEntry.CalcSums("Setup Time", "Run Time");
        TotalSetupTime := CapLedgerEntry."Setup Time";
        TotalRunTime := CapLedgerEntry."Run Time";
    end;

    local procedure UpdateProdOrderLine(var ItemJnlLine: Record "Item Journal Line"; var ProdOrderLine: Record "Prod. Order Line"; ReTrack: Boolean; ItemLedgEntryNo: Integer)
    var
        ReservMgt: Codeunit "Reservation Management";
    begin
        OnBeforeUpdateProdOrderLine(ProdOrderLine, ItemJnlLine, ReTrack);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeUpdateProdOrderLine(ProdOrderLine, ItemJnlLine, ReTrack);
#endif

        if ItemJnlLine."Output Quantity (Base)" > ProdOrderLine."Remaining Qty. (Base)" then
            ProdOrderLineReserve.AssignForPlanning(ProdOrderLine);
        ProdOrderLine."Finished Qty. (Base)" := ProdOrderLine."Finished Qty. (Base)" + ItemJnlLine."Output Quantity (Base)";
        ProdOrderLine."Finished Quantity" := ProdOrderLine."Finished Qty. (Base)" / ProdOrderLine."Qty. per Unit of Measure";
        if ProdOrderLine."Finished Qty. (Base)" < 0 then
            ProdOrderLine.FieldError("Finished Quantity", CannotBeLessThanZeroErr);
        ProdOrderLine."Remaining Qty. (Base)" := ProdOrderLine."Quantity (Base)" - ProdOrderLine."Finished Qty. (Base)";
        if ProdOrderLine."Remaining Qty. (Base)" < 0 then
            ProdOrderLine."Remaining Qty. (Base)" := 0;
        ProdOrderLine."Remaining Quantity" := ProdOrderLine."Remaining Qty. (Base)" / ProdOrderLine."Qty. per Unit of Measure";
        OnBeforeProdOrderLineModify(ProdOrderLine, ItemJnlLine, ItemLedgEntryNo);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeProdOrderLineModify(ProdOrderLine, ItemJnlLine, ItemLedgEntryNo);
#endif
        ProdOrderLine.Modify();

        if ReTrack then begin
            ReservMgt.SetReservSource(ProdOrderLine);
            ReservMgt.ClearSurplus();
            ReservMgt.AutoTrack(ProdOrderLine."Remaining Qty. (Base)");
        end;

        OnAfterUpdateProdOrderLine(ProdOrderLine, ReTrack, ItemJnlLine);
#if not CLEAN27
        ItemJnlPostLine.RunOnAfterUpdateProdOrderLine(ProdOrderLine, ReTrack, ItemJnlLine);
#endif
    end;

    local procedure FlushOperation(
        var ItemJnlLine: Record "Item Journal Line"; ProdOrder: Record "Production Order"; ProdOrderLine: Record "Prod. Order Line";
        var GlobalItemTrackingSetup: Record "Item Tracking Setup"; var GlobalItemTrackingCode: Record "Item Tracking Code";
        LastOperation: Boolean; var sender: Codeunit "Item Jnl.-Post Line")
    var
        ProdOrderRoutingLine: Record "Prod. Order Routing Line";
        ProdOrderComp: Record "Prod. Order Component";
        ItemJnlLineSaved: Record "Item Journal Line";
        TempSplitItemJnlLineSaved: Record "Item Journal Line" temporary;
        ItemTrackingCodeSaved: Record "Item Tracking Code";
        ItemTrackingSetupSaved: Record "Item Tracking Setup";
        xCalledFromInvtPutawayPick: Boolean;
    begin
        OnBeforeFlushOperation(ProdOrder, ProdOrderLine, ItemJnlLine, LastOperation);
#if not CLEAN27
        sender.RunOnBeforeFlushOperation(ProdOrder, ProdOrderLine, ItemJnlLine, LastOperation);
#endif

        if ItemJnlLine."Operation No." = '' then
            exit;

        ItemJnlLineSaved := ItemJnlLine;
        TempSplitItemJnlLineSaved.Reset();
        TempSplitItemJnlLineSaved.DeleteAll();
        sender.SaveTempSplitItemJnlLine(TempSplitItemJnlLineSaved);
        ItemTrackingSetupSaved := GlobalItemTrackingSetup;
        ItemTrackingCodeSaved := GlobalItemTrackingCode;
        xCalledFromInvtPutawayPick := sender.GetCalledFromInvtPutawayPick();
        sender.SetCalledFromInvtPutawayPick(false);

        GetProdOrderRoutingLine(ProdOrderRoutingLine, ItemJnlLineSaved);
        OnFlushOperationOnBeforeCheckRoutingLinkCode(ProdOrder, ProdOrderLine, ProdOrderRoutingLine, ItemJnlLine, LastOperation);
#if not CLEAN27
        sender.RunOnFlushOperationOnBeforeCheckRoutingLinkCode(ProdOrder, ProdOrderLine, ProdOrderRoutingLine, ItemJnlLine, LastOperation);
#endif
        if ProdOrderRoutingLine."Routing Link Code" <> '' then begin
            ProdOrderComp.SetCurrentKey(Status, "Prod. Order No.", "Routing Link Code", "Flushing Method");
            ProdOrderComp.SetRange("Flushing Method", ProdOrderComp."Flushing Method"::Forward, ProdOrderComp."Flushing Method"::"Pick + Backward");
            ProdOrderComp.SetRange("Routing Link Code", ProdOrderRoutingLine."Routing Link Code");
            ProdOrderComp.SetRange(Status, ProdOrderComp.Status::Released);
            ProdOrderComp.SetRange("Prod. Order No.", ItemJnlLineSaved."Order No.");
            ProdOrderComp.SetRange("Prod. Order Line No.", ItemJnlLineSaved."Order Line No.");
            OnFlushOperationOnAfterProdOrderCompSetFilters(ProdOrderComp, ItemJnlLineSaved, ProdOrderRoutingLine);
#if not CLEAN27
            sender.RunOnFlushOperationOnAfterProdOrderCompSetFilters(ProdOrderComp, ItemJnlLineSaved, ProdOrderRoutingLine);
#endif
            if ProdOrderComp.FindSet() then begin
                sender.SetSkipRetrieveItemTracking(true);
                repeat
                    PostFlushedConsumption(
                        ItemJnlLine, ProdOrder, ProdOrderLine, ProdOrderComp, ProdOrderRoutingLine, ItemJnlLineSaved, sender);
                until ProdOrderComp.Next() = 0;
                sender.SetSkipRetrieveItemTracking(false);
            end;
        end;

        ItemJnlLine := ItemJnlLineSaved;
        sender.RestoreTempSplitItemJnlLine(TempSplitItemJnlLineSaved);
        sender.SetGlobalItemTrackingCode(ItemTrackingCodeSaved);
        sender.SetGlobalItemTrackingSetup(ItemTrackingSetupSaved);
        sender.SetCalledFromInvtPutawayPick(xCalledFromInvtPutawayPick);

        OnAfterFlushOperation(ProdOrder, ProdOrderLine, ItemJnlLine);
#if not CLEAN27
        sender.RunOnAfterFlushOperation(ProdOrder, ProdOrderLine, ItemJnlLine);
#endif
    end;

    procedure PostFlushedConsumption(var ItemJnlLine: Record "Item Journal Line"; ProdOrder: Record "Production Order"; ProdOrderLine: Record "Prod. Order Line"; ProdOrderComp: Record "Prod. Order Component"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; OldItemJnlLine: Record "Item Journal Line"; var sender: Codeunit "Item Jnl.-Post Line")
    var
        CompItem: Record Item;
        TempTrackingSpecificationSaved: Record "Tracking Specification" temporary;
        SourceCodeSetup: Record "Source Code Setup";
        MfgCostCalcMgt: Codeunit "Mfg. Cost Calculation Mgt.";
        OutputQtyBase: Decimal;
        QtyToPost: Decimal;
        CalcBasedOn: Option "Actual Output","Expected Output";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePostFlushedConsump(ProdOrder, ProdOrderLine, ProdOrderComp, ProdOrderRoutingLine, OldItemJnlLine, IsHandled);
#if not CLEAN27
        sender.RunOnBeforePostFlushedConsump(ProdOrder, ProdOrderLine, ProdOrderComp, ProdOrderRoutingLine, OldItemJnlLine, IsHandled);
#endif
        if IsHandled then
            exit;

        OutputQtyBase := OldItemJnlLine."Output Quantity (Base)" + OldItemJnlLine."Scrap Quantity (Base)";

        CompItem.Get(ProdOrderComp."Item No.");
        CompItem.TestField("Rounding Precision");

        OnPostFlushedConsumptionOnBeforeCalcQtyToPost(ProdOrder, ProdOrderLine, ProdOrderComp, ProdOrderRoutingLine, OldItemJnlLine, OutputQtyBase);
#if not CLEAN27
        sender.RunOnPostFlushedConsumptionOnBeforeCalcQtyToPost(ProdOrder, ProdOrderLine, ProdOrderComp, ProdOrderRoutingLine, OldItemJnlLine, OutputQtyBase);
#endif
        if ProdOrderComp."Flushing Method" in
           [ProdOrderComp."Flushing Method"::Backward, ProdOrderComp."Flushing Method"::"Pick + Backward"]
        then begin
            QtyToPost := ProdOrderRoutingLine."Fixed Scrap Qty. (Accum.)" + MfgCostCalcMgt.CalcActNeededQtyBase(ProdOrderLine, ProdOrderComp,
              OutputQtyBase - ProdOrderRoutingLine."Fixed Scrap Qty. (Accum.)") / ProdOrderComp."Qty. per Unit of Measure";
            if (ProdOrderLine."Remaining Qty. (Base)" = OutputQtyBase) and
               (ProdOrderComp."Remaining Quantity" <> 0) and
               (Abs(Round(QtyToPost, CompItem."Rounding Precision") - ProdOrderComp."Remaining Quantity") <= CompItem."Rounding Precision") and
               (Abs(Round(QtyToPost, CompItem."Rounding Precision") - ProdOrderComp."Remaining Quantity") < 1)
            then
                QtyToPost := ProdOrderComp."Remaining Quantity";
        end else
            QtyToPost := ProdOrderComp.GetNeededQty(CalcBasedOn::"Expected Output", true);
        QtyToPost := UOMMgt.RoundToItemRndPrecision(QtyToPost, CompItem."Rounding Precision");
        OnPostFlushedConsumpOnAfterCalcQtyToPost(ProdOrder, ProdOrderLine, ProdOrderComp, OutputQtyBase, QtyToPost, OldItemJnlLine, ProdOrderRoutingLine, CompItem);
#if not CLEAN27
        sender.RunOnPostFlushedConsumpOnAfterCalcQtyToPost(ProdOrder, ProdOrderLine, ProdOrderComp, OutputQtyBase, QtyToPost, OldItemJnlLine, ProdOrderRoutingLine, CompItem);
#endif
        if QtyToPost = 0 then
            exit;

        ManufacturingSetup.Get();
        SourceCodeSetup.Get();

        ItemJnlLine.Init();
        ItemJnlLine."Line No." := 0;
        ItemJnlLine."Entry Type" := ItemJnlLine."Entry Type"::Consumption;
        ItemJnlLine.Validate("Posting Date", OldItemJnlLine."Posting Date");
        if ManufacturingSetup."Doc. No. Is Prod. Order No." then
            ItemJnlLine."Document No." := ProdOrderLine."Prod. Order No."
        else
            ItemJnlLine."Document No." := OldItemJnlLine."Document No.";
        ItemJnlLine."Source No." := ProdOrderLine."Item No.";
        ItemJnlLine."Order Type" := ItemJnlLine."Order Type"::Production;
        ItemJnlLine."Order No." := ProdOrderLine."Prod. Order No.";
        ItemJnlLine.Validate("Order Line No.", ProdOrderLine."Line No.");
        ItemJnlLine.Validate("Item No.", ProdOrderComp."Item No.");
        ItemJnlLine.Validate("Prod. Order Comp. Line No.", ProdOrderComp."Line No.");
        ItemJnlLine.Validate("Unit of Measure Code", ProdOrderComp."Unit of Measure Code");
        ItemJnlLine.Description := ProdOrderComp.Description;
        ItemJnlLine.Validate(Quantity, QtyToPost);
        ItemJnlLine.Validate("Unit Cost", ProdOrderComp."Unit Cost");
        ItemJnlLine."Location Code" := ProdOrderComp."Location Code";
        ItemJnlLine."Bin Code" := ProdOrderComp."Bin Code";
        ItemJnlLine."Variant Code" := ProdOrderComp."Variant Code";
        ItemJnlLine."Source Code" := SourceCodeSetup.Flushing;
        ItemJnlLine."Gen. Bus. Posting Group" := ProdOrder."Gen. Bus. Posting Group";
        ItemJnlLine."Gen. Prod. Posting Group" := CompItem."Gen. Prod. Posting Group";
        OnPostFlushedConsumpOnAfterCopyProdOrderFieldsToItemJnlLine(ItemJnlLine, OldItemJnlLine, ProdOrderLine, ProdOrderComp, CompItem);
#if not CLEAN27
        sender.RunOnPostFlushedConsumpOnAfterCopyProdOrderFieldsToItemJnlLine(ItemJnlLine, OldItemJnlLine, ProdOrderLine, ProdOrderComp, CompItem);
#endif

        TempTrackingSpecificationSaved.Reset();
        TempTrackingSpecificationSaved.DeleteAll();
        sender.SaveTempTrackingSpecification(TempTrackingSpecificationSaved);

        OnPostFlushedConsumpOnBeforeProdOrderCompReserveTransferPOCompToItemJnlLine(ItemJnlLine, ProdOrderComp);
#if not CLEAN27
        sender.RunOnPostFlushedConsumpOnBeforeProdOrderCompReserveTransferPOCompToItemJnlLine(ItemJnlLine, ProdOrderComp);
#endif
        ProdOrderCompReserve.TransferPOCompToItemJnlLine(
          ProdOrderComp, ItemJnlLine, Round(QtyToPost * ProdOrderComp."Qty. per Unit of Measure", UOMMgt.QtyRndPrecision()));

        OnBeforePostFlushedConsumpItemJnlLine(ItemJnlLine);
#if not CLEAN27
        sender.RunOnBeforePostFlushedConsumpItemJnlLine(ItemJnlLine);
#endif
        sender.PostFlushedConsumptionItemJnlLine(
            ItemJnlLine, GetCombinedDimSetID(ProdOrderLine."Dimension Set ID", ProdOrderComp."Dimension Set ID"));

        sender.RestoreTempTrackingSpecification(TempTrackingSpecificationSaved);

        OnAfterPostFlushedConsump(ProdOrderComp, ProdOrderRoutingLine, OldItemJnlLine);
#if not CLEAN27
        sender.RunOnAfterPostFlushedConsump(ProdOrderComp, ProdOrderRoutingLine, OldItemJnlLine);
#endif
    end;

    local procedure GetCombinedDimSetID(DimSetID1: Integer; DimSetID2: Integer): Integer
    var
        DimMgt: Codeunit DimensionManagement;
        DummyGlobalDimCode: array[2] of Code[20];
        DimID: array[10] of Integer;
    begin
        DimID[1] := DimSetID1;
        DimID[2] := DimSetID2;
        exit(DimMgt.GetCombinedDimensionSetID(DimID, DummyGlobalDimCode[1], DummyGlobalDimCode[2]));
    end;

    local procedure FindOpenOutputEntryNoToApply(ItemJournalLine: Record "Item Journal Line"): Integer
    var
        ItemLedgerEntry: Record "Item Ledger Entry";
    begin
        if not ItemJournalLine.TrackingExists() then
            exit(0);

        ItemLedgerEntry.SetCurrentKey("Order Type", "Order No.", "Order Line No.", "Entry Type", "Prod. Order Comp. Line No.");
        ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::Production);
        ItemLedgerEntry.SetRange("Order No.", ItemJournalLine."Order No.");
        ItemLedgerEntry.SetRange("Order Line No.", ItemJournalLine."Order Line No.");
        ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::Output);
        ItemLedgerEntry.SetRange("Prod. Order Comp. Line No.", 0);
        ItemLedgerEntry.SetRange("Item No.", ItemJournalLine."Item No.");
        ItemLedgerEntry.SetRange("Location Code", ItemJournalLine."Location Code");
        ItemLedgerEntry.SetTrackingFilterFromItemJournalLine(ItemJournalLine);
        ItemLedgerEntry.SetRange(Positive, true);
        ItemLedgerEntry.SetRange(Open, true);
        ItemLedgerEntry.SetFilter("Remaining Quantity", '>=%1', -ItemJournalLine."Output Quantity (Base)");
        if not ItemLedgerEntry.IsEmpty() then
            if ItemLedgerEntry.Count = 1 then begin
                ItemLedgerEntry.FindFirst();
                exit(ItemLedgerEntry."Entry No.");
            end;

        exit(0);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnSetOrderAdjmtPropertiesForProduction', '', true, false)]
    local procedure OnSetOrderAdjmtPropertiesForProduction(var InventoryAdjmtEntryOrder: Record "Inventory Adjmt. Entry (Order)"; OrderNo: Code[20]; OrderLineNo: Integer)
    var
        ProdOrderLine: Record "Prod. Order Line";
    begin
        GetProdOrderLine(ProdOrderLine, OrderNo, OrderLineNo);
        InventoryAdjmtEntryOrder.SetProdOrderLine(ProdOrderLine);
    end;

    local procedure GetProdOrderLine(var ProdOrderLine: Record "Prod. Order Line"; OrderNo: Code[20]; OrderLineNo: Integer)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetProdOrderLine(ProdOrderLine, OrderNo, OrderLineNo, IsHandled);
#if not CLEAN27
        ItemJnlPostLine.RunOnBeforeGetProdOrderLine(ProdOrderLine, OrderNo, OrderLineNo, IsHandled);
#endif
        if IsHandled then
            exit;

        ProdOrderLine.Get(ProdOrderLine.Status::Released, OrderNo, OrderLineNo);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnCorrectOutputValuationDateOnCheckProduction', '', true, false)]
    local procedure OnCorrectOutputValuationDateOnCheckProduction(ItemLedgerEntry: Record "Item Ledger Entry"; var ShouldExit: Boolean; var TempValueEntry: Record "Value Entry" temporary; var ValuationDate: Date; var sender: Codeunit "Item Jnl.-Post Line")
    var
        ValueEntry: Record "Value Entry";
        ProductionOrder: Record "Production Order";
        IsHandled: Boolean;
    begin
        if not (ItemLedgerEntry."Entry Type" in [ItemLedgerEntry."Entry Type"::Consumption, ItemLedgerEntry."Entry Type"::Output]) then
            exit;

        IsHandled := false;
        OnCorrectOutputValuationDateOnBeforeCheckProdOrder(ItemLedgerEntry, IsHandled);
#if not CLEAN27
        sender.RunOnCorrectOutputValuationDateOnBeforeCheckProdOrder(ItemLedgerEntry, IsHandled);
#endif
        if not IsHandled then
            if not ProductionOrder.Get(ProductionOrder.Status::Released, ItemLedgerEntry."Order No.") then
                exit;

        ValuationDate := MaxConsumptionValuationDate(ItemLedgerEntry);

        ValueEntry.SetCurrentKey("Order Type", "Order No.");
        ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Production);
        ValueEntry.SetFilter("Valuation Date", '<%1', ValuationDate);
        ValueEntry.SetRange("Order No.", ItemLedgerEntry."Order No.");
        ValueEntry.SetRange("Order Line No.", ItemLedgerEntry."Order Line No.");
        ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::Output);
        OnCorrectOutputValuationDateOnBeforeValueEntryFindSet(ValueEntry);
#if not CLEAN27
        sender.RunOnCorrectOutputValuationDateOnBeforeValueEntryFindSet(ValueEntry);
#endif
        if ValueEntry.FindSet() then
            repeat
                TempValueEntry := ValueEntry;
                TempValueEntry.Insert();
            until ValueEntry.Next() = 0;
    end;

    local procedure MaxConsumptionValuationDate(ItemLedgerEntry: Record "Item Ledger Entry"): Date
    var
        ValueEntry: Record "Value Entry";
    begin
        ValueEntry.ReadIsolation(IsolationLevel::ReadCommitted);
        ValueEntry.SetCurrentKey("Item Ledger Entry Type", "Order No.", "Valuation Date");
        ValueEntry.SetLoadFields("Valuation Date");
        ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Production);
        ValueEntry.SetRange("Order No.", ItemLedgerEntry."Order No.");
        ValueEntry.SetRange("Order Line No.", ItemLedgerEntry."Order Line No.");
        ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::Consumption);
        ValueEntry.SetFilter("Entry Type", '<>%1', ValueEntry."Entry Type"::Revaluation);
        if ValueEntry.FindLast() then
            exit(ValueEntry."Valuation Date");
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCorrectOutputValuationDateOnBeforeCheckProdOrder(ItemLedgerEntry: Record "Item Ledger Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCorrectOutputValuationDateOnBeforeValueEntryFindSet(var ValueEntry: Record "Value Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnBeforeProdOrderRtngLineModify(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ProdOrderLine: Record "Prod. Order Line"; var ItemJournalLine: Record "Item Journal Line"; var LastOperation: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostFlushedConsump(ProdOrder: Record "Production Order"; ProdOrderLine: Record "Prod. Order Line"; ProdOrderComp: Record "Prod. Order Component"; ProdOrderRoutingLine: Record "Prod. Order Routing Line"; OldItemJnlLine: Record "Item Journal Line"; var IsHandled: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetProdOrderLine(var ProdOrderLine: Record "Prod. Order Line"; OrderNo: Code[20]; OrderLineNo: Integer; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnAfterInsertCapLedgEntry(ItemJournalLine: Record "Item Journal Line"; var SkipPost: Boolean)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnPostOutputOnBeforeInsertCostValueEntries(var ItemJournalLine: Record "Item Journal Line"; var CapacityLedgerEntry: Record "Capacity Ledger Entry"; var ValuedQty: Decimal; var DirCostAmt: Decimal; var IndirCostAmt: Decimal; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnAfterInsertCostValueEntries(ItemJournalLine: Record "Item Journal Line"; var CapLedgEntry: Record "Capacity Ledger Entry"; CalledFromAdjustment: Boolean; PostToGL: Boolean; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnBeforeGetMfgAmounts(var ItemJnlLine: Record "Item Journal Line"; ProdOrder: Record "Production Order"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnAfterSetMfgUnitCost(var ItemJournalLine: Record "Item Journal Line"; var MfgUnitCost: Decimal; var ProdOrderLine: Record "Prod. Order Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnAfterUpdateAmounts(var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnBeforeCreateWhseJnlLine(var ItemJournalLine: Record "Item Journal Line"; var PostWhseJnlLine: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnAfterCreateWhseJnlLine(var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnBeforePostItem(var ItemJournalLine: Record "Item Journal Line"; var ProdOrderLine: Record "Prod. Order Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnBeforeUpdateProdOrderLine(var ItemJournalLine: Record "Item Journal Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPostOutput(var ItemLedgerEntry: Record "Item Ledger Entry"; var ProdOrderLine: Record "Prod. Order Line"; var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostOutputForProdOrder(var ItemJnlLine: Record "Item Journal Line"; var LastOperation: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnAfterProdOrderRtngLineSetFilters(var ProdOrderRtngLine: Record "Prod. Order Routing Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCallFlushOperation(var ItemJnlLine: Record "Item Journal Line"; var ShouldFlushOperation: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetOutputProdOrder(var ProdOrder: Record "Production Order"; ItemJnlLine: Record "Item Journal Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetOutputProdOrderLine(var ProdOrderLine: Record "Prod. Order Line"; ItemJnlLine: Record "Item Journal Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetProdOrderRoutingLine(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; OldItemJnlLine: Record "Item Journal Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostOutputUpdateProdOrderRtngLine(var ProdOrderRtngLine: Record "Prod. Order Routing Line"; ItemJnlLine: Record "Item Journal Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeOnApplyCapNeed(var ItemJnlLine: Record "Item Journal Line"; var PostedSetupTime: Decimal; var PostedRunTime: Decimal; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCalcCapQty(var ItemJnlLine: Record "Item Journal Line"; var CapQty: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnApplyCapNeedOnAfterSetFilters(var ProdOrderCapNeed: Record "Prod. Order Capacity Need"; ItemJnlLine: Record "Item Journal Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputForProdOrderOnAfterApplyCapNeed(var ItemJnlLine: Record "Item Journal Line"; var ValuedQty: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeNextOperationExist(var ProdOrderRoutingLine: Record "Prod. Order Routing Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCalcCapLedgerEntriesSetupRunTimeOnAfterCapLedgerEntrySetFilters(var CapLedgerEntry: Record "Capacity Ledger Entry"; ItemJnlLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateProdOrderLine(var ProdOrderLine: Record "Prod. Order Line"; var ItemJournalLine: Record "Item Journal Line"; ReTrack: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeProdOrderLineModify(var ProdOrderLine: Record "Prod. Order Line"; ItemJournalLine: Record "Item Journal Line"; ItemLedgEntryNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateProdOrderLine(var ProdOrderLine: Record "Prod. Order Line"; ReTrack: Boolean; var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnFlushOperationOnBeforeCheckRoutingLinkCode(var ProductionOrder: Record "Production Order"; var ProdOrderLine: Record "Prod. Order Line"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ItemJournalLine: Record "Item Journal Line"; LastOperation: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostFlushedConsumpOnBeforeProdOrderCompReserveTransferPOCompToItemJnlLine(ItemJournalLine: Record "Item Journal Line"; ProdOrderComponent: Record "Prod. Order Component")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostFlushedConsumpItemJnlLine(var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPostFlushedConsump(var ProdOrderComp: Record "Prod. Order Component"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; OldItemJnlLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostOutputOnAfterUpdateProdOrderLine(var ItemJournalLine: Record "Item Journal Line"; var WhseJnlLine: Record "Warehouse Journal Line"; var GlobalItemLedgEntry: Record "Item Ledger Entry");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFlushOperationOnAfterProdOrderCompSetFilters(var ProdOrderComponent: Record "Prod. Order Component"; ItemJournalLineSaved: Record "Item Journal Line"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line")
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnBeforeFlushOperation(var ProdOrder: Record "Production Order"; var ProdOrderLine: Record "Prod. Order Line"; var ItemJnlLine: Record "Item Journal Line"; LastOperation: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterFlushOperation(var ProdOrder: Record "Production Order"; var ProdOrderLine: Record "Prod. Order Line"; var ItemJnlLine: Record "Item Journal Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostFlushedConsumptionOnBeforeCalcQtyToPost(ProdOrder: Record "Production Order"; ProdOrderLine: Record "Prod. Order Line"; ProdOrderComp: Record "Prod. Order Component"; ProdOrderRoutingLine: Record "Prod. Order Routing Line"; OldItemJnlLine: Record "Item Journal Line"; var OutputQtyBase: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostFlushedConsumpOnAfterCalcQtyToPost(ProductionOrder: Record "Production Order"; ProdOrderLine: Record "Prod. Order Line"; ProdOrderComponent: Record "Prod. Order Component"; ActOutputQtyBase: Decimal; var QtyToPost: Decimal; var OldItemJournalLine: Record "Item Journal Line"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var CompItem: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPostFlushedConsumpOnAfterCopyProdOrderFieldsToItemJnlLine(var ItemJournalLine: Record "Item Journal Line"; var OldItemJournalLine: Record "Item Journal Line"; ProdOrderLine: Record "Prod. Order Line"; ProdOrderComponent: Record "Prod. Order Component"; CompItem: record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostOutput(var ItemJnlLine: Record "Item Journal Line"; var SkipInventoryValueZeroCheck: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetItem(var Item: Record Item; ItemNo: Code[20]; ForceGetItem: Boolean; var HasGotItem: Boolean; var IsHandled: Boolean)
    begin
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnCodeOnAfterCalcQtyPerUnitOfMeasure', '', true, false)]
    local procedure OnCodeOnAfterCalcQtyPerUnitOfMeasure(var ItemJnlLine: Record "Item Journal Line")
    begin
        ItemJnlLine."Setup Time" := ItemJnlLine."Setup Time (Base)";
        ItemJnlLine."Run Time" := ItemJnlLine."Run Time (Base)";
        ItemJnlLine."Stop Time" := ItemJnlLine."Stop Time (Base)";
        ItemJnlLine."Output Quantity" := ItemJnlLine."Output Quantity (Base)";
        ItemJnlLine."Scrap Quantity" := ItemJnlLine."Scrap Quantity (Base)";
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnBeforeInsertCapLedgEntry', '', true, false)]
    local procedure OnBeforeInsertCapLedgEntry(var CapLedgEntry: Record "Capacity Ledger Entry"; ItemJournalLine: Record "Item Journal Line"; LastOperation: Boolean)
    begin
        CapLedgEntry."Setup Time" := ItemJournalLine."Setup Time";
        CapLedgEntry."Run Time" := ItemJournalLine."Run Time";
        CapLedgEntry."Stop Time" := ItemJournalLine."Stop Time";
        CapLedgEntry."Output Quantity" := ItemJournalLine."Output Quantity";
        CapLedgEntry."Scrap Quantity" := ItemJournalLine."Scrap Quantity";
        CapLedgEntry."Routing No." := ItemJournalLine."Routing No.";
        CapLedgEntry."Routing Reference No." := ItemJournalLine."Routing Reference No.";
        CapLedgEntry."Operation No." := ItemJournalLine."Operation No.";
        CapLedgEntry."Stop Code" := ItemJournalLine."Stop Code";
        CapLedgEntry."Scrap Code" := ItemJournalLine."Scrap Code";
        CapLedgEntry."Work Center No." := ItemJournalLine."Work Center No.";
        CapLedgEntry."Work Center Group Code" := ItemJournalLine."Work Center Group Code";
        CapLedgEntry."Starting Time" := ItemJournalLine."Starting Time";
        CapLedgEntry."Ending Time" := ItemJournalLine."Ending Time";
        CapLedgEntry."Concurrent Capacity" := ItemJournalLine."Concurrent Capacity";
        CapLedgEntry."Work Shift Code" := ItemJournalLine."Work Shift Code";
        CapLedgEntry."Last Output Line" := LastOperation;

        if ItemJournalLine."Rev. Capacity Ledger Entry No." <> 0 then
            UpdateReversedCapacityLedgerEntry(ItemJournalLine, CapLedgEntry);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnSetupTempSplitItemJnlLineOnAfterDeductNonDistr', '', true, false)]
    local procedure OnSetupTempSplitItemJnlLineOnAfterDeductNonDistr(var TempSplitItemJnlLine: Record "Item Journal Line")
    begin
        TempSplitItemJnlLine."Setup Time" := 0;
        TempSplitItemJnlLine."Run Time" := 0;
        TempSplitItemJnlLine."Stop Time" := 0;
        TempSplitItemJnlLine."Setup Time (Base)" := 0;
        TempSplitItemJnlLine."Run Time (Base)" := 0;
        TempSplitItemJnlLine."Stop Time (Base)" := 0;
        TempSplitItemJnlLine."Starting Time" := 0T;
        TempSplitItemJnlLine."Ending Time" := 0T;
        TempSplitItemJnlLine."Scrap Quantity" := 0;
        TempSplitItemJnlLine."Scrap Quantity (Base)" := 0;
        TempSplitItemJnlLine."Concurrent Capacity" := 0;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnSetupSplitJnlLineOnSetDisableItemTracking', '', true, false)]
    local procedure OnSetupSplitJnlLineOnSetDisableItemTracking(var ItemJournalLine: Record "Item Journal Line"; var DisableItemTracking: Boolean)
    begin
        DisableItemTracking := not ItemJournalLine.ItemPosting();
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnSetupSplitJnlLineOnCheckOperationNo', '', true, false)]
    local procedure OnSetupSplitJnlLineOnCheckOperationNo(var ItemJournalLine: Record "Item Journal Line")
    begin
        Error(MustNotDefineItemTrackingErr, ItemJournalLine.FieldCaption("Operation No."), ItemJournalLine."Operation No.");
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnAfterPrepareItem', '', true, false)]
    local procedure OnAfterPrepareItem(var ItemJnlLineToPost: Record "Item Journal Line")
    begin
        CheckItemAndItemVariantProductionBlocked(ItemJnlLineToPost);
    end;

    local procedure CheckItemAndItemVariantProductionBlocked(ItemJournalLine: Record "Item Journal Line")
    var
        OutputItem: Record Item;
    begin
        case ItemJournalLine."Entry Type" of
            ItemJournalLine."Entry Type"::Output:
                OutputItem.CheckItemAndVariantForProdBlocked(ItemJournalLine."Item No.", ItemJournalLine."Variant Code", OutputItem."Production Blocked"::Output);
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnAfterSetupTempSplitItemJnlLineSetQty', '', true, false)]
    local procedure OnAfterSetupTempSplitItemJnlLineSetQty(var TempSplitItemJnlLine: Record "Item Journal Line" temporary; ItemJournalLine: Record "Item Journal Line")
    begin
        if ItemJournalLine."Output Quantity" <> 0 then begin
            TempSplitItemJnlLine."Output Quantity (Base)" := TempSplitItemJnlLine."Quantity (Base)";
            TempSplitItemJnlLine."Output Quantity" := TempSplitItemJnlLine.Quantity;
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnAfterInitItemLedgEntry', '', true, false)]
    local procedure OnAfterInitItemLedgEntry(var NewItemLedgEntry: Record "Item Ledger Entry"; var ItemJournalLine: Record "Item Journal Line"; var ItemLedgEntryNo: Integer)
    begin
        NewItemLedgEntry."Prod. Order Comp. Line No." := ItemJournalLine."Prod. Order Comp. Line No.";
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnBeforeInsertCapValueEntry', '', true, false)]
    local procedure CopyLocationCodeToCapValueEntry(var ValueEntry: Record "Value Entry"; ItemJnlLine: Record "Item Journal Line")
    begin
        if (ValueEntry.Type = ValueEntry.Type::"Work Center") and (ValueEntry."Order Type" = ValueEntry."Order Type"::Production) then begin
            ManufacturingSetup.GetRecordOnce();
            if ManufacturingSetup."Copy Loc. to Cap. Val. Entries" then
                ValueEntry."Location Code" := ItemJnlLine."Location Code";
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnInsertCapValueEntryOnBeforeCapLedgEntryModify', '', true, false)]
    local procedure OnInsertCapValueEntryOnBeforeCapLedgEntryModify(var CapLedgEntry: Record "Capacity Ledger Entry"; ItemJournalLine: Record "Item Journal Line")
    begin
        if ItemJournalLine.Subcontracting then
            CapLedgEntry."Completely Invoiced" := CapLedgEntry."Invoiced Quantity" = CapLedgEntry."Output Quantity"
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Jnl.-Post Line", 'OnAfterGetUpdatedAppliedQtyForConsumption', '', true, false)]
    local procedure OnAfterGetUpdatedAppliedQtyForConsumption(OldItemLedgerEntry: Record "Item Ledger Entry"; ItemLedgerEntry: Record "Item Ledger Entry"; ReservationEntry2: Record "Reservation Entry"; SourceType: Integer; var AppliedQty: Decimal)
    begin
        if SourceType = Database::"Prod. Order Component" then begin
            if (ReservationEntry2."Source ID" <> ItemLedgerEntry."Order No.") then begin
                AppliedQty := 0;
                exit;
            end;

            if ReservationEntry2."Source Ref. No." <> ItemLedgerEntry."Prod. Order Comp. Line No." then begin
                AppliedQty := 0;
                exit;
            end;

            AppliedQty := -Abs(OldItemLedgerEntry."Reserved Quantity")
        end;
    end;

    local procedure UpdateReversedCapacityLedgerEntry(var ItemJnlLine: Record "Item Journal Line"; var CapLedgEntry: Record Microsoft.Manufacturing.Capacity."Capacity Ledger Entry")
    var
        ReversedCapacityLedgerEntry: Record Microsoft.Manufacturing.Capacity."Capacity Ledger Entry";
    begin
        ReversedCapacityLedgerEntry.Get(ItemJnlLine."Rev. Capacity Ledger Entry No.");
        CapLedgEntry.Reversed := true;
        CapLedgEntry."Reversed Entry No." := ReversedCapacityLedgerEntry."Entry No.";
        CapLedgEntry.Description := ReversedCapacityLedgerEntry.Description;

        ReversedCapacityLedgerEntry.Reversed := true;
        ReversedCapacityLedgerEntry."Reversed by Entry No." := CapLedgEntry."Entry No.";
        ReversedCapacityLedgerEntry.Modify();
    end;
}