From b0777e98458b3826779e3774d2560319d776c65d Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Wed, 23 Sep 2026 14:21:57 +0530 Subject: [PATCH] fix(deposits): FD Single Rate Calculator sent tenureInMonths=0 for tenures under 30 days SYMPTOM FD Single account create screen, Rate Calculator: entering a tenure under 30 days (e.g. 27) and clicking "Find Rate" produced a Bad Request - "The parameter `tenureInMonths` must be greater than 0." ROOT CAUSE calculateRate() (fixed-deposit-account-interest-rate-chart-step. component.ts) always converted the Days-unit tenure to months before calling the backend calculator: tenureInMonths = Math.floor(enteredDays / 30) For any tenure under 30 days this floors to 0, which the backend correctly rejects (paired backend commit: "FD Single Rate Calculator crashed for tenures under 30 days"). FIX - fixed-deposits.service.ts: calculateFixedDepositInterest() - tenureInMonths is now optional, added optional tenureInDays. - fixed-deposit-account-interest-rate-chart-step.component.ts - calculateRate(): for a Days-unit tenure >= 30 days, unchanged (tenureInMonths = floor(days/30)); for < 30 days, sends tenureInDays instead and leaves tenureInMonths undefined. Also fixed the API-failure fallback's periodic-compounding math, which divided by tenureInMonths directly and would have produced NaN once tenureInMonths could legitimately be undefined - it now falls back to (enteredDays / 30) when tenureInMonths is absent. SCOPE Only the Rate Calculator preview inside the FD Single/Double/Special account create screen. Does not touch how depositPeriod / depositPeriodFrequencyId get sent on actual account submission. IF THIS BREAKS SOMETHING LATER - The same 400 reappearing for a short FD Single tenure -> confirm the Find Rate network call carries tenureInDays and NOT a zero tenureInMonths; check calculateRate()'s branch choosing between the two. - A wrong maturity preview number specifically when the backend API call fails and the frontend falls back to its own formula -> check the `effectiveMonths = tenureInMonths ?? enteredDays / 30` fallback line in calculateRate(). Co-Authored-By: Claude Sonnet 5 --- ...t-account-interest-rate-chart-step.component.ts | 14 ++++++++++---- .../fixed-deposits/fixed-deposits.service.ts | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/app/deposits/fixed-deposits/fixed-deposit-account-stepper/fixed-deposit-account-interest-rate-chart-step/fixed-deposit-account-interest-rate-chart-step.component.ts b/src/app/deposits/fixed-deposits/fixed-deposit-account-stepper/fixed-deposit-account-interest-rate-chart-step/fixed-deposit-account-interest-rate-chart-step.component.ts index beff3f51d..a8ebfa8de 100644 --- a/src/app/deposits/fixed-deposits/fixed-deposit-account-stepper/fixed-deposit-account-interest-rate-chart-step/fixed-deposit-account-interest-rate-chart-step.component.ts +++ b/src/app/deposits/fixed-deposits/fixed-deposit-account-stepper/fixed-deposit-account-interest-rate-chart-step/fixed-deposit-account-interest-rate-chart-step.component.ts @@ -334,14 +334,18 @@ export class FixedDepositAccountInterestRateChartStepComponent implements OnChan const frequencyId = this.resolveFrequencyId(this.tenurePeriodUnit); if (this.principalAmount && this.principalAmount > 0) { - // Convert tenure to months for backend API - let tenureInMonths = 0; + // Convert tenure to months for backend API. A Days tenure under 30 days rounds down to 0 + // months, which the backend rejects -- send it as tenureInDays instead in that case. + let tenureInMonths: number | undefined; + let tenureInDays: number | undefined; if (this.tenurePeriodUnit === 'Years') { tenureInMonths = this.tenureValue * 12; } else if (this.tenurePeriodUnit === 'Months') { tenureInMonths = this.tenureValue; - } else { + } else if (enteredDays >= 30) { tenureInMonths = Math.floor(enteredDays / 30); + } else { + tenureInDays = enteredDays; } // Map compounding period type id → months (0=Daily, 1=Daily, 4=Monthly, 5=Quarterly, 6=SemiAnnual, 7=Annual) @@ -395,6 +399,7 @@ export class FixedDepositAccountInterestRateChartStepComponent implements OnChan principalAmount: this.principalAmount, annualInterestRate: rate, tenureInMonths, + tenureInDays, interestCompoundingPeriodInMonths: compMonths, // 0 = daily, now supported by backend interestPostingPeriodInMonths: postMonths, submittedOnDate: submittedOnDateStr, @@ -417,7 +422,8 @@ export class FixedDepositAccountInterestRateChartStepComponent implements OnChan Math.round(this.principalAmount * Math.pow(1 + r / daysInYearVal, enteredDays) * 100) / 100; } else { const n = 12 / compMonths; - const totalCompoundings = Math.floor(tenureInMonths / compMonths); + const effectiveMonths = tenureInMonths ?? enteredDays / 30; + const totalCompoundings = Math.floor(effectiveMonths / compMonths); const rPerCompounding = rate / (n * 100); result.maturityAmount = Math.round(this.principalAmount * Math.pow(1 + rPerCompounding, totalCompoundings) * 100) / 100; diff --git a/src/app/deposits/fixed-deposits/fixed-deposits.service.ts b/src/app/deposits/fixed-deposits/fixed-deposits.service.ts index dd82ede92..b0257e1bc 100644 --- a/src/app/deposits/fixed-deposits/fixed-deposits.service.ts +++ b/src/app/deposits/fixed-deposits/fixed-deposits.service.ts @@ -133,7 +133,8 @@ export class FixedDepositsService { calculateFixedDepositInterest(params: { principalAmount: number; annualInterestRate: number; - tenureInMonths: number; + tenureInMonths?: number; + tenureInDays?: number; // alternative to tenureInMonths, for sub-month FD Single tenures interestCompoundingPeriodInMonths: number; interestPostingPeriodInMonths: number; submittedOnDate?: string; // yyyy-MM-dd — enables exact calendar calculation