[ 
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)

Reply via email to