[
https://issues.apache.org/jira/browse/FINERACT-2689?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Adam Saghy updated FINERACT-2689:
---------------------------------
Labels: beginner beginner-friendly (was: )
> Closing (or posting interest on) a withholding-tax deposit account fails with
> a 500 NullPointerException whenever the total interest posted on the account
> is zero. The withholding-tax step dereferences a null amount:
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: FINERACT-2689
> URL: https://issues.apache.org/jira/browse/FINERACT-2689
> Project: Apache Fineract
> Issue Type: Bug
> Reporter: Farooq Ayoade
> Priority: Major
> Labels: beginner, beginner-friendly
>
> java.lang.NullPointerException: Cannot invoke
> "java.math.BigDecimal.compareTo(java.math.BigDecimal)"
> because "amount" is null
> at ...SavingsAccount.createWithHoldTransaction(SavingsAccount.java:719)
> at ...SavingsAccount.applyWithholdTaxForDepositAccounts(...)
> at ...FixedDepositAccount.postPreMaturityInterest(...)
> at ...DepositAccountDomainServiceJpa.handleFDAccountPreMatureClosure(...)
>
> The most common trigger is premature-closing a short-term fixed deposit whose
> {*}pre-closure penalty rate exceeds the chart rate{*}: the effective interest
> is clamped to zero, so no interest-posting transaction is created, and the
> withholding-tax pass then runs with a null interest total.
> h3. Steps to reproduce
> # Create a Fixed Deposit product with *withholding tax enabled* (assign a
> tax group) and a pre-closure penalty configured so the penalty rate is
> *greater than or equal to* the applicable chart rate (e.g. chart 5%,
> pre-closure penalty 20%, "Till Premature Withdrawal").
> # Open and activate an FD account ({{{}withHoldTax = true{}}}, tax group
> inherited).
> # Premature-close it a few days into the term: {{POST
> /fixeddepositaccounts/\{id}?command=prematureClose}} with
> {{onAccountClosureId}} = withdraw (100) or transfer-to-savings (200).
> # *500* {{{}NullPointerException … because "amount" is null{}}}. The command
> rolls back; the account cannot be closed.
> Because the penalty (20%) exceeds the chart rate (5%), the effective
> premature rate clamps to 0
> ({{{}FixedDepositAccount.getEffectiveInterestRateAsFraction{}}} →
> {{{}max(rate − penalty, 0){}}}), so {{postPreMaturityInterest}} posts *no*
> interest transaction and the interest total is null at the withholding step.
>
> h3. Root cause
> {{FixedDepositAccount.postPreMaturityInterest(...)}} (and the normal
> {{postInterest}} path) calls
> {{{}SavingsAccount.applyWithholdTaxForDepositAccounts(...){}}}, which
> computes:
>
>
> {{final BigDecimal totalInterestPosted =
> this.savingsAccountTransactionSummaryWrapper.calculateTotalInterestPosted(this.currency,
> this.transactions);}}
> {{SavingsAccountTransactionSummaryWrapper.calculateTotalInterestPosted(...)}}
> returns {{total.getAmountDefaultedToNullIfZero()}} — i.e. *{{null}}* when
> there are no (net) interest-posting transactions. That null is passed
> straight into the withholding helpers, both of which guard only on the tax
> group and then dereference {{{}amount{}}}:
>
>
> {{// SavingsAccount.createWithHoldTransaction(amount, date,
> backdatedTxnsAllowedTill)
> if (this.taxGroup != null && amount.compareTo(BigDecimal.ZERO) > 0) { // NPE:
> amount == null
> // SavingsAccount.updateWithHoldTransaction(amount, withholdTransaction)
> if (this.taxGroup != null && amount.compareTo(BigDecimal.ZERO) > 0) \{ //
> same flaw}}
> For a withholding-tax account the tax group is non-null, so the first clause
> passes and {{amount.compareTo}} throws. The bug surfaces on any
> withholding-tax deposit account whose net interest posted is zero — premature
> close where the penalty wipes out interest is the easy real-world path, but
> it also applies to a zero-interest posting cycle.
> h3. Fix
> Null-guard {{amount}} in both
> {{SavingsAccount.createWithHoldTransaction(...)}} and
> {{SavingsAccount.updateWithHoldTransaction(...)}} — a null (or non-positive)
> interest total means there is nothing to withhold tax on, so both should
> no-op and return {{{}false{}}}. No behavior change when interest is actually
> posted: a non-null positive amount takes the exact same path as before.
> h3. Impact
> Withholding-tax fixed/recurring deposit accounts can be premature-closed (and
> post interest) when net interest is zero, instead of 500-ing and rolling
> back. No change for accounts with a positive interest total or with no tax
> group.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)