FINERACT-1646-backdated-transaction-available-balance-fix
This commit is contained in:
committed by
Aleksandar Vidakovic
parent
c9be0a2816
commit
c21ea4e1d3
+10
@@ -116,6 +116,8 @@ public final class SavingsAccountData implements Serializable {
|
|||||||
private final BigDecimal minOverdraftForInterestCalculation;
|
private final BigDecimal minOverdraftForInterestCalculation;
|
||||||
private transient List<SavingsAccountTransactionData> savingsAccountTransactionData = new ArrayList<>();
|
private transient List<SavingsAccountTransactionData> savingsAccountTransactionData = new ArrayList<>();
|
||||||
|
|
||||||
|
private transient SavingsAccountTransactionData lastSavingsAccountTransaction;
|
||||||
|
|
||||||
private List<DatatableData> datatables = null;
|
private List<DatatableData> datatables = null;
|
||||||
|
|
||||||
// import field
|
// import field
|
||||||
@@ -1104,4 +1106,12 @@ public final class SavingsAccountData implements Serializable {
|
|||||||
public Set<Long> getExistingReversedTransactionIds() {
|
public Set<Long> getExistingReversedTransactionIds() {
|
||||||
return this.existingReversedTransactionIds;
|
return this.existingReversedTransactionIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SavingsAccountTransactionData getLastSavingsAccountTransaction() {
|
||||||
|
return lastSavingsAccountTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastSavingsAccountTransaction(SavingsAccountTransactionData lastSavingsAccountTransaction) {
|
||||||
|
this.lastSavingsAccountTransaction = lastSavingsAccountTransaction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -223,16 +223,23 @@ public class SavingsAccountSummaryData implements Serializable {
|
|||||||
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);
|
Money overdraftInterestTotal = Money.of(currency, this.totalOverdraftInterestDerived);
|
||||||
|
this.totalDeposits = wrapper.calculateTotalDeposits(currency, savingsAccountTransactions);
|
||||||
|
this.totalWithdrawals = wrapper.calculateTotalWithdrawals(currency, savingsAccountTransactions);
|
||||||
final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal,
|
final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal,
|
||||||
overdraftInterestTotal, 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");
|
overdraftInterestTotal = map.get("overdraftInterestTotal");
|
||||||
|
BigDecimal deltaInterest = interestTotal.minus(this.totalInterestPosted).getAmountDefaultedToNullIfZero();
|
||||||
|
BigDecimal deltaWithholdTax = withHoldTaxTotal.minus(this.totalWithholdTax).getAmountDefaultedToNullIfZero();
|
||||||
|
BigDecimal deltaOverdraftInterestDerived = overdraftInterestTotal.minus(this.totalOverdraftInterestDerived)
|
||||||
|
.getAmountDefaultedToNullIfZero();
|
||||||
this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero();
|
this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero();
|
||||||
this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero();
|
this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero();
|
||||||
this.totalOverdraftInterestDerived = overdraftInterestTotal.getAmountDefaultedToNullIfZero();
|
this.totalOverdraftInterestDerived = overdraftInterestTotal.getAmountDefaultedToNullIfZero();
|
||||||
this.accountBalance = Money.of(currency, this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax)
|
this.accountBalance = getRunningBalanceOnPivotDate();
|
||||||
.minus(this.totalOverdraftInterestDerived).getAmount();
|
this.accountBalance = Money.of(currency, this.accountBalance).plus(Money.of(currency, this.totalDeposits)).plus(deltaInterest)
|
||||||
|
.minus(this.totalWithdrawals).minus(deltaWithholdTax).minus(deltaOverdraftInterestDerived).getAmount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-5
@@ -48,6 +48,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdraw
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -74,6 +75,7 @@ import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
|||||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
|
||||||
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
||||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -381,12 +383,25 @@ 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
|
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
|
||||||
&& account.getSummary().getInterestPostedTillDate() != null) {
|
if (backdatedTxnsAllowedTill && account.getTransactions() != null && account.getSummary().getInterestPostedTillDate() != null) {
|
||||||
account.getSummary().setRunningBalanceOnPivotDate(account.getTransactions().get(account.getTransactions().size() - 1)
|
List<SavingsAccountTransactionData> removalList = new ArrayList<>();
|
||||||
.getRunningBalance(account.getCurrency()).getAmount());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (int i = 0; i < account.getTransactions().size(); i++) {
|
||||||
|
SavingsAccountTransactionData savingsAccountTransaction = account.getTransactions().get(i);
|
||||||
|
removalList.add(savingsAccountTransaction);
|
||||||
|
if ((savingsAccountTransaction.isInterestPostingAndNotReversed()
|
||||||
|
|| savingsAccountTransaction.isOverdraftInterestAndNotReversed())
|
||||||
|
&& !savingsAccountTransaction.isReversalTransaction()) {
|
||||||
|
account.getSummary().setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance());
|
||||||
|
account.setLastSavingsAccountTransaction(savingsAccountTransaction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
account.getTransactions().removeAll(removalList);
|
||||||
|
} else {
|
||||||
|
account.getSummary().setRunningBalanceOnPivotDate(BigDecimal.ZERO);
|
||||||
|
}
|
||||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
|
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -76,7 +76,7 @@ public class PostInterestForSavingTasklet implements Tasklet {
|
|||||||
final int pageSize = batchSize * threadPoolSize;
|
final int pageSize = batchSize * threadPoolSize;
|
||||||
Long maxSavingsIdInList = 0L;
|
Long maxSavingsIdInList = 0L;
|
||||||
final ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
|
final ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
|
||||||
final boolean backdatedTxnsAllowedTill = false;
|
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -364,8 +364,12 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
|
|||||||
}
|
}
|
||||||
final List<SavingsAccountTransactionData> listOfTransactionsSorted = new ArrayList<>();
|
final List<SavingsAccountTransactionData> listOfTransactionsSorted = new ArrayList<>();
|
||||||
listOfTransactionsSorted.addAll(savingsAccountData.getTransactions());
|
listOfTransactionsSorted.addAll(savingsAccountData.getTransactions());
|
||||||
final SavingsAccountTransactionDataComparator transactionComparator = new SavingsAccountTransactionDataComparator();
|
if (!listOfTransactionsSorted.isEmpty()) {
|
||||||
Collections.sort(listOfTransactionsSorted, transactionComparator);
|
final SavingsAccountTransactionDataComparator transactionComparator = new SavingsAccountTransactionDataComparator();
|
||||||
|
Collections.sort(listOfTransactionsSorted, transactionComparator);
|
||||||
|
} else {
|
||||||
|
listOfTransactionsSorted.add(savingsAccountData.getLastSavingsAccountTransaction());
|
||||||
|
}
|
||||||
return listOfTransactionsSorted.get(0);
|
return listOfTransactionsSorted.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -272,7 +272,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
+ "where (CASE WHEN sa.interest_posted_till_date is not null THEN tr.transaction_date >= sa.interest_posted_till_date ELSE tr.transaction_date >= sa.activatedon_date END) ";
|
+ "where (CASE WHEN sa.interest_posted_till_date is not null THEN tr.transaction_date >= sa.interest_posted_till_date ELSE tr.transaction_date >= sa.activatedon_date END) ";
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = sql + " and (sa.interest_posted_till_date is null or sa.interest_posted_till_date < ? ) ";
|
sql = sql + " and (sa.interest_posted_till_date is null or sa.interest_posted_till_date <= ? ) ";
|
||||||
sql = sql + " order by sa.id, tr.transaction_date, tr.created_date, tr.id";
|
sql = sql + " order by sa.id, tr.transaction_date, tr.created_date, tr.id";
|
||||||
|
|
||||||
List<SavingsAccountData> savingsAccountDataList = this.jdbcTemplate.query(sql, this.savingAccountMapperForInterestPosting, // NOSONAR
|
List<SavingsAccountData> savingsAccountDataList = this.jdbcTemplate.query(sql, this.savingAccountMapperForInterestPosting, // NOSONAR
|
||||||
|
|||||||
+7
-5
@@ -2973,18 +2973,20 @@ public class ClientSavingsIntegrationTest {
|
|||||||
|
|
||||||
configurationForBackdatedTransaction();
|
configurationForBackdatedTransaction();
|
||||||
|
|
||||||
String transactionDate = "1 July 2022";
|
LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(10);
|
||||||
|
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy");
|
||||||
|
String startDate = formatter.format(transactionDate);
|
||||||
|
|
||||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, transactionDate);
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate);
|
||||||
Assertions.assertNotNull(clientID);
|
Assertions.assertNotNull(clientID);
|
||||||
|
|
||||||
final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, transactionDate);
|
final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, startDate);
|
||||||
this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", transactionDate, CommonConstants.RESPONSE_RESOURCE_ID);
|
this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", startDate, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||||
final String jobName = "Post Interest For Savings";
|
final String jobName = "Post Interest For Savings";
|
||||||
this.scheduleJobHelper.executeAndAwaitJob(jobName);
|
this.scheduleJobHelper.executeAndAwaitJob(jobName);
|
||||||
final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(403).build();
|
final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||||
final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse);
|
final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse);
|
||||||
List<HashMap> error = (List<HashMap>) validationErrorHelper.depositToSavingsAccount(savingsId, "3000", transactionDate,
|
List<HashMap> error = (List<HashMap>) validationErrorHelper.depositToSavingsAccount(savingsId, "300", startDate,
|
||||||
CommonConstants.RESPONSE_ERROR);
|
CommonConstants.RESPONSE_ERROR);
|
||||||
|
|
||||||
assertEquals("error.msg.savings.transaction.is.not.allowed", error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
assertEquals("error.msg.savings.transaction.is.not.allowed", error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
||||||
|
|||||||
Reference in New Issue
Block a user