From a80f589ad4ad91a7b1c8abbd864e6a5129e8e2cf Mon Sep 17 00:00:00 2001 From: logoutdhaval <100835289+logoutdhaval@users.noreply.github.com> Date: Thu, 28 Jul 2022 14:00:15 +0530 Subject: [PATCH] fineract-1646 and fineract-1638 combined fix (#2457) authored-by: Dhaval Maniyar --- .../savings/data/SavingsAccountData.java | 6 +-- .../data/SavingsAccountSummaryData.java | 5 ++- .../data/SavingsAccountTransactionData.java | 5 ++- .../savings/domain/SavingsAccount.java | 4 +- .../domain/interest/PostingPeriod.java | 5 ++- ...ingsAccountInterestPostingServiceImpl.java | 40 +++++++------------ ...SavingsAccountReadPlatformServiceImpl.java | 10 ++--- .../SavingsSchedularInterestPoster.java | 9 +++-- .../service/SavingsSchedularServiceImpl.java | 2 +- 9 files changed, 38 insertions(+), 48 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java index ee89ea6d7..8f66a23cf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java @@ -366,10 +366,6 @@ public final class SavingsAccountData implements Serializable { return this.glAccountIdForInterestOnSavings; } - public SavingsAccountSummaryData getSavingsAccountSummaryData() { - return this.savingsAccountSummaryData; - } - public List getSavingsAccountTransactionData() { return this.savingsAccountTransactionData; } @@ -417,7 +413,7 @@ public final class SavingsAccountData implements Serializable { SavingsAccountTransactionData savingsTransaction = null; List trans = getTransactions(); for (final SavingsAccountTransactionData transaction : trans) { - if (transaction.isNotReversed() && transaction.occursOn(date)) { + if (transaction.isNotReversed() && !transaction.isReversalTransaction() && transaction.occursOn(date)) { savingsTransaction = transaction; break; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java index 2af8f1484..a7eea4d47 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java @@ -152,7 +152,10 @@ public class SavingsAccountSummaryData implements Serializable { public void updateSummaryWithPivotConfig(final CurrencyData currency, final SavingsAccountTransactionSummaryWrapper wrapper, final SavingsAccountTransaction transaction, final List savingsAccountTransactions) { - if (transaction != null && !transaction.isReversalTransaction()) { + if (transaction != null) { + if (transaction.isReversalTransaction()) { + return; + } Money transactionAmount = Money.of(currency, transaction.getAmount()); switch (SavingsAccountTransactionType.fromInt(transaction.getTypeOf())) { case DEPOSIT: diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java index 92cd095be..009a3b3af 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java @@ -245,7 +245,8 @@ public final class SavingsAccountTransactionData implements Serializable { return this.transactionDate; } - public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy) { + public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy, + final boolean isAllowOverdraft) { final MonetaryCurrency currency = openingBalance.getCurrency(); Money endOfDayBalance = openingBalance.copy(); @@ -263,7 +264,7 @@ public final class SavingsAccountTransactionData implements Serializable { if (isDeposit() || isDividendPayoutAndNotReversed()) { endOfDayBalance = endOfDayBalance.plus(getAmount()); } else if (isWithdrawal() || isChargeTransactionAndNotReversed()) { - if (endOfDayBalance.isGreaterThanZero()) { + if (endOfDayBalance.isGreaterThanZero() || isAllowOverdraft) { endOfDayBalance = endOfDayBalance.minus(getAmount()); } else { endOfDayBalance = Money.of(currency, this.runningBalance); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java index 938666668..90fbb967f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java @@ -1168,8 +1168,8 @@ public class SavingsAccount extends AbstractPersistableCustom { public void validatePivotDateTransaction(LocalDate transactionDate, final boolean backdatedTxnsAllowedTill, final Long relaxingDaysConfigForPivotDate, final String resourceTypeName) { if (backdatedTxnsAllowedTill) { - if (this.getSummary().getLastInterestCalculationDate() != null && transactionDate - .isBefore(this.getSummary().getLastInterestCalculationDate().minusDays(relaxingDaysConfigForPivotDate))) { + if (this.getSummary().getInterestPostedTillDate() != null + && transactionDate.isBefore(this.getSummary().getInterestPostedTillDate().minusDays(relaxingDaysConfigForPivotDate))) { final Object[] defaultUserArgs = Arrays.asList(transactionDate, getActivationLocalDate()).toArray(); final String defaultUserMessage = "Transaction date cannot be before transactions pivot date."; final ApiParameterError error = ApiParameterError.parameterError( diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/interest/PostingPeriod.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/interest/PostingPeriod.java index cc2851f1d..9fb422440 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/interest/PostingPeriod.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/interest/PostingPeriod.java @@ -164,7 +164,7 @@ public final class PostingPeriod { final LocalDate upToInterestCalculationDate, Collection interestPostTransactions, boolean isInterestTransfer, final Money minBalanceForInterestCalculation, final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final BigDecimal overdraftInterestRateAsFraction, final Money minOverdraftForInterestCalculation, boolean isUserPosting, - int financialYearBeginningMonth) { + int financialYearBeginningMonth, final boolean isAllowOverdraft) { final List accountEndOfDayBalances = new ArrayList<>(); boolean interestTransfered = false; @@ -182,7 +182,8 @@ public final class PostingPeriod { openingDayBalance = endOfDayBalance.closingBalance(); } else if (transaction.spansAnyPortionOf(periodInterval)) { - final EndOfDayBalance endOfDayBalance = transaction.toEndOfDayBalanceBoundedBy(openingDayBalance, periodInterval); + final EndOfDayBalance endOfDayBalance = transaction.toEndOfDayBalanceBoundedBy(openingDayBalance, periodInterval, + isAllowOverdraft); accountEndOfDayBalances.add(endOfDayBalance); closeOfDayBalance = endOfDayBalance.closingBalance(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java index b6e54a073..dc2a87309 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java @@ -29,9 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.domain.LocalDateInterval; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.savings.DepositAccountType; @@ -72,7 +70,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI interestPostedToDate = Money.of(savingsAccountData.currency(), savingsAccountData.getSummary().getTotalInterestPosted()); SavingsAccountTransactionData savingsAccountTransactionData = retrieveLastTransactions(savingsAccountData); LocalDate lastTransactionDate = savingsAccountTransactionData.getLastTransactionDate(); - savingsAccountData.setStartInterestCalculationDate(lastTransactionDate); + savingsAccountData.setStartInterestCalculationDate(lastTransactionDate.plusDays(1)); } else { savingsAccountData.setStartInterestCalculationDate(startInterestDate); } @@ -251,21 +249,12 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI final SavingsAccountTransactionData transaction = retrieveLastTransactions(savingsAccountData); if (transaction == null) { - final String defaultUserMessage = "No transactions were found on the specified date " - + savingsAccountData.getStartInterestCalculationDate().toString() + " for account number " - + savingsAccountData.getAccountNo() + " and resource id " + savingsAccountData.getId(); - - final ApiParameterError error = ApiParameterError.parameterError( - "error.msg.savingsaccount.transaction.incorrect.start.interest.calculation.date", defaultUserMessage, - "transactionDate", savingsAccountData.getStartInterestCalculationDate().toString()); - - final List dataValidationErrors = new ArrayList<>(); - dataValidationErrors.add(error); - - throw new PlatformApiDataValidationException(dataValidationErrors); + periodStartingBalance = Money.zero(savingsAccountData.currency()); + } else { + periodStartingBalance = Money.of(savingsAccountData.currency(), + savingsAccountData.getSummary().getRunningBalanceOnPivotDate()); } - periodStartingBalance = transaction.getRunningBalance(savingsAccountData.currency()); } else { periodStartingBalance = Money.zero(savingsAccountData.currency()); } @@ -292,7 +281,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI interestCalculationType, interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions, isInterestTransfer, minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation, - isUserPosting, financialYearBeginningMonth); + isUserPosting, financialYearBeginningMonth, savingsAccountData.isAllowOverdraft()); periodStartingBalance = postingPeriod.closingBalance(); @@ -322,7 +311,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI for (final SavingsAccountTransactionData transaction : listOfTransactionsSorted) { if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) - && transaction.isNotReversed()) { + && transaction.isNotReversed() && !transaction.isReversalTransaction()) { orderedNonInterestPostingTransactions.add(transaction); } } @@ -331,10 +320,6 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI } private List retreiveListOfTransactions(final SavingsAccountData savingsAccountData) { - if (savingsAccountData.getTransactions() != null && savingsAccountData.getTransactions().size() == 1) { - return savingsAccountData.getTransactions(); - } - final List listOfTransactionsSorted = new ArrayList<>(); listOfTransactionsSorted.addAll(savingsAccountData.getTransactions()); @@ -405,7 +390,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI public List getManualPostingDates(final SavingsAccountData savingsAccountData) { List transactions = new ArrayList<>(); for (SavingsAccountTransactionData trans : savingsAccountData.getSavingsAccountTransactionData()) { - if (trans.isInterestPosting() && trans.isNotReversed() && trans.isManualTransaction()) { + if (trans.isInterestPosting() && trans.isNotReversed() && !trans.isReversalTransaction() && trans.isManualTransaction()) { transactions.add(trans.getTransactionLocalDate()); } } @@ -444,7 +429,10 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI } runningBalance = runningBalance.plus(transactionAmount); - transaction.updateRunningBalance(runningBalance); + if (!transaction.getRunningBalance(transactionAmount.getCurrency()).isEqualTo(transactionAmount)) { + transaction.updateRunningBalance(runningBalance); + } + // transaction.updateRunningBalance(runningBalance); if (overdraftAmount.isZero() && runningBalance.isLessThanZero()) { overdraftAmount = overdraftAmount.plus(runningBalance.getAmount().negate()); } @@ -522,7 +510,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI List trans = savingsAccountData.getSavingsAccountTransactionData(); for (final SavingsAccountTransactionData transaction : trans) { if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) - && transaction.occursOn(postingDate)) { + && transaction.occursOn(postingDate) && !transaction.isReversalTransaction()) { postingTransation = transaction; break; } @@ -536,7 +524,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI LocalDate endOfBalanceDate = interestPostingUpToDate; for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) { final SavingsAccountTransactionData transaction = accountTransactionsSorted.get(i); - if (transaction.isNotReversed() + if (transaction.isNotReversed() && !transaction.isReversalTransaction() && !(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())) { transaction.updateCumulativeBalanceAndDates(MonetaryCurrency.fromCurrencyData(savingsAccountData.currency()), endOfBalanceDate); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index a608a6794..b53a1bfed 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -340,7 +340,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("tg.id as taxGroupId, "); sqlBuilder.append("(select COALESCE(max(sat.transaction_date),sa.activatedon_date) "); sqlBuilder.append("from m_savings_account_transaction as sat "); - sqlBuilder.append("where sat.is_reversed = false "); + sqlBuilder.append("where sat.is_reversed = false and sat.is_reversal = false "); sqlBuilder.append("and sat.transaction_type_enum in (1,2) "); sqlBuilder.append("and sat.savings_account_id = sa.id) as lastActiveTransactionDate, "); sqlBuilder.append("sp.id as productId, "); @@ -825,7 +825,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, "); sqlBuilder.append("(select COALESCE(max(sat.transaction_date),sa.activatedon_date) "); sqlBuilder.append("from m_savings_account_transaction as sat "); - sqlBuilder.append("where sat.is_reversed = false "); + sqlBuilder.append("where sat.is_reversed = false and sat.is_reversal = false "); sqlBuilder.append("and sat.transaction_type_enum in (1,2) "); sqlBuilder.append("and sat.savings_account_id = sa.id) as lastActiveTransactionDate, "); sqlBuilder.append("sp.is_dormancy_tracking_active as isDormancyTrackingActive, "); @@ -1684,7 +1684,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sql.append(" where sa.status_enum = 300 "); sql.append(" and sa.sub_status_enum = 0 "); String compareDate = "(select COALESCE(max(sat.transaction_date), sa.activatedon_date) " - + "from m_savings_account_transaction as sat where sat.is_reversed = false" + + "from m_savings_account_transaction as sat where sat.is_reversed = false and sat.is_reversal = false" + " and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)"; sql.append(" and ").append(sqlGenerator.dateDiff("?", compareDate)).append(" >= sp.days_to_inactive "); @@ -1708,7 +1708,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sql.append(" where sa.status_enum = 300 "); sql.append(" and sa.sub_status_enum = 100 "); sql.append(" and " + sqlGenerator.dateDiff("?", - "(select COALESCE(max(sat.transaction_date),sa.activatedon_date) from m_savings_account_transaction as sat where sat.is_reversed = false and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)") + "(select COALESCE(max(sat.transaction_date),sa.activatedon_date) from m_savings_account_transaction as sat where sat.is_reversed = false and sat.is_reversal = false and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)") + " "); sql.append(" >= sp.days_to_dormancy "); @@ -1732,7 +1732,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sql.append(" where sa.status_enum = 300 "); sql.append(" and sa.sub_status_enum = 200 "); sql.append(" and " + sqlGenerator.dateDiff("?", - "(select COALESCE(max(sat.transaction_date),sa.activatedon_date) from m_savings_account_transaction as sat where sat.is_reversed = false and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)") + "(select COALESCE(max(sat.transaction_date),sa.activatedon_date) from m_savings_account_transaction as sat where sat.is_reversed = false and sat.is_reversal = false and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)") + " "); sql.append(" >= sp.days_to_escheat "); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java index 79d5e012a..ef7c25fd9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java @@ -22,6 +22,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.math.BigDecimal; import java.security.SecureRandom; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -270,6 +271,7 @@ public class SavingsSchedularInterestPoster implements Callable { .atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), savingsAccountData.getId() }); List savingsAccountTransactionDataList = savingsAccountData.getSavingsAccountTransactionData(); + LocalDateTime currentDate = DateUtils.getLocalDateTimeOfTenant(); for (SavingsAccountTransactionData savingsAccountTransactionData : savingsAccountTransactionDataList) { Date balanceEndDate = null; if (savingsAccountTransactionData.getBalanceEndDate() != null) { @@ -284,10 +286,9 @@ public class SavingsSchedularInterestPoster implements Callable { savingsAccountTransactionData.isReversed(), savingsAccountTransactionData.getTransactionType().getId(), savingsAccountTransactionData.getTransactionDate(), savingsAccountTransactionData.getAmount(), balanceEndDate, savingsAccountTransactionData.getBalanceNumberOfDays(), savingsAccountTransactionData.getRunningBalance(), - savingsAccountTransactionData.getCumulativeBalance(), savingsAccountTransactionData.getSubmittedOnDate(), - Integer.valueOf(1), savingsAccountTransactionData.isManualTransaction(), - savingsAccountTransactionData.getRefNo(), savingsAccountTransactionData.isReversalTransaction(), - savingsAccountTransactionData.getOverdraftAmount(), }); + savingsAccountTransactionData.getCumulativeBalance(), currentDate, Integer.valueOf(1), + savingsAccountTransactionData.isManualTransaction(), savingsAccountTransactionData.getRefNo(), + savingsAccountTransactionData.isReversalTransaction(), savingsAccountTransactionData.getOverdraftAmount(), }); } else { paramsForTransactionUpdate.add(new Object[] { savingsAccountTransactionData.isReversed(), savingsAccountTransactionData.getAmount(), savingsAccountTransactionData.getOverdraftAmount(), balanceEndDate, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java index 5234e5932..018fc5b98 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java @@ -76,7 +76,7 @@ public class SavingsSchedularServiceImpl implements SavingsSchedularService { Long maxSavingsIdInList = 0L; // initialise the executor service with fetched configurations final ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize); - final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig(); + final boolean backdatedTxnsAllowedTill = false; long start = System.currentTimeMillis();