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 145f3e19f..2af8f1484 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 @@ -256,7 +256,6 @@ public class SavingsAccountSummaryData implements Serializable { final SavingsAccountTransactionData savingsAccountTransaction = savingsAccountTransactions.get(i); if (savingsAccountTransaction.isInterestPostingAndNotReversed() && !savingsAccountTransaction.isReversalTransaction() && !isUpdated) { - setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount()); setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate()); isUpdated = true; if (!backdatedTxnsAllowedTill) { @@ -265,7 +264,6 @@ public class SavingsAccountSummaryData implements Serializable { } if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction() && !isUpdated) { - setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount()); setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate()); isUpdated = true; if (!backdatedTxnsAllowedTill) { @@ -273,13 +271,13 @@ public class SavingsAccountSummaryData implements Serializable { } } if (backdatedTxnsAllowedTill) { - if (savingsAccountTransaction.isInterestPostingAndNotReversed()) { + if (savingsAccountTransaction.isInterestPostingAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()) { interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount()); } - if (savingsAccountTransaction.isOverdraftInterestAndNotReversed()) { + if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()) { overdraftInterestTotal = overdraftInterestTotal.plus(savingsAccountTransaction.getAmount()); } - if (savingsAccountTransaction.isWithHoldTaxAndNotReversed()) { + if (savingsAccountTransaction.isWithHoldTaxAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()) { withHoldTaxTotal = withHoldTaxTotal.plus(savingsAccountTransaction.getAmount()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java index 5a6027829..98e1a4823 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java @@ -541,10 +541,11 @@ public class RecurringDepositAccount extends SavingsAccount { final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance); final boolean backdatedTxnsAllowedTill = false; String refNo = null; + final Long relaxingDaysConfigForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate(); if (minRequiredOpeningBalance.isGreaterThanZero()) { final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationLocalDate(), minRequiredOpeningBalance.getAmount(), null, DateUtils.getLocalDateTimeOfSystem(), user, accountType); - deposit(transactionDTO, backdatedTxnsAllowedTill, refNo); + deposit(transactionDTO, backdatedTxnsAllowedTill, relaxingDaysConfigForPivotDate, refNo); // update existing transactions so derived balance fields are // correct. @@ -842,7 +843,7 @@ public class RecurringDepositAccount extends SavingsAccount { @Override public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill, - final String refNo) { + final Long relaxingDaysConfigForPivotDate, final String refNo) { if (isAccountMatured()) { final String defaultUserMessage = "Transaction is not allowed. Account is matured."; @@ -880,7 +881,8 @@ public class RecurringDepositAccount extends SavingsAccount { throw new PlatformApiDataValidationException(dataValidationErrors); } - final SavingsAccountTransaction transaction = super.deposit(transactionDTO, backdatedTxnsAllowedTill, refNo); + final SavingsAccountTransaction transaction = super.deposit(transactionDTO, backdatedTxnsAllowedTill, + relaxingDaysConfigForPivotDate, refNo); return transaction; } 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 928531625..938666668 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 @@ -72,6 +72,7 @@ import javax.persistence.Transient; import javax.persistence.UniqueConstraint; import javax.persistence.Version; import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; @@ -337,6 +338,8 @@ public class SavingsAccount extends AbstractPersistableCustom { @OneToMany(cascade = CascadeType.ALL, mappedBy = "account", orphanRemoval = true, fetch = FetchType.LAZY) protected List identifiers = new ArrayList<>(); + public transient ConfigurationDomainService configurationDomainService; + protected SavingsAccount() { // } @@ -529,7 +532,12 @@ public class SavingsAccount extends AbstractPersistableCustom { if (!interestPostingTransactionDate.isAfter(interestPostingUpToDate)) { interestPostedToDate = interestPostedToDate.plus(interestEarnedToBePostedForPeriod); - final SavingsAccountTransaction postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate); + SavingsAccountTransaction postingTransaction = null; + if (backdatedTxnsAllowedTill) { + postingTransaction = findInterestPostingSavingsTransactionWithPivotConfig(interestPostingTransactionDate); + } else { + postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate); + } if (postingTransaction == null) { SavingsAccountTransaction newPostingTransaction; if (interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))) { @@ -741,7 +749,7 @@ public class SavingsAccount extends AbstractPersistableCustom { SavingsAccountTransaction savingsTransaction = null; List trans = getTransactions(); for (final SavingsAccountTransaction transaction : trans) { - if (transaction.isNotReversed() && transaction.occursOn(date)) { + if (transaction.isNotReversed() && !transaction.isReversalTransaction() && transaction.occursOn(date)) { savingsTransaction = transaction; break; } @@ -754,7 +762,7 @@ public class SavingsAccount extends AbstractPersistableCustom { SavingsAccountTransaction savingsTransaction = null; List trans = getSavingsAccountTransactionsWithPivotConfig(); for (final SavingsAccountTransaction transaction : trans) { - if (transaction.isNotReversed() && transaction.occursOn(date)) { + if (transaction.isNotReversed() && !transaction.isReversalTransaction() && transaction.occursOn(date)) { savingsTransaction = transaction; break; } @@ -765,7 +773,7 @@ public class SavingsAccount extends AbstractPersistableCustom { public List getManualPostingDates() { List transactions = new ArrayList<>(); for (SavingsAccountTransaction trans : this.transactions) { - if (trans.isInterestPosting() && trans.isNotReversed() && trans.isManualTransaction()) { + if (trans.isInterestPosting() && trans.isNotReversed() && !trans.isReversalTransaction() && trans.isManualTransaction()) { transactions.add(trans.getTransactionLocalDate()); } } @@ -829,7 +837,12 @@ public class SavingsAccount extends AbstractPersistableCustom { final SavingsInterestCalculationDaysInYearType daysInYearType = SavingsInterestCalculationDaysInYearType .fromInt(this.interestCalculationDaysInYearType); - List postedAsOnDates = getManualPostingDates(); + List postedAsOnDates = null; + if (backdatedTxnsAllowedTill) { + postedAsOnDates = getManualPostingDatesWithPivotConfig(); + } else { + postedAsOnDates = getManualPostingDates(); + } if (postInterestOnDate != null) { postedAsOnDates.add(postInterestOnDate); } @@ -840,26 +853,20 @@ public class SavingsAccount extends AbstractPersistableCustom { final List allPostingPeriods = new ArrayList<>(); Money periodStartingBalance; - if (this.startInterestCalculationDate != null) { + if (this.startInterestCalculationDate != null && !this.getStartInterestCalculationDate().equals(this.getActivationLocalDate())) { LocalDate startInterestCalculationDate = this.startInterestCalculationDate; - final SavingsAccountTransaction transaction = findLastTransaction(startInterestCalculationDate); - - if (transaction == null) { - final String defaultUserMessage = "No transactions were found on the specified date " - + getStartInterestCalculationDate().toString() + " for account number " + this.accountNumber.toString() - + " and resource id " + getId(); - - final ApiParameterError error = ApiParameterError.parameterError( - "error.msg.savingsaccount.transaction.incorrect.start.interest.calculation.date", defaultUserMessage, - "transactionDate", getStartInterestCalculationDate().toString()); - - final List dataValidationErrors = new ArrayList<>(); - dataValidationErrors.add(error); - - throw new PlatformApiDataValidationException(dataValidationErrors); + SavingsAccountTransaction transaction = null; + if (backdatedTxnsAllowedTill) { + transaction = findLastFilteredTransactionWithPivotConfig(startInterestCalculationDate); + } else { + transaction = findLastTransaction(startInterestCalculationDate); } - periodStartingBalance = transaction.getRunningBalance(this.currency); + if (transaction == null) { + periodStartingBalance = Money.zero(this.currency); + } else { + periodStartingBalance = Money.of(this.currency, this.summary.getRunningBalanceOnPivotDate()); + } } else { periodStartingBalance = Money.zero(this.currency); } @@ -878,11 +885,19 @@ public class SavingsAccount extends AbstractPersistableCustom { isUserPosting = true; } - final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, - retreiveOrderedNonInterestPostingTransactions(), this.currency, compoundingPeriodType, interestCalculationType, - interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions, - isInterestTransfer, minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd, - overdraftInterestRateAsFraction, minOverdraftForInterestCalculation, isUserPosting, financialYearBeginningMonth); + PostingPeriod postingPeriod = null; + List orderedNonInterestPostingTransactions = null; + if (backdatedTxnsAllowedTill) { + orderedNonInterestPostingTransactions = retreiveOrderedNonInterestPostingSavingsTransactionsWithPivotConfig(); + } else { + orderedNonInterestPostingTransactions = retreiveOrderedNonInterestPostingTransactions(); + } + + postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, orderedNonInterestPostingTransactions, + this.currency, compoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYearType.getValue(), + upToInterestCalculationDate, interestPostTransactions, isInterestTransfer, minBalanceForInterestCalculation, + isSavingsInterestPostingAtCurrentPeriodEnd, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation, + isUserPosting, financialYearBeginningMonth); periodStartingBalance = postingPeriod.closingBalance(); @@ -1023,7 +1038,7 @@ public class SavingsAccount extends AbstractPersistableCustom { if (overdraftAmount.isGreaterThanZero()) { accountTransaction.updateOverdraftAmount(overdraftAmount.getAmount()); } - // accountTransaction.updateRunningBalance(runningBalance); + accountTransaction.updateRunningBalance(runningBalance); if (backdatedTxnsAllowedTill) { addTransactionToExisting(accountTransaction); if (reversal != null) { @@ -1068,18 +1083,21 @@ public class SavingsAccount extends AbstractPersistableCustom { } public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill, - final String refNo) { - return deposit(transactionDTO, SavingsAccountTransactionType.DEPOSIT, backdatedTxnsAllowedTill, refNo); + final Long relaxingDaysConfigForPivotDate, final String refNo) { + return deposit(transactionDTO, SavingsAccountTransactionType.DEPOSIT, backdatedTxnsAllowedTill, relaxingDaysConfigForPivotDate, + refNo); } public SavingsAccountTransaction dividendPayout(final SavingsAccountTransactionDTO transactionDTO, - final boolean backdatedTxnsAllowedTill) { + final boolean backdatedTxnsAllowedTill, final Long relaxingDaysConfigForPivotDate) { String refNo = null; - return deposit(transactionDTO, SavingsAccountTransactionType.DIVIDEND_PAYOUT, backdatedTxnsAllowedTill, refNo); + return deposit(transactionDTO, SavingsAccountTransactionType.DIVIDEND_PAYOUT, backdatedTxnsAllowedTill, + relaxingDaysConfigForPivotDate, refNo); } public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, - final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill, final String refNo) { + final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill, + final Long relaxingDaysConfigForPivotDate, final String refNo) { final String resourceTypeName = depositAccountType().resourceName(); if (isNotActive()) { final String defaultUserMessage = "Transaction is not allowed. Account is not active."; @@ -1117,6 +1135,9 @@ public class SavingsAccount extends AbstractPersistableCustom { throw new PlatformApiDataValidationException(dataValidationErrors); } + validatePivotDateTransaction(transactionDTO.getTransactionDate(), backdatedTxnsAllowedTill, relaxingDaysConfigForPivotDate, + resourceTypeName); + validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_DEPOSIT, transactionDTO.getTransactionDate()); final Money amount = Money.of(this.currency, transactionDTO.getTransactionAmount()); @@ -1144,6 +1165,25 @@ public class SavingsAccount extends AbstractPersistableCustom { return transaction; } + 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))) { + final Object[] defaultUserArgs = Arrays.asList(transactionDate, getActivationLocalDate()).toArray(); + final String defaultUserMessage = "Transaction date cannot be before transactions pivot date."; + final ApiParameterError error = ApiParameterError.parameterError( + "error.msg." + resourceTypeName + ".transaction.before.pivot.date", defaultUserMessage, "transactionDate", + defaultUserArgs); + + final List dataValidationErrors = new ArrayList<>(); + dataValidationErrors.add(error); + + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } + } + public LocalDate getActivationLocalDate() { return this.activatedOnDate; } @@ -1172,8 +1212,12 @@ public class SavingsAccount extends AbstractPersistableCustom { return startInterestCalculationLocalDate; } + public void setStartInterestCalculationDate(LocalDate startInterestCalculationDate) { + this.startInterestCalculationDate = startInterestCalculationDate; + } + public SavingsAccountTransaction withdraw(final SavingsAccountTransactionDTO transactionDTO, final boolean applyWithdrawFee, - final boolean backdatedTxnsAllowedTill, String refNo) { + final boolean backdatedTxnsAllowedTill, final Long relaxingDaysConfigForPivotDate, String refNo) { if (!isTransactionsAllowed()) { @@ -1224,6 +1268,8 @@ public class SavingsAccount extends AbstractPersistableCustom { throw new PlatformApiDataValidationException(dataValidationErrors); } + validatePivotDateTransaction(transactionDTO.getTransactionDate(), backdatedTxnsAllowedTill, relaxingDaysConfigForPivotDate, + "savingsaccount"); validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_WITHDRAWAL, transactionDTO.getTransactionDate()); if (applyWithdrawFee) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java index d3e34cbbb..fa234fcaa 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java @@ -349,6 +349,16 @@ public class SavingsAccountAssembler { LocalDate interestPostedTillDate = account.getSummary().getInterestPostedTillDate(); savingsAccountTransactions = this.savingsAccountRepository.findTransactionsAfterPivotDate(account, interestPostedTillDate.minusDays(relaxingDaysForPivotDate)); + + savingsAccountTransactions.get(0).getSavingsAccount() + .setStartInterestCalculationDate(interestPostedTillDate.minusDays(relaxingDaysForPivotDate)); + List pivotDateTransaction = this.savingsAccountRepository + .findTransactionRunningBalanceBeforePivotDate(account, + interestPostedTillDate.minusDays(relaxingDaysForPivotDate + 1)); + if (pivotDateTransaction != null && !pivotDateTransaction.isEmpty()) { + account.getSummary().setRunningBalanceOnPivotDate(pivotDateTransaction.get(pivotDateTransaction.size() - 1) + .getRunningBalance(account.getCurrency()).getAmount()); + } } else { savingsAccountTransactions = this.savingsAccountRepository.findTransactionsAfterPivotDate(account, account.getSummary().getInterestPostedTillDate()); @@ -358,24 +368,12 @@ public class SavingsAccountAssembler { // Update transient variable account.setSavingsAccountTransactions(savingsAccountTransactions); } - // Update last running balance on account level - if (savingsAccountTransactions != null && !savingsAccountTransactions.isEmpty()) { - account.getSummary().setRunningBalanceOnPivotDate(savingsAccountTransactions.get(savingsAccountTransactions.size() - 1) - .getRunningBalance(account.getCurrency()).getAmount()); - } } else { savingsAccountTransactions = this.savingsAccountRepository.findAllTransactions(account); account.setSavingsAccountTransactions(savingsAccountTransactions); } } - // Update last running balance on account level - // if (savingsAccountTransactions != null && !savingsAccountTransactions.isEmpty()) { - // account.getSummary().setRunningBalanceOnPivotDate(savingsAccountTransactions.get(savingsAccountTransactions.size() - // - 1) - // .getRunningBalance(account.getCurrency()).getAmount()); - // } - account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); return account; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java index 4806d5e91..555585145 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java @@ -91,6 +91,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi account.validateForDebitBlock(); final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); + final Long relaxingDaysConfigForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); if (transactionBooleanValues.isRegularTransaction() && !account.allowWithdrawal()) { throw new DepositAccountTransactionNotAllowedException(account.getId(), "withdraw", account.depositAccountType()); @@ -110,7 +111,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi paymentDetail, DateUtils.getLocalDateTimeOfSystem(), user, accountType); UUID refNo = UUID.randomUUID(); final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee(), - backdatedTxnsAllowedTill, refNo.toString()); + backdatedTxnsAllowedTill, relaxingDaysConfigForPivotDate, refNo.toString()); final MathContext mc = MathContext.DECIMAL64; final LocalDate today = DateUtils.getBusinessLocalDate(); @@ -134,7 +135,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi depositAccountOnHoldTransactions, backdatedTxnsAllowedTill); saveTransactionToGenerateTransactionId(withdrawal); - + if (backdatedTxnsAllowedTill) { + // Update transactions separately + saveUpdatedTransactionsOfSavingsAccount(account.getSavingsAccountTransactionsWithPivotConfig()); + } this.savingsAccountRepository.save(account); postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, transactionBooleanValues.isAccountTransfer(), @@ -174,7 +178,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); - + final Long relaxingDaysConfigForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate(); if (isRegularTransaction && !account.allowDeposit()) { throw new DepositAccountTransactionNotAllowedException(account.getId(), "deposit", account.depositAccountType()); } @@ -193,7 +197,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi paymentDetail, DateUtils.getLocalDateTimeOfSystem(), user, accountType); UUID refNo = UUID.randomUUID(); final SavingsAccountTransaction deposit = account.deposit(transactionDTO, savingsAccountTransactionType, backdatedTxnsAllowedTill, - refNo.toString()); + relaxingDaysConfigForPivotDate, refNo.toString()); final LocalDate postInterestOnDate = null; final MathContext mc = MathContext.DECIMAL64; @@ -292,6 +296,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); + final Long relaxingDaysConfigForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate(); final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); @@ -327,7 +332,8 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals); } - + account.validatePivotDateTransaction(savingsAccountTransaction.getLastTransactionDate(), backdatedTxnsAllowedTill, + relaxingDaysConfigForPivotDate, "savingsaccount"); account.validateAccountBalanceDoesNotBecomeNegativeMinimal(savingsAccountTransaction.getAmount(), false); account.activateAccountBasedOnBalance(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepositoryWrapper.java index 0746b5ea7..7b7c23869 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepositoryWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepositoryWrapper.java @@ -134,6 +134,11 @@ public class SavingsAccountRepositoryWrapper { return this.savingsAccountTransactionRepository.findTransactionsAfterPivotDate(savingsAccount, transactionDate); } + public List findTransactionRunningBalanceBeforePivotDate( + @Param("savingsAccount") SavingsAccount savingsAccount, @Param("date") LocalDate date) { + return this.savingsAccountTransactionRepository.findTransactionRunningBalanceBeforePivotDate(savingsAccount, date); + } + @Transactional public List findAllTransactions(@Param("savingsAccount") SavingsAccount savingsAccount) { return this.savingsAccountTransactionRepository.findBySavingsAccount(savingsAccount); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java index a44dbcf03..90a49ced9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java @@ -117,7 +117,10 @@ public final class SavingsAccountSummary { public void updateSummaryWithPivotConfig(final MonetaryCurrency 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: @@ -188,12 +191,7 @@ public final class SavingsAccountSummary { Money overdraftInterestTotal = Money.zero(currency); this.totalDeposits = wrapper.calculateTotalDeposits(currency, savingsAccountTransactions); this.totalWithdrawals = wrapper.calculateTotalWithdrawals(currency, savingsAccountTransactions); - this.totalWithdrawalFees = wrapper.calculateTotalWithdrawalFees(currency, savingsAccountTransactions); - this.totalAnnualFees = wrapper.calculateTotalAnnualFees(currency, savingsAccountTransactions); - this.totalFeeCharge = wrapper.calculateTotalFeesCharge(currency, savingsAccountTransactions); - this.totalPenaltyCharge = wrapper.calculateTotalPenaltyCharge(currency, savingsAccountTransactions); - this.totalFeeChargesWaived = wrapper.calculateTotalFeesChargeWaived(currency, savingsAccountTransactions); - this.totalPenaltyChargesWaived = wrapper.calculateTotalPenaltyChargeWaived(currency, savingsAccountTransactions); + final HashMap map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal, overdraftInterestTotal, withHoldTaxTotal, currency); interestTotal = map.get("interestTotal"); @@ -202,12 +200,11 @@ public final class SavingsAccountSummary { this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero(); this.totalOverdraftInterestDerived = overdraftInterestTotal.getAmountDefaultedToNullIfZero(); this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero(); - this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals) - .minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge) - .minus(this.totalOverdraftInterestDerived).minus(totalWithholdTax).getAmount(); - // this.accountBalance = Money.of(currency, - // this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax) - // .getAmount(); + + this.accountBalance = getRunningBalanceOnPivotDate(); + this.accountBalance = Money.of(currency, this.accountBalance).plus(Money.of(currency, this.totalDeposits)) + .plus(this.totalInterestPosted).minus(this.totalWithdrawals).minus(this.totalWithholdTax) + .minus(this.totalOverdraftInterestDerived).getAmount(); } } @@ -221,7 +218,6 @@ public final class SavingsAccountSummary { final SavingsAccountTransaction savingsAccountTransaction = savingsAccountTransactions.get(i); if (savingsAccountTransaction.isInterestPostingAndNotReversed() && !savingsAccountTransaction.isReversalTransaction() && !isUpdated) { - setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount()); setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate()); isUpdated = true; if (!backdatedTxnsAllowedTill) { @@ -230,7 +226,6 @@ public final class SavingsAccountSummary { } if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction() && !isUpdated) { - setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount()); setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate()); isUpdated = true; if (!backdatedTxnsAllowedTill) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java index c40bf9d89..6d2db4080 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java @@ -39,6 +39,11 @@ public interface SavingsAccountTransactionRepository List findTransactionsAfterPivotDate(@Param("savingsAccount") SavingsAccount savingsAccount, @Param("transactionDate") LocalDate transactionDate); + @Lock(LockModeType.PESSIMISTIC_WRITE) + @Query("select st from SavingsAccountTransaction st where st.savingsAccount = :savingsAccount and st.dateOf = :date and st.reversalTransaction <> 1 and st.reversed <> 1 order by st.id") + List findTransactionRunningBalanceBeforePivotDate(@Param("savingsAccount") SavingsAccount savingsAccount, + @Param("date") LocalDate date); + @Lock(LockModeType.PESSIMISTIC_WRITE) List findBySavingsAccount(@Param("savingsAccount") SavingsAccount savingsAccount); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java index aadea8e85..3aab8ef0a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java @@ -703,7 +703,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); - + final Long relaxingDaysConfigForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate(); this.depositAccountTransactionDataValidator.validate(command, DepositAccountType.RECURRING_DEPOSIT); final SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository @@ -750,11 +750,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo if (savingsAccountTransaction.isDeposit()) { final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, paymentDetail, savingsAccountTransaction.getCreatedDate(), user, accountType); - transaction = account.deposit(transactionDTO, false, refNo.toString()); + transaction = account.deposit(transactionDTO, false, relaxingDaysConfigForPivotDate, refNo.toString()); } else { final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, paymentDetail, savingsAccountTransaction.getCreatedDate(), user, accountType); - transaction = account.withdraw(transactionDTO, true, false, refNo.toString()); + transaction = account.withdraw(transactionDTO, true, false, relaxingDaysConfigForPivotDate, refNo.toString()); } final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction); boolean isInterestTransfer = false; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 35f567556..648a4bd0d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -822,7 +822,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); - + final Long relaxingDaysConfigForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate(); final SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository .findOneByIdAndSavingsAccountId(transactionId, savingsId); if (savingsAccountTransaction == null) { @@ -882,9 +882,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi paymentDetail, savingsAccountTransaction.getCreatedDate(), user, accountType); UUID refNo = UUID.randomUUID(); if (savingsAccountTransaction.isDeposit()) { - transaction = account.deposit(transactionDTO, false, refNo.toString()); + transaction = account.deposit(transactionDTO, false, relaxingDaysConfigForPivotDate, refNo.toString()); } else { - transaction = account.withdraw(transactionDTO, true, false, refNo.toString()); + transaction = account.withdraw(transactionDTO, true, false, relaxingDaysConfigForPivotDate, refNo.toString()); } final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction); final LocalDate postInterestOnDate = null; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java index f0512f740..d12abc8a3 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java @@ -76,6 +76,8 @@ public class ClientSavingsIntegrationTest { private ResponseSpecification responseSpec; private RequestSpecification requestSpec; private SavingsAccountHelper savingsAccountHelper; + private SavingsProductHelper savingsProductHelper; + private SchedulerJobHelper scheduleJobHelper; @BeforeEach public void setup() { @@ -2820,9 +2822,7 @@ public class ClientSavingsIntegrationTest { @Test public void testAccountBalanceAndTransactionRunningBalanceWithConfigOn() { this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); - GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec, this.responseSpec, "38", false); - GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec, this.responseSpec, "39", true); - GlobalConfigurationHelper.updateValueForGlobalConfiguration(requestSpec, responseSpec, "39", "5"); + configurationForBackdatedTransaction(); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); @@ -2843,17 +2843,19 @@ public class ClientSavingsIntegrationTest { savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId); SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); - + LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy"); + String startDate = formatter.format(transactionDate); // withdrawal transaction 1 - Integer withdrawalTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500", - SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID); + Integer withdrawalTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500", startDate, + CommonConstants.RESPONSE_RESOURCE_ID); HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsId); Float balance = Float.parseFloat("-500.0"); assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is -500"); // withdrawal transaction 2 - withdrawalTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500", - SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID); + withdrawalTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500", startDate, + CommonConstants.RESPONSE_RESOURCE_ID); summary = this.savingsAccountHelper.getSavingsSummary(savingsId); balance = Float.parseFloat("-1000.0"); assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is -1000"); @@ -2866,6 +2868,155 @@ public class ClientSavingsIntegrationTest { assertEquals(balance.toString(), requestedTransaction.get("runningBalance").toString(), "Equality check for Balance"); } + @Test + public void testRunningBalanceAfterWithdrawalWithBackdateConfigurationOn() { + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + this.savingsProductHelper = new SavingsProductHelper(); + this.scheduleJobHelper = new SchedulerJobHelper(requestSpec); + configurationForBackdatedTransaction(); + LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy"); + String startDate = formatter.format(transactionDate); + String secondTrx = formatter.format(transactionDate.plusDays(1)); + final String jobName = "Post Interest For Savings"; + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); + Assertions.assertNotNull(clientID); + + final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, startDate); + this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", startDate, CommonConstants.RESPONSE_RESOURCE_ID); + this.scheduleJobHelper.executeAndAwaitJob(jobName); + this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "200", secondTrx, CommonConstants.RESPONSE_RESOURCE_ID); + HashMap summaryObj = this.savingsAccountHelper.getSavingsSummary(savingsId); + + assertEquals("-100.0822", summaryObj.get("availableBalance").toString(), "Equality check for Balance"); + } + + @Test + public void testRunningBalanceAfterDepositWithBackdateConfigurationOn() { + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + this.savingsProductHelper = new SavingsProductHelper(); + this.scheduleJobHelper = new SchedulerJobHelper(requestSpec); + configurationForBackdatedTransaction(); + LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy"); + String startDate = formatter.format(transactionDate); + String secondTrx = formatter.format(transactionDate.plusDays(1)); + final String jobName = "Post Interest For Savings"; + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); + Assertions.assertNotNull(clientID); + + final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, startDate); + this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "100", startDate, CommonConstants.RESPONSE_RESOURCE_ID); + this.scheduleJobHelper.executeAndAwaitJob(jobName); + this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", secondTrx, CommonConstants.RESPONSE_RESOURCE_ID); + HashMap summaryObj = this.savingsAccountHelper.getSavingsSummary(savingsId); + assertEquals("100.0822", summaryObj.get("availableBalance").toString(), "Equality check for Balance"); + } + + @Test + public void testRunningBalanceAfterWithdrawalReversalWithBackdateConfigurationOn() { + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + this.savingsProductHelper = new SavingsProductHelper(); + this.scheduleJobHelper = new SchedulerJobHelper(requestSpec); + configurationForBackdatedTransaction(); + LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy"); + String startDate = formatter.format(transactionDate); + String secondTrx = formatter.format(transactionDate.plusDays(1)); + final String jobName = "Post Interest For Savings"; + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); + Assertions.assertNotNull(clientID); + + final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, startDate); + this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", startDate, CommonConstants.RESPONSE_RESOURCE_ID); + this.scheduleJobHelper.executeAndAwaitJob(jobName); + + Integer withdrawalToReverse = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "200", secondTrx, + CommonConstants.RESPONSE_RESOURCE_ID); + this.savingsAccountHelper.reverseSavingsAccountTransaction(savingsId, withdrawalToReverse); + HashMap summaryObj = this.savingsAccountHelper.getSavingsSummary(savingsId); + + assertEquals("100.137", summaryObj.get("availableBalance").toString(), "Equality check for Balance"); + } + + @Test + public void testRunningBalanceAfterDepositReversalWithBackdateConfigurationOn() { + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + this.savingsProductHelper = new SavingsProductHelper(); + this.scheduleJobHelper = new SchedulerJobHelper(requestSpec); + configurationForBackdatedTransaction(); + LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy"); + String startDate = formatter.format(transactionDate); + String secondTrx = formatter.format(transactionDate.plusDays(1)); + final String jobName = "Post Interest For Savings"; + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); + Assertions.assertNotNull(clientID); + + final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, startDate); + this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "100", startDate, CommonConstants.RESPONSE_RESOURCE_ID); + this.scheduleJobHelper.executeAndAwaitJob(jobName); + Integer depositToReverse = (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", secondTrx, + CommonConstants.RESPONSE_RESOURCE_ID); + this.savingsAccountHelper.reverseSavingsAccountTransaction(savingsId, depositToReverse); + + HashMap summaryObj = this.savingsAccountHelper.getSavingsSummary(savingsId); + assertEquals("-100.137", summaryObj.get("availableBalance").toString(), "Equality check for Balance"); + } + + @Test + public void testToPerformTransactionBeforePivotDate() { + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + this.savingsProductHelper = new SavingsProductHelper(); + this.scheduleJobHelper = new SchedulerJobHelper(requestSpec); + + configurationForBackdatedTransaction(); + + String transactionDate = "1 July 2022"; + + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, transactionDate); + Assertions.assertNotNull(clientID); + + final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, transactionDate); + this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", transactionDate, CommonConstants.RESPONSE_RESOURCE_ID); + final String jobName = "Post Interest For Savings"; + this.scheduleJobHelper.executeAndAwaitJob(jobName); + final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(403).build(); + final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse); + List error = (List) validationErrorHelper.depositToSavingsAccount(savingsId, "3000", transactionDate, + CommonConstants.RESPONSE_ERROR); + + assertEquals("error.msg.savings.transaction.is.not.allowed", error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + } + + private Integer createSavingsAccountDailyPostingOverdraft(final Integer clientID, final String startDate) { + final Integer savingsProductID = createSavingsProductDailyPostingOverdraft(); + Assertions.assertNotNull(savingsProductID); + final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplicationOnDate(clientID, savingsProductID, + ACCOUNT_TYPE_INDIVIDUAL, startDate); + Assertions.assertNotNull(savingsId); + HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavingsOnDate(savingsId, startDate); + SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap); + savingsStatusHashMap = this.savingsAccountHelper.activateSavingsAccount(savingsId, startDate); + SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); + return savingsId; + } + + private Integer createSavingsProductDailyPostingOverdraft() { + final String overDraftLimit = "10000.0"; + final String nominalAnnualInterestRateOverdraft = "10"; + final String savingsProductJSON = this.savingsProductHelper.withInterestCompoundingPeriodTypeAsDaily() + .withInterestPostingPeriodTypeAsDaily().withInterestCalculationPeriodTypeAsDailyBalance() + .withOverDraftRate(overDraftLimit, nominalAnnualInterestRateOverdraft).build(); + return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); + } + + public void configurationForBackdatedTransaction() { + GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec, this.responseSpec, "38", false); + GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec, this.responseSpec, "39", true); + GlobalConfigurationHelper.updateValueForGlobalConfiguration(requestSpec, responseSpec, "39", "5"); + } + @AfterEach public void tearDown() { GlobalConfigurationHelper.resetAllDefaultGlobalConfigurations(this.requestSpec, this.responseSpec);