From 18f236c718b478d590aab6a40f6c5fbe039362f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Wed, 17 Sep 2025 15:16:08 +0200 Subject: [PATCH 1/9] Invoice Details for "Unit Cost Surcharge" --- .../Base/Enums/InvoiceDetailOrigin.Enum.al | 15 + .../Base/Pages/ServiceContractSetup.Page.al | 9 + .../Tables/SubscriptionContractSetup.Table.al | 4 + .../SubContractBillingPrintout.Codeunit.al | 10 +- .../CreateUsageDataBilling.Codeunit.al | 14 +- .../GenericConnectorProcessing.Codeunit.al | 16 +- .../Pages/UsageDataBillings.Page.al | 2 + .../Tables/UsageDataBilling.Table.al | 22 +- .../CreateSubBillGenSett.Codeunit.al | 2 +- .../UBB/UsageBasedBillingTest.Codeunit.al | 285 ++++++++++++------ 10 files changed, 267 insertions(+), 112 deletions(-) create mode 100644 src/Apps/W1/Subscription Billing/App/Base/Enums/InvoiceDetailOrigin.Enum.al diff --git a/src/Apps/W1/Subscription Billing/App/Base/Enums/InvoiceDetailOrigin.Enum.al b/src/Apps/W1/Subscription Billing/App/Base/Enums/InvoiceDetailOrigin.Enum.al new file mode 100644 index 0000000000..f38d556075 --- /dev/null +++ b/src/Apps/W1/Subscription Billing/App/Base/Enums/InvoiceDetailOrigin.Enum.al @@ -0,0 +1,15 @@ +namespace Microsoft.SubscriptionBilling; + +enum 8021 "Invoice Detail Origin" +{ + Extensible = true; + + value(0; "Product Name (default)") + { + Caption = 'Product Name (default)'; + } + value(1; "Subscription Line") + { + Caption = 'Subscription Line'; + } +} diff --git a/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al b/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al index a5dab98a61..bf4d2b00e1 100644 --- a/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al +++ b/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al @@ -112,6 +112,15 @@ page 8051 "Service Contract Setup" } } } + group("Usage Data") + { + Caption = 'Usage Data'; + + field("Invoice Detail Origin"; Rec."Invoice Detail Origin") + { + ToolTip = 'Specifies the origin of the invoice details'' description for usage data to be charged as Unit Cost Surcharge.'; + } + } group("Gen. Journal Templates") { Caption = 'Journal Templates'; diff --git a/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al b/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al index 6e7195ea8e..7ad178aaa6 100644 --- a/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al @@ -76,6 +76,10 @@ table 8051 "Subscription Contract Setup" Caption = 'Dimension Code for Customer Subscription Contract'; TableRelation = Dimension; } + field(30; "Invoice Detail Origin"; Enum "Invoice Detail Origin") + { + Caption = 'Invoice Detail Origin'; + } field(59; "Default Period Calculation"; enum "Period Calculation") { Caption = 'Default Period Calculation'; diff --git a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al index b8a6bbf1a5..dbb7ec7953 100644 --- a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al @@ -8,6 +8,7 @@ codeunit 8064 "Sub. Contract Billing Printout" { procedure FillContractBillingDetailsBufferFromSalesInvoice(SalesInvoiceHeader: Record "Sales Invoice Header"; var TempJobLedgerEntryBuffer: Record "Job Ledger Entry"; var ColumnHeaders: array[5] of Text) var + ServiceContractSetup: Record "Subscription Contract Setup"; BillingLineArchive: Record "Billing Line Archive"; SalesInvoiceLine: Record "Sales Invoice Line"; CustomerContract: Record "Customer Subscription Contract"; @@ -23,6 +24,8 @@ codeunit 8064 "Sub. Contract Billing Printout" if SalesInvoiceHeader."Sub. Contract Detail Overview" = Enum::"Contract Detail Overview"::None then exit; + ServiceContractSetup.Get(); + SalesDocuments.MoveBillingLineToBillingLineArchiveForPostingPreview(SalesInvoiceHeader); SalesInvoiceLine.SetRange("Document No.", SalesInvoiceHeader."No."); @@ -48,7 +51,12 @@ codeunit 8064 "Sub. Contract Billing Printout" TempJobLedgerEntryBuffer."Document Date" := UsageDataBilling."Charge Start Date"; TempJobLedgerEntryBuffer."Posting Date" := UsageDataBilling."Charge End Date"; TempJobLedgerEntryBuffer.Quantity := UsageDataBilling.Quantity; - TempJobLedgerEntryBuffer.Description := UsageDataBilling."Subscription Description"; + if (UsageDataBilling."Usage Base Pricing" = Enum::"Usage Based Pricing"::"Unit Cost Surcharge") and + (ServiceContractSetup."Invoice Detail Origin" = Enum::"Invoice Detail Origin"::"Product Name (default)") + then + TempJobLedgerEntryBuffer.Description := UsageDataBilling."Product Name" + else + TempJobLedgerEntryBuffer.Description := UsageDataBilling."Subscription Description"; TempJobLedgerEntryBuffer."External Document No." := UsageDataBilling."Subscription Contract No."; TempJobLedgerEntryBuffer."Resource Group No." := SalesInvoiceHeader."Sell-to Customer No."; if SalesInvoiceHeader."Sub. Contract Detail Overview" = Enum::"Contract Detail Overview"::Complete then begin diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al index 7022595fab..8a732eec67 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al @@ -57,24 +57,26 @@ codeunit 8023 "Create Usage Data Billing" OnAfterCollectServiceCommitments(TempServiceCommitment, ServiceObjectNo, SubscriptionEndDate); end; - internal procedure CreateUsageDataBillingFromTempServiceCommitments(var TempServiceCommitment: Record "Subscription Line"; SupplierNo: Code[20]; UsageDataImportEntryNo: Integer; ServiceObjectNo: Code[20]; BillingPeriodStartDate: Date; - BillingPeriodEndDate: Date; UnitCost: Decimal; NewQuantity: Decimal; CostAmount: Decimal; UnitPrice: Decimal; NewAmount: Decimal; CurrencyCode: Code[10]) + internal procedure CreateUsageDataBillingFromTempServiceCommitments( + var TempServiceCommitment: Record "Subscription Line"; SupplierNo: Code[20]; UsageDataImportEntryNo: Integer; ServiceObjectNo: Code[20]; ProductID: Text[80]; ProductName: Text[100]; + BillingPeriodStartDate: Date; BillingPeriodEndDate: Date; UnitCost: Decimal; NewQuantity: Decimal; CostAmount: Decimal; UnitPrice: Decimal; NewAmount: Decimal; CurrencyCode: Code[10]) begin repeat - CreateUsageDataBillingFromTempServiceCommitment(TempServiceCommitment, SupplierNo, UsageDataImportEntryNo, ServiceObjectNo, BillingPeriodStartDate, BillingPeriodEndDate, UnitCost, NewQuantity, CostAmount, UnitPrice, NewAmount, CurrencyCode); + CreateUsageDataBillingFromTempServiceCommitment(TempServiceCommitment, SupplierNo, UsageDataImportEntryNo, ServiceObjectNo, ProductID, ProductName, BillingPeriodStartDate, BillingPeriodEndDate, UnitCost, NewQuantity, CostAmount, UnitPrice, NewAmount, CurrencyCode); until TempServiceCommitment.Next() = 0; OnAfterCreateUsageDataBillingFromTempSubscriptionLines(TempServiceCommitment); end; - local procedure CreateUsageDataBillingFromTempServiceCommitment(var TempServiceCommitment: Record "Subscription Line"; SupplierNo: Code[20]; UsageDataImportEntryNo: Integer; ServiceObjectNo: Code[20]; BillingPeriodStartDate: Date; - BillingPeriodEndDate: Date; UnitCost: Decimal; NewQuantity: Decimal; CostAmount: Decimal; UnitPrice: Decimal; NewAmount: Decimal; CurrencyCode: Code[10]) + local procedure CreateUsageDataBillingFromTempServiceCommitment( + var TempServiceCommitment: Record "Subscription Line"; SupplierNo: Code[20]; UsageDataImportEntryNo: Integer; ServiceObjectNo: Code[20]; ProductID: Text[80]; ProductName: Text[100]; + BillingPeriodStartDate: Date; BillingPeriodEndDate: Date; UnitCost: Decimal; NewQuantity: Decimal; CostAmount: Decimal; UnitPrice: Decimal; NewAmount: Decimal; CurrencyCode: Code[10]) var UsageDataBilling: Record "Usage Data Billing"; UsageDataSupplier: Record "Usage Data Supplier"; begin UsageDataSupplier.Get(SupplierNo); - UsageDataBilling.InitFrom(UsageDataImportEntryNo, ServiceObjectNo, BillingPeriodStartDate, BillingPeriodEndDate, UnitCost, NewQuantity, CostAmount, UnitPrice, NewAmount, CurrencyCode); + UsageDataBilling.InitFrom(UsageDataImportEntryNo, ServiceObjectNo, ProductID, ProductName, BillingPeriodStartDate, BillingPeriodEndDate, UnitCost, NewQuantity, CostAmount, UnitPrice, NewAmount, CurrencyCode); UsageDataBilling."Supplier No." := SupplierNo; UsageDataBilling."Subscription Header No." := TempServiceCommitment."Subscription Header No."; UsageDataBilling.Partner := TempServiceCommitment.Partner; diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/GenericConnectorProcessing.Codeunit.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/GenericConnectorProcessing.Codeunit.al index 4c1759b926..d7a62d3902 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/GenericConnectorProcessing.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/GenericConnectorProcessing.Codeunit.al @@ -205,9 +205,19 @@ codeunit 8033 "Generic Connector Processing" implements "Usage Data Processing" SetUsageDataGenericImportError(''); if not CheckServiceCommitments(TempServiceCommitment) then exit; - CreateUsageDataBilling.CreateUsageDataBillingFromTempServiceCommitments(TempServiceCommitment, UsageDataImport."Supplier No.", UsageDataGenericImportGlobal."Usage Data Import Entry No.", UsageDataGenericImportGlobal."Subscription Header No.", UsageDataGenericImportGlobal."Billing Period Start Date", - UsageDataGenericImportGlobal."Billing Period End Date", UsageDataGenericImportGlobal.Cost, UsageDataGenericImportGlobal.Quantity, - UsageDataGenericImportGlobal."Cost Amount", UsageDataGenericImportGlobal.Price, UsageDataGenericImportGlobal.Amount, UsageDataGenericImportGlobal.GetCurrencyCode()); + CreateUsageDataBilling.CreateUsageDataBillingFromTempServiceCommitments( + TempServiceCommitment, UsageDataImport."Supplier No.", + UsageDataGenericImportGlobal."Usage Data Import Entry No.", + UsageDataGenericImportGlobal."Subscription Header No.", + UsageDataGenericImportGlobal."Product ID", + UsageDataGenericImportGlobal."Product Name", + UsageDataGenericImportGlobal."Billing Period Start Date", + UsageDataGenericImportGlobal."Billing Period End Date", + UsageDataGenericImportGlobal.Cost, UsageDataGenericImportGlobal.Quantity, + UsageDataGenericImportGlobal."Cost Amount", + UsageDataGenericImportGlobal.Price, + UsageDataGenericImportGlobal.Amount, + UsageDataGenericImportGlobal.GetCurrencyCode()); until UsageDataGenericImportGlobal.Next() = 0 else begin UsageDataImport.SetErrorReason(StrSubstNo(NoDataFoundErr, UsageDataImport."Processing Step")); diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Pages/UsageDataBillings.Page.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Pages/UsageDataBillings.Page.al index 0a844b6ffa..faa5696d94 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Pages/UsageDataBillings.Page.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Pages/UsageDataBillings.Page.al @@ -55,6 +55,8 @@ page 8035 "Usage Data Billings" { ToolTip = 'Specifies the Subscription Line for which the usage data is billed.'; } + field("Product ID"; Rec."Product ID") { } + field("Product Name"; Rec."Product Name") { } field("Processing Date"; Rec."Processing Date") { ToolTip = 'Specifies the date of processing.'; diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al index 3587f979e2..7e4c9b3df3 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al @@ -275,6 +275,16 @@ table 8006 "Usage Data Billing" { Caption = 'Rebilling'; } + field(35; "Product ID"; Text[80]) + { + Caption = 'Product Id'; + ToolTip = 'Specifies the unique ID of the product for this subscription with the supplier.'; + } + field(36; "Product Name"; Text[100]) + { + Caption = 'Product Name'; + ToolTip = 'Specifies the vendor''s product name for this subscription.'; + } } keys { @@ -347,20 +357,22 @@ table 8006 "Usage Data Billing" end; end; - internal procedure InitFrom(UsageDataImportEntryNo: Integer; ServiceObjectNo: Code[20]; BillingPeriodStartDate: Date; - BillingPeriodEndDate: Date; UnitCost: Decimal; NewQuantity: Decimal; CostAmount: Decimal; UnitPrice: Decimal; - NewAmount: Decimal; CurrencyCode: Code[10]) + internal procedure InitFrom(UsageDataImportEntryNo: Integer; SubscriptionHeaderNo: Code[20]; ProductID: Text[80]; ProductName: Text[100]; + BillingPeriodStartDate: Date; BillingPeriodEndDate: Date; UnitCost: Decimal; NewQuantity: Decimal; CostAmount: Decimal; + UnitPrice: Decimal; NewAmount: Decimal; CurrencyCode: Code[10]) begin Rec.Init(); Rec."Entry No." := 0; Rec."Usage Data Import Entry No." := UsageDataImportEntryNo; - Rec."Subscription Header No." := ServiceObjectNo; + Rec."Subscription Header No." := SubscriptionHeaderNo; + Rec."Product ID" := ProductID; + Rec."Product Name" := ProductName; Rec."Charge Start Date" := BillingPeriodStartDate; Rec."Charge End Date" := BillingPeriodEndDate; Rec."Unit Cost" := UnitCost; Rec.Quantity := NewQuantity; if CostAmount = 0 then - Rec."Cost Amount" := NewQuantity * unitCost + Rec."Cost Amount" := NewQuantity * UnitCost else Rec."Cost Amount" := CostAmount; Rec."Unit Price" := UnitPrice; diff --git a/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al b/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al index d0563321ee..d0f40b5364 100644 --- a/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al @@ -45,5 +45,5 @@ codeunit 8115 "Create Sub. Bill. Gen. Sett." var UsageDataGenericUsTok: Label 'USAGE-GENERIC-US', Locked = true; - UsageDataGenericUsTxt: Label '', Locked = true; + UsageDataGenericUsTxt: Label '', Locked = true; } \ No newline at end of file diff --git a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al index 125a1b9170..dde4e55945 100644 --- a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al @@ -51,10 +51,8 @@ codeunit 148153 "Usage Based Billing Test" ServiceCommitmentPackage: Record "Subscription Package"; ServiceCommitmentTemplate: Record "Sub. Package Line Template"; ServiceObject: Record "Subscription Header"; - UsageDataBilling: Record "Usage Data Billing"; UsageDataBlob: Record "Usage Data Blob"; UsageDataCustomer: Record "Usage Data Supp. Customer"; - UsageDataGenericImport: Record "Usage Data Generic Import"; UsageDataImport: Record "Usage Data Import"; UsageDataSubscription: Record "Usage Data Supp. Subscription"; UsageDataSupplier: Record "Usage Data Supplier"; @@ -93,6 +91,7 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('MessageHandler,CreateCustomerBillingDocumentPageHandler')] procedure ApplyServiceCommitmentDiscountInContractInvoice() var + UsageDataBilling: Record "Usage Data Billing"; DiscountPct: Decimal; begin // [SCENARIO] Check that discount from Subscription Line is applied in the invoice and usage data is updated accordingly @@ -125,7 +124,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); // [THEN] Expect that discount is not applied in the Usage data, but in the invoice - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); UsageDataBilling.FindFirst(); BillingLine.FilterBillingLineOnContractLine(UsageDataBilling.Partner, UsageDataBilling."Subscription Contract No.", UsageDataBilling."Subscription Contract Line No."); @@ -135,12 +134,14 @@ codeunit 148153 "Usage Based Billing Test" until BillingLine.Next() = 0; // [THEN] Test that prices Subscription Line is not updated - CheckIfServiceCommitmentRemains(); + CheckIfServiceCommitmentRemains(UsageDataBilling); end; [Test] [HandlerFunctions('MessageHandler,CreateCustomerBillingDocsContractPageHandler,ConfirmHandler')] procedure CheckIfCreditMemoIsCreatedWhenDiscountInServiceCommitmentIs100Percent() + var + UsageDataBilling: Record "Usage Data Billing"; begin //[SCENARIO]: Create service object with two service commitments; One has discount 100%, and the other one is marked as discount; Test that credit memo is created on recurring billing @@ -202,16 +203,48 @@ codeunit 148153 "Usage Based Billing Test" Codeunit.Run(Codeunit::"Create Billing Documents", BillingLine); //[THEN]: Test that credit memo is created - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); UsageDataBilling.SetRange("Document Type", UsageDataBilling."Document Type"::"Credit Memo"); Assert.RecordIsNotEmpty(UsageDataBilling); end; + [Test] + [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] + procedure EnsureUsageDataBillingContainsSubscriptionAndProduct() + var + UsageDataBilling: Record "Usage Data Billing"; + UsageDataGenericImport: Record "Usage Data Generic Import"; + SubscriptionLine: Record "Subscription Line"; + begin + // [SCENARIO] Ensure that Usage Data Billing contains Subscription Line Entry No and Product details after processing usage data import + + // [GIVEN] Create Usage data and process it + Initialize(); + CreateUsageDataBilling("Usage Based Pricing"::"Unit Cost Surcharge", LibraryRandom.RandDec(10, 2)); + PostDocument := false; + UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); + UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); + UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); + + // [THEN] Test that Subscription Line Entry No and Product details are populated in Usage Data Billing + UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); + UsageDataGenericImport.FindFirst(); + UsageDataBilling.FindSet(); + repeat + UsageDataBilling.TestField("Subscription Line Entry No."); + SubscriptionLine.Get(UsageDataBilling."Subscription Line Entry No."); + UsageDataBilling.TestField("Subscription Line Description", SubscriptionLine.Description); + UsageDataBilling.TestField("Product ID", UsageDataGenericImport."Product ID"); + UsageDataBilling.TestField("Product Name", UsageDataGenericImport."Product Name"); + until UsageDataBilling.Next() = 0; + end; + [Test] procedure ExistForContractLineDependsOnUsageDataForContractLine() var CustomerContractLine1: Record "Cust. Sub. Contract Line"; - UsageDataBilling1: Record "Usage Data Billing"; + UsageDataBilling: Record "Usage Data Billing"; UsageDataExist: Boolean; begin // [SCENARIO] Action Usage Data should be disabled if there is no Usage Data for Contract Line and should be enabled if there is Usage Data for Contract Line @@ -221,15 +254,15 @@ codeunit 148153 "Usage Based Billing Test" UsageBasedBTestLibrary.MockCustomerContractLine(CustomerContractLine1); // [WHEN] Contract line is selected - UsageDataExist := UsageDataBilling1.ExistForContractLine("Service Partner"::Customer, CustomerContractLine1."Subscription Contract No.", CustomerContractLine1."Line No."); + UsageDataExist := UsageDataBilling.ExistForContractLine("Service Partner"::Customer, CustomerContractLine1."Subscription Contract No.", CustomerContractLine1."Line No."); // [THEN] Action Usage Data should be disabled Assert.IsFalse(UsageDataExist, 'Usage Data Action should be disabled'); // [WHEN] Usage Data is created and Contract line is selected UsageBasedBTestLibrary.MockCustomerContractLine(CustomerContractLine1); - UsageBasedBTestLibrary.MockUsageDataBillingForContractLine(UsageDataBilling1, "Service Partner"::Customer, CustomerContractLine1."Subscription Contract No.", CustomerContractLine1."Line No."); - UsageDataExist := UsageDataBilling1.ExistForContractLine("Service Partner"::Customer, CustomerContractLine1."Subscription Contract No.", CustomerContractLine1."Line No."); + UsageBasedBTestLibrary.MockUsageDataBillingForContractLine(UsageDataBilling, "Service Partner"::Customer, CustomerContractLine1."Subscription Contract No.", CustomerContractLine1."Line No."); + UsageDataExist := UsageDataBilling.ExistForContractLine("Service Partner"::Customer, CustomerContractLine1."Subscription Contract No.", CustomerContractLine1."Line No."); // [THEN] Action Usage Data should be enabled Assert.IsTrue(UsageDataExist, 'Usage Data Action should be enabled'); @@ -241,7 +274,7 @@ codeunit 148153 "Usage Based Billing Test" Item1: Record Item; SalesHeader1: Record "Sales Header"; SalesLine1: Record "Sales Line"; - UsageDataBilling1: Record "Usage Data Billing"; + UsageDataBilling: Record "Usage Data Billing"; UsageDataExist: Boolean; begin // [SCENARIO] Action Usage Data should be disabled if there is no Usage Data for Document line and should be enabled if there is Usage Data for Document Line @@ -253,14 +286,14 @@ codeunit 148153 "Usage Based Billing Test" LibrarySales.CreateSalesLine(SalesLine1, SalesHeader1, SalesLine1.Type::Item, Item1."No.", LibraryRandom.RandInt(100)); // [WHEN] Sales line is selected - UsageDataExist := UsageDataBilling1.ExistForSalesDocuments(SalesLine1."Document Type", SalesLine1."Document No.", SalesLine1."Line No."); + UsageDataExist := UsageDataBilling.ExistForSalesDocuments(SalesLine1."Document Type", SalesLine1."Document No.", SalesLine1."Line No."); // [THEN] Action Usage Data should be disabled Assert.IsFalse(UsageDataExist, 'Usage Data Action should be disabled'); // [WHEN] Usage Data is created and Sales line is selected - UsageBasedBTestLibrary.MockUsageDataBillingForDocuments(UsageDataBilling1, SalesLine1."Document Type", SalesLine1."Document No.", SalesLine1."Line No."); - UsageDataExist := UsageDataBilling1.ExistForSalesDocuments(SalesLine1."Document Type", SalesLine1."Document No.", SalesLine1."Line No."); + UsageBasedBTestLibrary.MockUsageDataBillingForDocuments(UsageDataBilling, SalesLine1."Document Type", SalesLine1."Document No.", SalesLine1."Line No."); + UsageDataExist := UsageDataBilling.ExistForSalesDocuments(SalesLine1."Document Type", SalesLine1."Document No.", SalesLine1."Line No."); // [THEN] Action Usage Data should be enabled Assert.IsTrue(UsageDataExist, 'Usage Data Action should be enabled'); @@ -270,7 +303,7 @@ codeunit 148153 "Usage Based Billing Test" procedure ExistForRecurringBillingDependsOnBillingUsageData() var BillingLine1: Record "Billing Line"; - UsageDataBilling1: Record "Usage Data Billing"; + UsageDataBilling: Record "Usage Data Billing"; UsageDataExist: Boolean; begin // [SCENARIO] Action Usage Data should be disabled if there is no Usage Data for Billing Line and should be enabled if there is Usage Data for Billing Line @@ -280,7 +313,7 @@ codeunit 148153 "Usage Based Billing Test" UsageBasedBTestLibrary.MockBillingLine(BillingLine1); // [WHEN] Billing line is selected - UsageDataExist := UsageDataBilling1.ExistForRecurringBilling(BillingLine1."Subscription Header No.", BillingLine1."Subscription Line Entry No.", BillingLine1."Document Type", BillingLine1."Document No."); + UsageDataExist := UsageDataBilling.ExistForRecurringBilling(BillingLine1."Subscription Header No.", BillingLine1."Subscription Line Entry No.", BillingLine1."Document Type", BillingLine1."Document No."); // [THEN] Action Usage Data should be disabled Assert.IsFalse(UsageDataExist, 'Usage Data Action should be disabled'); @@ -288,8 +321,8 @@ codeunit 148153 "Usage Based Billing Test" // [WHEN] Usage Data is created and Billing line is selected UsageBasedBTestLibrary.MockBillingLineWithServObjectNo(BillingLine1); UsageBasedBTestLibrary.CreateSalesInvoiceAndAssignToBillingLine(BillingLine1); - UsageBasedBTestLibrary.MockUsageDataForBillingLine(UsageDataBilling1, BillingLine1); - UsageDataExist := UsageDataBilling1.ExistForRecurringBilling(BillingLine1."Subscription Header No.", BillingLine1."Subscription Line Entry No.", BillingLine1."Document Type", BillingLine1."Document No."); + UsageBasedBTestLibrary.MockUsageDataForBillingLine(UsageDataBilling, BillingLine1); + UsageDataExist := UsageDataBilling.ExistForRecurringBilling(BillingLine1."Subscription Header No.", BillingLine1."Subscription Line Entry No.", BillingLine1."Document Type", BillingLine1."Document No."); // [THEN] Action Usage Data should be enabled Assert.IsTrue(UsageDataExist, 'Usage Data Action should be enabled'); @@ -299,7 +332,7 @@ codeunit 148153 "Usage Based Billing Test" procedure ExistForServiceCommitmentsDependsOnServiceCommitmentUsageData() var ServiceCommitment1: Record "Subscription Line"; - UsageDataBilling1: Record "Usage Data Billing"; + UsageDataBilling: Record "Usage Data Billing"; UsageDataExist: Boolean; begin // [SCENARIO] Action Usage Data should be disabled if there is no Usage Data for Subscription Line Line and should be enabled if there is Usage Data for Subscription Line Line @@ -309,14 +342,14 @@ codeunit 148153 "Usage Based Billing Test" UsageBasedBTestLibrary.MockServiceCommitmentLine(ServiceCommitment1); // [WHEN] Subscription Line line is selected - UsageDataExist := UsageDataBilling1.ExistForServiceCommitments(ServiceCommitment1.Partner, ServiceCommitment1."Subscription Header No.", ServiceCommitment1."Entry No."); + UsageDataExist := UsageDataBilling.ExistForServiceCommitments(ServiceCommitment1.Partner, ServiceCommitment1."Subscription Header No.", ServiceCommitment1."Entry No."); // [THEN] Action Usage Data should be disabled Assert.IsFalse(UsageDataExist, 'Usage Data Action should be disabled'); // [WHEN] Usage data is created and Subscription Line line is selected - UsageBasedBTestLibrary.MockUsageDataBillingForServiceCommitmentLine(UsageDataBilling1, ServiceCommitment1.Partner, ServiceCommitment1."Subscription Header No.", ServiceCommitment1."Entry No."); - UsageDataExist := UsageDataBilling1.ExistForServiceCommitments(ServiceCommitment1.Partner, ServiceCommitment1."Subscription Header No.", ServiceCommitment1."Entry No."); + UsageBasedBTestLibrary.MockUsageDataBillingForServiceCommitmentLine(UsageDataBilling, ServiceCommitment1.Partner, ServiceCommitment1."Subscription Header No.", ServiceCommitment1."Entry No."); + UsageDataExist := UsageDataBilling.ExistForServiceCommitments(ServiceCommitment1.Partner, ServiceCommitment1."Subscription Header No.", ServiceCommitment1."Entry No."); // [THEN] Action Usage Data should be enabled Assert.IsTrue(UsageDataExist, 'Usage Data Action should be enabled'); @@ -336,6 +369,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure ExpectErrorIfServiceCommitmentIsNotAssignedToContract() + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin Initialize(); SetupUsageDataForProcessingToGenericImport(WorkDate(), WorkDate(), WorkDate(), WorkDate(), 1, false); @@ -358,7 +393,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); UsageDataGenericImport.FindFirst(); - PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling("Usage Based Pricing"::"Usage Quantity", '1D', '1D'); + PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport, "Usage Based Pricing"::"Usage Quantity", '1D', '1D'); Codeunit.Run(Codeunit::"Import And Process Usage Data", UsageDataImport); UsageDataImport.SetRecFilter(); UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Create Usage Data Billing"); @@ -370,6 +405,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure ExpectErrorOnDeleteCustomerContractLine() + var + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); @@ -430,6 +467,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure ExpectErrorWhenServiceCommitmentStartDateIsNotValid() + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin Initialize(); SetupUsageDataForProcessingToGenericImport(); @@ -450,6 +489,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure ExpectNoInvoicesCreateIfUsageDataImportProcessingStatusIsError() + var + UsageDataBilling: Record "Usage Data Billing"; begin // [SCENARIO] When usage data is processed with an error // expect no invoices to be created @@ -468,7 +509,7 @@ codeunit 148153 "Usage Based Billing Test" // [THEN] Test if Processing Status Error is set in Usage Data Import and that no invoice has been created and assigned in Usage Data Billing UsageDataImport.Get(UsageDataImport."Entry No."); UsageDataImport.TestField("Processing Status", Enum::"Processing Status"::Error); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::Invoice); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::Invoice); Assert.RecordIsEmpty(UsageDataBilling); end; @@ -553,6 +594,7 @@ codeunit 148153 "Usage Based Billing Test" var CustomerContract2: Record "Customer Subscription Contract"; ServiceObject2: Record "Subscription Header"; + UsageDataBilling: Record "Usage Data Billing"; TestSubscribers: Codeunit "Usage Based B. Test Subscr."; QuantityOfServiceCommitments: Integer; begin @@ -592,6 +634,7 @@ codeunit 148153 "Usage Based Billing Test" var CustomerContract2: Record "Customer Subscription Contract"; ServiceObject2: Record "Subscription Header"; + UsageDataBilling: Record "Usage Data Billing"; TestSubscribers: Codeunit "Usage Based B. Test Subscr."; QuantityOfServiceCommitments: Integer; begin @@ -627,13 +670,18 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure TestCreateUsageDataBilling() + var + UsageDataBilling: Record "Usage Data Billing"; + UsageDataGenericImport: Record "Usage Data Generic Import"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); UsageDataImport.FindLast(); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataBilling.FindLast(); - TestUsageDataBilling(); + UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); + UsageDataGenericImport.FindFirst(); + TestUsageDataBilling(UsageDataGenericImport, UsageDataBilling); end; [Test] @@ -658,6 +706,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] procedure TestCreateUsageDataGenericImport() + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin // Create Setup Data and Import file Initialize(); @@ -723,13 +773,16 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure TestDeleteUsageDataBilling() + var + UsageDataBilling: Record "Usage Data Billing"; + UsageDataGenericImport: Record "Usage Data Generic Import"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); UsageDataImport.DeleteUsageDataBillingLines(); Commit(); // retain data after asserterror - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No."); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); Assert.RecordIsEmpty(UsageDataBilling); Clear(UsageDataGenericImport); UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); @@ -766,6 +819,9 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure TestIfRelatedDataIsDeletedOnDeleteUsageDataImport() + var + UsageDataBilling: Record "Usage Data Billing"; + UsageDataGenericImport: Record "Usage Data Generic Import"; begin Initialize(); j := LibraryRandom.RandIntInRange(2, 10); @@ -787,7 +843,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); Assert.RecordIsEmpty(UsageDataGenericImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No."); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); Assert.RecordIsEmpty(UsageDataBilling); until UsageDataImport.Next() = 0; end; @@ -852,6 +908,8 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure TestPriceCalculationInUsageBasedBasedOnDay() var + UsageDataBilling: Record "Usage Data Billing"; + UsageDataGenericImport: Record "Usage Data Generic Import"; ProcessUsageDataBilling: Codeunit "Process Usage Data Billing"; RoundingPrecision: Decimal; begin @@ -877,13 +935,13 @@ codeunit 148153 "Usage Based Billing Test" UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); UsageDataGenericImport.FindFirst(); - PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling("Usage Based Pricing"::"Usage Quantity", '1D', '1D'); + PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport, "Usage Based Pricing"::"Usage Quantity", '1D', '1D'); Codeunit.Run(Codeunit::"Import And Process Usage Data", UsageDataImport); UsageDataImport.SetRecFilter(); UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Create Usage Data Billing"); UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No."); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); UsageDataBilling.FindSet(); ProcessUsageDataBilling.SetRoundingPrecision(RoundingPrecision, UsageDataBilling."Unit Price", Currency); Assert.AreEqual(Round(ServiceCommitment.Price, RoundingPrecision), UsageDataBilling."Unit Price", 'Amount was not calculated properly in Usage data.'); @@ -929,6 +987,7 @@ codeunit 148153 "Usage Based Billing Test" [Test] procedure TestProcessUsageDataBillingWithFixedQuantityAndPartialPeriods() var + UsageDataBilling: Record "Usage Data Billing"; ProcessUsageDataBilling: Codeunit "Process Usage Data Billing"; CalculatedAmount: Decimal; ExpectedResult: Decimal; @@ -954,7 +1013,7 @@ codeunit 148153 "Usage Based Billing Test" ProcessUsageDataWithSimpleGenericImport(CalcDate('<-CM>', WorkDate()), WorkDate(), CalcDate('<-CM>', WorkDate()), WorkDate(), ServiceObject.Quantity, "Usage Based Pricing"::"Fixed Quantity"); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); UsageDataBilling.CalcSums(Amount); CalculatedAmount := UsageDataBilling.Amount; UsageDataBilling.FindFirst(); @@ -966,6 +1025,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure TestProcessUsageDataGenericImport() + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin Initialize(); SetupUsageDataForProcessingToGenericImport(); @@ -978,11 +1039,11 @@ codeunit 148153 "Usage Based Billing Test" SetupServiceObjectAndContracts(WorkDate()); ProcessUsageDataImport(Enum::"Processing Step"::"Process Imported Lines"); // Process Usage Data Generic Import - CheckIfUsageDataSubscriptionIsCreated(); - CheckIfUsageDataCustomerIsCreated(); - CheckIfCustomerSupplierReferencesAreIsCreated(); - CheckIfSubscriptionSupplierReferencesAreIsCreated(); - CheckIfProductSupplierReferencesAreIsCreated(); + CheckIfUsageDataSubscriptionIsCreated(UsageDataGenericImport); + CheckIfUsageDataCustomerIsCreated(UsageDataGenericImport."Customer ID"); + CheckIfCustomerSupplierReferencesAreIsCreated(UsageDataGenericImport."Customer ID"); + CheckIfSubscriptionSupplierReferencesAreIsCreated(UsageDataGenericImport."Supp. Subscription ID"); + CheckIfProductSupplierReferencesAreIsCreated(UsageDataGenericImport."Product ID"); end; [Test] @@ -1128,6 +1189,7 @@ codeunit 148153 "Usage Based Billing Test" procedure TestUpdateUsageBasedAfterDeletePurchaseCreditMemo() var PurchaseInvoiceHeader: Record "Purch. Inv. Header"; + UsageDataBilling: Record "Usage Data Billing"; begin //[SCENARIO]: Check that usage data billing is deleted after deleting purchase credit memo ResetAll(); @@ -1159,13 +1221,15 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateVendorBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterDeletePurchaseInvoice() + var + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectVendorContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No."); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); UsageDataBilling.MarkPurchaseHeaderFromUsageDataBilling(UsageDataBilling, PurchaseHeader); PurchaseHeader.FindSet(); PurchaseHeader.Delete(true); @@ -1202,6 +1266,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterDeleteSalesCreditMemo() + var + UsageDataBilling: Record "Usage Data Billing"; begin //[SCENARIO]: Check that usage data billing is deleted after deleting sales credit memo ResetAll(); @@ -1214,7 +1280,7 @@ codeunit 148153 "Usage Based Billing Test" //[GIVEN] Create sales invoice from Usage Data Import UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); UsageDataBilling.FindSet(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); @@ -1276,6 +1342,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterInsertCreditMemo() + var + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); @@ -1283,12 +1351,12 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); UsageDataBilling.FindSet(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); Assert.RecordCount(UsageDataBilling, 2); // Expect additional usage data billing for credit memo UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", SalesCrMemoHeader."No."); @@ -1299,6 +1367,7 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateVendorBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterInsertPurchaseCreditMemo() var + UsageDataBilling: Record "Usage Data Billing"; PurchaseInvoiceHeader: Record "Purch. Inv. Header"; begin Initialize(); @@ -1312,7 +1381,7 @@ codeunit 148153 "Usage Based Billing Test" PurchaseInvoiceHeader.FindLast(); CorrectPostedPurchaseInvoice.CreateCreditMemoCopyDocument(PurchaseInvoiceHeader, PurchaseHeader); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Vendor); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Vendor); Assert.RecordCount(UsageDataBilling, 2); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Vendor, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", PurchaseHeader."No."); @@ -1322,6 +1391,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterInsertSalesCreditMemo() + var + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); @@ -1330,12 +1401,12 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); UsageDataBilling.FindSet(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); Assert.RecordCount(UsageDataBilling, 2); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", SalesCrMemoHeader."No."); @@ -1345,6 +1416,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterPostCreditMemo() + var + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); @@ -1352,14 +1425,14 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); UsageDataBilling.FindSet(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); CorrectedDocumentNo := LibrarySales.PostSalesDocument(SalesCrMemoHeader, true, true); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); Assert.RecordCount(UsageDataBilling, 3); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Posted Credit Memo", CorrectedDocumentNo); @@ -1373,6 +1446,7 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateVendorBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterPostPurchaseCreditMemo() var + UsageDataBilling: Record "Usage Data Billing"; PurchaseInvoiceHeader: Record "Purch. Inv. Header"; begin Initialize(); @@ -1389,7 +1463,7 @@ codeunit 148153 "Usage Based Billing Test" PurchaseHeader.Modify(false); CorrectedDocumentNo := LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Vendor); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Vendor); Assert.RecordCount(UsageDataBilling, 3); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Vendor, Enum::"Usage Based Billing Doc. Type"::"Posted Credit Memo", CorrectedDocumentNo); @@ -1420,6 +1494,8 @@ codeunit 148153 "Usage Based Billing Test" [Test] [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] procedure TestUpdateUsageBasedAfterPostSalesCreditMemo() + var + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Fixed Quantity", LibraryRandom.RandDec(10, 2)); @@ -1427,14 +1503,14 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); UsageDataBilling.FindSet(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); CorrectedDocumentNo := LibrarySales.PostSalesDocument(SalesCrMemoHeader, true, true); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); Assert.RecordCount(UsageDataBilling, 3); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Posted Credit Memo", CorrectedDocumentNo); @@ -1463,7 +1539,7 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('MessageHandler,CreateCustomerBillingDocumentPageHandler')] procedure TestYearlyServiceCommitmentWithDailyUsageData() var - UsageDataBilling2: Record "Usage Data Billing"; + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); ContractTestLibrary.CreateItemWithServiceCommitmentOption(Item, Enum::"Item Service Commitment Type"::"Service Commitment Item"); @@ -1476,13 +1552,13 @@ codeunit 148153 "Usage Based Billing Test" '1Y', '1Y', '1Y', "Service Partner"::Customer, 100, Item."No."); ProcessUsageDataWithSimpleGenericImport(WorkDate(), WorkDate(), WorkDate(), WorkDate(), 1); - UsageDataBilling2.Reset(); - UsageDataBilling2.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); - UsageDataBilling2.SetRange(Partner, "Service Partner"::Customer); - if UsageDataBilling2.FindSet() then + UsageDataBilling.Reset(); + UsageDataBilling.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); + UsageDataBilling.SetRange(Partner, "Service Partner"::Customer); + if UsageDataBilling.FindSet() then repeat - UsageDataBilling2.TestField("Unit Price", UsageDataBilling2."Charged Period (Days)"); - until UsageDataBilling2.Next() = 0; + UsageDataBilling.TestField("Unit Price", UsageDataBilling."Charged Period (Days)"); + until UsageDataBilling.Next() = 0; CreateContractInvoicesAndTestProcessedUsageData(); end; @@ -1490,7 +1566,7 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('MessageHandler,CreateCustomerBillingDocumentPageHandler')] procedure TestYearlyServiceCommitmentWithMonthlyUsageData() var - UsageDataBilling2: Record "Usage Data Billing"; + UsageDataBilling: Record "Usage Data Billing"; begin Initialize(); ContractTestLibrary.CreateItemWithServiceCommitmentOption(Item, Enum::"Item Service Commitment Type"::"Service Commitment Item"); @@ -1503,13 +1579,13 @@ codeunit 148153 "Usage Based Billing Test" '1Y', '1Y', '1Y', "Service Partner"::Customer, 100, Item."No."); ProcessUsageDataWithSimpleGenericImport(WorkDate(), CalcDate('', WorkDate()), WorkDate(), CalcDate('', WorkDate()), 1); - UsageDataBilling2.Reset(); - UsageDataBilling2.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); - UsageDataBilling2.SetRange(Partner, "Service Partner"::Customer); - if UsageDataBilling2.FindSet() then + UsageDataBilling.Reset(); + UsageDataBilling.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); + UsageDataBilling.SetRange(Partner, "Service Partner"::Customer); + if UsageDataBilling.FindSet() then repeat - UsageDataBilling2.TestField("Unit Price", UsageDataBilling2."Charged Period (Days)"); - until UsageDataBilling2.Next() = 0; + UsageDataBilling.TestField("Unit Price", UsageDataBilling."Charged Period (Days)"); + until UsageDataBilling.Next() = 0; CreateContractInvoicesAndTestProcessedUsageData(); end; @@ -1517,6 +1593,7 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler')] procedure UpdatingServiceObjectAvailabilityDuringProcessing() var + UsageDataGenericImport: Record "Usage Data Generic Import"; ItemReference: Record "Item Reference"; begin // [SCENARIO]: The Subscription Availability should be properly updated after processing imported lines @@ -1542,6 +1619,8 @@ codeunit 148153 "Usage Based Billing Test" ValidateUsageDataGenericImportAvailability(UsageDataImport."Entry No.", "Service Object Availability"::"Not Available", ''); // [WHEN]: insert an item reference to a usage data supplier reference + UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); + UsageDataGenericImport.FindFirst(); UsageDataSubscription.FindForSupplierReference(UsageDataImport."Supplier No.", UsageDataGenericImport."Supp. Subscription ID"); UsageDataSupplierReference.FindSupplierReference(UsageDataImport."Supplier No.", UsageDataSubscription."Product ID", Enum::"Usage Data Reference Type"::Product); LibraryItemReference.CreateItemReference(ItemReference, Item."No.", "Item Reference Type"::Vendor, UsageDataSupplier."Vendor No."); @@ -1645,7 +1724,8 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('MessageHandler,CreateCustomerBillingDocumentPageHandler')] procedure TestUsageDataImportWithMultipleUsageDataGenericImports() var - UBBTestLibrary: Codeunit "Usage Based B. Test Library"; + UsageDataBilling: Record "Usage Data Billing"; + UsageDataGenericImport: Record "Usage Data Generic Import"; BillingPeriodStartDate: Date; SubscriptionStartDate: Date; SubscriptionID: Text; @@ -1668,14 +1748,14 @@ codeunit 148153 "Usage Based Billing Test" '1M', '1M', '1M', "Service Partner"::Customer, 100, Item."No."); // [WHEN] Create and process simple usage data - UBBTestLibrary.CreateUsageDataSupplier(UsageDataSupplier, Enum::"Usage Data Supplier Type"::Generic, false, Enum::"Vendor Invoice Per"::Import); - UBBTestLibrary.CreateGenericImportSettings(GenericImportSettings, UsageDataSupplier."No.", true, true); - UBBTestLibrary.CreateUsageDataImport(UsageDataImport, UsageDataSupplier."No."); + UsageBasedBTestLibrary.CreateUsageDataSupplier(UsageDataSupplier, Enum::"Usage Data Supplier Type"::Generic, false, Enum::"Vendor Invoice Per"::Import); + UsageBasedBTestLibrary.CreateGenericImportSettings(GenericImportSettings, UsageDataSupplier."No.", true, true); + UsageBasedBTestLibrary.CreateUsageDataImport(UsageDataImport, UsageDataSupplier."No."); BillingPeriodStartDate := CalcDate('<-CM>', WorkDate()); SubscriptionStartDate := CalcDate('<-CM>', WorkDate()); SubscriptionID := LibraryRandom.RandText(80); for i := 1 to LibraryRandom.RandInt(10) do begin - UBBTestLibrary.CreateSimpleUsageDataGenericImport(UsageDataGenericImport, UsageDataImport."Entry No.", ServiceObject."No.", Customer."No.", Item."Unit Cost", + UsageBasedBTestLibrary.CreateSimpleUsageDataGenericImport(UsageDataGenericImport, UsageDataImport."Entry No.", ServiceObject."No.", Customer."No.", Item."Unit Cost", BillingPeriodStartDate, CalcDate('', BillingPeriodStartDate), SubscriptionStartDate, CalcDate('', SubscriptionStartDate), LibraryRandom.RandInt(10)); UsageDataGenericImport."Supp. Subscription ID" := CopyStr(SubscriptionID, 1, MaxStrLen(UsageDataGenericImport."Supp. Subscription ID")); @@ -1690,7 +1770,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); UsageDataGenericImport.FindFirst(); repeat - PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(Enum::"Usage Based Pricing"::"Usage Quantity", '1M', '1M', Calcdate('<-CM>', WorkDate())); + PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport, Enum::"Usage Based Pricing"::"Usage Quantity", '1M', '1M', Calcdate('<-CM>', WorkDate())); until UsageDataGenericImport.Next() = 0; Codeunit.Run(Codeunit::"Import And Process Usage Data", UsageDataImport); @@ -1761,15 +1841,15 @@ codeunit 148153 "Usage Based Billing Test" BillingLine.DeleteAll(false); end; - local procedure CheckIfCustomerSupplierReferencesAreIsCreated() + local procedure CheckIfCustomerSupplierReferencesAreIsCreated(CustomerID: Text[80]) begin - UsageDataSupplierReference.FilterUsageDataSupplierReference(UsageDataImport."Supplier No.", UsageDataGenericImport."Customer ID", Enum::"Usage Data Reference Type"::Customer); + UsageDataSupplierReference.FilterUsageDataSupplierReference(UsageDataImport."Supplier No.", CustomerID, Enum::"Usage Data Reference Type"::Customer); UsageDataSupplierReference.FindFirst(); end; - local procedure CheckIfProductSupplierReferencesAreIsCreated() + local procedure CheckIfProductSupplierReferencesAreIsCreated(ProductID: Text[80]) begin - UsageDataSupplierReference.FilterUsageDataSupplierReference(UsageDataImport."Supplier No.", UsageDataGenericImport."Product ID", Enum::"Usage Data Reference Type"::Product); + UsageDataSupplierReference.FilterUsageDataSupplierReference(UsageDataImport."Supplier No.", ProductID, Enum::"Usage Data Reference Type"::Product); UsageDataSupplierReference.FindFirst(); end; @@ -1818,6 +1898,8 @@ codeunit 148153 "Usage Based Billing Test" end; local procedure TestIfInvoicesMatchesUsageData(ServicePartner: Enum "Service Partner"; InvoiceAmount: Decimal; DocumentNo: Code[20]) + var + UsageDataBilling: Record "Usage Data Billing"; begin UsageDataBilling.Reset(); UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(ServicePartner, Enum::"Usage Based Billing Doc. Type"::"Invoice", DocumentNo); @@ -1830,7 +1912,7 @@ codeunit 148153 "Usage Based Billing Test" end; end; - local procedure CheckIfServiceCommitmentRemains() + local procedure CheckIfServiceCommitmentRemains(UsageDataBilling: Record "Usage Data Billing") begin ServiceCommitment.Reset(); ServiceCommitment.SetRange("Subscription Header No.", UsageDataBilling."Subscription Header No."); @@ -1844,20 +1926,20 @@ codeunit 148153 "Usage Based Billing Test" until ServiceCommitment.Next() = 0; end; - local procedure CheckIfSubscriptionSupplierReferencesAreIsCreated() + local procedure CheckIfSubscriptionSupplierReferencesAreIsCreated(SuppSubscriptionID: Text[80]) begin - UsageDataSupplierReference.FilterUsageDataSupplierReference(UsageDataImport."Supplier No.", UsageDataGenericImport."Supp. Subscription ID", Enum::"Usage Data Reference Type"::Subscription); + UsageDataSupplierReference.FilterUsageDataSupplierReference(UsageDataImport."Supplier No.", SuppSubscriptionID, Enum::"Usage Data Reference Type"::Subscription); UsageDataSupplierReference.FindFirst(); end; - local procedure CheckIfUsageDataCustomerIsCreated() + local procedure CheckIfUsageDataCustomerIsCreated(CustomerID: Text[80]) begin UsageDataCustomer.SetRange("Supplier No.", UsageDataImport."Supplier No."); - UsageDataCustomer.SetRange("Supplier Reference", UsageDataGenericImport."Customer ID"); + UsageDataCustomer.SetRange("Supplier Reference", CustomerID); UsageDataCustomer.FindFirst(); end; - local procedure CheckIfUsageDataSubscriptionIsCreated() + local procedure CheckIfUsageDataSubscriptionIsCreated(UsageDataGenericImport: Record "Usage Data Generic Import") begin UsageDataSubscription.FindForSupplierReference(UsageDataImport."Supplier No.", UsageDataGenericImport."Supp. Subscription ID"); UsageDataSubscription.TestField("Customer ID", UsageDataGenericImport."Customer ID"); @@ -1887,9 +1969,10 @@ codeunit 148153 "Usage Based Billing Test" local procedure CreateContractInvoicesAndTestProcessedUsageData() var + UsageDataBilling: Record "Usage Data Billing"; ExpectedInvoiceAmount: Decimal; begin - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); UsageDataBilling.CalcSums(Amount); ExpectedInvoiceAmount := UsageDataBilling.Amount; UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); @@ -1897,7 +1980,7 @@ codeunit 148153 "Usage Based Billing Test" Currency.InitRoundingPrecision(); UsageDataBilling.FindFirst(); - CheckIfServiceCommitmentRemains(); + CheckIfServiceCommitmentRemains(UsageDataBilling); BillingLine.FilterBillingLineOnContractLine(UsageDataBilling.Partner, UsageDataBilling."Subscription Contract No.", UsageDataBilling."Subscription Contract Line No."); BillingLine.CalcSums(Amount); @@ -1940,6 +2023,8 @@ codeunit 148153 "Usage Based Billing Test" end; local procedure CreateUsageDataBilling(UsageBasedPricing: Enum "Usage Based Pricing"; BillingPeriodStartingDate: Date; BillingPeriodEndingDate: Date; SubscriptionStartingDate: Date; SubscriptionEndingDate: Date; Quantity: Decimal) + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin SetupUsageDataForProcessingToGenericImport(BillingPeriodStartingDate, BillingPeriodEndingDate, SubscriptionStartingDate, SubscriptionEndingDate, Quantity); SetupDataExchangeDefinition(); @@ -1952,7 +2037,7 @@ codeunit 148153 "Usage Based Billing Test" // Therefore Processing needs to be performed twice - refer to AB2070 UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); UsageDataGenericImport.FindFirst(); - PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageBasedPricing); + PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport, UsageBasedPricing); Codeunit.Run(Codeunit::"Import And Process Usage Data", UsageDataImport); UsageDataImport.SetRecFilter(); UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Create Usage Data Billing"); @@ -1987,21 +2072,21 @@ codeunit 148153 "Usage Based Billing Test" ContractTestLibrary.SetGeneralPostingSetup(Vendor."Gen. Bus. Posting Group", Item."Gen. Prod. Posting Group", false, Enum::"Service Partner"::Vendor); end; - local procedure FilterUsageDataBillingOnUsageDataImport(UsageDataImportEntryNo: Integer) + local procedure FilterUsageDataBillingOnUsageDataImport(var UsageDataBilling: Record "Usage Data Billing"; UsageDataImportEntryNo: Integer) begin UsageDataBilling.Reset(); UsageDataBilling.SetRange("Usage Data Import Entry No.", UsageDataImportEntryNo); end; - local procedure FilterUsageDataBillingOnUsageDataImport(UsageDataImportEntryNo: Integer; ServicePartner: Enum "Service Partner") + local procedure FilterUsageDataBillingOnUsageDataImport(var UsageDataBilling: Record "Usage Data Billing"; UsageDataImportEntryNo: Integer; ServicePartner: Enum "Service Partner") begin - FilterUsageDataBillingOnUsageDataImport(UsageDataImportEntryNo); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImportEntryNo); UsageDataBilling.SetRange(Partner, ServicePartner); end; - local procedure FilterUsageDataBillingOnUsageDataImport(UsageDataImportEntryNo: Integer; ServicePartner: Enum "Service Partner"; UsageBasedBillingDocType: Enum "Usage Based Billing Doc. Type") + local procedure FilterUsageDataBillingOnUsageDataImport(var UsageDataBilling: Record "Usage Data Billing"; UsageDataImportEntryNo: Integer; ServicePartner: Enum "Service Partner"; UsageBasedBillingDocType: Enum "Usage Based Billing Doc. Type") begin - FilterUsageDataBillingOnUsageDataImport(UsageDataImportEntryNo, ServicePartner); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImportEntryNo, ServicePartner); UsageDataBilling.SetRange("Document Type", UsageBasedBillingDocType); end; @@ -2046,8 +2131,11 @@ codeunit 148153 "Usage Based Billing Test" end; local procedure PostPurchaseDocuments() + var + + UsageDataBilling: Record "Usage Data Billing"; begin - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No."); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); UsageDataBilling.MarkPurchaseHeaderFromUsageDataBilling(UsageDataBilling, PurchaseHeader); PurchaseHeader.FindSet(); repeat @@ -2057,20 +2145,17 @@ codeunit 148153 "Usage Based Billing Test" until PurchaseHeader.Next() = 0; end; - local procedure PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageBasedPricing: Enum "Usage Based Pricing") + local procedure PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport: Record "Usage Data Generic Import"; UsageBasedPricing: Enum "Usage Based Pricing") begin - PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageBasedPricing, '', ''); + PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport, UsageBasedPricing, '', ''); end; - local procedure PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageBasedPricing: Enum "Usage Based Pricing"; BillingBasePeriod: Text; - BillingRhythm: Text) + local procedure PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport: Record "Usage Data Generic Import"; UsageBasedPricing: Enum "Usage Based Pricing"; BillingBasePeriod: Text; BillingRhythm: Text) begin - PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageBasedPricing, BillingBasePeriod, BillingRhythm, 0D); - + PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport, UsageBasedPricing, BillingBasePeriod, BillingRhythm, 0D); end; - local procedure PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageBasedPricing: Enum "Usage Based Pricing"; BillingBasePeriod: Text; - BillingRhythm: Text; ServiceStartDate: Date) + local procedure PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport: Record "Usage Data Generic Import"; UsageBasedPricing: Enum "Usage Based Pricing"; BillingBasePeriod: Text; BillingRhythm: Text; ServiceStartDate: Date) begin ServiceCommitment.SetRange("Subscription Header No.", ServiceObject."No."); ServiceCommitment.FindSet(); @@ -2104,6 +2189,8 @@ codeunit 148153 "Usage Based Billing Test" end; local procedure ProcessUsageDataWithSimpleGenericImport(BillingPeriodStartDate: Date; BillingPeriodEndDate: Date; SubscriptionStartDate: Date; SubscriptionEndDate: Date; Quantity: Decimal; UsageBasedPricing: Enum "Usage Based Pricing") + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin UsageBasedBTestLibrary.CreateUsageDataSupplier(UsageDataSupplier, Enum::"Usage Data Supplier Type"::Generic, false, Enum::"Vendor Invoice Per"::Import); UsageBasedBTestLibrary.CreateGenericImportSettings(GenericImportSettings, UsageDataSupplier."No.", true, true); @@ -2112,7 +2199,7 @@ codeunit 148153 "Usage Based Billing Test" ProcessUsageDataImport(Enum::"Processing Step"::"Process Imported Lines"); UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); UsageDataGenericImport.FindFirst(); - PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageBasedPricing); + PrepareServiceCommitmentAndUsageDataGenericImportForUsageBilling(UsageDataGenericImport, UsageBasedPricing); Codeunit.Run(Codeunit::"Import And Process Usage Data", UsageDataImport); UsageDataImport.SetRecFilter(); @@ -2224,6 +2311,8 @@ codeunit 148153 "Usage Based Billing Test" end; local procedure SetupUsageDataForProcessingToGenericImport(BillingPeriodStartingDate: Date; BillingPeriodEndingDate: Date; SubscriptionStartingDate: Date; SubscriptionEndingDate: Date; Quantity: Decimal; UnitPriceFromImport: Boolean) + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin UsageBasedBTestLibrary.CreateUsageDataSupplier(UsageDataSupplier, Enum::"Usage Data Supplier Type"::Generic, UnitPriceFromImport, Enum::"Vendor Invoice Per"::Import); UsageBasedBTestLibrary.CreateGenericImportSettings(GenericImportSettings, UsageDataSupplier."No.", true, true); @@ -2245,8 +2334,10 @@ codeunit 148153 "Usage Based Billing Test" end; local procedure TestIfRelatedUsageDataBillingIsUpdated(ServicePartner: Enum "Service Partner"; UsageBasedBillingDocType: Enum "Usage Based Billing Doc. Type"; DocumentNo: Code[20]; TestNotEmptyDocLineNo: Boolean; BillingLineNo: Integer) + var + UsageDataBilling: Record "Usage Data Billing"; begin - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", ServicePartner); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", ServicePartner); UsageDataBilling.FindSet(); repeat UsageDataBilling.TestField("Document Type", UsageBasedBillingDocType); @@ -2262,7 +2353,7 @@ codeunit 148153 "Usage Based Billing Test" until UsageDataBilling.Next() = 0 end; - local procedure TestUsageDataBilling() + local procedure TestUsageDataBilling(UsageDataGenericImport: Record "Usage Data Generic Import"; var UsageDataBilling: Record "Usage Data Billing") begin UsageDataBilling.TestField("Usage Data Import Entry No.", UsageDataGenericImport."Usage Data Import Entry No."); UsageDataBilling.TestField("Subscription Header No.", UsageDataGenericImport."Subscription Header No."); @@ -2285,6 +2376,8 @@ codeunit 148153 "Usage Based Billing Test" end; local procedure ValidateUsageDataGenericImportAvailability(UsageDataImportEntryNo: Integer; ExpectedServiceObjectAvailability: Enum "Service Object Availability"; ExpectedServiceObjectNo: Code[20]) + var + UsageDataGenericImport: Record "Usage Data Generic Import"; begin UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImportEntryNo); UsageDataGenericImport.FindFirst(); From 8af80ab5e92e2c20ce71b4af153d738b6995786b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Thu, 23 Oct 2025 15:24:11 +0200 Subject: [PATCH 2/9] Adressing feedback --- .../SubContractBillingPrintout.Codeunit.al | 10 +---- .../CreateUsageDataBilling.Codeunit.al | 4 +- .../Tables/UsageDataBilling.Table.al | 30 ++++++++++++++ .../Demo Data/.resources/USAGE-GENERIC-US.xml | 39 +++++++++++++++++++ .../CreateSubBillGenSett.Codeunit.al | 3 +- .../Subscription Billing/Demo Data/app.json | 3 ++ 6 files changed, 76 insertions(+), 13 deletions(-) create mode 100644 src/Apps/W1/Subscription Billing/Demo Data/.resources/USAGE-GENERIC-US.xml diff --git a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al index dbb7ec7953..216f501771 100644 --- a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/SubContractBillingPrintout.Codeunit.al @@ -8,7 +8,6 @@ codeunit 8064 "Sub. Contract Billing Printout" { procedure FillContractBillingDetailsBufferFromSalesInvoice(SalesInvoiceHeader: Record "Sales Invoice Header"; var TempJobLedgerEntryBuffer: Record "Job Ledger Entry"; var ColumnHeaders: array[5] of Text) var - ServiceContractSetup: Record "Subscription Contract Setup"; BillingLineArchive: Record "Billing Line Archive"; SalesInvoiceLine: Record "Sales Invoice Line"; CustomerContract: Record "Customer Subscription Contract"; @@ -24,8 +23,6 @@ codeunit 8064 "Sub. Contract Billing Printout" if SalesInvoiceHeader."Sub. Contract Detail Overview" = Enum::"Contract Detail Overview"::None then exit; - ServiceContractSetup.Get(); - SalesDocuments.MoveBillingLineToBillingLineArchiveForPostingPreview(SalesInvoiceHeader); SalesInvoiceLine.SetRange("Document No.", SalesInvoiceHeader."No."); @@ -51,12 +48,7 @@ codeunit 8064 "Sub. Contract Billing Printout" TempJobLedgerEntryBuffer."Document Date" := UsageDataBilling."Charge Start Date"; TempJobLedgerEntryBuffer."Posting Date" := UsageDataBilling."Charge End Date"; TempJobLedgerEntryBuffer.Quantity := UsageDataBilling.Quantity; - if (UsageDataBilling."Usage Base Pricing" = Enum::"Usage Based Pricing"::"Unit Cost Surcharge") and - (ServiceContractSetup."Invoice Detail Origin" = Enum::"Invoice Detail Origin"::"Product Name (default)") - then - TempJobLedgerEntryBuffer.Description := UsageDataBilling."Product Name" - else - TempJobLedgerEntryBuffer.Description := UsageDataBilling."Subscription Description"; + TempJobLedgerEntryBuffer.Description := UsageDataBilling.GetPrintoutDescription(); TempJobLedgerEntryBuffer."External Document No." := UsageDataBilling."Subscription Contract No."; TempJobLedgerEntryBuffer."Resource Group No." := SalesInvoiceHeader."Sell-to Customer No."; if SalesInvoiceHeader."Sub. Contract Detail Overview" = Enum::"Contract Detail Overview"::Complete then begin diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al index 8a732eec67..6e9d506350 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Codeunits/CreateUsageDataBilling.Codeunit.al @@ -68,7 +68,7 @@ codeunit 8023 "Create Usage Data Billing" end; local procedure CreateUsageDataBillingFromTempServiceCommitment( - var TempServiceCommitment: Record "Subscription Line"; SupplierNo: Code[20]; UsageDataImportEntryNo: Integer; ServiceObjectNo: Code[20]; ProductID: Text[80]; ProductName: Text[100]; + var TempServiceCommitment: Record "Subscription Line"; SupplierNo: Code[20]; UsageDataImportEntryNo: Integer; SubscriptionNo: Code[20]; ProductID: Text[80]; ProductName: Text[100]; BillingPeriodStartDate: Date; BillingPeriodEndDate: Date; UnitCost: Decimal; NewQuantity: Decimal; CostAmount: Decimal; UnitPrice: Decimal; NewAmount: Decimal; CurrencyCode: Code[10]) var UsageDataBilling: Record "Usage Data Billing"; @@ -76,7 +76,7 @@ codeunit 8023 "Create Usage Data Billing" begin UsageDataSupplier.Get(SupplierNo); - UsageDataBilling.InitFrom(UsageDataImportEntryNo, ServiceObjectNo, ProductID, ProductName, BillingPeriodStartDate, BillingPeriodEndDate, UnitCost, NewQuantity, CostAmount, UnitPrice, NewAmount, CurrencyCode); + UsageDataBilling.InitFrom(UsageDataImportEntryNo, SubscriptionNo, ProductID, ProductName, BillingPeriodStartDate, BillingPeriodEndDate, UnitCost, NewQuantity, CostAmount, UnitPrice, NewAmount, CurrencyCode); UsageDataBilling."Supplier No." := SupplierNo; UsageDataBilling."Subscription Header No." := TempServiceCommitment."Subscription Header No."; UsageDataBilling.Partner := TempServiceCommitment.Partner; diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al index 7e4c9b3df3..5b6856b2de 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al @@ -706,11 +706,41 @@ table 8006 "Usage Data Billing" exit((Rec."Document Type" <> "Usage Based Billing Doc. Type"::None) and (Rec."Document No." <> '')); end; + internal procedure GetPrintoutDescription() Description: Text[100] + begin + if ShouldPrintProductName() then + Description := "Product Name" + else + Description := "Subscription Description"; + OnAfterGetPrintoutDescription(Rec, Description); + end; + + internal procedure ShouldPrintProductName() Result: Boolean + var + ServiceContractSetup: Record "Subscription Contract Setup"; + begin + ServiceContractSetup.Get(); + Result := + ("Usage Base Pricing" = Enum::"Usage Based Pricing"::"Unit Cost Surcharge") and + (ServiceContractSetup."Invoice Detail Origin" = Enum::"Invoice Detail Origin"::"Product Name (default)"); + OnAfterShouldPrintProductName(Rec, Result); + end; + [IntegrationEvent(false, false)] local procedure OnAfterSaveDocumentValues(UsageDateBilling: Record "Usage Data Billing") begin end; + [IntegrationEvent(false, false)] + local procedure OnAfterGetPrintoutDescription(Rec: Record "Usage Data Billing"; var Description: Text[100]) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterShouldPrintProductName(Rec: Record "Usage Data Billing"; var Result: Boolean) + begin + end; + var UsageBasedDocTypeConv: Codeunit "Usage Based Doc. Type Conv."; } diff --git a/src/Apps/W1/Subscription Billing/Demo Data/.resources/USAGE-GENERIC-US.xml b/src/Apps/W1/Subscription Billing/Demo Data/.resources/USAGE-GENERIC-US.xml new file mode 100644 index 0000000000..935c91ab98 --- /dev/null +++ b/src/Apps/W1/Subscription Billing/Demo Data/.resources/USAGE-GENERIC-US.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al b/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al index d0f40b5364..12afb9e796 100644 --- a/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al @@ -37,7 +37,7 @@ codeunit 8115 "Create Sub. Bill. Gen. Sett." DataExchDef.Delete(true); TempBlob.CreateOutStream(XMLOutStream); - XMLOutStream.WriteText(UsageDataGenericUsTxt); + XMLOutStream.WriteText(NavApp.GetResourceAsText('USAGE-GENERIC-US.xml')); TempBlob.CreateInStream(XMLInStream); Xmlport.Import(Xmlport::"Imp / Exp Data Exch Def & Map", XMLInStream); Clear(TempBlob); @@ -45,5 +45,4 @@ codeunit 8115 "Create Sub. Bill. Gen. Sett." var UsageDataGenericUsTok: Label 'USAGE-GENERIC-US', Locked = true; - UsageDataGenericUsTxt: Label '', Locked = true; } \ No newline at end of file diff --git a/src/Apps/W1/Subscription Billing/Demo Data/app.json b/src/Apps/W1/Subscription Billing/Demo Data/app.json index 6fcbd6f961..b299534f09 100644 --- a/src/Apps/W1/Subscription Billing/Demo Data/app.json +++ b/src/Apps/W1/Subscription Billing/Demo Data/app.json @@ -42,5 +42,8 @@ }, "features": [ "TranslationFile" + ], + "resourceFolders": [ + ".resources" ] } From 3676ebb2d70e0e8169e56ed677f05f160783a0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Thu, 23 Oct 2025 15:47:13 +0200 Subject: [PATCH 3/9] XML read with UTF8 --- .../Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al b/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al index 12afb9e796..d4fd9b4937 100644 --- a/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Demo Data/Demo Data/2.Master Data/CreateSubBillGenSett.Codeunit.al @@ -37,7 +37,7 @@ codeunit 8115 "Create Sub. Bill. Gen. Sett." DataExchDef.Delete(true); TempBlob.CreateOutStream(XMLOutStream); - XMLOutStream.WriteText(NavApp.GetResourceAsText('USAGE-GENERIC-US.xml')); + XMLOutStream.WriteText(NavApp.GetResourceAsText('USAGE-GENERIC-US.xml', TextEncoding::UTF8)); TempBlob.CreateInStream(XMLInStream); Xmlport.Import(Xmlport::"Imp / Exp Data Exch Def & Map", XMLInStream); Clear(TempBlob); From 200e33d551d616b4ac173b33b80a1649fde3e3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Mon, 27 Oct 2025 10:33:41 +0100 Subject: [PATCH 4/9] renamed field "Invoice Detail Origin" to "Invoice Desc. (Surcharge)" --- .../App/Base/Pages/ServiceContractSetup.Page.al | 2 +- .../App/Base/Tables/SubscriptionContractSetup.Table.al | 4 ++-- .../App/Usage Based Billing/Tables/UsageDataBilling.Table.al | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al b/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al index bf4d2b00e1..96f38f5f73 100644 --- a/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al +++ b/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al @@ -116,7 +116,7 @@ page 8051 "Service Contract Setup" { Caption = 'Usage Data'; - field("Invoice Detail Origin"; Rec."Invoice Detail Origin") + field("Invoice Desc. (Surcharge)"; Rec."Invoice Desc. (Surcharge)") { ToolTip = 'Specifies the origin of the invoice details'' description for usage data to be charged as Unit Cost Surcharge.'; } diff --git a/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al b/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al index 7ad178aaa6..b119a400a2 100644 --- a/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Base/Tables/SubscriptionContractSetup.Table.al @@ -76,9 +76,9 @@ table 8051 "Subscription Contract Setup" Caption = 'Dimension Code for Customer Subscription Contract'; TableRelation = Dimension; } - field(30; "Invoice Detail Origin"; Enum "Invoice Detail Origin") + field(30; "Invoice Desc. (Surcharge)"; Enum "Invoice Detail Origin") { - Caption = 'Invoice Detail Origin'; + Caption = 'Invoice Description (Surcharge)'; } field(59; "Default Period Calculation"; enum "Period Calculation") { diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al index 5b6856b2de..eabe9786e4 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al @@ -722,7 +722,7 @@ table 8006 "Usage Data Billing" ServiceContractSetup.Get(); Result := ("Usage Base Pricing" = Enum::"Usage Based Pricing"::"Unit Cost Surcharge") and - (ServiceContractSetup."Invoice Detail Origin" = Enum::"Invoice Detail Origin"::"Product Name (default)"); + (ServiceContractSetup."Invoice Desc. (Surcharge)" = Enum::"Invoice Detail Origin"::"Product Name (default)"); OnAfterShouldPrintProductName(Rec, Result); end; From ceb4166031d4fb5546f8579a81632867eaec5f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Tue, 28 Oct 2025 17:46:21 +0100 Subject: [PATCH 5/9] moved Usage Data group to FasTab "Invoice Details" --- .../Base/Pages/ServiceContractSetup.Page.al | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al b/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al index 96f38f5f73..fcfcda38b4 100644 --- a/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al +++ b/src/Apps/W1/Subscription Billing/App/Base/Pages/ServiceContractSetup.Page.al @@ -82,6 +82,15 @@ page 8051 "Service Contract Setup" { ToolTip = 'Specifies which customer information (name) is transferred to collective invoices. This setting is applies for collective invoices only.'; } + group("Usage Data") + { + Caption = 'Usage Data'; + + field("Invoice Desc. (Surcharge)"; Rec."Invoice Desc. (Surcharge)") + { + ToolTip = 'Specifies the origin of the invoice details'' description for usage data to be charged as Unit Cost Surcharge.'; + } + } group(ArrangeTexts) { Caption = 'Arrange Texts'; @@ -112,15 +121,6 @@ page 8051 "Service Contract Setup" } } } - group("Usage Data") - { - Caption = 'Usage Data'; - - field("Invoice Desc. (Surcharge)"; Rec."Invoice Desc. (Surcharge)") - { - ToolTip = 'Specifies the origin of the invoice details'' description for usage data to be charged as Unit Cost Surcharge.'; - } - } group("Gen. Journal Templates") { Caption = 'Journal Templates'; From 582a60793ee5fc82281cf639c6cad9b122a6a15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Thu, 30 Oct 2025 13:43:23 +0100 Subject: [PATCH 6/9] [WHEN] in automated test --- .../Test/UBB/UsageBasedBillingTest.Codeunit.al | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al index dde4e55945..ed9621597a 100644 --- a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al @@ -221,13 +221,15 @@ codeunit 148153 "Usage Based Billing Test" // [GIVEN] Create Usage data and process it Initialize(); CreateUsageDataBilling("Usage Based Pricing"::"Unit Cost Surcharge", LibraryRandom.RandDec(10, 2)); + + // [WHEN] Process Usage Data Import PostDocument := false; UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); // [THEN] Test that Subscription Line Entry No and Product details are populated in Usage Data Billing + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); UsageDataGenericImport.SetRange("Usage Data Import Entry No.", UsageDataImport."Entry No."); UsageDataGenericImport.FindFirst(); UsageDataBilling.FindSet(); From 2ba50a7831b23e22e50b21cbbea0f26ac369029e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Tue, 11 Nov 2025 11:26:23 +0100 Subject: [PATCH 7/9] resolving conflicts --- .../Test/UBB/UsageBasedBillingTest.Codeunit.al | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al index 2022e15b0d..1566320ac1 100644 --- a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al @@ -1816,6 +1816,8 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] [Test] procedure DeleteUsageDataBillingLineWhenRelatedSalesCrMemoLineIsDeleted() + var + UsageDataBilling: Record "Usage Data Billing"; begin // [SCENARIO] Creating a corrective credit memo for a contract with two usage-based service commitments, deleting one line, and posting the memo should only create a new usage data billing line for the credited line. // [GIVEN] A customer contract with two usage-based service commitments, both invoiced @@ -1825,7 +1827,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); UsageDataBilling.FindSet(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); @@ -1840,7 +1842,7 @@ codeunit 148153 "Usage Based Billing Test" // Delete the first line (simulate user action) SalesLine.Delete(true); - // [THEN] Only the credited line should have a new usage data billing line + // [THEN] Only the credited line should have a new usage data billing line // Check usage data billing lines for the contract UsageDataBilling.Reset(); UsageDataBilling.SetRange("Document Type", UsageDataBilling."Document Type"::"Credit Memo"); @@ -1852,6 +1854,8 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateCustomerBillingDocumentPageHandler,MessageHandler')] [Test] procedure ResetUsageDataBillingWhenRelatedSalesInvoiceLineIsDeleted() + var + UsageDataBilling: Record "Usage Data Billing"; begin // [SCENARIO] When sales invoice with usage data is created if a line is deleted related usage data billing should be reset // [GIVEN] A customer contract with usage-based service commitments and a sales invoice created from usage data @@ -1861,7 +1865,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Invoice"); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Invoice"); UsageDataBilling.FindSet(); SalesLine.Reset(); @@ -1885,6 +1889,8 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,CreateVendorBillingDocumentPageHandler,MessageHandler')] [Test] procedure ResetUsageDataBillingWhenRelatedPurchLineIsDeleted() + var + UsageDataBilling: Record "Usage Data Billing"; begin // [SCENARIO] When purchase invoice with usage data is created if a line is deleted related usage data billing should be reset // [GIVEN] A vendor contract with usage-based service commitments and a purchase invoice created from usage data @@ -1893,7 +1899,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectVendorContractsAndCreateInvoices(UsageDataImport); - FilterUsageDataBillingOnUsageDataImport(UsageDataImport."Entry No.", "Service Partner"::Vendor, UsageDataBilling."Document Type"::Invoice); + FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Vendor, UsageDataBilling."Document Type"::Invoice); UsageDataBilling.FindSet(); PurchaseHeader.Get(PurchaseHeader."Document Type"::Invoice, UsageDataBilling."Document No."); @@ -1923,6 +1929,7 @@ codeunit 148153 "Usage Based Billing Test" var PurchCrMemoHeader: Record "Purchase Header"; PurchInvHeader: Record "Purch. Inv. Header"; + UsageDataBilling: Record "Usage Data Billing"; begin // [SCENARIO] Creating a corrective purchase credit memo for a contract with two usage-based service commitments, deleting one line, and posting the memo should only create a new usage data billing line for the credited line. // [GIVEN] A vendor contract with two usage-based service commitments, both invoiced @@ -1944,7 +1951,7 @@ codeunit 148153 "Usage Based Billing Test" // Delete the first line (simulate user action) PurchaseLine.Delete(true); - // [THEN] Only the credited line should have a new usage data billing line + // [THEN] Only the credited line should have a new usage data billing line // Check usage data billing lines for the contract UsageDataBilling.Reset(); UsageDataBilling.SetRange("Document Type", UsageDataBilling."Document Type"::"Credit Memo"); @@ -1958,6 +1965,7 @@ codeunit 148153 "Usage Based Billing Test" procedure TestBillingLineInUsageDataNoWhenBillingProposalIsCreated() var BillingProposal: Codeunit "Billing Proposal"; + UsageDataBilling: Record "Usage Data Billing"; begin //[SCENARIO] Create recurring billing for simple customer contract; Check if Usage Data Billing Line No. has billing line no From a145611ae74ed593fe0d3eef381cba042ec16b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Mon, 24 Nov 2025 16:49:37 +0100 Subject: [PATCH 8/9] Fix AppSource Cop issues --- .../UBB/UsageBasedBillingTest.Codeunit.al | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al index 1566320ac1..b6d60e41de 100644 --- a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al @@ -1018,7 +1018,7 @@ codeunit 148153 "Usage Based Billing Test" FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer); UsageDataBilling.CalcSums(Amount); CalculatedAmount := UsageDataBilling.Amount; - UsageDataBilling.FindFirst(); + Assert.RecordIsNotEmpty(UsageDataBilling); ProcessUsageDataBilling.SetRoundingPrecision(RoundingPrecision, CalculatedAmount, Currency); Assert.AreEqual(Round(ExpectedResult, RoundingPrecision), CalculatedAmount, 'Amount was not calculated properly in Usage data.'); @@ -1211,7 +1211,7 @@ codeunit 148153 "Usage Based Billing Test" //[GIVEN] Usage Data Billing for sales credit memo UsageDataBilling.FilterOnDocumentTypeAndDocumentNo("Service Partner"::Vendor, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", PurchaseHeader."No."); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); //[WHEN] Delete Purchase Credit Memo PurchaseHeader.Delete(true); @@ -1362,7 +1362,7 @@ codeunit 148153 "Usage Based Billing Test" Assert.RecordCount(UsageDataBilling, 2); // Expect additional usage data billing for credit memo UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", SalesCrMemoHeader."No."); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); end; [Test] @@ -1387,7 +1387,7 @@ codeunit 148153 "Usage Based Billing Test" Assert.RecordCount(UsageDataBilling, 2); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Vendor, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", PurchaseHeader."No."); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); end; [Test] @@ -1412,7 +1412,7 @@ codeunit 148153 "Usage Based Billing Test" Assert.RecordCount(UsageDataBilling, 2); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", SalesCrMemoHeader."No."); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); end; [Test] @@ -1438,10 +1438,10 @@ codeunit 148153 "Usage Based Billing Test" Assert.RecordCount(UsageDataBilling, 3); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Posted Credit Memo", CorrectedDocumentNo); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::None, ''); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); end; [Test] @@ -1469,10 +1469,10 @@ codeunit 148153 "Usage Based Billing Test" Assert.RecordCount(UsageDataBilling, 3); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Vendor, Enum::"Usage Based Billing Doc. Type"::"Posted Credit Memo", CorrectedDocumentNo); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Vendor, Enum::"Usage Based Billing Doc. Type"::None, ''); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); end; [Test] @@ -1516,10 +1516,10 @@ codeunit 148153 "Usage Based Billing Test" Assert.RecordCount(UsageDataBilling, 3); // Expect additional usage data billing for credit memo and one without document type and document no UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Posted Credit Memo", CorrectedDocumentNo); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); UsageDataBilling.FilterOnDocumentTypeAndDocumentNo(Enum::"Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::None, ''); - UsageDataBilling.FindSet(); + Assert.RecordIsNotEmpty(UsageDataBilling); end; [Test] From 4f3aa0cf59399b1776008d2b5bd1c461951d8616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miljan=20Milosavljevi=C4=87?= Date: Tue, 25 Nov 2025 14:19:00 +0100 Subject: [PATCH 9/9] Fix Source Cop issues --- .../UBB/UsageBasedBillingTest.Codeunit.al | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al index b6d60e41de..0d7587fe3a 100644 --- a/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/UBB/UsageBasedBillingTest.Codeunit.al @@ -944,7 +944,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.ProcessUsageDataImport(UsageDataImport, Enum::"Processing Step"::"Process Usage Data Billing"); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No."); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); ProcessUsageDataBilling.SetRoundingPrecision(RoundingPrecision, UsageDataBilling."Unit Price", Currency); Assert.AreEqual(Round(ServiceCommitment.Price, RoundingPrecision), UsageDataBilling."Unit Price", 'Amount was not calculated properly in Usage data.'); end; @@ -1283,7 +1283,7 @@ codeunit 148153 "Usage Based Billing Test" //[GIVEN] Create sales invoice from Usage Data Import UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); //[GIVEN] Create sales credit memo from sales invoice @@ -1291,7 +1291,7 @@ codeunit 148153 "Usage Based Billing Test" //[GIVEN] Usage Data Billing for sales credit memo UsageDataBilling.FilterOnDocumentTypeAndDocumentNo("Service Partner"::Customer, Enum::"Usage Based Billing Doc. Type"::"Credit Memo", SalesCrMemoHeader."No."); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); //[WHEN] Delete sales credit memo SalesCrMemoHeader.Delete(true); @@ -1354,7 +1354,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); @@ -1404,7 +1404,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); @@ -1428,7 +1428,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); @@ -1506,7 +1506,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); @@ -1828,7 +1828,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Posted Invoice"); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); SalesInvoiceHeader.Get(UsageDataBilling."Document No."); CorrectPostedSalesInvoice.CreateCreditMemoCopyDocument(SalesInvoiceHeader, SalesCrMemoHeader); @@ -1866,7 +1866,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectCustomerContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Customer, UsageDataBilling."Document Type"::"Invoice"); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); SalesLine.Reset(); SalesLine.SetRange("Document Type", "Sales Document Type"::Invoice); @@ -1900,7 +1900,7 @@ codeunit 148153 "Usage Based Billing Test" UsageDataImport.TestField("Processing Status", "Processing Status"::Ok); UsageDataImport.CollectVendorContractsAndCreateInvoices(UsageDataImport); FilterUsageDataBillingOnUsageDataImport(UsageDataBilling, UsageDataImport."Entry No.", "Service Partner"::Vendor, UsageDataBilling."Document Type"::Invoice); - UsageDataBilling.FindSet(); + UsageDataBilling.FindFirst(); PurchaseHeader.Get(PurchaseHeader."Document Type"::Invoice, UsageDataBilling."Document No."); @@ -1964,8 +1964,8 @@ codeunit 148153 "Usage Based Billing Test" [HandlerFunctions('ExchangeRateSelectionModalPageHandler,MessageHandler,StrMenuHandlerClearBillingProposal')] procedure TestBillingLineInUsageDataNoWhenBillingProposalIsCreated() var - BillingProposal: Codeunit "Billing Proposal"; UsageDataBilling: Record "Usage Data Billing"; + BillingProposal: Codeunit "Billing Proposal"; begin //[SCENARIO] Create recurring billing for simple customer contract; Check if Usage Data Billing Line No. has billing line no