Codeunit 99000854 Inventory Profile Offsetting

App
Base Application
Namespace
Microsoft.Inventory.Tracking
Versions
17-28

Procedures, 60Events, 279Obsolete, 28

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/Inventory/Tracking/InventoryProfileOffsetting.Codeunit.al6132 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.Tracking;

using Microsoft.Foundation.Calendar;
using Microsoft.Foundation.Shipping;
using Microsoft.Foundation.UOM;
using Microsoft.Inventory;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Ledger;
using Microsoft.Inventory.Location;
using Microsoft.Inventory.Planning;
using Microsoft.Inventory.Requisition;
using Microsoft.Inventory.Setup;
using Microsoft.Inventory.Transfer;
using Microsoft.Pricing.Calculation;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.Vendor;
using Microsoft.Sales.Document;
using Microsoft.Warehouse.Availability;
using Microsoft.Warehouse.Ledger;
using System.Reflection;

codeunit 99000854 "Inventory Profile Offsetting"
{
    Permissions = TableData "Reservation Entry" = id;

    trigger OnRun()
    begin
    end;

    var
        ReqLine: Record "Requisition Line";
        InventorySetup: Record "Inventory Setup";
        TempSKU: Record "Stockkeeping Unit" temporary;
        TempTransferSKU: Record "Stockkeeping Unit" temporary;
        ReservEntry: Record "Reservation Entry";
        TempTrkgReservEntry: Record "Reservation Entry" temporary;
        TempItemTrkgEntry: Record "Reservation Entry" temporary;
        ActionMsgEntry: Record "Action Message Entry";
        TempPlanningCompList: Record "Planning Component" temporary;
        DummyInventoryProfileTrackBuffer: Record "Inventory Profile Track Buffer";
        CustomizedCalendarChange: Record "Customized Calendar Change";
        CalendarManagement: Codeunit "Calendar Management";
        LeadTimeMgt: Codeunit "Lead-Time Management";
        PlanningLineManagement: Codeunit "Planning Line Management";
        PlanningTransparency: Codeunit "Planning Transparency";
        UOMMgt: Codeunit "Unit of Measure Management";
        BucketSize: DateFormula;
        ExcludeForecastBefore: Date;
        ScheduleDirection: Option Forward,Backward;
        PlanningLineStage: Option " ","Line Created","Routing Created",Exploded,Obsolete;
        SurplusType: Enum "Planning Surplus Type";
        CurrWorksheetType: Option Requisition,Planning;
        PriceCalculationMethod: Enum "Price Calculation Method";
        DampenerQty: Decimal;
        FutureSupplyWithinLeadtime: Decimal;
        LineNo: Integer;
        DampenersDays: Integer;
        BucketSizeInDays: Integer;
        CurrTemplateName: Code[10];
        CurrWorksheetName: Code[10];
        CurrForecast: Code[10];
        PlanMRP: Boolean;
        SpecificLotTracking: Boolean;
        SpecificSNTracking: Boolean;
#pragma warning disable AA0074
#pragma warning disable AA0470
        Text001: Label 'Assertion failed: %1.';
#pragma warning restore AA0470
#pragma warning restore AA0074
        UseParm: Boolean;
        PlanningResiliency: Boolean;
        PlanningSkippedForMissingSKUPolicy: Boolean;
#pragma warning disable AA0074
#pragma warning disable AA0470
        Text002: Label 'The %1 from ''%2'' to ''%3'' does not exist.';
        Text003: Label 'The %1 for %2 %3 %4 %5 does not exist.';
        Text004: Label '%1 must not be %2 in %3 %4 %5 %6 when %7 is %8.';
        Text005: Label '%1 must not be %2 in %3 %4 when %5 is %6.';
        Text006: Label '%1: The projected available inventory is %2 on the planning starting date %3.';
        Text007: Label '%1: The projected available inventory is below %2 %3 on %4.';
        Text008: Label '%1: The %2 %3 is before the work date %4.';
        Text009: Label '%1: The Status of %2 %3 is %4.';
        Text010: Label 'The projected inventory %1 is higher than the overflow level %2 on %3.';
#pragma warning restore AA0470
#pragma warning restore AA0074
        LocationMandatoryTxt: Label 'Location is mandatory.';
        MissingStockkeepingUnitTxt: Label 'Missing stockkeeping unit.';
        MinimalSupplyPlannedTxt: Label '%1: %2 The item is planned to cover the exact demand.', Comment = '%1: Attention, %2: Reason';
        PlanToDate: Date;
        OverflowLevel: Decimal;
        ExceedROPqty: Decimal;
        NextStateTxt: Label 'StartOver,MatchDates,MatchQty,CreateSupply,ReduceSupply,CloseDemand,CloseSupply,CloseLoop';
        NextState: Option StartOver,MatchDates,MatchQty,CreateSupply,ReduceSupply,CloseDemand,CloseSupply,CloseLoop;
        LotAccumulationPeriodStartDate: Date;
        PlanningParametersTakenFromItemCardTxt: Label 'Item %3 at Location %4 was planned using the planning parameters from the Item Card, because no stockkeeping unit exists and %1 is set to %2.', Comment = '%1: Field Caption, %2: Missing SKU Policy, %3: Item No., %4: Location Code';
        SKUNotPlannedTxt: Label 'Item %1 at Location %2 was not planned, because no stockkeeping unit exists and %3 is set to %4.', Comment = '%1: Item No., %2: Location Code, %3: Field Caption, %4: Missing SKU Policy';

#if not CLEAN27
    [Obsolete('Replaced by same procedure without parameter Manufacturing Setup', '27.0')]
    procedure CalculatePlanFromWorksheet(var Item: Record Item; ManufacturingSetup2: Record Microsoft.Manufacturing.Setup."Manufacturing Setup"; TemplateName: Code[10]; WorksheetName: Code[10]; OrderDate: Date; ToDate: Date; MRPPlanning: Boolean; RespectPlanningParm: Boolean)
    begin
        CalculatePlanFromWorksheet(Item, TemplateName, WorksheetName, OrderDate, ToDate, MRPPlanning, RespectPlanningParm);
    end;
#endif

    procedure CalculatePlanFromWorksheet(var Item: Record Item; TemplateName: Code[10]; WorksheetName: Code[10]; OrderDate: Date; ToDate: Date; MRPPlanning: Boolean; RespectPlanningParm: Boolean)
    var
        InventoryProfile: array[2] of Record "Inventory Profile" temporary;
#if not CLEAN27
        ManufacturingSetup: Record Microsoft.Manufacturing.Setup."Manufacturing Setup";
#endif
    begin
#if not CLEAN27
        ManufacturingSetup.GetRecordOnce();
        OnBeforeCalculatePlanFromWorksheet(
          Item, ManufacturingSetup, TemplateName, WorksheetName, OrderDate, ToDate, MRPPlanning, RespectPlanningParm);
#endif
        OnBeforeCalculatePlanFromWorksheet2(
          Item, TemplateName, WorksheetName, OrderDate, ToDate, MRPPlanning, RespectPlanningParm);

        PlanToDate := ToDate;
        InitVariables(InventoryProfile[1], Item, TemplateName, WorksheetName, MRPPlanning);
        DemandToInvtProfile(InventoryProfile[1], Item, ToDate);
        OrderDate := ForecastConsumption(InventoryProfile[1], Item, OrderDate, ToDate);
        OnCalculatePlanFromWorksheetOnAfterForecastConsumption(InventoryProfile[1], Item, OrderDate, ToDate, LineNo);
        BlanketOrderConsump(InventoryProfile[1], Item, ToDate);
        SupplytoInvProfile(InventoryProfile[1], Item, ToDate);
        OnCalculatePlanFromWorksheetOnBeforeUnfoldItemTracking(InventoryProfile[1], Item, ToDate, LineNo, TempTrkgReservEntry);
        UnfoldItemTracking(InventoryProfile[1], InventoryProfile[2]);
        FindCombination(InventoryProfile[1], InventoryProfile[2], Item);
        PlanItem(InventoryProfile[1], InventoryProfile[2], OrderDate, ToDate, RespectPlanningParm);
        OnCalculatePlanFromWorksheetOnAfterPlanItem(CurrTemplateName, CurrWorksheetName, Item, ReqLine, TempTrkgReservEntry);
        CommitTracking();

        OnAfterCalculatePlanFromWorksheet(Item);
    end;

    local procedure InitVariables(var InventoryProfile: Record "Inventory Profile"; Item: Record Item; TemplateName: Code[10]; WorksheetName: Code[10]; MRPPlanning: Boolean)
    var
        ItemTrackingCode: Record "Item Tracking Code";
    begin
        InventorySetup.GetRecordOnce();
        CurrTemplateName := TemplateName;
        CurrWorksheetName := WorksheetName;
        InventoryProfile.Reset();
        InventoryProfile.DeleteAll();
        TempSKU.Reset();
        TempSKU.DeleteAll();
        Clear(TempSKU);
        TempTransferSKU.Reset();
        TempTransferSKU.DeleteAll();
        Clear(TempTransferSKU);
        TempTrkgReservEntry.Reset();
        TempTrkgReservEntry.DeleteAll();
        TempItemTrkgEntry.Reset();
        TempItemTrkgEntry.DeleteAll();
        PlanMRP := MRPPlanning;
        if Item."Item Tracking Code" <> '' then begin
            ItemTrackingCode.Get(Item."Item Tracking Code");
            SpecificLotTracking := IsLotSpecificTracking(ItemTrackingCode);
            SpecificSNTracking := IsSNSpecificTracking(ItemTrackingCode);
        end else begin
            SpecificLotTracking := false;
            SpecificSNTracking := false;
        end;
        LineNo := 0; // Global variable
        PlanningTransparency.SetTemplAndWorksheet(CurrTemplateName, CurrWorksheetName);

        OnAfterInitVariables(InventoryProfile, Item);
    end;

    procedure CreateTempSKUForLocation(ItemNo: Code[20]; LocationCode: Code[10])
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateTempSKUForLocation(TempSKU, LocationCode, IsHandled, ItemNo);
        if IsHandled then
            exit;

        TempSKU.Init();
        TempSKU."Item No." := ItemNo;
        TransferPlanningParameters(TempSKU);
        TempSKU."Location Code" := LocationCode;
        if TempSKU."Reordering Policy" <> TempSKU."Reordering Policy"::" " then
            TempSKU.Insert();
    end;

    local procedure DemandToInvtProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date)
    var
        CopyOfItem: Record Item;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeDemandToInvProfile(InventoryProfile, Item, IsHandled);
        if IsHandled then
            exit;

        InventoryProfile.SetCurrentKey("Line No.");

        CopyOfItem.Copy(Item);
        Item.SetRange("Date Filter", 0D, ToDate);

        TransTransReqLineToProfile(InventoryProfile, Item, ToDate);
        TransShptTransLineToProfile(InventoryProfile, Item);

        OnAfterDemandToInvProfile(InventoryProfile, Item, TempItemTrkgEntry, LineNo, PlanMRP);

        Item.Copy(CopyOfItem);
    end;

    local procedure SupplytoInvProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date)
    var
        CopyOfItem: Record Item;
    begin
        InventoryProfile.Reset();
        InventoryProfile.SetCurrentKey("Line No.");

        CopyOfItem.Copy(Item);
        Item.SetRange("Date Filter");

        OnBeforeSupplyToInvProfile(InventoryProfile, Item, ToDate, TempItemTrkgEntry, LineNo);

        TransItemLedgEntryToProfile(InventoryProfile, Item);
        TransReqLineToProfile(InventoryProfile, Item, ToDate);
        TransRcptTransLineToProfile(InventoryProfile, Item, ToDate);

        OnAfterSupplyToInvProfile(InventoryProfile, Item, ToDate, TempItemTrkgEntry, LineNo, TempSKU, TempTransferSKU);

        Item.Copy(CopyOfItem);
    end;


    local procedure TransTransReqLineToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date)
    var
        TransferReqLine: Record "Requisition Line";
    begin
        TransferReqLine.SetCurrentKey("Replenishment System", Type, "No.", "Variant Code", "Transfer-from Code", "Transfer Shipment Date");
        TransferReqLine.SetRange("Replenishment System", TransferReqLine."Replenishment System"::Transfer);
        TransferReqLine.SetRange(Type, TransferReqLine.Type::Item);
        TransferReqLine.SetRange("No.", Item."No.");
        Item.CopyFilter("Location Filter", TransferReqLine."Transfer-from Code");
        Item.CopyFilter("Variant Filter", TransferReqLine."Variant Code");
        TransferReqLine.SetFilter("Transfer Shipment Date", '>%1&<=%2', 0D, ToDate);
        if TransferReqLine.FindSet() then
            repeat
                InsertInventoryProfile(InventoryProfile, TransferReqLine, Item);
            until TransferReqLine.Next() = 0;
    end;

    local procedure TransShptTransLineToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item)
    var
        TransLine: Record "Transfer Line";
        FilterIsSetOnLocation: Boolean;
        ShouldProcess: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTransShptTransLineToProfile(InventoryProfile, Item, LineNo, IsHandled, TransLine);
        if IsHandled then
            exit;

        FilterIsSetOnLocation := Item.GetFilter("Location Filter") <> '';
        if TransLine.FindLinesWithItemToPlan(Item, false, true) then
            repeat
                ShouldProcess := TransLine."Shipment Date" <> 0D;
                OnTransShptTransLineToProfileOnBeforeProcessLine(TransLine, ShouldProcess, Item);
                if ShouldProcess then begin
                    InventoryProfile.Init();
                    InventoryProfile."Line No." := GetNextLineNo();
                    InventoryProfile."Item No." := Item."No.";
                    OnTransShptTransLineToProfileOnBeforeTransferFromOutboundTransfer(Item, Transline);
                    InventoryProfile.TransferFromOutboundTransfer(TransLine, TempItemTrkgEntry);
                    OnTransShptTransLineToProfileOnAfterTransferFromOutboundTransfer(Item, Transline, InventoryProfile);
                    if InventoryProfile.IsSupply then
                        InventoryProfile.ChangeSign();
                    if FilterIsSetOnLocation then
                        InventoryProfile."Transfer Location Not Planned" := TransferLocationIsFilteredOut(Item, TransLine);
                    SyncTransferDemandWithReqLine(InventoryProfile, TransLine."Transfer-to Code");
                    InventoryProfile.Insert();
                    OnTransShptTransLineToProfileOnAfterInventoryProfileInsert(Item, Transline, InventoryProfile);
                end;
            until TransLine.Next() = 0;
    end;

    local procedure TransItemLedgEntryToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item)
    var
        ItemLedgEntry: Record "Item Ledger Entry";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeTransItemLedgEntryToProfile(InventoryProfile, Item, ItemLedgEntry, IsHandled, LineNo);
        if IsHandled then
            exit;
        if ItemLedgEntry.FindLinesWithItemToPlan(Item, false) then
            repeat
                InventoryProfile.Init();
                InventoryProfile."Line No." := GetNextLineNo();
                OnTransItemLedgEntryToProfileOnBeforeTransferFromItemLedgerEntry(Item, ItemLedgEntry);
                InventoryProfile.TransferFromItemLedgerEntry(ItemLedgEntry, TempItemTrkgEntry);
                OnTransItemLedgEntryToProfileOnAfterTransferFromItemLedgerEntry(Item, ItemLedgEntry, InventoryProfile);
                InventoryProfile."Due Date" := 0D;
                if not InventoryProfile.IsSupply then
                    InventoryProfile.ChangeSign();
                InventoryProfile.Insert();
                OnTransItemLedgEntryToProfileOnAfterInsertInventoryProfile(Item, ItemLedgEntry, InventoryProfile);
            until ItemLedgEntry.Next() = 0;
    end;

    local procedure TransReqLineToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date)
    var
        ReqLine: Record "Requisition Line";
        ReqLineReserve: Codeunit "Req. Line-Reserve";
    begin
        if ReqLine.FindLinesWithItemToPlan(Item) then
            repeat
                if ReqLine."Due Date" <> 0D then begin
                    InventoryProfile.Init();
                    InventoryProfile."Line No." := GetNextLineNo();
                    InventoryProfile."Item No." := Item."No.";
                    ReqLineReserve.TransferInventoryProfileFromRequisitionLine(InventoryProfile, ReqLine, TempItemTrkgEntry);
                    InventoryProfile.InsertSupplyInvtProfile(ToDate);
                end;
            until ReqLine.Next() = 0;
    end;

    local procedure TransRcptTransLineToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date)
    var
        TransLine: Record "Transfer Line";
        WhseEntry: Record "Warehouse Entry";
        FilterIsSetOnLocation: Boolean;
        ShouldProcess: Boolean;
    begin
        OnBeforeTransRcptTransLineToProfile(InventoryProfile, Item, ToDate);
        FilterIsSetOnLocation := Item.GetFilter("Location Filter") <> '';
        if TransLine.FindLinesWithItemToPlan(Item, true, true) then
            repeat
                ShouldProcess := TransLine."Receipt Date" <> 0D;
                OnTransRcptTransLineToProfileOnBeforeProcessLine(TransLine, ShouldProcess, Item);
                if ShouldProcess then begin
                    InventoryProfile.Init();
                    InventoryProfile."Line No." := GetNextLineNo();
                    InventoryProfile.TransferFromInboundTransfer(TransLine, TempItemTrkgEntry);
                    if TransLine."Planning Flexibility" = TransLine."Planning Flexibility"::Unlimited then
                        if (InventoryProfile."Finished Quantity" > 0) or
                           (TransLine."Quantity Shipped" > 0) or (TransLine."Derived From Line No." > 0)
                        then
                            InventoryProfile."Planning Flexibility" := InventoryProfile."Planning Flexibility"::None
                        else begin
                            WhseEntry.SetSourceFilter(
                              Database::"Transfer Line", 0, InventoryProfile."Source ID", InventoryProfile."Source Ref. No.", true);
                            if not WhseEntry.IsEmpty() then
                                InventoryProfile."Planning Flexibility" := InventoryProfile."Planning Flexibility"::None;
                        end;
                    if FilterIsSetOnLocation then
                        InventoryProfile."Transfer Location Not Planned" := TransferLocationIsFilteredOut(Item, TransLine);
                    OnTransRcptTransLineToProfileOnBeforeInsertSupplyInvtProfile(InventoryProfile, TransLine);
                    InventoryProfile.InsertSupplyInvtProfile(ToDate);
                    InsertTempTransferSKU(TransLine);
                    OnTransRcptTransLineToProfileOnAfterInsertInventoryProfile(TransLine, InventoryProfile);
                end;
            until TransLine.Next() = 0;
    end;

    local procedure TransferLocationIsFilteredOut(var Item: Record Item; var TransLine: Record "Transfer Line"): Boolean
    var
        TempTransLine: Record "Transfer Line" temporary;
    begin
        TempTransLine := TransLine;
        TempTransLine.Insert();
        Item.CopyFilter("Location Filter", TempTransLine."Transfer-from Code");
        Item.CopyFilter("Location Filter", TempTransLine."Transfer-to Code");
        exit(TempTransLine.IsEmpty);
    end;

    procedure ForecastConsumption(var DemandInvtProfile: Record "Inventory Profile"; var Item: Record Item; OrderDate: Date; ToDate: Date) UpdatedOrderDate: Date
    var
        ForecastEntry: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry";
        ForecastEntry2: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry";
        NextForecast: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry";
        ItemLedgEntry: Record "Item Ledger Entry";
        CustomCalendarChange: array[2] of Record "Customized Calendar Change";
        TotalForecastQty: Decimal;
        ReplenishmentLocation: Code[10];
        ForecastExist: Boolean;
        NextForecastExist: Boolean;
        ReplenishmentLocationFound: Boolean;
        ComponentForecast: Boolean;
        ComponentForecastFrom: Boolean;
        ByLocations: Boolean;
        ByVariants: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeForecastConsumption(
            DemandInvtProfile, Item, OrderDate, ToDate, UpdatedOrderDate, IsHandled,
            CurrForecast, ExcludeForecastBefore, UseParm, LineNo);
        if IsHandled then
            exit;

        UpdatedOrderDate := OrderDate;
        ComponentForecastFrom := false;
        InventorySetup.GetRecordOnce();
        ByLocations := InventorySetup."Use Forecast on Locations";
        ByVariants := InventorySetup."Use Forecast on Variants";

        if not ByLocations then begin
            ReplenishmentLocationFound := FindReplishmentLocation(ReplenishmentLocation, Item);
            if InventorySetup."Location Mandatory" and not ReplenishmentLocationFound then
                ComponentForecastFrom := true;
        end;

        case true of
            ByLocations and ByVariants:
                ForecastEntry.SetCurrentKey(
                  "Production Forecast Name", "Item No.", "Location Code", "Variant Code", "Forecast Date", "Component Forecast");
            ByLocations and not ByVariants:
                ForecastEntry.SetCurrentKey(
                  "Production Forecast Name", "Item No.", "Location Code", "Forecast Date", "Component Forecast", "Variant Code");
            not ByLocations and ByVariants:
                ForecastEntry.SetCurrentKey(
                  "Production Forecast Name", "Item No.", "Variant Code", "Forecast Date", "Component Forecast", "Location Code");
            not ByLocations and not ByVariants:
                ForecastEntry.SetCurrentKey(
                  "Production Forecast Name", "Item No.", "Component Forecast", "Forecast Date", "Location Code", "Variant Code");
        end;

        ItemLedgEntry.Reset();
        DemandInvtProfile.SetCurrentKey("Item No.", "Variant Code", "Location Code", "Due Date");

        NextForecast.Copy(ForecastEntry);

        InventorySetup.GetRecordOnce();

        if not UseParm then
            CurrForecast := InventorySetup."Current Demand Forecast";

        ForecastEntry.SetRange("Production Forecast Name", CurrForecast);
        ForecastEntry.SetRange("Forecast Date", ExcludeForecastBefore, ToDate);

        ForecastEntry.SetRange("Item No.", Item."No.");
        ForecastEntry2.Copy(ForecastEntry);
        Item.CopyFilter("Location Filter", ForecastEntry2."Location Code");

        for ComponentForecast := ComponentForecastFrom to true do begin
            if not InventorySetup."Use Forecast on Locations" then
                if ComponentForecast then begin
                    if not FindReplishmentLocation(ReplenishmentLocation, Item) then
                        ReplenishmentLocation := GetComponentsAtLocationCode();
                    if InventorySetup."Location Mandatory" and (ReplenishmentLocation = '') then
                        exit;
                end;
            ForecastEntry.SetRange("Component Forecast", ComponentForecast);
            ForecastEntry2.SetRange("Component Forecast", ComponentForecast);
            if ForecastEntry2.Find('-') then
                repeat
                    if ByLocations then begin
                        ForecastEntry2.SetRange("Location Code", ForecastEntry2."Location Code");
                        ItemLedgEntry.SetRange("Location Code", ForecastEntry2."Location Code");
                        DemandInvtProfile.SetRange("Location Code", ForecastEntry2."Location Code");
                    end else begin
                        Item.CopyFilter("Location Filter", ForecastEntry2."Location Code");
                        Item.CopyFilter("Location Filter", ItemLedgEntry."Location Code");
                        Item.CopyFilter("Location Filter", DemandInvtProfile."Location Code");
                    end;

                    if ByVariants then begin
                        ForecastEntry2.SetRange("Variant Code", ForecastEntry2."Variant Code");
                        ItemLedgEntry.SetRange("Variant Code", ForecastEntry2."Variant Code");
                        DemandInvtProfile.SetRange("Variant Code", ForecastEntry2."Variant Code");
                    end else begin
                        Item.CopyFilter("Variant Filter", ForecastEntry2."Variant Code");
                        Item.CopyFilter("Variant Filter", ItemLedgEntry."Variant Code");
                        Item.CopyFilter("Variant Filter", DemandInvtProfile."Variant Code");
                    end;

                    ForecastEntry2.Find('+');
                    ForecastEntry2.CopyFilter("Location Code", ForecastEntry."Location Code");
                    Item.CopyFilter("Location Filter", ForecastEntry2."Location Code");
                    ForecastEntry2.CopyFilter("Variant Code", ForecastEntry."Variant Code");
                    Item.CopyFilter("Variant Filter", ForecastEntry2."Variant Code");

                    ForecastExist := CheckForecastExist(ForecastEntry, OrderDate, ToDate);

                    if ForecastExist then
                        repeat
                            ForecastEntry.SetRange("Forecast Date", ForecastEntry."Forecast Date");
                            ForecastEntry.CalcSums("Forecast Quantity (Base)");
                            TotalForecastQty := ForecastEntry."Forecast Quantity (Base)";
                            ForecastEntry.Find('+');
                            NextForecast.CopyFilters(ForecastEntry);
                            NextForecast.SetRange("Forecast Date", ForecastEntry."Forecast Date" + 1, ToDate);
                            if not NextForecast.FindFirst() then
                                NextForecast."Forecast Date" := ToDate + 1
                            else
                                repeat
                                    NextForecast.SetRange("Forecast Date", NextForecast."Forecast Date");
                                    NextForecast.CalcSums("Forecast Quantity (Base)");
                                    if NextForecast."Forecast Quantity (Base)" = 0 then begin
                                        NextForecast.SetRange("Forecast Date", NextForecast."Forecast Date" + 1, ToDate);
                                        if not NextForecast.FindFirst() then
                                            NextForecast."Forecast Date" := ToDate + 1
                                    end else
                                        NextForecastExist := true
                                until (NextForecast."Forecast Date" = ToDate + 1) or NextForecastExist;
                            NextForecastExist := false;

                            ItemLedgEntry.SetRange("Item No.", Item."No.");
                            ItemLedgEntry.SetRange(Positive, false);
                            ItemLedgEntry.SetRange(Open);
                            ItemLedgEntry.SetRange(
                              "Posting Date", ForecastEntry."Forecast Date", NextForecast."Forecast Date" - 1);
                            Item.CopyFilter("Variant Filter", ItemLedgEntry."Variant Code");
                            if ComponentForecast then begin
                                ItemLedgEntry.SetRange("Entry Type", ItemLedgEntry."Entry Type"::Consumption);
                                ItemLedgEntry.CalcSums(Quantity);
                                TotalForecastQty += ItemLedgEntry.Quantity;
                            end else begin
                                ItemLedgEntry.SetRange("Entry Type", ItemLedgEntry."Entry Type"::Sale);
                                ItemLedgEntry.SetRange("Derived from Blanket Order", false);
                                ItemLedgEntry.CalcSums(Quantity);
                                TotalForecastQty += ItemLedgEntry.Quantity;
                                ItemLedgEntry.SetRange("Derived from Blanket Order");
                                // Undo shipment shall neutralize consumption from sales
                                ItemLedgEntry.SetRange(Positive, true);
                                ItemLedgEntry.SetRange(Correction, true);
                                ItemLedgEntry.CalcSums(Quantity);
                                TotalForecastQty += ItemLedgEntry.Quantity;
                                ItemLedgEntry.SetRange(Correction);
                            end;

                            DemandInvtProfile.SetRange("Item No.", ForecastEntry."Item No.");
                            DemandInvtProfile.SetRange(
                              "Due Date", ForecastEntry."Forecast Date", NextForecast."Forecast Date" - 1);
                            DemandInvtProfile.SetRange("Source Type");
                            if ComponentForecast then begin
                                DemandInvtProfile.SetSourceTypeFilter(5407); // Database::"Prod. Order Component"
                                DemandInvtProfile.SetSourceTypeFilter(Database::"Planning Component");
                                OnForecastConsumptionOnAfterSetPlanningSourceTypeFilter(DemandInvtProfile);
                            end else begin
                                DemandInvtProfile.SetSourceTypeFilter(Database::"Sales Line");
                                OnForecastConsumptionOnAfterSetSalesSourceTypeFilter(DemandInvtProfile);
                            end;
                            OnForecastConsumptionOnBeforeFindDemandInvtProfile(DemandInvtProfile, ComponentForecast);
                            if DemandInvtProfile.Find('-') then
                                repeat
                                    if not (DemandInvtProfile.IsSupply or DemandInvtProfile."Derived from Blanket Order")
                                    then
                                        TotalForecastQty := TotalForecastQty - DemandInvtProfile."Remaining Quantity (Base)";
                                until (DemandInvtProfile.Next() = 0) or (TotalForecastQty < 0);
                            if TotalForecastQty > 0 then begin
                                ForecastInitDemand(DemandInvtProfile, ForecastEntry, Item."No.", ReplenishmentLocation, TotalForecastQty);
                                CustomCalendarChange[1].SetSource(CustomizedCalendarChange."Source Type"::Location, DemandInvtProfile."Location Code", '', '');
                                CustomCalendarChange[2].SetSource(CustomizedCalendarChange."Source Type"::Location, DemandInvtProfile."Location Code", '', '');
                                DemandInvtProfile."Due Date" := CalendarManagement.CalcDateBOC2('<0D>', ForecastEntry."Forecast Date", CustomCalendarChange, false);
                                OnForecastConsumptionOnAfterCalcDueDate(DemandInvtProfile, TotalForecastQty, ForecastEntry, NextForecast, Item, OrderDate, ToDate);
                                if DemandInvtProfile."Due Date" < UpdatedOrderDate then
                                    UpdatedOrderDate := DemandInvtProfile."Due Date";
                                DemandInvtProfile.Insert();
                            end;
                            ForecastEntry.SetRange("Forecast Date", ExcludeForecastBefore, ToDate);
                        until ForecastEntry.Next() = 0;
                until ForecastEntry2.Next() = 0;
        end;
    end;

    local procedure BlanketOrderConsump(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date)
    var
        BlanketSalesLine: Record "Sales Line";
        SalesLineInvtProfile: Codeunit "Sales Line Invt. Profile";
        QtyReleased: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeBlanketOrderConsump(InventoryProfile, Item, ToDate, IsHandled);
        if IsHandled then
            exit;

        InventoryProfile.Reset();
        BlanketSalesLine.SetCurrentKey("Document Type", "Document No.", Type, "No.");
        BlanketSalesLine.SetRange("Document Type", BlanketSalesLine."Document Type"::"Blanket Order");
        BlanketSalesLine.SetRange(Type, BlanketSalesLine.Type::Item);
        BlanketSalesLine.SetRange("No.", Item."No.");
        Item.CopyFilter("Location Filter", BlanketSalesLine."Location Code");
        Item.CopyFilter("Variant Filter", BlanketSalesLine."Variant Code");
        BlanketSalesLine.SetFilter("Outstanding Qty. (Base)", '<>0');
        BlanketSalesLine.SetFilter("Shipment Date", '>%1&<=%2', 0D, ToDate);
        OnBeforeBlanketOrderConsumpFind(BlanketSalesLine);
        if BlanketSalesLine.Find('-') then
            repeat
                QtyReleased := CalcInventoryProfileRemainingQty(InventoryProfile, BlanketSalesLine."Document No.", BlanketSalesLine."Line No.");
                if BlanketSalesLine."Quantity (Base)" <> BlanketSalesLine."Qty. to Asm. to Order (Base)" then
                    if BlanketSalesLine."Outstanding Qty. (Base)" - BlanketSalesLine."Qty. to Asm. to Order (Base)" > QtyReleased then begin
                        InventoryProfile.Init();
                        InventoryProfile."Line No." := GetNextLineNo();
                        SalesLineInvtProfile.TransferInventoryProfileFromSalesLine(InventoryProfile, BlanketSalesLine, TempItemTrkgEntry);
                        InventoryProfile."Untracked Quantity" := BlanketSalesLine."Outstanding Qty. (Base)" - QtyReleased;
                        InventoryProfile."Remaining Quantity (Base)" := InventoryProfile."Untracked Quantity";
                        InventoryProfile.Insert();
                    end;
            until BlanketSalesLine.Next() = 0;
    end;

    procedure CheckForecastExist(var ForecastEntry: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry"; OrderDate: Date; ToDate: Date): Boolean
    var
        ForecastExist: Boolean;
    begin
        ForecastEntry.SetRange("Forecast Date", ExcludeForecastBefore, OrderDate);
        if ForecastEntry.Find('+') then
            repeat
                ForecastEntry.SetRange("Forecast Date", ForecastEntry."Forecast Date");
                ForecastEntry.CalcSums("Forecast Quantity (Base)");
                if ForecastEntry."Forecast Quantity (Base)" <> 0 then
                    ForecastExist := true
                else
                    ForecastEntry.SetRange("Forecast Date", ExcludeForecastBefore, ForecastEntry."Forecast Date" - 1);
            until (not ForecastEntry.Find('+')) or ForecastExist;

        if not ForecastExist then begin
            if ExcludeForecastBefore > OrderDate then
                ForecastEntry.SetRange("Forecast Date", ExcludeForecastBefore, ToDate)
            else
                ForecastEntry.SetRange("Forecast Date", OrderDate + 1, ToDate);
            if ForecastEntry.Find('-') then
                repeat
                    ForecastEntry.SetRange("Forecast Date", ForecastEntry."Forecast Date");
                    ForecastEntry.CalcSums("Forecast Quantity (Base)");
                    if ForecastEntry."Forecast Quantity (Base)" <> 0 then
                        ForecastExist := true
                    else
                        ForecastEntry.SetRange("Forecast Date", ForecastEntry."Forecast Date" + 1, ToDate);
                until (not ForecastEntry.Find('-')) or ForecastExist
        end;

        OnAfterCheckForecastExist(ForecastEntry, ExcludeForecastBefore, OrderDate, ToDate, ForecastExist);
        exit(ForecastExist);
    end;

    procedure FindReplishmentLocation(var ReplenishmentLocation: Code[10]; var Item: Record Item): Boolean
    var
        SKU: Record "Stockkeeping Unit";
    begin
        ReplenishmentLocation := '';
        SKU.SetCurrentKey("Item No.", "Location Code", "Variant Code");
        SKU.SetRange("Item No.", Item."No.");
        Item.CopyFilter("Location Filter", SKU."Location Code");
        Item.CopyFilter("Variant Filter", SKU."Variant Code");
        SKU.SetRange("Replenishment System", Item."Replenishment System"::Purchase, Item."Replenishment System"::"Prod. Order");
        SKU.SetFilter("Reordering Policy", '<>%1', SKU."Reordering Policy"::" ");
        OnFindReplishmentLocationOnBeforeFindSKU(SKU);
        if SKU.Find('-') then
            if SKU.Next() = 0 then
                ReplenishmentLocation := SKU."Location Code";
        exit(ReplenishmentLocation <> '');
    end;

    local procedure FindCombination(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var Item: Record Item)
    var
        SKU: Record "Stockkeeping Unit";
        Location: Record Location;
        State: Option DemandExist,SupplyExist,BothExist;
        DemandBool: Boolean;
        SupplyBool: Boolean;
        TransitLocation: Boolean;
        IsHandled: Boolean;
    begin
        InventorySetup.GetRecordOnce();
        CreateTempSKUForComponentsLocation(Item);

        SKU.SetCurrentKey("Item No.", "Location Code", "Variant Code");
        SKU.SetRange("Item No.", Item."No.");
        Item.CopyFilter("Variant Filter", SKU."Variant Code");
        Item.CopyFilter("Location Filter", SKU."Location Code");

        OnFindCombinationOnBeforeSKUFindSet(SKU, Item);
        if SKU.FindSet() then
            FillSkUBuffer(SKU)
        else
            FillTempSKUForLocation(Item, SupplyInvtProfile);

        Clear(DemandInvtProfile);
        Clear(SupplyInvtProfile);
        OnFindCombinationOnBeforeFilterDemandAndSupply(DemandInvtProfile, SupplyInvtProfile);
        DemandInvtProfile.SetCurrentKey(
          "Item No.", "Variant Code", "Location Code", "Due Date", "Attribute Priority", "Order Priority");
        SupplyInvtProfile.SetCurrentKey(
          "Item No.", "Variant Code", "Location Code", "Due Date", "Attribute Priority", "Order Priority");
        DemandInvtProfile.SetRange(IsSupply, false);
        SupplyInvtProfile.SetRange(IsSupply, true);
        DemandBool := DemandInvtProfile.Find('-');
        SupplyBool := SupplyInvtProfile.Find('-');

        while DemandBool or SupplyBool do begin
            if DemandBool then begin
                TempSKU."Item No." := DemandInvtProfile."Item No.";
                TempSKU."Variant Code" := DemandInvtProfile."Variant Code";
                TempSKU."Location Code" := DemandInvtProfile."Location Code";
                OnFindCombinationAfterAssignTempSKU(TempSKU, DemandInvtProfile);
            end else begin
                TempSKU."Item No." := SupplyInvtProfile."Item No.";
                TempSKU."Variant Code" := SupplyInvtProfile."Variant Code";
                TempSKU."Location Code" := SupplyInvtProfile."Location Code";
                OnFindCombinationAfterAssignTempSKU(TempSKU, SupplyInvtProfile);
            end;

            IsHandled := false;
            OnFindCombinationOnBeforeSetState(TempSKU, Item, IsHandled);
            if IsHandled then
                exit;

            if DemandBool and SupplyBool then
                State := State::BothExist
            else
                if DemandBool then
                    State := State::DemandExist
                else
                    State := State::SupplyExist;

            case State of
                State::DemandExist:
                    DemandBool := FindNextSKU(DemandInvtProfile);
                State::SupplyExist:
                    SupplyBool := FindNextSKU(SupplyInvtProfile);
                State::BothExist:
                    if DemandInvtProfile."Variant Code" = SupplyInvtProfile."Variant Code" then begin
                        if DemandInvtProfile."Location Code" = SupplyInvtProfile."Location Code" then begin
                            DemandBool := FindNextSKU(DemandInvtProfile);
                            SupplyBool := FindNextSKU(SupplyInvtProfile);
                        end else
                            if DemandInvtProfile."Location Code" < SupplyInvtProfile."Location Code" then
                                DemandBool := FindNextSKU(DemandInvtProfile)
                            else
                                SupplyBool := FindNextSKU(SupplyInvtProfile)
                    end else
                        if DemandInvtProfile."Variant Code" < SupplyInvtProfile."Variant Code" then
                            DemandBool := FindNextSKU(DemandInvtProfile)
                        else
                            SupplyBool := FindNextSKU(SupplyInvtProfile);
            end;

            if TempSKU."Location Code" <> '' then begin
                Location.Get(TempSKU."Location Code"); // Assert: will fail if location cannot be found.
                TransitLocation := Location."Use As In-Transit";
            end else
                TransitLocation := false; // Variant SKU only - no location code involved.

            if not TransitLocation then begin
                TransferPlanningParameters(TempSKU);
                InsertTempSKU();
                while (TempSKU."Replenishment System" = TempSKU."Replenishment System"::Transfer) and
                      (TempSKU."Reordering Policy" <> TempSKU."Reordering Policy"::" ")
                do begin
                    TempSKU."Location Code" := TempSKU."Transfer-from Code";
                    TransferPlanningParameters(TempSKU);
                    if TempSKU."Reordering Policy" <> TempSKU."Reordering Policy"::" " then
                        InsertTempSKU();
                end;
            end;
        end;

        Item.CopyFilter("Location Filter", TempSKU."Location Code");
        Item.CopyFilter("Variant Filter", TempSKU."Variant Code");

        OnAfterFindCombination(DemandInvtProfile, SupplyInvtProfile);
    end;

    local procedure FillSKUBuffer(var SKU: Record "Stockkeeping Unit")
    var
        PlanningGetParameters: Codeunit "Planning-Get Parameters";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeFillSkUBuffer(SKU, TempSKU, IsHandled);
        if IsHandled then
            exit;

        repeat
            PlanningGetParameters.AdjustInvalidSettings(SKU);
            if (SKU."Safety Stock Quantity" <> 0) or (SKU."Reorder Point" <> 0) or
               (SKU."Reorder Quantity" <> 0) or (SKU."Maximum Inventory" <> 0)
            then begin
                TempSKU.TransferFields(SKU);
                if TempSKU.Insert() then;
                while (TempSKU."Replenishment System" = TempSKU."Replenishment System"::Transfer) and
                      (TempSKU."Reordering Policy" <> TempSKU."Reordering Policy"::" ")
                do begin
                    TempSKU."Location Code" := TempSKU."Transfer-from Code";
                    TransferPlanningParameters(TempSKU);
                    if TempSKU."Reordering Policy" <> TempSKU."Reordering Policy"::" " then
                        InsertTempSKU();
                end;
            end;
        until SKU.Next() = 0;
    end;

    local procedure FillTempSKUForLocation(var Item: Record Item; SupplyInvtProfile: Record "Inventory Profile")
    begin
        OnFillTempSKUForLocation(Item, SupplyInvtProfile);
    end;

    local procedure InsertTempSKU()
    var
        SKU2: Record "Stockkeeping Unit";
        PlanningGetParameters: Codeunit "Planning-Get Parameters";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertTempSKU(TempSKU, IsHandled);
        if IsHandled then
            exit;

        if not TempSKU.Find('=') then begin
            if not IsMissingSKUPlanningPolicyItemCard(TempSKU."Location Code") then
                PlanningGetParameters.SetLotForLot();
            PlanningGetParameters.AtSKU(SKU2, TempSKU."Item No.", TempSKU."Variant Code", TempSKU."Location Code");
            TempSKU := SKU2;
            if TempSKU."Reordering Policy" <> TempSKU."Reordering Policy"::" " then begin
                OnBeforeTempSKUInsert(TempSKU, PlanningGetParameters);
                TempSKU.Insert();
            end;
        end;
    end;

    local procedure FindNextSKU(var InventoryProfile: Record "Inventory Profile"): Boolean
    begin
        TempSKU."Variant Code" := InventoryProfile."Variant Code";
        TempSKU."Location Code" := InventoryProfile."Location Code";
        OnFindNextSKUOnAfterAssignTempSKU(TempSKU, InventoryProfile);

        InventoryProfile.SetRange("Variant Code", TempSKU."Variant Code");
        InventoryProfile.SetRange("Location Code", TempSKU."Location Code");
        InventoryProfile.FindLast();
        InventoryProfile.SetRange("Variant Code");
        InventoryProfile.SetRange("Location Code");
        exit(InventoryProfile.Next() <> 0);
    end;

    local procedure TransferPlanningParameters(var SKU: Record "Stockkeeping Unit")
    var
        SKU2: Record "Stockkeeping Unit";
        PlanningGetParameters: Codeunit "Planning-Get Parameters";
    begin
        PlanningGetParameters.AtSKU(SKU2, SKU."Item No.", SKU."Variant Code", SKU."Location Code");
        SKU := SKU2;

        OnAfterTransferPlanningParameters(SKU);
    end;

    local procedure DeleteTracking(var SKU: Record "Stockkeeping Unit"; ToDate: Date; var SupplyInventoryProfile: Record "Inventory Profile")
    var
        Item: Record Item;
        ReservEntry1: Record "Reservation Entry";
        ResEntryWasDeleted: Boolean;
    begin
        ActionMsgEntry.SetCurrentKey("Reservation Entry");

        ReservEntry.Reset();
        ReservEntry.SetCurrentKey("Item No.", "Variant Code", "Location Code");
        ReservEntry.SetRange("Item No.", SKU."Item No.");
        ReservEntry.SetRange("Variant Code", SKU."Variant Code");
        ReservEntry.SetRange("Location Code", SKU."Location Code");
        ReservEntry.SetFilter(ReservEntry."Reservation Status", '<>%1', ReservEntry."Reservation Status"::Prospect);
        OnDeleteTrackingOnAfterSetReservEntryFilters(ReservEntry, SKU, ToDate);
        if ReservEntry.Find('-') then
            repeat
                Item.SetLoadFields("Manufacturing Policy", "Replenishment System", "Reordering Policy", "Order Tracking Policy");
                Item.Get(ReservEntry."Item No.");
                if not IsTrkgForSpecialOrderOrDropShpt(ReservEntry) then begin
                    if ShouldDeleteReservEntry(ReservEntry, ToDate) then begin
                        ResEntryWasDeleted := true;
                        if ((ReservEntry."Source Type" = Database::"Item Ledger Entry") or CheckReorderingPolicyAndOrderTrackingPolicy(Item)) and
                           (ReservEntry."Reservation Status" = ReservEntry."Reservation Status"::Tracking)
                        then
                            if ReservEntry1.Get(ReservEntry."Entry No.", not ReservEntry.Positive) then
                                ReservEntry1.Delete();
                        ReservEntry.Delete();
                    end else
                        ResEntryWasDeleted := CloseTracking(ReservEntry, SupplyInventoryProfile, ToDate);

                    if ResEntryWasDeleted then begin
                        ActionMsgEntry.SetRange("Reservation Entry", ReservEntry."Entry No.");
                        ActionMsgEntry.DeleteAll();
                    end;
                end;
            until ReservEntry.Next() = 0;
    end;

    local procedure ShouldDeleteReservEntry(ReservEntry: Record "Reservation Entry"; ToDate: Date): Boolean
    var
        Item: Record Item;
        IsReservedForProdComponent: Boolean;
        DeleteCondition: Boolean;
    begin
        IsReservedForProdComponent := ReservedForProdComponent(ReservEntry);
        if IsReservedForProdComponent and not ReservEntry.IsReservationOrTracking() then
            if IsProdOrderPlanned(ReservEntry) then
                exit(false);

        Item.SetLoadFields("Manufacturing Policy", "Replenishment System");
        Item.Get(ReservEntry."Item No.");
        DeleteCondition :=
            (ReservEntry."Reservation Status" <> ReservEntry."Reservation Status"::Reservation) and
            (((ReservEntry."Expected Receipt Date" <= ToDate) and
            (ReservEntry."Shipment Date" <= ToDate)) or
            ((ReservEntry.Binding = ReservEntry.Binding::"Order-to-Order") and (ReservEntry."Shipment Date" <= ToDate) and
            (Item."Manufacturing Policy" = Item."Manufacturing Policy"::"Make-to-Stock") and Item.IsMfgItem() and
            (not IsReservedForProdComponent)));

        OnAfterShouldDeleteReservEntry(ReservEntry, ToDate, DeleteCondition, CurrTemplateName, CurrWorksheetName);
        exit(DeleteCondition);
    end;

    local procedure IsProdOrderPlanned(var ReservEntry: Record "Reservation Entry") Planned: Boolean
    begin
        OnIsProdOrderPlanned(ReservEntry, Planned);
    end;

    local procedure RemoveOrdinaryInventory(var Supply: Record "Inventory Profile")
    var
        Supply2: Record "Inventory Profile";
    begin
        Supply2.Copy(Supply);
        Supply.SetRange(IsSupply);
        Supply.SetRange("Source Type", Database::"Item Ledger Entry");
        Supply.SetFilter(Binding, '<>%1', Supply2.Binding::"Order-to-Order");
        Supply.DeleteAll();
        Supply.Copy(Supply2);
    end;

    local procedure UnfoldItemTracking(var ParentInvProfile: Record "Inventory Profile"; var ChildInvProfile: Record "Inventory Profile")
    begin
        OnBeforeUnfoldItemTracking(ParentInvProfile, ChildInvProfile, TempItemTrkgEntry);

        ParentInvProfile.Reset();
        TempItemTrkgEntry.Reset();
        if not TempItemTrkgEntry.Find('-') then
            exit;
        ParentInvProfile.SetFilter("Source Type", '<>%1', Database::"Item Ledger Entry");
        ParentInvProfile.SetRange("Tracking Reference", 0);
        if ParentInvProfile.Find('-') then
            repeat
                TempItemTrkgEntry.Reset();
                TempItemTrkgEntry.SetSourceFilter(
                  ParentInvProfile."Source Type", ParentInvProfile."Source Order Status", ParentInvProfile."Source ID",
                  ParentInvProfile."Source Ref. No.", false);
                TempItemTrkgEntry.SetSourceFilter(ParentInvProfile."Source Batch Name", ParentInvProfile."Source Prod. Order Line");
                if TempItemTrkgEntry.Find('-') then begin
                    if ParentInvProfile.IsSupply and
                       (ParentInvProfile.Binding <> ParentInvProfile.Binding::"Order-to-Order")
                    then
                        ParentInvProfile."Planning Flexibility" := ParentInvProfile."Planning Flexibility"::None;
                    repeat
                        ChildInvProfile := ParentInvProfile;
                        ChildInvProfile."Line No." := GetNextLineNo();
                        ChildInvProfile."Tracking Reference" := ParentInvProfile."Line No.";
                        ChildInvProfile.CopyTrackingFromReservEntry(TempItemTrkgEntry);
                        ChildInvProfile."Expiration Date" := TempItemTrkgEntry."Expiration Date";
                        ChildInvProfile.TransferQtyFromItemTrgkEntry(TempItemTrkgEntry);
                        OnAfterTransToChildInvProfile(TempItemTrkgEntry, ChildInvProfile);
                        ChildInvProfile.Insert();
                        ParentInvProfile.ReduceQtyByItemTracking(ChildInvProfile);
                        ParentInvProfile.Modify();
                    until TempItemTrkgEntry.Next() = 0;
                end;
            until ParentInvProfile.Next() = 0;

        OnAfterUnfoldItemTracking(ParentInvProfile, ChildInvProfile);
    end;

    local procedure MatchAttributes(var SupplyInvtProfile: Record "Inventory Profile"; var DemandInvtProfile: Record "Inventory Profile"; RespectPlanningParm: Boolean; DemandForAdditionalProfile: Boolean)
    var
        xDemandInvtProfile: Record "Inventory Profile";
        xSupplyInvtProfile: Record "Inventory Profile";
        SupplyIleInvtProfile: Record "Inventory Profile";
        NewSupplyDate: Date;
        SupplyExists: Boolean;
        CanBeRescheduled: Boolean;
        ItemInventoryExists: Boolean;
        SkipMatchingAttributes: Boolean;
    begin
        SkipMatchingAttributes := false;
        OnBeforeMatchAttributes(SupplyInvtProfile, DemandInvtProfile, SkipMatchingAttributes);
        if SkipMatchingAttributes then
            exit;

        xDemandInvtProfile.CopyFilters(DemandInvtProfile);
        xSupplyInvtProfile.CopyFilters(SupplyInvtProfile);
        ItemInventoryExists := CheckItemInventoryExists(SupplyInvtProfile);
        DemandInvtProfile.SetRange("Attribute Priority", 1, 7);
        DemandInvtProfile.SetFilter("Source Type", '<>%1', Database::"Requisition Line");
        if DemandInvtProfile.FindSet(true) then
            repeat
                SupplyInvtProfile.SetRange(Binding, DemandInvtProfile.Binding);
                SupplyInvtProfile.SetRange("Primary Order Status", DemandInvtProfile."Primary Order Status");
                SupplyInvtProfile.SetRange("Primary Order No.", DemandInvtProfile."Primary Order No.");
                SupplyInvtProfile.SetRange("Primary Order Line", DemandInvtProfile."Primary Order Line");
                SupplyInvtProfile.SetRange("Source Prod. Order Line");
                if ((DemandInvtProfile."Ref. Order Type" = DemandInvtProfile."Ref. Order Type"::Assembly) or
                    ((DemandInvtProfile."Ref. Order Type" = DemandInvtProfile."Ref. Order Type"::"Prod. Order") and
                     (DemandInvtProfile."Source Type" = Database::"Planning Component"))) and
                   (DemandInvtProfile.Binding = DemandInvtProfile.Binding::"Order-to-Order") and
                   (DemandInvtProfile."Primary Order No." = '')
                then
                    SupplyInvtProfile.SetRange("Source Prod. Order Line", DemandInvtProfile."Source Prod. Order Line");

                SupplyInvtProfile.SetTrackingFilter(DemandInvtProfile);
                SupplyExists := SupplyInvtProfile.FindFirst();
                SupplyIleInvtProfile.Copy(SupplyInvtProfile);
                OnBeforeMatchAttributesDemandApplicationLoop(SupplyInvtProfile, DemandInvtProfile, SupplyExists);
                while (DemandInvtProfile."Untracked Quantity" > 0) and
                      (not ApplyUntrackedQuantityToItemInventory(SupplyExists, ItemInventoryExists, DemandForAdditionalProfile))
                do begin
                    OnStartOfMatchAttributesDemandApplicationLoop(SupplyInvtProfile, DemandInvtProfile, SupplyExists);
                    if SupplyExists and (DemandInvtProfile.Binding = DemandInvtProfile.Binding::"Order-to-Order") then begin
                        NewSupplyDate := SupplyInvtProfile."Due Date";
                        CanBeRescheduled :=
                          (SupplyInvtProfile."Fixed Date" = 0D) and
                          ((SupplyInvtProfile."Due Date" <> DemandInvtProfile."Due Date") or
                           (SupplyInvtProfile."Due Time" <> DemandInvtProfile."Due Time"));
                        if CanBeRescheduled then
                            if (SupplyInvtProfile."Due Date" > DemandInvtProfile."Due Date") or
                               (SupplyInvtProfile."Due Time" > DemandInvtProfile."Due Time")
                            then
                                CanBeRescheduled := CheckScheduleIn(SupplyInvtProfile, DemandInvtProfile."Due Date", NewSupplyDate, false)
                            else
                                CanBeRescheduled := CheckScheduleOut(SupplyInvtProfile, DemandInvtProfile."Due Date", NewSupplyDate, false);
                        if CanBeRescheduled and
                           ((NewSupplyDate <> SupplyInvtProfile."Due Date") or (SupplyInvtProfile."Planning Level Code" > 0))
                        then begin
                            Reschedule(SupplyInvtProfile, DemandInvtProfile."Due Date", DemandInvtProfile."Due Time");
                            SupplyInvtProfile."Fixed Date" := SupplyInvtProfile."Due Date";
                        end;
                    end;
                    if not SupplyExists or (SupplyInvtProfile."Due Date" > DemandInvtProfile."Due Date") then begin
                        InitSupply(
                          SupplyInvtProfile, DemandInvtProfile."Untracked Quantity", DemandInvtProfile."Due Date", DemandInvtProfile."Due Time");
                        OnMatchAttributesOnAfterInitSupply(SupplyInvtProfile, DemandInvtProfile);
                        TransferAttributes(SupplyInvtProfile, DemandInvtProfile);
                        SupplyInvtProfile."Fixed Date" := SupplyInvtProfile."Due Date";
                        SupplyInvtProfile.Insert();
                        SupplyExists := true;
                    end;

                    if DemandInvtProfile.Binding = DemandInvtProfile.Binding::"Order-to-Order" then
                        if (DemandInvtProfile."Untracked Quantity" > SupplyInvtProfile."Untracked Quantity") and
                           (SupplyInvtProfile."Due Date" <= DemandInvtProfile."Due Date")
                        then
                            IncreaseQtyToMeetDemand(SupplyInvtProfile, DemandInvtProfile, false, RespectPlanningParm, false);
                    if (TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Maximum Qty.") and DemandForAdditionalProfile then
                        DecreaseQtyForMaxQty(SupplyInvtProfile, SupplyIleInvtProfile."Untracked Quantity");
                    if SupplyInvtProfile."Untracked Quantity" < DemandInvtProfile."Untracked Quantity" then
                        SupplyExists := CloseSupply(DemandInvtProfile, SupplyInvtProfile)
                    else
                        CloseDemand(DemandInvtProfile, SupplyInvtProfile);
                    OnEndMatchAttributesDemandApplicationLoop(SupplyInvtProfile, DemandInvtProfile, SupplyExists);
                end;
            until DemandInvtProfile.Next() = 0;

        // Neutralize or generalize excess Order-To-Order Supply
        SupplyInvtProfile.CopyFilters(xSupplyInvtProfile);
        SupplyInvtProfile.SetRange(Binding, SupplyInvtProfile.Binding::"Order-to-Order");
        SupplyInvtProfile.SetFilter("Untracked Quantity", '>=0');
        if SupplyInvtProfile.FindSet() then
            repeat
                if SupplyInvtProfile."Untracked Quantity" > 0 then begin
                    if DecreaseQty(SupplyInvtProfile, SupplyInvtProfile."Untracked Quantity", false) then begin
                        // Assertion: New specific Supply shall match the Demand exactly and must not update
                        // the Planning Line again since that will double the derived demand in case of transfers
                        if SupplyInvtProfile."Action Message" = SupplyInvtProfile."Action Message"::New then
                            SupplyInvtProfile.FieldError("Action Message");
                        MaintainPlanningLine(SupplyInvtProfile, DemandInvtProfile, PlanningLineStage::Exploded, ScheduleDirection::Backward)
                    end else
                        // Evaluate excess supply
                        if TempSKU."Include Inventory" then begin
                            // Release the remaining Untracked Quantity
                            SupplyInvtProfile.Binding := SupplyInvtProfile.Binding::" ";
                            SupplyInvtProfile."Primary Order Type" := 0;
                            SupplyInvtProfile."Primary Order Status" := 0;
                            SupplyInvtProfile."Primary Order No." := '';
                            SupplyInvtProfile."Primary Order Line" := 0;
                            SetAttributePriority(SupplyInvtProfile);
                        end else
                            SupplyInvtProfile."Untracked Quantity" := 0;

                    // Ensure that the directly allocated quantity will not be part of Projected Inventory
                    if SupplyInvtProfile."Untracked Quantity" <> 0 then begin
                        UpdateQty(SupplyInvtProfile, SupplyInvtProfile."Untracked Quantity");
                        SupplyInvtProfile.Modify();
                    end;
                end;
                if SupplyInvtProfile."Untracked Quantity" = 0 then
                    SupplyInvtProfile.Delete();
            until SupplyInvtProfile.Next() = 0;

        DemandInvtProfile.CopyFilters(xDemandInvtProfile);
        SupplyInvtProfile.CopyFilters(xSupplyInvtProfile);

        OnAfterMatchAttributes(SupplyInvtProfile, DemandInvtProfile, TempTrkgReservEntry);
    end;

    local procedure DecreaseQtyForMaxQty(var SupplyInvtProfile: Record "Inventory Profile"; ReduceQty: Decimal)
    begin
        if ReduceQty > 0 then begin
            SupplyInvtProfile."Remaining Quantity (Base)" -= ReduceQty;
            SupplyInvtProfile."Quantity (Base)" -= ReduceQty;
            SupplyInvtProfile.Modify();
        end;
    end;

    local procedure MatchReservationEntries(var FromTrkgReservEntry: Record "Reservation Entry"; var ToTrkgReservEntry: Record "Reservation Entry")
    begin
        if (FromTrkgReservEntry."Reservation Status" = FromTrkgReservEntry."Reservation Status"::Reservation) xor
           (ToTrkgReservEntry."Reservation Status" = ToTrkgReservEntry."Reservation Status"::Reservation)
        then begin
            SwitchTrackingToReservationStatus(FromTrkgReservEntry);
            SwitchTrackingToReservationStatus(ToTrkgReservEntry);
        end;
    end;

    local procedure SwitchTrackingToReservationStatus(var ReservEntry: Record "Reservation Entry")
    begin
        if ReservEntry."Reservation Status" = ReservEntry."Reservation Status"::Tracking then
            ReservEntry."Reservation Status" := ReservEntry."Reservation Status"::Reservation;
    end;

    local procedure PlanItem(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; PlanningStartDate: Date; ToDate: Date; RespectPlanningParm: Boolean)
    var
        TempReminderInvtProfile: Record "Inventory Profile" temporary;
        PlanningGetParameters: Codeunit "Planning-Get Parameters";
        LatestBucketStartDate: Date;
        LastProjectedInventory: Decimal;
        LastAvailableInventory: Decimal;
        SupplyWithinLeadtime: Decimal;
        DemandExists: Boolean;
        SupplyExists: Boolean;
        PlanThisSKU: Boolean;
        ROPHasBeenCrossed: Boolean;
        NewSupplyHasTakenOver: Boolean;
        WeAreSureThatDatesMatch: Boolean;
        IsReorderPointPlanning: Boolean;
        NeedOfPublishSurplus: Boolean;
        IsHandled: Boolean;
        DemandForAdditionalProfile: Boolean;
        ProcessSupplyBeforeStartDate: Boolean;
        DoUpdatePriorities, DoInsertInsertSupplyForEmergencyOrder, DoCheckSupplyWithinLeadtime : Boolean;
    begin
        ReqLine.Reset();
        ReqLine.SetRange("Worksheet Template Name", CurrTemplateName);
        ReqLine.SetRange("Journal Batch Name", CurrWorksheetName);
        ReqLine.LockTable();
        if ReqLine.FindLast() then;

        if PlanningResiliency then
            ReqLine.SetResiliencyOn(CurrTemplateName, CurrWorksheetName, TempSKU."Item No.");

        PlanItemSetInvtProfileFilters(DemandInvtProfile, SupplyInvtProfile);

        TempReminderInvtProfile.SetCurrentKey("Item No.", "Variant Code", "Location Code", "Due Date");

        ExceedROPqty := 0.000000001;

        UpdateTempSKUTransferLevels();

        TempSKU.SetCurrentKey("Item No.", "Transfer-Level Code");
        OnPlanItemOnBeforeTempSKUFind(TempSKU, PlanningStartDate);
        if TempSKU.Find('-') then
            repeat
                IsReorderPointPlanning := IsSKUSetUpForReorderPointPlanning(TempSKU);
                OnPlanItemAfterCalcIsReorderPointPlanning(TempSKU, IsReorderPointPlanning, ReqLine, PlanningTransparency, PlanningResiliency, CurrTemplateName, CurrWorksheetName, PlanningStartDate);

                BucketSize := TempSKU."Time Bucket";
                // Minimum bucket size is 1 day:
                if CalcDate(BucketSize) <= Today then
                    Evaluate(BucketSize, '<1D>');
                BucketSizeInDays := CalcDate(BucketSize) - Today;

                FilterDemandSupplyRelatedToSKU(DemandInvtProfile);
                FilterDemandSupplyRelatedToSKU(SupplyInvtProfile);

                DampenersDays := PlanningGetParameters.CalcDampenerDays(TempSKU);
                DampenerQty := PlanningGetParameters.CalcDampenerQty(TempSKU);
                OverflowLevel := PlanningGetParameters.CalcOverflowLevel(TempSKU);

                if not TempSKU."Include Inventory" then
                    RemoveOrdinaryInventory(SupplyInvtProfile);

                DoUpdatePriorities := true;
                OnPlanItemOnBeforeInsertSafetyStockDemands(DemandInvtProfile, TempSKU, DoUpdatePriorities);
                InsertSafetyStockDemands(DemandInvtProfile, PlanningStartDate);
                if DoUpdatePriorities then
                    UpdatePriorities(SupplyInvtProfile, IsReorderPointPlanning, ToDate);

                DemandExists := DemandInvtProfile.FindSet();
                DemandForAdditionalProfile := DemandForAdditionalLine(DemandInvtProfile, SupplyInvtProfile);
                SupplyExists := SupplyInvtProfile.FindSet();
                LatestBucketStartDate := PlanningStartDate;
                OnPlanItemOnAfterInitLatestBucketStartDate(LatestBucketStartDate);
                LastProjectedInventory := 0;
                LastAvailableInventory := 0;
                PlanThisSKU := CheckPlanSKU(TempSKU, DemandExists, SupplyExists, IsReorderPointPlanning);

                if PlanThisSKU then begin
                    PrepareDemand(DemandInvtProfile, IsReorderPointPlanning, ToDate);
                    PlanThisSKU :=
                      not (DemandMatchedSupply(DemandInvtProfile, SupplyInvtProfile, TempSKU) and
                           DemandMatchedSupply(SupplyInvtProfile, DemandInvtProfile, TempSKU));
                    OnPlanItemOnAfterCheckDemandMatchedSupplyPlanThisSKU(DemandInvtProfile, SupplyInvtProfile, PlanThisSKU);
                end;
                if PlanThisSKU then begin
                    // Preliminary clean of tracking
                    if DemandExists or SupplyExists then
                        DeleteTracking(TempSKU, ToDate, SupplyInvtProfile);

                    MatchAttributes(SupplyInvtProfile, DemandInvtProfile, RespectPlanningParm, DemandForAdditionalProfile);

                    // Calculate initial inventory
                    PlanItemCalcInitialInventory(
                      DemandInvtProfile, SupplyInvtProfile, PlanningStartDate, DemandExists, SupplyExists, LastProjectedInventory);

                    OnBeforePrePlanDateDemandProc(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists);
                    while DemandExists do begin
                        IsHandled := false;
                        OnPlanItemOnBeforeSumDemandInvtProfile(DemandInvtProfile, IsHandled, PlanningStartDate, LastProjectedInventory, LastAvailableInventory);
                        if not IsHandled then begin
                            LastProjectedInventory -= DemandInvtProfile."Remaining Quantity (Base)";
                            LastAvailableInventory -= DemandInvtProfile."Untracked Quantity";
                        end;
                        DemandInvtProfile.Modify();
                        DemandExists := DemandInvtProfile.Next() <> 0;
                    end;

                    OnBeforePrePlanDateSupplyProc(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists);
                    while SupplyExists do begin
                        IsHandled := false;
                        OnPlanItemOnBeforeSumSupplyInvtProfile(SupplyInvtProfile, IsHandled, LastProjectedInventory, LastAvailableInventory);
                        if not IsHandled then begin
                            LastProjectedInventory += SupplyInvtProfile."Remaining Quantity (Base)";
                            LastAvailableInventory += SupplyInvtProfile."Untracked Quantity";
                        end;
                        SupplyInvtProfile."Planning Flexibility" := SupplyInvtProfile."Planning Flexibility"::None;
                        OnPlanItemOnBeforeSupplyInvtProfileModify(SupplyInvtProfile);
                        SupplyInvtProfile.Modify();
                        SupplyExists := SupplyInvtProfile.Next() <> 0;
                    end;
                    DoInsertInsertSupplyForEmergencyOrder := LastAvailableInventory < 0;
                    OnAfterPrePlanDateSupplyProc(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists, TempSKU, TempTrkgReservEntry, ReqLine, DoInsertInsertSupplyForEmergencyOrder);

                    // Insert supply for emergency order
                    if DoInsertInsertSupplyForEmergencyOrder then
                        InsertEmergencyOrderSupply(SupplyInvtProfile, DemandInvtProfile, LastAvailableInventory, LastProjectedInventory, PlanningStartDate);

                    if not DemandInvtProfile.IsEmpty() then
                        DemandInvtProfile.ModifyAll("Untracked Quantity", 0);

                    // Initial Safety Stock Warning
                    if LastAvailableInventory < TempSKU."Safety Stock Quantity" then
                        InsertInitialSafetyStockWarningSupply(SupplyInvtProfile, LastAvailableInventory, LastProjectedInventory, PlanningStartDate, RespectPlanningParm, IsReorderPointPlanning);

                    DoCheckSupplyWithinLeadtime := IsReorderPointPlanning;
                    OnPlanItemOnBeforeCheckSupplyWithinLeadtime(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists, TempSKU, TempTrkgReservEntry, ReqLine, DoCheckSupplyWithinLeadtime);

                    if DoCheckSupplyWithinLeadtime then begin
                        SupplyWithinLeadtime :=
                          SumUpProjectedSupply(SupplyInvtProfile, PlanningStartDate, PlanningStartDate + BucketSizeInDays - 1);

                        if LastProjectedInventory + SupplyWithinLeadtime <= TempSKU."Reorder Point" then begin
                            IsHandled := false;
                            OnPlanItemOnBeforeInitSupply(LastProjectedInventory, SupplyWithinLeadtime, TempSKU, IsHandled, PlanningStartDate);
                            if not IsHandled then begin
                                if (TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Maximum Qty.") and DemandForAdditionalProfile then
                                    LastProjectedInventory := 0;
                                InitSupply(SupplyInvtProfile, 0, 0D, 0T);

                                IsHandled := false;
                                OnPlanItemOnBeforeCreateSupplyForward(TempSKU, SupplyInvtProfile, DemandInvtProfile, TempReminderInvtProfile, PlanningStartDate, LastAvailableInventory, LastProjectedInventory, NewSupplyHasTakenOver, IsHandled);
                                if not IsHandled then
                                    CreateSupplyForward(
                                    SupplyInvtProfile, DemandInvtProfile, TempReminderInvtProfile,
                                    PlanningStartDate, LastProjectedInventory, NewSupplyHasTakenOver, DemandInvtProfile."Due Date");

                                NeedOfPublishSurplus := SupplyInvtProfile."Due Date" > ToDate;
                                OnPlanItemOnAfterCreateInitialReorderPointSupply(PlanningStartDate);
                            end;
                        end;
                    end;

                    // Common balancing
                    OnBeforeCommonBalancing(TempSKU, DemandInvtProfile, SupplyInvtProfile, PlanningStartDate, ToDate, NewSupplyHasTakenOver, NeedOfPublishSurplus, FutureSupplyWithinLeadtime, OverflowLevel);
                    DemandInvtProfile.SetRange("Due Date", PlanningStartDate, ToDate);

                    DemandExists := DemandInvtProfile.FindSet();
                    DemandInvtProfile.SetRange("Due Date");

                    SupplyInvtProfile.SetFilter("Untracked Quantity", '>=0');
                    SupplyExists := SupplyInvtProfile.FindSet();

                    ProcessSupplyBeforeStartDate := SupplyExists;
                    while ProcessSupplyBeforeStartDate do begin
                        if (SupplyInvtProfile."Due Date" < PlanningStartDate) and (SupplyInvtProfile."Due Date" > 0D) and (SupplyInvtProfile."Untracked Quantity" = 0) then
                            SupplyExists := SupplyInvtProfile.Next() <> 0;
                        ProcessSupplyBeforeStartDate := SupplyExists and (SupplyInvtProfile."Due Date" < PlanningStartDate) and (SupplyInvtProfile."Due Date" > 0D) and (SupplyInvtProfile."Untracked Quantity" = 0);
                    end;

                    SupplyInvtProfile.SetRange("Untracked Quantity");
                    SupplyInvtProfile.SetRange("Due Date");

                    if not SupplyExists then
                        if not SupplyInvtProfile.IsEmpty() then begin
                            SupplyInvtProfile.SetRange("Due Date", PlanningStartDate, ToDate);
                            SupplyExists := SupplyInvtProfile.FindSet();
                            SupplyInvtProfile.SetRange("Due Date");
                            if NeedOfPublishSurplus and not (DemandExists or SupplyExists) then begin
                                Track(SupplyInvtProfile, DemandInvtProfile, true, false, SupplyInvtProfile.Binding::" ");
                                PlanningTransparency.PublishSurplus(SupplyInvtProfile, TempSKU, ReqLine, TempTrkgReservEntry);
                            end;
                        end;

                    if IsReorderPointPlanning then
                        ChkInitialOverflow(DemandInvtProfile, SupplyInvtProfile,
                          OverflowLevel, LastProjectedInventory, PlanningStartDate, ToDate);

                    CheckSupplyWithSKU(SupplyInvtProfile, TempSKU);

                    LotAccumulationPeriodStartDate := 0D;
                    NextState := NextState::StartOver;
                    OnPlanItemOnBeforePlanThisSKULoop(TempSKU, DemandInvtProfile);
                    while PlanThisSKU do begin
                        OnPlanItemOnBeforePlanThisSKULoopIteration(TempSKU, NextState, DemandInvtProfile, SupplyInvtProfile, SupplyExists, DemandExists, LotAccumulationPeriodStartDate);
                        case NextState of
                            NextState::StartOver:
                                PlanItemNextStateStartOver(
                                  DemandInvtProfile, SupplyInvtProfile, DemandExists, SupplyExists);
                            NextState::MatchDates:
                                PlanItemNextStateMatchDates(
                                  DemandInvtProfile, SupplyInvtProfile, TempReminderInvtProfile, WeAreSureThatDatesMatch, IsReorderPointPlanning,
                                  LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed, NewSupplyHasTakenOver);
                            NextState::MatchQty:
                                PlanItemNextStateMatchQty(
                                  DemandInvtProfile, SupplyInvtProfile, LastProjectedInventory, IsReorderPointPlanning, RespectPlanningParm);
                            NextState::CreateSupply:
                                PlanItemNextStateCreateSupply(
                                  DemandInvtProfile, SupplyInvtProfile, TempReminderInvtProfile, WeAreSureThatDatesMatch, IsReorderPointPlanning,
                                  LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed, NewSupplyHasTakenOver, SupplyExists,
                                  RespectPlanningParm);
                            NextState::ReduceSupply:
                                PlanItemNextStateReduceSupply(
                                  DemandInvtProfile, SupplyInvtProfile, TempReminderInvtProfile, IsReorderPointPlanning,
                                  LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed, NewSupplyHasTakenOver, DemandExists);
                            NextState::CloseDemand:
                                PlanItemNextStateCloseDemand(
                                  DemandInvtProfile, SupplyInvtProfile, TempReminderInvtProfile, IsReorderPointPlanning,
                                  LatestBucketStartDate, DemandExists, SupplyExists, PlanningStartDate);
                            NextState::CloseSupply:
                                PlanItemNextStateCloseSupply(
                                  DemandInvtProfile, SupplyInvtProfile, TempReminderInvtProfile, IsReorderPointPlanning,
                                  LatestBucketStartDate, DemandExists, SupplyExists, ToDate);
                            NextState::CloseLoop:
                                PlanItemNextStateCloseLoop(
                                  DemandInvtProfile, SupplyInvtProfile, TempReminderInvtProfile, IsReorderPointPlanning,
                                  LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed, NewSupplyHasTakenOver, SupplyExists,
                                  ToDate, PlanThisSKU);
                            else
                                Error(Text001, SelectStr(NextState + 1, NextStateTxt));
                        end;
                    end;
                end;
                OnPlanItemOnAfterTempSKULoop(TempSKU, ReqLine);
            until TempSKU.Next() = 0;

        SetAcceptAction(TempSKU."Item No.");
    end;

    local procedure PlanItemCalcInitialInventory(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; PlanningStartDate: Date; var DemandExists: Boolean; var SupplyExists: Boolean; var LastProjectedInventory: Decimal)
    var
        IncrementLastProjectedInventory: Boolean;
    begin
        DemandInvtProfile.SetRange("Due Date", 0D, PlanningStartDate - 1);
        SupplyInvtProfile.SetRange("Due Date", 0D, PlanningStartDate - 1);
        DemandExists := DemandInvtProfile.FindSet();
        SupplyExists := SupplyInvtProfile.FindSet();
        OnBeforePrePlanDateApplicationLoop(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists, LastProjectedInventory);
        while DemandExists and SupplyExists do begin
            IncrementLastProjectedInventory := true;
            OnStartOfPrePlanDateApplicationLoop(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists, IncrementLastProjectedInventory);
            if DemandInvtProfile."Untracked Quantity" > SupplyInvtProfile."Untracked Quantity" then begin
                OnPlanItemCalcInitialInventoryOnBeforeChechkIncrementLastProjectedInventory(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists, IncrementLastProjectedInventory, LastProjectedInventory);
                if IncrementLastProjectedInventory then
                    LastProjectedInventory += SupplyInvtProfile."Remaining Quantity (Base)";
                DemandInvtProfile."Untracked Quantity" -= SupplyInvtProfile."Untracked Quantity";
                FrozenZoneTrack(SupplyInvtProfile, DemandInvtProfile);
                SupplyInvtProfile."Untracked Quantity" := 0;
                SupplyInvtProfile.Modify();
                SupplyExists := SupplyInvtProfile.Next() <> 0;
            end else begin
                if IncrementLastProjectedInventory then
                    LastProjectedInventory -= DemandInvtProfile."Remaining Quantity (Base)";
                SupplyInvtProfile."Untracked Quantity" -= DemandInvtProfile."Untracked Quantity";
                FrozenZoneTrack(DemandInvtProfile, SupplyInvtProfile);
                DemandInvtProfile."Untracked Quantity" := 0;
                DemandInvtProfile.Modify();
                DemandExists := DemandInvtProfile.Next() <> 0;
                if not DemandExists then
                    SupplyInvtProfile.Modify();
            end;
            OnEndOfPrePlanDateApplicationLoop(SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists);
        end;
    end;

    local procedure PlanItemNextStateCloseDemand(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var TempReminderInvtProfile: Record "Inventory Profile" temporary; IsReorderPointPlanning: Boolean; LatestBucketStartDate: Date; var DemandExists: Boolean; var SupplyExists: Boolean; PlanningStartDate: Date)
    begin
        if DemandInvtProfile."Due Date" < PlanningStartDate then
            Error(Text001, DemandInvtProfile.FieldCaption("Due Date"));

        if DemandInvtProfile."Order Relation" = DemandInvtProfile."Order Relation"::"Safety Stock" then begin
            AllocateSafetystock(SupplyInvtProfile, DemandInvtProfile."Untracked Quantity", DemandInvtProfile."Due Date");
            if IsReorderPointPlanning and (SupplyInvtProfile."Due Date" >= LatestBucketStartDate) then
                PostInvChgReminder(TempReminderInvtProfile, SupplyInvtProfile, true);
        end else begin
            if IsReorderPointPlanning then
                PostInvChgReminder(TempReminderInvtProfile, DemandInvtProfile, false);
            if DemandInvtProfile."Untracked Quantity" <> 0 then begin
                SupplyInvtProfile."Untracked Quantity" -= DemandInvtProfile."Untracked Quantity";
                if SupplyInvtProfile."Untracked Quantity" < SupplyInvtProfile."Safety Stock Quantity" then
                    SupplyInvtProfile."Safety Stock Quantity" := SupplyInvtProfile."Untracked Quantity";
                if SupplyInvtProfile."Action Message" <> SupplyInvtProfile."Action Message"::" " then
                    MaintainPlanningLine(
                      SupplyInvtProfile, DemandInvtProfile, PlanningLineStage::"Line Created", ScheduleDirection::Backward);
                SupplyInvtProfile.Modify();
                if IsReorderPointPlanning and (SupplyInvtProfile."Due Date" >= LatestBucketStartDate) then
                    PostInvChgReminder(TempReminderInvtProfile, SupplyInvtProfile, true);
                CheckSupplyAndTrack(DemandInvtProfile, SupplyInvtProfile);
                SurplusType := PlanningTransparency.GetSurplusType(DemandInvtProfile);
                if SurplusType <> SurplusType::None then
                    PlanningTransparency.LogPlanningSurplus(
                      SupplyInvtProfile."Line No.", DemandInvtProfile."Line No.",
                      DemandInvtProfile."Source Type", DemandInvtProfile."Source ID",
                      DemandInvtProfile."Untracked Quantity", SurplusType);
            end;
        end;

        OnPlanItemNextStateCloseDemandOnBeforeDemandInvtProfileDelete(DemandInvtProfile, ReqLine);
        DemandInvtProfile.Delete();

        // If just handled demand was safetystock
        if DemandInvtProfile."Order Relation" = DemandInvtProfile."Order Relation"::"Safety Stock" then
            SupplyExists := SupplyInvtProfile.FindSet(true); // We assume that next profile is NOT safety stock

        DemandExists := DemandInvtProfile.Next() <> 0;
        NextState := NextState::StartOver;

        OnAfterPlanItemNextStateCloseDemand(SupplyInvtProfile, SupplyExists);
    end;

    local procedure PlanItemNextStateCloseLoop(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var TempReminderInvtProfile: Record "Inventory Profile" temporary; IsReorderPointPlanning: Boolean; var LastProjectedInventory: Decimal; var LatestBucketStartDate: Date; var ROPHasBeenCrossed: Boolean; var NewSupplyHasTakenOver: Boolean; var SupplyExists: Boolean; ToDate: Date; var PlanThisSKU: Boolean)
    begin
        if IsReorderPointPlanning then
            MaintainProjectedInventory(
              TempReminderInvtProfile, ToDate, LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed);
        if ROPHasBeenCrossed then begin
            CreateSupplyForward(
              SupplyInvtProfile, DemandInvtProfile, TempReminderInvtProfile,
              LatestBucketStartDate, LastProjectedInventory, NewSupplyHasTakenOver, DemandInvtProfile."Due Date");
            SupplyExists := true;
            NextState := NextState::StartOver;
        end else
            PlanThisSKU := false;
    end;

    local procedure PlanItemNextStateCloseSupply(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var TempReminderInvtProfile: Record "Inventory Profile" temporary; IsReorderPointPlanning: Boolean; LatestBucketStartDate: Date; DemandExists: Boolean; var SupplyExists: Boolean; ToDate: Date)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnPlanItemNextStateCloseSupplyOnBeforeUpdateDemandUntrackedQty(SupplyInvtProfile, DemandInvtProfile, IsHandled);
        if not IsHandled then
            if DemandExists and (SupplyInvtProfile."Untracked Quantity" > 0) then begin
                DemandInvtProfile."Untracked Quantity" -= SupplyInvtProfile."Untracked Quantity";
                DemandInvtProfile.Modify();
            end;

        if DemandExists and
           (DemandInvtProfile."Order Relation" = DemandInvtProfile."Order Relation"::"Safety Stock")
        then begin
            AllocateSafetystock(SupplyInvtProfile, SupplyInvtProfile."Untracked Quantity", DemandInvtProfile."Due Date");
            if IsReorderPointPlanning and (SupplyInvtProfile."Due Date" >= LatestBucketStartDate) then
                PostInvChgReminder(TempReminderInvtProfile, SupplyInvtProfile, true);
        end else begin
            if IsReorderPointPlanning and (SupplyInvtProfile."Due Date" >= LatestBucketStartDate) then
                PostInvChgReminder(TempReminderInvtProfile, SupplyInvtProfile, false);

            if SupplyInvtProfile."Action Message" <> SupplyInvtProfile."Action Message"::" " then
                MaintainPlanningLine(
                  SupplyInvtProfile, DemandInvtProfile, PlanningLineStage::Exploded, ScheduleDirection::Backward)
            else
                SupplyInvtProfile.TestField("Planning Line No.", 0);

            IsHandled := false;
            OnPlanItemNextStateCloseSupplyOnBeforeProcessActionMessageNew(SupplyInvtProfile, DemandInvtProfile, IsHandled);
            if not IsHandled then begin
                if (SupplyInvtProfile."Action Message" = SupplyInvtProfile."Action Message"::New) or
                   (SupplyInvtProfile."Due Date" <= ToDate)
                then
                    if DemandExists then
                        Track(SupplyInvtProfile, DemandInvtProfile, false, false, SupplyInvtProfile.Binding)
                    else
                        Track(SupplyInvtProfile, DemandInvtProfile, true, false, SupplyInvtProfile.Binding::" ");
                SupplyInvtProfile.Delete();
            end;

            // Planning Transparency
            if DemandExists then begin
                SurplusType := PlanningTransparency.GetSurplusType(DemandInvtProfile);
                if SurplusType <> SurplusType::None then
                    PlanningTransparency.LogPlanningSurplus(
                        SupplyInvtProfile."Line No.", DemandInvtProfile."Line No.",
                        DemandInvtProfile."Source Type", DemandInvtProfile."Source ID",
                        SupplyInvtProfile."Untracked Quantity", SurplusType);
            end;
            if SupplyInvtProfile."Planning Line No." <> 0 then begin
                if SupplyInvtProfile."Safety Stock Quantity" > 0 then
                    PlanningTransparency.LogPlanningSurplus(
                        SupplyInvtProfile."Line No.", SupplyInvtProfile."Line No.", 0, '',
                        SupplyInvtProfile."Safety Stock Quantity", SurplusType::SafetyStock);
                if SupplyInvtProfile."Planning Line No." <> ReqLine."Line No." then
                    ReqLine.Get(CurrTemplateName, CurrWorksheetName, SupplyInvtProfile."Planning Line No.");
                PlanningTransparency.PublishSurplus(SupplyInvtProfile, TempSKU, ReqLine, TempTrkgReservEntry);
            end else
                PlanningTransparency.CleanLog(SupplyInvtProfile."Line No.");
        end;
        if TempSKU."Maximum Order Quantity" > 0 then
            CheckSupplyRemQtyAndUntrackQty(SupplyInvtProfile);
        SupplyExists := SupplyInvtProfile.Next() <> 0;
        OnPlanItemNextStateCloseSupplyOnAfterCheckSupplyExist(SupplyInvtProfile, SupplyExists);

        NextState := NextState::StartOver;
    end;

    local procedure PlanItemNextStateCreateSupply(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var TempReminderInvtProfile: Record "Inventory Profile" temporary; var WeAreSureThatDatesMatch: Boolean; IsReorderPointPlanning: Boolean; var LastProjectedInventory: Decimal; var LatestBucketStartDate: Date; var ROPHasBeenCrossed: Boolean; var NewSupplyHasTakenOver: Boolean; var SupplyExists: Boolean; RespectPlanningParm: Boolean)
    var
        NewSupplyDate: Date;
        IsExceptionOrder: Boolean;
    begin
        WeAreSureThatDatesMatch := true; // We assume this is true at this point.....
        if FromLotAccumulationPeriodStartDate(LotAccumulationPeriodStartDate, DemandInvtProfile."Due Date") then
            NewSupplyDate := LotAccumulationPeriodStartDate
        else begin
            NewSupplyDate := DemandInvtProfile."Due Date";
            LotAccumulationPeriodStartDate := 0D;
        end;
        OnPlanItemNextStateCreateSupplyOnAfterCalcNewSupplyDate(NewSupplyDate, TempSKU, SupplyInvtProfile);

        if (NewSupplyDate >= LatestBucketStartDate) and IsReorderPointPlanning then
            MaintainProjectedInventory(
              TempReminderInvtProfile, NewSupplyDate, LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed);
        if ROPHasBeenCrossed then begin
            CreateSupplyForward(SupplyInvtProfile, DemandInvtProfile, TempReminderInvtProfile,
              LatestBucketStartDate, LastProjectedInventory, NewSupplyHasTakenOver, DemandInvtProfile."Due Date");
            if NewSupplyHasTakenOver then begin
                SupplyExists := true;
                WeAreSureThatDatesMatch := false;
                NextState := NextState::MatchDates;
            end;
        end;

        if WeAreSureThatDatesMatch then begin
            IsExceptionOrder := IsReorderPointPlanning;
            CreateSupply(SupplyInvtProfile, DemandInvtProfile,
              LastProjectedInventory +
              QtyFromPendingReminders(TempReminderInvtProfile, DemandInvtProfile."Due Date", LatestBucketStartDate) -
              DemandInvtProfile."Remaining Quantity (Base)",
              IsExceptionOrder, RespectPlanningParm);
            SupplyInvtProfile."Due Date" := NewSupplyDate;
            SupplyInvtProfile."Fixed Date" := SupplyInvtProfile."Due Date"; // We note the latest possible date on the SupplyInvtProfile.
            SupplyExists := true;
            if IsExceptionOrder then begin
                DummyInventoryProfileTrackBuffer."Warning Level" :=
                  DummyInventoryProfileTrackBuffer."Warning Level"::Exception;
                PlanningTransparency.LogWarning(
                  SupplyInvtProfile."Line No.", ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                  StrSubstNo(Text007, DummyInventoryProfileTrackBuffer."Warning Level",
                    TempSKU.FieldCaption("Safety Stock Quantity"), TempSKU."Safety Stock Quantity",
                    DemandInvtProfile."Due Date"));
            end;
            NextState := NextState::MatchQty;
        end;
    end;

    local procedure PlanItemNextStateMatchDates(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var TempReminderInvtProfile: Record "Inventory Profile" temporary; var WeAreSureThatDatesMatch: Boolean; IsReorderPointPlanning: Boolean; var LastProjectedInventory: Decimal; var LatestBucketStartDate: Date; var ROPHasBeenCrossed: Boolean; var NewSupplyHasTakenOver: Boolean)
    var
        OriginalSupplyDate: Date;
        ShouldCalcNewSupplyDate: Boolean;
        NewSupplyDate: Date;
        CanBeRescheduled: Boolean;
        DemandDueDate: Date;
        LimitedHorizon: Boolean;
        IsHandled: Boolean;
    begin
        ShouldCalcNewSupplyDate := true;
        IsHandled := false;
        OnBeforePlanItemNextStateMatchDates(DemandInvtProfile, SupplyInvtProfile, NextState, IsHandled, ShouldCalcNewSupplyDate);
        if IsHandled then
            exit;

        if ShouldCalcNewSupplyDate then
            if FromLotAccumulationPeriodStartDate(LotAccumulationPeriodStartDate, DemandInvtProfile."Due Date") then begin
                NewSupplyDate := LotAccumulationPeriodStartDate;
                SupplyInvtProfile."Fixed Date" := NewSupplyDate;
            end else begin
                NewSupplyDate := SupplyInvtProfile."Due Date";
                LotAccumulationPeriodStartDate := 0D;
            end;

        OnPlanItemNextStateMatchDatesOnAfterCalcNewSupplyDate(NewSupplyDate, TempSKU, SupplyInvtProfile, LotAccumulationPeriodStartDate);
        DemandDueDate := DemandInvtProfile."Due Date";
        if TempSKU."Replenishment System" = TempSKU."Replenishment System"::Purchase then
            DemandDueDate := GetPrevAvailDateFromCompanyCalendar(DemandInvtProfile."Due Date");

        OriginalSupplyDate := SupplyInvtProfile."Due Date";
        WeAreSureThatDatesMatch := false;

        if DemandDueDate < SupplyInvtProfile."Due Date" then begin
            CanBeRescheduled := CheckScheduleIn(SupplyInvtProfile, DemandDueDate, NewSupplyDate, true);
            if CanBeRescheduled then
                WeAreSureThatDatesMatch := true
            else
                NextState := NextState::CreateSupply;
        end else
            if DemandDueDate > SupplyInvtProfile."Due Date" then begin
                LimitedHorizon := true;
                OnPlanItemNextStateMatchDatesOnBeforeCheckScheduleOut(SupplyInvtProfile, LimitedHorizon);
                CanBeRescheduled := CheckScheduleOut(SupplyInvtProfile, DemandDueDate, NewSupplyDate, LimitedHorizon);
                if CanBeRescheduled then
                    WeAreSureThatDatesMatch := not ScheduleAllOutChangesSequence(SupplyInvtProfile, NewSupplyDate)
                else
                    NextState := NextState::ReduceSupply;
            end else begin
                WeAreSureThatDatesMatch := true;
                CanBeRescheduled := SupplyInvtProfile."Planning Flexibility" = SupplyInvtProfile."Planning Flexibility"::Unlimited;
            end;

        if WeAreSureThatDatesMatch and IsReorderPointPlanning then begin
            // Now we know the final position on the timeline of the SupplyInvtProfile.
            MaintainProjectedInventory(
              TempReminderInvtProfile, NewSupplyDate, LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed);
            if ROPHasBeenCrossed then begin
                CreateSupplyForward(SupplyInvtProfile, DemandInvtProfile, TempReminderInvtProfile,
                  LatestBucketStartDate, LastProjectedInventory, NewSupplyHasTakenOver, DemandDueDate);
                if NewSupplyHasTakenOver then begin
                    WeAreSureThatDatesMatch := false;
                    NextState := NextState::MatchDates;
                end;
            end;
        end;

        if WeAreSureThatDatesMatch then begin
            if CanBeRescheduled and (NewSupplyDate <> OriginalSupplyDate) then begin
                Reschedule(SupplyInvtProfile, NewSupplyDate, 0T);
                SupplyInvtProfile.TestField("Due Date", NewSupplyDate);
            end;
            SupplyInvtProfile."Fixed Date" := SupplyInvtProfile."Due Date"; // We note the latest possible date on the SupplyInvtProfile.
            NextState := NextState::MatchQty;
        end;
    end;

    local procedure PlanItemNextStateMatchQty(var DemandInventoryProfile: Record "Inventory Profile"; var SupplyInventoryProfile: Record "Inventory Profile"; var LastProjectedInventory: Decimal; IsReorderPointPlanning: Boolean; RespectPlanningParm: Boolean)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforePlanItemNextStateMatchQty(SupplyInventoryProfile, DemandInventoryProfile, NextState, IsHandled);
        if IsHandled then
            exit;

        case true of
            SupplyInventoryProfile."Untracked Quantity" >= DemandInventoryProfile."Untracked Quantity":
                NextState := NextState::CloseDemand;
            ShallSupplyBeClosed(SupplyInventoryProfile, DemandInventoryProfile."Due Date", IsReorderPointPlanning):
                NextState := NextState::CloseSupply;
            IncreaseQtyToMeetDemand(SupplyInventoryProfile, DemandInventoryProfile, true, RespectPlanningParm, true):
                begin
                    NextState := NextState::CloseDemand;
                    // initial Safety Stock can be changed to normal, if we can increase qty for normal demand
                    if (SupplyInventoryProfile."Order Relation" = SupplyInventoryProfile."Order Relation"::"Safety Stock") and
                       (DemandInventoryProfile."Order Relation" = DemandInventoryProfile."Order Relation"::Normal)
                    then begin
                        SupplyInventoryProfile."Order Relation" := SupplyInventoryProfile."Order Relation"::Normal;
                        LastProjectedInventory -= TempSKU."Safety Stock Quantity";
                    end;
                end;
            else begin
                NextState := NextState::CloseSupply;
                if TempSKU."Maximum Order Quantity" > 0 then
                    LotAccumulationPeriodStartDate := SupplyInventoryProfile."Due Date";
            end;
        end;
    end;

    local procedure PlanItemNextStateReduceSupply(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var TempReminderInvtProfile: Record "Inventory Profile" temporary; IsReorderPointPlanning: Boolean; var LastProjectedInventory: Decimal; var LatestBucketStartDate: Date; var ROPHasBeenCrossed: Boolean; var NewSupplyHasTakenOver: Boolean; DemandExists: Boolean)
    begin
        if IsReorderPointPlanning and (SupplyInvtProfile."Due Date" >= LatestBucketStartDate) then
            MaintainProjectedInventory(
              TempReminderInvtProfile, SupplyInvtProfile."Due Date", LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed);
        NewSupplyHasTakenOver := false;
        if ROPHasBeenCrossed then begin
            CreateSupplyForward(
              SupplyInvtProfile, DemandInvtProfile, TempReminderInvtProfile,
              LatestBucketStartDate, LastProjectedInventory, NewSupplyHasTakenOver, SupplyInvtProfile."Due Date");
            if NewSupplyHasTakenOver then
                if DemandExists then
                    NextState := NextState::MatchDates
                else
                    NextState := NextState::CloseSupply;
        end;

        if not NewSupplyHasTakenOver then
            if DecreaseQty(SupplyInvtProfile, SupplyInvtProfile."Untracked Quantity", true) then
                NextState := NextState::CloseSupply
            else begin
                SupplyInvtProfile."Max. Quantity" := SupplyInvtProfile."Remaining Quantity (Base)";
                if DemandExists then
                    NextState := NextState::MatchQty
                else
                    NextState := NextState::CloseSupply;
            end;
    end;

    local procedure PlanItemNextStateStartOver(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; var DemandExists: Boolean; var SupplyExists: Boolean)
    var
        IsHandled: Boolean;
    begin
        if DemandExists and (DemandInvtProfile."Source Type" = Database::"Transfer Line") then
            while CancelTransfer(SupplyInvtProfile, DemandInvtProfile, DemandExists) do
                DemandExists := DemandInvtProfile.Next() <> 0;

        IsHandled := false;
        OnBeforePlanStepSettingOnStartOver(
          SupplyInvtProfile, DemandInvtProfile, SupplyExists, DemandExists, NextState, IsHandled);
        if not IsHandled then
            if DemandExists then
                if DemandInvtProfile."Untracked Quantity" = 0 then
                    NextState := NextState::CloseDemand
                else
                    if SupplyExists then
                        NextState := NextState::MatchDates
                    else
                        NextState := NextState::CreateSupply
            else
                if SupplyExists then
                    NextState := NextState::ReduceSupply
                else
                    NextState := NextState::CloseLoop;

        OnAfterPlanItemNextStateStartOver(SupplyInvtProfile, TempSKU);
    end;

    local procedure PlanItemSetInvtProfileFilters(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile")
    var
        IsHandled: Boolean;
    begin
        DemandInvtProfile.Reset();
        SupplyInvtProfile.Reset();
        DemandInvtProfile.SetRange(IsSupply, false);
        SupplyInvtProfile.SetRange(IsSupply, true);

        IsHandled := false;
        OnPlanItemSetInvtProfileFiltersOnBeforeSetCurrentKeys(SupplyInvtProfile, DemandInvtProfile, IsHandled);
        if not IsHandled then begin
            DemandInvtProfile.SetCurrentKey("Item No.", "Variant Code", "Location Code", "Due Date", "Attribute Priority", "Order Priority");
            SupplyInvtProfile.SetCurrentKey("Item No.", "Variant Code", "Location Code", "Due Date", "Attribute Priority", "Order Priority");
        end;

        SupplyInvtProfile.SetRange("Drop Shipment", false);
        SupplyInvtProfile.SetRange("Special Order", false);
        DemandInvtProfile.SetRange("Drop Shipment", false);
        DemandInvtProfile.SetRange("Special Order", false);

        OnAfterPlanItemSetInvtProfileFilters(DemandInvtProfile, SupplyInvtProfile);
    end;

    local procedure FilterDemandSupplyRelatedToSKU(var InventoryProfile: Record "Inventory Profile")
    begin
        InventoryProfile.SetRange("Item No.", TempSKU."Item No.");
        InventoryProfile.SetRange("Variant Code", TempSKU."Variant Code");
        InventoryProfile.SetRange("Location Code", TempSKU."Location Code");
        OnAfterFilterDemandSupplyRelatedToSKU(InventoryProfile, TempSKU);
    end;

    procedure ScheduleForward(var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; StartingDate: Date)
    begin
        SupplyInvtProfile."Starting Date" := StartingDate;
        MaintainPlanningLine(SupplyInvtProfile, DemandInvtProfile, PlanningLineStage::"Routing Created", ScheduleDirection::Forward);
        if (SupplyInvtProfile."Fixed Date" > 0D) and
           (SupplyInvtProfile."Fixed Date" < SupplyInvtProfile."Due Date")
        then
            SupplyInvtProfile."Due Date" := SupplyInvtProfile."Fixed Date"
        else
            SupplyInvtProfile."Fixed Date" := SupplyInvtProfile."Due Date";
    end;

    local procedure IncreaseQtyToMeetDemand(var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; LimitedHorizon: Boolean; RespectPlanningParm: Boolean; CheckSourceType: Boolean) Result: Boolean
    var
        TotalDemandedQty: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIncreaseQtyToMeetDemand(SupplyInvtProfile, DemandInvtProfile, CheckSourceType, Result, IsHandled, TempSKU);
        if IsHandled then
            exit(Result);

        if SupplyInvtProfile."Planning Flexibility" <> SupplyInvtProfile."Planning Flexibility"::Unlimited then
            exit(false);

        if CheckSourceType then
            if ((DemandInvtProfile."Source Type" = Database::"Planning Component") and
                (SupplyInvtProfile."Source Type" = 5406) or // Database::"Prod. Order Line"
                (DemandInvtProfile."Source Type" = Database::"Requisition Line")) and
               (DemandInvtProfile.Binding = DemandInvtProfile.Binding::"Order-to-Order")
            then
                exit(false);

        if (SupplyInvtProfile."Max. Quantity" > 0) or
           (SupplyInvtProfile."Action Message" = SupplyInvtProfile."Action Message"::Cancel)
        then
            if SupplyInvtProfile."Max. Quantity" <= SupplyInvtProfile."Remaining Quantity (Base)" then
                exit(false);

        if LimitedHorizon then
            if not AllowLotAccumulation(SupplyInvtProfile, DemandInvtProfile."Due Date") then
                exit(false);

        TotalDemandedQty := DemandInvtProfile."Untracked Quantity";
        IncreaseQty(
          SupplyInvtProfile, DemandInvtProfile."Untracked Quantity" - SupplyInvtProfile."Untracked Quantity", RespectPlanningParm);
        exit(TotalDemandedQty <= SupplyInvtProfile."Untracked Quantity");
    end;

    local procedure IncreaseQty(var SupplyInvtProfile: Record "Inventory Profile"; NeededQty: Decimal; RespectPlanningParm: Boolean)
    var
        TempQty: Decimal;
    begin
        OnBeforeIncreaseQty(SupplyInvtProfile, NeededQty, TempSKU);

        TempQty := SupplyInvtProfile."Remaining Quantity (Base)";

        if not SupplyInvtProfile."Is Exception Order" or RespectPlanningParm then
            SupplyInvtProfile."Remaining Quantity (Base)" += NeededQty +
              AdjustReorderQty(
                SupplyInvtProfile."Remaining Quantity (Base)" + NeededQty, TempSKU, SupplyInvtProfile."Line No.",
                SupplyInvtProfile."Min. Quantity")
        else
            SupplyInvtProfile."Remaining Quantity (Base)" += NeededQty;

        if TempSKU."Maximum Order Quantity" > 0 then
            if SupplyInvtProfile."Remaining Quantity (Base)" > TempSKU."Maximum Order Quantity" then
                SupplyInvtProfile."Remaining Quantity (Base)" := TempSKU."Maximum Order Quantity";
        if (SupplyInvtProfile."Action Message" <> SupplyInvtProfile."Action Message"::New) and
           (SupplyInvtProfile."Remaining Quantity (Base)" <> TempQty)
        then begin
            if SupplyInvtProfile."Original Quantity" = 0 then
                SupplyInvtProfile."Original Quantity" := SupplyInvtProfile.Quantity;
            if SupplyInvtProfile."Original Due Date" = 0D then
                SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::"Change Qty."
            else
                SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::"Resched. & Chg. Qty.";
        end;

        SupplyInvtProfile."Untracked Quantity" :=
          SupplyInvtProfile."Untracked Quantity" +
          SupplyInvtProfile."Remaining Quantity (Base)" -
          TempQty;

        SupplyInvtProfile."Quantity (Base)" :=
          SupplyInvtProfile."Quantity (Base)" +
          SupplyInvtProfile."Remaining Quantity (Base)" -
          TempQty;
        SupplyInvtProfile.Modify();
    end;

    local procedure InsertEmergencyOrderSupply(var SupplyInvtProfile: Record "Inventory Profile"; var DemandInvtProfile: Record "Inventory Profile"; var LastAvailableInventory: Decimal; var LastProjectedInventory: Decimal; PlanningStartDate: Date)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertEmergencyOrderSupply(SupplyInvtProfile, DemandInvtProfile, IsHandled, PlanningStartDate);
        if IsHandled then
            exit;

        InitSupply(SupplyInvtProfile, -LastAvailableInventory, PlanningStartDate - 1, 0T);
        OnInsertEmergencyOrderSupplyOnAfterInitSupply(SupplyInvtProfile, DemandInvtProfile);
        SupplyInvtProfile."Planning Flexibility" := SupplyInvtProfile."Planning Flexibility"::None;
        SupplyInvtProfile.Insert();
        MaintainPlanningLine(SupplyInvtProfile, DemandInvtProfile, PlanningLineStage::Exploded, ScheduleDirection::Backward);
        Track(SupplyInvtProfile, DemandInvtProfile, true, false, SupplyInvtProfile.Binding::" ");

        DemandInvtProfile.SetFilter("Untracked Quantity", '<>0');
        if DemandInvtProfile.FindFirst() then
            Track(DemandInvtProfile, SupplyInvtProfile, true, false, Enum::"Reservation Binding"::" ");
        DemandInvtProfile.SetRange("Untracked Quantity");

        LastProjectedInventory += SupplyInvtProfile."Remaining Quantity (Base)";
        LastAvailableInventory += SupplyInvtProfile."Untracked Quantity";
        PlanningTransparency.LogPlanningSurplus(
            SupplyInvtProfile."Line No.", SupplyInvtProfile."Line No.", 0, '',
            SupplyInvtProfile."Untracked Quantity", SurplusType::EmergencyOrder);
        SupplyInvtProfile."Untracked Quantity" := 0;
        if SupplyInvtProfile."Planning Line No." <> ReqLine."Line No." then
            ReqLine.Get(CurrTemplateName, CurrWorksheetName, SupplyInvtProfile."Planning Line No.");
        PlanningTransparency.PublishSurplus(SupplyInvtProfile, TempSKU, ReqLine, TempTrkgReservEntry);
        DummyInventoryProfileTrackBuffer."Warning Level" := DummyInventoryProfileTrackBuffer."Warning Level"::Emergency;
        PlanningTransparency.LogWarning(
            0, ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
            StrSubstNo(
            Text006, DummyInventoryProfileTrackBuffer."Warning Level", -SupplyInvtProfile."Remaining Quantity (Base)",
            PlanningStartDate));
        SupplyInvtProfile.Delete();
        OnAfterInsertEmergencyOrderSupply(SupplyInvtProfile, DemandInvtProfile, PlanningStartDate);
    end;

    procedure DecreaseQty(var SupplyInvtProfile: Record "Inventory Profile"; ReduceQty: Decimal; RespectPlanningParm: Boolean): Boolean
    var
        TempQty: Decimal;
        NewRemainingQty: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeDecreaseQty(SupplyInvtProfile, ReduceQty, TempSKU, IsHandled);
        if IsHandled then
            exit;

        if not CanDecreaseSupply(SupplyInvtProfile, ReduceQty) then begin
            if (ReduceQty <= DampenerQty) and (SupplyInvtProfile."Planning Level Code" = 0) then
                PlanningTransparency.LogPlanningSurplus(
                  SupplyInvtProfile."Line No.", 0,
                  99000765, SupplyInvtProfile."Source ID", // Database::"Manufacturing Setup"
                  DampenerQty, SurplusType::DampenerQty);
            exit(false);
        end;

        if ReduceQty > 0 then begin
            TempQty := SupplyInvtProfile."Remaining Quantity (Base)";

            if RespectPlanningParm then begin
                NewRemainingQty :=
                    SupplyInvtProfile."Remaining Quantity (Base)" - ReduceQty +
                    AdjustReorderQty(
                        SupplyInvtProfile."Remaining Quantity (Base)" - ReduceQty, TempSKU, SupplyInvtProfile."Line No.",
                        SupplyInvtProfile."Min. Quantity");

                if (SupplyInvtProfile."Action Message" <> SupplyInvtProfile."Action Message"::New) and (TempQty <> NewRemainingQty) then
                    if (Abs(TempQty - NewRemainingQty) < DampenerQty) and (SupplyInvtProfile."Planning Level Code" = 0) then
                        exit(false);

                SupplyInvtProfile."Remaining Quantity (Base)" := NewRemainingQty;
            end else
                SupplyInvtProfile."Remaining Quantity (Base)" -= ReduceQty;

            if TempSKU."Maximum Order Quantity" > 0 then
                if SupplyInvtProfile."Remaining Quantity (Base)" > TempSKU."Maximum Order Quantity" then
                    SupplyInvtProfile."Remaining Quantity (Base)" := TempSKU."Maximum Order Quantity";
            if (SupplyInvtProfile."Action Message" <> SupplyInvtProfile."Action Message"::New) and
               (TempQty <> SupplyInvtProfile."Remaining Quantity (Base)")
            then begin
                if SupplyInvtProfile."Original Quantity" = 0 then
                    SupplyInvtProfile."Original Quantity" := SupplyInvtProfile.Quantity;
                if SupplyInvtProfile."Remaining Quantity (Base)" = 0 then
                    SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::Cancel
                else
                    if SupplyInvtProfile."Original Due Date" = 0D then
                        SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::"Change Qty."
                    else
                        SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::"Resched. & Chg. Qty.";
            end;

            SupplyInvtProfile."Untracked Quantity" :=
              SupplyInvtProfile."Untracked Quantity" -
              TempQty +
              SupplyInvtProfile."Remaining Quantity (Base)";

            SupplyInvtProfile."Quantity (Base)" :=
              SupplyInvtProfile."Quantity (Base)" -
              TempQty +
              SupplyInvtProfile."Remaining Quantity (Base)";

            SupplyInvtProfile.Modify();
        end;

        exit(SupplyInvtProfile."Untracked Quantity" = 0);
    end;

    procedure CanDecreaseSupply(InventoryProfileSupply: Record "Inventory Profile"; var ReduceQty: Decimal): Boolean
    var
        TrackedQty: Decimal;
        IsHandled: Boolean;
        Result: Boolean;
    begin
        if ReduceQty > InventoryProfileSupply."Untracked Quantity" then
            ReduceQty := InventoryProfileSupply."Untracked Quantity";
        if InventoryProfileSupply."Min. Quantity" > InventoryProfileSupply."Remaining Quantity (Base)" - ReduceQty then
            ReduceQty := InventoryProfileSupply."Remaining Quantity (Base)" - InventoryProfileSupply."Min. Quantity";

        // Ensure leaving enough untracked qty. to cover the safety stock
        TrackedQty := InventoryProfileSupply."Remaining Quantity (Base)" - InventoryProfileSupply."Untracked Quantity";
        if TrackedQty + InventoryProfileSupply."Safety Stock Quantity" > InventoryProfileSupply."Remaining Quantity (Base)" - ReduceQty then
            ReduceQty := InventoryProfileSupply."Remaining Quantity (Base)" - (TrackedQty + InventoryProfileSupply."Safety Stock Quantity");

        // Planning Transparency
        if (ReduceQty <= DampenerQty) and (InventoryProfileSupply."Planning Level Code" = 0) then
            exit(false);

        if (InventoryProfileSupply."Planning Flexibility" = InventoryProfileSupply."Planning Flexibility"::None) or
           ((ReduceQty <= DampenerQty) and
            (InventoryProfileSupply."Planning Level Code" = 0))
        then
            exit(false);

        IsHandled := false;
        OnAfterCanDecreaseSupply(InventoryProfileSupply, ReduceQty, DampenerQty, Result, IsHandled);
        if IsHandled then
            exit(Result);

        exit(true);
    end;

    local procedure CreateSupply(var SupplyInvtProfile: Record "Inventory Profile"; var DemandInvtProfile: Record "Inventory Profile"; ProjectedInventory: Decimal; IsExceptionOrder: Boolean; RespectPlanningParm: Boolean)
    var
        ReorderQty: Decimal;
    begin
        OnBeforeCreateSupply(SupplyInvtProfile, DemandInvtProfile);

        InitSupply(SupplyInvtProfile, 0, DemandInvtProfile."Due Date", DemandInvtProfile."Due Time");
        OnCreateSupplyOnAfterInitSupply(SupplyInvtProfile, DemandInvtProfile);

        ReorderQty := DemandInvtProfile."Untracked Quantity";
        if (not IsExceptionOrder) or RespectPlanningParm then begin
            if not RespectPlanningParm then
                ReorderQty := CalcReorderQty(ReorderQty, ProjectedInventory, SupplyInvtProfile."Line No.")
            else
                if IsExceptionOrder then begin
                    if DemandInvtProfile."Order Relation" =
                       DemandInvtProfile."Order Relation"::"Safety Stock"
                    then // Compensate for Safety Stock offset
                        ProjectedInventory := ProjectedInventory + DemandInvtProfile."Remaining Quantity (Base)";
                    ReorderQty := CalcReorderQty(ReorderQty, ProjectedInventory, SupplyInvtProfile."Line No.");
                    if ReorderQty < -ProjectedInventory then
                        if ProjectedInventory mod TempSKU."Reorder Quantity" = 0 then
                            ReorderQty :=
                              Round(-ProjectedInventory / TempSKU."Reorder Quantity", 1, '>') *
                              TempSKU."Reorder Quantity"
                        else
                            ReorderQty :=
                              Round(-ProjectedInventory / TempSKU."Reorder Quantity" + ExceedROPqty, 1, '>') *
                              TempSKU."Reorder Quantity";
                end;

            if IsReorderQtyToAdjust(TempSKU) then
                ReorderQty += AdjustReorderQty(ReorderQty, TempSKU, SupplyInvtProfile."Line No.", SupplyInvtProfile."Min. Quantity");
            SupplyInvtProfile."Max. Quantity" := TempSKU."Maximum Order Quantity";
        end;
        UpdateQty(SupplyInvtProfile, ReorderQty);
        if TempSKU."Maximum Order Quantity" > 0 then begin
            if SupplyInvtProfile."Remaining Quantity (Base)" > TempSKU."Maximum Order Quantity" then
                SupplyInvtProfile."Remaining Quantity (Base)" := TempSKU."Maximum Order Quantity";
            if SupplyInvtProfile."Untracked Quantity" >= TempSKU."Maximum Order Quantity" then
                SupplyInvtProfile."Untracked Quantity" :=
                  SupplyInvtProfile."Untracked Quantity" -
                  ReorderQty +
                  SupplyInvtProfile."Remaining Quantity (Base)";
        end;
        SupplyInvtProfile."Min. Quantity" := SupplyInvtProfile."Remaining Quantity (Base)";
        TransferAttributes(SupplyInvtProfile, DemandInvtProfile);
        SupplyInvtProfile."Is Exception Order" := IsExceptionOrder;
        OnCreateSupplyOnBeforeSupplyInvtProfileInsert(SupplyInvtProfile, TempSKU);
        SupplyInvtProfile.Insert();
        if (not IsExceptionOrder or RespectPlanningParm) and (OverflowLevel > 0) then
            // the new supply might cause overflow in inventory since
            // it wasn't considered when Overflow was calculated
            CheckNewOverflow(SupplyInvtProfile, ProjectedInventory + ReorderQty, ReorderQty, SupplyInvtProfile."Due Date");
    end;

    procedure CreateDemand(var DemandInvtProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit"; NeededQuantity: Decimal; NeededDueDate: Date; OrderRelation: Option Normal,"Safety Stock","Reorder Point")
    begin
        DemandInvtProfile.Init();
        DemandInvtProfile."Line No." := GetNextLineNo();
        DemandInvtProfile."Item No." := SKU."Item No.";
        DemandInvtProfile."Variant Code" := SKU."Variant Code";
        DemandInvtProfile."Location Code" := SKU."Location Code";
        DemandInvtProfile."Quantity (Base)" := NeededQuantity;
        DemandInvtProfile."Remaining Quantity (Base)" := NeededQuantity;
        DemandInvtProfile.IsSupply := false;
        DemandInvtProfile."Order Relation" := OrderRelation;
        DemandInvtProfile."Source Type" := 0;
        DemandInvtProfile."Untracked Quantity" := NeededQuantity;
        DemandInvtProfile."Due Date" := NeededDueDate;
        DemandInvtProfile."Planning Flexibility" := DemandInvtProfile."Planning Flexibility"::None;
        OnBeforeDemandInvtProfileInsert(DemandInvtProfile, SKU);
        DemandInvtProfile.Insert();
    end;

    local procedure Track(FromProfile: Record "Inventory Profile"; ToProfile: Record "Inventory Profile"; IsSurplus: Boolean; IssueActionMessage: Boolean; Binding: Enum "Reservation Binding")
    var
        TrkgReservEntryArray: array[6] of Record "Reservation Entry";
        SplitState: Option NoSplit,SplitFromProfile,SplitToProfile,Cancel;
        SplitQty: Decimal;
        SplitQty2: Decimal;
        TrackQty: Decimal;
        DecreaseSupply: Boolean;
    begin
        OnBeforeTrack(FromProfile, ToProfile, IsSurplus, IssueActionMessage, Binding);
        DecreaseSupply :=
          FromProfile.IsSupply and
          (FromProfile."Action Message" in [FromProfile."Action Message"::"Change Qty.",
                                            FromProfile."Action Message"::"Resched. & Chg. Qty."]) and
          (FromProfile."Quantity (Base)" < FromProfile."Original Quantity" * FromProfile."Qty. per Unit of Measure");

        if ((FromProfile."Action Message" = FromProfile."Action Message"::Cancel) and
            (FromProfile."Untracked Quantity" = 0)) or (DecreaseSupply and IsSurplus)
        then begin
            IsSurplus := false;
            if DecreaseSupply then
                FromProfile."Untracked Quantity" :=
                  FromProfile."Original Quantity" * FromProfile."Qty. per Unit of Measure" - FromProfile."Quantity (Base)"
            else
                if FromProfile.IsSupply then
                    FromProfile."Untracked Quantity" := FromProfile."Remaining Quantity" * FromProfile."Qty. per Unit of Measure"
                else
                    FromProfile."Untracked Quantity" := -FromProfile."Remaining Quantity" * FromProfile."Qty. per Unit of Measure";
            FromProfile.TransferToTrackingEntry(TrkgReservEntryArray[1], false);
            TrkgReservEntryArray[3] := TrkgReservEntryArray[1];
            ReqLine.TransferToTrackingEntry(TrkgReservEntryArray[3], true);
            if FromProfile.IsSupply then
                TrkgReservEntryArray[3]."Shipment Date" := FromProfile."Due Date"
            else
                TrkgReservEntryArray[3]."Expected Receipt Date" := FromProfile."Due Date";
            SplitState := SplitState::Cancel;
        end else begin
            TrackQty := FromProfile."Untracked Quantity";

            if FromProfile.IsSupply then begin
                if not ((FromProfile."Original Quantity" * FromProfile."Qty. per Unit of Measure" > FromProfile."Quantity (Base)") or
                        (FromProfile."Untracked Quantity" > 0))
                then
                    exit;

                SplitQty := FromProfile."Original Quantity" * FromProfile."Qty. per Unit of Measure" +
                  FromProfile."Untracked Quantity" - FromProfile."Quantity (Base)";

                case FromProfile."Action Message" of
                    FromProfile."Action Message"::"Resched. & Chg. Qty.",
                    FromProfile."Action Message"::Reschedule,
                    FromProfile."Action Message"::New,
                    FromProfile."Action Message"::"Change Qty.":
                        begin
                            if (SplitQty > 0) and (SplitQty < TrackQty) then begin
                                SplitState := SplitState::SplitFromProfile;
                                FromProfile.TransferToTrackingEntry(TrkgReservEntryArray[1],
                                  (FromProfile."Action Message" = FromProfile."Action Message"::Reschedule) or
                                  (FromProfile."Action Message" = FromProfile."Action Message"::"Resched. & Chg. Qty."));
                                TrkgReservEntryArray[3] := TrkgReservEntryArray[1];
                                ReqLine.TransferToTrackingEntry(TrkgReservEntryArray[3], true);
                                if IsSurplus then begin
                                    TrkgReservEntryArray[3]."Quantity (Base)" := TrackQty - SplitQty;
                                    TrkgReservEntryArray[1]."Quantity (Base)" := SplitQty;
                                end else begin
                                    TrkgReservEntryArray[1]."Quantity (Base)" := TrackQty - SplitQty;
                                    TrkgReservEntryArray[3]."Quantity (Base)" := SplitQty;
                                end;
                                TrkgReservEntryArray[1].Quantity :=
                                  Round(
                                    TrkgReservEntryArray[1]."Quantity (Base)" / TrkgReservEntryArray[1]."Qty. per Unit of Measure",
                                    UOMMgt.QtyRndPrecision());
                                TrkgReservEntryArray[3].Quantity :=
                                  Round(
                                    TrkgReservEntryArray[3]."Quantity (Base)" / TrkgReservEntryArray[3]."Qty. per Unit of Measure",
                                    UOMMgt.QtyRndPrecision());
                            end else begin
                                FromProfile.TransferToTrackingEntry(TrkgReservEntryArray[1], false);
                                ReqLine.TransferToTrackingEntry(TrkgReservEntryArray[1], true);
                            end;
                            if IsSurplus then begin
                                TrkgReservEntryArray[4] := TrkgReservEntryArray[1];
                                ReqLine.TransferToTrackingEntry(TrkgReservEntryArray[4], true);
                                TrkgReservEntryArray[4]."Shipment Date" := ReqLine."Due Date";
                            end;
                            ToProfile.TransferToTrackingEntry(TrkgReservEntryArray[2], false);
                        end;
                    else
                        FromProfile.TransferToTrackingEntry(TrkgReservEntryArray[1], false);
                        ToProfile.TransferToTrackingEntry(TrkgReservEntryArray[2],
                          (ToProfile."Source Type" = Database::"Planning Component") and
                          (ToProfile."Primary Order Status" > 1)); // Firm Planned, Released Prod.Order
                end;
            end else begin
                ToProfile.TestField(IsSupply, true);
                SplitQty := ToProfile."Remaining Quantity" * ToProfile."Qty. per Unit of Measure" + ToProfile."Untracked Quantity" +
                  FromProfile."Untracked Quantity" - ToProfile."Quantity (Base)";

                if FromProfile."Source Type" = Database::"Planning Component" then begin
                    SplitQty2 := FromProfile."Original Quantity" * FromProfile."Qty. per Unit of Measure";
                    if FromProfile."Untracked Quantity" < SplitQty2 then
                        SplitQty2 := FromProfile."Untracked Quantity";
                    if SplitQty2 > SplitQty then
                        SplitQty2 := SplitQty;
                end;

                if SplitQty2 > 0 then begin
                    ToProfile.TransferToTrackingEntry(TrkgReservEntryArray[5], false);
                    if ToProfile."Action Message" = ToProfile."Action Message"::New then begin
                        ReqLine.TransferToTrackingEntry(TrkgReservEntryArray[5], true);
                        FromProfile.TransferToTrackingEntry(TrkgReservEntryArray[6], false);
                    end else
                        FromProfile.TransferToTrackingEntry(TrkgReservEntryArray[6], true);
                    TrkgReservEntryArray[5]."Quantity (Base)" := SplitQty2;
                    TrkgReservEntryArray[5].Quantity :=
                      Round(
                        TrkgReservEntryArray[5]."Quantity (Base)" / TrkgReservEntryArray[5]."Qty. per Unit of Measure",
                        UOMMgt.QtyRndPrecision());
                    FromProfile."Untracked Quantity" := FromProfile."Untracked Quantity" - SplitQty2;
                    TrackQty := TrackQty - SplitQty2;
                    SplitQty := SplitQty - SplitQty2;
                    PrepareTempTracking(TrkgReservEntryArray[5], TrkgReservEntryArray[6], IsSurplus, IssueActionMessage, Binding);
                end;

                if (ToProfile."Action Message" <> ToProfile."Action Message"::" ") and
                   (SplitQty < TrackQty)
                then begin
                    if (SplitQty > 0) and (SplitQty < TrackQty) then begin
                        SplitState := SplitState::SplitToProfile;
                        ToProfile.TransferToTrackingEntry(TrkgReservEntryArray[2],
                          (FromProfile."Action Message" = FromProfile."Action Message"::Reschedule) or
                          (FromProfile."Action Message" = FromProfile."Action Message"::"Resched. & Chg. Qty."));
                        TrkgReservEntryArray[3] := TrkgReservEntryArray[2];
                        ReqLine.TransferToTrackingEntry(TrkgReservEntryArray[2], true);
                        TrkgReservEntryArray[2]."Quantity (Base)" := TrackQty - SplitQty;
                        TrkgReservEntryArray[3]."Quantity (Base)" := SplitQty;
                        TrkgReservEntryArray[2].Quantity :=
                          Round(
                            TrkgReservEntryArray[2]."Quantity (Base)" / TrkgReservEntryArray[2]."Qty. per Unit of Measure",
                            UOMMgt.QtyRndPrecision());
                        TrkgReservEntryArray[3].Quantity :=
                          Round(
                            TrkgReservEntryArray[3]."Quantity (Base)" / TrkgReservEntryArray[3]."Qty. per Unit of Measure",
                            UOMMgt.QtyRndPrecision());
                    end else begin
                        ToProfile.TransferToTrackingEntry(TrkgReservEntryArray[2], false);
                        ReqLine.TransferToTrackingEntry(TrkgReservEntryArray[2], true);
                    end;
                end else
                    ToProfile.TransferToTrackingEntry(TrkgReservEntryArray[2], false);
                FromProfile.TransferToTrackingEntry(TrkgReservEntryArray[1], false);
            end;
        end;

        OnTrackBeforePrepareTempTracking(TrkgReservEntryArray, SplitState, IsSurplus, IssueActionMessage, Binding);
        case SplitState of
            SplitState::NoSplit:
                PrepareTempTracking(TrkgReservEntryArray[1], TrkgReservEntryArray[2], IsSurplus, IssueActionMessage, Binding);
            SplitState::SplitFromProfile:
                if IsSurplus then begin
                    PrepareTempTracking(TrkgReservEntryArray[1], TrkgReservEntryArray[4], false, IssueActionMessage, Binding);
                    PrepareTempTracking(TrkgReservEntryArray[3], TrkgReservEntryArray[4], true, IssueActionMessage, Binding);
                end else begin
                    TrkgReservEntryArray[4] := TrkgReservEntryArray[2];
                    PrepareTempTracking(TrkgReservEntryArray[1], TrkgReservEntryArray[2], IsSurplus, IssueActionMessage, Binding);
                    PrepareTempTracking(TrkgReservEntryArray[3], TrkgReservEntryArray[4], IsSurplus, IssueActionMessage, Binding);
                end;
            SplitState::SplitToProfile:
                begin
                    TrkgReservEntryArray[4] := TrkgReservEntryArray[1];
                    PrepareTempTracking(TrkgReservEntryArray[2], TrkgReservEntryArray[1], IsSurplus, IssueActionMessage, Binding);
                    PrepareTempTracking(TrkgReservEntryArray[3], TrkgReservEntryArray[4], IsSurplus, IssueActionMessage, Binding);
                end;
            SplitState::Cancel:
                PrepareTempTracking(TrkgReservEntryArray[1], TrkgReservEntryArray[3], IsSurplus, IssueActionMessage, Binding);
        end;
        OnAfterTrack(FromProfile, ToProfile, IsSurplus, IssueActionMessage, Binding);
    end;

    local procedure PrepareTempTracking(var FromTrkgReservEntry: Record "Reservation Entry"; var ToTrkgReservEntry: Record "Reservation Entry"; IsSurplus: Boolean; IssueActionMessage: Boolean; Binding: Enum "Reservation Binding")
    begin
        if not IsSurplus then begin
            ToTrkgReservEntry."Quantity (Base)" := -FromTrkgReservEntry."Quantity (Base)";
            ToTrkgReservEntry.Quantity :=
              Round(ToTrkgReservEntry."Quantity (Base)" / ToTrkgReservEntry."Qty. per Unit of Measure", UOMMgt.QtyRndPrecision());
        end else
            ToTrkgReservEntry."Suppressed Action Msg." := not IssueActionMessage;

        ToTrkgReservEntry.Positive := ToTrkgReservEntry."Quantity (Base)" > 0;
        FromTrkgReservEntry.Positive := FromTrkgReservEntry."Quantity (Base)" > 0;

        FromTrkgReservEntry.Binding := Binding;
        ToTrkgReservEntry.Binding := Binding;

        OnPrepareTempTrackingOnBeforeInsertTempTracking(FromTrkgReservEntry, ToTrkgReservEntry, IsSurplus);

        if IsSurplus or (ToTrkgReservEntry."Reservation Status" = ToTrkgReservEntry."Reservation Status"::Surplus) then begin
            FromTrkgReservEntry."Reservation Status" := FromTrkgReservEntry."Reservation Status"::Surplus;
            FromTrkgReservEntry."Suppressed Action Msg." := ToTrkgReservEntry."Suppressed Action Msg.";
            InsertTempTracking(FromTrkgReservEntry, ToTrkgReservEntry);
            exit;
        end;

        if FromTrkgReservEntry."Reservation Status" = FromTrkgReservEntry."Reservation Status"::Surplus then begin
            ToTrkgReservEntry."Reservation Status" := ToTrkgReservEntry."Reservation Status"::Surplus;
            ToTrkgReservEntry."Suppressed Action Msg." := FromTrkgReservEntry."Suppressed Action Msg.";
            InsertTempTracking(ToTrkgReservEntry, FromTrkgReservEntry);
            exit;
        end;

        InsertTempTracking(FromTrkgReservEntry, ToTrkgReservEntry);
    end;

    local procedure InsertTempTracking(var FromTrkgReservEntry: Record "Reservation Entry"; var ToTrkgReservEntry: Record "Reservation Entry")
    var
        NextEntryNo: Integer;
        ShouldInsert: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertTempTracking(FromTrkgReservEntry, ToTrkgReservEntry, IsHandled);
        if IsHandled then
            exit;

        if FromTrkgReservEntry."Quantity (Base)" = 0 then
            exit;
        NextEntryNo := TempTrkgReservEntry."Entry No." + 1;

        if FromTrkgReservEntry."Reservation Status" = FromTrkgReservEntry."Reservation Status"::Surplus then begin
            TempTrkgReservEntry := FromTrkgReservEntry;
            TempTrkgReservEntry."Entry No." := NextEntryNo;
            SetQtyToHandle(TempTrkgReservEntry);
            TempTrkgReservEntry.Insert();
        end else begin
            MatchReservationEntries(FromTrkgReservEntry, ToTrkgReservEntry);
            if FromTrkgReservEntry.Positive then begin
                FromTrkgReservEntry."Shipment Date" := ToTrkgReservEntry."Shipment Date";
                if ToTrkgReservEntry."Source Type" = Database::"Item Ledger Entry" then
                    ToTrkgReservEntry."Shipment Date" := DMY2Date(31, 12, 9999);
                ToTrkgReservEntry."Expected Receipt Date" := FromTrkgReservEntry."Expected Receipt Date";
            end else begin
                ToTrkgReservEntry."Shipment Date" := FromTrkgReservEntry."Shipment Date";
                if FromTrkgReservEntry."Source Type" = Database::"Item Ledger Entry" then
                    FromTrkgReservEntry."Shipment Date" := DMY2Date(31, 12, 9999);
                FromTrkgReservEntry."Expected Receipt Date" := ToTrkgReservEntry."Expected Receipt Date";
            end;

            if FromTrkgReservEntry.Positive then
                ShouldInsert := ShouldInsertTrackingEntry(FromTrkgReservEntry)
            else
                ShouldInsert := ShouldInsertTrackingEntry(ToTrkgReservEntry);

            if ShouldInsert then begin
                TempTrkgReservEntry := FromTrkgReservEntry;
                TempTrkgReservEntry."Entry No." := NextEntryNo;
                SetQtyToHandle(TempTrkgReservEntry);
                TempTrkgReservEntry.Insert();

                TempTrkgReservEntry := ToTrkgReservEntry;
                TempTrkgReservEntry."Entry No." := NextEntryNo;
                SetQtyToHandle(TempTrkgReservEntry);
                TempTrkgReservEntry.Insert();
            end;
        end;
    end;

    local procedure SetQtyToHandle(var TrkgReservEntry: Record "Reservation Entry")
    var
        WarehouseAvailabilityMgt: Codeunit "Warehouse Availability Mgt.";
        TypeHelper: Codeunit "Type Helper";
        PickedQty: Decimal;
    begin
        if not TrkgReservEntry.TrackingExists() then
            exit;

        TrkgReservEntry."Qty. to Handle (Base)" := TrkgReservEntry."Quantity (Base)";
        TrkgReservEntry."Qty. to Invoice (Base)" := TrkgReservEntry."Quantity (Base)";

        PickedQty := WarehouseAvailabilityMgt.CalcQtyRegisteredPick(TrkgReservEntry);
        if PickedQty > 0 then begin
            TrkgReservEntry."Qty. to Handle (Base)" := TypeHelper.Maximum(-PickedQty, TrkgReservEntry."Quantity (Base)");
            TrkgReservEntry."Qty. to Invoice (Base)" := TrkgReservEntry."Qty. to Handle (Base)";
        end;

        OnAfterSetQtyToHandle(TrkgReservEntry);
    end;

    local procedure CommitTracking()
    var
        PrevTempEntryNo: Integer;
        PrevInsertedEntryNo: Integer;
        IsHandled: Boolean;
        InsertedEntryNos: List of [Integer];
    begin
        IsHandled := false;
        OnBeforeCommitTracking(TempTrkgReservEntry, IsHandled);
        if not IsHandled then begin
            if not TempTrkgReservEntry.Find('-') then
                exit;

            repeat
                ReservEntry := TempTrkgReservEntry;
                if TempTrkgReservEntry."Entry No." = PrevTempEntryNo then
                    ReservEntry."Entry No." := PrevInsertedEntryNo
                else
                    ReservEntry."Entry No." := 0;
                ReservEntry.UpdateItemTracking();
                UpdateAppliedItemEntry(ReservEntry);
                if (ReservEntry."Source Type" = Database::"Transfer Line") and (ReservEntry."Reservation Status" = ReservEntry."Reservation Status"::Surplus) then begin
                    if not UpdateOrSkipDuplicateSurplusEntry(ReservEntry, InsertedEntryNos) then begin
                        ReservEntry.Insert();
                        OnCommitTrackingOnAfterInsertReservationEntry(ReservEntry);
                        PrevInsertedEntryNo := ReservEntry."Entry No.";
                        InsertedEntryNos.Add(ReservEntry."Entry No.");
                    end;
                end else begin
                    ReservEntry.Insert();
                    OnCommitTrackingOnAfterInsertReservationEntry(ReservEntry);
                    PrevTempEntryNo := TempTrkgReservEntry."Entry No.";
                    PrevInsertedEntryNo := ReservEntry."Entry No.";
                end;
                TempTrkgReservEntry.Delete();
            until TempTrkgReservEntry.Next() = 0;
            Clear(TempTrkgReservEntry);
        end;

        OnAfterCommitTracking(TempItemTrkgEntry);
    end;

    local procedure UpdateOrSkipDuplicateSurplusEntry(var NewReservEntry: Record "Reservation Entry"; InsertedEntryNos: List of [Integer]): Boolean
    var
        ExistingReservEntry: Record "Reservation Entry";
    begin
        if NewReservEntry."Reservation Status" <> NewReservEntry."Reservation Status"::Surplus then
            exit(false);

        if not NewReservEntry.TrackingExists() then
            exit(false);

        ExistingReservEntry.SetSourceFilterFromReservEntry(NewReservEntry);
        ExistingReservEntry.SetRange("Reservation Status", ExistingReservEntry."Reservation Status"::Surplus);
        ExistingReservEntry.SetRange(Positive, NewReservEntry.Positive);
        ExistingReservEntry.SetTrackingFilterFromReservEntry(NewReservEntry);
        if ExistingReservEntry.FindSet() then
            repeat
                // Only treat as duplicate if the entry existed before this CommitTracking call
                if not InsertedEntryNos.Contains(ExistingReservEntry."Entry No.") then begin
                    if ExistingReservEntry."Quantity (Base)" <> NewReservEntry."Quantity (Base)" then begin
                        ExistingReservEntry."Quantity (Base)" := NewReservEntry."Quantity (Base)";
                        ExistingReservEntry.Quantity := NewReservEntry.Quantity;
                        ExistingReservEntry."Qty. to Handle (Base)" := NewReservEntry."Qty. to Handle (Base)";
                        ExistingReservEntry."Qty. to Invoice (Base)" := NewReservEntry."Qty. to Invoice (Base)";
                        ExistingReservEntry.Modify();
                    end;
                    exit(true);
                end;
            until ExistingReservEntry.Next() = 0;

        exit(false);
    end;

    procedure MaintainPlanningLine(var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; NewPhase: Option " ","Line Created","Routing Created",Exploded,Obsolete; Direction: Option Forward,Backward)
    var
        PurchaseLine: Record "Purchase Line";
        TransLine: Record "Transfer Line";
        CurrentSupplyInvtProfile: Record "Inventory Profile";
        PlanLineNo: Integer;
        RecalculationRequired: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeMaintainPlanningLine(SupplyInvtProfile, DemandInvtProfile, NewPhase, Direction, TempTrkgReservEntry, IsHandled);
        if IsHandled then
            exit;

        if (NewPhase = NewPhase::"Line Created") or
           (SupplyInvtProfile."Planning Line Phase" < SupplyInvtProfile."Planning Line Phase"::"Line Created")
        then
            if SupplyInvtProfile."Planning Line No." = 0 then begin
                ReqLine.BlockDynamicTracking(true);
                if ReqLine.FindLast() then
                    PlanLineNo := ReqLine."Line No." + 10000
                else
                    PlanLineNo := 10000;

                OnMaintainPlanningLineOnAfterCalcPlanLineNo(ReqLine, PlanLineNo);

                ReqLine.Init();
                ReqLine."Worksheet Template Name" := CurrTemplateName;
                ReqLine."Journal Batch Name" := CurrWorksheetName;
                ReqLine."Line No." := PlanLineNo;
                ReqLine.Type := ReqLine.Type::Item;
                ReqLine."No." := SupplyInvtProfile."Item No.";
                ReqLine."Variant Code" := SupplyInvtProfile."Variant Code";
                ReqLine."Location Code" := SupplyInvtProfile."Location Code";
                ReqLine."Bin Code" := SupplyInvtProfile."Bin Code";
                ReqLine."Planning Line Origin" := ReqLine."Planning Line Origin"::Planning;
                SetPriceCalculationMethod(ReqLine);
                OnMaintainPlanningLineOnAfterPopulateReqLineFields(ReqLine, SupplyInvtProfile, DemandInvtProfile, NewPhase, Direction, TempSKU, CurrTemplateName, CurrWorksheetName);
                if SupplyInvtProfile."Action Message" = SupplyInvtProfile."Action Message"::New then begin
                    ReqLine."Order Date" := SupplyInvtProfile."Due Date";
                    ReqLine."Planning Level" := SupplyInvtProfile."Planning Level Code";
                    case TempSKU."Replenishment System" of
                        TempSKU."Replenishment System"::Purchase:
                            ReqLine."Ref. Order Type" := ReqLine."Ref. Order Type"::Purchase;
                        TempSKU."Replenishment System"::Transfer:
                            ReqLine."Ref. Order Type" := ReqLine."Ref. Order Type"::Transfer;
                    end;
                    OnMaintainPlanningLineOnBeforeValidateNo(ReqLine, SupplyInvtProfile, TempSKU);
                    ReqLine.Validate(ReqLine."No.");
                    ValidateUOMFromInventoryProfile(ReqLine, SupplyInvtProfile);
                    OnMaintainPlanningLineOnAfterValidateFieldsForNewReqLine(ReqLine, SupplyInvtProfile, TempSKU);
                end else
                    case SupplyInvtProfile."Source Type" of
                        Database::"Purchase Line":
                            SetPurchase(PurchaseLine, SupplyInvtProfile);
                        Database::"Transfer Line":
                            SetTransfer(TransLine, SupplyInvtProfile);
                        else
                            OnMaintainPlanningLineOnAfterSetSourceForNotNewReqLine(ReqLine, SupplyInvtProfile);
                    end;

                if ReqLine."Ref. Order Type" <> ReqLine."Ref. Order Type"::"Prod. Order" then
                    ReqLine."Low-Level Code" := 0;

                OnMaintainPlanningLineOnBeforeAdjustPlanLine(ReqLine, SupplyInvtProfile, TempSKU);
                AdjustPlanLine(SupplyInvtProfile);
                ReqLine."Accept Action Message" := true;
                ReqLine."Routing Reference No." := ReqLine."Line No.";
                ReqLine.UpdateDatetime();
                ReqLine."MPS Order" := SupplyInvtProfile."MPS Order";

                if TempSKU."Plan Minimal Supply" then begin
                    DummyInventoryProfileTrackBuffer."Warning Level" := DummyInventoryProfileTrackBuffer."Warning Level"::Attention;
                    if TempSKU."Location Code" = '' then
                        PlanningTransparency.LogWarning(
                          0, ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                          StrSubstNo(MinimalSupplyPlannedTxt, DummyInventoryProfileTrackBuffer."Warning Level", LocationMandatoryTxt))
                    else
                        PlanningTransparency.LogWarning(
                           0, ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                           StrSubstNo(MinimalSupplyPlannedTxt, DummyInventoryProfileTrackBuffer."Warning Level", MissingStockkeepingUnitTxt));
                end;

                OnMaintainPlanningLineOnBeforeReqLineInsert(
                  ReqLine, SupplyInvtProfile, PlanToDate, CurrForecast, NewPhase, Direction, DemandInvtProfile, ExcludeForecastBefore);
                ReqLine.Insert();
                OnMaintainPlanningLineOnAfterReqLineInsert(ReqLine);
                SupplyInvtProfile."Planning Line No." := ReqLine."Line No.";
                if NewPhase = NewPhase::"Line Created" then
                    SupplyInvtProfile."Planning Line Phase" := SupplyInvtProfile."Planning Line Phase"::"Line Created";
            end else begin
                if SupplyInvtProfile."Planning Line No." <> ReqLine."Line No." then
                    ReqLine.Get(CurrTemplateName, CurrWorksheetName, SupplyInvtProfile."Planning Line No.");
                ReqLine.BlockDynamicTracking(true);
                AdjustPlanLine(SupplyInvtProfile);
                OnMaintainPlanLineOnAfterAdjustPlanLine(
                    TempSKU, ReqLine, SupplyInvtProfile, DemandInvtProfile, PlanToDate, CurrForecast, NewPhase, Direction);
                if NewPhase = NewPhase::"Line Created" then
                    ReqLine.Modify();
            end;

        OnMaintainPlanningLineOnAfterLineCreated(SupplyInvtProfile, ReqLine);

        if (NewPhase = NewPhase::"Routing Created") or
           ((NewPhase > NewPhase::"Routing Created") and
            (SupplyInvtProfile."Planning Line Phase" < SupplyInvtProfile."Planning Line Phase"::"Routing Created"))
        then begin
            ReqLine.BlockDynamicTracking(true);
            if SupplyInvtProfile."Planning Line No." <> ReqLine."Line No." then
                ReqLine.Get(CurrTemplateName, CurrWorksheetName, SupplyInvtProfile."Planning Line No.");
            AdjustPlanLine(SupplyInvtProfile);
            if ReqLine.Quantity > 0 then begin
                if SupplyInvtProfile."Starting Date" <> 0D then
                    ReqLine."Starting Date" := SupplyInvtProfile."Starting Date"
                else
                    ReqLine."Starting Date" := SupplyInvtProfile."Due Date";
                GetRouting(ReqLine);
                RecalculationRequired := true;
                if NewPhase = NewPhase::"Routing Created" then
                    SupplyInvtProfile."Planning Line Phase" := SupplyInvtProfile."Planning Line Phase"::"Routing Created";
            end;
            OnMaintainPlanningLineOnBeforeReqLineModify(ReqLine, SupplyInvtProfile);
            ReqLine.Modify();
        end;

        if NewPhase = NewPhase::Exploded then begin
            if SupplyInvtProfile."Planning Line No." <> ReqLine."Line No." then
                ReqLine.Get(CurrTemplateName, CurrWorksheetName, SupplyInvtProfile."Planning Line No.");
            ReqLine.BlockDynamicTracking(true);
            AdjustPlanLine(SupplyInvtProfile);
            if ReqLine.Quantity = 0 then
                if ReqLine."Action Message" = ReqLine."Action Message"::New then begin
                    ReqLine.BlockDynamicTracking(true);
                    ReqLine.Delete(true);

                    RecalculationRequired := false;
                end else
                    DisableRelations(ReqLine)
            else begin
                GetComponents(ReqLine);
                RecalculationRequired := true;
            end;

            if (ReqLine."Ref. Order Type" = ReqLine."Ref. Order Type"::Transfer) and
               not ((ReqLine.Quantity = 0) and (ReqLine."Action Message" = ReqLine."Action Message"::New))
            then begin
                AdjustTransferDates(ReqLine);
                if ReqLine."Action Message" = ReqLine."Action Message"::New then begin
                    IsHandled := false;
                    OnMaintainPlanningLineOnBeforeCreateDemandInvtProfileForTransfer(ReqLine, SupplyInvtProfile, TempTrkgReservEntry, LineNo, IsHandled);
                    if not IsHandled then begin
                        CurrentSupplyInvtProfile.Copy(SupplyInvtProfile);

                        SupplyInvtProfile.Reset();
                        SupplyInvtProfile.SetSourceFilter(
                          Database::"Requisition Line", 1, ReqLine."Worksheet Template Name", ReqLine."Line No.", ReqLine."Journal Batch Name", 0);
                        SupplyInvtProfile.SetTrackingFilter(CurrentSupplyInvtProfile);
                        if not SupplyInvtProfile.FindFirst() then begin
                            SupplyInvtProfile.Init();
                            SupplyInvtProfile."Line No." := GetNextLineNo();
                            SupplyInvtProfile."Item No." := ReqLine."No.";
                            SupplyInvtProfile.TransferFromOutboundTransfPlan(ReqLine, TempItemTrkgEntry);
                            SupplyInvtProfile.CopyTrackingFromInvtProfile(CurrentSupplyInvtProfile);
                            if SupplyInvtProfile.IsSupply then
                                SupplyInvtProfile.ChangeSign();
                            OnMaintainPlanningLineOnBeforeSupplyInvtProfileInsert(SupplyInvtProfile, CurrentSupplyInvtProfile);
                            SupplyInvtProfile.Insert();
                        end else begin
                            SupplyInvtProfile.TransferFromOutboundTransfPlan(ReqLine, TempItemTrkgEntry);
                            SupplyInvtProfile.Modify();
                        end;

                        SupplyInvtProfile.Copy(CurrentSupplyInvtProfile);
                    end;
                end else
                    SynchronizeTransferProfiles(SupplyInvtProfile, ReqLine);
            end;
        end;

        if RecalculationRequired then begin
            Recalculate(
              ReqLine, Direction,
              ((SupplyInvtProfile."Planning Line Phase" < SupplyInvtProfile."Planning Line Phase"::"Routing Created") or
               (ReqLine."Action Message" = ReqLine."Action Message"::New)) and
              (ReqLine."Ref. Order Type" = ReqLine."Ref. Order Type"::"Prod. Order"));
            ReqLine.UpdateDatetime();
            ReqLine.Modify();

            SupplyInvtProfile."Starting Date" := ReqLine."Starting Date";
            SupplyInvtProfile."Due Date" := ReqLine."Due Date";

            OnMaintainPlanningLineOnAfterCopyDatesToInvtProfile(SupplyInvtProfile, ReqLine);
        end;

        if NewPhase = NewPhase::Obsolete then begin
            if SupplyInvtProfile."Planning Line No." <> ReqLine."Line No." then
                ReqLine.Get(CurrTemplateName, CurrWorksheetName, SupplyInvtProfile."Planning Line No.");
            DeletePlanningCompList(ReqLine);
            ReqLine.Delete(true);
            SupplyInvtProfile."Planning Line No." := 0;
            SupplyInvtProfile."Planning Line Phase" := SupplyInvtProfile."Planning Line Phase"::" ";
        end;

        SupplyInvtProfile.Modify();

        OnAfterMaintainPlanningLine(ReqLine, SupplyInvtProfile, NewPhase);
    end;

    local procedure ValidateUOMFromInventoryProfile(var RequisitionLine: Record "Requisition Line"; InventoryProfile: Record "Inventory Profile")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeValidateUOMFromInventoryProfile(RequisitionLine, InventoryProfile, TempSKU, IsHandled);
        if IsHandled then
            exit;

        RequisitionLine.Validate("Unit of Measure Code", InventoryProfile."Unit of Measure Code");
    end;

    procedure AdjustReorderQty(OrderQty: Decimal; SKU: Record "Stockkeeping Unit"; SupplyLineNo: Integer; MinQty: Decimal): Decimal
    var
        DeltaQty: Decimal;
        Rounding: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeAdjustReorderQty(OrderQty, SKU, SupplyLineNo, MinQty, DeltaQty, IsHandled);
        if IsHandled then
            exit(DeltaQty);

        // Copy of this procedure exists in COD5400- Available Management
        if OrderQty <= 0 then
            exit(0);

        if (SKU."Maximum Order Quantity" < OrderQty) and
           (SKU."Maximum Order Quantity" <> 0) and
           (SKU."Maximum Order Quantity" > MinQty)
        then begin
            DeltaQty := SKU."Maximum Order Quantity" - OrderQty;
            PlanningTransparency.LogPlanningSurplus(
              SupplyLineNo, 0, Database::Item, TempSKU."Item No.",
              DeltaQty, SurplusType::MaxOrder);
        end else
            DeltaQty := 0;
        if SKU."Minimum Order Quantity" > (OrderQty + DeltaQty) then begin
            DeltaQty := SKU."Minimum Order Quantity" - OrderQty;
            PlanningTransparency.LogPlanningSurplus(
              SupplyLineNo, 0, Database::Item, TempSKU."Item No.",
              SKU."Minimum Order Quantity", SurplusType::MinOrder);
        end;
        if SKU."Order Multiple" <> 0 then begin
            Rounding := Round(OrderQty + DeltaQty, SKU."Order Multiple", '>') - (OrderQty + DeltaQty);
            DeltaQty += Rounding;
            if DeltaQty <> 0 then
                PlanningTransparency.LogPlanningSurplus(
                  SupplyLineNo, 0, Database::Item, TempSKU."Item No.",
                  Rounding, SurplusType::OrderMultiple);
        end;

        OnAfterAdjustReorderQty(OrderQty, SKU, SupplyLineNo, MinQty, DeltaQty);
        exit(DeltaQty);
    end;

    local procedure CalcInventoryProfileRemainingQty(var InventoryProfile: Record "Inventory Profile"; DocumentNo: Code[20]; LineNo: Integer) RemQty: Decimal
    var
        SalesLine: Record "Sales Line";
    begin
        RemQty := 0;

        InventoryProfile.SetRange("Source Type", Database::"Sales Line");
        InventoryProfile.SetRange("Source Order Status", SalesLine."Document Type"::Order);
        InventoryProfile.SetRange("Ref. Blanket Order No.", DocumentNo);
        if InventoryProfile.FindSet() then
            repeat
                SalesLine.SetLoadFields("Blanket Order No.", "Blanket Order Line No.");
                SalesLine.Get(SalesLine."Document Type"::Order, InventoryProfile."Source ID", InventoryProfile."Source Ref. No.");
                if (SalesLine."Blanket Order No." = DocumentNo) and (SalesLine."Blanket Order Line No." = LineNo) then
                    RemQty += InventoryProfile."Remaining Quantity (Base)";
            until InventoryProfile.Next() = 0;

        OnAfterCalcInventoryProfileRemainingQty(InventoryProfile, DocumentNo, LineNo, RemQty);
    end;

    procedure CalcReorderQty(NeededQty: Decimal; ProjectedInventory: Decimal; SupplyLineNo: Integer) QtyToOrder: Decimal
    var
        Item: Record Item;
        SKU: Record "Stockkeeping Unit";
        IsHandled: Boolean;
    begin
        // Calculate qty to order:
        // If Max:   QtyToOrder = MaxInv - ProjInvLevel
        // If Fixed: QtyToOrder = FixedReorderQty
        // Copy of this procedure exists in COD5400- Available Management
        case TempSKU."Reordering Policy" of
            TempSKU."Reordering Policy"::"Maximum Qty.":
                begin
                    if TempSKU."Maximum Inventory" <= TempSKU."Reorder Point" then
                        CalcMaximumReorderQty();

                    QtyToOrder := TempSKU."Maximum Inventory" - ProjectedInventory;
                    PlanningTransparency.LogPlanningSurplus(
                      SupplyLineNo, 0, Database::Item, TempSKU."Item No.",
                      QtyToOrder, SurplusType::MaxInventory);
                end;
            TempSKU."Reordering Policy"::"Fixed Reorder Qty.":
                begin
                    if TempSKU."Reorder Quantity" = 0 then
                        if SKU.Get(TempSKU."Location Code", TempSKU."Item No.", TempSKU."Variant Code") then begin
                            if PlanningResiliency then
                                ReqLine.SetResiliencyError(
                                  StrSubstNo(
                                    Text004, SKU.FieldCaption("Reorder Quantity"), 0, SKU.TableCaption(),
                                    SKU."Location Code", SKU."Item No.", SKU."Variant Code",
                                    SKU.FieldCaption("Reordering Policy"), SKU."Reordering Policy"),
                                  Database::"Stockkeeping Unit", SKU.GetPosition());
                            TempSKU.TestField("Reorder Quantity");
                        end else
                            if Item.Get(TempSKU."Item No.") then begin
                                if PlanningResiliency then
                                    ReqLine.SetResiliencyError(
                                      StrSubstNo(
                                        Text005, Item.FieldCaption("Reorder Quantity"), 0, Item.TableCaption(),
                                        Item."No.", Item.FieldCaption("Reordering Policy"), Item."Reordering Policy"),
                                      Database::Item, Item.GetPosition());
                                Item.TestField("Reorder Quantity");
                            end;

                    QtyToOrder := TempSKU."Reorder Quantity";
                    PlanningTransparency.LogPlanningSurplus(
                      SupplyLineNo, 0, Database::Item, TempSKU."Item No.",
                      QtyToOrder, SurplusType::FixedOrderQty);
                end;
            else begin
                IsHandled := false;
                OnCalcReorderQtyOnCaseElse(QtyToOrder, NeededQty, ProjectedInventory, SupplyLineNo, TempSKU, PlanningResiliency, IsHandled);
                if not IsHandled then
                    QtyToOrder := NeededQty;
            end;
        end;
    end;

    procedure CalcMaximumReorderQty()
    var
        Item: Record Item;
        SKU: Record "Stockkeeping Unit";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCalcMaximumReorderQty(TempSKU, ReqLine, PlanningResiliency, IsHandled);
        if IsHandled then
            exit;

        if PlanningResiliency then
            if SKU.Get(TempSKU."Location Code", TempSKU."Item No.", TempSKU."Variant Code") then
                ReqLine.SetResiliencyError(
                    StrSubstNo(
                    Text004, SKU.FieldCaption("Maximum Inventory"), SKU."Maximum Inventory", SKU.TableCaption(),
                    SKU."Location Code", SKU."Item No.", SKU."Variant Code",
                    SKU.FieldCaption("Reorder Point"), SKU."Reorder Point"),
                    Database::"Stockkeeping Unit", SKU.GetPosition())
            else
                if Item.Get(TempSKU."Item No.") then
                    ReqLine.SetResiliencyError(
                        StrSubstNo(
                        Text005, Item.FieldCaption("Maximum Inventory"), Item."Maximum Inventory", Item.TableCaption(),
                        Item."No.", Item.FieldCaption("Reorder Point"), Item."Reorder Point"),
                        Database::Item, Item.GetPosition());
        TempSKU.TestField("Maximum Inventory", TempSKU."Reorder Point" + 1); // Assertion
    end;

    procedure CalcOrderQty(NeededQty: Decimal; ProjectedInventory: Decimal; SupplyLineNo: Integer) QtyToOrder: Decimal
    begin
        QtyToOrder := CalcReorderQty(NeededQty, ProjectedInventory, SupplyLineNo);
        // Ensure that QtyToOrder is large enough to exceed ROP:
        if QtyToOrder <= (TempSKU."Reorder Point" - ProjectedInventory) then
            QtyToOrder :=
              Round((TempSKU."Reorder Point" - ProjectedInventory) / TempSKU."Reorder Quantity" + 0.000000001, 1, '>') *
              TempSKU."Reorder Quantity";

        OnAfterCalcOrderQty(TempSKU, NeededQty, ProjectedInventory, SupplyLineNo, QtyToOrder);
    end;

    local procedure AdjustPlanLine(var SupplyInventoryProfile: Record "Inventory Profile")
    begin
        OnBeforeAdjustPlanLine(ReqLine, SupplyInventoryProfile);

        ReqLine."Action Message" := SupplyInventoryProfile."Action Message";
        ReqLine.BlockDynamicTracking(true);
        if SupplyInventoryProfile."Action Message" in
           [SupplyInventoryProfile."Action Message"::New,
            SupplyInventoryProfile."Action Message"::"Change Qty.",
            SupplyInventoryProfile."Action Message"::Reschedule,
            SupplyInventoryProfile."Action Message"::"Resched. & Chg. Qty.",
            SupplyInventoryProfile."Action Message"::Cancel]
        then begin
            if SupplyInventoryProfile."Qty. per Unit of Measure" = 0 then
                SupplyInventoryProfile."Qty. per Unit of Measure" := 1;
            UpdateReqLineQuantity(SupplyInventoryProfile);
            UpdateReqLineOriginalQuantity(SupplyInventoryProfile);
            ReqLine."Net Quantity (Base)" :=
              ReqLine."Remaining Qty. (Base)" - ReqLine."Original Quantity" * ReqLine."Qty. per Unit of Measure";
            OnAdjustPlanLineAfterValidateQuantity(ReqLine, SupplyInventoryProfile);
        end;
        UpdateOriginalDueDate(SupplyInventoryProfile);
        ReqLine."Due Date" := SupplyInventoryProfile."Due Date";
        if SupplyInventoryProfile."Planning Level Code" = 0 then begin
            ReqLine."Ending Date" :=
              LeadTimeMgt.GetPlannedEndingDate(
                SupplyInventoryProfile."Item No.", SupplyInventoryProfile."Location Code", SupplyInventoryProfile."Variant Code", SupplyInventoryProfile."Due Date", '', ReqLine."Ref. Order Type");
            InventorySetup.GetRecordOnce();
            if not IsSKUSetUpForReorderPointPlanning(TempSKU) then
                if CalcDate(TempSKU."Safety Lead Time", ReqLine."Ending Date") = ReqLine."Ending Date" then
                    if CalcDate(InventorySetup."Default Safety Lead Time", ReqLine."Ending Date") = ReqLine."Ending Date" then
                        ReqLine."Ending Time" := SupplyInventoryProfile."Due Time";
        end else begin
            ReqLine."Ending Date" := SupplyInventoryProfile."Due Date";
            ReqLine."Ending Time" := SupplyInventoryProfile."Due Time";
        end;
        if (ReqLine."Starting Date" = 0D) or
           (ReqLine."Starting Date" > ReqLine."Ending Date")
        then
            ReqLine."Starting Date" := ReqLine."Ending Date";
        if (ReqLine."Starting Date" = ReqLine."Ending Date") and
           (ReqLine."Ending Time" < ReqLine."Starting Time")
        then
            ReqLine."Ending Time" := ReqLine."Starting Time";

        OnAfterAdjustPlanLine(ReqLine, SupplyInventoryProfile);
    end;

    local procedure UpdateOriginalDueDate(var SupplyInventoryProfile: Record "Inventory Profile")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateOriginalDueDate(SupplyInventoryProfile, IsHandled);
        if not IsHandled then
            ReqLine."Original Due Date" := SupplyInventoryProfile."Original Due Date";
    end;

    local procedure UpdateReqLineQuantity(var SupplyInventoryProfile: Record "Inventory Profile")
    var
        QtyRoundingPrecisionBase: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateReqLineQuantity(ReqLine, SupplyInventoryProfile, IsHandled);
        if IsHandled then
            exit;

        ReqLine.Validate(
            Quantity,
            Round(SupplyInventoryProfile."Remaining Quantity (Base)" / SupplyInventoryProfile."Qty. per Unit of Measure", UOMMgt.QtyRndPrecision()));

        QtyRoundingPrecisionBase := ReqLine."Qty. Rounding Precision (Base)";
        if QtyRoundingPrecisionBase = 0 then
            QtyRoundingPrecisionBase := UOMMgt.QtyRndPrecision();
        if Abs(ReqLine."Quantity (Base)" - SupplyInventoryProfile."Remaining Quantity (Base)") <=
            (SupplyInventoryProfile."Qty. per Unit of Measure" * UOMMgt.QtyRndPrecision() + QtyRoundingPrecisionBase) / 2
        then
            if ReqLine."Quantity (Base)" <> SupplyInventoryProfile."Remaining Quantity (Base)" then begin
                ReqLine."Remaining Qty. (Base)" := SupplyInventoryProfile."Remaining Quantity (Base)";
                ReqLine."Quantity (Base)" := SupplyInventoryProfile."Remaining Quantity (Base)";
            end;
    end;

    local procedure UpdateReqLineOriginalQuantity(var SupplyInventoryProfile: Record "Inventory Profile")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateReqLineOriginalQuantity(ReqLine, SupplyInventoryProfile, IsHandled, TempSKU);
        if IsHandled then
            exit;

        ReqLine."Original Quantity" := SupplyInventoryProfile."Original Quantity";
    end;

    procedure DisableRelations(var ReqLine2: Record "Requisition Line")
    var
        PlanningComponent: Record "Planning Component";
    begin
        if ReqLine2.Type <> ReqLine2.Type::Item then
            exit;

        PlanningComponent.SetRange("Worksheet Template Name", ReqLine2."Worksheet Template Name");
        PlanningComponent.SetRange("Worksheet Batch Name", ReqLine2."Journal Batch Name");
        PlanningComponent.SetRange("Worksheet Line No.", ReqLine2."Line No.");
        if PlanningComponent.Find('-') then
            repeat
                PlanningComponent.BlockDynamicTracking(false);
                PlanningComponent.Delete(true);
            until PlanningComponent.Next() = 0;

        OnAfterDisableRelations(ReqLine2);
    end;

    local procedure SynchronizeTransferProfiles(var InventoryProfile: Record "Inventory Profile"; var TransferReqLine: Record "Requisition Line")
    var
        SupplyInvtProfile: Record "Inventory Profile";
    begin
        if InventoryProfile."Transfer Location Not Planned" then
            exit;
        SupplyInvtProfile.Copy(InventoryProfile);
        if GetTransferSisterProfile(SupplyInvtProfile, InventoryProfile) then begin
            TransferReqLineToInvProfiles(InventoryProfile, TransferReqLine);
            InventoryProfile.Modify();
        end;
        InventoryProfile.Copy(SupplyInvtProfile);
    end;

    procedure TransferReqLineToInvProfiles(var InventoryProfile: Record "Inventory Profile"; var TransferReqLine: Record "Requisition Line")
    begin
        InventoryProfile.TestField("Location Code", TransferReqLine."Transfer-from Code");

        InventoryProfile."Min. Quantity" := InventoryProfile."Remaining Quantity (Base)";
        InventoryProfile."Original Quantity" := TransferReqLine."Original Quantity";
        InventoryProfile.Quantity := TransferReqLine.Quantity;
        InventoryProfile."Remaining Quantity" := TransferReqLine.Quantity;
        InventoryProfile."Quantity (Base)" := TransferReqLine."Quantity (Base)";
        InventoryProfile."Remaining Quantity (Base)" := TransferReqLine."Quantity (Base)";
        InventoryProfile."Untracked Quantity" := TransferReqLine."Quantity (Base)";
        InventoryProfile."Unit of Measure Code" := TransferReqLine."Unit of Measure Code";
        InventoryProfile."Qty. per Unit of Measure" := TransferReqLine."Qty. per Unit of Measure";
        InventoryProfile."Due Date" := TransferReqLine."Transfer Shipment Date";
    end;

    local procedure SyncTransferDemandWithReqLine(var InventoryProfile: Record "Inventory Profile"; LocationCode: Code[10])
    var
        TransferReqLine: Record "Requisition Line";
    begin
        TransferReqLine.SetRange("Ref. Order Type", TransferReqLine."Ref. Order Type"::Transfer);
        TransferReqLine.SetRange("Ref. Order No.", InventoryProfile."Source ID");
        TransferReqLine.SetRange("Ref. Line No.", InventoryProfile."Source Ref. No.");
        TransferReqLine.SetRange("Transfer-from Code", InventoryProfile."Location Code");
        TransferReqLine.SetRange("Location Code", LocationCode);
        TransferReqLine.SetFilter("Action Message", '<>%1', TransferReqLine."Action Message"::New);
        OnSyncTransferDemandWithReqLineOnAfterSetFilters(TransferReqLine, InventoryProfile, LocationCode, CurrTemplateName, CurrWorksheetName);
        if TransferReqLine.FindFirst() then
            TransferReqLineToInvProfiles(InventoryProfile, TransferReqLine);
    end;

    local procedure GetTransferSisterProfile(CurrInvProfile: Record "Inventory Profile"; var SisterInvProfile: Record "Inventory Profile") InvtProfileFound: Boolean
    begin
        // Finds the invprofile which represents the opposite side of a transfer order.
        if (CurrInvProfile."Source Type" <> Database::"Transfer Line") or
           (CurrInvProfile."Action Message" = CurrInvProfile."Action Message"::New)
        then
            exit(false);

        SetFiltersForSisterInventoryProfile(CurrInvProfile, SisterInvProfile);

        InvtProfileFound := SisterInvProfile.Find('-');
        if InvtProfileFound then
            if SisterInvProfile.Next() <> 0 then
                Error(Text001, SisterInvProfile.TableCaption());

        exit;
    end;

    local procedure SetFiltersForSisterInventoryProfile(CurrInvProfile: Record "Inventory Profile"; var SisterInvProfile: Record "Inventory Profile")
    begin
        SisterInvProfile.Reset();
        SisterInvProfile.SetRange("Source Type", Database::"Transfer Line");
        SisterInvProfile.SetRange("Source ID", CurrInvProfile."Source ID");
        SisterInvProfile.SetRange("Source Ref. No.", CurrInvProfile."Source Ref. No.");
        SisterInvProfile.SetTrackingFilterFromInvtProfile(CurrInvProfile);
        SisterInvProfile.SetRange(IsSupply, not CurrInvProfile.IsSupply);

        OnAfterSetFiltersForSisterInventoryProfile(CurrInvProfile, SisterInvProfile);
    end;

    local procedure AdjustTransferDates(var TransferReqLine: Record "Requisition Line")
    var
        TransferRoute: Record "Transfer Route";
        ShippingAgentServices: Record "Shipping Agent Services";
        Location: Record Location;
        SKU: Record "Stockkeeping Unit";
        ShippingTime: DateFormula;
        OutboundWhseTime: DateFormula;
        InboundWhseTime: DateFormula;
        OK: Boolean;
        IsHandled: Boolean;
    begin
        // Used for planning lines handling transfer orders.
        // "Ending Date", Starting Date and "Transfer Shipment Date" are calculated backwards from "Due Date".
        IsHandled := false;
        OnBeforeAdjustTransferDates(TransferReqLine, IsHandled);
        if IsHandled then
            exit;

        TransferReqLine.TestField("Ref. Order Type", TransferReqLine."Ref. Order Type"::Transfer);
        OK := Location.Get(TransferReqLine."Transfer-from Code");
        if PlanningResiliency and not OK then
            if SKU.Get(TransferReqLine."Location Code", TransferReqLine."No.", TransferReqLine."Variant Code") then
                ReqLine.SetResiliencyError(
                  StrSubstNo(
                    Text003, SKU.FieldCaption("Transfer-from Code"), SKU.TableCaption(),
                    SKU."Location Code", SKU."Item No.", SKU."Variant Code"),
                  Database::"Stockkeeping Unit", SKU.GetPosition());
        if not OK then
            Location.Get(TransferReqLine."Transfer-from Code");
        OutboundWhseTime := Location."Outbound Whse. Handling Time";

        Location.Get(TransferReqLine."Location Code");
        InboundWhseTime := Location."Inbound Whse. Handling Time";
        OnAdjustTransferDatesOnAfterInboundWhseTimeSet(TransferReqLine, Location, InboundWhseTime);

        OK := TransferRoute.Get(TransferReqLine."Transfer-from Code", TransferReqLine."Location Code");
        if PlanningResiliency and not OK then
            ReqLine.SetResiliencyError(
              StrSubstNo(
                Text002, TransferRoute.TableCaption(),
                TransferReqLine."Transfer-from Code", TransferReqLine."Location Code"),
              Database::"Transfer Route", '');
        if not OK then
            TransferRoute.Get(TransferReqLine."Transfer-from Code", TransferReqLine."Location Code");

        if ShippingAgentServices.Get(TransferRoute."Shipping Agent Code", TransferRoute."Shipping Agent Service Code") then
            ShippingTime := ShippingAgentServices."Shipping Time"
        else
            Evaluate(ShippingTime, '');

        // The calculation will run through the following steps:
        // ShipmentDate <- PlannedShipmentDate <- PlannedReceiptDate <- ReceiptDate
        // Calc Planned Receipt Date (Ending Date) backward from ReceiptDate
        TransferRoute.CalcPlanReceiptDateBackward(
          TransferReqLine."Ending Date", TransferReqLine."Due Date", InboundWhseTime,
          TransferReqLine."Location Code", TransferRoute."Shipping Agent Code", TransferRoute."Shipping Agent Service Code");

        // Calc Planned Shipment Date (Starting Date) backward from Planned ReceiptDate (Ending Date)
        TransferRoute.CalcPlanShipmentDateBackward(
          TransferReqLine."Starting Date", TransferReqLine."Ending Date", ShippingTime,
          TransferReqLine."Transfer-from Code", TransferRoute."Shipping Agent Code", TransferRoute."Shipping Agent Service Code");

        // Calc Shipment Date backward from Planned Shipment Date (Starting Date)
        TransferRoute.CalcShipmentDateBackward(
          TransferReqLine."Transfer Shipment Date", TransferReqLine."Starting Date", OutboundWhseTime, TransferReqLine."Transfer-from Code");

        TransferReqLine.UpdateDatetime();
        OnAdjustTransferDatesOnBeforeTransferReqLineModify(TransferReqLine);
        TransferReqLine.Modify();
    end;

    local procedure InsertTempTransferSKU(var TransLine: Record "Transfer Line")
    var
        SKU: Record "Stockkeeping Unit";
    begin
        TempTransferSKU.Init();
        TempTransferSKU."Item No." := TransLine."Item No.";
        TempTransferSKU."Variant Code" := TransLine."Variant Code";
        if TransLine.Quantity > 0 then
            TempTransferSKU."Location Code" := TransLine."Transfer-to Code"
        else
            TempTransferSKU."Location Code" := TransLine."Transfer-from Code";
        if SKU.Get(TempTransferSKU."Location Code", TempTransferSKU."Item No.", TempTransferSKU."Variant Code") then
            TempTransferSKU."Transfer-from Code" := SKU."Transfer-from Code"
        else
            TempTransferSKU."Transfer-from Code" := '';

        OnBeforeTempTransferSKUInsert(TempTransferSKU, TransLine);
        if TempTransferSKU.Insert() then;
    end;

    local procedure UpdateTempSKUTransferLevels()
    var
        SKU: Record "Stockkeeping Unit";
    begin
        SKU.Copy(TempSKU);
        TempTransferSKU.Reset();
        if TempTransferSKU.Find('-') then
            repeat
                TempSKU.Reset();
                if TempSKU.Get(TempTransferSKU."Location Code", TempTransferSKU."Item No.", TempTransferSKU."Variant Code") then
                    if TempSKU."Transfer-from Code" = '' then begin
                        TempSKU.SetRange("Location Code", TempTransferSKU."Transfer-from Code");
                        TempSKU.SetRange("Item No.", TempTransferSKU."Item No.");
                        TempSKU.SetRange("Variant Code", TempTransferSKU."Variant Code");
                        if not TempSKU.Find('-') then
                            TempTransferSKU."Transfer-Level Code" := -1
                        else
                            TempTransferSKU."Transfer-Level Code" := TempSKU."Transfer-Level Code" - 1;
                        TempSKU.Get(TempTransferSKU."Location Code", TempTransferSKU."Item No.", TempTransferSKU."Variant Code");
                        TempSKU."Transfer-from Code" := TempTransferSKU."Transfer-from Code";
                        TempSKU."Transfer-Level Code" := TempTransferSKU."Transfer-Level Code";
                        TempSKU.Modify();
                        TempSKU.UpdateTempSKUTransferLevels(TempSKU, TempSKU, TempSKU."Transfer-from Code");
                    end;
            until TempTransferSKU.Next() = 0;
        TempSKU.Copy(SKU);
    end;

    local procedure CancelTransfer(var SupplyInvtProfile: Record "Inventory Profile"; var DemandInvtProfile: Record "Inventory Profile"; DemandExists: Boolean) Cancel: Boolean
    var
        xSupply2: Record "Inventory Profile";
    begin
        // Used to handle transfers where supply is planned with a higher Transfer Level Code than DemandInvtProfile.
        // If you encounter the demand before the SupplyInvtProfile, the supply must be removed.

        if not DemandExists then
            exit(false);
        if DemandInvtProfile."Source Type" <> Database::"Transfer Line" then
            exit(false);

        DemandInvtProfile.TestField(IsSupply, false);

        xSupply2.Copy(SupplyInvtProfile);
        if GetTransferSisterProfile(DemandInvtProfile, SupplyInvtProfile) then begin
            if SupplyInvtProfile."Action Message" = SupplyInvtProfile."Action Message"::New then
                SupplyInvtProfile.FieldError("Action Message");

            if SupplyInvtProfile."Planning Flexibility" = SupplyInvtProfile."Planning Flexibility"::Unlimited then begin
                SupplyInvtProfile."Original Quantity" := SupplyInvtProfile.Quantity;
                SupplyInvtProfile."Max. Quantity" := SupplyInvtProfile."Remaining Quantity (Base)";
                SupplyInvtProfile."Quantity (Base)" := SupplyInvtProfile."Min. Quantity";
                SupplyInvtProfile."Remaining Quantity (Base)" := SupplyInvtProfile."Min. Quantity";
                SupplyInvtProfile."Untracked Quantity" := 0;

                if SupplyInvtProfile."Remaining Quantity (Base)" = 0 then
                    SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::Cancel
                else
                    SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::"Change Qty.";
                SupplyInvtProfile.Modify();

                MaintainPlanningLine(SupplyInvtProfile, DemandInvtProfile, PlanningLineStage::Exploded, ScheduleDirection::Backward);
                Track(SupplyInvtProfile, DemandInvtProfile, true, false, SupplyInvtProfile.Binding::" ");
                SupplyInvtProfile.Delete();

                Cancel := (SupplyInvtProfile."Action Message" = SupplyInvtProfile."Action Message"::Cancel);

                // IF supply is fully cancelled, demand is deleted, otherwise demand is modified:
                if Cancel then
                    DemandInvtProfile.Delete()
                else begin
                    DemandInvtProfile.Get(DemandInvtProfile."Line No."); // Get the updated version
                    DemandInvtProfile."Untracked Quantity" -= (DemandInvtProfile."Original Quantity" - DemandInvtProfile."Quantity (Base)");
                    DemandInvtProfile.Modify();
                end;
            end;
        end;
        SupplyInvtProfile.Copy(xSupply2);
    end;

    local procedure PostInvChgReminder(var TempReminderInvtProfile: Record "Inventory Profile" temporary; var InvProfile: Record "Inventory Profile"; PostOnlyMinimum: Boolean)
    begin
        // Update information on changes in the Projected Inventory over time
        // Only the quantity that is known for sure should be posted

        OnBeforePostInvChgReminder(TempReminderInvtProfile, InvProfile, PostOnlyMinimum);
        TempReminderInvtProfile := InvProfile;

        if PostOnlyMinimum then begin
            TempReminderInvtProfile."Remaining Quantity (Base)" -= InvProfile."Untracked Quantity";
            TempReminderInvtProfile."Remaining Quantity (Base)" += InvProfile."Safety Stock Quantity";
        end;

        if not TempReminderInvtProfile.Insert() then
            TempReminderInvtProfile.Modify();
        OnAfterPostInvChgReminder(TempReminderInvtProfile, InvProfile, PostOnlyMinimum);
    end;

    local procedure QtyFromPendingReminders(var TempReminderInvtProfile: Record "Inventory Profile" temporary; AtDate: Date; LatestBucketStartDate: Date) PendingQty: Decimal
    var
        xReminderInvtProfile: Record "Inventory Profile";
    begin
        // Calculates the sum of queued up adjustments to the projected inventory level
        xReminderInvtProfile.Copy(TempReminderInvtProfile);

        FilterDemandSupplyRelatedToSKU(TempReminderInvtProfile);
        TempReminderInvtProfile.SetRange("Due Date", LatestBucketStartDate, AtDate);
        if TempReminderInvtProfile.FindSet() then
            repeat
                if TempReminderInvtProfile.IsSupply then
                    PendingQty += TempReminderInvtProfile."Remaining Quantity (Base)"
                else
                    PendingQty -= TempReminderInvtProfile."Remaining Quantity (Base)";
            until TempReminderInvtProfile.Next() = 0;

        TempReminderInvtProfile.Copy(xReminderInvtProfile);
    end;

    local procedure MaintainProjectedInventory(var TempReminderInvtProfile: Record "Inventory Profile" temporary; AtDate: Date; var LastProjectedInventory: Decimal; var LatestBucketStartDate: Date; var ROPHasBeenCrossed: Boolean)
    var
        NextBucketEndDate: Date;
        NewProjectedInv: Decimal;
        SupplyIncrementQty: Decimal;
        DemandIncrementQty: Decimal;
        IsHandled: Boolean;
    begin
        // Updates information about projected inventory up until AtDate or until reorder point is crossed.
        // The check is performed within time buckets.
        IsHandled := false;
        OnBeforeMaintainProjectedInventory(
          TempReminderInvtProfile, AtDate, LastProjectedInventory, LatestBucketStartDate, ROPHasBeenCrossed, IsHandled);
        if IsHandled then
            exit;

        ROPHasBeenCrossed := false;
        LatestBucketStartDate := FindNextBucketStartDate(TempReminderInvtProfile, AtDate, LatestBucketStartDate);
        NextBucketEndDate := LatestBucketStartDate + BucketSizeInDays - 1;

        while (NextBucketEndDate < AtDate) and not ROPHasBeenCrossed do begin
            TempReminderInvtProfile.SetFilter("Due Date", '%1..%2', LatestBucketStartDate, NextBucketEndDate);
            SupplyIncrementQty := 0;
            DemandIncrementQty := 0;
            if TempReminderInvtProfile.FindSet() then
                repeat
                    if TempReminderInvtProfile.IsSupply then begin
                        if TempReminderInvtProfile."Order Relation" <> TempReminderInvtProfile."Order Relation"::"Safety Stock" then
                            SupplyIncrementQty += TempReminderInvtProfile."Remaining Quantity (Base)";
                    end else
                        DemandIncrementQty -= TempReminderInvtProfile."Remaining Quantity (Base)";
                    TempReminderInvtProfile.Delete();
                until TempReminderInvtProfile.Next() = 0;

            NewProjectedInv := LastProjectedInventory + SupplyIncrementQty + DemandIncrementQty;
            if FutureSupplyWithinLeadtime > SupplyIncrementQty then
                FutureSupplyWithinLeadtime -= SupplyIncrementQty
            else
                FutureSupplyWithinLeadtime := 0;
            ROPHasBeenCrossed :=
              (LastProjectedInventory + SupplyIncrementQty > TempSKU."Reorder Point") and
              (NewProjectedInv <= TempSKU."Reorder Point") or
              (NewProjectedInv + FutureSupplyWithinLeadtime <= TempSKU."Reorder Point");
            LastProjectedInventory := NewProjectedInv;
            if ROPHasBeenCrossed then
                LatestBucketStartDate := NextBucketEndDate + 1
            else
                LatestBucketStartDate := FindNextBucketStartDate(TempReminderInvtProfile, AtDate, LatestBucketStartDate);
            NextBucketEndDate := LatestBucketStartDate + BucketSizeInDays - 1;
        end;
    end;

    local procedure FindNextBucketStartDate(var TempReminderInvtProfile: Record "Inventory Profile" temporary; AtDate: Date; LatestBucketStartDate: Date) NextBucketStartDate: Date
    var
        NumberOfDaysToNextReminder: Integer;
    begin
        if AtDate = 0D then
            exit(LatestBucketStartDate);

        TempReminderInvtProfile.SetFilter("Due Date", '%1..%2', LatestBucketStartDate, AtDate);
        if TempReminderInvtProfile.FindFirst() then
            AtDate := TempReminderInvtProfile."Due Date";

        NumberOfDaysToNextReminder := AtDate - LatestBucketStartDate;
        NextBucketStartDate := AtDate - (NumberOfDaysToNextReminder mod BucketSizeInDays);
    end;

    local procedure SetIgnoreOverflow(var SupplyInvtProfile: Record "Inventory Profile")
    begin
        // Apply a minimum quantity to the existing orders to protect the
        // remaining valid surplus from being reduced in the common balancing act

        if SupplyInvtProfile.FindSet(true) then
            repeat
                SupplyInvtProfile."Min. Quantity" := SupplyInvtProfile."Remaining Quantity (Base)";
                SupplyInvtProfile.Modify();
            until SupplyInvtProfile.Next() = 0;
    end;

    local procedure ChkInitialOverflow(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; OverflowLevel: Decimal; InventoryLevel: Decimal; FromDate: Date; ToDate: Date)
    var
        xDemandInvtProfile: Record "Inventory Profile";
        xSupplyInvtProfile: Record "Inventory Profile";
        OverflowQty: Decimal;
        OriginalSupplyQty: Decimal;
        DecreasedSupplyQty: Decimal;
        PrevBucketStartDate: Date;
        PrevBucketEndDate: Date;
        CurrBucketStartDate: Date;
        CurrBucketEndDate: Date;
        NumberOfDaysToNextSupply: Integer;
    begin
        xDemandInvtProfile.Copy(DemandInvtProfile);
        xSupplyInvtProfile.Copy(SupplyInvtProfile);
        SupplyInvtProfile.SetRange("Is Exception Order", false);

        if OverflowLevel > 0 then begin
            // Detect if there is overflow in inventory within any time bucket
            // In that case: Decrease superfluous Supply; latest first
            // Apply a minimum quantity to the existing orders to protect the
            // remaining valid surplus from being reduced in the common balancing act

            // Avoid Safety Stock Demand
            DemandInvtProfile.SetRange("Order Relation", DemandInvtProfile."Order Relation"::Normal);

            PrevBucketStartDate := FromDate;
            CurrBucketEndDate := ToDate;

            while PrevBucketStartDate <= ToDate do begin
                SupplyInvtProfile.SetRange("Due Date", PrevBucketStartDate, ToDate);
                if SupplyInvtProfile.FindFirst() then begin
                    NumberOfDaysToNextSupply := SupplyInvtProfile."Due Date" - PrevBucketStartDate;
                    CurrBucketEndDate :=
                      SupplyInvtProfile."Due Date" - (NumberOfDaysToNextSupply mod BucketSizeInDays) + BucketSizeInDays - 1;
                    CurrBucketStartDate := CurrBucketEndDate - BucketSizeInDays + 1;
                    PrevBucketEndDate := CurrBucketStartDate - 1;

                    DemandInvtProfile.SetRange("Due Date", PrevBucketStartDate, PrevBucketEndDate);
                    DemandInvtProfile.CalcSums("Remaining Quantity (Base)");
                    InventoryLevel -= DemandInvtProfile."Remaining Quantity (Base)";

                    // Negative inventory from previous buckets shall not influence
                    // possible overflow in the current time bucket
                    if InventoryLevel < 0 then
                        InventoryLevel := 0;

                    DemandInvtProfile.SetRange("Due Date", CurrBucketStartDate, CurrBucketEndDate);
                    DemandInvtProfile.CalcSums("Remaining Quantity (Base)");
                    InventoryLevel -= DemandInvtProfile."Remaining Quantity (Base)";

                    SupplyInvtProfile.SetRange("Due Date", CurrBucketStartDate, CurrBucketEndDate);
                    if SupplyInvtProfile.Find('-') then begin
                        repeat
                            InventoryLevel += SupplyInvtProfile."Remaining Quantity (Base)";
                        until SupplyInvtProfile.Next() = 0;

                        OverflowQty := InventoryLevel - OverflowLevel;
                        repeat
                            if OverflowQty > 0 then begin
                                OriginalSupplyQty := SupplyInvtProfile."Quantity (Base)";
                                SupplyInvtProfile."Min. Quantity" := 0;
                                DecreaseQty(SupplyInvtProfile, OverflowQty, true);

                                // If the supply has not been decreased as planned, try to cancel it.
                                DecreasedSupplyQty := SupplyInvtProfile."Quantity (Base)";
                                if (DecreasedSupplyQty > 0) and (OriginalSupplyQty - DecreasedSupplyQty < OverflowQty) and
                                   (SupplyInvtProfile."Order Priority" < 1000)
                                then
                                    if CanDecreaseSupply(SupplyInvtProfile, OverflowQty) then
                                        DecreaseQty(SupplyInvtProfile, DecreasedSupplyQty, true);

                                if OriginalSupplyQty <> SupplyInvtProfile."Quantity (Base)" then begin
                                    DummyInventoryProfileTrackBuffer."Warning Level" := DummyInventoryProfileTrackBuffer."Warning Level"::Attention;
                                    PlanningTransparency.LogWarning(
                                      SupplyInvtProfile."Line No.", ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                                      StrSubstNo(Text010, InventoryLevel, OverflowLevel, CurrBucketEndDate));
                                    OverflowQty -= (OriginalSupplyQty - SupplyInvtProfile."Quantity (Base)");
                                    InventoryLevel -= (OriginalSupplyQty - SupplyInvtProfile."Quantity (Base)");
                                end;
                            end;
                            SupplyInvtProfile."Min. Quantity" := SupplyInvtProfile."Remaining Quantity (Base)";
                            SupplyInvtProfile.Modify();
                            if SupplyInvtProfile."Line No." = xSupplyInvtProfile."Line No." then
                                xSupplyInvtProfile := SupplyInvtProfile;
                        until (SupplyInvtProfile.Next(-1) = 0);
                    end;

                    if InventoryLevel < 0 then
                        InventoryLevel := 0;
                    PrevBucketStartDate := CurrBucketEndDate + 1;
                end else
                    PrevBucketStartDate := ToDate + 1;
            end;
        end else
            if OverflowLevel = 0 then
                SetIgnoreOverflow(SupplyInvtProfile);

        DemandInvtProfile.Copy(xDemandInvtProfile);
        SupplyInvtProfile.Copy(xSupplyInvtProfile);
    end;

    procedure CheckNewOverflow(var SupplyInvtProfile: Record "Inventory Profile"; InventoryLevel: Decimal; QtyToDecreaseOverFlow: Decimal; LastDueDate: Date)
    var
        xSupplyInvtProfile: Record "Inventory Profile";
        OriginalSupplyQty: Decimal;
        QtyToDecrease: Decimal;
    begin
        // the function tries to avoid overflow when a new supply was suggested
        xSupplyInvtProfile.Copy(SupplyInvtProfile);
        SupplyInvtProfile.SetRange("Due Date", LastDueDate + 1, PlanToDate);
        SupplyInvtProfile.SetFilter("Remaining Quantity (Base)", '>0');

        if SupplyInvtProfile.FindSet(true) then
            repeat
                if SupplyInvtProfile."Original Quantity" > 0 then
                    InventoryLevel := InventoryLevel + SupplyInvtProfile."Original Quantity" * SupplyInvtProfile."Qty. per Unit of Measure"
                else
                    InventoryLevel := InventoryLevel + SupplyInvtProfile."Remaining Quantity (Base)";
                OriginalSupplyQty := SupplyInvtProfile."Quantity (Base)";

                if InventoryLevel > OverflowLevel then begin
                    SupplyInvtProfile."Min. Quantity" := 0;
                    DummyInventoryProfileTrackBuffer."Warning Level" := DummyInventoryProfileTrackBuffer."Warning Level"::Attention;
                    QtyToDecrease := InventoryLevel - OverflowLevel;

                    if QtyToDecrease > QtyToDecreaseOverFlow then
                        QtyToDecrease := QtyToDecreaseOverFlow;

                    if QtyToDecrease > SupplyInvtProfile."Remaining Quantity (Base)" then
                        QtyToDecrease := SupplyInvtProfile."Remaining Quantity (Base)";

                    DecreaseQty(SupplyInvtProfile, QtyToDecrease, true);

                    PlanningTransparency.LogWarning(
                      SupplyInvtProfile."Line No.", ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                      StrSubstNo(Text010, InventoryLevel, OverflowLevel, SupplyInvtProfile."Due Date"));

                    QtyToDecreaseOverFlow := QtyToDecreaseOverFlow - (OriginalSupplyQty - SupplyInvtProfile."Quantity (Base)");
                    InventoryLevel := InventoryLevel - (OriginalSupplyQty - SupplyInvtProfile."Quantity (Base)");
                    SupplyInvtProfile."Min. Quantity" := SupplyInvtProfile."Remaining Quantity (Base)";
                    SupplyInvtProfile.Modify();
                end;
            until (SupplyInvtProfile.Next() = 0) or (QtyToDecreaseOverFlow <= 0);

        SupplyInvtProfile.Copy(xSupplyInvtProfile);
    end;

    local procedure CheckScheduleIn(var SupplyInvtProfile: Record "Inventory Profile"; TargetDate: Date; var PossibleDate: Date; LimitedHorizon: Boolean) Result: Boolean
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckScheduleIn(SupplyInvtProfile, TempSKU, TargetDate, PossibleDate, LimitedHorizon, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if SupplyInvtProfile."Planning Flexibility" <> SupplyInvtProfile."Planning Flexibility"::Unlimited then
            exit(false);

        if LimitedHorizon and not AllowScheduleIn(SupplyInvtProfile, TargetDate) then
            PossibleDate := SupplyInvtProfile."Due Date"
        else
            PossibleDate := TargetDate;

        exit(TargetDate = PossibleDate);
    end;

    local procedure CheckScheduleOut(var SupplyInvtProfile: Record "Inventory Profile"; TargetDate: Date; var PossibleDate: Date; LimitedHorizon: Boolean): Boolean
    var
        ShouldExitAllowLotAccumulation: Boolean;
        IsHandled: Boolean;
        Result: Boolean;
    begin
        OnBeforeCheckScheduleOut(SupplyInvtProfile, TempSKU, BucketSize, DampenersDays);

        if SupplyInvtProfile."Planning Flexibility" <> SupplyInvtProfile."Planning Flexibility"::Unlimited then
            exit(false);

        if (TargetDate - SupplyInvtProfile."Due Date") <= DampenersDays then begin
            if (TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Lot-for-Lot") and
               AllowLotAccumulation(SupplyInvtProfile, TargetDate) and
               (TargetDate > SupplyInvtProfile."Due Date") and
               (SupplyInvtProfile."Untracked Quantity" < TempSKU."Safety Stock Quantity")
            then
                exit(false)
            else
                PossibleDate := SupplyInvtProfile."Due Date";
        end else
            if not LimitedHorizon or
               (SupplyInvtProfile."Planning Level Code" > 0)
            then
                PossibleDate := TargetDate
            else
                if AllowScheduleOut(SupplyInvtProfile, TargetDate) then
                    PossibleDate := TargetDate
                else begin
                    // Do not reschedule but may be lot accumulation is still an option
                    PossibleDate := SupplyInvtProfile."Due Date";

                    IsHandled := false;
                    OnCheckScheduleOutOnBeforeAllowLotAccumulation(PossibleDate, TargetDate, SupplyInvtProfile, IsHandled, Result);
                    if IsHandled then
                        exit(Result);

                    ShouldExitAllowLotAccumulation := SupplyInvtProfile."Fixed Date" <> 0D;
                    OnCheckScheduleOutOnNotAllowScheduleOut(SupplyInvtProfile, ShouldExitAllowLotAccumulation);
                    if ShouldExitAllowLotAccumulation then
                        exit(AllowLotAccumulation(SupplyInvtProfile, TargetDate));

                    exit(false);
                end;

        // Limit possible rescheduling in case the supply is already linked up to another demand
        if (SupplyInvtProfile."Fixed Date" <> 0D) and
           (SupplyInvtProfile."Fixed Date" < PossibleDate)
        then begin
            if not AllowLotAccumulation(SupplyInvtProfile, TargetDate) then // but reschedule only if lot accumulation is allowed for target date
                exit(false);

            PossibleDate := SupplyInvtProfile."Fixed Date";
        end;

        exit(true);
    end;

    local procedure CheckSupplyWithSKU(var InventoryProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit")
    var
        xInventoryProfile: Record "Inventory Profile";
    begin
        xInventoryProfile.Copy(InventoryProfile);

        if SKU."Maximum Order Quantity" > 0 then
            if InventoryProfile.Find('-') then
                repeat
                    CheckUpdateInventoryProfileMaxQuantity(InventoryProfile, SKU);
                until InventoryProfile.Next() = 0;
        InventoryProfile.Copy(xInventoryProfile);
        if InventoryProfile.Get(InventoryProfile."Line No.") then;
    end;

    local procedure CheckUpdateInventoryProfileMaxQuantity(var InventoryProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit")
    begin
        OnBeforeCheckUpdateInventoryProfileMaxQuantity(InventoryProfile, SKU);

        if (SKU."Maximum Order Quantity" > InventoryProfile."Max. Quantity") and
               (InventoryProfile."Quantity (Base)" > 0) and
               (InventoryProfile."Max. Quantity" = 0)
            then begin
            InventoryProfile."Max. Quantity" := SKU."Maximum Order Quantity";
            InventoryProfile.Modify();
        end;
    end;

    procedure CreateSupplyForward(var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; var TempReminderInvtProfile: Record "Inventory Profile" temporary; AtDate: Date; ProjectedInventory: Decimal; var NewSupplyHasTakenOver: Boolean; CurrDueDate: Date)
    var
        TempSupplyInvtProfile: Record "Inventory Profile" temporary;
        CurrSupplyInvtProfile: Record "Inventory Profile";
        LeadTimeEndDate: Date;
        QtyToOrder: Decimal;
        QtyToOrderThisLine: Decimal;
        SupplyWithinLeadtime: Decimal;
        HasLooped: Boolean;
        CurrSupplyExists: Boolean;
        QtyToDecreaseOverFlow: Decimal;
    begin
        // Save current supply and check if it is real
        CurrSupplyInvtProfile := SupplyInvtProfile;
        CurrSupplyExists := SupplyInvtProfile.Find('=');

        // Initiate new supplyprofile
        InitSupply(TempSupplyInvtProfile, 0, AtDate, 0T);

        // Make sure VAR boolean is reset:
        NewSupplyHasTakenOver := false;
        QtyToOrder := CalcOrderQty(QtyToOrder, ProjectedInventory, TempSupplyInvtProfile."Line No.");

        // Use new supplyprofile to determine lead-time
        UpdateQty(TempSupplyInvtProfile, QtyToOrder + AdjustReorderQty(QtyToOrder, TempSKU, TempSupplyInvtProfile."Line No.", 0));
        TempSupplyInvtProfile.Insert();
        ScheduleForward(TempSupplyInvtProfile, DemandInvtProfile, AtDate);
        LeadTimeEndDate := TempSupplyInvtProfile."Due Date";

        // Find supply within leadtime, returns a qty
        TempReminderInvtProfile.SetRange(IsSupply, true);
        SupplyWithinLeadtime :=
          SumUpProjectedSupply(SupplyInvtProfile, AtDate, LeadTimeEndDate) +
          QtyFromPendingReminders(TempReminderInvtProfile, LeadTimeEndDate, AtDate);
        TempReminderInvtProfile.SetRange(IsSupply);
        FutureSupplyWithinLeadtime := SupplyWithinLeadtime;

        // If found supply + projinvlevel covers ROP then the situation has already been taken care of: roll back and (exit)
        if SupplyWithinLeadtime + ProjectedInventory > TempSKU."Reorder Point" then begin
            // Delete obsolete Planning Line
            MaintainPlanningLine(TempSupplyInvtProfile, DemandInvtProfile, PlanningLineStage::Obsolete, ScheduleDirection::Backward);
            PlanningTransparency.CleanLog(TempSupplyInvtProfile."Line No.");
            exit;
        end;

        // If found supply only covers ROP partialy, then we need to adjust quantity.
        if TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Fixed Reorder Qty." then
            if SupplyWithinLeadtime > 0 then begin
                QtyToOrder -= SupplyWithinLeadtime;
                if QtyToOrder < TempSKU."Reorder Quantity" then
                    QtyToOrder := TempSKU."Reorder Quantity";
                PlanningTransparency.ModifyPlanningLog(
                  TempSupplyInvtProfile."Line No.", 0, Database::Item, TempSKU."Item No.", -SupplyWithinLeadtime,
                  SurplusType::ReorderPoint);
            end;

        // If Max: Deduct found supply in order to stay below max inventory and adjust transparency log
        if TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Maximum Qty." then
            if SupplyWithinLeadtime <> 0 then begin
                QtyToOrder -= SupplyWithinLeadtime;
                PlanningTransparency.ModifyPlanningLog(
                  TempSupplyInvtProfile."Line No.", 0, Database::Item, TempSKU."Item No.", -SupplyWithinLeadtime,
                  SurplusType::MaxInventory);
            end;

        LeadTimeEndDate := AtDate;

        OnCreateSupplyForwardOnBeforeLoopQtyToOrderMoreThanZero(TempSKU, QtyToOrder, SupplyWithinLeadtime, TempSupplyInvtProfile);

        while QtyToOrder > 0 do begin
            // In case of max order the new supply could be split in several new supplies:
            if HasLooped then begin
                InitSupply(TempSupplyInvtProfile, 0, AtDate, 0T);
                case TempSKU."Reordering Policy" of
                    TempSKU."Reordering Policy"::"Maximum Qty.":
                        SurplusType := SurplusType::MaxInventory;
                    TempSKU."Reordering Policy"::"Fixed Reorder Qty.":
                        SurplusType := SurplusType::FixedOrderQty;
                end;
                PlanningTransparency.LogPlanningSurplus(TempSupplyInvtProfile."Line No.", 0, 0, '', QtyToOrder, SurplusType);
                QtyToOrderThisLine := QtyToOrder + AdjustReorderQty(QtyToOrder, TempSKU, TempSupplyInvtProfile."Line No.", 0);
                UpdateQty(TempSupplyInvtProfile, QtyToOrderThisLine);
                TempSupplyInvtProfile.Insert();
                ScheduleForward(TempSupplyInvtProfile, DemandInvtProfile, AtDate);
            end else begin
                QtyToOrderThisLine := QtyToOrder + AdjustReorderQty(QtyToOrder, TempSKU, TempSupplyInvtProfile."Line No.", 0);
                if QtyToOrderThisLine <> TempSupplyInvtProfile."Remaining Quantity (Base)" then begin
                    UpdateQty(TempSupplyInvtProfile, QtyToOrderThisLine);
                    ScheduleForward(TempSupplyInvtProfile, DemandInvtProfile, AtDate);
                end;
                HasLooped := true;
            end;

            // The supply is inserted into the overall supply dataset
            SupplyInvtProfile := TempSupplyInvtProfile;
            TempSupplyInvtProfile.Delete();
            SupplyInvtProfile."Min. Quantity" := SupplyInvtProfile."Remaining Quantity (Base)";
            SupplyInvtProfile."Max. Quantity" := TempSKU."Maximum Order Quantity";
            SupplyInvtProfile."Fixed Date" := SupplyInvtProfile."Due Date";
            SupplyInvtProfile."Order Priority" := 1000; // Make sure to give last priority if supply exists on the same date
            SupplyInvtProfile."Attribute Priority" := 1000;
            OnCreateSupplyForwardOnBeforeSupplyInvtProfileInsert(SupplyInvtProfile, TempSKU);
            SupplyInvtProfile.Insert();

            // Planning Transparency
            PlanningTransparency.LogPlanningSurplus(
              SupplyInvtProfile."Line No.", 0, 0, '', SupplyInvtProfile."Untracked Quantity", SurplusType::ReorderPoint);

            if SupplyInvtProfile."Due Date" < CurrDueDate then begin
                CurrSupplyInvtProfile := SupplyInvtProfile;
                CurrDueDate := SupplyInvtProfile."Due Date";
                NewSupplyHasTakenOver := true
            end;

            if LeadTimeEndDate < SupplyInvtProfile."Due Date" then
                LeadTimeEndDate := SupplyInvtProfile."Due Date";

            if (not CurrSupplyExists) or
               (SupplyInvtProfile."Due Date" < CurrSupplyInvtProfile."Due Date")
            then begin
                CurrSupplyInvtProfile := SupplyInvtProfile;
                CurrSupplyExists := true;
                NewSupplyHasTakenOver := CurrSupplyInvtProfile."Due Date" <= CurrDueDate;
            end;

            QtyToOrder -= SupplyInvtProfile."Remaining Quantity (Base)";
            FutureSupplyWithinLeadtime += SupplyInvtProfile."Remaining Quantity (Base)";
            QtyToDecreaseOverFlow += SupplyInvtProfile."Quantity (Base)";
        end;

        if HasLooped and (OverflowLevel > 0) then
            // the new supply might cause overflow in inventory since
            // it wasn't considered when Overflow was calculated
            CheckNewOverflow(SupplyInvtProfile, ProjectedInventory + QtyToDecreaseOverFlow, QtyToDecreaseOverFlow, LeadTimeEndDate);

        SupplyInvtProfile := CurrSupplyInvtProfile;
    end;

    local procedure AllowScheduleIn(SupplyInvtProfile: Record "Inventory Profile"; TargetDate: Date) CanReschedule: Boolean
    begin
        CanReschedule := CalcDate(TempSKU."Rescheduling Period", TargetDate) >= SupplyInvtProfile."Due Date";

        OnAfterAllowScheduleIn(SupplyInvtProfile, TargetDate, CanReschedule);
    end;

    local procedure AllowScheduleOut(SupplyInvtProfile: Record "Inventory Profile"; TargetDate: Date) CanReschedule: Boolean
    begin
        CanReschedule := CalcDate(TempSKU."Rescheduling Period", SupplyInvtProfile."Due Date") >= TargetDate;

        OnAfterAllowScheduleOut(SupplyInvtProfile, TargetDate, CanReschedule, TempSKU);
    end;

    local procedure AllowLotAccumulation(SupplyInvtProfile: Record "Inventory Profile"; DemandDueDate: Date) AccumulationOK: Boolean
    begin
        AccumulationOK := CalcDate(TempSKU."Lot Accumulation Period", SupplyInvtProfile."Due Date") >= DemandDueDate;
        OnAfterAllowLotAccumulation(SupplyInvtProfile, DemandDueDate, TempSKU, AccumulationOK);
    end;

    local procedure ShallSupplyBeClosed(SupplyInventoryProfile: Record "Inventory Profile"; DemandDueDate: Date; IsReorderPointPlanning: Boolean) CloseSupply: Boolean
    begin
        if SupplyInventoryProfile."Is Exception Order" then begin
            if TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Lot-for-Lot" then
                // supply within Lot Accumulation Period will be summed up with Exception order
                CloseSupply := not AllowLotAccumulation(SupplyInventoryProfile, DemandDueDate)
            else
                // only demand in the same day as Exception will be summed up
                CloseSupply := SupplyInventoryProfile."Due Date" <> DemandDueDate;
        end else
            CloseSupply := IsReorderPointPlanning;

        OnAfterShallSupplyBeClosed(TempSKU, SupplyInventoryProfile, DemandDueDate, IsReorderPointPlanning, CloseSupply);
    end;

    local procedure GetNextLineNo(): Integer
    begin
        LineNo += 1;
        exit(LineNo);
    end;

    local procedure Reschedule(var SupplyInvtProfile: Record "Inventory Profile"; TargetDate: Date; TargetTime: Time)
    begin
        SupplyInvtProfile.TestField("Planning Flexibility", SupplyInvtProfile."Planning Flexibility"::Unlimited);

        if (TargetDate <> SupplyInvtProfile."Due Date") and
           (SupplyInvtProfile."Action Message" <> SupplyInvtProfile."Action Message"::New)
        then begin
            if SupplyInvtProfile."Original Due Date" = 0D then
                SupplyInvtProfile."Original Due Date" := SupplyInvtProfile."Due Date";
            UpdateActionMessageOnReschedule(SupplyInvtProfile);
        end;
        SupplyInvtProfile."Due Date" := TargetDate;
        if (SupplyInvtProfile."Due Time" = 0T) or
           (SupplyInvtProfile."Due Time" > TargetTime)
        then
            SupplyInvtProfile."Due Time" := TargetTime;
        OnRescheduleOnBeforeModifySupplyInvtProfile(SupplyInvtProfile, TargetDate, TargetTime);
        SupplyInvtProfile.Modify();
    end;

    local procedure UpdateActionMessageOnReschedule(var SupplyInvtProfile: Record "Inventory Profile")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateActionMessageOnReschedule(SupplyInvtProfile, IsHandled);
        if IsHandled then
            exit;

        if SupplyInvtProfile."Original Quantity" = 0 then
            SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::Reschedule
        else
            SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::"Resched. & Chg. Qty.";

    end;

    procedure InitSupply(var SupplyInvtProfile: Record "Inventory Profile"; OrderQty: Decimal; DueDate: Date; DueTime: Time)
    var
        Item: Record Item;
        ItemUnitOfMeasure: Record "Item Unit of Measure";
    begin
        SupplyInvtProfile.Init();
        SupplyInvtProfile."Line No." := GetNextLineNo();
        SupplyInvtProfile."Item No." := TempSKU."Item No.";
        SupplyInvtProfile."Variant Code" := TempSKU."Variant Code";
        SupplyInvtProfile."Location Code" := TempSKU."Location Code";
        SupplyInvtProfile."Action Message" := SupplyInvtProfile."Action Message"::New;
        UpdateQty(SupplyInvtProfile, OrderQty);
        SupplyInvtProfile."Due Date" := DueDate;
        SupplyInvtProfile."Due Time" := DueTime;
        SupplyInvtProfile.IsSupply := true;
        Item.Get(TempSKU."Item No.");
        SupplyInvtProfile."Unit of Measure Code" := Item."Base Unit of Measure";
        SupplyInvtProfile."Qty. per Unit of Measure" := 1;

        case TempSKU."Replenishment System" of
            TempSKU."Replenishment System"::Purchase:
                begin
                    SupplyInvtProfile."Source Type" := Database::"Purchase Line";
                    SupplyInvtProfile."Unit of Measure Code" := Item."Purch. Unit of Measure";
                    if SupplyInvtProfile."Unit of Measure Code" <> Item."Base Unit of Measure" then begin
                        ItemUnitOfMeasure.Get(TempSKU."Item No.", Item."Purch. Unit of Measure");
                        SupplyInvtProfile."Qty. per Unit of Measure" := ItemUnitOfMeasure."Qty. per Unit of Measure";
                    end;
                end;
            TempSKU."Replenishment System"::"Prod. Order":
                SupplyInvtProfile."Source Type" := 5406; // Database::"Prod. Order Line"
            TempSKU."Replenishment System"::Transfer:
                SupplyInvtProfile."Source Type" := Database::"Transfer Line";
        end;

        OnAfterInitSupply(SupplyInvtProfile, TempSKU, Item);
    end;

    local procedure UpdateQty(var InvProfile: Record "Inventory Profile"; Qty: Decimal)
    begin
        InvProfile."Untracked Quantity" := Qty;
        InvProfile."Quantity (Base)" := InvProfile."Untracked Quantity";
        InvProfile."Remaining Quantity (Base)" := InvProfile."Quantity (Base)";
    end;

    local procedure TransferAttributes(var ToInvProfile: Record "Inventory Profile"; var FromInvProfile: Record "Inventory Profile")
    begin
        if SpecificLotTracking then
            ToInvProfile."Lot No." := FromInvProfile."Lot No.";
        if SpecificSNTracking then
            ToInvProfile."Serial No." := FromInvProfile."Serial No.";

        if TempSKU."Replenishment System" = TempSKU."Replenishment System"::"Prod. Order" then
            if FromInvProfile."Planning Level Code" > 0 then begin
                ToInvProfile.Binding := ToInvProfile.Binding::"Order-to-Order";
                ToInvProfile."Planning Level Code" := FromInvProfile."Planning Level Code";
                ToInvProfile."Due Time" := FromInvProfile."Due Time";
                ToInvProfile."Bin Code" := FromInvProfile."Bin Code";
            end;

        if FromInvProfile.Binding = FromInvProfile.Binding::"Order-to-Order" then begin
            ToInvProfile.Binding := ToInvProfile.Binding::"Order-to-Order";
            ToInvProfile."Primary Order Status" := FromInvProfile."Primary Order Status";
            ToInvProfile."Primary Order No." := FromInvProfile."Primary Order No.";
            ToInvProfile."Primary Order Line" := FromInvProfile."Primary Order Line";
        end;

        ToInvProfile."MPS Order" := FromInvProfile."MPS Order";

        if ToInvProfile.TrackingExists() then
            ToInvProfile."Planning Flexibility" := ToInvProfile."Planning Flexibility"::None;

        OnAfterTransferAttributes(ToInvProfile, FromInvProfile, TempSKU, SpecificLotTracking, SpecificSNTracking);
    end;

    local procedure AllocateSafetystock(var SupplyInvtProfile: Record "Inventory Profile"; QtyToAllocate: Decimal; AtDate: Date)
    var
        MinQtyToCoverSafetyStock: Decimal;
    begin
        if QtyToAllocate > SupplyInvtProfile."Safety Stock Quantity" then begin
            SupplyInvtProfile."Safety Stock Quantity" := QtyToAllocate;
            MinQtyToCoverSafetyStock :=
              SupplyInvtProfile."Remaining Quantity (Base)" -
              SupplyInvtProfile."Untracked Quantity" + SupplyInvtProfile."Safety Stock Quantity";
            if SupplyInvtProfile."Min. Quantity" < MinQtyToCoverSafetyStock then
                SupplyInvtProfile."Min. Quantity" := MinQtyToCoverSafetyStock;
            if SupplyInvtProfile."Min. Quantity" > SupplyInvtProfile."Remaining Quantity (Base)" then
                Error(Text001, SupplyInvtProfile.FieldCaption("Safety Stock Quantity"));
            if (SupplyInvtProfile."Fixed Date" = 0D) or (SupplyInvtProfile."Fixed Date" > AtDate) then
                SupplyInvtProfile."Fixed Date" := AtDate;
            SupplyInvtProfile.Modify();
        end;
    end;

    procedure SumUpProjectedSupply(var SupplyInvtProfile: Record "Inventory Profile"; FromDate: Date; ToDate: Date) ProjectedQty: Decimal
    var
        xSupplyInvtProfile: Record "Inventory Profile";
    begin
        // Sums up the contribution to the projected inventory
        OnBeforeSumUpProjectedSupply(SupplyInvtProfile, FromDate, ToDate);

        xSupplyInvtProfile.Copy(SupplyInvtProfile);
        SupplyInvtProfile.SetRange("Due Date", FromDate, ToDate);

        if SupplyInvtProfile.FindSet() then
            repeat
                if (SupplyInvtProfile.Binding <> SupplyInvtProfile.Binding::"Order-to-Order") and
                   (SupplyInvtProfile."Order Relation" <> SupplyInvtProfile."Order Relation"::"Safety Stock")
                then
                    ProjectedQty += SupplyInvtProfile."Remaining Quantity (Base)";
            until SupplyInvtProfile.Next() = 0;

        SupplyInvtProfile.Copy(xSupplyInvtProfile);
    end;

    local procedure SumUpAvailableSupply(var SupplyInvtProfile: Record "Inventory Profile"; FromDate: Date; ToDate: Date) AvailableQty: Decimal
    var
        xSupplyInvtProfile: Record "Inventory Profile";
    begin
        // Sums up the contribution to the available inventory
        OnBeforeSumUpAvailableSupply(SupplyInvtProfile, FromDate, ToDate);

        xSupplyInvtProfile.Copy(SupplyInvtProfile);
        SupplyInvtProfile.SetRange("Due Date", FromDate, ToDate);

        SupplyInvtProfile.CalcSums("Untracked Quantity");
        AvailableQty += SupplyInvtProfile."Untracked Quantity";

        SupplyInvtProfile.Copy(xSupplyInvtProfile);
    end;

    local procedure SetPriority(var InventoryProfile: Record "Inventory Profile"; IsReorderPointPlanning: Boolean; ToDate: Date)
    begin
        if InventoryProfile.IsSupply then begin
            if InventoryProfile."Due Date" > ToDate then
                InventoryProfile."Planning Flexibility" := InventoryProfile."Planning Flexibility"::None;

            if IsReorderPointPlanning and (InventoryProfile.Binding <> InventoryProfile.Binding::"Order-to-Order") and
               (InventoryProfile."Planning Flexibility" <> InventoryProfile."Planning Flexibility"::None)
            then
                InventoryProfile."Planning Flexibility" := InventoryProfile."Planning Flexibility"::"Reduce Only";
            SetSupplyPriority(InventoryProfile);
        end else
            SetDemandPriority(InventoryProfile);

        OnAfterSetOrderPriority(InventoryProfile);

        InventoryProfile.TestField("Order Priority");
        // Inflexible supply must be handled before all other supply and is therefore grouped
        // together with inventory in group 100:
        if InventoryProfile.IsSupply and (InventoryProfile."Source Type" <> Database::"Item Ledger Entry") then
            if InventoryProfile."Planning Flexibility" <> InventoryProfile."Planning Flexibility"::Unlimited then
                InventoryProfile."Order Priority" := 100 + (InventoryProfile."Order Priority" / 10);

        if InventoryProfile."Planning Flexibility" = InventoryProfile."Planning Flexibility"::Unlimited then
            if InventoryProfile.ActiveInWarehouse() then
                InventoryProfile."Order Priority" -= 1;

        SetAttributePriority(InventoryProfile);

        InventoryProfile.Modify();
    end;

    local procedure SetSupplyPriority(var InventoryProfile: Record "Inventory Profile")
    begin
        case InventoryProfile."Source Type" of
            Database::"Item Ledger Entry":
                InventoryProfile."Order Priority" := 100;
            Database::"Transfer Line":
                InventoryProfile."Order Priority" := 300;
        end;

        OnAfterSetSupplyPriority(InventoryProfile);
    end;

    local procedure SetDemandPriority(var InventoryProfile: Record "Inventory Profile")
    begin
        case InventoryProfile."Source Type" of
            Database::"Item Ledger Entry":
                InventoryProfile."Order Priority" := 100;
            Database::"Transfer Line":
                InventoryProfile."Order Priority" := 600;
            Database::Microsoft.Manufacturing.Forecast."Production Forecast Entry":
                InventoryProfile."Order Priority" := 800;
        end;

        OnAfterSetDemandPriority(InventoryProfile);
    end;

    local procedure SetAttributePriority(var InvProfile: Record "Inventory Profile")
    var
        HandleLot: Boolean;
        HandleSN: Boolean;
    begin
        HandleSN := (InvProfile."Serial No." <> '') and SpecificSNTracking;
        HandleLot := (InvProfile."Lot No." <> '') and SpecificLotTracking;

        if HandleSN then begin
            if HandleLot then
                if InvProfile.Binding = InvProfile.Binding::"Order-to-Order" then
                    InvProfile."Attribute Priority" := 1
                else
                    InvProfile."Attribute Priority" := 4
            else
                if InvProfile.Binding = InvProfile.Binding::"Order-to-Order" then
                    InvProfile."Attribute Priority" := 2
                else
                    InvProfile."Attribute Priority" := 5;
        end else
            if HandleLot then
                if InvProfile.Binding = InvProfile.Binding::"Order-to-Order" then
                    InvProfile."Attribute Priority" := 3
                else
                    InvProfile."Attribute Priority" := 6
            else
                if InvProfile.Binding = InvProfile.Binding::"Order-to-Order" then
                    InvProfile."Attribute Priority" := 7
                else
                    InvProfile."Attribute Priority" := 8;
    end;

    local procedure UpdatePriorities(var InvProfile: Record "Inventory Profile"; IsReorderPointPlanning: Boolean; ToDate: Date)
    var
        xInvProfile: Record "Inventory Profile";
    begin
        xInvProfile.Copy(InvProfile);
        InvProfile.SetCurrentKey("Line No.");
        if InvProfile.FindSet(true) then
            repeat
                SetPriority(InvProfile, IsReorderPointPlanning, ToDate);
            until InvProfile.Next() = 0;
        InvProfile.Copy(xInvProfile);
    end;

    local procedure InsertSafetyStockDemands(var DemandInvtProfile: Record "Inventory Profile"; PlanningStartDate: Date)
    var
        xDemandInvtProfile: Record "Inventory Profile";
        TempSafetyStockInvtProfile: Record "Inventory Profile" temporary;
        OrderRelation: Option Normal,"Safety Stock","Reorder Point";
    begin
        if TempSKU."Safety Stock Quantity" = 0 then
            exit;

        xDemandInvtProfile.Copy(DemandInvtProfile);

        OnInsertSafetyStockDemandsOnBeforeCreateDemand(DemandInvtProfile, PlanningStartDate, TempSKU);

        DemandInvtProfile.SetCurrentKey(
          "Item No.", "Variant Code", "Location Code", "Due Date", "Attribute Priority", "Order Priority");
        DemandInvtProfile.SetFilter("Due Date", '%1..', PlanningStartDate);
        if DemandInvtProfile.FindSet() then
            repeat
                if TempSafetyStockInvtProfile."Due Date" <> DemandInvtProfile."Due Date" then begin
                    CreateDemand(
                        TempSafetyStockInvtProfile, TempSKU, TempSKU."Safety Stock Quantity", DemandInvtProfile."Due Date", OrderRelation::"Safety Stock");
                    TempSafetyStockInvtProfile."MPS Order" := DemandInvtProfile."MPS Order";
                    TempSafetyStockInvtProfile.Modify();
                end;
            until DemandInvtProfile.Next() = 0;

        DemandInvtProfile.SetRange("Due Date", PlanningStartDate);
        if DemandInvtProfile.IsEmpty() then
            CreateDemand(
              TempSafetyStockInvtProfile, TempSKU, TempSKU."Safety Stock Quantity", PlanningStartDate, OrderRelation::"Safety Stock");

        if TempSafetyStockInvtProfile.FindSet(true) then
            repeat
                DemandInvtProfile := TempSafetyStockInvtProfile;
                DemandInvtProfile."Order Priority" := 1000;
                DemandInvtProfile.Insert();
            until TempSafetyStockInvtProfile.Next() = 0;

        DemandInvtProfile.Copy(xDemandInvtProfile);

        OnAfterInsertSafetyStockDemands(
          DemandInvtProfile, xDemandInvtProfile, TempSafetyStockInvtProfile, TempSKU, PlanningStartDate, PlanToDate);
    end;

    local procedure ScheduleAllOutChangesSequence(var SupplyInvtProfile: Record "Inventory Profile"; NewDate: Date): Boolean
    var
        TempRescheduledSupplyInvtProfile: Record "Inventory Profile" temporary;
        NumberofSupplies: Integer;
        NextRecExists: Integer;
        SavedPosition: Integer;
        IsHandled: Boolean;
    begin
        SavedPosition := SupplyInvtProfile."Line No.";
        if (SupplyInvtProfile."Due Date" = 0D) or
           (SupplyInvtProfile."Planning Flexibility" <> SupplyInvtProfile."Planning Flexibility"::Unlimited)
        then
            exit(false);

        if not AllowScheduleOut(SupplyInvtProfile, NewDate) then
            exit(false);

        NextRecExists := 1;

        // check if reschedule is needed
        IsHandled := false;
        OnScheduleAllOutChangesSequenceOnBeforeCheckIfRescheduleIsNeeded(SupplyInvtProfile, NextRecExists, IsHandled, NewDate, NumberofSupplies);
        if not IsHandled then
            while (SupplyInvtProfile."Due Date" < NewDate) and
                  (SupplyInvtProfile."Action Message" <> SupplyInvtProfile."Action Message"::New) and
                  (SupplyInvtProfile."Planning Flexibility" = SupplyInvtProfile."Planning Flexibility"::Unlimited) and
                  (SupplyInvtProfile."Fixed Date" = 0D) and
                  (NextRecExists <> 0)
            do begin
                NumberofSupplies += 1;
                TempRescheduledSupplyInvtProfile := SupplyInvtProfile;
                TempRescheduledSupplyInvtProfile.Insert();
                Reschedule(TempRescheduledSupplyInvtProfile, NewDate, 0T);

                NextRecExists := SupplyInvtProfile.Next();
            end;

        // if there is only one supply before the demand we roll back
        if NumberofSupplies <= 1 then
            if not ((NextRecExists <> 0) and (SupplyInvtProfile."Due Date" = NewDate) and (SupplyInvtProfile."Line No." < SavedPosition)) then begin
                SupplyInvtProfile.Get(SavedPosition);
                exit(false);
            end;

        TempRescheduledSupplyInvtProfile.SetCurrentKey(
          "Item No.", "Variant Code", "Location Code", "Due Date", "Attribute Priority", "Order Priority");

        // If we have resheduled we replace the original supply records with the resceduled ones,
        // we re-write the primary key to make sure that the supplies are handled in the right order.
        if TempRescheduledSupplyInvtProfile.FindSet() then begin
            if (NextRecExists <> 0) and (SupplyInvtProfile."Due Date" = NewDate) then
                SavedPosition := SupplyInvtProfile."Line No."
            else
                SavedPosition := 0;

            repeat
                SupplyInvtProfile := TempRescheduledSupplyInvtProfile;
                SupplyInvtProfile.Delete();
                SupplyInvtProfile."Line No." := GetNextLineNo();
                OnScheduleAllOutChangesSequenceOnBeforeSupplyInvtProfileInsert(SupplyInvtProfile);
                SupplyInvtProfile.Insert();
                if SavedPosition = 0 then
                    SavedPosition := SupplyInvtProfile."Line No.";
            until TempRescheduledSupplyInvtProfile.Next() = 0;

            SupplyInvtProfile.Get(SavedPosition);
        end;

        exit(true);
    end;

    local procedure PrepareOrderToOrderLink(var InventoryProfile: Record "Inventory Profile")
    var
        IsHandled: Boolean;
    begin
        // Prepare new demand for order-to-order planning
        if InventoryProfile.FindSet(true) then
            repeat
                if not InventoryProfile.IsSupply and
                    (not (InventoryProfile."Source Type" = Database::Microsoft.Manufacturing.Forecast."Production Forecast Entry")) and
                    (not ((InventoryProfile."Source Type" = Database::"Sales Line") and (InventoryProfile."Source Order Status" = 4))) and
                    ((TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::Order) or (InventoryProfile."Planning Level Code" <> 0))
                then begin
                    if InventoryProfile."Source Type" = Database::"Planning Component" then
                        // Primary Order references have already been set on Component Lines
                        InventoryProfile.Binding := InventoryProfile.Binding::"Order-to-Order"
                    else begin
                        InventoryProfile.Binding := InventoryProfile.Binding::"Order-to-Order";
                        InventoryProfile."Primary Order Type" := InventoryProfile."Source Type";
                        InventoryProfile."Primary Order Status" := InventoryProfile."Source Order Status";
                        InventoryProfile."Primary Order No." := InventoryProfile."Source ID";
                        if InventoryProfile."Source Type" <> 5407 then // Database::"Prod. Order Component"
                            InventoryProfile."Primary Order Line" := InventoryProfile."Source Ref. No."
                        else
                            InventoryProfile."Primary Order Line" := InventoryProfile."Source Prod. Order Line";
                    end;
                    IsHandled := false;
                    OnPrepareOrderToOrderLinkOnBeforeInventoryProfileModify(InventoryProfile, TempSKU, IsHandled);
                    if not IsHandled then
                        InventoryProfile.Modify();
                end;
            until InventoryProfile.Next() = 0;
    end;

    local procedure SetAcceptAction(ItemNo: Code[20])
    var
        ReqLine: Record "Requisition Line";
        PurchHeader: Record "Purchase Header";
        TransHeader: Record "Transfer Header";
        ReqWkshTempl: Record "Req. Wksh. Template";
        AcceptActionMsg: Boolean;
        IsHandled: Boolean;
    begin
        ReqWkshTempl.Get(CurrTemplateName);
        if ReqWkshTempl.Type <> ReqWkshTempl.Type::Planning then
            exit;
        ReqLine.SetCurrentKey("Worksheet Template Name", "Journal Batch Name", Type, "No.");
        ReqLine.SetRange("Worksheet Template Name", CurrTemplateName);
        ReqLine.SetRange("Journal Batch Name", CurrWorksheetName);
        ReqLine.SetRange(Type, ReqLine.Type::Item);
        ReqLine.SetRange("No.", ItemNo);
        DummyInventoryProfileTrackBuffer."Warning Level" := DummyInventoryProfileTrackBuffer."Warning Level"::Attention;

        if ReqLine.FindSet(true) then
            repeat
                AcceptActionMsg := ReqLine."Starting Date" >= WorkDate();
                if not AcceptActionMsg then
                    PlanningTransparency.LogWarning(0, ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                      StrSubstNo(Text008, DummyInventoryProfileTrackBuffer."Warning Level", ReqLine.FieldCaption(ReqLine."Starting Date"),
                        ReqLine."Starting Date", WorkDate()));

                if ReqLine."Action Message" <> ReqLine."Action Message"::New then
                    case ReqLine."Ref. Order Type" of
                        ReqLine."Ref. Order Type"::Purchase:
                            if (PurchHeader.Get(PurchHeader."Document Type"::Order, ReqLine."Ref. Order No.") and
                                (PurchHeader.Status = PurchHeader.Status::Released))
                            then begin
                                AcceptActionMsg := false;
                                PlanningTransparency.LogWarning(
                                    0, ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                                    StrSubstNo(Text009,
                                        DummyInventoryProfileTrackBuffer."Warning Level", ReqLine."Ref. Order Type",
                                        ReqLine."Ref. Order No.", PurchHeader.Status));
                            end;
                        ReqLine."Ref. Order Type"::"Prod. Order":
                            if ReqLine."Ref. Order Status" = ReqLine."Ref. Order Status"::Released then begin
                                AcceptActionMsg := false;
                                PlanningTransparency.LogWarning(
                                    0, ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                                    StrSubstNo(Text009,
                                        DummyInventoryProfileTrackBuffer."Warning Level", ReqLine."Ref. Order Type",
                                        ReqLine."Ref. Order No.", ReqLine."Ref. Order Status"));
                            end;
                        ReqLine."Ref. Order Type"::Transfer:
                            begin
                                IsHandled := false;
                                OnSetAcceptActionOnCaseRefOrderTypeTransfer(ReqLine, AcceptActionMsg, IsHandled);
                                if not IsHandled then
                                    if (TransHeader.Get(ReqLine."Ref. Order No.") and (TransHeader.Status = TransHeader.Status::Released)) then begin
                                        AcceptActionMsg := false;
                                        PlanningTransparency.LogWarning(
                                            0, ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
                                            StrSubstNo(Text009,
                                                DummyInventoryProfileTrackBuffer."Warning Level", ReqLine."Ref. Order Type",
                                                ReqLine."Ref. Order No.", TransHeader.Status));
                                    end;
                            end;
                    end;

                OnSetAcceptActionOnBeforeAcceptActionMsg(ReqLine, AcceptActionMsg, PlanningTransparency);

                if AcceptActionMsg then
                    AcceptActionMsg := PlanningTransparency.ReqLineWarningLevel(ReqLine) = 0;

                if not AcceptActionMsg then begin
                    ReqLine."Accept Action Message" := false;
                    ReqLine.Modify();
                end;
            until ReqLine.Next() = 0;
    end;

    procedure GetRouting(var ReqLine2: Record "Requisition Line")
    begin
        OnGetRouting(ReqLine2);
    end;

    procedure GetComponents(var ReqLine2: Record "Requisition Line")
    begin
        ReqLine.BlockDynamicTracking(true);
        if ReqLine."Action Message" = ReqLine."Action Message"::New then
            OnGetComponentsOnNewActionMessage(ReqLine)
        else
            OnGetComponentsOnUpdateForActionMessage(ReqLine);

        OnGetComponents(ReqLine2);
    end;

    procedure Recalculate(var ReqLine: Record "Requisition Line"; Direction: Option Forward,Backward; RefreshRouting: Boolean)
    begin
        Clear(PlanningLineManagement);
        if PlanningResiliency then
            PlanningLineManagement.SetResiliencyOn(ReqLine."Worksheet Template Name", ReqLine."Journal Batch Name", ReqLine."No.");
        PlanningLineManagement.BlockDynamicTracking(true);
        OnGetRoutingOnAfterSetResiliencyOn(ReqLine);

        PlanningLineManagement.Calculate(
            ReqLine, Direction, RefreshRouting,
            (ReqLine."Action Message" = ReqLine."Action Message"::New) and
            (ReqLine."Ref. Order Type" in [ReqLine."Ref. Order Type"::"Prod. Order", ReqLine."Ref. Order Type"::Assembly]), -1);
        OnAfterRecalculateReqLine(ReqLine);
        if ReqLine."Action Message" = ReqLine."Action Message"::New then
            PlanningLineManagement.GetPlanningCompList(TempPlanningCompList);
    end;

    procedure GetPlanningCompList(var PlanningCompList: Record "Planning Component" temporary)
    begin
        TempPlanningCompList.Reset();
        if TempPlanningCompList.Find('-') then
            repeat
                PlanningCompList := TempPlanningCompList;
                if not PlanningCompList.Insert() then
                    PlanningCompList.Modify();
                TempPlanningCompList.Delete();
            until TempPlanningCompList.Next() = 0;
    end;

    local procedure DeletePlanningCompList(RequisitionLine: Record "Requisition Line")
    begin
        TempPlanningCompList.SetRange("Worksheet Template Name", RequisitionLine."Worksheet Template Name");
        TempPlanningCompList.SetRange("Worksheet Batch Name", RequisitionLine."Journal Batch Name");
        TempPlanningCompList.SetRange("Worksheet Line No.", RequisitionLine."Line No.");
        TempPlanningCompList.DeleteAll();
    end;

    procedure SetParm(Forecast: Code[10]; ExclBefore: Date; WorksheetType: Option Requisition,Planning; PriceCalcMethod: Enum "Price Calculation Method")
    begin
        SetParm(Forecast, ExclBefore, WorksheetType);
        PriceCalculationMethod := PriceCalcMethod;
    end;

    procedure SetParm(Forecast: Code[10]; ExclBefore: Date; WorksheetType: Option Requisition,Planning)
    begin
        CurrForecast := Forecast;
        ExcludeForecastBefore := ExclBefore;
        UseParm := true;
        CurrWorksheetType := WorksheetType;
    end;

    procedure SetResiliencyOn()
    begin
        PlanningResiliency := true;
    end;

    /// <summary>
    /// Gets the policy whether planning should be skipped for missing SKU policy.
    /// </summary>
    /// <returns>true if planning should be skipped for missing SKU policy otherwise, false.</returns>
    procedure GetPlanningSkippedForMissingSKUPolicy(): Boolean
    begin
        exit(PlanningSkippedForMissingSKUPolicy);
    end;

    procedure GetResiliencyError(var PlanningErrorLog: Record "Planning Error Log"): Boolean
    begin
        if ReqLine.GetResiliencyError(PlanningErrorLog) then
            exit(true);
        exit(PlanningLineManagement.GetResiliencyError(PlanningErrorLog));
    end;

    /// <summary>
    /// Gets all resiliency errors from the planning error log.
    /// </summary>
    /// <param name="PlanningErrorLog">The planning error log record to populate with errors.</param>
    /// <returns>true if there are resiliency errors; otherwise, false.</returns>
    procedure GetResiliencyErrors(var PlanningErrorLog: Record "Planning Error Log"): Boolean
    begin
        if ReqLine.GetResiliencyErrors(PlanningErrorLog) then
            exit(true);
        exit(PlanningLineManagement.GetResiliencyError(PlanningErrorLog));
    end;

    local procedure CloseTracking(ReservEntry: Record "Reservation Entry"; var SupplyInventoryProfile: Record "Inventory Profile"; ToDate: Date): Boolean
    var
        xSupplyInventoryProfile: Record "Inventory Profile";
        ReservationEngineMgt: Codeunit "Reservation Engine Mgt.";
        Closed: Boolean;
    begin
        if ReservEntry."Reservation Status" <> ReservEntry."Reservation Status"::Tracking then
            exit(false);

        xSupplyInventoryProfile.Copy(SupplyInventoryProfile);
        Closed := false;

        if (ReservEntry."Expected Receipt Date" <= ToDate) and
           (ReservEntry."Shipment Date" > ToDate)
        then begin
            // tracking exists with demand in future
            SupplyInventoryProfile.SetCurrentKey(
              "Source Type", "Source Order Status", "Source ID", "Source Batch Name", "Source Ref. No.", "Source Prod. Order Line", IsSupply,
              "Due Date");
            SupplyInventoryProfile.SetRange("Source Type", ReservEntry."Source Type");
            SupplyInventoryProfile.SetRange("Source Order Status", ReservEntry."Source Subtype");
            SupplyInventoryProfile.SetRange("Source ID", ReservEntry."Source ID");
            SupplyInventoryProfile.SetRange("Source Batch Name", ReservEntry."Source Batch Name");
            SupplyInventoryProfile.SetRange("Source Ref. No.", ReservEntry."Source Ref. No.");
            SupplyInventoryProfile.SetRange("Source Prod. Order Line", ReservEntry."Source Prod. Order Line");
            SupplyInventoryProfile.SetRange("Due Date", 0D, ToDate);

            if not SupplyInventoryProfile.IsEmpty() then begin
                // demand is either deleted as well or will get Surplus status
                ReservationEngineMgt.CloseReservEntry(ReservEntry, false, false);
                Closed := true;
            end;
        end;

        SupplyInventoryProfile.Copy(xSupplyInventoryProfile);
        exit(Closed);
    end;

    procedure FrozenZoneTrack(FromInventoryProfile: Record "Inventory Profile"; ToInventoryProfile: Record "Inventory Profile")
    begin
        if FromInventoryProfile.TrackingExists() then
            Track(FromInventoryProfile, ToInventoryProfile, true, false, FromInventoryProfile.Binding::" ");

        if ToInventoryProfile.TrackingExists() then begin
            ToInventoryProfile."Untracked Quantity" := FromInventoryProfile."Untracked Quantity";
            ToInventoryProfile."Quantity (Base)" := FromInventoryProfile."Untracked Quantity";
            ToInventoryProfile."Original Quantity" := 0;
            Track(ToInventoryProfile, FromInventoryProfile, true, false, ToInventoryProfile.Binding::" ");
        end;
    end;

    local procedure ExceedROPinException(RespectPlanningParm: Boolean): Boolean
    begin
        if not RespectPlanningParm then
            exit(false);

        exit(TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Fixed Reorder Qty.");
    end;

    local procedure CreateSupplyForInitialSafetyStockWarning(var SupplyInventoryProfile: Record "Inventory Profile"; ProjectedInventory: Decimal; var LastProjectedInventory: Decimal; var LastAvailableInventory: Decimal; PlanningStartDate: Date; RespectPlanningParm: Boolean; IsReorderPointPlanning: Boolean)
    var
        OrderQty: Decimal;
        ReorderQty: Decimal;
    begin
        OnBeforeCreateSupplyForInitialSafetyStockWarning(PlanningStartDate, SupplyInventoryProfile);
        OrderQty := TempSKU."Safety Stock Quantity" - ProjectedInventory;
        if ExceedROPinException(RespectPlanningParm) then
            OrderQty := TempSKU."Reorder Point" - ProjectedInventory;

        ReorderQty := OrderQty;

        repeat
            InitSupply(SupplyInventoryProfile, ReorderQty, PlanningStartDate, 0T);
            if RespectPlanningParm then begin
                if IsReorderPointPlanning then
                    ReorderQty := CalcOrderQty(ReorderQty, ProjectedInventory, SupplyInventoryProfile."Line No.");

                ReorderQty += AdjustReorderQty(ReorderQty, TempSKU, SupplyInventoryProfile."Line No.", SupplyInventoryProfile."Min. Quantity");
                SupplyInventoryProfile."Max. Quantity" := TempSKU."Maximum Order Quantity";
                UpdateQty(SupplyInventoryProfile, ReorderQty);
                SupplyInventoryProfile."Min. Quantity" := SupplyInventoryProfile."Quantity (Base)";
            end;
            SupplyInventoryProfile."Fixed Date" := SupplyInventoryProfile."Due Date";
            SupplyInventoryProfile."Order Relation" := SupplyInventoryProfile."Order Relation"::"Safety Stock";
            SupplyInventoryProfile."Is Exception Order" := true;
            OnCreateSupplyForInitialSafetyStockWarningOnBeforeSupplyInventoryProfileInsert(SupplyInventoryProfile, TempSKU);
            SupplyInventoryProfile.Insert();

            DummyInventoryProfileTrackBuffer."Warning Level" := DummyInventoryProfileTrackBuffer."Warning Level"::Exception;
            PlanningTransparency.LogWarning(
              SupplyInventoryProfile."Line No.", ReqLine, DummyInventoryProfileTrackBuffer."Warning Level",
              StrSubstNo(Text007, DummyInventoryProfileTrackBuffer."Warning Level", TempSKU.FieldCaption("Safety Stock Quantity"),
                TempSKU."Safety Stock Quantity", PlanningStartDate));

            LastProjectedInventory += SupplyInventoryProfile."Remaining Quantity (Base)";
            ProjectedInventory += SupplyInventoryProfile."Remaining Quantity (Base)";
            LastAvailableInventory += SupplyInventoryProfile."Untracked Quantity";

            OrderQty -= ReorderQty;
            if ExceedROPinException(RespectPlanningParm) and (OrderQty = 0) then
                OrderQty := ExceedROPqty;
            ReorderQty := OrderQty;
        until OrderQty <= 0; // Create supplies until Safety Stock is met or Reorder point is exceeded
    end;

    local procedure IsTrkgForSpecialOrderOrDropShpt(ReservEntry: Record "Reservation Entry") Result: Boolean
    var
        SalesLine: Record "Sales Line";
        PurchaseLine: Record "Purchase Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeIsTrkgForSpecialOrderOrDropShpt(ReservEntry, Result, IsHandled);
        if IsHandled then
            exit(Result);

        case ReservEntry."Source Type" of
            Database::"Sales Line":
                begin
                    SalesLine.SetLoadFields("Special Order", "Drop Shipment");
                    if SalesLine.Get(ReservEntry."Source Subtype", ReservEntry."Source ID", ReservEntry."Source Ref. No.") then
                        exit(SalesLine."Special Order" or SalesLine."Drop Shipment");
                end;
            Database::"Purchase Line":
                begin
                    PurchaseLine.SetLoadFields("Special Order", "Drop Shipment");
                    if PurchaseLine.Get(ReservEntry."Source Subtype", ReservEntry."Source ID", ReservEntry."Source Ref. No.") then
                        exit(PurchaseLine."Special Order" or PurchaseLine."Drop Shipment");
                end;
        end;

        exit(false);
    end;

    local procedure CheckSupplyRemQtyAndUntrackQty(var InventoryProfile: Record "Inventory Profile")
    var
        RemQty: Decimal;
    begin
        if InventoryProfile."Source Type" = Database::"Item Ledger Entry" then
            exit;

        if InventoryProfile."Remaining Quantity (Base)" >= TempSKU."Maximum Order Quantity" then begin
            RemQty := InventoryProfile."Remaining Quantity (Base)";
            InventoryProfile."Remaining Quantity (Base)" := TempSKU."Maximum Order Quantity";
            if not (InventoryProfile."Action Message" in [InventoryProfile."Action Message"::New, InventoryProfile."Action Message"::Reschedule]) then
                InventoryProfile."Original Quantity" := InventoryProfile."Quantity (Base)";
        end;
        if InventoryProfile."Untracked Quantity" >= TempSKU."Maximum Order Quantity" then
            InventoryProfile."Untracked Quantity" := InventoryProfile."Untracked Quantity" - RemQty + InventoryProfile."Remaining Quantity (Base)";
    end;

    local procedure CheckItemInventoryExists(var InventoryProfile: Record "Inventory Profile") ItemInventoryExists: Boolean
    begin
        InventoryProfile.SetRange("Source Type", Database::"Item Ledger Entry");
        InventoryProfile.SetFilter(Binding, '<>%1', InventoryProfile.Binding::"Order-to-Order");
        ItemInventoryExists := not InventoryProfile.IsEmpty();
        InventoryProfile.SetRange("Source Type");
        InventoryProfile.SetRange(Binding);
    end;

    local procedure ApplyUntrackedQuantityToItemInventory(SupplyExists: Boolean; ItemInventoryExists: Boolean; DemandForAdditionalProfile: Boolean): Boolean
    begin
        if SupplyExists then
            exit(false);
        if DemandForAdditionalProfile then
            exit(false);
        exit(ItemInventoryExists);
    end;

    local procedure UpdateAppliedItemEntry(var ReservEntry: Record "Reservation Entry")
    var
        ItemTrackingSetup: Record "Item Tracking Setup";
    begin
        TempItemTrkgEntry.SetSourceFilter(
            ReservEntry."Source Type", ReservEntry."Source Subtype", ReservEntry."Source ID", ReservEntry."Source Ref. No.", true);
        ItemTrackingSetup.CopyTrackingFromReservEntry(ReservEntry);
        TempItemTrkgEntry.SetTrackingFilterFromItemTrackingSetupIfNotBlank(ItemTrackingSetup);
        OnUpdateAppliedItemEntryOnBeforeFindApplEntry(TempItemTrkgEntry, ReservEntry);
        if TempItemTrkgEntry.FindFirst() then begin
            ReservEntry."Appl.-from Item Entry" := TempItemTrkgEntry."Appl.-from Item Entry";
            ReservEntry."Appl.-to Item Entry" := TempItemTrkgEntry."Appl.-to Item Entry";
        end;

        OnAfterUpdateAppliedItemEntry(ReservEntry, TempItemTrkgEntry, ReqLine);
    end;

    local procedure CheckSupplyAndTrack(InventoryProfileFromDemand: Record "Inventory Profile"; InventoryProfileFromSupply: Record "Inventory Profile")
    begin
        OnBeforeCheckSupplyAndTrack(InventoryProfileFromDemand, InventoryProfileFromSupply);

        if InventoryProfileFromSupply."Source Type" = Database::"Item Ledger Entry" then
            Track(InventoryProfileFromDemand, InventoryProfileFromSupply, false, false, InventoryProfileFromSupply.Binding)
        else
            Track(InventoryProfileFromDemand, InventoryProfileFromSupply, false, false, InventoryProfileFromDemand.Binding);
    end;

    local procedure CheckPlanSKU(SKU: Record "Stockkeeping Unit"; DemandExists: Boolean; SupplyExists: Boolean; IsReorderPointPlanning: Boolean): Boolean
    var
        SKU2: Record "Stockkeeping Unit";
        Location: Record Location;
        Item: Record Item;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckPlanSKU(SKU, IsHandled);
        if IsHandled then
            exit(false);

        Item.SetLoadFields("No.");
        if not SKU2.Get(SKU."Location Code", SKU."Item No.", SKU."Variant Code") then
            if Location.Get(SKU."Location Code") then begin
                if PlanningResiliency then begin
                    Item.Get(SKU."Item No.");
                    case Location."Missing SKU Planning Policy" of
                        Enum::"Missing SKU Planning Policy"::"Item Card":
                            begin
                                ReqLine.SetResiliencyError(StrSubstNo(PlanningParametersTakenFromItemCardTxt, Location.FieldCaption("Missing SKU Planning Policy"), Location."Missing SKU Planning Policy", SKU."Item No.", SKU."Location Code"), Database::Item, Item.GetPosition());
                                PlanningSkippedForMissingSKUPolicy := true;
                            end;
                        Enum::"Missing SKU Planning Policy"::"Dont Plan":
                            begin
                                ReqLine.SetResiliencyError(StrSubstNo(SKUNotPlannedTxt, SKU."Item No.", SKU."Location Code", Location.FieldCaption("Missing SKU Planning Policy"), Location."Missing SKU Planning Policy"), Database::Item, Item.GetPosition());
                                PlanningSkippedForMissingSKUPolicy := true;
                            end;
                    end;
                end;

                if Location."Missing SKU Planning Policy" = Location."Missing SKU Planning Policy"::"Dont Plan" then
                    exit(false);
            end;

        if (CurrWorksheetType = CurrWorksheetType::Requisition) and (SKU.IsMfgSKU() or SKU.IsAssemblySKU()) then
            exit(false);

        if DemandExists or SupplyExists or IsReorderPointPlanning then
            exit(true);

        exit(false);
    end;

    local procedure PrepareDemand(var InventoryProfile: Record "Inventory Profile"; IsReorderPointPlanning: Boolean; ToDate: Date)
    begin
        // Transfer attributes
        if (TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::Order) or
           (TempSKU."Manufacturing Policy" = TempSKU."Manufacturing Policy"::"Make-to-Order")
        then
            PrepareOrderToOrderLink(InventoryProfile);
        UpdatePriorities(InventoryProfile, IsReorderPointPlanning, ToDate);
    end;

    local procedure DemandMatchedSupply(var FromInventoryProfile: Record "Inventory Profile"; var ToInventoryProfile: Record "Inventory Profile"; SKU: Record "Stockkeeping Unit"): Boolean
    var
        xFromInventoryProfile: Record "Inventory Profile";
        xToInventoryProfile: Record "Inventory Profile";
        UntrackedQty: Decimal;
        ToInventoryUntrackedQty: Decimal;
        FromInventoryUntrackedQty: Decimal;
    begin
        xToInventoryProfile.CopyFilters(FromInventoryProfile);
        xFromInventoryProfile.CopyFilters(ToInventoryProfile);
        FromInventoryProfile.SetRange(FromInventoryProfile."Attribute Priority", 1, 7);
        FromInventoryProfile.SetRange(FromInventoryProfile."Planning Level Code", 0);
        if FromInventoryProfile.FindSet() then begin
            repeat
                ToInventoryProfile.SetRange(Binding, FromInventoryProfile.Binding);
                ToInventoryProfile.SetRange("Primary Order Status", FromInventoryProfile."Primary Order Status");
                ToInventoryProfile.SetRange("Primary Order No.", FromInventoryProfile."Primary Order No.");
                ToInventoryProfile.SetRange("Primary Order Line", FromInventoryProfile."Primary Order Line");
                ToInventoryProfile.SetTrackingFilter(FromInventoryProfile);
                OnDemandMatchedSupplyOnAfterSetFiltersToInvProfile(ToInventoryProfile, FromInventoryProfile);
                ToInventoryProfile.CalcSums("Untracked Quantity");
                ToInventoryUntrackedQty += ToInventoryProfile."Untracked Quantity";
                FromInventoryUntrackedQty += FromInventoryProfile."Untracked Quantity";
                UntrackedQty += ToInventoryProfile."Untracked Quantity";
                UntrackedQty -= FromInventoryProfile."Untracked Quantity";
            until FromInventoryProfile.Next() = 0;
            if (UntrackedQty = 0) and (SKU."Reordering Policy" = SKU."Reordering Policy"::"Lot-for-Lot") then begin
                FromInventoryProfile.SetRange(FromInventoryProfile."Attribute Priority", 8);
                FromInventoryProfile.CalcSums(FromInventoryProfile."Untracked Quantity");
                if FromInventoryProfile."Untracked Quantity" = 0 then begin
                    FromInventoryProfile.CopyFilters(xToInventoryProfile);
                    ToInventoryProfile.CopyFilters(xFromInventoryProfile);
                    exit(true);
                end;
            end;
        end;
        FromInventoryProfile.CopyFilters(xToInventoryProfile);
        ToInventoryProfile.CopyFilters(xFromInventoryProfile);

        if (Abs(ToInventoryUntrackedQty) = Abs(FromInventoryUntrackedQty)) and (ToInventoryUntrackedQty <> 0) and (FromInventoryUntrackedQty <> 0) and
           (SKU."Replenishment System" = SKU."Replenishment System"::"Prod. Order") and
           (SKU."Reordering Policy" <> SKU."Reordering Policy"::"Lot-for-Lot") then
            exit(true);

        exit(false);
    end;

    local procedure ReservedForProdComponent(ReservationEntry: Record "Reservation Entry"): Boolean
    begin
        if not ReservationEntry.Positive then
            exit(ReservationEntry."Source Type" = 5407); //  Database::"Prod. Order Component"
        if ReservationEntry.Get(ReservationEntry."Entry No.", false) then
            exit(ReservationEntry."Source Type" = 5407);  //  Database::"Prod. Order Component"
    end;

    local procedure ShouldInsertTrackingEntry(FromTrkgReservEntry: Record "Reservation Entry"): Boolean
    var
        InsertedReservEntry: Record "Reservation Entry";
    begin
        InsertedReservEntry.SetRange("Source ID", FromTrkgReservEntry."Source ID");
        InsertedReservEntry.SetRange("Source Ref. No.", FromTrkgReservEntry."Source Ref. No.");
        InsertedReservEntry.SetRange("Source Type", FromTrkgReservEntry."Source Type");
        InsertedReservEntry.SetRange("Source Subtype", FromTrkgReservEntry."Source Subtype");
        InsertedReservEntry.SetRange("Source Batch Name", FromTrkgReservEntry."Source Batch Name");
        InsertedReservEntry.SetRange("Source Prod. Order Line", FromTrkgReservEntry."Source Prod. Order Line");
        InsertedReservEntry.SetRange("Reservation Status", FromTrkgReservEntry."Reservation Status");
        exit(InsertedReservEntry.IsEmpty);
    end;

    local procedure CloseInventoryProfile(var ClosedInvtProfile: Record "Inventory Profile"; var OpenInvtProfile: Record "Inventory Profile"; ActionMessage: Enum "Action Message Type")
    var
        PlanningStageToMaintain: Option " ","Line Created","Routing Created",Exploded,Obsolete;
    begin
        OpenInvtProfile."Untracked Quantity" -= ClosedInvtProfile."Untracked Quantity";
        OpenInvtProfile.Modify();

        if OpenInvtProfile.Binding = OpenInvtProfile.Binding::"Order-to-Order" then
            PlanningStageToMaintain := PlanningStageToMaintain::Exploded
        else
            PlanningStageToMaintain := PlanningStageToMaintain::"Line Created";

        if ActionMessage <> ActionMessage::" " then
            if OpenInvtProfile.IsSupply then
                MaintainPlanningLine(OpenInvtProfile, ClosedInvtProfile, PlanningStageToMaintain, ScheduleDirection::Backward)
            else
                MaintainPlanningLine(ClosedInvtProfile, ClosedInvtProfile, PlanningStageToMaintain, ScheduleDirection::Backward);

        Track(ClosedInvtProfile, OpenInvtProfile, false, false, OpenInvtProfile.Binding);

        if ClosedInvtProfile.Binding = ClosedInvtProfile.Binding::"Order-to-Order" then
            ClosedInvtProfile."Remaining Quantity (Base)" -= ClosedInvtProfile."Untracked Quantity";

        ClosedInvtProfile."Untracked Quantity" := 0;
        if ClosedInvtProfile."Remaining Quantity (Base)" = 0 then
            ClosedInvtProfile.Delete()
        else
            ClosedInvtProfile.Modify();
    end;

    local procedure CloseDemand(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile")
    begin
        CloseInventoryProfile(DemandInvtProfile, SupplyInvtProfile, SupplyInvtProfile."Action Message");
    end;

    local procedure CloseSupply(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"): Boolean
    begin
        CloseInventoryProfile(SupplyInvtProfile, DemandInvtProfile, SupplyInvtProfile."Action Message");
        exit(SupplyInvtProfile.Next() <> 0);
    end;

    local procedure CreateTempSKUForComponentsLocation(var Item: Record Item)
    var
        SKU: Record "Stockkeeping Unit";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCreateTempSKUForComponentsLocation(Item, IsHandled);
        if IsHandled then
            exit;

        if GetComponentsAtLocationCode() = '' then
            exit;

        SKU.SetRange("Item No.", Item."No.");
        IsHandled := false;
        OnCreateTempSKUForComponentsLocationOnBeforeSetLocationCodeFilter(Item, SKU, IsHandled);
        if not IsHandled then
            SKU.SetRange("Location Code", GetComponentsAtLocationCode());
        IsHandled := false;
        OnCreateTempSKUForComponentsLocationOnBeforeItemCopyFilter(SKU, Item, IsHandled);
        if not IsHandled then
            Item.CopyFilter("Variant Filter", SKU."Variant Code");
        if SKU.IsEmpty() then
            CreateTempSKUForLocation(Item."No.", GetComponentsAtLocationCode());
    end;

    local procedure GetComponentsAtLocationCode() LocationCode: Code[10]
    begin
        OnGetComponentsAtLocationCode(LocationCode);
    end;

    procedure ForecastInitDemand(var InventoryProfile: Record "Inventory Profile"; ProductionForecastEntry: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry"; ItemNo: Code[20]; LocationCode: Code[10]; TotalForecastQty: Decimal)
    begin
        InventoryProfile.Init();
        InventoryProfile."Line No." := GetNextLineNo();
        InventoryProfile."Source Type" := Database::Microsoft.Manufacturing.Forecast."Production Forecast Entry";
        InventoryProfile."Planning Flexibility" := InventoryProfile."Planning Flexibility"::None;
        InventoryProfile."Qty. per Unit of Measure" := 1;
        InventoryProfile."MPS Order" := true;
        InventoryProfile."Source ID" := ProductionForecastEntry."Production Forecast Name";
        InventoryProfile."Item No." := ItemNo;
        InventorySetup.GetRecordOnce();
        if InventorySetup."Use Forecast on Locations" then
            InventoryProfile."Location Code" := ProductionForecastEntry."Location Code"
        else
            InventoryProfile."Location Code" := LocationCode;
        if InventorySetup."Use Forecast on Variants" then
            InventoryProfile."Variant Code" := ProductionForecastEntry."Variant Code"
        else
            InventoryProfile."Variant Code" := '';
        InventoryProfile."Remaining Quantity (Base)" := TotalForecastQty;
        InventoryProfile."Untracked Quantity" := TotalForecastQty;
        OnAfterForecastInitDemand(InventoryProfile, ProductionForecastEntry, ItemNo, LocationCode, TotalForecastQty);
    end;

    local procedure SetPurchase(var PurchaseLine: Record "Purchase Line"; var InventoryProfile: Record "Inventory Profile")
    var
        PurchaseLineExists: Boolean;
        DocumentType: Enum "Purchase Document Type";
        NotFoundError: Label 'Purchase Line with Document Type %1, Document No. %2, Line No. %3 was not found.', Comment = '%1 = Document Type, %2 = Document No., %3 = Line No.';
    begin
        ReqLine."Ref. Order Type" := ReqLine."Ref. Order Type"::Purchase;
        ReqLine."Ref. Order No." := InventoryProfile."Source ID";
        ReqLine."Ref. Line No." := InventoryProfile."Source Ref. No.";
        DocumentType := PurchaseLine."Document Type"::Order;
        PurchaseLineExists := PurchaseLine.Get(DocumentType, ReqLine."Ref. Order No.", ReqLine."Ref. Line No.");
        OnSetPurchaseOnBeforeTransferFromPurchaseLine(ReqLine, PurchaseLine, DocumentType, PurchaseLineExists);
        if not PurchaseLineExists then
            Error(NotFoundError, DocumentType, ReqLine."Ref. Order No.", ReqLine."Ref. Line No.");
        ReqLine.TransferFromPurchaseLine(PurchaseLine);

        OnAfterSetPurchase(PurchaseLine, ReqLine, InventoryProfile);
    end;

    local procedure SetTransfer(var TransLine: Record "Transfer Line"; var InventoryProfile: Record "Inventory Profile")
    var
        IsHandled: Boolean;
    begin
        ReqLine."Ref. Order Type" := ReqLine."Ref. Order Type"::Transfer;
        ReqLine."Ref. Order Status" := ReqLine."Ref. Order Status"::Simulated;
        ReqLine."Ref. Order No." := InventoryProfile."Source ID";
        ReqLine."Ref. Line No." := InventoryProfile."Source Ref. No.";

        IsHandled := false;
        OnSetTransferOnBeforeTransferFromTransLine(InventoryProfile, ReqLine, IsHandled);
        if not IsHandled then begin
            TransLine.Get(ReqLine."Ref. Order No.", ReqLine."Ref. Line No.");
            ReqLine.TransferFromTransLine(TransLine);
        end;
    end;

    local procedure FromLotAccumulationPeriodStartDate(LotAccumulationPeriodStartDate: Date; DemandDueDate: Date) Result: Boolean
    var
        IsHandled: Boolean;
    begin
        isHandled := false;
        OnBeforeFromLotAccumulationPeriodStartDate(LotAccumulationPeriodStartDate, DemandDueDate, Result, IsHandled);
        if IsHandled then
            exit(Result);

        if LotAccumulationPeriodStartDate > 0D then
            exit(CalcDate(TempSKU."Lot Accumulation Period", LotAccumulationPeriodStartDate) >= DemandDueDate);
    end;

    local procedure IsSKUSetUpForReorderPointPlanning(SKU: Record "Stockkeeping Unit"): Boolean
    begin
        exit(
          (SKU."Reorder Point" > SKU."Safety Stock Quantity") or
          (SKU."Reordering Policy" in [SKU."Reordering Policy"::"Maximum Qty.", SKU."Reordering Policy"::"Fixed Reorder Qty."]));
    end;

    procedure InsertPlanningComponent(var PlanningComponent: Record "Planning Component");
    begin
        OnBeforeInsertPlanningComponent(PlanningComponent);

        PlanningComponent.Insert();
        TempPlanningCompList := PlanningComponent;
        if not TempPlanningCompList.Insert() then
            TempPlanningCompList.Modify();
    end;

    local procedure InsertInitialSafetyStockWarningSupply(var SupplyInvtProfile: Record "Inventory Profile"; var LastAvailableInventory: Decimal; var LastProjectedInventory: Decimal; PlanningStartDate: Date; RespectPlanningParm: Boolean; var IsReorderPointPlanning: Boolean)
    var
        SupplyAvailableWithinLeadTime: Decimal;
        InitialProjectedInventory: Decimal;
        IsHandled: Boolean;
    begin
        OnBeforeInsertInitialSafetyStockWarningSupply(SupplyInvtProfile, LastAvailableInventory, LastProjectedInventory, PlanningStartDate, RespectPlanningParm, IsReorderPointPlanning, IsHandled);
        if IsHandled then
            exit;

        SupplyAvailableWithinLeadTime := SumUpAvailableSupply(SupplyInvtProfile, PlanningStartDate, PlanningStartDate);
        InitialProjectedInventory := LastAvailableInventory + SupplyAvailableWithinLeadTime;
        if InitialProjectedInventory < TempSKU."Safety Stock Quantity" then
            CreateSupplyForInitialSafetyStockWarning(
              SupplyInvtProfile, InitialProjectedInventory, LastProjectedInventory, LastAvailableInventory, PlanningStartDate, RespectPlanningParm, IsReorderPointPlanning);
    end;

    local procedure InsertInventoryProfile(var InventoryProfile: Record "Inventory Profile"; RequisitionLine: Record "Requisition Line"; Item: Record Item)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInsertInventoryProfile(RequisitionLine, IsHandled);
        if IsHandled then
            exit;

        InventoryProfile.Init();
        InventoryProfile."Line No." := GetNextLineNo();
        InventoryProfile."Item No." := Item."No.";
        InventoryProfile.TransferFromOutboundTransfPlan(RequisitionLine, TempItemTrkgEntry);
        if InventoryProfile.IsSupply then
            InventoryProfile.ChangeSign();
        InventoryProfile.Insert();
    end;

    local procedure GetPrevAvailDateFromCompanyCalendar(InitialDate: Date): Date
    var
        CustomCalendarChange: array[2] of Record "Customized Calendar Change";
    begin
        if InitialDate = 0D then
            exit(InitialDate);

        CustomCalendarChange[1].SetSource(CustomCalendarChange[1]."Source Type"::Company, '', '', '');
        exit(CalendarManagement.CalcDateBOC2('<0D>', InitialDate, CustomCalendarChange, false));
    end;

    local procedure SetPriceCalculationMethod(var RequisitionLine: Record "Requisition Line")
    var
        Vendor: Record Vendor;
    begin
        if PriceCalculationMethod = PriceCalculationMethod::" " then
            RequisitionLine."Price Calculation Method" := Vendor.GetPriceCalculationMethod()
        else
            RequisitionLine."Price Calculation Method" := PriceCalculationMethod;
    end;

    local procedure DemandForAdditionalLine(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"): Boolean
    begin
        if (TempSKU."Replenishment System" = TempSKU."Replenishment System"::"Prod. Order") and
            (TempSKU."Manufacturing Policy" = TempSKU."Manufacturing Policy"::"Make-to-Order") then begin
            if TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Lot-for-Lot" then
                if DemandInvtProfile.Count() > 1 then
                    exit(true);
            if TempSKU."Reordering Policy" = TempSKU."Reordering Policy"::"Maximum Qty." then
                if CheckItemInventoryExists(SupplyInvtProfile) then
                    exit(true);
        end;
    end;

    local procedure IsReorderQtyToAdjust(StockkeepingUnit: Record "Stockkeeping Unit"): Boolean
    begin
        exit(not ((StockkeepingUnit."Reordering Policy" = StockkeepingUnit."Reordering Policy"::"Lot-for-Lot") and (StockkeepingUnit."Manufacturing Policy" = StockkeepingUnit."Manufacturing Policy"::"Make-to-Order")) or
            ((StockkeepingUnit."Replenishment System" = StockkeepingUnit."Replenishment System"::"Prod. Order") and (StockkeepingUnit."Manufacturing Policy" = StockkeepingUnit."Manufacturing Policy"::"Make-to-Stock")) or
            (StockkeepingUnit."Replenishment System" in [StockkeepingUnit."Replenishment System"::Purchase, StockkeepingUnit."Replenishment System"::Assembly]))
    end;

    local procedure CheckReorderingPolicyAndOrderTrackingPolicy(Item: Record Item): Boolean
    begin
        if not (Item."Reordering Policy" in ["Reordering Policy"::"Fixed Reorder Qty.", "Reordering Policy"::"Lot-for-Lot"]) then
            exit(false);

        if Item."Order Tracking Policy" <> Item."Order Tracking Policy"::"Tracking Only" then
            exit(false);

        exit(true);
    end;

    local procedure IsLotSpecificTracking(ItemTrackingCode: Record "Item Tracking Code"): Boolean
    var
        LotSepecificTracking: Boolean;
    begin
        LotSepecificTracking := (
            (ItemTrackingCode."Lot Specific Tracking") or
            (ItemTrackingCode."Lot Warehouse Tracking") or
            (ItemTrackingCode."Lot Transfer Tracking") or
            (ItemTrackingCode."Lot Info. Outbound Must Exist") or
            (ItemTrackingCode."Lot Purchase Outbound Tracking") or
            (ItemTrackingCode."Lot Sales Outbound Tracking") or
            (ItemTrackingCode."Lot Pos. Adjmt. Outb. Tracking") or
            (ItemTrackingCode."Lot Neg. Adjmt. Outb. Tracking") or
            (ItemTrackingCode."Lot Info. Inbound Must Exist") or
            (ItemTrackingCode."Lot Purchase Inbound Tracking") or
            (ItemTrackingCode."Lot Sales Inbound Tracking") or
            (ItemTrackingCode."Lot Pos. Adjmt. Inb. Tracking") or
            (ItemTrackingCode."Lot Neg. Adjmt. Inb. Tracking"));

        if not LotSepecificTracking then
            OnCheckIsLotSpecificTracking(ItemTrackingCode, LotSepecificTracking);

        exit(LotSepecificTracking);
    end;

    local procedure IsSNSpecificTracking(ItemTrackingCode: Record "Item Tracking Code"): Boolean
    var
        SerialSepecificTracking: Boolean;
    begin
        SerialSepecificTracking := (
            (ItemTrackingCode."SN Specific Tracking") or
            (ItemTrackingCode."SN Warehouse Tracking") or
            (ItemTrackingCode."SN Transfer Tracking") or
            (ItemTrackingCode."SN Info. Outbound Must Exist") or
            (ItemTrackingCode."SN Purchase Outbound Tracking") or
            (ItemTrackingCode."SN Sales Outbound Tracking") or
            (ItemTrackingCode."SN Pos. Adjmt. Outb. Tracking") or
            (ItemTrackingCode."SN Neg. Adjmt. Outb. Tracking") or
            (ItemTrackingCode."SN Info. Inbound Must Exist") or
            (ItemTrackingCode."SN Purchase Inbound Tracking") or
            (ItemTrackingCode."SN Sales Inbound Tracking") or
            (ItemTrackingCode."SN Pos. Adjmt. Inb. Tracking") or
            (ItemTrackingCode."SN Neg. Adjmt. Inb. Tracking"));

        if not SerialSepecificTracking then
            OnCheckIsSNSpecificTracking(ItemTrackingCode, SerialSepecificTracking);

        exit(SerialSepecificTracking);
    end;

    /// <summary>
    /// Determines if the missing SKU planning policy for a location is set to Item Card.
    /// </summary>
    /// <param name="LocationCode">The location code to check. If empty, returns false.</param>
    /// <returns>True if the location's Missing SKU Planning Policy is set to Item Card; otherwise, false.</returns>
    local procedure IsMissingSKUPlanningPolicyItemCard(LocationCode: Code[10]): Boolean
    var
        Location: Record Location;
    begin
        if LocationCode = '' then
            exit(false);

        Location.Get(LocationCode);

        exit(Location."Missing SKU Planning Policy" = Location."Missing SKU Planning Policy"::"Item Card");
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterAdjustPlanLine(var RequisitionLine: Record "Requisition Line"; var SupplyInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterAllowScheduleIn(SupplyInvtProfile: Record "Inventory Profile"; TargetDate: Date; var CanReschedule: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterAllowScheduleOut(SupplyInvtProfile: Record "Inventory Profile"; TargetDate: Date; var CanReschedule: Boolean; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterAllowLotAccumulation(SupplyInventoryProfile: Record "Inventory Profile"; DemandDueDate: Date; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var AccumulationOK: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAdjustPlanLineAfterValidateQuantity(var ReqLine: Record "Requisition Line"; var SupplyInventoryProfile: Record "Inventory Profile");
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnAfterForecastInitDemand(var InventoryProfile: Record "Inventory Profile"; ProductionForecastEntry: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry"; ItemNo: Code[20]; LocationCode: Code[10]; TotalForecastQty: Decimal)
    begin
    end;

#if not CLEAN27
    internal procedure RunOnAfterGetRoutingFromProdOrder(var RequisitionLine: Record "Requisition Line")
    begin
        OnAfterGetRoutingFromProdOrder(RequisitionLine);
    end;

    [Obsolete('Moved to codeunit MfgInvtProfileOffsetting', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnAfterGetRoutingFromProdOrder(var RequisitionLine: Record "Requisition Line")
    begin
    end;
#endif

    [IntegrationEvent(false, false)]
    local procedure OnAfterInitSupply(var InventoryProfile: Record "Inventory Profile"; var StockkeepingUnit: Record "Stockkeeping Unit"; Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterTransToChildInvProfile(var ReservEntry: Record "Reservation Entry"; var ChildInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterDemandToInvProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; var ReservEntry: Record "Reservation Entry"; var NextLineNo: Integer; PlanMRP: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetFiltersForSisterInventoryProfile(CurrentInventoryProfile: Record "Inventory Profile"; var SisterInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterShallSupplyBeClosed(StockkeepingUnit: Record "Stockkeeping Unit"; SupplyInventoryProfile: Record "Inventory Profile"; DemandDueDate: Date; IsReorderPointPlanning: Boolean; var CloseSupply: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateAppliedItemEntry(var ReservationEntry: Record "Reservation Entry"; var TempItemTrackingEntry: Record "Reservation Entry"; RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterMatchAttributes(var SupplyInvtProfile: Record "Inventory Profile"; var DemandInvtProfile: Record "Inventory Profile"; var TempTrkgReservEntry: Record "Reservation Entry" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPlanItemNextStateStartOver(var SupplyInvtProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSupplyToInvProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; var ToDate: Date; var ReservEntry: Record "Reservation Entry" temporary; var NextLineNo: Integer; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var TempTransferStockkeepingUnit: Record "Stockkeeping Unit" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUnfoldItemTracking(var ParentInvProfile: Record "Inventory Profile"; var ChildInvProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSupplyToInvProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; var ToDate: Date; var ReservEntry: Record "Reservation Entry"; var NextLineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateUOMFromInventoryProfile(var RequisitionLine: Record "Requisition Line"; InventoryProfile: Record "Inventory Profile"; StockkeepingUnit: Record "Stockkeeping Unit"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertTempTracking(var FromReservationEntry: Record "Reservation Entry"; var ToReservationEntry: Record "Reservation Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetQtyToHandle(var ReservationEntry: Record "Reservation Entry");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetOrderPriority(var InventoryProfile: Record "Inventory Profile")
    begin
    end;

#if not CLEAN27
    internal procedure RunOnAfterSetProdOrder(var ReqLine: Record "Requisition Line"; var ProdOrderLine: Record Microsoft.Manufacturing.Document."Prod. Order Line"; var InventoryProfile: Record "Inventory Profile")
    begin
        OnAfterSetProdOrder(ReqLine, ProdOrderLine, InventoryProfile);
    end;

    [Obsolete('Moved to codeunit MfgInvtProfileOffsetting', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnAfterSetProdOrder(var ReqLine: Record "Requisition Line"; var ProdOrderLine: Record Microsoft.Manufacturing.Document."Prod. Order Line"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;
#endif

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetPurchase(var PurchaseLine: Record "Purchase Line"; ReqLine: Record "Requisition Line"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSetPurchaseOnBeforeTransferFromPurchaseLine(var RequisitionLine: Record "Requisition Line"; var PurchaseLine: Record "Purchase Line"; var DocumentType: Enum "Purchase Document Type"; var PurchaseLineExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterShouldDeleteReservEntry(ReservationEntry: Record "Reservation Entry"; ToDate: Date; var DeleteCondition: Boolean; TemplateName: Code[10]; WorksheetName: Code[10])
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterTransferAttributes(var ToInventoryProfile: Record "Inventory Profile"; var FromInventoryProfile: Record "Inventory Profile"; var TempSKU: Record "Stockkeeping Unit" temporary; SpecificLotTracking: Boolean; SpecificSNTracking: Boolean)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnBeforeAdjustPlanLine(var RequisitionLine: Record "Requisition Line"; var SupplyInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeBlanketOrderConsumpFind(var BlanketSalesLine: Record "Sales Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeBlanketOrderConsump(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date; var IsHandled: Boolean)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckScheduleOut(var InventoryProfile: Record "Inventory Profile"; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; BucketSize: DateFormula; var DampenersDays: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckUpdateInventoryProfileMaxQuantity(var InventoryProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCommitTracking(TempReservationEntry: Record "Reservation Entry" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCommonBalancing(var TempSKU: Record "Stockkeeping Unit" temporary; var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile"; PlanningStartDate: Date; ToDate: Date; var NewSupplyHasTakenOver: Boolean; var NeedOfPublishSurplus: Boolean; var FutureSupplyWithinLeadtime: Decimal; var OverflowLevel: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateSupply(var SupplyInvtProfile: Record "Inventory Profile"; var DemandInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDecreaseQty(var SupplyInvtProfile: Record "Inventory Profile"; ReduceQty: Decimal; var SKU: Record "Stockkeeping Unit"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDemandInvtProfileInsert(var InventoryProfile: Record "Inventory Profile"; StockkeepingUnit: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDemandToInvProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeForecastConsumption(var DemandInvtProfile: Record "Inventory Profile"; var Item: Record Item; OrderDate: Date; ToDate: Date; var UpdatedOrderDate: Date; var IsHandled: Boolean; var CurrForecast: Code[10]; var ExcludeForecastBefore: Date; var UseParm: Boolean; var LineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIncreaseQty(var SupplyInvtProfile: Record "Inventory Profile"; NeededQty: Decimal; var SKU: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertEmergencyOrderSupply(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean; var PlanningStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIsTrkgForSpecialOrderOrDropShpt(ReservEntry: Record "Reservation Entry"; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnBeforeMaintainPlanningLine(var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; NewPhase: Option " ","Line Created","Routing Created",Exploded,Obsolete; Direction: Option Forward,Backward; var TrackingReservEntry: Record "Reservation Entry"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeTempTransferSKUInsert(var TempTransferSKU: Record "Stockkeeping Unit" temporary; TransferLine: Record "Transfer Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeTrack(var FromProfile: Record "Inventory Profile"; var ToProfile: Record "Inventory Profile"; IsSurplus: Boolean; IssueActionMessage: Boolean; Binding: Enum "Reservation Binding")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeTransItemLedgEntryToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; var ItemLedgerEntry: Record "Item Ledger Entry"; var IsHandled: Boolean; var LineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeTransShptTransLineToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; LineNo: Integer; var IsHandled: Boolean; var TransferLine: Record "Transfer Line")
    begin
    end;



    [IntegrationEvent(false, false)]
    local procedure OnBeforeTransRcptTransLineToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeMatchAttributesDemandApplicationLoop(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateActionMessageOnReschedule(var InventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUnfoldItemTracking(var ParentInvProfile: Record "Inventory Profile"; var ChildInvProfile: Record "Inventory Profile"; var TempItemTrkgEntry: Record "Reservation Entry" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateSupplyOnBeforeSupplyInvtProfileInsert(var SupplyInvtProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateSupplyForwardOnBeforeSupplyInvtProfileInsert(var SupplyInvtProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateSupplyForInitialSafetyStockWarningOnBeforeSupplyInventoryProfileInsert(var SupplyInvtProfile: Record "Inventory Profile"; var SKU: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnEndMatchAttributesDemandApplicationLoop(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnStartOfMatchAttributesDemandApplicationLoop(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnScheduleAllOutChangesSequenceOnBeforeSupplyInvtProfileInsert(var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePrePlanDateApplicationLoop(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean; var LastProjectedInventory: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnStartOfPrePlanDateApplicationLoop(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean; var IncrementLastProjectedInventory: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePrePlanDateDemandProc(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePrePlanDateSupplyProc(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePlanItemNextStateMatchDates(var DemandInventoryProfile: Record "Inventory Profile"; var SupplyInventoryProfile: Record "Inventory Profile"; NextState: Option; var IsHandled: Boolean; var ShouldCalcNewSupplyDate: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPrePlanDateSupplyProc(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean; var TempSKU: Record "Stockkeeping Unit" temporary; var TempTrkgReservEntry: Record "Reservation Entry" temporary; var ReqLine: Record "Requisition Line"; var DoInsertInsertSupplyForEmergencyOrder: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterRecalculateReqLine(var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePlanStepSettingOnStartOver(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean; var NextState: Option; var IsHandled: Boolean)
    begin
    end;

#if not CLEAN27
    [Obsolete('Replaced by event OnBeforeCalculatePlanFromWorksheet2', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalculatePlanFromWorksheet(var Item: Record Item; ManufacturingSetup2: Record Microsoft.Manufacturing.Setup."Manufacturing Setup"; TemplateName: Code[10]; WorksheetName: Code[10]; OrderDate: Date; ToDate: Date; MRPPlanning: Boolean; RespectPlanningParm: Boolean)
    begin
    end;
#endif

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalculatePlanFromWorksheet2(var Item: Record Item; TemplateName: Code[10]; WorksheetName: Code[10]; OrderDate: Date; ToDate: Date; MRPPlanning: Boolean; RespectPlanningParm: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertSafetyStockDemands(var DemandInvtProfile: Record "Inventory Profile"; xDemandInvtProfile: Record "Inventory Profile"; var TempSafetyStockInvtProfile: Record "Inventory Profile" temporary; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var PlanningStartDate: Date; var PlanToDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindCombinationAfterAssignTempSKU(var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePostInvChgReminder(var InventoryProfileChangeReminder: Record "Inventory Profile"; var InventoryProfile: Record "Inventory Profile"; PostOnlyMinimum: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPlanItemNextStateCloseDemand(var SupplyInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPostInvChgReminder(var InventoryProfileChangeReminder: Record "Inventory Profile"; var InventoryProfile: Record "Inventory Profile"; PostOnlyMinimum: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeAdjustReorderQty(OrderQty: Decimal; var SKU: Record "Stockkeeping Unit"; SupplyLineNo: Integer; MinQty: Decimal; var DeltaQty: Decimal; var IsHandled: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeTempSKUInsert(var TempSKU: Record "Stockkeeping Unit"; var PlanningGetParameters: Codeunit "Planning-Get Parameters")
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnEndOfPrePlanDateApplicationLoop(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnAfterReqLineInsert(var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnBeforeReqLineInsert(var RequisitionLine: Record "Requisition Line"; var SupplyInvtProfile: Record "Inventory Profile"; PlanToDate: Date; CurrentForecast: Code[10]; NewPhase: Option " ","Line Created","Routing Created",Exploded,Obsolete; Direction: Option Forward,Backward; var DemandInvtProfile: Record "Inventory Profile"; ExcludeForecastBefore: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemNextStateCloseDemandOnBeforeDemandInvtProfileDelete(DemandInventoryProfile: Record "Inventory Profile"; RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeSumDemandInvtProfile(DemandInvtProfile: Record "Inventory Profile"; var IsHandled: Boolean; PlanningStartDate: Date; var LastProjectedInventory: Decimal; var LastAvailableInventory: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforePlanThisSKULoop(var StockkeepingUnit: Record "Stockkeeping Unit"; var DemandInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforePlanThisSKULoopIteration(var StockkeepingUnit: Record "Stockkeeping Unit"; var NextState: Option; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean; var LotAccumulationPeriodStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeSumSupplyInvtProfile(SupplyInvtProfile: Record "Inventory Profile"; var IsHandled: Boolean; var LastProjectedInventory: Decimal; var LastAvailableInventory: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemAfterCalcIsReorderPointPlanning(var TempSKU: Record "Stockkeeping Unit"; var IsReorderPointPlanning: Boolean; var RequisitionLine: Record "Requisition Line"; var PlanningTransparency: Codeunit "Planning Transparency"; PlanningResilicency: Boolean; var CurrTemplateName: Code[10]; var CurrWorksheetName: Code[10]; var PlanningStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateAppliedItemEntryOnBeforeFindApplEntry(var TempItemTrackingEntry: Record "Reservation Entry"; var ReservationEntry: Record "Reservation Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeMaintainProjectedInventory(var ReminderInvtProfile: Record "Inventory Profile"; AtDate: Date; var LastProjectedInventory: Decimal; var LatestBucketStartDate: Date; var ROPHasBeenCrossed: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnAfterLineCreated(var SupplyInvtProfile: Record "Inventory Profile"; var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnBeforeCreateDemandInvtProfileForTransfer(var RequisitionLine: Record "Requisition Line"; var SupplyInventoryProfile: Record "Inventory Profile"; var TempTrackingReservationEntry: Record "Reservation Entry" temporary; var InventoryProfileLineNo: Integer; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnBeforeSupplyInvtProfileInsert(var SupplyInventoryProfile: Record "Inventory Profile"; CurrentSupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCalculatePlanFromWorksheetOnAfterPlanItem(CurrTemplateName: Code[10]; CurrWorksheetName: Code[10]; var Item: Record Item; var RequisitionLine: Record "Requisition Line"; var TrackingReservEntry: Record "Reservation Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCalculatePlanFromWorksheetOnAfterForecastConsumption(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; var OrderDate: Date; var ToDate: Date; var LineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCalcReorderQtyOnCaseElse(var QtyToOrder: Decimal; NeededQty: Decimal; ProjectedInventory: Decimal; SupplyLineNo: Integer; TempSKU: Record "Stockkeeping Unit"; PlanningResilicency: Boolean; var IsHandled: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnForecastConsumptionOnBeforeFindDemandInvtProfile(var DemandInventoryProfile: Record "Inventory Profile"; ComponentForecast: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnForecastConsumptionOnAfterCalcDueDate(var DemandInventoryProfile: Record "Inventory Profile"; TotalForecastQty: Decimal; ForecastEntry: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry"; NextForecastEntry: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry"; var Item: Record Item; OrderDate: Date; ToDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnForecastConsumptionOnAfterSetSalesSourceTypeFilter(var DemandInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnForecastConsumptionOnAfterSetPlanningSourceTypeFilter(var DemandInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindReplishmentLocationOnBeforeFindSKU(var StockkeepingUnit: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindNextSKUOnAfterAssignTempSKU(var TempSKU: Record "Stockkeeping Unit" temporary; var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnBeforeAdjustPlanLine(var RequisitionLine: Record "Requisition Line"; InventoryProfile: Record "Inventory Profile"; StockkeepingUnit: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnBeforeValidateNo(var RequisitionLine: Record "Requisition Line"; InventoryProfile: Record "Inventory Profile"; StockkeepingUnit: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnAfterValidateFieldsForNewReqLine(var RequisitionLine: Record "Requisition Line"; InventoryProfile: Record "Inventory Profile"; StockkeepingUnit: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnAfterSetSourceForNotNewReqLine(var RequisitionLine: Record "Requisition Line"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPrepareTempTrackingOnBeforeInsertTempTracking(var FromReservEntry: Record "Reservation Entry"; var ToReservEntry: Record "Reservation Entry"; IsSurplus: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSetAcceptActionOnBeforeAcceptActionMsg(var RequisitionLine: Record "Requisition Line"; var AcceptActionMsg: Boolean; var PlanningTransparency: Codeunit "Planning Transparency")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAdjustTransferDatesOnBeforeTransferReqLineModify(var RequisitionLine: Record "Requisition Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeIncreaseQtyToMeetDemand(var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; CheckSourceType: Boolean; var Result: Boolean; var IsHandled: Boolean; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertPlanningComponent(var PlanningComponent: Record "Planning Component");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCalcOrderQty(TempSKU: Record "Stockkeeping Unit" temporary; NeededQty: Decimal; ProjectedInventory: Decimal; SupplyLineNo: Integer; var QtyToOrder: Decimal);
    begin
    end;

#if not CLEAN27
    internal procedure RunOnAfterGetComponents(var RequisitionLine: Record "Requisition Line");
    begin
        OnAfterGetComponents(RequisitionLine);
    end;

    [Obsolete('Moved to codeunit MfgInvtProfileOffsetting', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnAfterGetComponents(var RequisitionLine: Record "Requisition Line");
    begin
    end;
#endif

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertInitialSafetyStockWarningSupply(var SupplyInvtProfile: Record "Inventory Profile"; var LastAvailableInventory: Decimal; var LastProjectedInventory: Decimal; PlanningStartDate: Date; RespectPlanningParm: Boolean; var IsReorderPointPlanning: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCalculatePlanFromWorksheetOnBeforeUnfoldItemTracking(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date; var LineNo: Integer; var TempTrkgReservEntry: Record "Reservation Entry" temporary);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeAdjustTransferDates(TransferReqLine: Record "Requisition Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeFillSkUBuffer(var SKU: Record "Stockkeeping Unit"; var TempSKU: Record "Stockkeeping Unit" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertInventoryProfile(RequisitionLine: Record "Requisition Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnAfterTempSKULoop(var TempSKU: Record "Stockkeeping Unit"; var ReqLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSyncTransferDemandWithReqLineOnAfterSetFilters(var TransferReqLine: Record "Requisition Line"; var InventoryProfile: Record "Inventory Profile"; LocationCode: Code[10]; CurrTemplateName: Code[10]; CurrWorksheetName: Code[10])
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnFindCombinationOnBeforeSKUFindSet(var SKU: Record "Stockkeeping Unit"; var Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindCombinationOnBeforeFilterDemandAndSupply(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterPlanItemSetInvtProfileFilters(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeTempSKUFind(var TempSKU: Record "Stockkeeping Unit" temporary; var PlanningStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterTrack(FromProfile: Record "Inventory Profile"; ToProfile: Record "Inventory Profile"; IsSurplus: Boolean; IssueActionMessage: Boolean; Binding: Enum "Reservation Binding")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterTransferPlanningParameters(var SKU: Record "Stockkeeping Unit")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertTempSKU(var TempSKU: Record "Stockkeeping Unit" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterFindCombination(var DemandInvtProfile: Record "Inventory Profile"; var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInitVariables(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnFindCombinationOnBeforeSetState(var TempSKU: Record "Stockkeeping Unit" temporary; var Item: Record Item; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnGetRoutingOnAfterSetResiliencyOn(var ReqLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateReqLineQuantity(var ReqLine: Record "Requisition Line"; var SupplyInventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateReqLineOriginalQuantity(var ReqLine: Record "Requisition Line"; var SupplyInventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean; TempStockkeepingUnit: Record "Stockkeeping Unit" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnAfterPopulateReqLineFields(var ReqLine: Record "Requisition Line"; var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; NewPhase: Option " ","Line Created","Routing Created",Exploded,Obsolete; Direction: Option Forward,Backward; var TempSKU: Record "Stockkeeping Unit"; CurrTemplateName: Code[10]; CurrWorksheetName: Code[10])
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnBeforeReqLineModify(var ReqLine: Record "Requisition Line"; var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterMaintainPlanningLine(var ReqLine: Record "Requisition Line"; SupplyInvtProfile: Record "Inventory Profile"; NewPhase: Option " ","Line Created","Routing Created",Exploded,Obsolete)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTrackBeforePrepareTempTracking(var TrkgReservEntryArray: array[6] of Record "Reservation Entry"; SplitState: Option; var IsSurplus: Boolean; var IssueActionMessage: Boolean; var Binding: Enum "Reservation Binding")
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnTransItemLedgEntryToProfileOnAfterTransferFromItemLedgerEntry(var Item: Record Item; var ItemLedgerEntry: Record "Item Ledger Entry"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTransItemLedgEntryToProfileOnAfterInsertInventoryProfile(var Item: Record Item; var ItemLedgerEntry: Record "Item Ledger Entry"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTransShptTransLineToProfileOnBeforeTransferFromOutboundTransfer(var Item: Record Item; var TransferLine: Record "Transfer Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTransShptTransLineToProfileOnAfterTransferFromOutboundTransfer(var Item: Record Item; var TransferLine: Record "Transfer Line"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTransShptTransLineToProfileOnAfterInventoryProfileInsert(var Item: Record Item; var TransferLine: Record "Transfer Line"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;







    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanLineOnAfterAdjustPlanLine(var TempSKU: Record "Stockkeeping Unit" temporary; var RequisitionLine: Record "Requisition Line"; var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile"; PlanToDate: Date; CurrentForecast: Code[10]; NewPhase: Option " ","Line Created","Routing Created",Exploded,Obsolete; Direction: Option Forward,Backward)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnAfterCanDecreaseSupply(InventoryProfile: Record "Inventory Profile"; ReduceQty: Decimal; DampenerQty: Decimal; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeSupplyInvtProfileModify(var SupplyInvtProfileP: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemNextStateMatchDatesOnBeforeCheckScheduleOut(var SupplyInvtProfile: Record "Inventory Profile"; var LimitedHorizon: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDemandMatchedSupplyOnAfterSetFiltersToInvProfile(var ToInventoryProfile: Record "Inventory Profile"; FromInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateOriginalDueDate(SupplyInventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSetTransferOnBeforeTransferFromTransLine(InventoryProfile: Record "Inventory Profile"; RequisitionLine: Record "Requisition Line"; var IsHandled: Boolean)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnCreateTempSKUForComponentsLocationOnBeforeSetLocationCodeFilter(Item: Record Item; var StockkeepingUnit: Record "Stockkeeping Unit"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateTempSKUForLocation(var TempStockkeeping: Record "Stockkeeping Unit" temporary; LocationCode: Code[10]; var IsHandled: Boolean; ItemNo: Code[20])
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertSafetyStockDemandsOnBeforeCreateDemand(DemandInvtProfile: Record "Inventory Profile"; var PlanningStartDate: Date; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalcMaximumReorderQty(var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var RequisitionLine: Record "Requisition Line"; PlanningResiliency: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTransShptTransLineToProfileOnBeforeProcessLine(TransferLine: Record "Transfer Line"; var ShouldProcess: Boolean; var Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateSupplyOnAfterInitSupply(var SupplyInvtProfile: Record "Inventory Profile"; DemandInvtProfile: Record "Inventory Profile")
    begin
    end;

#if not CLEAN27
    internal procedure RunOnFindCombinationOnBeforeCreateTempSKUForLocation(var Item: Record Item; var IsHandled: Boolean)
    begin
        OnFindCombinationOnBeforeCreateTempSKUForLocation(Item, IsHandled);
    end;

    [Obsolete('Moved to codeunit MfgInvtProfileOffsetting', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnFindCombinationOnBeforeCreateTempSKUForLocation(var Item: Record Item; var IsHandled: Boolean)
    begin
    end;
#endif

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemNextStateCreateSupplyOnAfterCalcNewSupplyDate(var NewSupplyDate: Date; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnTransRcptTransLineToProfileOnBeforeProcessLine(TransferLine: Record "Transfer Line"; var ShouldProcess: Boolean; var Item: Record Item)
    begin
    end;

#if not CLEAN27
    internal procedure RunOnTransProdOrderToProfileOnBeforeProcessLine(ProdOrderLine: Record Microsoft.Manufacturing.Document."Prod. Order Line"; var ShouldProcess: Boolean)
    begin
        OnTransProdOrderToProfileOnBeforeProcessLine(ProdOrderLine, ShouldProcess);
    end;

    [Obsolete('Moved to codeunit MfgInvtProfileOffsetting', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnTransProdOrderToProfileOnBeforeProcessLine(ProdOrderLine: Record Microsoft.Manufacturing.Document."Prod. Order Line"; var ShouldProcess: Boolean)
    begin
    end;
#endif





    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnAfterCopyDatesToInvtProfile(var SupplyInvtProfile: Record "Inventory Profile"; var RequisitionLine: Record "Requisition Line")
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnCheckScheduleOutOnNotAllowScheduleOut(var SupplyInvtProfile: Record "Inventory Profile"; var ShouldExitAllowLotAccumulation: Boolean)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnMaintainPlanningLineOnAfterCalcPlanLineNo(RequisitionLine: Record "Requisition Line"; var PlanLineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSetAcceptActionOnCaseRefOrderTypeTransfer(ReqLine: Record "Requisition Line"; var AcceptActionMsg: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckPlanSKU(var StockkeepingUnit: Record "Stockkeeping Unit"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckSupplyAndTrack(var InventoryProfileFromDemand: Record "Inventory Profile"; var InventoryProfileFromSupply: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPrepareOrderToOrderLinkOnBeforeInventoryProfileModify(var InventoryProfile: Record "Inventory Profile"; var TempSKU: Record "Stockkeeping Unit" temporary; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeInitSupply(LastProjectedInventory: Decimal; SupplyWithinLeadtime: Decimal; var TempSKU: Record "Stockkeeping Unit" temporary; var IsHandled: Boolean; var PlanningStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterAdjustReorderQty(OrderQty: Decimal; var SKU: Record "Stockkeeping Unit"; SupplyLineNo: Integer; MinQty: Decimal; var DeltaQty: Decimal);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckScheduleOutOnBeforeAllowLotAccumulation(PossibleDate: Date; TargetDate: Date; SupplyInvtProfile: Record "Inventory Profile"; var IsHandled: Boolean; var Result: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckScheduleIn(var InventoryProfile: Record "Inventory Profile"; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; TargetDate: date; var PossibleDate: Date; LimitedHorizon: Boolean; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeCreateSupplyForward(var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var TempReminderInventoryProfile: Record "Inventory Profile" temporary; PlanningStartDate: Date; LastAvailableInventory: Decimal; LastProjectedInventory: Decimal; var NewSupplyHasTakenOver: Boolean; var IsHandled: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeFromLotAccumulationPeriodStartDate(LotAccumulationPeriodStartDate: Date; DemandDueDate: Date; var Result: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRescheduleOnBeforeModifySupplyInvtProfile(var SupplyInventoryProfile: Record "Inventory Profile"; TargetDate: Date; TargetTime: Time);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeInsertSafetyStockDemands(var InventoryProfile: Record "Inventory Profile"; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var DoUpdatePriorities: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertEmergencyOrderSupplyOnAfterInitSupply(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnMatchAttributesOnAfterInitSupply(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforePlanItemNextStateMatchQty(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var NextState: Option StartOver,MatchDates,MatchQty,CreateSupply,ReduceSupply,CloseDemand,CloseSupply,CloseLoop; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemSetInvtProfileFiltersOnBeforeSetCurrentKeys(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemNextStateCloseSupplyOnBeforeUpdateDemandUntrackedQty(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemNextStateCloseSupplyOnBeforeProcessActionMessageNew(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemNextStateCloseSupplyOnAfterCheckSupplyExist(var SupplyInventoryProfile: Record "Inventory Profile"; SupplyExist: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCheckForecastExist(var ProductionForecastEntry: Record Microsoft.Manufacturing.Forecast."Production Forecast Entry"; ExcludeForecastBefore: Date; OrderDate: Date; ToDate: Date; var ForecastExist: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetSupplyPriority(var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetDemandPriority(var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCommitTracking(var TempReservationEntryItemTrkgEntry: Record "Reservation Entry" temporary)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTransRcptTransLineToProfileOnAfterInsertInventoryProfile(var TransferLine: Record "Transfer Line"; var InventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemNextStateMatchDatesOnAfterCalcNewSupplyDate(var NewSupplyDate: Date; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var SupplyInvtProfile: Record "Inventory Profile"; LotAccumulationPeriodStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    procedure OnAfterFilterDemandSupplyRelatedToSKU(var InventoryProfile: Record "Inventory Profile"; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary)
    begin
    end;

#if not CLEAN27
    internal procedure RunOnBeforeTransProdOrderToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date; var IsHandled: Boolean)
    begin
        OnBeforeTransProdOrderToProfile(InventoryProfile, Item, ToDate, IsHandled);
    end;

    [Obsolete('Moved to codeunit MfgInvtProfileOffsetting', '27.0')]
    [IntegrationEvent(false, false)]
    local procedure OnBeforeTransProdOrderToProfile(var InventoryProfile: Record "Inventory Profile"; var Item: Record Item; ToDate: Date; var IsHandled: Boolean)
    begin
    end;
#endif

    [IntegrationEvent(false, false)]
    local procedure OnGetComponentsOnNewActionMessage(var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnGetComponentsOnUpdateForActionMessage(var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnBeforeCheckSupplyWithinLeadtime(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean; var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var TempTrkgReservationEntry: Record "Reservation Entry" temporary; var RequisitionLine: Record "Requisition Line"; var DoCheckSupplyWithinLeadtime: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckIsLotSpecificTracking(ItemTrackingCode: Record "Item Tracking Code"; var LotSepecificTracking: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckIsSNSpecificTracking(ItemTrackingCode: Record "Item Tracking Code"; var SNSepecificTracking: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterDisableRelations(var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnIsProdOrderPlanned(var ReservEntry: Record "Reservation Entry"; var Planned: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnGetComponentsAtLocationCode(var LocationCode: Code[10])
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnGetComponents(var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnGetRouting(var RequisitionLine: Record "Requisition Line")
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnFillTempSKUForLocation(var Item: Record Item; var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateTempSKUForComponentsLocationOnBeforeItemCopyFilter(var StockkeepingUnit: Record "Stockkeeping Unit"; var Item: Record Item; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAdjustTransferDatesOnAfterInboundWhseTimeSet(var TransferRequisitionLine: Record "Requisition Line"; var Location: Record Location; var InboundWhseTime: DateFormula)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeMatchAttributes(var SupplyInvtProfile: Record "Inventory Profile"; var DemandInvtProfile: Record "Inventory Profile"; var SkipMatchingAttributes: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnAfterCheckDemandMatchedSupplyPlanThisSKU(var DemandInventoryProfile: Record "Inventory Profile"; var SupplyInventoryProfile: Record "Inventory Profile"; PlanThisSKU: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnScheduleAllOutChangesSequenceOnBeforeCheckIfRescheduleIsNeeded(SupplyInventoryProfile: Record "Inventory Profile"; var NextRecExists: Integer; var IsHandled: Boolean; NewDate: Date; var NumberofSupplies: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCreateSupplyForwardOnBeforeLoopQtyToOrderMoreThanZero(var TempStockkeepingUnit: Record "Stockkeeping Unit" temporary; var QtoToOrder: Decimal; SupplyWithinLeadtime: Decimal; var SupplyInvtProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCommitTrackingOnAfterInsertReservationEntry(var ReservationEntry: Record "Reservation Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTransRcptTransLineToProfileOnBeforeInsertSupplyInvtProfile(var InventoryProfile: Record "Inventory Profile"; TransferLine: Record "Transfer Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnAfterInitLatestBucketStartDate(var LatestBucketStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertEmergencyOrderSupply(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var PlanningStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemOnAfterCreateInitialReorderPointSupply(var PlanningStartDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateSupplyForInitialSafetyStockWarning(var PlanningStartDate: Date; var SupplyInventoryProfile: Record "Inventory Profile")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSumUpProjectedSupply(var SupplyInventoryProfile: Record "Inventory Profile"; var FromDate: Date; var ToDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSumUpAvailableSupply(var SupplyInventoryProfile: Record "Inventory Profile"; var FromDate: Date; var ToDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnPlanItemCalcInitialInventoryOnBeforeChechkIncrementLastProjectedInventory(var SupplyInventoryProfile: Record "Inventory Profile"; var DemandInventoryProfile: Record "Inventory Profile"; var SupplyExists: Boolean; var DemandExists: Boolean; var IncrementLastProjectedInventory: Boolean; var LastProjectedInventory: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDeleteTrackingOnAfterSetReservEntryFilters(var ReservationEntry: Record "Reservation Entry"; StockkeepingUnit: Record "Stockkeeping Unit"; ToDate: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCalcInventoryProfileRemainingQty(var InventoryProfile: Record "Inventory Profile"; DocumentNo: Code[20]; LineNo: Integer; var RemQty: Decimal)
    begin
    end;
}