Skip to content

Commit c3b4629

Browse files
Dhaval Maniyarvidakovic
authored andcommitted
FINERACT-1646-backdated-transaction-available-balance-fix
1 parent edc734c commit c3b4629

7 files changed

Lines changed: 54 additions & 16 deletions

File tree

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ public final class SavingsAccountData implements Serializable {
116116
private final BigDecimal minOverdraftForInterestCalculation;
117117
private transient List<SavingsAccountTransactionData> savingsAccountTransactionData = new ArrayList<>();
118118

119+
private transient SavingsAccountTransactionData lastSavingsAccountTransaction;
120+
119121
private List<DatatableData> datatables = null;
120122

121123
// import field
@@ -1104,4 +1106,12 @@ public Set<Long> getExistingTransactionIds() {
11041106
public Set<Long> getExistingReversedTransactionIds() {
11051107
return this.existingReversedTransactionIds;
11061108
}
1109+
1110+
public SavingsAccountTransactionData getLastSavingsAccountTransaction() {
1111+
return lastSavingsAccountTransaction;
1112+
}
1113+
1114+
public void setLastSavingsAccountTransaction(SavingsAccountTransactionData lastSavingsAccountTransaction) {
1115+
this.lastSavingsAccountTransaction = lastSavingsAccountTransaction;
1116+
}
11071117
}

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,16 +223,23 @@ public void updateSummaryWithPivotConfig(final CurrencyData currency, final Savi
223223
Money interestTotal = Money.of(currency, this.totalInterestPosted);
224224
Money withHoldTaxTotal = Money.of(currency, this.totalWithholdTax);
225225
Money overdraftInterestTotal = Money.of(currency, this.totalOverdraftInterestDerived);
226+
this.totalDeposits = wrapper.calculateTotalDeposits(currency, savingsAccountTransactions);
227+
this.totalWithdrawals = wrapper.calculateTotalWithdrawals(currency, savingsAccountTransactions);
226228
final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal,
227229
overdraftInterestTotal, withHoldTaxTotal, currency);
228230
interestTotal = map.get("interestTotal");
229231
withHoldTaxTotal = map.get("withHoldTax");
230232
overdraftInterestTotal = map.get("overdraftInterestTotal");
233+
BigDecimal deltaInterest = interestTotal.minus(this.totalInterestPosted).getAmountDefaultedToNullIfZero();
234+
BigDecimal deltaWithholdTax = withHoldTaxTotal.minus(this.totalWithholdTax).getAmountDefaultedToNullIfZero();
235+
BigDecimal deltaOverdraftInterestDerived = overdraftInterestTotal.minus(this.totalOverdraftInterestDerived)
236+
.getAmountDefaultedToNullIfZero();
231237
this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero();
232238
this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero();
233239
this.totalOverdraftInterestDerived = overdraftInterestTotal.getAmountDefaultedToNullIfZero();
234-
this.accountBalance = Money.of(currency, this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax)
235-
.minus(this.totalOverdraftInterestDerived).getAmount();
240+
this.accountBalance = getRunningBalanceOnPivotDate();
241+
this.accountBalance = Money.of(currency, this.accountBalance).plus(Money.of(currency, this.totalDeposits)).plus(deltaInterest)
242+
.minus(this.totalWithdrawals).minus(deltaWithholdTax).minus(deltaOverdraftInterestDerived).getAmount();
236243
}
237244
}
238245

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.google.gson.JsonElement;
4949
import java.math.BigDecimal;
5050
import java.time.LocalDate;
51+
import java.util.ArrayList;
5152
import java.util.Arrays;
5253
import java.util.List;
5354
import java.util.Set;
@@ -74,6 +75,7 @@
7475
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
7576
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
7677
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
78+
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
7779
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
7880
import org.apache.fineract.useradministration.domain.AppUser;
7981
import org.slf4j.Logger;
@@ -381,12 +383,25 @@ public SavingsAccount loadTransactionsToSavingsAccount(final SavingsAccount acco
381383
public SavingsAccountData assembleSavings(final SavingsAccountData account) {
382384

383385
// Update last running balance on account level
384-
if (account.getTransactions() != null && account.getTransactions().size() != 0
385-
&& account.getSummary().getInterestPostedTillDate() != null) {
386-
account.getSummary().setRunningBalanceOnPivotDate(account.getTransactions().get(account.getTransactions().size() - 1)
387-
.getRunningBalance(account.getCurrency()).getAmount());
386+
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
387+
if (backdatedTxnsAllowedTill && account.getTransactions() != null && account.getSummary().getInterestPostedTillDate() != null) {
388+
List<SavingsAccountTransactionData> removalList = new ArrayList<>();
389+
390+
for (int i = 0; i < account.getTransactions().size(); i++) {
391+
SavingsAccountTransactionData savingsAccountTransaction = account.getTransactions().get(i);
392+
removalList.add(savingsAccountTransaction);
393+
if ((savingsAccountTransaction.isInterestPostingAndNotReversed()
394+
|| savingsAccountTransaction.isOverdraftInterestAndNotReversed())
395+
&& !savingsAccountTransaction.isReversalTransaction()) {
396+
account.getSummary().setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance());
397+
account.setLastSavingsAccountTransaction(savingsAccountTransaction);
398+
break;
399+
}
400+
}
401+
account.getTransactions().removeAll(removalList);
402+
} else {
403+
account.getSummary().setRunningBalanceOnPivotDate(BigDecimal.ZERO);
388404
}
389-
390405
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
391406
return account;
392407
}

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,12 @@ private SavingsAccountTransactionData retrieveLastTransactions(final SavingsAcco
364364
}
365365
final List<SavingsAccountTransactionData> listOfTransactionsSorted = new ArrayList<>();
366366
listOfTransactionsSorted.addAll(savingsAccountData.getTransactions());
367-
final SavingsAccountTransactionDataComparator transactionComparator = new SavingsAccountTransactionDataComparator();
368-
Collections.sort(listOfTransactionsSorted, transactionComparator);
367+
if (!listOfTransactionsSorted.isEmpty()) {
368+
final SavingsAccountTransactionDataComparator transactionComparator = new SavingsAccountTransactionDataComparator();
369+
Collections.sort(listOfTransactionsSorted, transactionComparator);
370+
} else {
371+
listOfTransactionsSorted.add(savingsAccountData.getLastSavingsAccountTransaction());
372+
}
369373
return listOfTransactionsSorted.get(0);
370374
}
371375

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ public List<SavingsAccountData> retrieveAllSavingsDataForInterestPosting(final b
272272
+ "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) ";
273273
}
274274

