Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1946,9 +1946,13 @@ table 8059 "Subscription Line"
LastDateInLastMonth := CalcDate(PeriodFormula, FromDate);
LastDateInLastMonth := CalcDate('<CM>', LastDateInLastMonth);
NextToDate := LastDateInLastMonth - DistanceToEndOfMonth - 1;
if NextToDate < FromDate then
NextToDate := CalcDate(PeriodFormula, FromDate) - 1;
end;
end;
end;
if NextToDate < FromDate then
NextToDate := FromDate;
end;

local procedure GetBillingReferenceDate() BillingReferenceDate: Date
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ codeunit 139687 "Recurring Billing Docs Test"
LibraryUtility: Codeunit "Library - Utility";
LibraryVariableStorage: Codeunit "Library - Variable Storage";
IsInitialized: Boolean;
NextToDateBeforeFromDateErr: Label 'CalculateNextToDate returned %1 which is before FromDate %2. This would cause billing to get stuck.', Locked = true;
NoContractLinesFoundErr: Label 'No contract lines were found that can be billed with the specified parameters.', Locked = true;
StrMenuHandlerStep: Integer;

Expand Down Expand Up @@ -2452,6 +2453,90 @@ codeunit 139687 "Recurring Billing Docs Test"
CatalogItem.TestField("Subscription Option", "Item Service Commitment Type"::"Service Commitment Item");
end;

[Test]
procedure CalculateNextToDateAlignEndOfMonthDoesNotReturnDateBeforeFromDate()
var
SubscriptionLine: Record "Subscription Line";
PeriodFormula: DateFormula;
FromDate: Date;
NextToDate: Date;
begin
// [FEATURE] [AI test]
// [SCENARIO 623011] CalculateNextToDate with "Align to End of Month" does not return date before FromDate
Initialize();

// [GIVEN] Subscription Line "SL" with Period Calculation = "Align to End of Month" and start date Jan 29
MockSubscriptionLine(SubscriptionLine);
SubscriptionLine.Validate("Period Calculation", SubscriptionLine."Period Calculation"::"Align to End of Month");
SubscriptionLine.Validate("Subscription Line Start Date", DMY2Date(29, 1, 2025));
SubscriptionLine.Modify();

// [WHEN] CalculateNextToDate is called with period formula <1D> from Feb 27
Evaluate(PeriodFormula, '<1D>');
FromDate := DMY2Date(27, 2, 2025);
NextToDate := SubscriptionLine.CalculateNextToDate(PeriodFormula, FromDate);

// [THEN] NextToDate is not before FromDate
Assert.IsTrue(NextToDate >= FromDate,
StrSubstNo(NextToDateBeforeFromDateErr, NextToDate, FromDate));
end;

[Test]
procedure CalculateNextToDateZeroDayFormulaReturnsFromDate()
var
SubscriptionLine: Record "Subscription Line";
PeriodFormula: DateFormula;
FromDate: Date;
NextToDate: Date;
begin
// [FEATURE] [AI test]
// [SCENARIO 623011] CalculateNextToDate with <0D> formula returns exactly FromDate (boundary case)
Initialize();

// [GIVEN] Subscription Line "SL" with Period Calculation = "Align to End of Month" and start date Jan 31
MockSubscriptionLine(SubscriptionLine);
SubscriptionLine.Validate("Period Calculation", SubscriptionLine."Period Calculation"::"Align to End of Month");
SubscriptionLine.Validate("Subscription Line Start Date", DMY2Date(31, 1, 2025));
SubscriptionLine.Modify();

// [WHEN] CalculateNextToDate is called with period formula <0D> from Feb 28
Evaluate(PeriodFormula, '<0D>');
FromDate := DMY2Date(28, 2, 2025);
NextToDate := SubscriptionLine.CalculateNextToDate(PeriodFormula, FromDate);

// [THEN] NextToDate is not before FromDate (should be exactly FromDate or later)
Assert.IsTrue(NextToDate >= FromDate,
StrSubstNo(NextToDateBeforeFromDateErr, NextToDate, FromDate));
end;

[Test]
procedure CalculateNextToDateMonthFormulaLeapYearDoesNotReturnDateBeforeFromDate()
var
SubscriptionLine: Record "Subscription Line";
PeriodFormula: DateFormula;
FromDate: Date;
NextToDate: Date;
begin
// [FEATURE] [AI test]
// [SCENARIO 623011] CalculateNextToDate with monthly formula and leap year Feb 29 to Mar transition does not return date before FromDate
Initialize();

// [GIVEN] Subscription Line "SL" with Period Calculation = "Align to End of Month" and start date Jan 30 (leap year 2024)
MockSubscriptionLine(SubscriptionLine);
SubscriptionLine.Validate("Period Calculation", SubscriptionLine."Period Calculation"::"Align to End of Month");
SubscriptionLine.Validate("Subscription Line Start Date", DMY2Date(30, 1, 2024));
SubscriptionLine.Modify();

// [WHEN] CalculateNextToDate is called with period formula <1M> from Feb 29 (leap year)
Evaluate(PeriodFormula, '<1M>');
FromDate := DMY2Date(29, 2, 2024);
NextToDate := SubscriptionLine.CalculateNextToDate(PeriodFormula, FromDate);

// [THEN] NextToDate is not before FromDate
Assert.IsTrue(NextToDate >= FromDate,
StrSubstNo(NextToDateBeforeFromDateErr, NextToDate, FromDate));
end;

#endregion Tests

#region Procedures
Expand Down Expand Up @@ -2539,7 +2624,10 @@ codeunit 139687 "Recurring Billing Docs Test"
until BillingLine.Next() = 0;
end;

local procedure CountBillingArchiveLinesOnDocument(DocumentType: Enum "Rec. Billing Document Type"; DocumentNo: Code[20]; ServicePartner: Enum "Service Partner"; ContractNo: Code[20]; ContractLineNo: Integer): Integer
local procedure CountBillingArchiveLinesOnDocument(DocumentType: Enum "Rec. Billing Document Type"; DocumentNo: Code[20];
ServicePartner: Enum "Service Partner";
ContractNo: Code[20];
ContractLineNo: Integer): Integer
var
BillingArchiveLine: Record "Billing Line Archive";
begin
Expand Down Expand Up @@ -2622,14 +2710,16 @@ codeunit 139687 "Recurring Billing Docs Test"
SalesHeader.DeleteAll();
end;

local procedure FilterPurchaseLineOnDocumentLine(PurchaseDocumentType: Enum "Purchase Document Type"; DocumentNo: Code[20]; LineNo: Integer)
local procedure FilterPurchaseLineOnDocumentLine(PurchaseDocumentType: Enum "Purchase Document Type"; DocumentNo: Code[20];
LineNo: Integer)
begin
PurchaseLine.SetRange("Document Type", PurchaseDocumentType);
PurchaseLine.SetRange("Document No.", DocumentNo);
PurchaseLine.SetRange("Line No.", LineNo);
end;

local procedure FilterSalesLineOnDocumentLine(SalesDocumentType: Enum "Sales Document Type"; DocumentNo: Code[20]; LineNo: Integer)
local procedure FilterSalesLineOnDocumentLine(SalesDocumentType: Enum "Sales Document Type"; DocumentNo: Code[20];
LineNo: Integer)
begin
SalesLine.SetRange("Document Type", SalesDocumentType);
SalesLine.SetRange("Document No.", DocumentNo);
Expand Down Expand Up @@ -2925,6 +3015,17 @@ codeunit 139687 "Recurring Billing Docs Test"
end;
end;

local procedure MockSubscriptionLine(var SubscriptionLine: Record "Subscription Line")
var
ServiceCommitmentPackage: Record "Subscription Package";
begin
ContractTestLibrary.CreateServiceCommitmentPackage(ServiceCommitmentPackage);
SubscriptionLine.Init();
SubscriptionLine."Invoicing via" := SubscriptionLine."Invoicing via"::Contract;
SubscriptionLine."Subscription Package Code" := ServiceCommitmentPackage.Code;
SubscriptionLine.Insert(true);
end;

#endregion Procedures

#region Handlers
Expand Down
Loading