This is an automated email from the ASF dual-hosted git repository.

aleks pushed a commit to branch 1.8.0
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/1.8.0 by this push:
     new c3b462919 FINERACT-1646-backdated-transaction-available-balance-fix
c3b462919 is described below

commit c3b462919fed1206bd8a6d3255d3591f84970f2c
Author: Dhaval Maniyar <[email protected]>
AuthorDate: Sat Jul 30 22:08:59 2022 +0530

    FINERACT-1646-backdated-transaction-available-balance-fix
---
 .../portfolio/savings/data/SavingsAccountData.java | 10 +++++++++
 .../savings/data/SavingsAccountSummaryData.java    | 11 ++++++++--
 .../savings/domain/SavingsAccountAssembler.java    | 25 +++++++++++++++++-----
 .../SavingsAccountInterestPostingServiceImpl.java  |  8 +++++--
 .../SavingsAccountReadPlatformServiceImpl.java     |  2 +-
 .../service/SavingsSchedularServiceImpl.java       |  2 +-
 .../ClientSavingsIntegrationTest.java              | 12 ++++++-----
 7 files changed, 54 insertions(+), 16 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
index 8f66a23cf..befcbe8de 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
@@ -116,6 +116,8 @@ public final class SavingsAccountData implements 
Serializable {
     private final BigDecimal minOverdraftForInterestCalculation;
     private transient List<SavingsAccountTransactionData> 
savingsAccountTransactionData = new ArrayList<>();
 
+    private transient SavingsAccountTransactionData 
lastSavingsAccountTransaction;
+
     private List<DatatableData> datatables = null;
 
     // import field
@@ -1104,4 +1106,12 @@ public final class SavingsAccountData implements 
Serializable {
     public Set<Long> getExistingReversedTransactionIds() {
         return this.existingReversedTransactionIds;
     }
+
+    public SavingsAccountTransactionData getLastSavingsAccountTransaction() {
+        return lastSavingsAccountTransaction;
+    }
+
+    public void setLastSavingsAccountTransaction(SavingsAccountTransactionData 
lastSavingsAccountTransaction) {
+        this.lastSavingsAccountTransaction = lastSavingsAccountTransaction;
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
index a7eea4d47..9335f8df6 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
@@ -223,16 +223,23 @@ public class SavingsAccountSummaryData implements 
Serializable {
             Money interestTotal = Money.of(currency, this.totalInterestPosted);
             Money withHoldTaxTotal = Money.of(currency, this.totalWithholdTax);
             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,
                     overdraftInterestTotal, withHoldTaxTotal, currency);
             interestTotal = map.get("interestTotal");
             withHoldTaxTotal = map.get("withHoldTax");
             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.totalWithholdTax = 
withHoldTaxTotal.getAmountDefaultedToNullIfZero();
             this.totalOverdraftInterestDerived = 
overdraftInterestTotal.getAmountDefaultedToNullIfZero();
-            this.accountBalance = Money.of(currency, 
this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax)
-                    .minus(this.totalOverdraftInterestDerived).getAmount();
+            this.accountBalance = getRunningBalanceOnPivotDate();
+            this.accountBalance = Money.of(currency, 
this.accountBalance).plus(Money.of(currency, 
this.totalDeposits)).plus(deltaInterest)
+                    
.minus(this.totalWithdrawals).minus(deltaWithholdTax).minus(deltaOverdraftInterestDerived).getAmount();
         }
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java
index fa234fcaa..e45626574 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java
@@ -48,6 +48,7 @@ import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.withdraw
 import com.google.gson.JsonElement;
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 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.SavingsPostingInterestPeriodType;
 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.useradministration.domain.AppUser;
 import org.slf4j.Logger;
@@ -381,12 +383,25 @@ public class SavingsAccountAssembler {
     public SavingsAccountData assembleSavings(final SavingsAccountData 
account) {
 
         // Update last running balance on account level
-        if (account.getTransactions() != null && 
account.getTransactions().size() != 0
-                && account.getSummary().getInterestPostedTillDate() != null) {
-            
account.getSummary().setRunningBalanceOnPivotDate(account.getTransactions().get(account.getTransactions().size()
 - 1)
-                    .getRunningBalance(account.getCurrency()).getAmount());
+        final boolean backdatedTxnsAllowedTill = 
this.configurationDomainService.retrievePivotDateConfig();
+        if (backdatedTxnsAllowedTill && account.getTransactions() != null && 
account.getSummary().getInterestPostedTillDate() != null) {
+            List<SavingsAccountTransactionData> removalList = new 
ArrayList<>();
+
+            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);
         return account;
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java
index dc2a87309..0ee01f2ba 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountInterestPostingServiceImpl.java
@@ -364,8 +364,12 @@ public class SavingsAccountInterestPostingServiceImpl 
implements SavingsAccountI
         }
         final List<SavingsAccountTransactionData> listOfTransactionsSorted = 
new ArrayList<>();
         listOfTransactionsSorted.addAll(savingsAccountData.getTransactions());
-        final SavingsAccountTransactionDataComparator transactionComparator = 
new SavingsAccountTransactionDataComparator();
-        Collections.sort(listOfTransactionsSorted, transactionComparator);
+        if (!listOfTransactionsSorted.isEmpty()) {
+            final SavingsAccountTransactionDataComparator 
transactionComparator = new SavingsAccountTransactionDataComparator();
+            Collections.sort(listOfTransactionsSorted, transactionComparator);
+        } else {
+            
listOfTransactionsSorted.add(savingsAccountData.getLastSavingsAccountTransaction());
+        }
         return listOfTransactionsSorted.get(0);
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
index b53a1bfed..31e8e3f0e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
@@ -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) ";
         }
 
-        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";
 
         List<SavingsAccountData> savingsAccountDataList = 
this.jdbcTemplate.query(sql, this.savingAccountMapperForInterestPosting, // 
NOSONAR
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
index 018fc5b98..5234e5932 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java
@@ -76,7 +76,7 @@ public class SavingsSchedularServiceImpl implements 
SavingsSchedularService {
         Long maxSavingsIdInList = 0L;
         // initialise the executor service with fetched configurations
         final ExecutorService executorService = 
Executors.newFixedThreadPool(threadPoolSize);
-        final boolean backdatedTxnsAllowedTill = false;
+        final boolean backdatedTxnsAllowedTill = 
this.configurationDomainService.retrievePivotDateConfig();
 
         long start = System.currentTimeMillis();
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
index a98a796a2..3e778bba3 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
@@ -2972,18 +2972,20 @@ public class ClientSavingsIntegrationTest {
 
         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);
 
-        final Integer savingsId = 
createSavingsAccountDailyPostingOverdraft(clientID, transactionDate);
-        this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", 
transactionDate, CommonConstants.RESPONSE_RESOURCE_ID);
+        final Integer savingsId = 
createSavingsAccountDailyPostingOverdraft(clientID, startDate);
+        this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", 
startDate, CommonConstants.RESPONSE_RESOURCE_ID);
         final String jobName = "Post Interest For Savings";
         this.scheduleJobHelper.executeAndAwaitJob(jobName);
         final ResponseSpecification errorResponse = new 
ResponseSpecBuilder().expectStatusCode(403).build();
         final SavingsAccountHelper validationErrorHelper = new 
SavingsAccountHelper(this.requestSpec, errorResponse);
-        List<HashMap> error = (List<HashMap>) 
validationErrorHelper.depositToSavingsAccount(savingsId, "3000", 
transactionDate,
+        List<HashMap> error = (List<HashMap>) 
validationErrorHelper.depositToSavingsAccount(savingsId, "300", startDate,
                 CommonConstants.RESPONSE_ERROR);
 
         assertEquals("error.msg.savings.transaction.is.not.allowed", 
error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));

Reply via email to