Skip to content

[Bug]: [SubscriptionBilling]: Infinite loop in CalculateBillingPeriod when Harmonized Billing contract has a stale "Next Billing To" date #8374

@ngaspare

Description

@ngaspare

Describe the issue

When a Customer Subscription Contract has Harmonized Billing enabled and the "Next Billing To" date is stale (older than the
current billing period), running "Create Billing Proposal" on the Recurring Billing page (Page 8067) causes an infinite loop.
The process never completes and holds an Exclusive lock on the Customer Subscription Contract table indefinitely.

Root cause

In Codeunit 8062 "Billing Proposal", method CalculateBillingPeriod contains a while loop:

while (BillingPeriodEnd < BillingDate) and (...)
do
    BillingPeriodEnd := CalculateNextBillingToDateForServiceCommitment(
        ServiceCommitment, BillingPeriodEnd + 1);

Inside CalculateNextBillingToDateForServiceCommitment, when Harmonized Billing is enabled, HarmonizeNextBillingTo caps
NextBillingToDate to CustomerContract."Next Billing To":

if NextBillingToDate < CustomerContractNextBillingTo then exit;
NextBillingToDate := CustomerContractNextBillingTo; // caps backwards

When CustomerContract."Next Billing To" is a stale past date (e.g. 1/31/2026) and BillingDate is 5/28/2026:

  • Every iteration calculates a natural NextBillingToDate (2/28, 3/31, ...)
  • HarmonizeNextBillingTo caps it back to 1/31/2026
  • BillingPeriodEnd never advances → infinite loop

Verified via AL Debugger: BillingPeriodEnd = 01/31/2026 on every consecutive iteration, never changes.

Suggested fix (one possible approach)

In CalculateNextBillingToDateForServiceCommitment, skip harmonization
when "Next Billing To" is older than BillingFromDate:

if ServiceCommitment.IsPartnerCustomer() then begin
    CustomerContract.Get(ServiceCommitment."Subscription Contract No.");
    if CustomerContract.IsContractTypeSetAsHarmonizedBilling() then
        if CustomerContract."Next Billing To" >= BillingFromDate then
            HarmonizeNextBillingTo(CustomerContract."Next Billing To", NextBillingToDate);
end;

Note: This is a proposed direction. The correct fix may need to consider
harmonization behavior in catch-up scenarios.

Expected behavior

Billing proposal is created successfully even when billing is behind by more than one period.

Steps to reproduce

  1. Create a Customer Subscription Contract with Harmonized Billing enabled (set Billing Base Date, Default Billing Rhythm: 1M)
  2. Add subscription lines with Billing Rhythm: 1M and Next Billing Date more than one month in the past
  3. Ensure "Next Billing To" on the contract is in the past (this happens when invoices were never posted after a previous
    billing proposal, or when billing is skipped for one or more periods)
  4. Open Recurring Billing (Page 8067), set Billing Date to today, click "Create Billing Proposal"

Result: Process runs indefinitely
Expected: Billing proposal created successfully

When does this happen in production?

  • Billing proposal created but invoices never posted (proposal cleared)
  • Billing skipped for one or more periods
  • Initial setup where billing has never been run

Note: Annual (12M) contracts are not affected because CalculateNextToDate(12M, 1/1/2026) = 12/31/2026 already exceeds
any reasonable BillingDate, so the while loop never executes.

Version

Subscription Billing by Microsoft, version 28.0.46665.48632
Business Central SaaS Sandbox

Additional context

AL Debugger confirms BillingPeriodEnd is identical on consecutive iterations:

  • Iteration 1: BillingPeriodEnd = 01/31/2026, BillingFromDate = 02/01/2026
  • Iteration 2: BillingPeriodEnd = 01/31/2026, BillingFromDate = 02/01/2026

CustomerContract."Next Billing To" = 01/31/2026 (stale)
BillingDate = 05/28/2026

Database Locks page confirms Exclusive lock held on Customer Subscription Contract
for the entire duration with session never completing.

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

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions