Describe the issue
When a subscription line is priced per month but billed once a year — Billing Base Period 1M, Billing Rhythm 12M — the printed Contract Renewal Quote shows the wrong total. The subscription totals block at the bottom of the quote shows the monthly amount, not the amount for the 12-month renewal term the customer is actually being asked to sign.
For a line priced at 100 per month, renewed for 12 months and billed yearly, the quote reads 100 instead of 1,200. The amount the customer signs off on is nowhere on the document.
The problem is limited to lines where Billing Base Period and Billing Rhythm differ. When the two are equal — the common 1M/1M case — the total is correct, which is why this went unnoticed.
Affected objects:
- src/Apps/W1/Subscription Billing/App/Sales Service Commitments/Tables/SalesSubscriptionLine.Table.al
- src/Apps/W1/Subscription Billing/App/Service Commitments/Codeunits/SalesReportPrintoutMgmt.Codeunit.al
- src/Apps/W1/Subscription Billing/App/Sales Service Commitments/Report Extensions/ContractStandardSalesQuote.ReportExt.al
- src/Apps/W1/Subscription Billing/App/Base/Codeunits/DateFormulaManagement.Codeunit.al
Expected behavior
The subscription totals block on the Contract Renewal Quote should show the amount for the whole renewal term, scaled from the Billing Base Period to the Billing Rhythm and then to the renewal term. For Billing Base Period 1M, Billing Rhythm 12M and a 12M renewal term, a line priced at 100 must total 1,200.
Root cause
The totals block is built by SalesReportPrintoutMgmt.FillServiceCommitmentsGroups → SalesSubscriptionLine.CalcVATAmountLines → CreateTempSalesServiceCommitmentBuffForSalesServiceCommitment in SalesSubscriptionLine.Table.al. That procedure has two branches:
if SalesLineVAT.IsContractRenewal() then
TempSalesServiceCommitmentBuff."Line Amount" += SalesServiceCommitment.Amount * ContractRenewalPriceCalculationRatio
else
TempSalesServiceCommitmentBuff."Line Amount" += SalesServiceCommitment.Amount / BasePeriodCount * RhythmPeriodCount;
SalesServiceCommitment.Amount is the amount per Billing Base Period. The regular branch correctly converts it to the rhythm with / BasePeriodCount * RhythmPeriodCount. The contract-renewal branch does not — it only multiplies by ContractRenewalPriceCalculationRatio, which comes from DateFormulaManagement.CalculateRenewalTermRatioByBillingRhythm(AgreedStartDate, InitialTerm, BillingRhythm) and expresses how many billing rhythms fit into the renewal term, not the base-period-to-rhythm ratio.
With Renewal Term 12M and Billing Rhythm 12M that ratio is exactly 1, so the buffer receives the unscaled 1M amount and the printed total is the monthly value.
Proposed fix
Compute BasePeriodCount and RhythmPeriodCount via DateFormulaManagement.FindDateFormulaTypeForComparison in the contract-renewal branch as well, and apply both factors:
TempSalesServiceCommitmentBuff."Line Amount" +=
SalesServiceCommitment.Amount / BasePeriodCount * RhythmPeriodCount * ContractRenewalPriceCalculationRatio;
BasePeriodCount must be guarded against 0 for an empty Billing Base Period, in which case the amount is already the rhythm amount and only the renewal ratio applies.
Secondary observation for the same change: the per-line "Subscriptions*" detail rows are filled in SalesReportPrintoutMgmt.FillServiceCommitmentsForLine, which writes SalesSubscriptionLine.Price into "Unit Price" without any indication of the period it refers to. On a 1M/12M line the reader sees a monthly unit price next to a yearly total with nothing to explain the difference.
Steps to reproduce
- Create a new customer subscription contract for any customer.
- Add a subscription line ("article" line) to the contract.
- On the contract line, set Billing Base Period to
1M and Billing Rhythm to 12M. Leave a price of, say, 100.
- Set a Subscription Line End Date on the line so it becomes eligible for renewal.
- From the contract, run Create Contract Renewal and enter a Renewal Term of
12M.
- Open the created Sales Quote and choose Print/Send > Print > Preview.
- Look at the "Subscriptions (* Part of Subscription Billing)" totals block at the bottom of the quote: it shows 100 (the monthly amount) where it should show 1,200 (the amount for the 12-month renewal term).
Additional context
Setting Billing Base Period equal to Billing Rhythm (e.g. both 12M) produces the correct total, confirming that the missing base-period-to-rhythm conversion is the cause.
I will provide a fix for a bug
Describe the issue
When a subscription line is priced per month but billed once a year — Billing Base Period 1M, Billing Rhythm 12M — the printed Contract Renewal Quote shows the wrong total. The subscription totals block at the bottom of the quote shows the monthly amount, not the amount for the 12-month renewal term the customer is actually being asked to sign.
For a line priced at 100 per month, renewed for 12 months and billed yearly, the quote reads 100 instead of 1,200. The amount the customer signs off on is nowhere on the document.
The problem is limited to lines where Billing Base Period and Billing Rhythm differ. When the two are equal — the common 1M/1M case — the total is correct, which is why this went unnoticed.
Affected objects:
Expected behavior
The subscription totals block on the Contract Renewal Quote should show the amount for the whole renewal term, scaled from the Billing Base Period to the Billing Rhythm and then to the renewal term. For Billing Base Period 1M, Billing Rhythm 12M and a 12M renewal term, a line priced at 100 must total 1,200.
Root cause
The totals block is built by
SalesReportPrintoutMgmt.FillServiceCommitmentsGroups→SalesSubscriptionLine.CalcVATAmountLines→CreateTempSalesServiceCommitmentBuffForSalesServiceCommitmentinSalesSubscriptionLine.Table.al. That procedure has two branches:SalesServiceCommitment.Amountis the amount per Billing Base Period. The regular branch correctly converts it to the rhythm with/ BasePeriodCount * RhythmPeriodCount. The contract-renewal branch does not — it only multiplies byContractRenewalPriceCalculationRatio, which comes fromDateFormulaManagement.CalculateRenewalTermRatioByBillingRhythm(AgreedStartDate, InitialTerm, BillingRhythm)and expresses how many billing rhythms fit into the renewal term, not the base-period-to-rhythm ratio.With Renewal Term 12M and Billing Rhythm 12M that ratio is exactly 1, so the buffer receives the unscaled 1M amount and the printed total is the monthly value.
Proposed fix
Compute
BasePeriodCountandRhythmPeriodCountviaDateFormulaManagement.FindDateFormulaTypeForComparisonin the contract-renewal branch as well, and apply both factors:BasePeriodCountmust be guarded against 0 for an empty Billing Base Period, in which case the amount is already the rhythm amount and only the renewal ratio applies.Secondary observation for the same change: the per-line "Subscriptions*" detail rows are filled in
SalesReportPrintoutMgmt.FillServiceCommitmentsForLine, which writesSalesSubscriptionLine.Priceinto "Unit Price" without any indication of the period it refers to. On a 1M/12M line the reader sees a monthly unit price next to a yearly total with nothing to explain the difference.Steps to reproduce
1Mand Billing Rhythm to12M. Leave a price of, say, 100.12M.Additional context
Setting Billing Base Period equal to Billing Rhythm (e.g. both
12M) produces the correct total, confirming that the missing base-period-to-rhythm conversion is the cause.I will provide a fix for a bug