From 81e40ac0ad7c35eca54f39cf53bb9298ee9df97d Mon Sep 17 00:00:00 2001 From: v-nesinghal Date: Thu, 26 Mar 2026 14:20:20 +0545 Subject: [PATCH 1/9] 623011 fix and automation --- .../Tables/SubscriptionLine.Table.al | 2 + .../RecurringBillingDocsTest.Codeunit.al | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al index dd0be51524..541b482c7a 100644 --- a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al @@ -1946,6 +1946,8 @@ table 8059 "Subscription Line" LastDateInLastMonth := CalcDate(PeriodFormula, FromDate); LastDateInLastMonth := CalcDate('', LastDateInLastMonth); NextToDate := LastDateInLastMonth - DistanceToEndOfMonth - 1; + if NextToDate < FromDate then + NextToDate := CalcDate(PeriodFormula, FromDate) - 1; end; end; end; diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index 969753674b..5a60aa828b 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -65,8 +65,10 @@ codeunit 139687 "Recurring Billing Docs Test" LibrarySetupStorage: Codeunit "Library - Setup Storage"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; LibraryUtility: Codeunit "Library - Utility"; + LibraryLowerPermissions: Codeunit "Library - Lower Permissions"; 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; @@ -2452,6 +2454,35 @@ 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 0.3] + // [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."Period Calculation" := SubscriptionLine."Period Calculation"::"Align to End of Month"; + SubscriptionLine."Subscription Line Start Date" := DMY2Date(29, 1, 2025); + SubscriptionLine.Modify(false); + + // [WHEN] CalculateNextToDate is called with period formula <1D> from Feb 27 + Evaluate(PeriodFormula, '<1D>'); + FromDate := DMY2Date(27, 2, 2025); + LibraryLowerPermissions.SetO365Full(); + NextToDate := SubscriptionLine.CalculateNextToDate(PeriodFormula, FromDate); + + // [THEN] NextToDate is not before FromDate + Assert.IsTrue(NextToDate >= FromDate, + StrSubstNo(NextToDateBeforeFromDateErr, NextToDate, FromDate)); + end; + #endregion Tests #region Procedures @@ -2925,6 +2956,14 @@ codeunit 139687 "Recurring Billing Docs Test" end; end; + local procedure MockSubscriptionLine(var SubscriptionLine: Record "Subscription Line") + begin + SubscriptionLine.Init(); + SubscriptionLine."Entry No." := 0; + SubscriptionLine."Invoicing via" := SubscriptionLine."Invoicing via"::Contract; + SubscriptionLine.Insert(false); + end; + #endregion Procedures #region Handlers From 23e809447b705125bfda4bb0d2fe3da96b164a17 Mon Sep 17 00:00:00 2001 From: neeleshsinghal Date: Fri, 27 Mar 2026 15:12:24 +0545 Subject: [PATCH 2/9] Update src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Test/Billing/RecurringBillingDocsTest.Codeunit.al | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index 5a60aa828b..58494efc67 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -2477,6 +2477,7 @@ codeunit 139687 "Recurring Billing Docs Test" FromDate := DMY2Date(27, 2, 2025); LibraryLowerPermissions.SetO365Full(); NextToDate := SubscriptionLine.CalculateNextToDate(PeriodFormula, FromDate); + LibraryLowerPermissions.RestoreO365Permissions(); // [THEN] NextToDate is not before FromDate Assert.IsTrue(NextToDate >= FromDate, From 73de5ff7dd2353ea27ef52fff9fc2a83f4f482b0 Mon Sep 17 00:00:00 2001 From: neeleshsinghal Date: Fri, 27 Mar 2026 15:13:16 +0545 Subject: [PATCH 3/9] Update src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Test/Billing/RecurringBillingDocsTest.Codeunit.al | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index 58494efc67..228d4fb2a2 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -2960,9 +2960,8 @@ codeunit 139687 "Recurring Billing Docs Test" local procedure MockSubscriptionLine(var SubscriptionLine: Record "Subscription Line") begin SubscriptionLine.Init(); - SubscriptionLine."Entry No." := 0; SubscriptionLine."Invoicing via" := SubscriptionLine."Invoicing via"::Contract; - SubscriptionLine.Insert(false); + SubscriptionLine.Insert(true); end; #endregion Procedures From 077a0e0f29a7306323abc1d4f050ed29ceae8055 Mon Sep 17 00:00:00 2001 From: neeleshsinghal Date: Fri, 27 Mar 2026 15:13:41 +0545 Subject: [PATCH 4/9] Update src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Test/Billing/RecurringBillingDocsTest.Codeunit.al | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index 228d4fb2a2..695e7daa65 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -2468,9 +2468,9 @@ codeunit 139687 "Recurring Billing Docs Test" // [GIVEN] Subscription Line "SL" with Period Calculation = "Align to End of Month" and start date Jan 29 MockSubscriptionLine(SubscriptionLine); - SubscriptionLine."Period Calculation" := SubscriptionLine."Period Calculation"::"Align to End of Month"; - SubscriptionLine."Subscription Line Start Date" := DMY2Date(29, 1, 2025); - SubscriptionLine.Modify(false); + 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>'); From 8e4e140d68a813f5d1c3d368df6609ae95a3fd56 Mon Sep 17 00:00:00 2001 From: neeleshsinghal Date: Fri, 27 Mar 2026 15:49:34 +0545 Subject: [PATCH 5/9] Update src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Test/Billing/RecurringBillingDocsTest.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index 695e7daa65..d56e2522b2 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -2470,7 +2470,7 @@ codeunit 139687 "Recurring Billing Docs Test" 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(); + SubscriptionLine.Modify(true); // [WHEN] CalculateNextToDate is called with period formula <1D> from Feb 27 Evaluate(PeriodFormula, '<1D>'); From 5d5365db08bf0872b6b55c81306db6c7155a6ec2 Mon Sep 17 00:00:00 2001 From: neeleshsinghal Date: Fri, 27 Mar 2026 15:49:47 +0545 Subject: [PATCH 6/9] Update src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Test/Billing/RecurringBillingDocsTest.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index d56e2522b2..b03f0ebe3b 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -2960,7 +2960,7 @@ codeunit 139687 "Recurring Billing Docs Test" local procedure MockSubscriptionLine(var SubscriptionLine: Record "Subscription Line") begin SubscriptionLine.Init(); - SubscriptionLine."Invoicing via" := SubscriptionLine."Invoicing via"::Contract; + SubscriptionLine.Validate("Invoicing via", SubscriptionLine."Invoicing via"::Contract); SubscriptionLine.Insert(true); end; From d673f1ac138d9e40a1e1a42205e548f1068ee085 Mon Sep 17 00:00:00 2001 From: v-nesinghal Date: Sat, 28 Mar 2026 09:51:30 +0545 Subject: [PATCH 7/9] fixes --- .../Tables/SubscriptionLine.Table.al | 2 + .../RecurringBillingDocsTest.Codeunit.al | 69 +++++++++++++++++-- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al index 541b482c7a..30158e57fc 100644 --- a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al @@ -1951,6 +1951,8 @@ table 8059 "Subscription Line" end; end; end; + if NextToDate < FromDate then + NextToDate := FromDate; end; local procedure GetBillingReferenceDate() BillingReferenceDate: Date diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index b03f0ebe3b..24e5f3d225 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -65,7 +65,6 @@ codeunit 139687 "Recurring Billing Docs Test" LibrarySetupStorage: Codeunit "Library - Setup Storage"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; LibraryUtility: Codeunit "Library - Utility"; - LibraryLowerPermissions: Codeunit "Library - Lower Permissions"; 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; @@ -2462,7 +2461,7 @@ codeunit 139687 "Recurring Billing Docs Test" FromDate: Date; NextToDate: Date; begin - // [FEATURE] [AI test 0.3] + // [FEATURE] [AI test] // [SCENARIO 623011] CalculateNextToDate with "Align to End of Month" does not return date before FromDate Initialize(); @@ -2470,14 +2469,68 @@ codeunit 139687 "Recurring Billing Docs Test" 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(true); + SubscriptionLine.Modify(); // [WHEN] CalculateNextToDate is called with period formula <1D> from Feb 27 Evaluate(PeriodFormula, '<1D>'); FromDate := DMY2Date(27, 2, 2025); - LibraryLowerPermissions.SetO365Full(); NextToDate := SubscriptionLine.CalculateNextToDate(PeriodFormula, FromDate); - LibraryLowerPermissions.RestoreO365Permissions(); + + // [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, @@ -2958,9 +3011,13 @@ codeunit 139687 "Recurring Billing Docs Test" end; local procedure MockSubscriptionLine(var SubscriptionLine: Record "Subscription Line") + var + ServiceCommitmentPackage: Record "Subscription Package"; begin + ContractTestLibrary.CreateServiceCommitmentPackage(ServiceCommitmentPackage); SubscriptionLine.Init(); - SubscriptionLine.Validate("Invoicing via", SubscriptionLine."Invoicing via"::Contract); + SubscriptionLine."Invoicing via" := SubscriptionLine."Invoicing via"::Contract; + SubscriptionLine."Subscription Package Code" := ServiceCommitmentPackage.Code; SubscriptionLine.Insert(true); end; From 856028b2ff1a8946bd0967575210f122028134a5 Mon Sep 17 00:00:00 2001 From: v-nesinghal Date: Sat, 28 Mar 2026 10:06:31 +0545 Subject: [PATCH 8/9] validate --- .../Test/Billing/RecurringBillingDocsTest.Codeunit.al | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index 24e5f3d225..6308bae5f3 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -2469,7 +2469,7 @@ codeunit 139687 "Recurring Billing Docs Test" 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(); + SubscriptionLine.Modify(true); // [WHEN] CalculateNextToDate is called with period formula <1D> from Feb 27 Evaluate(PeriodFormula, '<1D>'); @@ -2497,7 +2497,7 @@ codeunit 139687 "Recurring Billing Docs Test" 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(); + SubscriptionLine.Modify(true); // [WHEN] CalculateNextToDate is called with period formula <0D> from Feb 28 Evaluate(PeriodFormula, '<0D>'); @@ -2525,7 +2525,7 @@ codeunit 139687 "Recurring Billing Docs Test" 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(); + SubscriptionLine.Modify(true); // [WHEN] CalculateNextToDate is called with period formula <1M> from Feb 29 (leap year) Evaluate(PeriodFormula, '<1M>'); From 07ab7b04f5d5fe2e360b700b46495291c7f6c4bf Mon Sep 17 00:00:00 2001 From: v-nesinghal Date: Sat, 28 Mar 2026 10:13:27 +0545 Subject: [PATCH 9/9] also add vallidate --- .../Test/Billing/RecurringBillingDocsTest.Codeunit.al | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al index 6308bae5f3..710849ca10 100644 --- a/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/Test/Billing/RecurringBillingDocsTest.Codeunit.al @@ -3016,8 +3016,8 @@ codeunit 139687 "Recurring Billing Docs Test" begin ContractTestLibrary.CreateServiceCommitmentPackage(ServiceCommitmentPackage); SubscriptionLine.Init(); - SubscriptionLine."Invoicing via" := SubscriptionLine."Invoicing via"::Contract; - SubscriptionLine."Subscription Package Code" := ServiceCommitmentPackage.Code; + SubscriptionLine.Validate("Invoicing via", SubscriptionLine."Invoicing via"::Contract); + SubscriptionLine.Validate("Subscription Package Code", ServiceCommitmentPackage.Code); SubscriptionLine.Insert(true); end;