Table 1304 Sales Price and Line Disc Buff, source in 29

Source29

src/Layers/W1/BaseApp/Sales/Pricing/SalesPriceandLineDiscBuff.Table.al1127 lines, Copyright (c) Microsoft Corporation. MIT

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

using Microsoft.CRM.BusinessRelation;
using Microsoft.CRM.Campaign;
using Microsoft.CRM.Contact;
using Microsoft.CRM.Segment;
using Microsoft.Finance.Currency;
using Microsoft.Finance.VAT.Setup;
using Microsoft.Inventory.Item;
using Microsoft.Sales.Customer;

/// <summary>
/// Provides a temporary buffer for displaying combined sales prices and line discounts in a unified view.
/// </summary>
table 1304 "Sales Price and Line Disc Buff"
{
    Caption = 'Sales Price and Line Disc Buff';
    DataClassification = CustomerContent;

    fields
    {
        /// <summary>
        /// Specifies the item number or item discount group code for the buffer entry.
        /// </summary>
        field(1; "Code"; Code[20])
        {
            Caption = 'Code';
            ToolTip = 'Specifies a code for the sales line price or discount.';
            DataClassification = SystemMetadata;
            NotBlank = true;
            TableRelation = if (Type = const(Item)) Item
            else
            if (Type = const("Item Disc. Group")) "Item Discount Group";

            trigger OnLookup()
            var
                Item: Record Item;
                ItemDiscountGroup: Record "Item Discount Group";
            begin
                case Type of
                    Type::Item:
                        if PAGE.RunModal(PAGE::"Item List", Item) = ACTION::LookupOK then
                            Validate(Code, Item."No.");
                    Type::"Item Disc. Group":
                        if PAGE.RunModal(PAGE::"Item Disc. Groups", ItemDiscountGroup) = ACTION::LookupOK then
                            Validate(Code, ItemDiscountGroup.Code);
                    else
                        OnLookupCodeCaseElse();
                end;
            end;

            trigger OnValidate()
            var
                Item: Record Item;
                CustPriceGr: Record "Customer Price Group";
            begin
                "Unit of Measure Code" := '';
                "Variant Code" := '';

                if Type = Type::Item then
                    if Item.Get(Code) then
                        "Unit of Measure Code" := Item."Sales Unit of Measure";

                if "Line Type" = "Line Type"::"Sales Price" then begin
                    if "Sales Type" = "Sales Type"::"Customer Price/Disc. Group" then
                        if CustPriceGr.Get("Sales Code") and
                           (CustPriceGr."Allow Invoice Disc." = "Allow Invoice Disc.")
                        then
                            exit;

                    UpdateValuesFromItem();
                end;
            end;
        }
        /// <summary>
        /// Specifies the customer, customer price group, or customer discount group that the buffer entry applies to.
        /// </summary>
        field(2; "Sales Code"; Code[20])
        {
            Caption = 'Sales Code';
            ToolTip = 'Specifies the sales code of the price or discount. The sales code depends on the value in the Sales Type field. The code can represent an individual customer, a customer discount group, or for all customers.';
            DataClassification = SystemMetadata;
            TableRelation = if ("Sales Type" = const("Customer Price/Disc. Group"),
                                "Line Type" = const("Sales Line Discount")) "Customer Discount Group"
            else
            if ("Sales Type" = const("Customer Price/Disc. Group"),
                                         "Line Type" = const("Sales Price")) "Customer Price Group"
            else
            if ("Sales Type" = const(Customer)) Customer;

            trigger OnValidate()
            var
                CustPriceGr: Record "Customer Price Group";
                Cust: Record Customer;
            begin
                if "Sales Code" <> '' then
                    case "Sales Type" of
                        "Sales Type"::"All Customers":
                            Error(MustBeBlankErr, FieldCaption("Sales Code"));
                        "Sales Type"::"Customer Price/Disc. Group":
                            if "Line Type" = "Line Type"::"Sales Price" then begin
                                CustPriceGr.Get("Sales Code");
                                "Price Includes VAT" := CustPriceGr."Price Includes VAT";
                                "VAT Bus. Posting Gr. (Price)" := CustPriceGr."VAT Bus. Posting Gr. (Price)";
                                "Allow Line Disc." := CustPriceGr."Allow Line Disc.";
                                "Allow Invoice Disc." := CustPriceGr."Allow Invoice Disc.";
                            end;
                        "Sales Type"::Customer:
                            begin
                                Cust.Get("Sales Code");
                                "Currency Code" := Cust."Currency Code";
                                if "Line Type" = "Line Type"::"Sales Price" then begin
                                    "Price Includes VAT" := Cust."Prices Including VAT";
                                    "VAT Bus. Posting Gr. (Price)" := Cust."VAT Bus. Posting Group";
                                    "Allow Line Disc." := Cust."Allow Line Disc.";
                                end;
                            end;
                    end;
            end;
        }
        /// <summary>
        /// Specifies the currency that the buffer entry is valid for. A blank value indicates the local currency.
        /// </summary>
        field(3; "Currency Code"; Code[10])
        {
            Caption = 'Currency Code';
            ToolTip = 'Specifies the currency that must be used on the sales document line to warrant the sales price or discount.';
            DataClassification = SystemMetadata;
            TableRelation = Currency;
        }
        /// <summary>
        /// Specifies the date from which the buffer entry is valid.
        /// </summary>
        field(4; "Starting Date"; Date)
        {
            Caption = 'Starting Date';
            ToolTip = 'Specifies the date from which the sales line discount is valid.';
            DataClassification = SystemMetadata;

            trigger OnValidate()
            begin
                if ("Starting Date" > "Ending Date") and ("Ending Date" <> 0D) then
                    Error(EndDateErr, FieldCaption("Starting Date"), FieldCaption("Ending Date"));
            end;
        }
        /// <summary>
        /// Specifies the line discount percentage when the line type is Sales Line Discount.
        /// </summary>
        field(5; "Line Discount %"; Decimal)
        {
            AutoFormatType = 0;
            DecimalPlaces = 0 : 5;
            Caption = 'Line Discount %';
            ToolTip = 'Specifies the discount percentage that is granted for the item on the line.';
            DataClassification = SystemMetadata;
            MaxValue = 100;
            MinValue = 0;
        }
        /// <summary>
        /// Specifies the unit price when the line type is Sales Price.
        /// </summary>
        field(6; "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.';
            DataClassification = SystemMetadata;
            MinValue = 0;
        }
        /// <summary>
        /// Indicates whether the unit price includes VAT.
        /// </summary>
        field(7; "Price Includes VAT"; Boolean)
        {
            Caption = 'Price Includes VAT';
            ToolTip = 'Specifies if the price that is granted includes VAT.';
            DataClassification = SystemMetadata;
        }
        /// <summary>
        /// Indicates whether invoice discounts can be applied when this price is used.
        /// </summary>
        field(10; "Allow Invoice Disc."; Boolean)
        {
            Caption = 'Allow Invoice Disc.';
            ToolTip = 'Specifies if an invoice discount will be calculated when the sales price is offered.';
            DataClassification = SystemMetadata;
            InitValue = true;
        }
        /// <summary>
        /// Specifies the VAT business posting group used for price calculations when the price includes VAT.
        /// </summary>
        field(11; "VAT Bus. Posting Gr. (Price)"; Code[20])
        {
            Caption = 'VAT Bus. Posting Gr. (Price)';
            DataClassification = SystemMetadata;
            TableRelation = "VAT Business Posting Group";
        }
        /// <summary>
        /// Specifies the type of sales target, such as customer, customer price/discount group, all customers, or campaign.
        /// </summary>
        field(13; "Sales Type"; Option)
        {
            Caption = 'Sales Type';
            ToolTip = 'Specifies the sales type of the price or discount. The sales type defines whether the sales price or discount is for an individual customer, a customer discount group, or for all customers.';
            DataClassification = SystemMetadata;
            OptionCaption = 'Customer,Customer Price/Disc. Group,All Customers,Campaign';
            OptionMembers = Customer,"Customer Price/Disc. Group","All Customers",Campaign;

            trigger OnValidate()
            begin
                case "Sales Type" of
                    "Sales Type"::Customer:
                        Validate("Sales Code", "Loaded Customer No.");
                    "Sales Type"::"All Customers":
                        Validate("Sales Code", '');
                    "Sales Type"::"Customer Price/Disc. Group":
                        if "Loaded Customer No." = '' then
                            Validate("Sales Code", '')
                        else begin
                            if "Line Type" = "Line Type"::"Sales Price" then begin
                                if "Loaded Price Group" = '' then
                                    Error(CustNotInPriceGrErr);
                                Validate("Sales Code", "Loaded Price Group");
                            end;

                            if "Line Type" = "Line Type"::"Sales Line Discount" then begin
                                if "Loaded Disc. Group" = '' then
                                    Error(CustNotInDiscGrErr);
                                Validate("Sales Code", "Loaded Disc. Group");
                            end;
                        end;
                end;

                UpdateValuesFromItem();
            end;
        }
        /// <summary>
        /// Specifies the minimum quantity that must be ordered to qualify for the price or discount.
        /// </summary>
        field(14; "Minimum Quantity"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Minimum Quantity';
            ToolTip = 'Specifies the quantity that must be entered on the sales document to warrant the sales price or discount.';
            DataClassification = SystemMetadata;
            MinValue = 0;
        }
        /// <summary>
        /// Specifies the last date on which the buffer entry is valid.
        /// </summary>
        field(15; "Ending Date"; Date)
        {
            Caption = 'Ending Date';
            ToolTip = 'Specifies the date to which the sales line discount is valid.';
            DataClassification = SystemMetadata;

            trigger OnValidate()
            begin
                Validate("Starting Date");
            end;
        }
        /// <summary>
        /// Specifies whether the buffer entry applies to an item or an item discount group.
        /// </summary>
        field(21; Type; Enum "Sales Line Discount Type")
        {
            Caption = 'Type';
            ToolTip = 'Specifies if the discount is valid for an item or for an item discount group.';
            DataClassification = SystemMetadata;

            trigger OnValidate()
            begin
                case Type of
                    Type::Item:
                        Validate(Code, "Loaded Item No.");
                    Type::"Item Disc. Group":
                        begin
                            Validate(Code, '');
                            if "Loaded Item No." <> '' then begin
                                if "Loaded Disc. Group" = '' then
                                    Error(ItemNotInDiscGrErr);

                                TestField("Line Type", "Line Type"::"Sales Line Discount");
                                Validate(Code, "Loaded Disc. Group");
                            end;
                        end;
                    else
                        OnValidateTypeCaseElse();
                end;
            end;
        }
        /// <summary>
        /// Specifies whether the buffer entry represents a sales price or a sales line discount.
        /// </summary>
        field(1300; "Line Type"; Option)
        {
            Caption = 'Line Type';
            ToolTip = 'Specifies if the line is for a sales price or a sales line discount.';
            DataClassification = SystemMetadata;
            OptionCaption = ' ,Sales Line Discount,Sales Price';
            OptionMembers = " ","Sales Line Discount","Sales Price";

            trigger OnValidate()
            begin
                TestField("Line Type");
                case "Line Type" of
                    "Line Type"::"Sales Price":
                        begin
                            TestField(Type, Type::Item);
                            "Line Discount %" := 0;
                        end;
                    "Line Type"::"Sales Line Discount":
                        "Unit Price" := 0;
                end;
                Validate("Sales Type", "Sales Type");
                Validate(Type, Type);
            end;
        }
        /// <summary>
        /// Stores the item number that was used to load data into the buffer.
        /// </summary>
        field(1301; "Loaded Item No."; Code[20])
        {
            Caption = 'Loaded Item No.';
            DataClassification = SystemMetadata;
            Editable = false;
        }
        /// <summary>
        /// Stores the discount group code that was used to load data into the buffer.
        /// </summary>
        field(1302; "Loaded Disc. Group"; Code[20])
        {
            Caption = 'Loaded Disc. Group';
            DataClassification = SystemMetadata;
            Editable = false;
        }
        /// <summary>
        /// Stores the customer number that was used to load data into the buffer.
        /// </summary>
        field(1303; "Loaded Customer No."; Code[20])
        {
            Caption = 'Loaded Customer No.';
            DataClassification = SystemMetadata;
            Editable = false;
        }
        /// <summary>
        /// Stores the customer price group code that was used to load data into the buffer.
        /// </summary>
        field(1304; "Loaded Price Group"; Code[20])
        {
            Caption = 'Loaded Price Group';
            DataClassification = SystemMetadata;
            Editable = false;
        }
        /// <summary>
        /// Specifies the unit of measure that the buffer entry applies to for the item.
        /// </summary>
        field(5400; "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.';
            DataClassification = SystemMetadata;
            TableRelation = if (Type = const(Item)) "Item Unit of Measure".Code where("Item No." = field(Code));

            trigger OnValidate()
            begin
                TestField(Type, Type::Item);
            end;
        }
        /// <summary>
        /// Specifies the item variant that the buffer entry applies to.
        /// </summary>
        field(5700; "Variant Code"; Code[10])
        {
            Caption = 'Variant Code';
            ToolTip = 'Specifies the variant that must be used on the sales document line to warrant the sales price or discount.';
            DataClassification = SystemMetadata;
            TableRelation = if (Type = const(Item)) "Item Variant".Code where("Item No." = field(Code));

            trigger OnValidate()
            begin
                TestField(Type, Type::Item);
            end;
        }
        /// <summary>
        /// Indicates whether line discounts can be applied when this price is used.
        /// </summary>
        field(7001; "Allow Line Disc."; Boolean)
        {
            Caption = 'Allow Line Disc.';
            ToolTip = 'Specifies if line discounts are allowed.';
            DataClassification = SystemMetadata;
            InitValue = true;
        }
    }

    keys
    {
        key(Key1; "Line Type", Type, "Code", "Sales Type", "Sales Code", "Starting Date", "Currency Code", "Variant Code", "Unit of Measure Code", "Minimum Quantity", "Loaded Item No.", "Loaded Disc. Group", "Loaded Customer No.", "Loaded Price Group")
        {
            Clustered = true;
        }
    }

    fieldgroups
    {
    }

    trigger OnDelete()
    begin
        DeleteOldRecordVersion();
    end;

    trigger OnInsert()
    begin
        if "Sales Type" = "Sales Type"::"All Customers" then
            "Sales Code" := ''
        else
            TestField("Sales Code");
        TestField(Code);

        InsertNewRecordVersion();
    end;

    trigger OnModify()
    begin
        DeleteOldRecordVersion();
        InsertNewRecordVersion();
    end;

    trigger OnRename()
    begin
        if "Sales Type" <> "Sales Type"::"All Customers" then
            TestField("Sales Code");

        TestField(Code);

        DeleteOldRecordVersion();
        InsertNewRecordVersion();
    end;

    var
#pragma warning disable AA0470
        EndDateErr: Label '%1 cannot be after %2.';
        MustBeBlankErr: Label '%1 must be blank.';
#pragma warning restore AA0470
        CustNotInPriceGrErr: Label 'This customer is not assigned to any price group, therefore a price group could not be used in context of this customer.';
        CustNotInDiscGrErr: Label 'This customer is not assigned to any discount group, therefore a discount group could not be used in context of this customer.';
        ItemNotInDiscGrErr: Label 'This item is not assigned to any discount group, therefore a discount group could not be used in context of this item.';
        IncludeVATQst: Label 'One or more of the sales prices do not include VAT.\Do you want to update all sales prices to include VAT?';
        ExcludeVATQst: Label 'One or more of the sales prices include VAT.\Do you want to update all sales prices to exclude VAT?';
        PricesAndDiscountsCountLbl: Label 'Prices and Discounts', Locked = true;
        PricesAndDiscountsCountMsg: Label 'Total count of Prices and Discounts loaded are: %1', Locked = true;

    local procedure UpdateValuesFromItem()
    var
        Item: Record Item;
    begin
        if "Line Type" <> "Line Type"::"Sales Price" then
            exit;

        if Item.Get(Code) then begin
            "Allow Invoice Disc." := Item."Allow Invoice Disc.";
            if "Sales Type" = "Sales Type"::"All Customers" then begin
                "Price Includes VAT" := Item."Price Includes VAT";
                "VAT Bus. Posting Gr. (Price)" := Item."VAT Bus. Posting Gr. (Price)";
            end;
        end;
    end;

    /// <summary>
    /// Loads sales prices and line discounts for the specified item into the buffer.
    /// </summary>
    /// <param name="Item">The item to load prices and discounts for.</param>
    procedure LoadDataForItem(Item: Record Item)
    var
        SalesPrice: Record "Sales Price";
        SalesLineDiscountItem: Record "Sales Line Discount";
        SalesLineDiscountItemGroup: Record "Sales Line Discount";
    begin
        Reset();
        DeleteAll();

        "Loaded Item No." := Item."No.";
        "Loaded Disc. Group" := Item."Item Disc. Group";

        SetFiltersOnSalesPrice(SalesPrice);
        LoadSalesPrice(SalesPrice, 0);

        SetFiltersOnSalesLineDiscountItem(SalesLineDiscountItem);
        LoadSalesLineDiscount(SalesLineDiscountItem, 0);

        SetFiltersOnSalesLineDiscountItemGroup(SalesLineDiscountItemGroup);
        LoadSalesLineDiscount(SalesLineDiscountItemGroup, 0);

        if FindFirst() then;

        Session.LogMessage('0000AI4', StrSubstNo(PricesAndDiscountsCountMsg, Count), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', PricesAndDiscountsCountLbl);
    end;

    /// <summary>
    /// Loads sales prices and line discounts for the specified customer into the buffer.
    /// </summary>
    /// <param name="Customer">The customer to load prices and discounts for.</param>
    procedure LoadDataForCustomer(Customer: Record Customer)
    begin
        LoadDataForCustomer(Customer, 0);
    end;

    /// <summary>
    /// Loads sales prices and line discounts for the specified customer into the buffer with a maximum number of lines.
    /// </summary>
    /// <param name="Customer">The customer to load prices and discounts for.</param>
    /// <param name="MaxNoOfLines">The maximum number of lines to load. Use 0 for unlimited.</param>
    /// <returns>The number of lines loaded.</returns>
    procedure LoadDataForCustomer(var Customer: Record Customer; MaxNoOfLines: Integer): Integer
    var
        LoadedLines: Integer;
        RemainingLinesToLoad: Integer;
    begin
        Reset();
        DeleteAll();
        LoadedLines := 0;
        if MaxNoOfLines > 0 then
            RemainingLinesToLoad := MaxNoOfLines - LoadedLines;
        if EnoughLoaded(LoadedLines, MaxNoOfLines, RemainingLinesToLoad) then begin
            OnLoadDataForCustomerOnAfterCalcLoadedLines(LoadedLines, RemainingLinesToLoad, Rec, Customer, MaxNoOfLines);
            exit(LoadedLines);
        end;

        "Loaded Customer No." := Customer."No.";
        "Loaded Disc. Group" := Customer."Customer Disc. Group";
        "Loaded Price Group" := Customer."Customer Price Group";
        OnLoadDataForCustomerOnAfterSetLoadedCustomerFields(Customer, MaxNoOfLines, Rec);

        LoadedLines += LoadSalesPriceForCustomer(RemainingLinesToLoad);

        LoadedLines += LoadSalesPriceForAllCustomers(RemainingLinesToLoad);
        if EnoughLoaded(LoadedLines, MaxNoOfLines, RemainingLinesToLoad) then begin
            OnLoadDataForCustomerOnAfterCalcLoadedLines(LoadedLines, RemainingLinesToLoad, Rec, Customer, MaxNoOfLines);
            exit(LoadedLines);
        end;
        LoadedLines += LoadSalesPriceForCustPriceGr(RemainingLinesToLoad);
        if EnoughLoaded(LoadedLines, MaxNoOfLines, RemainingLinesToLoad) then begin
            OnLoadDataForCustomerOnAfterCalcLoadedLines(LoadedLines, RemainingLinesToLoad, Rec, Customer, MaxNoOfLines);
            exit(LoadedLines);
        end;
        LoadedLines += LoadSalesLineDiscForCustomer(RemainingLinesToLoad);
        if EnoughLoaded(LoadedLines, MaxNoOfLines, RemainingLinesToLoad) then begin
            OnLoadDataForCustomerOnAfterCalcLoadedLines(LoadedLines, RemainingLinesToLoad, Rec, Customer, MaxNoOfLines);
            exit(LoadedLines);
        end;
        LoadedLines += LoadSalesLineDiscForAllCustomers(RemainingLinesToLoad);
        if EnoughLoaded(LoadedLines, MaxNoOfLines, RemainingLinesToLoad) then begin
            OnLoadDataForCustomerOnAfterCalcLoadedLines(LoadedLines, RemainingLinesToLoad, Rec, Customer, MaxNoOfLines);
            exit(LoadedLines);
        end;
        LoadedLines += LoadSalesLineDiscForCustDiscGr(RemainingLinesToLoad);
        if EnoughLoaded(LoadedLines, MaxNoOfLines, RemainingLinesToLoad) then begin
            OnLoadDataForCustomerOnAfterCalcLoadedLines(LoadedLines, RemainingLinesToLoad, Rec, Customer, MaxNoOfLines);
            exit(LoadedLines);
        end;
        LoadedLines += GetCustomerCampaignSalesPrice(RemainingLinesToLoad);
        OnLoadDataForCustomerOnAfterCalcLoadedLines(LoadedLines, RemainingLinesToLoad, Rec, Customer, MaxNoOfLines);

        Session.LogMessage('0000AI3', StrSubstNo(PricesAndDiscountsCountMsg, Count), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', PricesAndDiscountsCountLbl);
        exit(LoadedLines);
    end;

    local procedure EnoughLoaded(LoadedLines: Integer; MaxNoOfLines: Integer; var RemainingLinesToLoad: Integer): Boolean
    begin
        if MaxNoOfLines > 0 then begin
            RemainingLinesToLoad := MaxNoOfLines - LoadedLines;
            exit(RemainingLinesToLoad <= 0);
        end;
        exit(false);
    end;

    local procedure LoadSalesLineDiscForCustomer(MaxNoOfLines: Integer): Integer
    var
        SalesLineDiscount: Record "Sales Line Discount";
    begin
        SetFiltersForSalesLineDiscForCustomer(SalesLineDiscount);
        exit(LoadSalesLineDiscount(SalesLineDiscount, MaxNoOfLines));
    end;

    local procedure LoadSalesLineDiscForAllCustomers(MaxNoOfLines: Integer): Integer
    var
        SalesLineDiscount: Record "Sales Line Discount";
    begin
        SetFiltersForSalesLineDiscForAllCustomers(SalesLineDiscount);
        exit(LoadSalesLineDiscount(SalesLineDiscount, MaxNoOfLines));
    end;

    local procedure LoadSalesLineDiscForCustDiscGr(MaxNoOfLines: Integer): Integer
    var
        SalesLineDiscount: Record "Sales Line Discount";
    begin
        SetFiltersForSalesLineDiscForCustDiscGr(SalesLineDiscount);
        exit(LoadSalesLineDiscount(SalesLineDiscount, MaxNoOfLines));
    end;

    local procedure LoadSalesPriceForCustomer(MaxNoOfLines: Integer): Integer
    var
        SalesPrice: Record "Sales Price";
    begin
        SetFiltersForSalesPriceForCustomer(SalesPrice);
        exit(LoadSalesPrice(SalesPrice, MaxNoOfLines));
    end;

    local procedure LoadSalesPriceForAllCustomers(MaxNoOfLines: Integer): Integer
    var
        SalesPrice: Record "Sales Price";
    begin
        SetFiltersForSalesPriceForAllCustomers(SalesPrice);
        exit(LoadSalesPrice(SalesPrice, MaxNoOfLines));
    end;

    local procedure LoadSalesPriceForCustPriceGr(MaxNoOfLines: Integer): Integer
    var
        SalesPrice: Record "Sales Price";
    begin
        SetFiltersForSalesPriceForCustPriceGr(SalesPrice);
        exit(LoadSalesPrice(SalesPrice, MaxNoOfLines));
    end;

    local procedure SetFiltersForSalesLineDiscForCustomer(var SalesLineDiscount: Record "Sales Line Discount")
    begin
        SalesLineDiscount.SetRange("Sales Type", "Sales Type"::Customer);
        SalesLineDiscount.SetRange("Sales Code", "Loaded Customer No.");
    end;

    local procedure SetFiltersForSalesLineDiscForAllCustomers(var SalesLineDiscount: Record "Sales Line Discount")
    begin
        SalesLineDiscount.SetRange("Sales Type", "Sales Type"::"All Customers");
    end;

    local procedure SetFiltersForSalesLineDiscForCustDiscGr(var SalesLineDiscount: Record "Sales Line Discount")
    begin
        SalesLineDiscount.SetRange("Sales Code", "Loaded Disc. Group");
        SalesLineDiscount.SetRange("Sales Type", "Sales Type"::"Customer Price/Disc. Group");
    end;

    local procedure SetFiltersForSalesPriceForCustomer(var SalesPrice: Record "Sales Price")
    begin
        SalesPrice.SetRange("Sales Type", "Sales Type"::Customer);
        SalesPrice.SetRange("Sales Code", "Loaded Customer No.");
    end;

    local procedure SetFiltersForSalesPriceForAllCustomers(var SalesPrice: Record "Sales Price")
    begin
        SalesPrice.SetRange("Sales Type", "Sales Type"::"All Customers");
    end;

    local procedure SetFiltersForSalesPriceForCustPriceGr(var SalesPrice: Record "Sales Price")
    begin
        SalesPrice.SetRange("Sales Code", "Loaded Price Group");
        SalesPrice.SetRange("Sales Type", "Sales Type"::"Customer Price/Disc. Group");
    end;

    local procedure LoadSalesLineDiscount(var SalesLineDiscount: Record "Sales Line Discount"; MaxNoOfLines: Integer): Integer
    var
        NoOfRows: Integer;
    begin
        if SalesLineDiscount.FindSet() then
            repeat
                Init();
                "Line Type" := "Line Type"::"Sales Line Discount";

                Code := SalesLineDiscount.Code;
                Type := SalesLineDiscount.Type;
                "Sales Code" := SalesLineDiscount."Sales Code";
                "Sales Type" := SalesLineDiscount."Sales Type";

                "Starting Date" := SalesLineDiscount."Starting Date";
                "Minimum Quantity" := SalesLineDiscount."Minimum Quantity";
                "Unit of Measure Code" := SalesLineDiscount."Unit of Measure Code";

                "Line Discount %" := SalesLineDiscount."Line Discount %";
                "Currency Code" := SalesLineDiscount."Currency Code";
                "Ending Date" := SalesLineDiscount."Ending Date";
                "Variant Code" := SalesLineDiscount."Variant Code";
                OnLoadSalesLineDiscountOnBeforeInsert(Rec, SalesLineDiscount);
                Insert();
                NoOfRows += 1;
            until (SalesLineDiscount.Next() = 0) or (MaxNoOfLines > 0) and (NoOfRows >= MaxNoOfLines);
        exit(NoOfRows);
    end;

    local procedure LoadSalesPrice(var SalesPrice: Record "Sales Price"; MaxNoOfLines: Integer): Integer
    var
        NoOfRows: Integer;
    begin
        if SalesPrice.FindSet() then
            repeat
                Init();
                "Line Type" := "Line Type"::"Sales Price";

                Code := SalesPrice."Item No.";
                Type := Type::Item;
                "Sales Code" := SalesPrice."Sales Code";
                "Sales Type" := SalesPrice."Sales Type".AsInteger();

                "Starting Date" := SalesPrice."Starting Date";
                "Minimum Quantity" := SalesPrice."Minimum Quantity";
                "Unit of Measure Code" := SalesPrice."Unit of Measure Code";
                "Unit Price" := SalesPrice."Unit Price";
                "Currency Code" := SalesPrice."Currency Code";
                "Ending Date" := SalesPrice."Ending Date";
                "Variant Code" := SalesPrice."Variant Code";

                "Price Includes VAT" := SalesPrice."Price Includes VAT";
                "VAT Bus. Posting Gr. (Price)" := SalesPrice."VAT Bus. Posting Gr. (Price)";

                "Allow Invoice Disc." := SalesPrice."Allow Invoice Disc.";
                "Allow Line Disc." := SalesPrice."Allow Line Disc.";
                OnLoadSalesPriceOnBeforeInsert(Rec, SalesPrice);
                Insert();
                NoOfRows += 1;
            until (SalesPrice.Next() = 0) or (MaxNoOfLines > 0) and (NoOfRows >= MaxNoOfLines);
        exit(NoOfRows);
    end;

    local procedure InsertNewPriceLine()
    var
        SalesPrice: Record "Sales Price";
    begin
        SalesPrice.Init();

        SalesPrice."Item No." := Code;
        SalesPrice."Sales Code" := "Sales Code";
        SalesPrice."Sales Type" := "Sales Price Type".FromInteger("Sales Type");
        SalesPrice."Starting Date" := "Starting Date";
        SalesPrice."Minimum Quantity" := "Minimum Quantity";
        SalesPrice."Unit of Measure Code" := "Unit of Measure Code";
        SalesPrice."Unit Price" := "Unit Price";
        SalesPrice."Currency Code" := "Currency Code";
        SalesPrice."Ending Date" := "Ending Date";
        SalesPrice."Variant Code" := "Variant Code";

        SalesPrice."Allow Invoice Disc." := "Allow Invoice Disc.";
        SalesPrice."Allow Line Disc." := "Allow Line Disc.";
        SalesPrice."VAT Bus. Posting Gr. (Price)" := "VAT Bus. Posting Gr. (Price)";
        SalesPrice."Price Includes VAT" := "Price Includes VAT";

        OnInsertNewPriceLineOnBeforeInsert(SalesPrice, Rec);
        SalesPrice.Insert(true);
    end;

    local procedure InsertNewDiscountLine()
    var
        SalesLineDiscount: Record "Sales Line Discount";
    begin
        SalesLineDiscount.Init();

        SalesLineDiscount.Code := Code;
        SalesLineDiscount.Type := Type;
        SalesLineDiscount."Sales Code" := "Sales Code";
        SalesLineDiscount."Sales Type" := "Sales Type";
        SalesLineDiscount."Starting Date" := "Starting Date";
        SalesLineDiscount."Minimum Quantity" := "Minimum Quantity";
        SalesLineDiscount."Unit of Measure Code" := "Unit of Measure Code";
        SalesLineDiscount."Line Discount %" := "Line Discount %";
        SalesLineDiscount."Currency Code" := "Currency Code";
        SalesLineDiscount."Ending Date" := "Ending Date";
        SalesLineDiscount."Variant Code" := "Variant Code";
        OnInsertNewDiscountLineOnBeforeInsert(SalesLineDiscount, Rec);
        SalesLineDiscount.Insert(true);
    end;

    local procedure SetFiltersOnSalesPrice(var SalesPrice: Record "Sales Price")
    begin
        SalesPrice.SetRange("Item No.", "Loaded Item No.");
        SalesPrice.SetFilter("Sales Type", '<> %1', SalesPrice."Sales Type"::Campaign);

        OnAfterSetFiltersOnSalesPrice(Rec, SalesPrice);
    end;

    local procedure SetFiltersOnSalesLineDiscountItem(var SalesLineDiscount: Record "Sales Line Discount")
    begin
        SalesLineDiscount.SetRange(Type, SalesLineDiscount.Type::Item);
        SalesLineDiscount.SetRange(Code, "Loaded Item No.");
        SalesLineDiscount.SetFilter("Sales Type", '<> %1', SalesLineDiscount."Sales Type"::Campaign);

        OnAfterSetFiltersOnSalesLineDiscountItem(Rec, SalesLineDiscount);
    end;

    local procedure SetFiltersOnSalesLineDiscountItemGroup(var SalesLineDiscount: Record "Sales Line Discount")
    begin
        SalesLineDiscount.SetRange(Type, SalesLineDiscount.Type::"Item Disc. Group");
        SalesLineDiscount.SetRange(Code, "Loaded Disc. Group");
        SalesLineDiscount.SetFilter("Sales Type", '<> %1', SalesLineDiscount."Sales Type"::Campaign);

        OnAfterSetFiltersOnSalesLineDiscountItemGroup(Rec, SalesLineDiscount);
    end;

    /// <summary>
    /// Filters the buffer to show only active records that have not expired.
    /// </summary>
    procedure FilterToActualRecords()
    begin
        SetFilter("Ending Date", '%1|%2..', 0D, Today);

        OnAfterFilterToActualRecords(Rec);
    end;

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

        TestField("Line Type");
        if xRec."Line Type" = xRec."Line Type"::"Sales Line Discount" then
            DeleteOldRecordVersionFromDiscounts()
        else
            DeleteOldRecordVersionFromPrices();
    end;

    local procedure DeleteOldRecordVersionFromDiscounts()
    var
        SalesLineDiscount: Record "Sales Line Discount";
    begin
        SalesLineDiscount.Get(
          xRec.Type,
          xRec.Code,
          xRec."Sales Type",
          xRec."Sales Code",
          xRec."Starting Date",
          xRec."Currency Code",
          xRec."Variant Code",
          xRec."Unit of Measure Code",
          xRec."Minimum Quantity");

        SalesLineDiscount.Delete(true);
    end;

    local procedure DeleteOldRecordVersionFromPrices()
    var
        SalesPrice: Record "Sales Price";
        IsHandled: Boolean;
    begin
        OnBeforeDeleteOldRecordVersionFromPrices(xRec, IsHandled);
        if IsHandled then
            exit;

        SalesPrice.Get(
          xRec.Code,
          xRec."Sales Type",
          xRec."Sales Code",
          xRec."Starting Date",
          xRec."Currency Code",
          xRec."Variant Code",
          xRec."Unit of Measure Code",
          xRec."Minimum Quantity");

        SalesPrice.Delete(true);
    end;

    local procedure InsertNewRecordVersion()
    begin
        TestField("Line Type");
        if "Line Type" = "Line Type"::"Sales Line Discount" then
            InsertNewDiscountLine()
        else
            InsertNewPriceLine();
    end;

    /// <summary>
    /// Checks whether any sales prices or line discounts exist for the specified customer.
    /// </summary>
    /// <param name="Cust">The customer to check for prices and discounts.</param>
    /// <returns>True if the customer has any prices or discounts, otherwise false.</returns>
    procedure CustHasLines(Cust: Record Customer): Boolean
    var
        SalesLineDiscount: Record "Sales Line Discount";
        SalesPrice: Record "Sales Price";
    begin
        Reset();

        "Loaded Customer No." := Cust."No.";
        "Loaded Disc. Group" := Cust."Customer Disc. Group";
        "Loaded Price Group" := Cust."Customer Price Group";

        SetFiltersForSalesLineDiscForAllCustomers(SalesLineDiscount);
        if not SalesLineDiscount.IsEmpty() then
            exit(true);
        Clear(SalesLineDiscount);

        SetFiltersForSalesPriceForAllCustomers(SalesPrice);
        if not SalesPrice.IsEmpty() then
            exit(true);
        Clear(SalesPrice);

        SetFiltersForSalesLineDiscForCustDiscGr(SalesLineDiscount);
        if not SalesLineDiscount.IsEmpty() then
            exit(true);
        Clear(SalesLineDiscount);

        SetFiltersForSalesPriceForCustPriceGr(SalesPrice);
        if not SalesPrice.IsEmpty() then
            exit(true);
        Clear(SalesPrice);

        SetFiltersForSalesLineDiscForCustomer(SalesLineDiscount);
        if not SalesLineDiscount.IsEmpty() then
            exit(true);
        Clear(SalesLineDiscount);

        SetFiltersForSalesPriceForCustomer(SalesPrice);
        if not SalesPrice.IsEmpty() then
            exit(true);

        exit(false);
    end;

    /// <summary>
    /// Checks whether any sales prices or line discounts exist for the specified item.
    /// </summary>
    /// <param name="Item">The item to check for prices and discounts.</param>
    /// <returns>True if the item has any prices or discounts, otherwise false.</returns>
    procedure ItemHasLines(Item: Record Item): Boolean
    var
        SalesLineDiscount: Record "Sales Line Discount";
        SalesPrice: Record "Sales Price";
    begin
        Reset();

        "Loaded Item No." := Item."No.";
        "Loaded Disc. Group" := Item."Item Disc. Group";

        SetFiltersOnSalesPrice(SalesPrice);
        if not SalesPrice.IsEmpty() then
            exit(true);

        SetFiltersOnSalesLineDiscountItem(SalesLineDiscount);
        if not SalesLineDiscount.IsEmpty() then
            exit(true);
        Clear(SalesLineDiscount);

        SetFiltersOnSalesLineDiscountItemGroup(SalesLineDiscount);
        if not SalesLineDiscount.IsEmpty() then
            exit(true);

        exit(false);
    end;

    /// <summary>
    /// Updates the Price Includes VAT flag and recalculates unit prices for the item.
    /// </summary>
    /// <param name="Item">The item to update prices for.</param>
    /// <param name="IncludesVat">True if prices should include VAT, otherwise false.</param>
    procedure UpdatePriceIncludesVatAndPrices(Item: Record Item; IncludesVat: Boolean)
    var
        VATPostingSetup: Record "VAT Posting Setup";
        MsgQst: Text;
    begin
        SetRange("Price Includes VAT", not IncludesVat);
        SetRange("Line Type", "Line Type"::"Sales Price");
        SetRange(Type, Type::Item);
        SetFilter("Unit Price", '>0');

        if not FindSet() then
            exit;

        if IncludesVat then
            MsgQst := IncludeVATQst
        else
            MsgQst := ExcludeVATQst;

        if not Confirm(MsgQst, false) then
            exit;

        repeat
            VATPostingSetup.Get("VAT Bus. Posting Gr. (Price)", Item."VAT Prod. Posting Group");
            OnAfterVATPostingSetupGet(VATPostingSetup);

            "Price Includes VAT" := IncludesVat;

            if IncludesVat then
                "Unit Price" := "Unit Price" * (100 + VATPostingSetup."VAT %") / 100
            else
                "Unit Price" := "Unit Price" * 100 / (100 + VATPostingSetup."VAT %");

            Modify(true);
        until Next() = 0;
    end;

    local procedure GetCustomerCampaignSalesPrice(MaxNoOfLines: Integer): Integer
    var
        ContactBusinessRelation: Record "Contact Business Relation";
        SalesPrice: Record "Sales Price";
        TempCampaign: Record Campaign temporary;
        RemainingLinesToLoad: Integer;
        LoadedLines: Integer;
    begin
        if not ContactBusinessRelation.FindByRelation(ContactBusinessRelation."Link to Table"::Customer, "Loaded Customer No.") then
            exit(0);
        SalesPrice.SetRange("Sales Type", SalesPrice."Sales Type"::Campaign);
        if SalesPrice.IsEmpty() then
            exit;

        GetContactCampaigns(TempCampaign, ContactBusinessRelation."Contact No.");

        RemainingLinesToLoad := MaxNoOfLines;
        TempCampaign.SetAutoCalcFields(Activated);
        TempCampaign.SetRange(Activated, true);
        if TempCampaign.FindSet() then
            repeat
                SalesPrice.SetRange("Sales Code", TempCampaign."No.");
                LoadedLines += LoadSalesPrice(SalesPrice, RemainingLinesToLoad);
            until (TempCampaign.Next() = 0) or EnoughLoaded(LoadedLines, MaxNoOfLines, RemainingLinesToLoad);
        exit(LoadedLines);
    end;

    local procedure GetContactCampaigns(var TempCampaign: Record Campaign temporary; CompanyContactNo: Code[20])
    var
        Contact: Record Contact;
        SegmentLine: Record "Segment Line";
    begin
        Contact.SetLoadFields("No.", "Company No.");
        Contact.SetRange("Company No.", CompanyContactNo);
        if Contact.FindSet() then begin
            SegmentLine.SetFilter("Campaign No.", '<>%1', '');
            SegmentLine.SetRange("Campaign Target", true);
            repeat
                SegmentLine.SetRange("Contact No.", Contact."No.");
                InsertTempCampaignFromSegmentLines(TempCampaign, SegmentLine);
            until Contact.Next() = 0;
        end;
    end;

    local procedure InsertTempCampaignFromSegmentLines(var TempCampaign: Record Campaign temporary; var SegmentLine: Record "Segment Line")
    begin
        SegmentLine.SetLoadFields("Segment No.", "Line No.", "Campaign No.", "Campaign Target");
        if SegmentLine.FindSet() then
            repeat
                TempCampaign.Init();
                TempCampaign."No." := SegmentLine."Campaign No.";
                if TempCampaign.Insert() then;
            until SegmentLine.Next() = 0;
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterVATPostingSetupGet(var VATPostingSetup: Record "VAT Posting Setup")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDeleteOldRecordVersion(var SalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff"; xSalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDeleteOldRecordVersionFromPrices(xSalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertNewDiscountLineOnBeforeInsert(var SalesLineDiscount: Record "Sales Line Discount"; SalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertNewPriceLineOnBeforeInsert(var SalesPrice: Record "Sales Price"; SalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnLoadSalesLineDiscountOnBeforeInsert(var SalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff"; SalesLineDiscount: Record "Sales Line Discount")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnLoadSalesPriceOnBeforeInsert(var SalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff"; SalesPrice: Record "Sales Price")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnLoadDataForCustomerOnAfterSetLoadedCustomerFields(var Customer: Record Customer; MaxNoOfLines: Integer; var SalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnLoadDataForCustomerOnAfterCalcLoadedLines(var LoadedLines: Integer; var RemainingLinesToLoad: Integer; var SalesPriceAndLineDiscBuff: Record "Sales Price and Line Disc Buff"; var Customer: Record Customer; MaxNoOfLines: Integer)
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnLookupCodeCaseElse()
    begin
    end;

    [IntegrationEvent(true, false)]
    local procedure OnValidateTypeCaseElse()
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetFiltersOnSalesPrice(var SalesPriceandLineDiscBuff: Record "Sales Price and Line Disc Buff"; var SalesPrice: Record "Sales Price")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetFiltersOnSalesLineDiscountItem(var SalesPriceandLineDiscBuff: Record "Sales Price and Line Disc Buff"; var SalesLineDiscount: Record "Sales Line Discount")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSetFiltersOnSalesLineDiscountItemGroup(var SalesPriceandLineDiscBuff: Record "Sales Price and Line Disc Buff"; var SalesLineDiscount: Record "Sales Line Discount")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterFilterToActualRecords(var SalesPriceandLineDiscBuff: Record "Sales Price and Line Disc Buff")
    begin
    end;
}