Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
FD Special (monthly interest payout) accounts post interest each month and immediately sweep it to a linked savings account. Two independent interest recalculation paths were treating that sweep withdrawal as ordinary account activity and silently reversing + reposting already-settled periods at a slightly different (rounding-drifted) amount — after the original, correct amount had already been transferred out. This left the FD short by the difference every time it happened. Root causes (two separate engines, same underlying bug pattern): 1. SavingsAccountDomainServiceJpa#handleWithdrawal re-triggers a full postInterest()/calculateInterestUsing() after every withdrawal, including the sweep withdrawal itself. At that exact moment the withdrawal's own m_account_transfer_transaction linking row does not exist yet, so the balance-exclusion logic can't recognise it as a transfer leg — it gets treated as a real balance-reducing transaction and corrupts that period's (and any later period's) interest calculation. 2. SavingsAccountInterestPostingServiceImpl (the "Post Interest For Savings" batch job) has its own, separate reverse-and-repost correction loop with the same lack of a "was this period already settled" guard. Fixes, both scoped strictly to FD Special (transfer_interest_to_linked_account = true) so plain savings and recurring deposit behaviour is provably unchanged (the new hooks all default to the prior behaviour unless overridden): - SavingsAccount: new isInterestPostingCorrectionAllowed(...) extension point guarding the postInterest() correction loop; new isPostWithdrawalInterestRecalculationRequired(...) hook checked by handleWithdrawal before it re-recalculates; new refreshBalancesAndSummaryAfterTransfer(...) — the running-balance/summary bookkeeping postInterest() always performs, without re-running the posting/correction loop, so skipping the full recalculation doesn't leave the withdrawal's own running balance and the account summary stale. - FixedDepositAccount: overrides both hooks using the existing interestAlreadyPaidOut(...) date-matched sweep-withdrawal check (already used by postMaturityInterest) so an already-swept period is never recalculated again, from either the withdrawal path or a later job run. - SavingsAccountInterestPostingServiceImpl: mirrors the same guard (isInterestAlreadySweptOut) in its own correction loop for the batch job. Unrelated correctness fixes carried in the same files, applicable to any account type (not FD-Special-specific), found while investigating the above: - SavingsAccountWritePlatformServiceJpaRepositoryImpl: interest-payable GL entries were reading a financial_account_type that never exists in acc_product_mapping, always resolving to account id 0. Now reads the correct getGlAccountIdForInterestOnSavings(). - DepositAccountInterestRateChart#getApplicableInterestRate: missing break in the slab-matching loop meant HashSet's non-deterministic iteration order could pick an arbitrary matching slab instead of the intended one. - SavingsAccountReadPlatformServiceImpl / SavingsAccountData: thread the real transfer_interest_to_linked_account flag into the batch interest engine's per-account data so it can correctly disable interest compounding for FD Special (previously hard-coded false, causing the batch job to compound interest that should reset to zero each period). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>