Table 1003 Job Planning Line, source in 29

Source29

src/Layers/W1/BaseApp/Projects/Project/Planning/JobPlanningLine.Table.al3920 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.Projects.Project.Planning;

using Microsoft.Assembly.Document;
using Microsoft.Assembly.History;
using Microsoft.Finance.Currency;
using Microsoft.Finance.GeneralLedger.Account;
using Microsoft.Finance.GeneralLedger.Ledger;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Foundation.Address;
using Microsoft.Foundation.ExtendedText;
using Microsoft.Foundation.Navigate;
using Microsoft.Foundation.PaymentTerms;
using Microsoft.Foundation.UOM;
using Microsoft.Inventory.Availability;
using Microsoft.Inventory.BOM;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Ledger;
using Microsoft.Inventory.Location;
using Microsoft.Inventory.Tracking;
using Microsoft.Pricing.Calculation;
using Microsoft.Pricing.PriceList;
using Microsoft.Projects.Project.Job;
using Microsoft.Projects.Project.Journal;
using Microsoft.Projects.Project.Ledger;
using Microsoft.Projects.Project.Setup;
using Microsoft.Projects.Resources.Ledger;
using Microsoft.Projects.Resources.Pricing;
using Microsoft.Projects.Resources.Resource;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.History;
using Microsoft.Sales.Customer;
using Microsoft.Sales.Pricing;
using Microsoft.Utilities;
using Microsoft.Warehouse.Activity;
using Microsoft.Warehouse.Journal;
using Microsoft.Warehouse.Request;
using Microsoft.Warehouse.Structure;
using System.Security.AccessControl;

