Ralph Hopman created FINERACT-2851:
--------------------------------------
Summary: Savings hold/release transactions incorrectly affect
transaction running balance
Key: FINERACT-2851
URL: https://issues.apache.org/jira/browse/FINERACT-2851
Project: Apache Fineract
Issue Type: Bug
Components: Savings
Affects Versions: 1.15.0, 1.14.0
Reporter: Ralph Hopman
Assignee: Ralph Hopman
Fix For: 1.16.0
h2. Description
When an amount is placed on hold on a savings account, the hold is represented
as an {{AMOUNT_HOLD}} transaction.
A hold should reduce the *available balance* of the account, but should not
change the account's ledger/book balance. This is also consistent with the
existing savings account behavior: {{summary.accountBalance}} remains unchanged
while {{summary.availableBalance}} is reduced by the held amount.
However, the {{runningBalance}} reported on savings transactions treats
{{AMOUNT_HOLD}} as if it reduces the ledger balance, and {{AMOUNT_RELEASE}} as
if it increases it again.
This results in the transaction-level running balance being inconsistent with
the account-level balance.
h2. Example
Given a savings account with no initial balance:
# Deposit 1,000
# Hold 200
The account correctly reports:
{code:java}
accountBalance = 1000
availableBalance = 800
{code}
However, the transactions report approximately:
{code:java}
Deposit amount=1000 runningBalance=1000
Amount Hold amount= 200 runningBalance= 800
{code}
The {{runningBalance}} of the hold transaction therefore does not correspond to
the ledger/book balance after that transaction.
After the hold is released, the running balance increases again, even though
releasing a hold also has no effect on the ledger balance.
h2. Expected Behavior
{{AMOUNT_HOLD}} and {{AMOUNT_RELEASE}} should not change the transaction
{{runningBalance}} if that field represents the running ledger/book balance.
For the example above, the expected result is:
{code:java}
Deposit amount=1000 runningBalance=1000
Amount Hold amount= 200 runningBalance=1000
Amount Release amount= 200 runningBalance=1000
{code}
The effect of the hold should instead be reflected in the account's
{{{}availableBalance{}}}.
Note: If {{runningBalance}} is intentionally intended to represent available
balance rather than ledger balance, this should be explicitly defined and
consistently applied across the savings APIs. Currently its semantics differ
from the account-level {{accountBalance}} and can also affect downstream
calculations.
h2. Relevant Implementation
In {{{}SavingsAccount.recalculateDailyBalances(){}}}, hold and release
transactions are explicitly included in the running-balance calculation:
{code:java}
if (transaction.isCredit() || transaction.isAmountRelease()) {
...
transactionAmount =
transactionAmount.plus(transaction.getAmount(this.currency));
} else if (transaction.isDebit() || transaction.isAmountOnHold()) {
...
transactionAmount =
transactionAmount.minus(transaction.getAmount(this.currency));
}
runningBalance = runningBalance.plus(transactionAmount);
transaction.setRunningBalance(runningBalance);
{code}
This is notable because {{SavingsAccountTransactionType}} explicitly defines
{{AMOUNT_HOLD}} and {{AMOUNT_RELEASE}} as transactions that do not change the
account balance.
For example:
{code:java}
// AMOUNT_RELEASE is not credit, because the account balance is not changed
return isCreditEntryType() && !isAmountRelease();
// AMOUNT_HOLD ... [is] not debit, because the account balance is not changed
return isDebitEntryType() && !isAmountOnHold() && !isEscheat();
{code}
h2. Acceptance Criteria
* Placing an amount on hold does not reduce the transaction
{{{}runningBalance{}}}.
* Releasing a held amount does not increase the transaction
{{{}runningBalance{}}}.
* {{runningBalance}} after a hold/release remains equal to the ledger/book
balance at that point in the transaction history.
* {{availableBalance}} continues to reflect active holds.
* Existing rules preventing withdrawal of held funds continue to work.
* Regression tests cover:
** deposit -> hold
** deposit -> hold -> release
** deposit -> hold -> withdrawal
** deposit -> hold -> deposit
** multiple simultaneous holds
* Behavior is consistent between the entity-based and DTO-based savings
processing paths.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)