chinmaya samantara created FINERACT-2952:
--------------------------------------------
Summary: Undoing or adjusting a savings withdrawal does not always
reverse its withdrawal feef
Key: FINERACT-2952
URL: https://issues.apache.org/jira/browse/FINERACT-2952
Project: Apache Fineract
Issue Type: Bug
Components: Savings
Reporter: chinmaya samantara
Assignee: chinmaya samantara
When a savings withdrawal that triggered a withdrawal fee is undone or
adjusted, the fee is often not reversed. The customer keeps paying a fee for a
withdrawal that no longer exists (undo), or pays the old fee plus the new one
(adjust). The API returns 200, so nothing tells the user that the balance is
wrong.
*Steps to reproduce* (develop ddb1ca0, PostgreSQL)
Savings account with an active 1% withdrawal fee charge, balance 1000. Withdraw
100: the account gets a Withdrawal of 100 and a Withdrawal fee of 1.00, balance
899.
A) Undo the withdrawal:
{code}
POST
/fineract-provider/api/v1/savingsaccounts/{savingsId}/transactions/{withdrawalId}?command=undo
{code}
Actual result: balance 999.00. The withdrawal is reversed, the 1.00 fee is not.
Expected result: balance 1000.00, fee reversed.
B) Adjust the withdrawal to 50:
{code}
POST
/fineract-provider/api/v1/savingsaccounts/{savingsId}/transactions/{withdrawalId}?command=modify
{ "transactionDate": "02 August 2026", "transactionAmount": 50,
"paymentTypeId": 4, "locale": "en", "dateFormat": "dd MMMM yyyy" }
{code}
Actual result: balance 948.50. The old 1.00 fee stays and a new 0.50 fee is
added.
Expected result: balance 949.50 (only the 0.50 fee).
It does not happen every time. In 5 runs on fresh accounts, undo kept the fee 3
times and adjust 1 time. It depends on which of the two new rows gets the lower
id:
{code}
#13 Withdrawal fee 1.0 <- the fee got the lower id
#14 Withdrawal 100.0 REVERSED
#15 Withdrawal 50.0
#16 Withdrawal fee 0.5
{code}
*Cause*
SavingsAccountWritePlatformServiceJpaRepositoryImpl.undoTransaction() and
adjustSavingsTransaction() find the fee by id:
{code:java}
findOneByIdAndSavingsAccountId(transactionId + 1, savingsId)
{code}
SavingsAccount.withdraw() pays the withdrawal fee before it creates the
withdrawal transaction, and the order in which the two rows get their ids is
not guaranteed. When the fee gets the lower id, transactionId + 1 is a
different row (or none) and the fee stays.
The withdrawal and its fee already share the same ref_no (one UUID per
withdrawal, set in SavingsAccountDomainServiceJpa.handleWithdrawal), and
SavingsAccountTransactionRepository.findByRefNo() exists (it is used by the
bulk reverse command).
*Possible fix:* look the fee up by the withdrawal's ref_no instead of
transactionId + 1 (same savings account, withdrawal fee, not reversed), and
keep the id + 1 lookup only for old rows without a ref_no. Add an integration
test with a withdrawal fee for undo and adjust; ClientSavingsIntegrationTest
undoes and modifies a withdrawal, but its product has no withdrawal fee.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)