table 1003 "Job Planning Line"
{
    Caption = 'Project Planning Line';
    DrillDownPageID = "Job Planning Lines";
    LookupPageID = "Job Planning Lines";
    DataClassification = CustomerContent;

    fields
    {
        field(1; "Line No."; Integer)
        {
            Caption = 'Line No.';
            ToolTip = 'Specifies the planning line''s entry number.';
            Editable = false;
        }
        field(2; "Job No."; Code[20])
        {
            Caption = 'Project No.';
            ToolTip = 'Specifies the number of the related project.';
            NotBlank = true;
            TableRelation = Job;
        }
        field(3; "Planning Date"; Date)
        {
            Caption = 'Planning Date';
            ToolTip = 'Specifies the date of the planning line. You can use the planning date for filtering the totals of the project, for example, if you want to see the scheduled usage for a specific month of the year.';

            trigger OnValidate()
            var
                IsHandled: Boolean;
            begin
                IsHandled := false;
                OnBeforeValidatePlanningDate(Rec, xRec, IsHandled);
                if IsHandled then
                    exit;

                ValidateModification(xRec."Planning Date" <> "Planning Date", Rec.FieldNo("Planning Date"));

                Validate("Document Date", "Planning Date");
                if ("Currency Date" = 0D) or ("Currency Date" = xRec."Planning Date") then
                    Validate("Currency Date", "Planning Date");
                if (Type <> Type::Text) and ("No." <> '') then
                    UpdateAllAmounts();
                if "Planning Date" <> 0D then
                    CheckItemAvailable(FieldNo("Planning Date"));
                if CurrFieldNo = FieldNo("Planned Delivery Date") then
                    UpdateReservation(CurrFieldNo)
                else
                    UpdateReservation(FieldNo("Planning Date"));
                "Planned Delivery Date" := "Planning Date";

                UpdatePlannedDueDate();
            end;
        }
        field(4; "Document No."; Code[20])
        {
            Caption = 'Document No.';
            ToolTip = 'Specifies a document number for the planning line.';

            trigger OnValidate()
            begin
                ValidateModification(xRec."Document No." <> "Document No.", Rec.FieldNo("Document No."));
            end;
        }
        field(5; Type; Enum "Job Planning Line Type")
        {
            Caption = 'Type';
            ToolTip = 'Specifies the type of account to which the planning line relates.';

            trigger OnValidate()
            begin
                ValidateModification(xRec.Type <> Type, Rec.FieldNo(Type));

                UpdateReservation(FieldNo(Type));

                Validate("No.", '');
            end;
        }
        field(7; "No."; Code[20])
        {
            Caption = 'No.';
            ToolTip = 'Specifies the number of the account to which the resource, item or general ledger account is posted, depending on your selection in the Type field.';
            TableRelation = if (Type = const(Resource)) Resource
            else
            if (Type = const(Item)) Item
            else
            if (Type = const("G/L Account")) "G/L Account"
            else
            if (Type = const(Text)) "Standard Text";
            ValidateTableRelation = false;

            trigger OnValidate()
            begin
                "No." := FindOrCreateRecordByNo("No.");
                ValidateModification(xRec."No." <> "No.", Rec.FieldNo("No."));

                CheckUsageLinkRelations();

                UpdateReservation(FieldNo("No."));

                UpdateDescription();

                if ("No." = '') or ("No." <> xRec."No.") then begin
                    "Unit of Measure Code" := '';
                    "Qty. per Unit of Measure" := 1;
                    "Variant Code" := '';
                    "Work Type Code" := '';
                    "Gen. Bus. Posting Group" := '';
                    "Gen. Prod. Posting Group" := '';
                    Description := '';
                    "Description 2" := '';
                    Reserve := Reserve::Never;
                    DeleteAmounts();
                    "Cost Factor" := 0;
                    if Type = Type::Item then begin
                        "Bin Code" := '';
                        if "No." <> '' then
                            InitLocation();
                        if "Bin Code" = '' then
                            SetDefaultBin();
                        JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo("No."));
                    end;
                    if "No." = '' then
                        exit;
                end;

                CopyFieldsFromJob();

                case Type of
                    Type::Resource:
                        CopyFromResource();
                    Type::Item:
                        CopyFromItem();
                    Type::"G/L Account":
                        CopyFromGLAccount();
                    Type::Text:
                        CopyFromStandardText();
                end;

                InitQtyToAsm();

                OnValidateNoOnAfterCopyFromAccount(Rec, xRec, Job);

                if Type <> Type::Text then
                    Validate(Quantity);
            end;
        }
        field(8; Description; Text[100])
        {
            Caption = 'Description';
            ToolTip = 'Specifies the name of the resource, item, or G/L account to which this entry applies. You can change the description.';

            trigger OnValidate()
            begin
                ValidateModification(xRec.Description <> Description, Rec.FieldNo(Description));
            end;
        }
        field(9; Quantity; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Quantity';
            ToolTip = 'Specifies the number of units of the resource, item, or general ledger account that should be specified on the planning line. If you later change the No., the quantity you have entered remains on the line.';
            DecimalPlaces = 0 : 5;

            trigger OnValidate()
            begin
                if (Quantity <> 0) and (Type = Type::Text) then
                    FieldError(Type);

                CheckQuantityPosted();

                CalcFields("Qty. Transferred to Invoice");
                if ("Qty. Transferred to Invoice" > 0) and (Quantity < "Qty. Transferred to Invoice") then
                    Error(QtyLessErr, FieldCaption(Quantity), FieldCaption("Qty. Transferred to Invoice"));
                if ("Qty. Transferred to Invoice" < 0) and (Quantity > "Qty. Transferred to Invoice") then
                    Error(QtyGreaterErr, FieldCaption(Quantity), FieldCaption("Qty. Transferred to Invoice"));

                case Type of
                    Type::Item:
                        if not Item.Get("No.") then
                            Error(MissingItemResourceGLErr, Type, Item.FieldCaption("No."));
                    Type::Resource:
                        if not Res.Get("No.") then
                            Error(MissingItemResourceGLErr, Type, Res.FieldCaption("No."));
                    Type::"G/L Account":
                        if not GLAcc.Get("No.") then
                            Error(MissingItemResourceGLErr, Type, GLAcc.FieldCaption("No."));
                end;

                Quantity := UOMMgt.RoundAndValidateQty(Quantity, "Qty. Rounding Precision", FieldCaption(Quantity));

                CalcQuantityBase();

                "Completely Picked" := "Qty. Picked" >= Quantity;

                UpdateRemainingQuantity();

                UpdateQtyToTransfer();
                UpdateQtyToInvoice();

                CheckItemAvailable(FieldNo(Quantity));
                UpdateReservation(FieldNo(Quantity));

                UpdateAllAmounts();

                InitQtyToAsm();
                if "Line Type" in ["Line Type"::"Both Budget and Billable", "Line Type"::Budget] then
                    Validate("Qty. to Assemble");

                if not BypassQtyValidation then
                    JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo(Quantity));

                BypassQtyValidation := false;
            end;
        }
        field(11; "Direct Unit Cost (LCY)"; Decimal)
        {
            AutoFormatType = 2;
            AutoFormatExpression = '';
            Caption = 'Direct Unit Cost (LCY)';

            trigger OnValidate()
            begin
                if ("Direct Unit Cost (LCY)" <> 0) and (Type = Type::Text) then
                    FieldError(Type);
            end;
        }
        field(12; "Unit Cost (LCY)"; Decimal)
        {
            AutoFormatType = 2;
            AutoFormatExpression = '';
            Caption = 'Unit Cost (LCY)';
            Editable = false;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Unit Cost (LCY)" <> "Unit Cost (LCY)", Rec.FieldNo("Unit Cost (LCY)"));

                if ("Unit Cost (LCY)" <> 0) and (Type = Type::Text) then
                    FieldError(Type);

                if (Type = Type::Item) and
                   Item.Get("No.") and
                   (Item."Costing Method" = Item."Costing Method"::Standard)
                then
                    UpdateAllAmounts()
                else begin
                    InitRoundingPrecisions();
                    "Unit Cost" := ConvertAmountToFCY("Unit Cost (LCY)", UnitAmountRoundingPrecisionFCY);
                    UpdateAllAmounts();
                end;
            end;
        }
        field(13; "Total Cost (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Total Cost (LCY)';
            Editable = false;
        }
        field(14; "Unit Price (LCY)"; Decimal)
        {
            AutoFormatType = 2;
            AutoFormatExpression = '';
            Caption = 'Unit Price (LCY)';
            Editable = false;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Unit Price (LCY)" <> "Unit Price (LCY)", Rec.FieldNo("Unit Price (LCY)"));
                if ("Unit Price (LCY)" <> 0) and (Type = Type::Text) then
                    FieldError(Type);

                InitRoundingPrecisions();
                "Unit Price" := ConvertAmountToFCY("Unit Price (LCY)", UnitAmountRoundingPrecisionFCY);
                UpdateAllAmounts();
            end;
        }
        field(15; "Total Price (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Total Price (LCY)';
            Editable = false;
        }
        field(16; "Resource Group No."; Code[20])
        {
            Caption = 'Resource Group No.';
            Editable = false;
            TableRelation = "Resource Group";
        }
        field(17; "Unit of Measure Code"; Code[10])
        {
            Caption = 'Unit of Measure Code';
            ToolTip = 'Specifies how each unit of the item or resource is measured, such as in pieces or hours. By default, the value in the Base Unit of Measure field on the item or resource card is inserted.';
            TableRelation = if (Type = const(Item)) "Item Unit of Measure".Code where("Item No." = field("No."))
            else
            if (Type = const(Resource)) "Resource Unit of Measure".Code where("Resource No." = field("No."))
            else
            "Unit of Measure";

            trigger OnValidate()
            var
                Resource: Record Resource;
            begin
                ValidateModification(xRec."Unit of Measure Code" <> "Unit of Measure Code", Rec.FieldNo("Unit of Measure Code"));

                GetGLSetup();
                case Type of
                    Type::Item:
                        begin
                            Item.Get("No.");
                            "Qty. per Unit of Measure" :=
                              UOMMgt.GetQtyPerUnitOfMeasure(Item, "Unit of Measure Code");
                            "Qty. Rounding Precision" := UOMMgt.GetQtyRoundingPrecision(Item, "Unit of Measure Code");
                            "Qty. Rounding Precision (Base)" := UOMMgt.GetQtyRoundingPrecision(Item, Item."Base Unit of Measure");
                            JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo("Unit of Measure Code"));
                        end;
                    Type::Resource:
                        begin
                            if CurrFieldNo <> FieldNo("Work Type Code") then
                                if "Work Type Code" <> '' then begin
                                    WorkType.Get("Work Type Code");
                                    if WorkType."Unit of Measure Code" <> '' then
                                        TestField("Unit of Measure Code", WorkType."Unit of Measure Code");
                                end else
                                    TestField("Work Type Code", '');
                            if "Unit of Measure Code" = '' then begin
                                Resource.Get("No.");
                                "Unit of Measure Code" := Resource."Base Unit of Measure";
                            end;
                            ResourceUnitOfMeasure.Get("No.", "Unit of Measure Code");
                            "Qty. per Unit of Measure" := ResourceUnitOfMeasure."Qty. per Unit of Measure";
                            "Quantity (Base)" := Quantity * "Qty. per Unit of Measure";
                        end;
                    Type::"G/L Account":
                        "Qty. per Unit of Measure" := 1;
                end;
                CheckItemAvailable(FieldNo("Unit of Measure Code"));
                UpdateReservation(FieldNo("Unit of Measure Code"));
                Validate(Quantity);
            end;
        }
        field(18; "Qty. Rounding Precision"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. Rounding Precision';
            InitValue = 0;
            DecimalPlaces = 0 : 5;
            MinValue = 0;
            MaxValue = 1;
            Editable = false;
        }
        field(19; "Qty. Rounding Precision (Base)"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. Rounding Precision (Base)';
            InitValue = 0;
            DecimalPlaces = 0 : 5;
            MinValue = 0;
            MaxValue = 1;
            Editable = false;
        }
        field(20; "Location Code"; Code[10])
        {
            Caption = 'Location Code';
            ToolTip = 'Specifies a location code for an item.';
            TableRelation = Location where("Use As In-Transit" = const(false));

            trigger OnValidate()
            var
                SkipValidateQuantity: Boolean;
            begin
                ValidateModification(xRec."Location Code" <> "Location Code", Rec.FieldNo("Location Code"));

                "Bin Code" := '';
                if Type = Type::Item then begin
                    GetLocation("Location Code");
                    CheckItemAvailable(FieldNo("Location Code"));
                    UpdateReservation(FieldNo("Location Code"));
                    OnBeforeValidateQuantity(Rec, xRec, SkipValidateQuantity);
                    if not SkipValidateQuantity then
                        Validate(Quantity);
                    SetDefaultBin();
                    JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo("Location Code"));
                    InitQtyToAsm();
                    ATOLink.UpdateAsmFromJobPlanningLine(Rec);

                    DeleteWarehouseRequest(xRec);
                    CreateWarehouseRequest();
                end;
            end;
        }
        field(29; "Last Date Modified"; Date)
        {
            Caption = 'Last Date Modified';
            Editable = false;
        }
        field(30; "User ID"; Code[50])
        {
            Caption = 'User ID';
            ToolTip = 'Specifies the ID of the user who posted the entry, to be used, for example, in the change log.';
            DataClassification = EndUserIdentifiableInformation;
            Editable = false;
            TableRelation = User."User Name";
        }
        field(32; "Work Type Code"; Code[10])
        {
            Caption = 'Work Type Code';
            ToolTip = 'Specifies which work type the resource applies to. Prices are updated based on this entry.';
            TableRelation = "Work Type";

            trigger OnValidate()
            var
                IsHandled: Boolean;
            begin
                IsHandled := false;
                OnBeforeValidateWorkTypeCode(Rec, xRec, IsHandled);
                if IsHandled then
                    exit;

                ValidateModification(xRec."Work Type Code" <> "Work Type Code", Rec.FieldNo("Work Type Code"));
                TestField(Type, Type::Resource);

                Validate("Line Discount %", 0);
                if ("Work Type Code" = '') and (xRec."Work Type Code" <> '') then begin
                    Res.Get("No.");
                    "Unit of Measure Code" := Res."Base Unit of Measure";
                    Validate("Unit of Measure Code");
                end;
                if WorkType.Get("Work Type Code") then
                    if WorkType."Unit of Measure Code" <> '' then begin
                        "Unit of Measure Code" := WorkType."Unit of Measure Code";
                        if ResourceUnitOfMeasure.Get("No.", "Unit of Measure Code") then
                            "Qty. per Unit of Measure" := ResourceUnitOfMeasure."Qty. per Unit of Measure";
                    end else begin
                        Res.Get("No.");
                        "Unit of Measure Code" := Res."Base Unit of Measure";
                        Validate("Unit of Measure Code");
                    end;
                Validate(Quantity);
            end;
        }
        field(33; "Customer Price Group"; Code[10])
        {
            Caption = 'Customer Price Group';
            TableRelation = "Customer Price Group";

            trigger OnValidate()
            begin
                if (Type = Type::Item) and ("No." <> '') then
                    UpdateAllAmounts();
            end;
        }
        field(79; "Country/Region Code"; Code[10])
        {
            Caption = 'Country/Region Code';
            Editable = false;
            TableRelation = "Country/Region";
        }
        field(80; "Gen. Bus. Posting Group"; Code[20])
        {
            Caption = 'Gen. Bus. Posting Group';
            ToolTip = 'Specifies the vendor''s or customer''s trade type to link transactions made for this business partner with the appropriate general ledger account according to the general posting setup.';
            Editable = false;
            TableRelation = "Gen. Business Posting Group";
        }
        field(81; "Gen. Prod. Posting Group"; Code[20])
        {
            Caption = 'Gen. Prod. Posting Group';
            ToolTip = 'Specifies the item''s product type to link transactions made for this item with the appropriate general ledger account according to the general posting setup.';
            Editable = false;
            TableRelation = "Gen. Product Posting Group";
        }
        field(83; "Document Date"; Date)
        {
            Caption = 'Document Date';
        }
        field(84; "Planning Due Date"; Date)
        {
            Caption = 'Planning Due Date';

            trigger OnValidate()
            begin
                JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo("Planning Due Date"));
            end;
        }
        field(900; "Qty. to Assemble"; Decimal)
        {
            AutoFormatType = 0;
            AccessByPermission = TableData "BOM Component" = R;
            Caption = 'Qty. to Assemble';
            ToolTip = 'Specifies how many units of the project planning line quantity that you want to supply by assembly.';
            DecimalPlaces = 0 : 5;
            DataClassification = CustomerContent;

            trigger OnValidate()
            begin
                if "Line Type" = "Line Type"::Billable then
                    FieldError("Line Type");

                if (not "Usage Link") and ("Qty. to Assemble" <> 0) then
                    FieldError("Usage Link");

                if ("Qty. to Assemble" <> Quantity) and ("Qty. to Assemble" <> 0) and WhsePickReqForLocation() then
                    FieldError("Qty. to Assemble", StrSubstNo(DifferentQtyToAssembleErr, FieldCaption(Quantity)));

                "Qty. to Assemble" := UOMMgt.RoundAndValidateQty("Qty. to Assemble", "Qty. Rounding Precision", FieldCaption("Qty. to Assemble"));
                "Qty. to Assemble (Base)" := CalcBaseQty("Qty. to Assemble", FieldCaption("Qty. to Assemble"), FieldCaption("Qty. to Assemble (Base)"));

                if "Qty. to Assemble (Base)" < 0 then
                    FieldError("Qty. to Assemble", NegativeQtyToAssembleErr);

                CheckItemAvailable(FieldNo("Qty. to Assemble"));
                ATOLink.UpdateAsmFromJobPlanningLine(Rec);
            end;
        }
        field(901; "Qty. to Assemble (Base)"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. to Assemble (Base)';
            DecimalPlaces = 0 : 5;
            DataClassification = CustomerContent;

            trigger OnValidate()
            begin
                TestField("Qty. per Unit of Measure", 1);
                Validate("Qty. to Assemble", "Qty. to Assemble (Base)");
            end;
        }
        field(902; "Assemble to Order"; Boolean)
        {
            AccessByPermission = TableData "BOM Component" = R;
            Caption = 'Assemble to Order';
            Editable = false;
            DataClassification = CustomerContent;
        }
        field(903; "BOM Item No."; Code[20])
        {
            Caption = 'BOM Item No.';
            TableRelation = Item;
            DataClassification = CustomerContent;
        }
        field(904; "Attached to Line No."; Integer)
        {
            Caption = 'Attached to Line No.';
            Editable = false;
            DataClassification = CustomerContent;
            TableRelation = "Job Planning Line"."Line No." where("Job No." = field("Job No."),
                                                           "Job Task No." = field("Job Task No."));
        }
        field(1000; "Job Task No."; Code[20])
        {
            Caption = 'Project Task No.';
            ToolTip = 'Specifies the number of the related project task.';
            NotBlank = true;
            TableRelation = "Job Task"."Job Task No." where("Job No." = field("Job No."));
        }
        field(1001; "Line Amount (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Line Amount (LCY)';
            Editable = false;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Line Amount (LCY)" <> "Line Amount (LCY)", Rec.FieldNo("Line Amount (LCY)"));
                if ("Line Amount (LCY)" <> 0) and (Type = Type::Text) then
                    FieldError(Type);

                InitRoundingPrecisions();
                "Line Amount" := ConvertAmountToFCY("Line Amount (LCY)", AmountRoundingPrecisionFCY);
                UpdateAllAmounts();
            end;
        }
        field(1002; "Unit Cost"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 2;
            Caption = 'Unit Cost';
            ToolTip = 'Specifies the cost of one unit of the item or resource on the line.';

            trigger OnValidate()
            begin
                ValidateModification(xRec."Unit Cost" <> "Unit Cost", Rec.FieldNo("Unit Cost"));
                if ("Unit Cost" <> 0) and (Type = Type::Text) then
                    FieldError(Type);
                UpdateAllAmounts();
            end;
        }
        field(1003; "Total Cost"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Total Cost';
            ToolTip = 'Specifies the total cost for the planning line. The total cost is in the project currency, which comes from the Currency Code field in the Project Card.';
            Editable = false;
        }
        field(1004; "Unit Price"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 2;
            Caption = 'Unit Price';
            ToolTip = 'Specifies the price of one unit of the item or resource. You can enter a price manually or have it entered according to the Price/Profit Calculation field on the related card.';

            trigger OnValidate()
            begin
                ValidateModification(xRec."Unit Price" <> "Unit Price", Rec.FieldNo("Unit Price"));
                if ("Unit Price" <> 0) and (Type = Type::Text) then
                    FieldError(Type);
                UpdateAllAmounts();
            end;
        }
        field(1005; "Total Price"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Total Price';
            ToolTip = 'Specifies the total price in the project currency on the planning line.';
            Editable = false;
        }
        field(1006; "Line Amount"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Line Amount';
            ToolTip = 'Specifies the amount that will be posted to the project ledger.';

            trigger OnValidate()
            begin
                ValidateModification(xRec."Line Amount" <> "Line Amount", Rec.FieldNo("Line Amount"));
                if ("Line Amount" <> 0) and (Type = Type::Text) then
                    FieldError(Type);

                UpdateAllAmounts();
            end;
        }
        field(1007; "Line Discount Amount"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Line Discount Amount';
            ToolTip = 'Specifies the discount amount that is granted for the item on the line.';

            trigger OnValidate()
            begin
                ValidateModification(xRec."Line Discount Amount" <> "Line Discount Amount", Rec.FieldNo("Line Discount Amount"));
                if ("Line Discount Amount" <> 0) and (Type = Type::Text) then
                    FieldError(Type);
                UpdateAllAmounts();
            end;
        }
        field(1008; "Line Discount Amount (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Line Discount Amount (LCY)';
            Editable = false;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Line Discount Amount (LCY)" <> "Line Discount Amount (LCY)", Rec.FieldNo("Line Discount Amount (LCY)"));
                if ("Line Discount Amount (LCY)" <> 0) and (Type = Type::Text) then
                    FieldError(Type);
                InitRoundingPrecisions();
                "Line Discount Amount" :=
                    ConvertAmountToFCY("Line Discount Amount (LCY)", AmountRoundingPrecisionFCY);
                UpdateAllAmounts();
            end;
        }
        field(1015; "Cost Factor"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Cost Factor';
            Editable = false;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Cost Factor" <> "Cost Factor", Rec.FieldNo("Cost Factor"));

                UpdateAllAmounts();
            end;
        }
        field(1019; "Serial No."; Code[50])
        {
            Caption = 'Serial No.';
            ToolTip = 'Specifies the serial number that is applied to the posted item if the planning line was created from the posting of a project journal line.';
            Editable = false;
        }
        field(1020; "Lot No."; Code[50])
        {
            Caption = 'Lot No.';
            ToolTip = 'Specifies the lot number that is applied to the posted item if the planning line was created from the posting of a project journal line.';
            Editable = false;
        }
        field(1021; "Line Discount %"; Decimal)
        {
            AutoFormatType = 0;
            BlankZero = true;
            Caption = 'Line Discount %';
            ToolTip = 'Specifies the discount percentage that is granted for the item on the line.';
            DecimalPlaces = 0 : 5;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Line Discount %" <> "Line Discount %", Rec.FieldNo("Line Discount %"));
                if ("Line Discount %" <> 0) and (Type = Type::Text) then
                    FieldError(Type);
                UpdateAllAmounts();
            end;
        }
        field(1022; "Line Type"; Enum "Job Planning Line Line Type")
        {
            Caption = 'Line Type';
            ToolTip = 'Specifies the type of planning line.';

            trigger OnValidate()
            begin
                "Schedule Line" := true;
                "Contract Line" := true;
                if "Line Type" = "Line Type"::Budget then
                    "Contract Line" := false;
                if "Line Type" = "Line Type"::Billable then
                    "Schedule Line" := false;

                if not "Contract Line" and (("Qty. Transferred to Invoice" <> 0) or ("Qty. Invoiced" <> 0)) then
                    Error(LineTypeErr, TableCaption(), FieldCaption("Line Type"), "Line Type");

                ControlUsageLink();
            end;
        }
        field(1023; "Currency Code"; Code[10])
        {
            Caption = 'Currency Code';
            ToolTip = 'Specifies the currency that is used on the entry.';
            Editable = false;
            TableRelation = Currency;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Currency Code" <> "Currency Code", Rec.FieldNo("Currency Code"));

                UpdateCurrencyFactor();
                UpdateAllAmounts();
            end;
        }
        field(1024; "Currency Date"; Date)
        {
            AccessByPermission = TableData Currency = R;
            Caption = 'Currency Date';
            ToolTip = 'Specifies the date that will be used to find the exchange rate for the currency in the Currency Date field.';

            trigger OnValidate()
            begin
                ValidateModification(xRec."Currency Date" <> "Currency Date", Rec.FieldNo("Currency Date"));

                UpdateCurrencyFactor();
                if (CurrFieldNo <> FieldNo("Planning Date")) and (Type <> Type::Text) and ("No." <> '') then
                    UpdateFromCurrency();
            end;
        }
        field(1025; "Currency Factor"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Currency Factor';
            DecimalPlaces = 0 : 15;
            Editable = false;
            MinValue = 0;

            trigger OnValidate()
            begin
                ValidateModification(xRec."Currency Factor" <> "Currency Factor", Rec.FieldNo("Currency Factor"));

                if ("Currency Code" = '') and ("Currency Factor" <> 0) then
                    FieldError("Currency Factor", StrSubstNo(CurrencyFactorErr, FieldCaption("Currency Code")));
                UpdateAllAmounts();
            end;
        }
        field(1026; "Schedule Line"; Boolean)
        {
            Caption = 'Budget Line';
            Editable = false;
            InitValue = true;
        }
        field(1027; "Contract Line"; Boolean)
        {
            Caption = 'Billable Line';
            ToolTip = 'Specifies whether this line is a billable line.';
            Editable = false;
        }
        field(1030; "Job Contract Entry No."; Integer)
        {
            Caption = 'Project Contract Entry No.';
            ToolTip = 'Specifies the entry number of the project planning line that the sales line is linked to.';
            Editable = false;
        }
        field(1035; "Invoiced Amount (LCY)"; Decimal)
        {
            CalcFormula = sum("Job Planning Line Invoice"."Invoiced Amount (LCY)" where("Job No." = field("Job No."),
                                                                                         "Job Task No." = field("Job Task No."),
                                                                                         "Job Planning Line No." = field("Line No.")));
            Caption = 'Invoiced Amount (LCY)';
            Editable = false;
            FieldClass = FlowField;
            AutoFormatType = 1;
            AutoFormatExpression = '';
        }
        field(1036; "Invoiced Cost Amount (LCY)"; Decimal)
        {
            CalcFormula = sum("Job Planning Line Invoice"."Invoiced Cost Amount (LCY)" where("Job No." = field("Job No."),
                                                                                              "Job Task No." = field("Job Task No."),
                                                                                              "Job Planning Line No." = field("Line No.")));
            Caption = 'Invoiced Cost Amount (LCY)';
            Editable = false;
            FieldClass = FlowField;
            AutoFormatType = 1;
            AutoFormatExpression = '';
        }
        field(1037; "VAT Unit Price"; Decimal)
        {
            Caption = 'VAT Unit Price';
            AutoFormatType = 2;
            AutoFormatExpression = Rec."Currency Code";
        }
        field(1038; "VAT Line Discount Amount"; Decimal)
        {
            Caption = 'VAT Line Discount Amount';
            AutoFormatType = 1;
            AutoFormatExpression = Rec."Currency Code";
        }
        field(1039; "VAT Line Amount"; Decimal)
        {
            Caption = 'VAT Line Amount';
            AutoFormatType = 1;
            AutoFormatExpression = Rec."Currency Code";
        }
        field(1041; "VAT %"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'VAT %';
        }
        field(1042; "Description 2"; Text[50])
        {
            Caption = 'Description 2';
            ToolTip = 'Specifies information in addition to the description.';
        }
        field(1043; "Job Ledger Entry No."; Integer)
        {
            BlankZero = true;
            Caption = 'Project Ledger Entry No.';
            Editable = false;
            TableRelation = "Job Ledger Entry";
        }
        field(1048; Status; Enum "Job Planning Line Status")
        {
            Caption = 'Status';
            ToolTip = 'Specifies the status of a project order.';
            Editable = false;
            InitValue = "Order";

            trigger OnValidate()
            begin
                JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo(Status));
            end;
        }
        field(1050; "Ledger Entry Type"; Enum "Job Ledger Entry Type")
        {
            Caption = 'Ledger Entry Type';
            ToolTip = 'Specifies the entry type of the project ledger entry associated with the planning line.';
        }
        field(1051; "Ledger Entry No."; Integer)
        {
            BlankZero = true;
            Caption = 'Ledger Entry No.';
            ToolTip = 'Specifies the entry number of the project ledger entry associated with the project planning line.';
            TableRelation = if ("Ledger Entry Type" = const(Resource)) "Res. Ledger Entry"
            else
            if ("Ledger Entry Type" = const(Item)) "Item Ledger Entry"
            else
            if ("Ledger Entry Type" = const("G/L Account")) "G/L Entry";
        }
        field(1052; "System-Created Entry"; Boolean)
        {
            Caption = 'System-Created Entry';
            ToolTip = 'Specifies that an entry has been created by Business Central and is related to a project ledger entry. The check box is selected automatically.';
        }
        field(1053; "Usage Link"; Boolean)
        {
            Caption = 'Usage Link';
            ToolTip = 'Specifies whether the Usage Link field applies to the project planning line. When this check box is selected, usage entries are linked to the project planning line. Selecting this check box creates a link to the project planning line from places where usage has been posted, such as the project journal or a purchase line. You can select this check box only if the line type of the project planning line is Budget or Both Budget and Billable.';

            trigger OnValidate()
            var
                IsHandled: Boolean;
            begin
                IsHandled := false;
                OnBeforeValidateUsageLink(Rec, xRec, IsHandled);
                if not IsHandled then
                    if "Usage Link" and ("Line Type" = "Line Type"::Billable) then
                        Error(UsageLinkErr, FieldCaption("Usage Link"), TableCaption(), FieldCaption("Line Type"), "Line Type");

                ControlUsageLink();

                CheckItemAvailable(FieldNo("Usage Link"));
                UpdateReservation(FieldNo("Usage Link"));
            end;
        }
        field(1060; "Remaining Qty."; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Remaining Qty.';
            ToolTip = 'Specifies the remaining quantity of the resource, item, or G/L Account that remains to complete a project. The quantity is calculated as the difference between Quantity and Qty. Posted.';
            DecimalPlaces = 0 : 5;
            Editable = false;

            trigger OnValidate()
            begin
                Validate("Remaining Qty. (Base)", CalcBaseQty("Remaining Qty.", FieldCaption("Remaining Qty."), FieldCaption("Remaining Qty. (Base)")));
            end;
        }
        field(1061; "Remaining Qty. (Base)"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Remaining Qty. (Base)';
            DecimalPlaces = 0 : 5;
            Editable = false;
        }
        field(1062; "Remaining Total Cost"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Remaining Total Cost';
            ToolTip = 'Specifies the remaining total cost for the planning line. The total cost is in the project currency, which comes from the Currency Code field in the Project Card.';
            Editable = false;
        }
        field(1063; "Remaining Total Cost (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Remaining Total Cost (LCY)';
            Editable = false;
        }
        field(1064; "Remaining Line Amount"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Remaining Line Amount';
            ToolTip = 'Specifies the amount that will be posted to the project ledger.';
            Editable = false;
        }
        field(1065; "Remaining Line Amount (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Remaining Line Amount (LCY)';
            Editable = false;
        }
        field(1070; "Qty. Posted"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. Posted';
            ToolTip = 'Specifies the quantity that has been posted to the project ledger, if the Usage Link check box has been selected.';
            DecimalPlaces = 0 : 5;
            Editable = false;
        }
        field(1071; "Qty. to Transfer to Journal"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. to Transfer to Journal';
            ToolTip = 'Specifies the quantity you want to transfer to the project journal. Its default value is calculated as quantity minus the quantity that has already been posted, if the Apply Usage Link check box has been selected.';
            DecimalPlaces = 0 : 5;

            trigger OnValidate()
            begin
                if ("Qty. to Transfer to Journal" <> 0) and (Type = Type::Text) then
                    FieldError(Type);
            end;
        }
        field(1072; "Posted Total Cost"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Posted Total Cost';
            ToolTip = 'Specifies the total cost that has been posted to the project ledger, if the Usage Link check box has been selected.';
            Editable = false;
        }
        field(1073; "Posted Total Cost (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Posted Total Cost (LCY)';
            Editable = false;
        }
        field(1074; "Posted Line Amount"; Decimal)
        {
            AutoFormatExpression = Rec."Currency Code";
            AutoFormatType = 1;
            Caption = 'Posted Line Amount';
            ToolTip = 'Specifies the amount that has been posted to the project ledger. This field is only filled in if the Apply Usage Link check box selected on the project card.';
            Editable = false;
        }
        field(1075; "Posted Line Amount (LCY)"; Decimal)
        {
            AutoFormatType = 1;
            AutoFormatExpression = '';
            Caption = 'Posted Line Amount (LCY)';
            Editable = false;
        }
        field(1080; "Qty. Transferred to Invoice"; Decimal)
        {
            AutoFormatType = 0;
            CalcFormula = sum("Job Planning Line Invoice"."Quantity Transferred" where("Job No." = field("Job No."),
                                                                                        "Job Task No." = field("Job Task No."),
                                                                                        "Job Planning Line No." = field("Line No.")));
            Caption = 'Qty. Transferred to Invoice';
            ToolTip = 'Specifies the quantity that has been transferred to a sales invoice or credit memo.';
            DecimalPlaces = 0 : 5;
            Editable = false;
            FieldClass = FlowField;
        }
        field(1081; "Qty. to Transfer to Invoice"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. to Transfer to Invoice';
            ToolTip = 'Specifies the quantity you want to transfer to the sales invoice or credit memo. The value in this field is calculated as Quantity - Qty. Transferred to Invoice.';
            DecimalPlaces = 0 : 5;

            trigger OnValidate()
            var
                IsHandled: Boolean;
            begin
                IsHandled := false;
                OnBeforeValidateQtyToTransferToInvoice(Rec, xRec, IsHandled);
                if IsHandled then
                    exit;

                if "Qty. to Transfer to Invoice" = 0 then
                    exit;

                if Type = Type::Text then
                    FieldError(Type);

                if "Contract Line" then begin
                    if Quantity = "Qty. Transferred to Invoice" then
                        Error(QtyAlreadyTransferredErr, TableCaption);

                    if Quantity > 0 then begin
                        if ("Qty. to Transfer to Invoice" > 0) and ("Qty. to Transfer to Invoice" > (Quantity - "Qty. Transferred to Invoice")) or
                           ("Qty. to Transfer to Invoice" < 0)
                        then
                            Error(QtyToTransferToInvoiceErr, FieldCaption("Qty. to Transfer to Invoice"), 0, Quantity - "Qty. Transferred to Invoice");
                    end else
                        if ("Qty. to Transfer to Invoice" > 0) or
                           ("Qty. to Transfer to Invoice" < 0) and ("Qty. to Transfer to Invoice" < (Quantity - "Qty. Transferred to Invoice"))
                        then
                            Error(QtyToTransferToInvoiceErr, FieldCaption("Qty. to Transfer to Invoice"), Quantity - "Qty. Transferred to Invoice", 0);
                end else
                    Error(NoContractLineErr, FieldCaption("Qty. to Transfer to Invoice"), TableCaption(), "Line Type");
            end;
        }
        field(1090; "Qty. Invoiced"; Decimal)
        {
            AutoFormatType = 0;
            CalcFormula = sum("Job Planning Line Invoice"."Quantity Transferred" where("Job No." = field("Job No."),
                                                                                        "Job Task No." = field("Job Task No."),
                                                                                        "Job Planning Line No." = field("Line No."),
                                                                                        "Document Type" = filter("Posted Invoice" | "Posted Credit Memo")));
            Caption = 'Qty. Invoiced';
            ToolTip = 'Specifies the quantity that been posted through a sales invoice.';
            DecimalPlaces = 0 : 5;
            Editable = false;
            FieldClass = FlowField;
        }
        field(1091; "Qty. to Invoice"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. to Invoice';
            ToolTip = 'Specifies the quantity that remains to be invoiced. It is calculated as Quantity - Qty. Invoiced.';
            DecimalPlaces = 0 : 5;
            Editable = false;
        }
        field(1100; "Reserved Quantity"; Decimal)
        {
            AutoFormatType = 0;
            AccessByPermission = TableData Item = R;
            CalcFormula = - sum("Reservation Entry".Quantity where("Source Type" = const(1003),
#pragma warning disable AL0603
                                                                   "Source Subtype" = field(Status),
#pragma warning restore
                                                                   "Source ID" = field("Job No."),
                                                                   "Source Ref. No." = field("Job Contract Entry No."),
                                                                   "Reservation Status" = const(Reservation)));
            Caption = 'Reserved Quantity';
            ToolTip = 'Specifies the quantity of the item that is reserved for the project planning line.';
            DecimalPlaces = 0 : 5;
            Editable = false;
            FieldClass = FlowField;
        }
        field(1101; "Reserved Qty. (Base)"; Decimal)
        {
            AccessByPermission = TableData Item = R;
            AutoFormatType = 0;
            CalcFormula = - sum("Reservation Entry"."Quantity (Base)" where("Source Type" = const(1003),
#pragma warning disable AL0603
                                                                            "Source Subtype" = field(Status),
#pragma warning restore
                                                                            "Source ID" = field("Job No."),
                                                                            "Source Ref. No." = field("Job Contract Entry No."),
                                                                            "Reservation Status" = const(Reservation)));
            Caption = 'Reserved Qty. (Base)';
            DecimalPlaces = 0 : 5;
            Editable = false;
            FieldClass = FlowField;

            trigger OnValidate()
            begin
                TestField("Qty. per Unit of Measure");
                UpdatePlanned();
            end;
        }
        field(1102; Reserve; Enum "Reserve Method")
        {
            AccessByPermission = TableData Item = R;
            Caption = 'Reserve';
            ToolTip = 'Specifies whether or not a reservation can be made for items on the current line. The field is not applicable if the Type field is set to Resource, Cost, or G/L Account.';

            trigger OnValidate()
            begin
                if Reserve <> Reserve::Never then begin
                    TestField(Type, Type::Item);
                    TestField("No.");
                    TestField("Usage Link");
                end;
                CalcFields("Reserved Qty. (Base)");
                if (Reserve = Reserve::Never) and ("Reserved Qty. (Base)" > 0) then
                    TestField("Reserved Qty. (Base)", 0);

                if xRec.Reserve = Reserve::Always then begin
                    GetItem();
                    if Item.Reserve = Item.Reserve::Always then
                        TestField(Reserve, Reserve::Always);
                end;
            end;
        }
        field(1103; Planned; Boolean)
        {
            Caption = 'Planned';
            Editable = false;
        }
        field(5402; "Variant Code"; Code[10])
        {
            Caption = 'Variant Code';
            ToolTip = 'Specifies the variant of the item on the line.';
            TableRelation = if (Type = const(Item)) "Item Variant".Code where("Item No." = field("No."), Blocked = const(false));

            trigger OnValidate()
            var
                ItemVariant: Record "Item Variant";
            begin
                ValidateModification(xRec."Variant Code" <> "Variant Code", Rec.FieldNo("Variant Code"));

                if Rec."Variant Code" = '' then begin
                    if Type = Type::Item then begin
                        Item.Get("No.");
                        Description := Item.Description;
                        "Description 2" := Item."Description 2";
                    end
                end else begin
                    TestField(Type, Type::Item);
                    ItemVariant.SetLoadFields(Description, "Description 2", Blocked);
                    ItemVariant.Get("No.", "Variant Code");
                    ItemVariant.TestField(Blocked, false);
                    Description := ItemVariant.Description;
                    "Description 2" := ItemVariant."Description 2";
                end;
                GetItemTranslation();
                Validate(Quantity);
                CheckItemAvailable(FieldNo("Variant Code"));
                UpdateReservation(FieldNo("Variant Code"));
                InitQtyToAsm();
                ATOLink.UpdateAsmFromJobPlanningLine(Rec);
                JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo("Variant Code"));
            end;
        }
        field(5403; "Bin Code"; Code[20])
        {
            Caption = 'Bin Code';
            ToolTip = 'Specifies the bin where the selected item will be put away or picked in warehouse and inventory processes. If you specify a bin code in the To-Project Bin Code field on the Location page, that bin will be suggested when you choose the location.';
            TableRelation = Bin.Code where("Location Code" = field("Location Code"));

            trigger OnValidate()
            var
                WMSManagement: Codeunit "WMS Management";
                WhseIntegrationMgt: Codeunit "Whse. Integration Management";
                BinCodeCaption: Text[30];
            begin
                ValidateModification(xRec."Bin Code" <> "Bin Code", Rec.FieldNo("Bin Code"));
                if "Bin Code" <> '' then begin
                    TestField("Location Code");
                    GetLocation("Location Code");
                    TestField(Type, Type::Item);
                    GetItem();
                    Item.TestField(Type, Item.Type::Inventory);
                    CheckItemAvailable(FieldNo("Bin Code"));
                    WMSManagement.FindBin("Location Code", "Bin Code", '');
                    BinCodeCaption := CopyStr(FieldCaption("Bin Code"), 1, 30);
                    WhseIntegrationMgt.CheckBinTypeAndCode(
                        Database::"Job Planning Line", BinCodeCaption, "Location Code", "Bin Code", 0);
                    CheckBin();
                end;

                UpdateReservation(FieldNo("Bin Code"));
                JobWarehouseMgt.JobPlanningLineVerifyChange(Rec, xRec, FieldNo("Bin Code"));
                ATOLink.UpdateAsmBinCodeFromJobPlanningLine(Rec);
            end;

            trigger OnLookup()
            var
                WMSManagement: Codeunit "WMS Management";
                BinCode: Code[20];
            begin
                TestField("Location Code");
                TestField(Type, Type::Item);

                if Item.Get(Rec."No.") then
                    if BinCode <> '' then
                        Item.TestField(Type, Item.Type::Inventory);

                if Quantity > 0 then
                    BinCode := WMSManagement.BinContentLookUp("Location Code", "No.", "Variant Code", '', "Bin Code")
                else
                    BinCode := WMSManagement.BinLookUp("Location Code", "No.", "Variant Code", '');

                if BinCode <> '' then
                    Validate("Bin Code", BinCode);
            end;
        }
        field(5404; "Qty. per Unit of Measure"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. per Unit of Measure';
            DecimalPlaces = 0 : 5;
            Editable = false;
            InitValue = 1;
        }
        field(5410; "Quantity (Base)"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Quantity (Base)';
            DecimalPlaces = 0 : 5;

            trigger OnValidate()
            var
                IsHandled: Boolean;
            begin
                IsHandled := false;
                OnBeforeValidateQuantityBase(Rec, xRec, CurrFieldNo, IsHandled);
                if IsHandled then
                    exit;

                TestField("Qty. per Unit of Measure", 1);
                Validate(Quantity, "Quantity (Base)");
            end;
        }
        field(5790; "Requested Delivery Date"; Date)
        {
            Caption = 'Requested Delivery Date';

            trigger OnValidate()
            begin
                if ("Requested Delivery Date" <> xRec."Requested Delivery Date") and
                   ("Promised Delivery Date" <> 0D)
                then
                    Error(
                      RequestedDeliveryDateErr,
                      FieldCaption("Requested Delivery Date"),
                      FieldCaption("Promised Delivery Date"));

                if "Requested Delivery Date" <> 0D then
                    Validate("Planned Delivery Date", "Requested Delivery Date")
            end;
        }
        field(5791; "Promised Delivery Date"; Date)
        {
            Caption = 'Promised Delivery Date';

            trigger OnValidate()
            begin
                if "Promised Delivery Date" <> 0D then
                    Validate("Planned Delivery Date", "Promised Delivery Date")
                else
                    Validate("Requested Delivery Date");
            end;
        }
        field(5794; "Planned Delivery Date"; Date)
        {
            Caption = 'Planned Delivery Date';
            ToolTip = 'Specifies the date that is planned to deliver the item connected to the project planning line. For a resource, the planned delivery date is the date that the resource performs services with respect to the project.';

            trigger OnValidate()
            begin
                Validate("Planning Date", "Planned Delivery Date");
            end;
        }
        field(6515; "Package No."; Code[50])
        {
            Caption = 'Package No.';
            CaptionClass = '6,1';
            Editable = false;
        }
        field(7000; "Price Calculation Method"; Enum "Price Calculation Method")
        {
            Caption = 'Price Calculation Method';
            ToolTip = 'Specifies the method that will be used for price calculation in the item journal line.';
        }
        field(7001; "Cost Calculation Method"; Enum "Price Calculation Method")
        {
            Caption = 'Cost Calculation Method';
            ToolTip = 'Specifies the method that will be used for cost calculation in the item journal line.';
        }
        field(7300; "Pick Qty."; Decimal)
        {
            AutoFormatType = 0;
            CalcFormula = sum("Warehouse Activity Line"."Qty. Outstanding" where("Activity Type" = filter(<> "Put-away"),
                                                                                  "Source Type" = const(1003),
                                                                                  "Source No." = field("Job No."),
                                                                                  "Source Line No." = field("Job Contract Entry No."),
                                                                                  "Source Subline No." = field("Line No."),
                                                                                  "Unit of Measure Code" = field("Unit of Measure Code"),
                                                                                  "Action Type" = filter(" " | Place),
                                                                                  "Original Breakbulk" = const(false),
                                                                                  "Breakbulk No." = const(0)));
            Caption = 'Pick Qty.';
            DecimalPlaces = 0 : 5;
            Editable = false;
            FieldClass = FlowField;
        }
        field(7301; "Qty. Picked"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. Picked';
            ToolTip = 'Specifies the quantity of the item you have picked for the project planning line.';
            DecimalPlaces = 0 : 5;
            Editable = false;

            trigger OnValidate()
            begin
                "Qty. Picked (Base)" :=
                    UOMMgt.CalcBaseQty("No.", "Variant Code", "Unit of Measure Code", "Qty. Picked", "Qty. per Unit of Measure");

                "Completely Picked" := "Qty. Picked" >= Quantity;
            end;
        }
        field(7302; "Qty. Picked (Base)"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Qty. Picked (Base)';
            DecimalPlaces = 0 : 5;
            Editable = false;
        }
        field(7303; "Completely Picked"; Boolean)
        {
            Caption = 'Completely Picked';
            Editable = false;
        }
        field(7304; "Pick Qty. (Base)"; Decimal)
        {
            AutoFormatType = 0;
            CalcFormula = sum("Warehouse Activity Line"."Qty. Outstanding (Base)" where("Activity Type" = filter(<> "Put-away"),
                                                                                         "Source Type" = const(1003),
                                                                                         "Source No." = field("Job No."),
                                                                                         "Source Line No." = field("Job Contract Entry No."),
                                                                                         "Source Subline No." = field("Line No."),
                                                                                         "Action Type" = filter(" " | Place),
                                                                                         "Original Breakbulk" = const(false),
                                                                                         "Breakbulk No." = const(0)));
            Caption = 'Pick Qty. (Base)';
            DecimalPlaces = 0 : 5;
            Editable = false;
            FieldClass = FlowField;
        }
        field(7305; "Qty. on Journal"; Decimal)
        {
            AutoFormatType = 0;
            CalcFormula = sum("Job Journal Line"."Quantity (Base)" where("Job No." = field("Job No."),
                                                                  "Job Task No." = field("Job Task No."),
                                                                  "Job Planning Line No." = field("Line No."),
                                                                  Type = field(Type),
                                                                  "No." = field("No.")));
            Caption = 'Qty. on Journal';
            DecimalPlaces = 0 : 5;
            Editable = false;
            FieldClass = FlowField;
        }
    }

    keys
    {
        key(Key1; "Job No.", "Job Task No.", "Line No.")
        {
            Clustered = true;
        }
        key(Key2; "Job No.", "Job Task No.", "Schedule Line", "Planning Date")
        {
            SumIndexFields = "Total Price (LCY)", "Total Cost (LCY)", "Line Amount (LCY)", "Remaining Total Cost (LCY)", "Remaining Line Amount (LCY)", "Total Cost", "Line Amount";
        }
        key(Key3; "Job No.", "Job Task No.", "Contract Line", "Planning Date")
        {
            SumIndexFields = "Total Price (LCY)", "Total Cost (LCY)", "Line Amount (LCY)", "Remaining Total Cost (LCY)", "Remaining Line Amount (LCY)", "Total Cost", "Line Amount";
        }
        key(Key4; "Job No.", "Job Task No.", "Schedule Line", "Currency Date")
        {
        }
        key(Key5; "Job No.", "Job Task No.", "Contract Line", "Currency Date")
        {
        }
        key(Key6; "Job No.", "Schedule Line", Type, "No.", "Planning Date")
        {
            SumIndexFields = "Quantity (Base)";
        }
        key(Key7; "Job No.", "Schedule Line", Type, "Resource Group No.", "Planning Date")
        {
            SumIndexFields = "Quantity (Base)";
        }
        key(Key8; Status, "Schedule Line", Type, "No.", "Planning Date")
        {
            SumIndexFields = "Quantity (Base)";
        }
        key(Key9; Status, "Schedule Line", Type, "Resource Group No.", "Planning Date")
        {
            SumIndexFields = "Quantity (Base)";
        }
        key(Key10; "Job No.", "Contract Line")
        {
        }
        key(Key11; "Job Contract Entry No.")
        {
        }
        key(Key12; Type, "No.", "Job No.", "Job Task No.", "Usage Link", "System-Created Entry")
        {
        }
        key(Key13; Status, Type, "No.", "Variant Code", "Location Code", "Planning Date")
        {
            SumIndexFields = "Remaining Qty. (Base)";
        }
        key(Key14; "Job No.", "Planning Date", "Document No.")
        {
        }
    }

    fieldgroups
    {
    }

    trigger OnDelete()
    var
        JobUsageLink: Record "Job Usage Link";
        IsHandled: Boolean;
    begin
        ConfirmDeletion();

        PreventDeleteIfPurchaseExists(Rec);

        ValidateModification(true, 0);
        CheckRelatedJobPlanningLineInvoice();

        if "Usage Link" then begin
            JobUsageLink.SetRange("Job No.", "Job No.");
            JobUsageLink.SetRange("Job Task No.", "Job Task No.");
            JobUsageLink.SetRange("Line No.", "Line No.");
            IsHandled := false;
            OnDeleteOnAfterSetFilterOnJobUsageLink(Rec, JobUsageLink, IsHandled);
            if not IsHandled then
                if not JobUsageLink.IsEmpty() then
                    Error(JobUsageLinkErr, TableCaption);
        end;

        if (Rec.Quantity <> 0) and ItemExists(Rec."No.") then begin
            JobPlanningLineReserve.DeleteLine(Rec);
            CalcFields("Reserved Qty. (Base)");
            TestField("Reserved Qty. (Base)", 0);
        end;

        DeleteAttachedJobPlanningLines();

        if "Schedule Line" then
            Job.UpdateOverBudgetValue("Job No.", false, "Total Cost (LCY)");

        JobWarehouseMgt.JobPlanningLineDelete(Rec);

        if Rec.Type = Rec.Type::Item then
            ATOLink.DeleteAsmFromJobPlanningLine(Rec);

        DeleteWarehouseRequest(Rec);
    end;

    trigger OnInsert()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeOnInsert(Rec, IsHandled);
        if IsHandled then
            exit;

        LockTable();
        GetJob();
        if Job.Blocked = Job.Blocked::All then
            Job.TestBlocked();
        JobTask.Get("Job No.", "Job Task No.");
        JobTask.TestField("Job Task Type", JobTask."Job Task Type"::Posting);
        InitJobPlanningLine();
        if Quantity <> 0 then
            UpdateReservation(0);

        if "Schedule Line" then
            Job.UpdateOverBudgetValue("Job No.", false, "Total Cost (LCY)");

        CreateWarehouseRequest();
    end;

    trigger OnModify()
    begin
        "Last Date Modified" := Today;
        "User ID" := CopyStr(UserId(), 1, MaxStrLen("User ID"));

        if ((Quantity <> 0) or (xRec.Quantity <> 0)) and ItemExists(xRec."No.") then
            UpdateReservation(0);

        if "Schedule Line" then
            Job.UpdateOverBudgetValue("Job No.", false, "Total Cost (LCY)");

        if xRec."Location Code" <> Rec."Location Code" then begin
            DeleteWarehouseRequest(xRec);
            CreateWarehouseRequest();
        end;
    end;

    trigger OnRename()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeOnRename(Rec, IsHandled);
        if IsHandled then
            exit;

        Error(RecordRenameErr, FieldCaption("Job No."), FieldCaption("Job Task No."), TableCaption);
    end;

    var
        GLAcc: Record "G/L Account";
        Location: Record Location;
        Item: Record Item;
        JobTask: Record "Job Task";
        Res: Record Resource;
        WorkType: Record "Work Type";
        ResourceUnitOfMeasure: Record "Resource Unit of Measure";
        CurrExchRate: Record "Currency Exchange Rate";
        SKU: Record "Stockkeeping Unit";
        StandardText: Record "Standard Text";
        ItemTranslation: Record "Item Translation";
        GLSetup: Record "General Ledger Setup";
        ATOLink: Record "Assemble-to-Order Link";
        JobPlanningLineReserve: Codeunit "Job Planning Line-Reserve";
        JobWarehouseMgt: Codeunit "Job Warehouse Mgt.";
        UOMMgt: Codeunit "Unit of Measure Management";
        ItemCheckAvail: Codeunit "Item-Check Avail.";
        CurrencyFactorErr: Label 'cannot be specified without %1', Comment = '%1 = Currency Code field name';
        RecordRenameErr: Label 'You cannot change the %1 or %2 of this %3.', Comment = '%1 = Project Number field name; %2 = Project Task Number field name; %3 = Project Planning Line table name';
        CurrencyDate: Date;
        MissingItemResourceGLErr: Label 'You must specify %1 %2 in planning line.', Comment = '%1 = Document Type (Item, Resoure, or G/L); %2 = Field name';
        HasGotGLSetup: Boolean;
        QtyLessErr: Label '%1 cannot be less than %2.', Comment = '%1 = Name of first field to compare; %2 = Name of second field to compare';
        ControlUsageLinkErr: Label 'The %1 must be a %2 and %3 must be enabled, because linked Project Ledger Entries exist.', Comment = '%1 = Project Planning Line table name; %2 = Caption for field Schedule Line; %3 = Captiion for field Usage Link';
        JobUsageLinkErr: Label 'This %1 cannot be deleted because linked project ledger entries exist.', Comment = '%1 = Project Planning Line table name';
        BypassQtyValidation: Boolean;
        SkipCheckForMultipleJobsOnSalesLine: Boolean;
        CalledFromHeader: Boolean;
        LinkedJobLedgerErr: Label 'You cannot change this value because linked project ledger entries exist.';
