Skip to content

[Bug][Subscription Billing] "Cancellation Possible Until" is rounded to the end of the month when the Notice Period is expressed in days #10354

Description

Describe the issue

When the Notice Period on a subscription line is expressed in days rather than months — for example 60D — and the term ends on the last day of a month, the resulting "Cancellation Possible Until" date is not the notice period before the term end. It is pushed forward to the end of the month, silently shortening the notice period by up to a month.

Example: initial term 12M, start 01.01.2026, notice period 60D. "Term Until" is calculated correctly as 31.12.2026, but "Cancellation Possible Until" shows 30.11.2026 instead of 01.11.2026 — 30 days of notice instead of the agreed 60.

Because the field is the date the system and the users rely on to decide whether a cancellation is still in time, a contract can be cancelled far later than the contract terms allow, and the wrong date is what appears on cancellation overviews.

Affected objects:

  • src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al
  • src/Apps/W1/Subscription Billing/App/Base/Codeunits/DateTimeManagement.Codeunit.al
  • src/Apps/W1/Subscription Billing/App/Base/Codeunits/DateFormulaManagement.Codeunit.al

Expected behavior

"Cancellation Possible Until" must equal the Term Until date minus the notice period as literally entered. With Term Until 31.12.2026 and Notice Period 60D the value must be 01.11.2026, not 30.11.2026. Month-end alignment must only apply when the notice period itself is expressed in whole months, quarters or years.

Root cause

SubscriptionLine.Table.al, CalculateCancellationPossibleUntil:

internal procedure CalculateCancellationPossibleUntil(): Boolean
begin
    if IsNoticePeriodEmpty() or ("Term until" = 0D) then
        exit(false);
    CalendarManagement.ReverseDateFormula(NegativeDateFormula, "Notice Period");
    "Cancellation Possible Until" := CalcDate(NegativeDateFormula, "Term Until");
    if DateTimeManagement.IsLastDayOfMonth("Term until") then
        DateTimeManagement.MoveDateToLastDayOfMonth("Cancellation possible until");
    exit(true);
end;

The subtraction itself is right — 31.12.2026 minus 60 days is 01.11.2026. The IsLastDayOfMonth / MoveDateToLastDayOfMonth pair then unconditionally snaps the result to the last day of its month, producing 30.11.2026.

That alignment is sensible for month-based notice periods, where it compensates for months of different length and is a no-op for a correct result anyway. For a day-based notice period the exact day count is the whole point, so the alignment corrupts it.

The inverse procedure CalculateTermUntilFromCancellationPossibleUntil in the same table carries the identical unconditional alignment and has the same defect when the user types a cancellation date directly.

Proposed fix

Guard both alignments on the type of the notice period date formula. DateFormulaManagement.FindDateFormulaTypeForComparison already returns a "Date Formula Type" enum (Day, Week, Month, Quarter, Year, …); apply MoveDateToLastDayOfMonth only for Month, Quarter and Year, and skip it for Day and Week.

Steps to reproduce

  1. Create a customer subscription contract and add a subscription line.
  2. On the subscription line set Subscription Line Start Date to 01.01.2026.
  3. Set Initial Term to 12M and Subsequent Term to 12M.
  4. Set Notice Period to 60D.
  5. Look at the calculated dates on the line:
    • Term Until = 31.12.2026 — correct.
    • Cancellation Possible Until = 30.11.2026 — wrong; 60 days before 31.12.2026 is 01.11.2026.

Control case showing the calculation is correct when the term does not end on a month end:

  1. On another line set Subscription Line Start Date 17.01.2026, Initial Term 12M, Notice Period 20D.
  2. Term Until = 16.01.2027 and Cancellation Possible Until = 27.12.2026 — exactly 20 days, because the month-end alignment does not trigger here.

Additional context

The month-end alignment is applied whenever Term Until happens to be the last day of a month, so the size of the error varies with the notice period: with 60D on a 31.12 term end the customer loses 29 days of notice.

I will provide a fix for a bug

  • I will provide a fix for a bug

Metadata

Metadata

Assignees

No one assigned

    Labels

    FinanceGitHub request for Finance area

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions