diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java index 6928f730b66..b0908b2123c 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java @@ -63,17 +63,25 @@ public class SavingsSchedularInterestPoster { private Collection savingAccounts; private boolean backdatedTxnsAllowedTill; - @Transactional(isolation = Isolation.READ_UNCOMMITTED, rollbackFor = Exception.class) + @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class) public void postInterest() throws JobExecutionException { if (!savingAccounts.isEmpty()) { List errors = new ArrayList<>(); + LocalDate currentDate = DateUtils.getBusinessLocalDate(); for (SavingsAccountData savingsAccountData : savingAccounts) { boolean postInterestAsOn = false; LocalDate transactionDate = null; try { + if (isInterestAlreadyPostedForCurrentPeriod(savingsAccountData, currentDate)) { + log.debug("Interest already posted for savings account {} up to date {}, skipping", savingsAccountData.getId(), + savingsAccountData.getSummary().getInterestPostedTillDate()); + continue; + } SavingsAccountData savingsAccountDataRet = savingsAccountWritePlatformService.postInterest(savingsAccountData, postInterestAsOn, transactionDate, backdatedTxnsAllowedTill); - savingsAccountDataList.add(savingsAccountDataRet); + if (hasNewInterestTransactions(savingsAccountDataRet)) { + savingsAccountDataList.add(savingsAccountDataRet); + } } catch (Exception e) { errors.add(e); } @@ -109,7 +117,6 @@ private void batchUpdateJournalEntries(final List savingsAcc for (SavingsAccountTransactionData savingsAccountTransactionData : savingsAccountTransactionDataList) { if (savingsAccountTransactionData.getId() == null && !MathUtil.isZero(savingsAccountTransactionData.getAmount())) { final String key = savingsAccountTransactionData.getRefNo(); - final Boolean isOverdraft = savingsAccountTransactionData.getIsOverdraft(); final SavingsAccountTransactionData dataFromFetch = savingsAccountTransactionDataHashMap.get(key); savingsAccountTransactionData.setId(dataFromFetch.getId()); if (savingsAccountData.getGlAccountIdForSavingsControl() != 0 @@ -248,4 +255,20 @@ private String batchQueryForTransactionsUpdate() { + "SET is_reversed=?, amount=?, overdraft_amount_derived=?, balance_end_date_derived=?, balance_number_of_days_derived=?, running_balance_derived=?, cumulative_balance_derived=?, is_reversal=?, " + LAST_MODIFIED_DATE_DB_FIELD + " = ?, " + LAST_MODIFIED_BY_DB_FIELD + " = ? " + "WHERE id=?"; } + + private boolean isInterestAlreadyPostedForCurrentPeriod(SavingsAccountData savingsAccountData, LocalDate currentDate) { + LocalDate interestPostedTillDate = savingsAccountData.getSummary().getInterestPostedTillDate(); + if (interestPostedTillDate == null) { + return false; + } + return interestPostedTillDate.isAfter(currentDate) || interestPostedTillDate.equals(currentDate); + } + + private boolean hasNewInterestTransactions(SavingsAccountData savingsAccountData) { + if (savingsAccountData.getSavingsAccountTransactionData() == null) { + return false; + } + return savingsAccountData.getSavingsAccountTransactionData().stream() + .anyMatch(tx -> tx.getId() == null && !MathUtil.isZero(tx.getAmount()) && tx.isInterestPosting()); + } }