-
Notifications
You must be signed in to change notification settings - Fork 2.2k
FINERACT-2312: Reverse of Accruals to adjust late deposits #4904
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@JohnAlva Please drop this generic "Savings Accounts Improvements" and start using clear, descriptive short description for the PRs! |
|
Hi @adamsaghy, thank you for the feedback. Just to clarify, this PR is indeed related to the overall "Savings Accounts Improvements" initiative. The team decided to split the changes into multiple PRs to improve clarity and facilitate the review process, while keeping a consistent title to reflect that they all belong to the same scope. |
The Fineract story id just fine to connect them. The PR title should tell exactly what it is doing and "improvements" is too generic and useless. Kindly asking you to rename it! |
68d04ad to
bd5bf2a
Compare
|
@adamsaghy sorry, but we already changed the name of each PR for each section. |
|
Hi @adamsaghy, a quick review on this PR would be awesome. Thanks a lot in advance! |
| .toList(); | ||
| } | ||
|
|
||
| public void accrualsForSavingsReverse(SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do? Can you please give an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method reverts all accrual transactions on or after the given transaction date. It’s used when a backdated transaction is added (like a late deposit), so previously posted accruals can be recalculated correctly.
--Example:-- If a deposit is backdated to July 15 and accruals were posted on July 15, 20, and 25, those accruals will be reversed to allow correct recomputation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How the system will know the accruals were reversed, so during the next calculation it should start from that particular date?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JohnAlva well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JohnAlva How the system will know the accruals were reversed, so during the next calculation it should start from that particular date?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @adamsaghy
The calculation process likely still loops through the account's entire history. However:
*Accruals before the backdated transaction are untouched and skipped.
*The reversed flag on accruals on or after that date acts as a signal. It tells the system: "This is where you need to replace the old value with a new calculation."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @adamsaghy
The process is designed to handle that scenario correctly. The reversal logic will find and reverse all accrual transactions on or after the backdated transaction's date, regardless of their previous state (whether they were already reversed or not).
This ensures we always start with a clean slate before the recalculation step runs, which prevents any duplicate, active accruals for a given date.
Hope that clarifies it!
|
@JohnAlva All PR should involve proper testing attached! |
| } else { | ||
| accountTransactionsSorted = retrieveListOfTransactions(); | ||
| } | ||
| for (final SavingsAccountTransaction transaction : accountTransactionsSorted) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also i am missing test cases to cover the functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we added the test cases for this functionality
adamsaghy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review my comments!
|
It is put in draft by dependency to pr #4885 |
e137ccf to
2f675b0
Compare
|
Sure we made the changes, can you help us with the review |
|
Hi @adamsaghy, can you help us with the review please? |
|
LGTM |
|
|
||
| final List<LocalDate> accrualTransactionDates = savingsAccount.retrieveOrderedAccrualTransactions().stream() | ||
| .map(transaction -> transaction.getTransactionDate()).toList(); | ||
| final List<LocalDate> accrualTransactionDatesReverse = savingsAccount.retrieveOrderedAccrualTransactions().stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please rename this field? At first glance it seems to be a list of accrual transactions in reverse date order, but in fact it’s a list of reversed accrual transactions. The name should make that explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure we will change that part
|
|
||
| for (PostingPeriod period : allPostingPeriods) { | ||
| LocalDate valueDate = period.getPeriodInterval().endDate(); | ||
| List<LocalDate> matchingAccrualDates = accrualTransactionDatesReverse.stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you help me understand this logic? I have no clue why we need reversed accrual transactions with transaction date that matches with the period end date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @adamsaghy
Basically, that code handles the cleanup after a user reverses an old accrual. It makes sure we create a new transaction to replace the reversed one, even if the new interest amount is zero.
This is to avoid leaving a "hole" in the transaction history and to keep the accounting records correct.
adamsaghy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please kindly see my concerns!
d7915b9 to
e24e031
Compare
sayhaed
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @adamsaghy can you help us wit the review :)
|
|
||
| for (PostingPeriod period : allPostingPeriods) { | ||
| LocalDate valueDate = period.getPeriodInterval().endDate(); | ||
| List<LocalDate> matchingAccrualDates = accrualTransactionDatesReverse.stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @adamsaghy
Basically, that code handles the cleanup after a user reverses an old accrual. It makes sure we create a new transaction to replace the reversed one, even if the new interest amount is zero.
This is to avoid leaving a "hole" in the transaction history and to keep the accounting records correct.
|
|
||
| final List<LocalDate> accrualTransactionDates = savingsAccount.retrieveOrderedAccrualTransactions().stream() | ||
| .map(transaction -> transaction.getTransactionDate()).toList(); | ||
| final List<LocalDate> accrualTransactionDatesReverse = savingsAccount.retrieveOrderedAccrualTransactions().stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure we will change that part
|
#4904 (comment) |
|
You are absolutely right, and my apologies for the confusing explanation. We cannot have accrual transactions with a zero amount. The intent of this code is to correctly adjust accruals after back-dated transactions are made. If a deposit or withdrawal affects a past period, the original accrual is reversed. This logic then triggers a recalculation to post the new, correct accrual based on the updated transaction history. Its purpose is strictly for this adjustment process, not to create zero-amount transactions. |
|
Hi @adamsaghy, Thanks for the follow-up. I have now replied to your previous technical question. As that explanation shows, the current logic already handles the scenario you described correctly, which is why no code changes were necessary. Thank you again for your insightful comments. I hope my answers have addressed all your questions. |
|
LGTM |
Description
Reverse of Accruals to adjust late deposits
-When accruals are run and there is a balance change on the account within the period, the previously posted accruals will be reversed.
Ignore if these details are present on the associated Apache Fineract JIRA ticket.
Checklist
Please make sure these boxes are checked before submitting your pull request - thanks!
FYI our guidelines for code reviews are at https://cwiki.apache.org/confluence/display/FINERACT/Code+Review+Guide.