275-
sql = sql + " and (sa.interest_posted_till_date is null or sa.interest_posted_till_date < ? ) ";
275+
sql = sql + " and (sa.interest_posted_till_date is null or sa.interest_posted_till_date <= ? ) ";
276276
sql = sql + " order by sa.id, tr.transaction_date, tr.created_date, tr.id";
277277

278278
List<SavingsAccountData> savingsAccountDataList = this.jdbcTemplate.query(sql, this.savingAccountMapperForInterestPosting, // NOSONAR

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public void postInterestForAccounts(Map<String, String> jobParameters) throws Jo
7676
Long maxSavingsIdInList = 0L;
7777
// initialise the executor service with fetched configurations
7878
final ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
79-
final boolean backdatedTxnsAllowedTill = false;
79+
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
8080

8181
long start = System.currentTimeMillis();
8282

integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2972,18 +2972,20 @@ public void testToPerformTransactionBeforePivotDate() {
29722972

29732973
configurationForBackdatedTransaction();
29742974

2975-
String transactionDate = "1 July 2022";
2975+
LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(10);
2976+
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy");
2977+
String startDate = formatter.format(transactionDate);
29762978

2977-
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, transactionDate);
2979+
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate);
29782980
Assertions.assertNotNull(clientID);
29792981

2980-
final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, transactionDate);
2981-
this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", transactionDate, CommonConstants.RESPONSE_RESOURCE_ID);
2982+
final Integer savingsId = createSavingsAccountDailyPostingOverdraft(clientID, startDate);
2983+
this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", startDate, CommonConstants.RESPONSE_RESOURCE_ID);
29822984
final String jobName = "Post Interest For Savings";
29832985
this.scheduleJobHelper.executeAndAwaitJob(jobName);
29842986
final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(403).build();
29852987
final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse);
2986-
List<HashMap> error = (List<HashMap>) validationErrorHelper.depositToSavingsAccount(savingsId, "3000", transactionDate,
2988+
List<HashMap> error = (List<HashMap>) validationErrorHelper.depositToSavingsAccount(savingsId, "300", startDate,
29872989
CommonConstants.RESPONSE_ERROR);
29882990

29892991
assertEquals("error.msg.savings.transaction.is.not.allowed", error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));

0 commit comments

Comments
 (0)