#pragma warning disable AA0470
        LineTypeErr: Label 'The %1 cannot be of %2 %3 because it is transferred to an invoice.', Comment = 'The Project Planning Line cannot be of Line Type Schedule, because it is transferred to an invoice.';
#pragma warning restore AA0470
        QtyToTransferToInvoiceErr: Label '%1 may not be lower than %2 and may not exceed %3.', Comment = '%1 = Qty. to Transfer to Invoice field name; %2 = First value in comparison; %3 = Second value in comparison';
        AutoReserveQst: Label 'Automatic reservation is not possible.\Do you want to reserve items manually?';
        NoContractLineErr: Label '%1 cannot be set on a %2 of type %3.', Comment = '%1 = Qty. to Transfer to Invoice field name; %2 = Project Planning Line table name; %3 = The project''s line type';
        QtyAlreadyTransferredErr: Label 'The %1 has already been completely transferred.', Comment = '%1 = Project Planning Line table name';
#pragma warning disable AA0470
        UsageLinkErr: Label '%1 cannot be enabled on a %2 with %3 %4.', Comment = 'Usage Link cannot be enabled on a Project Planning Line with Line Type Schedule';
#pragma warning restore AA0470
        QtyGreaterErr: Label '%1 cannot be higher than %2.', Comment = '%1 = Caption for field Quantity; %2 = Captiion for field Qty. Transferred to Invoice';
        RequestedDeliveryDateErr: Label 'You cannot change the %1 when the %2 has been filled in.', Comment = '%1 = Caption for field Requested Delivery Date; %2 = Captiion for field Promised Delivery Date';
        NotPossibleJobPlanningLineErr: Label 'It is not possible to deleted project planning line transferred to an invoice.';
        NegativeQtyToAssembleErr: Label ' must be positive.', Comment = 'Qty. to Assemble can''t be negative';
        DifferentQtyToAssembleErr: Label ' must be equal to %1.', Comment = 'Qty. to Assemble must be equal to Quantity, %1 = Quantity';
        CannotBeMoreErr: Label 'cannot be more than %1', Comment = '%1 = Quantity';
        ConfirmDeleteQst: Label '%1 = %2 is greater than %3 = %4. If you delete the %5, the items will remain in the operation area until you put them away.\Any related item tracking information defined during the pick process will be deleted.\Do you still want to delete the %5?', Comment = '%1 = FieldCaption("Qty. Picked"), %2 = "Qty. Picked", %3 = FieldCaption("Qty. Posted"), %4 = "Qty. Posted", %5 = TableCaption';
        PurchRcptLineExistErr: Label 'You cannot delete this Project Planning Line because a Purchase Receipt %1 exists for it.', Comment = 'Purchase Receipt Line already exist for the Job Planning Line';

    protected var
        Job: Record Job;
        UnitAmountRoundingPrecision: Decimal;
        AmountRoundingPrecision: Decimal;
        UnitAmountRoundingPrecisionFCY: Decimal;
        AmountRoundingPrecisionFCY: Decimal;

    internal procedure OpenItemTrackingLines()
    begin
        JobPlanningLineReserve.CallItemTracking(Rec);
    end;

    internal procedure IsInbound(): Boolean
    begin
        exit("Quantity (Base)" < 0);
    end;

    procedure CheckItemAvailable(CalledByFieldNo: Integer)
    begin
        if CurrFieldNo <> CalledByFieldNo then
            exit;
        if (Type <> Type::Item) or ("No." = '') then
            exit;
        if Quantity <= 0 then
            exit;
        if not (Status in [Status::Order]) then
            exit;

        if ItemCheckAvail.JobPlanningLineCheck(Rec) then
            ItemCheckAvail.RaiseUpdateInterruptedError();
    end;

    local procedure CheckBin()
    var
        BinContent: Record "Bin Content";
        Bin: Record Bin;
    begin
        if "Bin Code" <> '' then begin
            GetLocation("Location Code");
            if not Location."Check Whse. Class" then
                exit;

            if BinContent.Get(
                 "Location Code", "Bin Code",
                 "No.", "Variant Code", "Unit of Measure Code")
            then begin
                if not BinContent.CheckWhseClass(false) then
                    "Bin Code" := '';
            end else begin
                Bin.Get("Location Code", "Bin Code");
                if not Bin.CheckWhseClass("No.", false) then
                    "Bin Code" := '';
            end;
        end;
    end;

    local procedure DeleteAttachedJobPlanningLines()
    var
        AttachedJobPlanningLine: Record "Job Planning Line";
    begin
        if Rec."Line No." = 0 then
            exit;
        AttachedJobPlanningLine.SetRange("Job No.", Rec."Job No.");
        AttachedJobPlanningLine.SetRange("Job Task No.", Rec."Job Task No.");
        AttachedJobPlanningLine.SetRange("Attached to Line No.", Rec."Line No.");
        AttachedJobPlanningLine.SetFilter("Line No.", '<>%1', Rec."Line No.");
        if not AttachedJobPlanningLine.IsEmpty() then
            AttachedJobPlanningLine.DeleteAll(true);
    end;

    /// <summary>
    /// Use this method to set the global Job variable.
    /// This is useful for passing unsaved job record changes.
    /// </summary>
    /// <param name="NewJob">The job record</param>
    procedure SetJob(NewJob: Record Job)
    begin
        Job := NewJob;
    end;

    procedure CopyFieldsFromJob()
    begin
        GetJob();
        Rec."Customer Price Group" := Job."Customer Price Group";
        Rec."Price Calculation Method" := Job.GetPriceCalculationMethod();
        Rec."Cost Calculation Method" := Job.GetCostCalculationMethod();

        OnAfterCopyFieldsFromJob(Rec, xRec, Job);
    end;

    /// <summary>
    /// Renames all Job Planning Line "No." values for the specified LineType and OldNo to NewNo.
    /// </summary>
    /// <param name="LineType">The type of the job planning line.</param>
    /// <param name="OldNo">The old number to be replaced.</param>
    /// <param name="NewNo">The new number to set.</param>
    procedure RenameNo(LineType: Enum "Job Planning Line Type"; OldNo: Code[20]; NewNo: Code[20])
    begin
        Reset();
        SetRange(Type, LineType);
        SetRange("No.", OldNo);
        if not Rec.IsEmpty() then
            ModifyAll("No.", NewNo, true);
    end;

    local procedure CheckQuantityPosted()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckQuantityPosted(Rec, xRec, IsHandled);
        if IsHandled then
            exit;

        if "Usage Link" then
            if not BypassQtyValidation then begin
                if ("Qty. Posted" > 0) and (Quantity < "Qty. Posted") then
                    Error(QtyLessErr, FieldCaption(Quantity), FieldCaption("Qty. Posted"));
                if ("Qty. Posted" < 0) and (Quantity > "Qty. Posted") then
                    Error(QtyGreaterErr, FieldCaption(Quantity), FieldCaption("Qty. Posted"));
            end;
    end;

    local procedure CopyFromResource()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCopyFromResource(Rec, xRec, IsHandled);
        if not IsHandled then begin
            Res.Get("No.");
            Res.CheckResourcePrivacyBlocked(false);
            Res.TestField(Blocked, false);
            Res.TestField("Gen. Prod. Posting Group");
            if Description = '' then
                Description := Res.Name;
            if "Description 2" = '' then
                "Description 2" := Res."Name 2";
            "Gen. Prod. Posting Group" := Res."Gen. Prod. Posting Group";
            "Resource Group No." := Res."Resource Group No.";
            Validate("Unit of Measure Code", Res."Base Unit of Measure");
        end;
        OnAfterCopyFromResource(Rec, Job, Res);
    end;

    local procedure CopyFromItem()
    begin
        GetItem();
        Item.TestField(Blocked, false);
        Item.TestField("Gen. Prod. Posting Group");
        Description := Item.Description;
        "Description 2" := Item."Description 2";
        if Job."Language Code" <> '' then
            GetItemTranslation();
        "Gen. Prod. Posting Group" := Item."Gen. Prod. Posting Group";
        Validate("Unit of Measure Code", Item."Base Unit of Measure");
        if "Usage Link" then
            if Item.Reserve = Item.Reserve::Optional then
                Reserve := Job.Reserve
            else
                Reserve := Item.Reserve;
        OnAfterCopyFromItem(Rec, Job, Item);
    end;

    local procedure CopyFromGLAccount()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCopyFromGLAccount(Rec, IsHandled, Job);
        if not IsHandled then begin
            GLAcc.Get("No.");
            GLAcc.CheckGLAcc();
            GLAcc.TestField("Direct Posting", true);
            GLAcc.TestField("Gen. Prod. Posting Group");
            Description := GLAcc.Name;
            "Gen. Bus. Posting Group" := GLAcc."Gen. Bus. Posting Group";
            "Gen. Prod. Posting Group" := GLAcc."Gen. Prod. Posting Group";
            "Unit of Measure Code" := '';
            "Direct Unit Cost (LCY)" := 0;
            "Unit Cost (LCY)" := 0;
            "Unit Price" := 0;
        end;

        OnAfterCopyFromGLAccount(Rec, Job, GLAcc);
    end;

    local procedure CopyFromStandardText()
    begin
        StandardText.Get("No.");
        Description := StandardText.Description;
    end;

    local procedure CalcQuantityBase()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCalcQuantityBase(Rec, xRec, CurrFieldNo, IsHandled);
        if IsHandled then
            exit;

        "Quantity (Base)" := CalcBaseQty(Quantity, FieldCaption(Quantity), FieldCaption("Quantity (Base)"));
    end;

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

    procedure GetJob()
    begin
        if ("Job No." <> Job."No.") and ("Job No." <> '') then
            Job.Get("Job No.");
        OnAfterGetJob(Rec, Job);
    end;

    procedure UpdateCurrencyFactor()
    begin
        if "Currency Code" <> '' then begin
            if "Currency Date" = 0D then
                CurrencyDate := WorkDate()
            else
                CurrencyDate := "Currency Date";
            OnUpdateCurrencyFactorOnBeforeGetExchangeRate(Rec, CurrExchRate);
            "Currency Factor" := CurrExchRate.ExchangeRate(CurrencyDate, "Currency Code");
        end else
            "Currency Factor" := 0;
        OnAfterUpdateCurrencyFactor(Rec);
    end;

    local procedure ItemExists(ItemNo: Code[20]): Boolean
    var
        Item2: Record Item;
    begin
        if Type = Type::Item then
            if not Item2.Get(ItemNo) then
                exit(false);
        exit(true);
    end;

    local procedure GetItem()
    begin
        if "No." <> Item."No." then
            if not Item.Get("No.") then
                Clear(Item);
    end;

    local procedure GetSKU() Result: Boolean
    begin
        if (SKU."Location Code" = "Location Code") and
           (SKU."Item No." = "No.") and
           (SKU."Variant Code" = "Variant Code")
        then
            exit(true);

        if SKU.Get("Location Code", "No.", "Variant Code") then
            exit(true);

        Result := false;
        OnAfterGetSKU(Rec, Result);
    end;

    procedure InitRoundingPrecisions()
    var
        Currency: Record Currency;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInitRoundingPrecisions(Rec, AmountRoundingPrecision, UnitAmountRoundingPrecision, AmountRoundingPrecisionFCY, UnitAmountRoundingPrecisionFCY, IsHandled);
        if IsHandled then
            exit;

        if (AmountRoundingPrecision = 0) or
           (UnitAmountRoundingPrecision = 0) or
           (AmountRoundingPrecisionFCY = 0) or
           (UnitAmountRoundingPrecisionFCY = 0)
        then begin
            Clear(Currency);
            Currency.InitRoundingPrecision();
            AmountRoundingPrecision := Currency."Amount Rounding Precision";
            UnitAmountRoundingPrecision := Currency."Unit-Amount Rounding Precision";

            if "Currency Code" <> '' then begin
                Currency.Get("Currency Code");
                Currency.TestField("Amount Rounding Precision");
                Currency.TestField("Unit-Amount Rounding Precision");
            end;

            AmountRoundingPrecisionFCY := Currency."Amount Rounding Precision";
            UnitAmountRoundingPrecisionFCY := Currency."Unit-Amount Rounding Precision";
        end;
    end;

    procedure Caption(): Text
    var
        JobForCaption: Record Job;
        JobTaskForCaption: Record "Job Task";
        Result: Text;
        IsHandled: Boolean;
    begin
        Result := '';
        IsHandled := false;
        OnBeforeCaption(Rec, IsHandled, Result);
        if IsHandled then
            exit(Result);

        JobForCaption.SetLoadFields("No.", Description);
        if not JobForCaption.Get("Job No.") then
            exit('');
        JobTaskForCaption.SetLoadFields("Job No.", "Job Task No.", Description);
        if not JobTaskForCaption.Get("Job No.", "Job Task No.") then
            exit('');
        exit(StrSubstNo('%1 %2 %3 %4',
            JobForCaption."No.",
            JobForCaption.Description,
            JobTaskForCaption."Job Task No.",
            JobTaskForCaption.Description));
    end;

    procedure SetUpNewLine(LastJobPlanningLine: Record "Job Planning Line")
    begin
        "Document Date" := LastJobPlanningLine."Planning Date";
        "Document No." := LastJobPlanningLine."Document No.";
        Type := LastJobPlanningLine.Type;
        Validate("Line Type", LastJobPlanningLine."Line Type");
        GetJob();
        "Currency Code" := Job."Currency Code";
        UpdateCurrencyFactor();
        if LastJobPlanningLine."Planning Date" <> 0D then
            Validate("Planning Date", LastJobPlanningLine."Planning Date");
        "Price Calculation Method" := Job.GetPriceCalculationMethod();
        "Cost Calculation Method" := Job.GetCostCalculationMethod();

        OnAfterSetupNewLine(Rec, LastJobPlanningLine);
    end;

    procedure InitJobPlanningLine()
    var
        JobJnlManagement: Codeunit JobJnlManagement;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeInitJobPlanningLine(Rec, Job, IsHandled);
        if not IsHandled then begin
            GetJob();
            if "Planning Date" = 0D then
                Validate("Planning Date", WorkDate());
            "Currency Code" := Job."Currency Code";
            UpdateCurrencyFactor();
            "VAT Unit Price" := 0;
            "VAT Line Discount Amount" := 0;
            "VAT Line Amount" := 0;
            "VAT %" := 0;
            "Job Contract Entry No." := JobJnlManagement.GetNextEntryNo();
            "User ID" := CopyStr(UserId(), 1, MaxStrLen("User ID"));
            "Last Date Modified" := 0D;
            Status := Job.Status;
            ControlUsageLink();
            "Country/Region Code" := Job."Bill-to Country/Region Code";
        end;
        OnAfterInitJobPlanningLine(Rec);
    end;

    local procedure DeleteAmounts()
    begin
        Quantity := 0;
        "Quantity (Base)" := 0;

        "Direct Unit Cost (LCY)" := 0;
        "Unit Cost (LCY)" := 0;
        "Unit Cost" := 0;

        "Total Cost (LCY)" := 0;
        "Total Cost" := 0;

        "Unit Price (LCY)" := 0;
        "Unit Price" := 0;

        "Total Price (LCY)" := 0;
        "Total Price" := 0;

        "Line Amount (LCY)" := 0;
        "Line Amount" := 0;

        "Line Discount %" := 0;

        "Line Discount Amount (LCY)" := 0;
        "Line Discount Amount" := 0;

        "Remaining Qty." := 0;
        "Remaining Qty. (Base)" := 0;
        "Remaining Total Cost" := 0;
        "Remaining Total Cost (LCY)" := 0;
        "Remaining Line Amount" := 0;
        "Remaining Line Amount (LCY)" := 0;

        "Qty. Posted" := 0;
        "Qty. to Transfer to Journal" := 0;
        "Posted Total Cost" := 0;
        "Posted Total Cost (LCY)" := 0;
        "Posted Line Amount" := 0;
        "Posted Line Amount (LCY)" := 0;

        "Qty. to Transfer to Invoice" := 0;
        "Qty. to Invoice" := 0;

        OnAfterDeleteAmounts(Rec);
    end;

    local procedure UpdateFromCurrency()
    begin
        UpdateAllAmounts();
    end;

    local procedure GetItemTranslation()
    begin
        GetJob();
        if ItemTranslation.Get("No.", "Variant Code", Job."Language Code") then begin
            Description := ItemTranslation.Description;
            "Description 2" := ItemTranslation."Description 2";
        end;
    end;

    local procedure GetGLSetup()
    begin
        if HasGotGLSetup then
            exit;
        GLSetup.Get();
        HasGotGLSetup := true;
    end;

    procedure GetRemainingQty(var RemainingQty: Decimal; var RemainingQtyBase: Decimal)
    begin
        CalcFields("Reserved Quantity", "Reserved Qty. (Base)");
        RemainingQty := "Remaining Qty." - Abs("Reserved Quantity");
        RemainingQtyBase := "Remaining Qty. (Base)" - Abs("Reserved Qty. (Base)");
        OnAfterGetRemainingQty(Rec, RemainingQty, RemainingQtyBase);
    end;

    procedure GetReservationQty(var QtyReserved: Decimal; var QtyReservedBase: Decimal; var QtyToReserve: Decimal; var QtyToReserveBase: Decimal): Decimal
    begin
        CalcFields("Reserved Quantity", "Reserved Qty. (Base)");
        QtyReserved := "Reserved Quantity";
        QtyReservedBase := "Reserved Qty. (Base)";
        QtyToReserve := "Remaining Qty.";
        QtyToReserveBase := "Remaining Qty. (Base)";
        exit("Qty. per Unit of Measure");
    end;

    procedure GetSourceCaption(): Text
    begin
        exit(StrSubstNo('%1 %2 %3', Status, "Job No.", "No."));
    end;

    procedure SetReservationEntry(var ReservEntry: Record "Reservation Entry")
    begin
        ReservEntry.SetSource(Database::"Job Planning Line", Status.AsInteger(), "Job No.", "Job Contract Entry No.", '', 0);
        ReservEntry.SetItemData("No.", Description, "Location Code", "Variant Code", "Qty. per Unit of Measure");
        if Type <> Type::Item then
            ReservEntry."Item No." := '';
        ReservEntry."Expected Receipt Date" := "Planning Date";
        ReservEntry."Shipment Date" := "Planning Date";
    end;

    procedure SetReservationFilters(var ReservEntry: Record "Reservation Entry")
    begin
        ReservEntry.SetSourceFilter(Database::"Job Planning Line", Status.AsInteger(), "Job No.", "Job Contract Entry No.", false);
        ReservEntry.SetSourceFilter('', 0);

        OnAfterSetReservationFilters(ReservEntry, Rec);
    end;

    procedure ReservEntryExist(): Boolean
    var
        ReservEntry: Record "Reservation Entry";
    begin
        ReservEntry.InitSortingAndFilters(false);
        SetReservationFilters(ReservEntry);
        exit(not ReservEntry.IsEmpty);
    end;

    procedure UpdateAllAmounts()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateAllAmounts(Rec, xRec, IsHandled, CurrFieldNo);
        if IsHandled then
            exit;

        InitRoundingPrecisions();

        UpdateUnitCost();
        FindPriceAndDiscount(CurrFieldNo);
        UpdateTotalCost();
        HandleCostFactor();
        UpdateUnitPrice();
        UpdateTotalPrice();
        UpdateAmountsAndDiscounts();
        UpdateRemainingCostsAndAmounts("Currency Date", "Currency Factor");

        OnAfterUpdateAllAmounts(Rec, xRec);
    end;

    local procedure UpdateUnitCost()
    var
        RetrievedCost: Decimal;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateUnitCost(Rec, IsHandled, xRec);
        if IsHandled then
            exit;

        GetJob();
        if (Type = Type::Item) and Item.Get("No.") then
            if Item."Costing Method" = Item."Costing Method"::Standard then
                if RetrieveCostPrice(CurrFieldNo) then begin
                    if GetSKU() then
                        "Unit Cost (LCY)" := Round(SKU."Unit Cost" * "Qty. per Unit of Measure", UnitAmountRoundingPrecision)
                    else
                        "Unit Cost (LCY)" := Round(Item."Unit Cost" * "Qty. per Unit of Measure", UnitAmountRoundingPrecision);

                    "Unit Cost" := ConvertAmountToFCY("Unit Cost (LCY)", UnitAmountRoundingPrecisionFCY);
                end else
                    RecalculateAmounts(Job."Exch. Calculation (Cost)", xRec."Unit Cost", "Unit Cost", "Unit Cost (LCY)")
            else
                if RetrieveCostPrice(CurrFieldNo) or (CurrFieldNo = FieldNo("Unit Price")) then begin
                    CalculateRetrievedCost(RetrievedCost);
                    if not (CurrFieldNo = FieldNo("Unit Price")) then begin
                        "Unit Cost" := ConvertAmountToFCY(RetrievedCost, UnitAmountRoundingPrecisionFCY);
                        "Unit Cost (LCY)" := Round(RetrievedCost, UnitAmountRoundingPrecision);
                    end;
                end else
                    RecalculateAmounts(Job."Exch. Calculation (Cost)", xRec."Unit Cost", "Unit Cost", "Unit Cost (LCY)")
        else
            RecalculateAmounts(Job."Exch. Calculation (Cost)", xRec."Unit Cost", "Unit Cost", "Unit Cost (LCY)");
    end;

    local procedure CalculateRetrievedCost(var RetrievedCost: Decimal)
    var
        FullyInvoiced: Boolean;
    begin
        CalcFields("Qty. Invoiced", "Invoiced Cost Amount (LCY)");
        FullyInvoiced := (Quantity = "Qty. Invoiced") and ("Qty. Invoiced" <> 0);
        if FullyInvoiced then
            RetrievedCost := "Invoiced Cost Amount (LCY)" / "Qty. Invoiced"
        else
            if GetSKU() then
                RetrievedCost := SKU."Unit Cost" * Rec."Qty. per Unit of Measure"
            else
                RetrievedCost := Item."Unit Cost" * Rec."Qty. per Unit of Measure";
        OnAfterCalculateRetrievedCost(Rec, xRec, SKU, Item, RetrievedCost);
    end;

    procedure AfterResourceFindCost(var ResourceCost: Record "Resource Cost");
    begin
        OnAfterResourceFindCost(Rec, ResourceCost);
    end;

    protected procedure RetrieveCostPrice(CalledByFieldNo: Integer): Boolean
    var
        ShouldRetrieveCostPrice: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        ShouldRetrieveCostPrice := false;
        OnBeforeRetrieveCostPrice(Rec, xRec, ShouldRetrieveCostPrice, IsHandled, CalledByFieldNo);
        if IsHandled then
            exit(ShouldRetrieveCostPrice);

        if CalledByFieldNo <> 0 then
            case Type of
                Type::Item:
                    if not (CalledByFieldNo in
                            [FieldNo("No."), FieldNo(Quantity), FieldNo("Location Code"),
                            FieldNo("Variant Code"), FieldNo("Unit of Measure Code")])
                    then
                        exit(false);
                Type::Resource:
                    if not (CalledByFieldNo in
                         [FieldNo("No."), FieldNo(Quantity), FieldNo("Work Type Code"), FieldNo("Unit of Measure Code")])
                    then
                        exit(false);
                Type::"G/L Account":
                    if not (CalledByFieldNo in [FieldNo("No."), FieldNo(Quantity)]) then
                        exit(false);
            end;

        case Type of
            Type::Item:
                ShouldRetrieveCostPrice :=
                    ("No." <> xRec."No.") or
                    IsQuantityChangedForPrice() or
                    ("Location Code" <> xRec."Location Code") or
                    ("Variant Code" <> xRec."Variant Code") or
                    (not BypassQtyValidation and (Quantity <> xRec.Quantity)) or
                    ("Unit of Measure Code" <> xRec."Unit of Measure Code");
            Type::Resource:
                ShouldRetrieveCostPrice :=
                    ("No." <> xRec."No.") or
                    IsQuantityChangedForPrice() or
                    ("Work Type Code" <> xRec."Work Type Code") or
                    ("Unit of Measure Code" <> xRec."Unit of Measure Code");
            Type::"G/L Account":
                ShouldRetrieveCostPrice :=
                    ("No." <> xRec."No.") or
                    IsQuantityChangedForPrice();
            else
                exit(false);
        end;
        exit(ShouldRetrieveCostPrice);
    end;

    local procedure IsQuantityChangedForPrice(): Boolean;
    var
        PriceCalculationMgt: Codeunit "Price Calculation Mgt.";
    begin
        if Quantity = xRec.Quantity then
            exit(false);
        exit(PriceCalculationMgt.IsExtendedPriceCalculationEnabled());
    end;

    local procedure UpdateTotalCost()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateTotalCost(Rec, AmountRoundingPrecisionFCY, AmountRoundingPrecision, IsHandled);
        if IsHandled then
            exit;

        "Total Cost" := Round("Unit Cost" * Quantity, AmountRoundingPrecisionFCY);
        "Total Cost (LCY)" := ConvertAmountToLCY("Total Cost", AmountRoundingPrecision);
    end;

    procedure FindPriceAndDiscount(CalledByFieldNo: Integer)
    var
        PriceType: Enum "Price Type";
        IsHandled: Boolean;
    begin
        if RetrieveCostPrice(CalledByFieldNo) and ("No." <> '') then begin
            IsHandled := false;
            OnBeforeFindPriceAndDiscount(CalledByFieldNo, IsHandled, Rec, xRec);
            if IsHandled then
                exit;

            ApplyPrice(PriceType::Sale, CalledByFieldNo);
            ApplyPrice(PriceType::Purchase, CalledByFieldNo);
            case Type of
                Type::Resource:
                    begin
                        "Unit Cost (LCY)" := ConvertAmountToLCY("Unit Cost", UnitAmountRoundingPrecision);
                        "Direct Unit Cost (LCY)" := ConvertAmountToLCY("Direct Unit Cost (LCY)", UnitAmountRoundingPrecision);
                    end;
                Type::"G/L Account":
                    if "Unit Cost" <> xRec."Unit Cost" then
                        "Unit Cost (LCY)" := ConvertAmountToLCY("Unit Cost", UnitAmountRoundingPrecision);
            end;
            OnAfterFindPriceAndDiscount(Rec, xRec, CalledByFieldNo);
        end;
    end;

    procedure ApplyPrice(PriceType: enum "Price Type"; CalledByFieldNo: Integer)
    var
        PriceCalculationMgt: Codeunit "Price Calculation Mgt.";
        LineWithPrice: Interface "Line With Price";
        PriceCalculation: Interface "Price Calculation";
        Line: Variant;
    begin
        GetLineWithPrice(LineWithPrice);
        LineWithPrice.SetLine(PriceType, Rec);
        PriceCalculationMgt.GetHandler(LineWithPrice, PriceCalculation);
        PriceCalculation.ApplyPrice(CalledByFieldNo);
        if PriceType = PriceType::Sale then
            PriceCalculation.ApplyDiscount();
        PriceCalculation.GetLine(Line);
        Rec := Line;
    end;

    procedure GetLineWithPrice(var LineWithPrice: Interface "Line With Price")
    var
        JobPlanningLinePrice: Codeunit "Job Planning Line - Price";
    begin
        LineWithPrice := JobPlanningLinePrice;
        OnAfterGetLineWithPrice(LineWithPrice);
    end;

    local procedure HandleCostFactor()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeHandleCostFactor(Rec, xRec, IsHandled);
        if IsHandled then
            exit;

        if ("Cost Factor" <> 0) and
           ((("Unit Cost" <> xRec."Unit Cost") or ("Cost Factor" <> xRec."Cost Factor")) or
            ((Quantity <> xRec.Quantity) or ("Location Code" <> xRec."Location Code")))
        then
            "Unit Price" := Round("Unit Cost" * "Cost Factor", UnitAmountRoundingPrecisionFCY)
        else
            if (Item."Price/Profit Calculation" = Item."Price/Profit Calculation"::"Price=Cost+Profit") and
               (Item."Profit %" < 100) and
               ("Unit Cost" <> xRec."Unit Cost")
            then
                "Unit Price" := Round("Unit Cost" / (1 - Item."Profit %" / 100), UnitAmountRoundingPrecisionFCY);

        OnAfterHandleCostFactor(Rec, xRec, Item);
    end;

    local procedure UpdateUnitPrice()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateUnitPrice(Rec, xRec, IsHandled);
        if not IsHandled then begin
            GetJob();
            RecalculateAmounts(Job."Exch. Calculation (Price)", xRec."Unit Price", "Unit Price", "Unit Price (LCY)");
        end;
        OnAfterUpdateUnitPrice(Rec, xRec, AmountRoundingPrecision, AmountRoundingPrecisionFCY);
    end;

    procedure RecalculateAmounts(JobExchCalculation: Option "Fixed FCY","Fixed LCY"; xAmount: Decimal; var Amount: Decimal; var AmountLCY: Decimal)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeRecalculateAmounts(Rec, xRec, AmountLCY, IsHandled, Amount);
        if IsHandled then
            exit;

        if (xRec."Currency Factor" <> "Currency Factor") and
           (Amount = xAmount) and (JobExchCalculation = JobExchCalculation::"Fixed LCY")
        then begin
            Amount := ConvertAmountToFCY(AmountLCY, UnitAmountRoundingPrecisionFCY);
            exit;
        end;

        AmountLCY := ConvertAmountToLCY(Amount, UnitAmountRoundingPrecision);
    end;

    local procedure ConvertAmountToFCY(AmountLCY: Decimal; Precision: Decimal) AmountFCY: Decimal;
    begin
        AmountFCY :=
            Round(
                CurrExchRate.ExchangeAmtLCYToFCY(
                    "Currency Date", "Currency Code", AmountLCY, "Currency Factor"),
                Precision);
    end;

    local procedure ConvertAmountToLCY(AmountFCY: Decimal; Precision: Decimal): Decimal;
    begin
        exit(ConvertAmountToLCY("Currency Date", AmountFCY, "Currency Factor", Precision));
    end;

    local procedure ConvertAmountToLCY(PostingDate: Date; AmountFCY: Decimal; CurrencyFactor: Decimal; Precision: Decimal) AmountLCY: Decimal;
    begin
        AmountLCY :=
            Round(
                CurrExchRate.ExchangeAmtFCYToLCY(
                    PostingDate, "Currency Code", AmountFCY, CurrencyFactor),
                Precision);
    end;

    local procedure UpdateTotalPrice()
    begin
        "Total Price" := Round(Quantity * "Unit Price", AmountRoundingPrecisionFCY);
        "Total Price (LCY)" := ConvertAmountToLCY("Total Price", AmountRoundingPrecision);
        OnAfterUpdateTotalPrice(Rec);
    end;

    procedure UpdateAmountsAndDiscounts()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateAmountsAndDiscounts(Rec, xRec, IsHandled);
        if not IsHandled then begin
            // Patch for fixing Edit-in-Excel issues due to dependency on xRec.
            if not GuiAllowed() then
                if xRec.Get(xRec.RecordId()) then;

            if "Total Price" = 0 then begin
                "Line Amount" := 0;
                "Line Discount Amount" := 0;
            end else
                if ("Line Amount" <> xRec."Line Amount") and ("Line Discount Amount" = xRec."Line Discount Amount") then begin
                    "Line Amount" := Round("Line Amount", AmountRoundingPrecisionFCY);
                    "Line Discount Amount" := "Total Price" - "Line Amount";
                    "Line Discount %" :=
                      Round("Line Discount Amount" / "Total Price" * 100, 0.00001);
                end else
                    if ("Line Discount Amount" <> xRec."Line Discount Amount") and ("Line Amount" = xRec."Line Amount") then begin
                        "Line Discount Amount" := Round("Line Discount Amount", AmountRoundingPrecisionFCY);
                        "Line Amount" := "Total Price" - "Line Discount Amount";
                        "Line Discount %" :=
                          Round("Line Discount Amount" / "Total Price" * 100, 0.00001);
                    end else
                        if ("Line Discount Amount" = xRec."Line Discount Amount") and
                           (("Line Amount" <> xRec."Line Amount") or ("Line Discount %" <> xRec."Line Discount %") or
                            ("Total Price" <> xRec."Total Price"))
                        then begin
                            "Line Discount Amount" :=
                              Round("Total Price" * "Line Discount %" / 100, AmountRoundingPrecisionFCY);
                            "Line Amount" := "Total Price" - "Line Discount Amount";
                        end;

            "Line Amount (LCY)" := ConvertAmountToLCY("Line Amount", AmountRoundingPrecision);
            "Line Discount Amount (LCY)" := ConvertAmountToLCY("Line Discount Amount", AmountRoundingPrecision);
        end;
        OnAfterUpdateAmountsAndDiscounts(Rec, xRec);
    end;

    procedure Use(PostedQty: Decimal; PostedTotalCost: Decimal; PostedLineAmount: Decimal; PostingDate: Date; CurrencyFactor: Decimal)
    begin
        if "Usage Link" then begin
            InitRoundingPrecisions();
            // Update Quantity Posted
            Validate("Qty. Posted", "Qty. Posted" + PostedQty);

            // Update Posted Costs and Amounts.
            "Posted Total Cost" += Round(PostedTotalCost, AmountRoundingPrecisionFCY);
            "Posted Total Cost (LCY)" :=
                ConvertAmountToLCY(
                    PostingDate, "Posted Total Cost", CurrencyFactor, AmountRoundingPrecision);

            "Posted Line Amount" += Round(PostedLineAmount, AmountRoundingPrecisionFCY);
            "Posted Line Amount (LCY)" :=
                ConvertAmountToLCY(
                    PostingDate, "Posted Line Amount", CurrencyFactor, AmountRoundingPrecision);

            // Update Remaining Quantity
            UpdateRemainingQuantityFromUse(PostedQty);

            // Update Remaining Costs and Amounts
            UpdateRemainingCostsAndAmounts(PostingDate, CurrencyFactor);

            // Update Quantity to Post
            Validate("Qty. to Transfer to Journal", "Remaining Qty.");

            // Update Qty. Pick for location with optional warehouse pick.
            UpdateQtyPickedForOptionalWhsePick("Qty. Posted");

        end else
            ClearValues();

        OnUseOnBeforeModify(Rec, xRec, AmountRoundingPrecision, UnitAmountRoundingPrecision, AmountRoundingPrecisionFCY, UnitAmountRoundingPrecisionFCY);
        Modify(true);
    end;

    local procedure UpdateQtyPickedForOptionalWhsePick(QtyPosted: Decimal)
    begin
        GetLocation("Location Code");
        if Location."Job Consump. Whse. Handling" <> Location."Job Consump. Whse. Handling"::"Warehouse Pick (mandatory)" then
            if ("Qty. Picked" < QtyPosted) then
                Validate("Qty. Picked", QtyPosted);
    end;

    local procedure UpdateRemainingQuantityFromUse(PostedQty: Decimal)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateRemainingQuantityFromUse(Rec, xRec, PostedQty, IsHandled);
        if IsHandled then
            exit;

        if (PostedQty >= 0) = ("Remaining Qty." >= 0) then
            if Abs(PostedQty) <= Abs("Remaining Qty.") then
                Validate("Remaining Qty.", "Remaining Qty." - PostedQty)
            else begin
                Validate(Quantity, Quantity + PostedQty - "Remaining Qty.");
                Validate("Remaining Qty.", 0);
            end
        else
            Validate("Remaining Qty.", "Remaining Qty." - PostedQty);
    end;

    local procedure UpdateRemainingCostsAndAmounts(PostingDate: Date; CurrencyFactor: Decimal)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateRemainingCostsAndAmounts(Rec, PostingDate, CurrencyFactor, AmountRoundingPrecisionFCY, AmountRoundingPrecision, IsHandled);
        if IsHandled then
            exit;

        if "Usage Link" then begin
            InitRoundingPrecisions();
            "Remaining Total Cost" := Round("Unit Cost" * "Remaining Qty.", AmountRoundingPrecisionFCY);
            "Remaining Total Cost (LCY)" :=
                ConvertAmountToLCY(
                    PostingDate, "Remaining Total Cost", CurrencyFactor, AmountRoundingPrecision);
            "Remaining Line Amount" := CalcLineAmount("Remaining Qty.");
            "Remaining Line Amount (LCY)" :=
                ConvertAmountToLCY(
                    PostingDate, "Remaining Line Amount", CurrencyFactor, AmountRoundingPrecision);
        end else
            ClearValues();
    end;

    local procedure UpdateRemainingQuantity()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateRemainingQuantity(Rec, xRec, IsHandled);
        if IsHandled then
            exit;

        if "Usage Link" then
            ControlUsageLink();
    end;

    procedure UpdateQtyToTransfer()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateQtyToTransfer(Rec, CurrFieldNo, IsHandled);
        if IsHandled then
            exit;

        if "Contract Line" then begin
            CalcFields("Qty. Transferred to Invoice");
            Validate("Qty. to Transfer to Invoice", Quantity - "Qty. Transferred to Invoice");
        end else
            Validate("Qty. to Transfer to Invoice", 0);
    end;

    procedure UpdateQtyToInvoice()
    begin
        if "Contract Line" then begin
            CalcFields("Qty. Invoiced");
            Validate("Qty. to Invoice", Quantity - "Qty. Invoiced")
        end else
            Validate("Qty. to Invoice", 0);
    end;

    procedure UpdatePostedTotalCost(AdjustJobCost: Decimal; AdjustJobCostLCY: Decimal)
    begin
        if "Usage Link" then begin
            InitRoundingPrecisions();
            "Posted Total Cost" += Round(AdjustJobCost, AmountRoundingPrecisionFCY);
            "Posted Total Cost (LCY)" += Round(AdjustJobCostLCY, AmountRoundingPrecision);
        end;
    end;

    procedure ValidateModification(FieldChanged: Boolean; FieldNo: Integer)
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeValidateModification(Rec, IsHandled, xRec, FieldNo);
        if IsHandled then
            exit;

        if FieldChanged then begin
            CalcFields("Qty. Transferred to Invoice");
            TestField("Qty. Transferred to Invoice", 0);
        end;

        OnAfterValidateModification(Rec, FieldChanged, FieldNo);
    end;

    local procedure CheckUsageLinkRelations()
    var
        JobUsageLink: Record "Job Usage Link";
    begin
        JobUsageLink.SetRange("Job No.", "Job No.");
        JobUsageLink.SetRange("Job Task No.", "Job Task No.");
        JobUsageLink.SetRange("Line No.", "Line No.");
        if not JobUsageLink.IsEmpty() then
            Error(LinkedJobLedgerErr);
    end;

    local procedure ControlUsageLink()
    var
        JobUsageLink: Record "Job Usage Link";
        IsHandled: Boolean;
    begin
        GetJob();

        IsHandled := false;
        OnControlUsageLinkOnAfterGetJob(Rec, Job, CurrFieldNo, IsHandled);
        if IsHandled then
            exit;

        if Job."Apply Usage Link" then begin
            if "Schedule Line" then
                "Usage Link" := true
            else
                "Usage Link" := false;
        end else
            if not "Schedule Line" then
                "Usage Link" := false;

        JobUsageLink.SetRange("Job No.", "Job No.");
        JobUsageLink.SetRange("Job Task No.", "Job Task No.");
        JobUsageLink.SetRange("Line No.", "Line No.");
        IsHandled := false;
        OnControlUsageLinkOnAfterSetFilterJobUsageLink(Rec, JobUsageLink, Job, CurrFieldNo, IsHandled);
        if not IsHandled then
            if not JobUsageLink.IsEmpty() and not "Usage Link" then
                Error(ControlUsageLinkErr, TableCaption(), FieldCaption("Schedule Line"), FieldCaption("Usage Link"));

        Validate("Remaining Qty.", Quantity - "Qty. Posted");
        Validate("Qty. to Transfer to Journal", Quantity - "Qty. Posted");
        UpdateRemainingCostsAndAmounts("Currency Date", "Currency Factor");

        UpdateQtyToTransfer();
        UpdateQtyToInvoice();

        OnAfterControlUsageLink(Rec, Job, CurrFieldNo);
    end;

    local procedure CalcLineAmount(Qty: Decimal): Decimal
    var
        TotalPrice: Decimal;
    begin
        InitRoundingPrecisions();
        TotalPrice := Round(Qty * "Unit Price", AmountRoundingPrecisionFCY);
        exit(TotalPrice - Round(TotalPrice * "Line Discount %" / 100, AmountRoundingPrecisionFCY));
    end;

    procedure Overdue(): Boolean
    begin
        if ("Planning Date" < WorkDate()) and ("Remaining Qty." > 0) then
            exit(true);
        exit(false);
    end;

    procedure SetBypassQtyValidation(Bypass: Boolean)
    begin
        BypassQtyValidation := Bypass;
    end;

    procedure UpdateReservation(CalledByFieldNo: Integer)
    var
        ReservationCheckDateConfl: Codeunit "Reservation-Check Date Confl.";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateReservation(Rec, xRec, CalledByFieldNo, IsHandled, CurrFieldNo);
        if IsHandled then
            exit;

        if (CurrFieldNo <> CalledByFieldNo) and (CurrFieldNo <> 0) then
            exit;

        case CalledByFieldNo of
            FieldNo("Planning Date"), FieldNo("Planned Delivery Date"):
                if (xRec."Planning Date" <> "Planning Date") and
                   (Quantity <> 0) and
                   (Reserve <> Reserve::Never)
                then
                    ReservationCheckDateConfl.JobPlanningLineCheck(Rec, true);
            FieldNo(Quantity):
                JobPlanningLineReserve.VerifyQuantity(Rec, xRec);
            FieldNo("Usage Link"):
                if (Type = Type::Item) and "Usage Link" then begin
                    GetItem();
                    if Item.Reserve = Item.Reserve::Optional then begin
                        GetJob();
                        Reserve := Job.Reserve
                    end else
                        Reserve := Item.Reserve;
                end else
                    Reserve := Reserve::Never;
        end;
        JobPlanningLineReserve.VerifyChange(Rec, xRec);
        UpdatePlanned();
    end;

    local procedure UpdateDescription()
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdateDescription(Rec, xRec, IsHandled);
        if IsHandled then
            exit;

        if (xRec.Type = xRec.Type::Resource) and (xRec."No." <> '') then begin
            Res.Get(xRec."No.");
            if Description = Res.Name then
                Description := '';
            if "Description 2" = Res."Name 2" then
                "Description 2" := '';
        end;
    end;

    procedure ShowReservation()
    var
        Reservation: Page Reservation;
    begin
        TestField(Type, Type::Item);
        TestField("No.");
        TestField(Reserve);
        TestField("Usage Link");
        Reservation.SetReservSource(Rec);
        Reservation.RunModal();
    end;

    procedure ShowReservationEntries(Modal: Boolean)
    var
        ReservEntry: Record "Reservation Entry";
    begin
        TestField(Type, Type::Item);
        TestField("No.");
        ReservEntry.InitSortingAndFilters(true);
        SetReservationFilters(ReservEntry);
        if Modal then
            Page.RunModal(Page::"Reservation Entries", ReservEntry)
        else
            Page.Run(Page::"Reservation Entries", ReservEntry);
    end;

    procedure AutoReserve()
    var
        ReservMgt: Codeunit "Reservation Management";
        FullAutoReservation: Boolean;
        QtyToReserve: Decimal;
        QtyToReserveBase: Decimal;
    begin
        TestField(Type, Type::Item);
        TestField("No.");
        if Reserve = Reserve::Never then
            FieldError(Reserve);
        JobPlanningLineReserve.ReservQuantity(Rec, QtyToReserve, QtyToReserveBase);
        if QtyToReserveBase <> 0 then begin
            TestField("Planning Date");
            ReservMgt.SetReservSource(Rec);
            ReservMgt.AutoReserve(FullAutoReservation, '', "Planning Date", QtyToReserve, QtyToReserveBase);
            Find();
            if not FullAutoReservation then begin
                Commit();
                if Confirm(AutoReserveQst, true) then begin
                    Rec.ShowReservation();
                    Find();
                end;
            end;
            UpdatePlanned();
        end;
    end;

    procedure ShowTracking()
    var
        OrderTracking: Page "Order Tracking";
    begin
        OrderTracking.SetVariantRec(Rec, Rec."No.", Rec."Remaining Qty. (Base)", Rec."Planning Date", Rec."Planning Date");
        OrderTracking.RunModal();
    end;

    procedure ShowOrderPromisingLine()
    var
        OrderPromisingLine: Record "Order Promising Line";
        OrderPromisingLines: Page "Order Promising Lines";
    begin
        OrderPromisingLine.SetRange("Source Type", OrderPromisingLine."Source Type"::Job);
        OrderPromisingLine.SetRange("Source Type", OrderPromisingLine."Source Type"::Job);
        OrderPromisingLine.SetRange("Source ID", "Job No.");
        OrderPromisingLine.SetRange("Source Line No.", "Job Contract Entry No.");

        OrderPromisingLines.SetSource(OrderPromisingLine."Source Type"::Job);
        OrderPromisingLines.SetTableView(OrderPromisingLine);
        OrderPromisingLines.RunModal();
    end;

    procedure FilterLinesWithItemToPlan(var Item: Record Item)
    begin
        Reset();
        SetCurrentKey(Status, Type, "No.", "Variant Code", "Location Code", "Planning Date");
        SetRange(Status, Status::Order);
        SetRange(Type, Type::Item);
        SetRange("No.", Item."No.");
        SetFilter("Variant Code", Item.GetFilter("Variant Filter"));
        SetFilter("Location Code", Item.GetFilter("Location Filter"));
        SetFilter("Planning Date", Item.GetFilter("Date Filter"));
        SetFilter("Remaining Qty. (Base)", '<>0');
        SetFilter("Unit of Measure Code", Item.GetFilter("Unit of Measure Filter"));

        OnAfterFilterLinesWithItemToPlan(Rec, Item);
    end;

    procedure FindLinesWithItemToPlan(var Item: Record Item): Boolean
    begin
        FilterLinesWithItemToPlan(Item);
        exit(Find('-'));
    end;

    procedure LinesWithItemToPlanExist(var Item2: Record Item): Boolean
    var
        IsHandled: Boolean;
        Result: Boolean;
    begin
        IsHandled := false;
        OnBeforeLinesWithItemToPlanExist(Item2, Result, IsHandled);
        if IsHandled then
            exit(Result);

        FilterLinesWithItemToPlan(Item2);
        exit(not IsEmpty);
    end;

    procedure FilterLinesForReservation(ReservationEntry: Record "Reservation Entry"; NewStatus: Option; AvailabilityFilter: Text; Positive: Boolean)
    begin
        Reset();
        SetCurrentKey(Status, Type, "No.", "Variant Code", "Location Code", "Planning Date");
        SetRange(Status, NewStatus);
        SetRange(Type, Type::Item);
        SetRange("No.", ReservationEntry."Item No.");
        SetRange("Variant Code", ReservationEntry."Variant Code");
        SetRange("Location Code", ReservationEntry."Location Code");
        SetFilter("Planning Date", AvailabilityFilter);
        if Positive then
            SetFilter("Quantity (Base)", '<0')
        else
            SetFilter("Quantity (Base)", '>0');

        OnAfterFilterLinesForReservation(Rec, ReservationEntry, NewStatus, AvailabilityFilter, Positive);
    end;

    procedure DrillDownJobInvoices()
    var
        JobInvoices: Page "Job Invoices";
    begin
        JobInvoices.SetShowDetails(false);
        JobInvoices.SetPrJobPlanningLine(Rec);
        JobInvoices.Run();
    end;

    local procedure CheckRelatedJobPlanningLineInvoice()
    var
        JobPlanningLineInvoice: Record "Job Planning Line Invoice";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeCheckRelatedJobPlanningLineInvoice(Rec, IsHandled);
        if IsHandled then
            exit;

        JobPlanningLineInvoice.SetRange("Job No.", "Job No.");
        JobPlanningLineInvoice.SetRange("Job Task No.", "Job Task No.");
        JobPlanningLineInvoice.SetRange("Job Planning Line No.", "Line No.");
        if not JobPlanningLineInvoice.IsEmpty() then
            Error(NotPossibleJobPlanningLineErr);
    end;

    procedure RowID1(): Text[250]
    var
        ItemTrackingMgt: Codeunit "Item Tracking Management";
    begin
        exit(
          ItemTrackingMgt.ComposeRowID(Database::"Job Planning Line", Status.AsInteger(),
            "Job No.", '', 0, "Job Contract Entry No."));
    end;

    internal procedure RowID2(): Text[250]
    var
        ItemTrackingMgt: Codeunit "Item Tracking Management";
    begin
        exit(
          ItemTrackingMgt.ComposeRowID(Database::Job, 0, "Job No.", '', 0, "Job Contract Entry No."));
    end;

    procedure UpdatePlanned(): Boolean
    begin
        CalcFields("Reserved Quantity");
        if Planned = ("Reserved Quantity" = "Remaining Qty.") then
            exit(false);
        Planned := not Planned;
        exit(true);
    end;

    procedure UpdatePlannedDueDate() Changed: Boolean;
    var
        Customer: Record Customer;
        PaymentTerms: Record "Payment Terms";
        DueDateCalculation: DateFormula;
        xPlanningDueDate: Date;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeUpdatePlannedDueDate(Rec, Changed, IsHandled);
        if IsHandled then
            exit(Changed);

        xPlanningDueDate := "Planning Due Date";
        if "Planning Date" = 0D then
            exit(false);
        "Planning Due Date" := "Planning Date";
        GetJob();
        if Job."No." = '' then
            exit(false);
        Customer.SetLoadFields("Payment Terms Code");
        if not Customer.Get(Job."Bill-to Customer No.") then
            exit(false);
        PaymentTerms.SetLoadFields("Due Date Calculation");
        if PaymentTerms.Get(Customer."Payment Terms Code") then begin
            PaymentTerms.GetDueDateCalculation(DueDateCalculation);
            "Planning Due Date" := CalcDate(DueDateCalculation, "Planning Date");
        end;
        exit("Planning Due Date" <> xPlanningDueDate);
    end;

    procedure ClearValues()
    begin
        Validate("Remaining Qty.", 0);
        "Remaining Total Cost" := 0;
        "Remaining Total Cost (LCY)" := 0;
        "Remaining Line Amount" := 0;
        "Remaining Line Amount (LCY)" := 0;
        Validate("Qty. Posted", 0);
        Validate("Qty. to Transfer to Journal", 0);
        "Posted Total Cost" := 0;
        "Posted Total Cost (LCY)" := 0;
        "Posted Line Amount" := 0;
        "Posted Line Amount (LCY)" := 0;

        OnAfterClearValues(Rec);
    end;

    procedure ClearTracking()
    begin
        "Serial No." := '';
        "Lot No." := '';

        OnAfterClearTracking(Rec);
    end;

    procedure InitFromJobPlanningLine(FromJobPlanningLine: Record "Job Planning Line"; NewQuantity: Decimal)
    var
        ToJobPlanningLine: Record "Job Planning Line";
        JobJnlManagement: Codeunit JobJnlManagement;
    begin
        ToJobPlanningLine := Rec;

        ToJobPlanningLine.Init();
        ToJobPlanningLine.TransferFields(FromJobPlanningLine);
        ToJobPlanningLine."Line No." := GetNextJobLineNo(FromJobPlanningLine);
        ToJobPlanningLine.Validate("Line Type", "Line Type"::Billable);
        ToJobPlanningLine.ClearValues();
        ToJobPlanningLine."Job Contract Entry No." := JobJnlManagement.GetNextEntryNo();
        if ToJobPlanningLine.Type <> ToJobPlanningLine.Type::Text then begin
            ToJobPlanningLine.Validate(Quantity, NewQuantity);
            ToJobPlanningLine.Validate("Currency Code", FromJobPlanningLine."Currency Code");
            ToJobPlanningLine.Validate("Currency Date", FromJobPlanningLine."Currency Date");
            ToJobPlanningLine.Validate("Currency Factor", FromJobPlanningLine."Currency Factor");
            ToJobPlanningLine.Validate("Unit Cost", FromJobPlanningLine."Unit Cost");
            ToJobPlanningLine.Validate("Unit Price", FromJobPlanningLine."Unit Price");
            if FromJobPlanningLine."Line Discount %" <> 0 then
                ToJobPlanningLine.Validate("Line Discount %", FromJobPlanningLine."Line Discount %");
        end;

        OnAfterInitFromJobPlanningLine(ToJobPlanningLine, FromJobPlanningLine);
        Rec := ToJobPlanningLine;
    end;

    protected procedure GetNextJobLineNo(FromJobPlanningLine: Record "Job Planning Line"): Integer
    var
        JobPlanningLine: Record "Job Planning Line";
    begin
        JobPlanningLine.SetRange("Job No.", FromJobPlanningLine."Job No.");
        JobPlanningLine.SetRange("Job Task No.", FromJobPlanningLine."Job Task No.");
        if JobPlanningLine.FindLast() then;
        exit(JobPlanningLine."Line No." + 10000);
    end;

    procedure IsInventoriableItem(): Boolean
    begin
        if Type <> Type::Item then
            exit(false);
        if "No." = '' then
            exit(false);
        GetItem();
        exit(Item.IsInventoriableType());
    end;

    procedure IsNonInventoriableItem(): Boolean
    begin
        if Type <> Type::Item then
            exit(false);
        if "No." = '' then
            exit(false);
        GetItem();
        exit(Item.IsNonInventoriableType());
    end;

    procedure ConvertToJobLineType() JobLineType: Enum "Job Line Type"
    begin
        JobLineType := Enum::"Job Line Type".FromInteger("Line Type".AsInteger() + 1);

        OnAfterConvertToJobLineType(Rec, JobLineType);
    end;

    procedure ConvertFromJobLineType(JobLineType: Enum "Job Line Type") JobPlanningLineLineType: Enum "Job Planning Line Line Type"
    begin
        JobPlanningLineLineType := Enum::"Job Planning Line Line Type".FromInteger(JobLineType.AsInteger() - 1);

        OnAfterConvertFromJobLineType(Rec, JobLineType, JobPlanningLineLineType);
    end;

    procedure CopyTrackingFromJobJnlLine(JobJnlLine: Record "Job Journal Line")
    begin
        "Serial No." := JobJnlLine."Serial No.";
        "Lot No." := JobJnlLine."Lot No.";

        OnAfterCopyTrackingFromJobJnlLine(Rec, JobJnlLine);
    end;

    procedure CopyTrackingFromJobLedgEntry(JobLedgEntry: Record "Job Ledger Entry")
    begin
        "Serial No." := JobLedgEntry."Serial No.";
        "Lot No." := JobLedgEntry."Lot No.";

        OnAfterCopyTrackingFromJobLedgEntry(Rec, JobLedgEntry);
    end;

    local procedure SetDefaultBin()
    begin
        if (Rec."No." <> '') then begin
            GetItem();
            if Item.IsInventoriableType() then
                Validate("Bin Code", FindBin());
        end;
    end;

    local procedure FindBin() NewBinCode: Code[20]
    var
        WMSManagement: Codeunit "WMS Management";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeFindBin(Rec, NewBinCode, IsHandled);
        if IsHandled then
            exit(NewBinCode);

        if (Rec."No." <> '') and (Rec."Location Code" <> '') then begin
            if FindBinFromJobTask(NewBinCode) then
                exit(NewBinCode);
            GetLocation(Rec."Location Code");
            if Location."To-Job Bin Code" <> '' then
                NewBinCode := Location."To-Job Bin Code"
            else
                if Location."Bin Mandatory" and not Location."Directed Put-away and Pick" then
                    WMSManagement.GetDefaultBin(Rec."No.", Rec."Variant Code", Rec."Location Code", NewBinCode);
        end;
    end;

    local procedure FindBinFromJobTask(var NewBinCode: Code[20]): Boolean
    begin
        JobTask.SetLoadFields("Location Code", "Bin Code");
        if not JobTask.Get(Rec."Job No.", Rec."Job Task No.") then
            exit(false);

        if ("Location Code" = JobTask."Location Code") and (JobTask."Bin Code" <> '') then begin
            NewBinCode := JobTask."Bin Code";
            exit(true);
        end;
    end;

    local procedure CalcBaseQty(Qty: Decimal; FromFieldName: Text; ToFieldName: Text): Decimal
    begin
        exit(UOMMgt.CalcBaseQty(
            "No.", "Variant Code", "Unit of Measure Code", Qty, "Qty. per Unit of Measure", "Qty. Rounding Precision (Base)", FieldCaption("Qty. Rounding Precision"), FromFieldName, ToFieldName));
    end;

    local procedure DeleteWarehouseRequest(JobPlanningLine: Record "Job Planning Line")
    var
        JobPlanningLine2: Record "Job Planning Line";
        WarehouseRequest: Record "Warehouse Request";
        WhsePickRequest: Record "Whse. Pick Request";
    begin
        JobPlanningLine2.SetFilter("Job Contract Entry No.", '<>%1', JobPlanningLine."Job Contract Entry No.");
        JobPlanningLine2.SetRange("Job No.", JobPlanningLine."Job No.");
        JobPlanningLine2.SetRange("Location Code", JobPlanningLine."Location Code");

        if JobPlanningLine2.IsEmpty() then
            // Check for both old format (Database::Job, 0) and new format (Database::"Job Planning Line", Order)
            if WarehouseRequest.Get(Enum::"Warehouse Request Type"::Outbound, JobPlanningLine."Location Code", Database::Job, 0, JobPlanningLine."Job No.") then
                WarehouseRequest.Delete(true)
            else
                if WarehouseRequest.Get(Enum::"Warehouse Request Type"::Outbound, JobPlanningLine."Location Code", Database::"Job Planning Line", "Job Planning Line Status"::Order.AsInteger(), JobPlanningLine."Job No.") then
                    WarehouseRequest.Delete(true)
                else
                    if WhsePickRequest.Get(WhsePickRequest."Document Type"::Job, 0, JobPlanningLine."Job No.", JobPlanningLine."Location Code") then
                        WhsePickRequest.Delete(true);
    end;

    internal procedure CreateWarehouseRequest()
    var
        WhsePickRequest: Record "Whse. Pick Request";
        WarehouseRequest: Record "Warehouse Request";
    begin
        if Rec."Location Code" = '' then
            exit;

        GetLocation(Rec."Location Code");

        case Location."Job Consump. Whse. Handling" of
            Enum::"Job Consump. Whse. Handling"::"Warehouse Pick (mandatory)",
            Enum::"Job Consump. Whse. Handling"::"Warehouse Pick (optional)":
                if not WhsePickRequest.Get(WhsePickRequest."Document Type"::Job, 0, Rec."Job No.", Rec."Location Code") then begin
                    WhsePickRequest.Init();
                    WhsePickRequest."Document Type" := WhsePickRequest."Document Type"::Job;
                    WhsePickRequest."Document Subtype" := 0;
                    WhsePickRequest."Document No." := Rec."Job No.";
                    WhsePickRequest.Status := WhsePickRequest.Status::Released;
                    WhsePickRequest."Location Code" := Location.Code;
                    if WhsePickRequest.Insert() then;
                end;
            Enum::"Job Consump. Whse. Handling"::"Inventory Pick":
                if not GetWarehouseRequest(WarehouseRequest) then begin
                    WarehouseRequest.Init();
                    WarehouseRequest.Type := WarehouseRequest.Type::Outbound;
                    WarehouseRequest."Location Code" := Rec."Location Code";
                    WarehouseRequest."Source Type" := Database::"Job Planning Line";
                    WarehouseRequest."Source No." := Rec."Job No.";
                    WarehouseRequest."Source Subtype" := "Job Planning Line Status"::Order.AsInteger();
                    WarehouseRequest."Source Document" := WarehouseRequest."Source Document"::"Job Usage";
                    WarehouseRequest."Document Status" := WarehouseRequest."Document Status"::Released;
                    if WarehouseRequest.Insert() then;
                end;
        end;
    end;

    local procedure GetWarehouseRequest(var WarehouseRequest: Record "Warehouse Request"): Boolean
    begin
        // Check for both old format (Database::Job, 0) and new format (Database::"Job Planning Line", Order)
        if WarehouseRequest.Get(WarehouseRequest.Type::Outbound, Rec."Location Code", Database::Job, 0, Rec."Job No.") then
            if (WarehouseRequest."Source Document" = WarehouseRequest."Source Document"::"Job Usage") and (WarehouseRequest."Document Status" = WarehouseRequest."Document Status"::Released) then
                exit(true);
        if WarehouseRequest.Get(WarehouseRequest.Type::Outbound, Rec."Location Code", Database::"Job Planning Line", "Job Planning Line Status"::Order.AsInteger(), Rec."Job No.") then
            if (WarehouseRequest."Source Document" = WarehouseRequest."Source Document"::"Job Usage") and (WarehouseRequest."Document Status" = WarehouseRequest."Document Status"::Released) then
                exit(true);
    end;

    procedure TestStatusOpen()
    begin
        TestField(Status, Status::Order);
        GetJob();
        Job.TestField(Status, Job.Status::Open);
    end;

    procedure CheckIfJobPlngLineMeetsReservedFromStockSetting(QtyToPost: Decimal; ReservedFromStock: Enum "Reservation From Stock") Result: Boolean
    var
        QtyReservedFromStock: Decimal;
    begin
        Result := true;

        if not Rec.IsInventoriableItem() then
            exit(true);

        if ReservedFromStock = ReservedFromStock::" " then
            exit(true);

        QtyReservedFromStock := JobPlanningLineReserve.GetReservedQtyFromInventory(Rec);

        case ReservedFromStock of
            ReservedFromStock::Full:
                if QtyToPost <> QtyReservedFromStock then
                    Result := false;
            ReservedFromStock::"Full and Partial":
                if QtyReservedFromStock = 0 then
                    Result := false;
            else
                OnCheckIfJobPlngLineMeetsReservedFromStockSetting(QtyToPost, ReservedFromStock, Result);
        end;

        exit(Result);
    end;

    procedure IsAsmToOrderAllowed() Result: Boolean
    begin
        Result := true;

        if Quantity < 0 then
            Result := false;
        if Type <> Type::Item then
            Result := false;
        if "No." = '' then
            Result := false;
        if "Line Type" = "Line Type"::Billable then
            Result := false;
    end;

    procedure QtyToAsmBaseOnATO(): Decimal
    var
        AsmHeader: Record "Assembly Header";
    begin
        if AsmToOrderExists(AsmHeader) then
            exit(AsmHeader."Quantity to Assemble (Base)");
        exit(0);
    end;

    procedure ShowAsmToJobPlanningLines()
    begin
        ATOLink.ShowAsmToJobPlanningLines(Rec);
    end;

    procedure CheckAsmToOrder(AsmHeader: Record "Assembly Header")
    begin
        TestField("Qty. to Assemble", AsmHeader.Quantity);
        TestField(Type, Type::Item);
        TestField("No.", AsmHeader."Item No.");
        TestField("Location Code", AsmHeader."Location Code");
        TestField("Unit of Measure Code", AsmHeader."Unit of Measure Code");
        TestField("Variant Code", AsmHeader."Variant Code");
        GetJob();
        if Job.Status = Job.Status::Open then begin
            AsmHeader.CalcFields("Reserved Qty. (Base)");
            AsmHeader.TestField("Reserved Qty. (Base)", AsmHeader."Remaining Quantity (Base)");
        end;
        TestField("Qty. to Assemble (Base)", AsmHeader."Quantity (Base)");
        if "Remaining Qty. (Base)" < AsmHeader."Remaining Quantity (Base)" then
            AsmHeader.FieldError("Remaining Quantity (Base)", StrSubstNo(CannotBeMoreErr, "Remaining Qty. (Base)"));
    end;

    procedure AsmToOrderExists(var AsmHeader: Record "Assembly Header"): Boolean
    begin
        if not ATOLink.AsmExistsForJobPlanningLine(Rec) then
            exit(false);
        exit(AsmHeader.Get(ATOLink."Assembly Document Type", ATOLink."Assembly Document No."));
    end;

    protected procedure InitQtyToAsm()
    var
        Qty, QtyBase : Decimal;
    begin
        if not IsAsmToOrderAllowed() then begin
            "Qty. to Assemble" := 0;
            "Qty. to Assemble (Base)" := 0;
            exit;
        end;

        if ((xRec."Qty. to Assemble (Base)" = 0) and IsAsmToOrderRequired()) or
           ((xRec."Qty. to Assemble (Base)" <> 0) and (xRec."Qty. to Assemble (Base)" = xRec."Quantity (Base)")) or
           ("Qty. to Assemble (Base)" > "Quantity (Base)")
        then begin
            Qty := 0;
            QtyBase := 0;
            AssembledQuantity(Qty, QtyBase);
            "Qty. to Assemble" := Quantity - Qty;
            "Qty. to Assemble (Base)" := "Quantity (Base)" - QtyBase;
        end;
    end;

    procedure AssembledQuantity(var Qty: Decimal; var QtyBase: Decimal)
    var
        PostedATOLink: Record "Posted Assemble-to-Order Link";
    begin
        PostedATOLink.SetCurrentKey("Job No.", "Job Task No.", "Document Line No.");
        PostedATOLink.SetRange("Job No.", Rec."Job No.");
        PostedATOLink.SetRange("Job Task No.", Rec."Job Task No.");
        PostedATOLink.SetRange("Document Line No.", Rec."Line No.");
        if PostedATOLink.FindSet() then
            repeat
                Qty += PostedATOLink."Assembled Quantity";
                QtyBase += PostedATOLink."Assembled Quantity (Base)";
            until PostedATOLink.Next() = 0;
    end;

    procedure IsAsmToOrderRequired(): Boolean
    begin
        if (Type <> Type::Item) or ("No." = '') then
            exit(false);
        GetItem();
        if GetSKU() then
            exit(SKU."Assembly Policy" = SKU."Assembly Policy"::"Assemble-to-Order");
        exit(Item."Assembly Policy" = Item."Assembly Policy"::"Assemble-to-Order");
    end;

    procedure SelectMultipleItems()
    var
        ItemListPage: Page "Item List";
        SelectionFilter: Text;
    begin
        OnBeforeSelectMultipleItems(Rec);

        SelectionFilter := ItemListPage.SelectActiveItems();

        if SelectionFilter <> '' then
            AddItems(SelectionFilter);

        OnAfterSelectMultipleItems(Rec);
    end;

    local procedure AddItems(SelectionFilter: Text)
    var
        Item: Record "Item";
        NewJobPlanningLine: Record "Job Planning Line";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeAddItems(Rec, SelectionFilter, IsHandled);
        if IsHandled then
            exit;

        InitNewLine(NewJobPlanningLine);
        Item.SetLoadFields("No.");
        Item.SetFilter("No.", SelectionFilter);
        if Item.FindSet() then
            repeat
                AddItem(NewJobPlanningLine, Item."No.");
            until Item.Next() = 0;
    end;

    procedure GetATOBin(Location: Record Location; var BinCode: Code[20]) Result: Boolean
    var
        AsmHeader: Record "Assembly Header";
    begin
        if not Location."Require Shipment" then
            BinCode := Location."Asm.-to-Order Shpt. Bin Code";
        if BinCode <> '' then
            exit(true);

        if AsmHeader.GetFromAssemblyBin(Location, BinCode) then
            exit(true);

        exit(false);
    end;

    local procedure AddItem(var NewJobPlanningLine: Record "Job Planning Line"; ItemNo: Code[20])
    var
        TransferExtendedText: Codeunit "Transfer Extended Text";
    begin
        NewJobPlanningLine."Line No." += 10000;
        NewJobPlanningLine.Validate(Type, NewJobPlanningLine.Type::Item);
        NewJobPlanningLine.Validate("No.", ItemNo);
        NewJobPlanningLine.Insert(true);

        if TransferExtendedText.JobCheckIfAnyExtText(NewJobPlanningLine, false) then
            TransferExtendedText.InsertJobExtText(NewJobPlanningLine);
    end;

    local procedure InitNewLine(var NewJobPlanningLine: Record "Job Planning Line")
    var
        ExistingJobPlanningLine: Record "Job Planning Line";
    begin
        NewJobPlanningLine.Copy(Rec);
        ExistingJobPlanningLine.SetRange("Job No.", NewJobPlanningLine."Job No.");
        ExistingJobPlanningLine.SetRange("Job Task No.", NewJobPlanningLine."Job Task No.");
        if ExistingJobPlanningLine.FindLast() then
            NewJobPlanningLine."Line No." := ExistingJobPlanningLine."Line No."
        else
            NewJobPlanningLine."Line No." := 0;
    end;

    procedure IsExtendedText(): Boolean
    begin
        exit((Type = Type::Text) and ("Attached to Line No." <> 0) and (Quantity = 0));
    end;

    local procedure WhsePickReqForLocation(): Boolean
    begin
        if Rec."Location Code" = '' then
            exit(false);

        GetLocation(Rec."Location Code");
        if Location."Job Consump. Whse. Handling" = Enum::"Job Consump. Whse. Handling"::"Warehouse Pick (mandatory)" then
            exit(true);
    end;

    local procedure InitLocation()
    begin
        if JobTask.Get(Rec."Job No.", Rec."Job Task No.") and (JobTask."Location Code" <> '') then
            Validate("Location Code", JobTask."Location Code");
    end;

    procedure SetSkipCheckForMultipleJobsOnSalesLine(Skip: Boolean)
    begin
        SkipCheckForMultipleJobsOnSalesLine := Skip;
    end;

    procedure GetSkipCheckForMultipleJobsOnSalesLine(): Boolean
    begin
        exit(SkipCheckForMultipleJobsOnSalesLine);
    end;

    local procedure ConfirmDeletion()
    begin
        if CalledFromHeader then
            exit;

        if "Qty. Posted" < "Qty. Picked" then begin
            if "Location Code" <> '' then begin
                GetLocation("Location Code");
                if Location."Job Consump. Whse. Handling" = Location."Job Consump. Whse. Handling"::"No Warehouse Handling" then
                    exit;
            end;

            if not Confirm(
                StrSubstNo(
                    ConfirmDeleteQst,
                    FieldCaption("Qty. Picked"),
                    "Qty. Picked",
                    FieldCaption("Qty. Posted"),
                    "Qty. Posted",
                    TableCaption),
                false)
            then
                Error('');
        end;
    end;

    procedure SuspendDeletionCheck(Suspend: Boolean)
    begin
        CalledFromHeader := Suspend;
    end;

    procedure SetPurchLineFilters(var PurchaseLine: Record "Purchase Line")
    begin
        PurchaseLine.SetCurrentKey("Document Type", "Job No.", "Job Task No.", "Job Planning Line No.");
        PurchaseLine.SetRange("Document Type", PurchaseLine."Document Type"::Order);
        PurchaseLine.SetRange("Job No.", "Job No.");
        PurchaseLine.SetRange("Job Task No.", "Job Task No.");
        PurchaseLine.SetRange("Job Planning Line No.", "Line No.");
    end;

    local procedure PreventDeleteIfPurchaseExists(var JobPlanningLine: Record "Job Planning Line")
    var
        PurchRcptLine: Record "Purch. Rcpt. Line";
    begin
        // Check if any Purchase Receipt Line exists for this Project Planning Line
        PurchRcptLine.SetLoadFields("Document No.");
        PurchRcptLine.SetCurrentKey("Job No.", "Job Task No.", "Job Planning Line No.");
        PurchRcptLine.SetRange("Job No.", JobPlanningLine."Job No.");
        PurchRcptLine.SetRange("Job Task No.", JobPlanningLine."Job Task No.");
        PurchRcptLine.SetRange("Job Planning Line No.", JobPlanningLine."Line No.");
        if PurchRcptLine.FindFirst() then
            Error(PurchRcptLineExistErr, PurchRcptLine."Document No.");
    end;

    local procedure FindOrCreateRecordByNo(SourceNo: Code[20]): Code[20]
    var
        Item2: Record Item;
        FindRecordManagement: Codeunit "Find Record Management";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeFindOrCreateRecordByNo(Rec, xRec, CurrFieldNo, IsHandled);
        if IsHandled then
            exit("No.");

        if (SourceNo = '') then
            exit('');
        if Type = Type::Item then
            exit(Item2.GetFirstItemNoFromLookup(SourceNo))
        else
            exit(FindRecordManagement.FindNoFromTypedValue(GetType(Type), "No.", false));

        exit(SourceNo);
    end;

    local procedure GetType(JobPlanningLineType: Enum "Job Planning Line Type") Result: Integer
    begin
        case JobPlanningLineType of
            JobPlanningLineType::Text:
                exit(0);
            JobPlanningLineType::"G/L Account":
                exit(1);
            JobPlanningLineType::Item:
                exit(2);
            JobPlanningLineType::Resource:
                exit(3);
            else
                OnGetType(JobPlanningLineType, Result);
        end;
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCalculateRetrievedCost(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; StockkeepingUnit: Record "Stockkeeping Unit"; Item: Record Item; var RetrievedCost: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyFromItem(var JobPlanningLine: Record "Job Planning Line"; Job: Record Job; Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyFromGLAccount(var JobPlanningLine: Record "Job Planning Line"; Job: Record Job; GLAccount: Record "G/L Account")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyFieldsFromJob(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; Job: Record Job)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyTrackingFromJobJnlLine(var JobPlanningLine: Record "Job Planning Line"; JobJnlLine: Record "Job Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterConvertToJobLineType(var JobPlanningLine: Record "Job Planning Line"; var JobLineType: Enum "Job Line Type")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterConvertFromJobLineType(var JobPlanningLine: Record "Job Planning Line"; var JobLineType: Enum "Job Line Type"; var JobPlanningLineLineType: Enum "Job Planning Line Line Type")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterClearTracking(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyTrackingFromJobLedgEntry(var JobPlanningLine: Record "Job Planning Line"; JobLedgEntry: Record "Job Ledger Entry")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterDeleteAmounts(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterGetJob(var JobPlanningLine: Record "Job Planning Line"; var Job: Record Job)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterGetSKU(JobPlanningLine: Record "Job Planning Line"; var Result: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterGetRemainingQty(JobPlanningLine: Record "Job Planning Line"; var RemainingQty: Decimal; var RemainingQtyBase: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterFilterLinesWithItemToPlan(var JobPlanningLine: Record "Job Planning Line"; var Item: Record Item);
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnAfterFilterLinesForReservation(var JobPlaningLine: Record "Job Planning Line"; ReservationEntry: Record "Reservation Entry"; NewStatus: Option; AvailabilityFilter: Text; Positive: Boolean)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnAfterGetLineWithPrice(var LineWithPrice: Interface "Line With Price")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterHandleCostFactor(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; Item: Record Item)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInitJobPlanningLine(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInitFromJobPlanningLine(var ToJobPlanningLine: Record "Job Planning Line"; FromJobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterResourceFindCost(var JobPlanningLine: Record "Job Planning Line"; var ResourceCost: Record "Resource Cost")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetReservationFilters(var ReservEntry: Record "Reservation Entry"; JobPlanningLine: Record "Job Planning Line");
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetupNewLine(var JobPlanningLine: Record "Job Planning Line"; LastJobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateAllAmounts(var JobPlanningLine: Record "Job Planning Line"; var xJobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateCurrencyFactor(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateTotalPrice(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateUnitPrice(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var AmountRoundingPrecision: Decimal; var AmountRoundingPrecisionFCY: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterUpdateAmountsAndDiscounts(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterValidateModification(var JobPlanningLine: Record "Job Planning Line"; FieldChanged: Boolean; FieldNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCalcQuantityBase(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; CurrentFieldNo: Integer; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckQuantityPosted(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCheckRelatedJobPlanningLineInvoice(JobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCopyFromResource(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;


    [IntegrationEvent(true, false)]
    local procedure OnBeforeFindPriceAndDiscount(CalledByFieldNo: Integer; var IsHandled: Boolean; var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeHandleCostFactor(var JobPlanningLine: Record "Job Planning Line"; var xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInitJobPlanningLine(var JobPlanningLine: Record "Job Planning Line"; Job: Record Job; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInitRoundingPrecisions(JobPlanningLine: Record "Job Planning Line"; var AmountRoundingPrecision: Decimal; var UnitAmountRoundingPrecision: Decimal; var AmountRoundingPrecisionFCY: Decimal; var UnitAmountRoundingPrecisionFCY: Decimal; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeRecalculateAmounts(var JobPlanningLine: Record "Job Planning Line"; var xJobPlanningLine: Record "Job Planning Line"; var AmountLCY: Decimal; var IsHandled: Boolean; var Amount: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdatePlannedDueDate(var JobPlanningLine: Record "Job Planning Line"; var Changed: Boolean; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeOnInsert(var JobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateAmountsAndDiscounts(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateDescription(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateModification(var JobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean; xJobPlanningLine: Record "Job Planning Line"; FieldNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidatePlanningDate(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateQuantityBase(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; CallingFieldNo: Integer; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateWorkTypeCode(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeRetrieveCostPrice(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var ShouldRetrieveCostPrice: Boolean; var IsHandled: Boolean; CalledByFieldNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateRemainingQuantity(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateRemainingQuantityFromUse(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; PostedQty: Decimal; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateAllAmounts(var JobPlanningLine: Record "Job Planning Line"; var xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean; CurrFieldNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateUnitCost(var JobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean; xJobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateReservation(var JobPlanningLine: Record "Job Planning Line"; var xJobPlanningLine: Record "Job Planning Line"; CalledByFieldNo: Integer; var IsHandled: Boolean; CurrentFieldNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateQtyToTransferToInvoice(var JobPlanningLine: Record "Job Planning Line"; var xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnControlUsageLinkOnAfterGetJob(var JobPlanningLine: Record "Job Planning Line"; Job: Record Job; CallingFieldNo: Integer; var IsHandling: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUpdateCurrencyFactorOnBeforeGetExchangeRate(JobPlanningLine: Record "Job Planning Line"; var CurrencyExchangeRate: Record "Currency Exchange Rate")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnUseOnBeforeModify(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; AmountRoundingPrecision: Decimal; UnitAmountRoundingPrecision: Decimal; AmountRoundingPrecisionFCY: Decimal; UnitAmountRoundingPrecisionFCY: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnValidateNoOnAfterCopyFromAccount(var JobPlanningLine: Record "Job Planning Line"; var xJobPlanningLine: Record "Job Planning Line"; var Job: Record Job)
    begin
    end;

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

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateUsageLink(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean);
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnDeleteOnAfterSetFilterOnJobUsageLink(JobPlanningLine: Record "Job Planning Line"; var JobUsageLink: Record "Job Usage Link"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeOnRename(var JobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnControlUsageLinkOnAfterSetFilterJobUsageLink(var JobPlanningLine: Record "Job Planning Line"; var JobUsageLink: Record "Job Usage Link"; Job: Record Job; CallingFieldNo: Integer; var IsHandling: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeFindBin(var JobPlanningLine: Record "Job Planning Line"; var NewBinCode: Code[20]; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterFindPriceAndDiscount(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; CalledByFieldNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCaption(JobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean; var Result: Text)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnCheckIfJobPlngLineMeetsReservedFromStockSetting(QtyToPost: Decimal; ReservedFromStock: Enum "Reservation From Stock"; var Result: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateUnitPrice(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
    begin
    end;

#pragma warning disable AS0077
    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateRemainingCostsAndAmounts(var JobPlanningLine: Record "Job Planning Line"; PostingDate: Date; CurrencyFactor: Decimal; AmountRoundingPrecisionFCY: Decimal; AmountRoundingPrecision: Decimal; var IsHandled: Boolean)
    begin
    end;
#pragma warning restore AS0077

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateTotalCost(var JobPlanningLine: Record "Job Planning Line"; AmountRoundingPrecisionFCY: Decimal; AmountRoundingPrecision: Decimal; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterClearValues(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterControlUsageLink(var JobPlanningLine: Record "Job Planning Line"; Job: Record Job; CurrFieldNo: Integer)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnBeforeCopyFromGLAccount(var JobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean; Job: Record Job)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeSelectMultipleItems(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSelectMultipleItems(var JobPlanningLine: Record "Job Planning Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeAddItems(var JobPlanningLine: Record "Job Planning Line"; SelectionFilter: Text; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyFromResource(var JobPlanningLine: Record "Job Planning Line"; Job: Record Job; Resource: Record Resource)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeUpdateQtyToTransfer(var JobPlanningLine: Record "Job Planning Line"; CurrFieldNo: Integer; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateQuantity(JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; var SkipValidateQuantity: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeFindOrCreateRecordByNo(var JobPlanningLine: Record "Job Planning Line"; xJobPlanningLine: Record "Job Planning Line"; CurrentFieldNo: Integer; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnGetType(JobPlanningLineType: Enum "Job Planning Line Type"; var Result: Integer)
    begin
    end;
}