naman2627 opened a new pull request, #6547:
URL: https://github.com/apache/fineract/pull/6547
## Problem
`SavingsAccountInterestPostingServiceImpl` selects the transactions for a
posting period by comparing only the calendar month:
`periodInterval.startDate().getMonth() == tx.getDate().getMonth()`
in `listForOverdraft`, `listForInterestPosting` and `isOverdraftAccount`
(introduced in FINERACT-2312, a6fa1adc99).
This ignores the year and the posting period's real start/end dates, so
transactions outside the period's first month are dropped and the days their
balances cover earn no interest.
Reproduced (overdraft + interest-receivable, accrual periodic, 10% nominal,
daily compounding, daily balance, 365 days, QUARTERLY posting; deposits of
10,000 on 2025-01-01 and 10,000 on 2025-02-15, up-to date 2025-04-02):
- Expected Q1 interest: **373.64**
- Actual on develop: **124.03** (shortfall 249.61, ~two-thirds)
- Same inputs without overdraft/interest-receivable (non-split branch):
373.64, correct
**Scope is wider than the JIRA title suggests.** Monthly posting is also
affected whenever a period's first transaction isn't on the 1st — the balance
carried over from the previous month is dropped. The existing integration tests
always place transactions on the first day of a period, which is why this
wasn't caught.
## Fix
Replace the four month-equality checks with an interval-overlap check
against the posting period:
```java
private static boolean hasBalanceWithin(final SavingsAccountTransactionData
tx, final LocalDateInterval periodInterval) {
return tx.fallsWithin(periodInterval) ||
tx.spansAnyPortionOf(periodInterval);
}
```
`fallsWithin` and `spansAnyPortionOf` are existing methods (since 2022) and
are the same pair `PostingPeriod#createFromDTO` already uses to decide which
transactions contribute to a period — so the list-building filter now matches
the criteria the interest calculation itself applies. Both compare the
transaction's balance span (`transactionDate` → `balanceEndDate`), inclusive at
both ends, and a balance straddling a period boundary is capped by the existing
`toEndOfDayBalanceBoundedBy`.
The overdraft/regular classification (`MathUtil.isLessThanZero(...)` on the
running balance) is **unchanged** — only the date filter is corrected. This
also resolves the idle-overdraft-month case as a consequence of the same
filter; it does not change the behaviour covered by FINERACT-2869 (#6532).
+9/−4 in one file, plus tests. No refactors.
## Verification
- New `SavingsAccountOverdraftInterestSplitTest`, both cases fail on develop
and pass with the fix:
- quarterly: split path posts 373.64 (was 124.03), matching the non-split
control
- monthly: confirms the carried-over overdraft balance is counted once,
not twice — with the fix the split result matches the non-split control of
−86.16 to within one rounding step (0.01); on develop the split path gives
+24.56 instead
- `:fineract-savings:test` passes: **57/57**, including the existing savings
tests.
- `spotlessApply` clean.
- **Not run:** the full `gradlew build` did not complete locally — it hit an
out-of-memory crash on my machine in unrelated modules (`oauth2-tests`,
`twofactor-tests`, `custom/acme`), not in savings. `SavingsInterestPostingTest`
(integration-tests module) also wasn't run as it needs a running server.
Relying on CI for both.
Resolves FINERACT-2881.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]