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
- Create a customer subscription contract and add a subscription line.
- On the subscription line set Subscription Line Start Date to 01.01.2026.
- Set Initial Term to
12M and Subsequent Term to 12M.
- Set Notice Period to
60D.
- 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:
- On another line set Subscription Line Start Date 17.01.2026, Initial Term
12M, Notice Period 20D.
- 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
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:
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:The subtraction itself is right — 31.12.2026 minus 60 days is 01.11.2026. The
IsLastDayOfMonth/MoveDateToLastDayOfMonthpair 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
CalculateTermUntilFromCancellationPossibleUntilin 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.FindDateFormulaTypeForComparisonalready returns a"Date Formula Type"enum (Day, Week, Month, Quarter, Year, …); applyMoveDateToLastDayOfMonthonly for Month, Quarter and Year, and skip it for Day and Week.Steps to reproduce
12Mand Subsequent Term to12M.60D.Control case showing the calculation is correct when the term does not end on a month end:
12M, Notice Period20D.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