fineract-1652: Account Balance and Transaction running balance is wrong

This commit is contained in:
Dhaval Maniyar
2022-07-10 18:29:02 +05:30
parent 16aafdf95b
commit e4eb8afdf4
13 changed files with 281 additions and 128 deletions
@@ -78,7 +78,7 @@ public class SavingsAccountSummaryData implements Serializable {
this.interestNotPosted = interestNotPosted; this.interestNotPosted = interestNotPosted;
this.lastInterestCalculationDate = lastInterestCalculationDate; this.lastInterestCalculationDate = lastInterestCalculationDate;
this.availableBalance = availableBalance; this.availableBalance = availableBalance;
this.interestPostedTillDate = interestPostedTillDate == null ? lastInterestCalculationDate : interestPostedTillDate; this.interestPostedTillDate = interestPostedTillDate;
} }
public void setPrevInterestPostedTillDate(LocalDate interestPostedTillDate) { public void setPrevInterestPostedTillDate(LocalDate interestPostedTillDate) {
@@ -152,7 +152,7 @@ public class SavingsAccountSummaryData implements Serializable {
public void updateSummaryWithPivotConfig(final CurrencyData currency, final SavingsAccountTransactionSummaryWrapper wrapper, public void updateSummaryWithPivotConfig(final CurrencyData currency, final SavingsAccountTransactionSummaryWrapper wrapper,
final SavingsAccountTransaction transaction, final List<SavingsAccountTransactionData> savingsAccountTransactions) { final SavingsAccountTransaction transaction, final List<SavingsAccountTransactionData> savingsAccountTransactions) {
if (transaction != null) { if (transaction != null && !transaction.isReversalTransaction()) {
Money transactionAmount = Money.of(currency, transaction.getAmount()); Money transactionAmount = Money.of(currency, transaction.getAmount());
switch (SavingsAccountTransactionType.fromInt(transaction.getTypeOf())) { switch (SavingsAccountTransactionType.fromInt(transaction.getTypeOf())) {
case DEPOSIT: case DEPOSIT:
@@ -219,15 +219,17 @@ public class SavingsAccountSummaryData implements Serializable {
// boolean isUpdated = false; // boolean isUpdated = false;
Money interestTotal = Money.of(currency, this.totalInterestPosted); Money interestTotal = Money.of(currency, this.totalInterestPosted);
Money withHoldTaxTotal = Money.of(currency, this.totalWithholdTax); Money withHoldTaxTotal = Money.of(currency, this.totalWithholdTax);
Money overdraftInterestTotal = Money.of(currency, this.totalOverdraftInterestDerived);
final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal, final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal,
withHoldTaxTotal, currency); overdraftInterestTotal, withHoldTaxTotal, currency);
interestTotal = map.get("interestTotal"); interestTotal = map.get("interestTotal");
withHoldTaxTotal = map.get("withHoldTax"); withHoldTaxTotal = map.get("withHoldTax");
overdraftInterestTotal = map.get("overdraftInterestTotal");
this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero(); this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero();
this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero(); this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero();
this.totalOverdraftInterestDerived = overdraftInterestTotal.getAmountDefaultedToNullIfZero();
this.accountBalance = Money.of(currency, this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax) this.accountBalance = Money.of(currency, this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax)
.getAmount(); .minus(this.totalOverdraftInterestDerived).getAmount();
} }
} }
@@ -246,13 +248,23 @@ public class SavingsAccountSummaryData implements Serializable {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private HashMap<String, Money> updateRunningBalanceAndPivotDate(final boolean backdatedTxnsAllowedTill, private HashMap<String, Money> updateRunningBalanceAndPivotDate(final boolean backdatedTxnsAllowedTill,
final List<SavingsAccountTransactionData> savingsAccountTransactions, Money interestTotal, Money withHoldTaxTotal, final List<SavingsAccountTransactionData> savingsAccountTransactions, Money interestTotal, Money overdraftInterestTotal,
CurrencyData currency) { Money withHoldTaxTotal, CurrencyData currency) {
boolean isUpdated = false; boolean isUpdated = false;
HashMap<String, Money> map = new HashMap<>(); HashMap<String, Money> map = new HashMap<>();
for (int i = savingsAccountTransactions.size() - 1; i >= 0; i--) { for (int i = savingsAccountTransactions.size() - 1; i >= 0; i--) {
final SavingsAccountTransactionData savingsAccountTransaction = savingsAccountTransactions.get(i); final SavingsAccountTransactionData savingsAccountTransaction = savingsAccountTransactions.get(i);
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed() && !isUpdated) { if (savingsAccountTransaction.isInterestPostingAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
&& !isUpdated) {
setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount());
setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate());
isUpdated = true;
if (!backdatedTxnsAllowedTill) {
break;
}
}
if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
&& !isUpdated) {
setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount()); setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount());
setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate()); setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate());
isUpdated = true; isUpdated = true;
@@ -261,10 +273,12 @@ public class SavingsAccountSummaryData implements Serializable {
} }
} }
if (backdatedTxnsAllowedTill) { if (backdatedTxnsAllowedTill) {
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed()) { if (savingsAccountTransaction.isInterestPostingAndNotReversed()) {
interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount()); interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount());
} }
if (savingsAccountTransaction.isOverdraftInterestAndNotReversed()) {
overdraftInterestTotal = overdraftInterestTotal.plus(savingsAccountTransaction.getAmount());
}
if (savingsAccountTransaction.isWithHoldTaxAndNotReversed()) { if (savingsAccountTransaction.isWithHoldTaxAndNotReversed()) {
withHoldTaxTotal = withHoldTaxTotal.plus(savingsAccountTransaction.getAmount()); withHoldTaxTotal = withHoldTaxTotal.plus(savingsAccountTransaction.getAmount());
} }
@@ -273,6 +287,7 @@ public class SavingsAccountSummaryData implements Serializable {
if (backdatedTxnsAllowedTill) { if (backdatedTxnsAllowedTill) {
map.put("interestTotal", interestTotal); map.put("interestTotal", interestTotal);
map.put("withHoldTax", withHoldTaxTotal); map.put("withHoldTax", withHoldTaxTotal);
map.put("overdraftInterestTotal", overdraftInterestTotal);
} }
return map; return map;
} }
@@ -293,7 +308,7 @@ public class SavingsAccountSummaryData implements Serializable {
this.totalWithholdTax = wrapper.calculateTotalWithholdTaxWithdrawal(currency, transactions); this.totalWithholdTax = wrapper.calculateTotalWithholdTaxWithdrawal(currency, transactions);
// boolean isUpdated = false; // boolean isUpdated = false;
updateRunningBalanceAndPivotDate(false, transactions, null, null, currency); updateRunningBalanceAndPivotDate(false, transactions, null, null, null, currency);
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals) 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.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge)
@@ -191,19 +191,20 @@ public class FixedDepositAccount extends SavingsAccount {
public void updateMaturityDateAndAmountBeforeAccountActivation(final MathContext mc, final boolean isPreMatureClosure, public void updateMaturityDateAndAmountBeforeAccountActivation(final MathContext mc, final boolean isPreMatureClosure,
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
List<SavingsAccountTransaction> allTransactions = new ArrayList<>(); List<SavingsAccountTransaction> allTransactions = new ArrayList<>();
String refNo = null;
final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount()); final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount());
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null,
this.accountSubmittedOrActivationDate(), transactionAmountMoney, new Date(), null); // TODO: this.accountSubmittedOrActivationDate(), transactionAmountMoney, new Date(), null, refNo); // TODO:
// verify // verify
// if // if
// it // it
// is // is
// ok // ok
// to // to
// pass // pass
// null // null
// for // for
// AppUser // AppUser
transaction.updateRunningBalance(transactionAmountMoney); transaction.updateRunningBalance(transactionAmountMoney);
transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto()); transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto());
allTransactions.add(transaction); allTransactions.add(transaction);
@@ -528,8 +529,10 @@ public class FixedDepositAccount extends SavingsAccount {
final boolean isInterestTransfer = false; final boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null; final LocalDate postInterestOnDate = null;
final boolean backdatedTxnsAllowedTill = false; final boolean backdatedTxnsAllowedTill = false;
boolean postReversals = false;
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill,
postReversals);
Money interestPostedToDate = Money.zero(this.currency); Money interestPostedToDate = Money.zero(this.currency);
@@ -568,7 +571,7 @@ public class FixedDepositAccount extends SavingsAccount {
if (recalucateDailyBalanceDetails) { if (recalucateDailyBalanceDetails) {
// update existing transactions so derived balance fields are // update existing transactions so derived balance fields are
// correct. // correct.
recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate, backdatedTxnsAllowedTill); recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate, backdatedTxnsAllowedTill, postReversals);
} }
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
@@ -597,11 +600,11 @@ public class FixedDepositAccount extends SavingsAccount {
} }
recalucateDailyBalance = applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance, backdatedTxnsAllowedTill); recalucateDailyBalance = applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance, backdatedTxnsAllowedTill);
boolean postReversals = false;
if (recalucateDailyBalance) { if (recalucateDailyBalance) {
// update existing transactions so derived balance fields are // update existing transactions so derived balance fields are
// correct. // correct.
recalculateDailyBalances(Money.zero(this.currency), accountCloseDate, backdatedTxnsAllowedTill); recalculateDailyBalances(Money.zero(this.currency), accountCloseDate, backdatedTxnsAllowedTill, postReversals);
} }
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
this.accountTermAndPreClosure.updateMaturityDetails(this.getAccountBalance(), accountCloseDate); this.accountTermAndPreClosure.updateMaturityDetails(this.getAccountBalance(), accountCloseDate);
@@ -651,10 +654,10 @@ public class FixedDepositAccount extends SavingsAccount {
@Override @Override
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer, public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer,
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth, final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
final LocalDate postAsInterestOn, final boolean backdatedTxnsAllowedTill) { final LocalDate postAsInterestOn, final boolean backdatedTxnsAllowedTill, final boolean postReversals) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate); final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postAsInterestOn, backdatedTxnsAllowedTill); financialYearBeginningMonth, postAsInterestOn, backdatedTxnsAllowedTill, postReversals);
} }
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) { private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
@@ -382,6 +382,7 @@ public class RecurringDepositAccount extends SavingsAccount {
latestTransactionDate = installment.getTransactionLocalDate(); latestTransactionDate = installment.getTransactionLocalDate();
} }
} }
String refNo = null;
if (generateFutureTransactions) { if (generateFutureTransactions) {
for (RecurringDepositScheduleInstallment installment : depositScheduleInstallments()) { for (RecurringDepositScheduleInstallment installment : depositScheduleInstallments()) {
if (installment.isPrincipalNotCompleted(getCurrency())) { if (installment.isPrincipalNotCompleted(getCurrency())) {
@@ -391,7 +392,7 @@ public class RecurringDepositAccount extends SavingsAccount {
} }
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, dueDate, final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, dueDate,
installment.getDepositAmountOutstanding(getCurrency()), installment.getDepositAmountOutstanding(getCurrency()),
Date.from(installment.dueDate().atStartOfDay(ZoneId.systemDefault()).toInstant()), null); Date.from(installment.dueDate().atStartOfDay(ZoneId.systemDefault()).toInstant()), null, refNo);
allTransactions.add(transaction); allTransactions.add(transaction);
} }
} }
@@ -542,14 +543,16 @@ public class RecurringDepositAccount extends SavingsAccount {
protected void processAccountUponActivation(final DateTimeFormatter fmt, final AppUser user) { protected void processAccountUponActivation(final DateTimeFormatter fmt, final AppUser user) {
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance); final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
final boolean backdatedTxnsAllowedTill = false; final boolean backdatedTxnsAllowedTill = false;
String refNo = null;
if (minRequiredOpeningBalance.isGreaterThanZero()) { if (minRequiredOpeningBalance.isGreaterThanZero()) {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationLocalDate(), final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationLocalDate(),
minRequiredOpeningBalance.getAmount(), null, new Date(), user, accountType); minRequiredOpeningBalance.getAmount(), null, new Date(), user, accountType);
deposit(transactionDTO, backdatedTxnsAllowedTill); deposit(transactionDTO, backdatedTxnsAllowedTill, refNo);
// update existing transactions so derived balance fields are // update existing transactions so derived balance fields are
// correct. // correct.
recalculateDailyBalances(Money.zero(this.currency), DateUtils.getBusinessLocalDate(), backdatedTxnsAllowedTill); boolean postReversals = false;
recalculateDailyBalances(Money.zero(this.currency), DateUtils.getBusinessLocalDate(), backdatedTxnsAllowedTill, postReversals);
} }
} }
@@ -644,8 +647,10 @@ public class RecurringDepositAccount extends SavingsAccount {
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
final boolean backdatedTxnsAllowedTill = false; final boolean backdatedTxnsAllowedTill = false;
boolean postReversals = false;
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate.minusDays(1), isInterestTransfer, final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate.minusDays(1), isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill,
postReversals);
Money interestPostedToDate = Money.zero(this.currency); Money interestPostedToDate = Money.zero(this.currency);
@@ -681,7 +686,7 @@ public class RecurringDepositAccount extends SavingsAccount {
if (recalucateDailyBalanceDetails) { if (recalucateDailyBalanceDetails) {
// update existing transactions so derived balance fields are // update existing transactions so derived balance fields are
// correct. // correct.
recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate, backdatedTxnsAllowedTill); recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate, backdatedTxnsAllowedTill, postReversals);
} }
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
} }
@@ -710,11 +715,11 @@ public class RecurringDepositAccount extends SavingsAccount {
} }
applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance, backdatedTxnsAllowedTill); applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance, backdatedTxnsAllowedTill);
boolean postReversals = false;
if (recalucateDailyBalance) { if (recalucateDailyBalance) {
// update existing transactions so derived balance fields are // update existing transactions so derived balance fields are
// correct. // correct.
recalculateDailyBalances(Money.zero(this.currency), accountCloseDate, backdatedTxnsAllowedTill); recalculateDailyBalances(Money.zero(this.currency), accountCloseDate, backdatedTxnsAllowedTill, postReversals);
} }
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
@@ -764,10 +769,10 @@ public class RecurringDepositAccount extends SavingsAccount {
@Override @Override
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer, public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer,
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth, final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
final LocalDate postAsInterestOn, final boolean backdatedTxnsAllowedTill) { final LocalDate postAsInterestOn, final boolean backdatedTxnsAllowedTill, final boolean postReversals) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate); final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postAsInterestOn, backdatedTxnsAllowedTill); financialYearBeginningMonth, postAsInterestOn, backdatedTxnsAllowedTill, postReversals);
} }
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) { private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
@@ -839,7 +844,8 @@ public class RecurringDepositAccount extends SavingsAccount {
} }
@Override @Override
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill) { public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill,
final String refNo) {
if (isAccountMatured()) { if (isAccountMatured()) {
final String defaultUserMessage = "Transaction is not allowed. Account is matured."; final String defaultUserMessage = "Transaction is not allowed. Account is matured.";
@@ -877,7 +883,7 @@ public class RecurringDepositAccount extends SavingsAccount {
throw new PlatformApiDataValidationException(dataValidationErrors); throw new PlatformApiDataValidationException(dataValidationErrors);
} }
final SavingsAccountTransaction transaction = super.deposit(transactionDTO, backdatedTxnsAllowedTill); final SavingsAccountTransaction transaction = super.deposit(transactionDTO, backdatedTxnsAllowedTill, refNo);
return transaction; return transaction;
} }
@@ -514,7 +514,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth, final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill, final boolean postReversals) { final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill, final boolean postReversals) {
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill,
postReversals);
Money interestPostedToDate = Money.zero(this.currency); Money interestPostedToDate = Money.zero(this.currency);
@@ -628,7 +629,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
// update existing transactions so derived balance fields are // update existing transactions so derived balance fields are
// correct. // correct.
recalculateDailyBalances(openingAccountBalance, interestPostingUpToDate, backdatedTxnsAllowedTill); recalculateDailyBalances(openingAccountBalance, interestPostingUpToDate, backdatedTxnsAllowedTill, postReversals);
} }
if (!backdatedTxnsAllowedTill) { if (!backdatedTxnsAllowedTill) {
@@ -654,7 +655,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
final List<SavingsAccountTransaction> withholdTransactions = new ArrayList<>(); final List<SavingsAccountTransaction> withholdTransactions = new ArrayList<>();
List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig(); List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig();
for (final SavingsAccountTransaction transaction : trans) { for (final SavingsAccountTransaction transaction : trans) {
if (transaction.isWithHoldTaxAndNotReversed()) { if (transaction.isWithHoldTaxAndNotReversed() && !transaction.isReversalTransaction()) {
withholdTransactions.add(transaction); withholdTransactions.add(transaction);
} }
} }
@@ -670,7 +671,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
List<SavingsAccountTransaction> trans = getTransactions(); List<SavingsAccountTransaction> trans = getTransactions();
for (final SavingsAccountTransaction transaction : trans) { for (final SavingsAccountTransaction transaction : trans) {
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
&& transaction.occursOn(postingDate)) { && transaction.occursOn(postingDate) && !transaction.isReversalTransaction()) {
postingTransation = transaction; postingTransation = transaction;
break; break;
} }
@@ -683,7 +684,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig(); List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig();
for (final SavingsAccountTransaction transaction : trans) { for (final SavingsAccountTransaction transaction : trans) {
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
&& transaction.occursOn(postingDate)) { && transaction.occursOn(postingDate) && !transaction.isReversalTransaction()) {
postingTransation = transaction; postingTransation = transaction;
break; break;
} }
@@ -810,7 +811,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate, public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate,
boolean isInterestTransfer, final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth, boolean isInterestTransfer, final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill) { final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill, final boolean postReversals) {
// no openingBalance concept supported yet but probably will to allow // no openingBalance concept supported yet but probably will to allow
// for migrations. // for migrations.
@@ -825,7 +826,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
// update existing transactions so derived balance fields are // update existing transactions so derived balance fields are
// correct. // correct.
recalculateDailyBalances(openingAccountBalance, upToInterestCalculationDate, backdatedTxnsAllowedTill);
recalculateDailyBalances(openingAccountBalance, upToInterestCalculationDate, backdatedTxnsAllowedTill, postReversals);
// 1. default to calculate interest based on entire history OR // 1. default to calculate interest based on entire history OR
// 2. determine latest 'posting period' and find interest credited to // 2. determine latest 'posting period' and find interest credited to
@@ -931,7 +933,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) { for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) {
if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
&& transaction.isNotReversed()) { && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
orderedNonInterestPostingTransactions.add(transaction); orderedNonInterestPostingTransactions.add(transaction);
} }
} }
@@ -946,7 +948,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) { for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) {
if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
&& transaction.isNotReversed()) { && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
orderedNonInterestPostingTransactions.add(transaction); orderedNonInterestPostingTransactions.add(transaction);
} }
} }
@@ -972,7 +974,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
} }
protected void recalculateDailyBalances(final Money openingAccountBalance, final LocalDate interestPostingUpToDate, protected void recalculateDailyBalances(final Money openingAccountBalance, final LocalDate interestPostingUpToDate,
final boolean backdatedTxnsAllowedTill) { final boolean backdatedTxnsAllowedTill, boolean postReversals) {
Money runningBalance = openingAccountBalance.copy(); Money runningBalance = openingAccountBalance.copy();
@@ -1026,15 +1028,25 @@ public class SavingsAccount extends AbstractPersistableCustom {
.add(SavingsAccountChargePaidBy.instance(accountTransaction, x.getSavingsAccountCharge(), x.getAmount()))); .add(SavingsAccountChargePaidBy.instance(accountTransaction, x.getSavingsAccountCharge(), x.getAmount())));
accountTransaction.getSavingsAccountChargesPaid().addAll(newChargePaidBy); accountTransaction.getSavingsAccountChargesPaid().addAll(newChargePaidBy);
} }
SavingsAccountTransaction reversal = null;
transaction.reverse(); transaction.reverse();
if (postReversals) {
reversal = SavingsAccountTransaction.reversal(transaction);
}
if (overdraftAmount.isGreaterThanZero()) { if (overdraftAmount.isGreaterThanZero()) {
accountTransaction.updateOverdraftAmount(overdraftAmount.getAmount()); accountTransaction.updateOverdraftAmount(overdraftAmount.getAmount());
} }
// accountTransaction.updateRunningBalance(runningBalance); // accountTransaction.updateRunningBalance(runningBalance);
if (backdatedTxnsAllowedTill) { if (backdatedTxnsAllowedTill) {
addTransactionToExisting(accountTransaction); addTransactionToExisting(accountTransaction);
if (reversal != null) {
addTransactionToExisting(reversal);
}
} else { } else {
addTransaction(accountTransaction); addTransaction(accountTransaction);
if (reversal != null) {
addTransaction(reversal);
}
} }
isTransactionsModified = true; isTransactionsModified = true;
} }
@@ -1058,7 +1070,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
LocalDate endOfBalanceDate = interestPostingUpToDate; LocalDate endOfBalanceDate = interestPostingUpToDate;
for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) { for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) {
final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i); final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i);
if (transaction.isNotReversed() if (transaction.isNotReversed() && !transaction.isReversalTransaction()
&& !(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())) { && !(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())) {
transaction.updateCumulativeBalanceAndDates(this.currency, endOfBalanceDate); transaction.updateCumulativeBalanceAndDates(this.currency, endOfBalanceDate);
// this transactions transaction date is end of balance date for // this transactions transaction date is end of balance date for
@@ -1068,17 +1080,19 @@ public class SavingsAccount extends AbstractPersistableCustom {
} }
} }
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill) { public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill,
return deposit(transactionDTO, SavingsAccountTransactionType.DEPOSIT, backdatedTxnsAllowedTill); final String refNo) {
return deposit(transactionDTO, SavingsAccountTransactionType.DEPOSIT, backdatedTxnsAllowedTill, refNo);
} }
public SavingsAccountTransaction dividendPayout(final SavingsAccountTransactionDTO transactionDTO, public SavingsAccountTransaction dividendPayout(final SavingsAccountTransactionDTO transactionDTO,
final boolean backdatedTxnsAllowedTill) { final boolean backdatedTxnsAllowedTill) {
return deposit(transactionDTO, SavingsAccountTransactionType.DIVIDEND_PAYOUT, backdatedTxnsAllowedTill); String refNo = null;
return deposit(transactionDTO, SavingsAccountTransactionType.DIVIDEND_PAYOUT, backdatedTxnsAllowedTill, refNo);
} }
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO,
final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill) { final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill, final String refNo) {
final String resourceTypeName = depositAccountType().resourceName(); final String resourceTypeName = depositAccountType().resourceName();
if (isNotActive()) { if (isNotActive()) {
final String defaultUserMessage = "Transaction is not allowed. Account is not active."; final String defaultUserMessage = "Transaction is not allowed. Account is not active.";
@@ -1122,7 +1136,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, office(), transactionDTO.getPaymentDetail(), final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, office(), transactionDTO.getPaymentDetail(),
transactionDTO.getTransactionDate(), amount, transactionDTO.getCreatedDate(), transactionDTO.getAppUser(), transactionDTO.getTransactionDate(), amount, transactionDTO.getCreatedDate(), transactionDTO.getAppUser(),
savingsAccountTransactionType); savingsAccountTransactionType, refNo);
if (backdatedTxnsAllowedTill) { if (backdatedTxnsAllowedTill) {
addTransactionToExisting(transaction); addTransactionToExisting(transaction);
@@ -1251,6 +1265,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
|| this.sub_status.equals(SavingsAccountSubStatusEnum.DORMANT.getValue())) { || this.sub_status.equals(SavingsAccountSubStatusEnum.DORMANT.getValue())) {
this.sub_status = SavingsAccountSubStatusEnum.NONE.getValue(); this.sub_status = SavingsAccountSubStatusEnum.NONE.getValue();
} }
if (backdatedTxnsAllowedTill) {
this.summary.updateSummaryWithPivotConfig(this.currency, this.savingsAccountTransactionSummaryWrapper, transaction,
this.savingsAccountTransactions);
}
return transaction; return transaction;
} }
@@ -1375,7 +1393,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
if (!backdatedTxnsAllowedTill) { if (!backdatedTxnsAllowedTill) {
for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) { for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
&& transaction.isAfter(transactionDate)) { && transaction.isAfter(transactionDate) && !transaction.isReversalTransaction()) {
transactionBeforeLastInterestPosting = true; transactionBeforeLastInterestPosting = true;
break; break;
} }
@@ -2760,15 +2778,15 @@ public class SavingsAccount extends AbstractPersistableCustom {
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestAsOnDate = null; LocalDate postInterestAsOnDate = null;
boolean postReversals = false;
if (this.isBeforeLastPostingPeriod(getActivationLocalDate(), backdatedTxnsAllowedTill)) { if (this.isBeforeLastPostingPeriod(getActivationLocalDate(), backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
this.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, this.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestAsOnDate, backdatedTxnsAllowedTill, postReversals); postInterestAsOnDate, backdatedTxnsAllowedTill, postReversals);
} else { } else {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
this.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, this.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestAsOnDate, backdatedTxnsAllowedTill); financialYearBeginningMonth, postInterestAsOnDate, backdatedTxnsAllowedTill, postReversals);
} }
} }
} }
@@ -3513,7 +3531,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
refNo.toString()); refNo.toString());
} }
} }
recalculateDailyBalances(Money.zero(this.currency), transactionDate, backdatedTxnsAllowedTill); boolean postReversals = false;
recalculateDailyBalances(Money.zero(this.currency), transactionDate, backdatedTxnsAllowedTill, postReversals);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
} }
@@ -3532,7 +3551,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
SavingsAccountTransaction transaction = SavingsAccountTransaction.escheat(this, transactionDate, appUser, postInterestAsOnDate); SavingsAccountTransaction transaction = SavingsAccountTransaction.escheat(this, transactionDate, appUser, postInterestAsOnDate);
this.transactions.add(transaction); this.transactions.add(transaction);
} }
recalculateDailyBalances(Money.zero(this.currency), transactionDate, false); boolean postReversals = false;
recalculateDailyBalances(Money.zero(this.currency), transactionDate, false, postReversals);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
} }
@@ -361,6 +361,11 @@ public class SavingsAccountAssembler {
// Update transient variable // Update transient variable
account.setSavingsAccountTransactions(savingsAccountTransactions); 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 { } else {
savingsAccountTransactions = this.savingsAccountRepository.findAllTransactions(account); savingsAccountTransactions = this.savingsAccountRepository.findAllTransactions(account);
account.setSavingsAccountTransactions(savingsAccountTransactions); account.setSavingsAccountTransactions(savingsAccountTransactions);
@@ -368,10 +373,11 @@ public class SavingsAccountAssembler {
} }
// Update last running balance on account level // Update last running balance on account level
if (savingsAccountTransactions != null) { // if (savingsAccountTransactions != null && !savingsAccountTransactions.isEmpty()) {
account.getSummary().setRunningBalanceOnPivotDate(savingsAccountTransactions.get(savingsAccountTransactions.size() - 1) // account.getSummary().setRunningBalanceOnPivotDate(savingsAccountTransactions.get(savingsAccountTransactions.size()
.getRunningBalance(account.getCurrency()).getAmount()); // - 1)
} // .getRunningBalance(account.getCurrency()).getAmount());
// }
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
return account; return account;
@@ -380,7 +386,8 @@ public class SavingsAccountAssembler {
public SavingsAccountData assembleSavings(final SavingsAccountData account) { public SavingsAccountData assembleSavings(final SavingsAccountData account) {
// Update last running balance on account level // Update last running balance on account level
if (account.getTransactions() != null && account.getTransactions().size() != 0) { if (account.getTransactions() != null && account.getTransactions().size() != 0
&& account.getSummary().getInterestPostedTillDate() != null) {
account.getSummary().setRunningBalanceOnPivotDate(account.getTransactions().get(account.getTransactions().size() - 1) account.getSummary().setRunningBalanceOnPivotDate(account.getTransactions().get(account.getTransactions().size() - 1)
.getRunningBalance(account.getCurrency()).getAmount()); .getRunningBalance(account.getCurrency()).getAmount());
} }
@@ -115,13 +115,14 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) { if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
boolean postReversals = false;
account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer(), isSavingsInterestPostingAtCurrentPeriodEnd, account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer(), isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals); financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} else { } else {
account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer(), account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer(),
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill,
postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
@@ -191,18 +192,20 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
Integer accountType = null; Integer accountType = null;
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, new Date(), user, accountType); paymentDetail, new Date(), user, accountType);
final SavingsAccountTransaction deposit = account.deposit(transactionDTO, savingsAccountTransactionType, backdatedTxnsAllowedTill); UUID refNo = UUID.randomUUID();
final SavingsAccountTransaction deposit = account.deposit(transactionDTO, savingsAccountTransactionType, backdatedTxnsAllowedTill,
refNo.toString());
final LocalDate postInterestOnDate = null; final LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) { if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, backdatedTxnsAllowedTill, postReversals); postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} else { } else {
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} }
saveTransactionToGenerateTransactionId(deposit); saveTransactionToGenerateTransactionId(deposit);
@@ -316,20 +319,22 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode()); final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
for (SavingsAccountTransaction savingsAccountTransaction : savingsAccountTransactions) { for (SavingsAccountTransaction savingsAccountTransaction : savingsAccountTransactions) {
boolean postReversals = true;
if (savingsAccountTransaction.isPostInterestCalculationRequired() if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), backdatedTxnsAllowedTill)) { && account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), backdatedTxnsAllowedTill)) {
boolean postReversals = true;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, backdatedTxnsAllowedTill, postReversals); postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} else { } else {
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} }
account.validateAccountBalanceDoesNotBecomeNegativeMinimal(savingsAccountTransaction.getAmount(), false); account.validateAccountBalanceDoesNotBecomeNegativeMinimal(savingsAccountTransaction.getAmount(), false);
account.activateAccountBasedOnBalance(); account.activateAccountBasedOnBalance();
} }
this.savingsAccountRepository.save(account); this.savingsAccountRepository.save(account);
newTransactions.addAll(account.getSavingsAccountTransactionsWithPivotConfig());
this.savingsAccountTransactionRepository.saveAll(newTransactions); this.savingsAccountTransactionRepository.saveAll(newTransactions);
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false, backdatedTxnsAllowedTill); postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false, backdatedTxnsAllowedTill);
@@ -113,7 +113,7 @@ public final class SavingsAccountSummary {
this.totalWithholdTax = wrapper.calculateTotalWithholdTaxWithdrawal(currency, transactions); this.totalWithholdTax = wrapper.calculateTotalWithholdTaxWithdrawal(currency, transactions);
// boolean isUpdated = false; // boolean isUpdated = false;
updateRunningBalanceAndPivotDate(false, transactions, null, null, currency); updateRunningBalanceAndPivotDate(false, transactions, null, null, null, currency);
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals) 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.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge)
@@ -189,30 +189,53 @@ public final class SavingsAccountSummary {
} }
} else { } else {
// boolean isUpdated = false; // boolean isUpdated = false;
Money interestTotal = Money.of(currency, this.totalInterestPosted); Money interestTotal = Money.zero(currency);
Money withHoldTaxTotal = Money.of(currency, this.totalWithholdTax); Money withHoldTaxTotal = Money.zero(currency);
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<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal, final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal,
withHoldTaxTotal, currency); overdraftInterestTotal, withHoldTaxTotal, currency);
interestTotal = map.get("interestTotal"); interestTotal = map.get("interestTotal");
withHoldTaxTotal = map.get("withHoldTax"); withHoldTaxTotal = map.get("withHoldTax");
overdraftInterestTotal = map.get("overdraftInterestTotal");
this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero(); this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero();
this.totalOverdraftInterestDerived = overdraftInterestTotal.getAmountDefaultedToNullIfZero();
this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero(); this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero();
this.accountBalance = Money.of(currency, this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax) this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
.getAmount(); .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();
} }
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private HashMap<String, Money> updateRunningBalanceAndPivotDate(final boolean backdatedTxnsAllowedTill, private HashMap<String, Money> updateRunningBalanceAndPivotDate(final boolean backdatedTxnsAllowedTill,
final List<SavingsAccountTransaction> savingsAccountTransactions, Money interestTotal, Money withHoldTaxTotal, final List<SavingsAccountTransaction> savingsAccountTransactions, Money interestTotal, Money overdraftInterestTotal,
MonetaryCurrency currency) { Money withHoldTaxTotal, MonetaryCurrency currency) {
boolean isUpdated = false; boolean isUpdated = false;
HashMap<String, Money> map = new HashMap<>(); HashMap<String, Money> map = new HashMap<>();
for (int i = savingsAccountTransactions.size() - 1; i >= 0; i--) { for (int i = savingsAccountTransactions.size() - 1; i >= 0; i--) {
final SavingsAccountTransaction savingsAccountTransaction = savingsAccountTransactions.get(i); final SavingsAccountTransaction savingsAccountTransaction = savingsAccountTransactions.get(i);
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed() if (savingsAccountTransaction.isInterestPostingAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
&& !savingsAccountTransaction.isReversalTransaction() && !isUpdated) { && !isUpdated) {
setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount());
setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate());
isUpdated = true;
if (!backdatedTxnsAllowedTill) {
break;
}
}
if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
&& !isUpdated) {
setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount()); setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount());
setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate()); setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate());
isUpdated = true; isUpdated = true;
@@ -225,8 +248,10 @@ public final class SavingsAccountSummary {
&& !savingsAccountTransaction.isReversalTransaction()) { && !savingsAccountTransaction.isReversalTransaction()) {
interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount(currency)); interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount(currency));
} }
if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()) {
if (savingsAccountTransaction.isWithHoldTaxAndNotReversed()) { overdraftInterestTotal = overdraftInterestTotal.plus(savingsAccountTransaction.getAmount());
}
if (savingsAccountTransaction.isWithHoldTaxAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()) {
withHoldTaxTotal = withHoldTaxTotal.plus(savingsAccountTransaction.getAmount(currency)); withHoldTaxTotal = withHoldTaxTotal.plus(savingsAccountTransaction.getAmount(currency));
} }
} }
@@ -234,6 +259,7 @@ public final class SavingsAccountSummary {
if (backdatedTxnsAllowedTill) { if (backdatedTxnsAllowedTill) {
map.put("interestTotal", interestTotal); map.put("interestTotal", interestTotal);
map.put("withHoldTax", withHoldTaxTotal); map.put("withHoldTax", withHoldTaxTotal);
map.put("overdraftInterestTotal", overdraftInterestTotal);
} }
return map; return map;
} }
@@ -153,22 +153,21 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
} }
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office, public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser) { final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser,
final String refNo) {
final boolean isReversed = false; final boolean isReversed = false;
final boolean isManualTransaction = false; final boolean isManualTransaction = false;
final Boolean lienTransaction = false; final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date, return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date,
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo); createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
} }
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office, public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser, final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser,
final SavingsAccountTransactionType savingsAccountTransactionType) { final SavingsAccountTransactionType savingsAccountTransactionType, final String refNo) {
final boolean isReversed = false; final boolean isReversed = false;
final boolean isManualTransaction = false; final boolean isManualTransaction = false;
final Boolean lienTransaction = false; final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, savingsAccountTransactionType.getValue(), date, return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, savingsAccountTransactionType.getValue(), date,
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo); createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
} }
@@ -239,6 +239,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
} }
final boolean isInterestTransfer = false; final boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null; final LocalDate postInterestOnDate = null;
final boolean postReversals = false;
if (activationChargeAmount.isGreaterThanZero()) { if (activationChargeAmount.isGreaterThanZero()) {
payActivationCharge(account, user); payActivationCharge(account, user);
} }
@@ -249,7 +250,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
} else { } else {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
@@ -366,6 +367,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
account.updateOverduePayments(overdueUptoDate); account.updateOverduePayments(overdueUptoDate);
final boolean isInterestTransfer = false; final boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null; final LocalDate postInterestOnDate = null;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate(), false)) { if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate(), false)) {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
@@ -373,7 +375,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
} else { } else {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -521,11 +523,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
checkClientOrGroupActive(account); checkClientOrGroupActive(account);
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode()); final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
this.savingAccountRepositoryWrapper.save(account); this.savingAccountRepositoryWrapper.save(account);
@@ -643,13 +646,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
checkClientOrGroupActive(account); checkClientOrGroupActive(account);
boolean postReversals = false;
if (savingsAccountTransaction.isPostInterestCalculationRequired() if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) { && account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false); postInterestOnDate, false);
} else { } else {
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -746,7 +750,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
if (savingsAccountTransaction.isDeposit()) { if (savingsAccountTransaction.isDeposit()) {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType); paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
transaction = account.deposit(transactionDTO, false); transaction = account.deposit(transactionDTO, false, refNo.toString());
} else { } else {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType); paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
@@ -755,13 +759,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction); final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null; final LocalDate postInterestOnDate = null;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, false) if (account.isBeforeLastPostingPeriod(transactionDate, false)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) { || account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false); postInterestOnDate, false);
} else { } else {
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -983,8 +988,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
boolean postReversals = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
this.savingsAccountTransactionRepository.save(newTransferTransaction); this.savingsAccountTransactionRepository.save(newTransferTransaction);
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
@@ -1014,11 +1020,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.office(), transferDate, user); savingsAccount.office(), transferDate, user);
savingsAccount.addTransaction(withdrawtransferTransaction); savingsAccount.addTransaction(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
boolean postReversals = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction); this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
@@ -1059,10 +1066,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.reassignSavingsOfficer(fieldOfficer, transferDate); savingsAccount.reassignSavingsOfficer(fieldOfficer, transferDate);
} }
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
boolean postReversals = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
this.savingsAccountTransactionRepository.save(acceptTransferTransaction); this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
@@ -1215,15 +1223,15 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), false)) { if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), false)) {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals); postInterestOnDate, false, postReversals);
} else { } else {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -1355,15 +1363,15 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, false)) { if (account.isBeforeLastPostingPeriod(transactionDate, false)) {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals); postInterestOnDate, false, postReversals);
} else { } else {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -422,11 +422,10 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
Money runningBalance = openingAccountBalance.copy(); Money runningBalance = openingAccountBalance.copy();
List<SavingsAccountTransactionData> accountTransactionsSorted = retreiveListOfTransactions(savingsAccountData); List<SavingsAccountTransactionData> accountTransactionsSorted = retreiveListOfTransactions(savingsAccountData);
boolean isTransactionsModified = false; boolean isTransactionsModified = false;
for (final SavingsAccountTransactionData transaction : accountTransactionsSorted) { for (final SavingsAccountTransactionData transaction : accountTransactionsSorted) {
if (transaction.isReversed()) { if (transaction.isReversed() || transaction.isReversalTransaction()) {
transaction.zeroBalanceFields(); transaction.zeroBalanceFields();
} else { } else {
Money overdraftAmount = Money.zero(savingsAccountData.currency()); Money overdraftAmount = Money.zero(savingsAccountData.currency());
@@ -515,9 +515,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode()); final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null; final LocalDate postInterestOnDate = null;
boolean postReversals = false;
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
if (backdatedTxnsAllowedTill) { if (backdatedTxnsAllowedTill) {
this.savingsAccountTransactionRepository.saveAll(account.getSavingsAccountTransactionsWithPivotConfig()); this.savingsAccountTransactionRepository.saveAll(account.getSavingsAccountTransactionsWithPivotConfig());
@@ -787,15 +787,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
} }
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
boolean postReversals = false;
checkClientOrGroupActive(account); checkClientOrGroupActive(account);
if (savingsAccountTransaction.isPostInterestCalculationRequired() if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) { && account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals); postInterestOnDate, false, postReversals);
} else { } else {
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -882,22 +882,22 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
Integer accountType = null; Integer accountType = null;
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType); paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
UUID refNo = UUID.randomUUID();
if (savingsAccountTransaction.isDeposit()) { if (savingsAccountTransaction.isDeposit()) {
transaction = account.deposit(transactionDTO, false); transaction = account.deposit(transactionDTO, false, refNo.toString());
} else { } else {
UUID refNo = UUID.randomUUID();
transaction = account.withdraw(transactionDTO, true, false, refNo.toString()); transaction = account.withdraw(transactionDTO, true, false, refNo.toString());
} }
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction); final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
final LocalDate postInterestOnDate = null; final LocalDate postInterestOnDate = null;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, false) if (account.isBeforeLastPostingPeriod(transactionDate, false)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) { || account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals); postInterestOnDate, false, postReversals);
} else { } else {
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -1079,8 +1079,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
boolean postReversals = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
this.savingsAccountTransactionRepository.save(newTransferTransaction); this.savingsAccountTransactionRepository.save(newTransferTransaction);
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
@@ -1110,8 +1111,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
boolean postReversals = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction); this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
@@ -1152,8 +1154,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
boolean postReversals = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false); financialYearBeginningMonth, postInterestOnDate, false, postReversals);
this.savingsAccountTransactionRepository.save(acceptTransferTransaction); this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
@@ -1322,15 +1325,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), backdatedTxnsAllowedTill)) { if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, backdatedTxnsAllowedTill, postReversals); postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} else { } else {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
@@ -1475,15 +1478,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null; LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) { if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, isInterestTransfer, postReversals); postInterestOnDate, isInterestTransfer, postReversals);
} else { } else {
final LocalDate today = DateUtils.getBusinessLocalDate(); final LocalDate today = DateUtils.getBusinessLocalDate();
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill); financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} }
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) { if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
@@ -253,14 +253,20 @@ public class SavingsSchedularInterestPoster implements Callable<Void> {
List<String> transRefNo = new ArrayList<>(); List<String> transRefNo = new ArrayList<>();
for (SavingsAccountData savingsAccountData : savingsAccountDataList) { for (SavingsAccountData savingsAccountData : savingsAccountDataList) {
SavingsAccountSummaryData savingsAccountSummaryData = savingsAccountData.getSummary(); SavingsAccountSummaryData savingsAccountSummaryData = savingsAccountData.getSummary();
paramsForSavingsSummary paramsForSavingsSummary.add(new Object[] { savingsAccountSummaryData.getTotalDeposits(),
.add(new Object[] { savingsAccountSummaryData.getTotalDeposits(), savingsAccountSummaryData.getTotalWithdrawals(), savingsAccountSummaryData.getTotalWithdrawals(), savingsAccountSummaryData.getTotalInterestEarned(),
savingsAccountSummaryData.getTotalInterestEarned(), savingsAccountSummaryData.getTotalInterestPosted(), savingsAccountSummaryData.getTotalInterestPosted(), savingsAccountSummaryData.getTotalWithdrawalFees(),
savingsAccountSummaryData.getTotalWithdrawalFees(), savingsAccountSummaryData.getTotalFeeCharge(), savingsAccountSummaryData.getTotalFeeCharge(), savingsAccountSummaryData.getTotalPenaltyCharge(),
savingsAccountSummaryData.getTotalPenaltyCharge(), savingsAccountSummaryData.getTotalAnnualFees(), savingsAccountSummaryData.getTotalAnnualFees(), savingsAccountSummaryData.getAccountBalance(),
savingsAccountSummaryData.getAccountBalance(), savingsAccountSummaryData.getTotalOverdraftInterestDerived(), savingsAccountSummaryData.getTotalOverdraftInterestDerived(), savingsAccountSummaryData.getTotalWithholdTax(),
savingsAccountSummaryData.getTotalWithholdTax(), savingsAccountSummaryData.getLastInterestCalculationDate(), Date.from(savingsAccountSummaryData.getLastInterestCalculationDate().atStartOfDay(DateUtils.getDateTimeZoneOfTenant())
savingsAccountSummaryData.getInterestPostedTillDate(), savingsAccountData.getId() }); .toInstant()),
savingsAccountSummaryData.getInterestPostedTillDate() != null
? Date.from(savingsAccountSummaryData.getInterestPostedTillDate()
.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant())
: Date.from(savingsAccountSummaryData.getLastInterestCalculationDate()
.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()),
savingsAccountData.getId() });
List<SavingsAccountTransactionData> savingsAccountTransactionDataList = savingsAccountData.getSavingsAccountTransactionData(); List<SavingsAccountTransactionData> savingsAccountTransactionDataList = savingsAccountData.getSavingsAccountTransactionData();
for (SavingsAccountTransactionData savingsAccountTransactionData : savingsAccountTransactionDataList) { for (SavingsAccountTransactionData savingsAccountTransactionData : savingsAccountTransactionDataList) {
if (savingsAccountTransactionData.getId() == null) { if (savingsAccountTransactionData.getId() == null) {
@@ -287,7 +293,7 @@ public class SavingsSchedularInterestPoster implements Callable<Void> {
if (transRefNo.size() > 0) { if (transRefNo.size() > 0) {
this.jdbcTemplate.batchUpdate(queryForSavingsUpdate, paramsForSavingsSummary); this.jdbcTemplate.batchUpdate(queryForSavingsUpdate, paramsForSavingsSummary);
this.jdbcTemplate.batchUpdate(queryForTransactionInsertion, paramsForTransactionInsertion); this.jdbcTemplate.batchUpdate(queryForTransactionInsertion, paramsForTransactionInsertion);
LOG.info("`Total No Of Interest Posting:` {}", transRefNo.size());
List<SavingsAccountTransactionData> savingsAccountTransactionDataList = fetchTransactionsFromIds(transRefNo); List<SavingsAccountTransactionData> savingsAccountTransactionDataList = fetchTransactionsFromIds(transRefNo);
if (savingsAccountDataList != null) { if (savingsAccountDataList != null) {
LOG.info("Fetched Transactions from DB: {}", savingsAccountTransactionDataList.size()); LOG.info("Fetched Transactions from DB: {}", savingsAccountTransactionDataList.size());
@@ -52,6 +52,7 @@ import org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper;
import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper; import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
import org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker; import org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -2815,4 +2816,59 @@ public class ClientSavingsIntegrationTest {
balance = Float.parseFloat("900.0"); balance = Float.parseFloat("900.0");
assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is 900"); assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is 900");
} }
@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");
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String minBalanceForInterestCalculation = null;
final String minRequiredBalance = "0";
final String enforceMinRequiredBalance = "false";
final boolean allowOverdraft = true;
final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, "0", minBalanceForInterestCalculation,
minRequiredBalance, enforceMinRequiredBalance, allowOverdraft);
Assertions.assertNotNull(savingsProductID);
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL);
Assertions.assertNotNull(savingsId);
HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsId);
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId);
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
// withdrawal transaction 1
Integer withdrawalTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500",
SavingsAccountHelper.TRANSACTION_DATE, 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);
summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
balance = Float.parseFloat("-1000.0");
assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is -1000");
// Check for last transactions running balance
Object transactionObj = this.savingsAccountHelper.getSavingsDetails(savingsId, "transactions");
ArrayList<HashMap<String, Object>> transactions = (ArrayList<HashMap<String, Object>>) transactionObj;
HashMap<String, Object> requestedTransaction = transactions.get(transactions.size() - 2);
balance = Float.parseFloat("-1000.0");
assertEquals(balance.toString(), requestedTransaction.get("runningBalance").toString(), "Equality check for Balance");
}
@AfterEach
public void tearDown() {
GlobalConfigurationHelper.resetAllDefaultGlobalConfigurations(this.requestSpec, this.responseSpec);
GlobalConfigurationHelper.verifyAllDefaultGlobalConfigurations(this.requestSpec, this.responseSpec);
}
} }