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

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


The following commit(s) were added to refs/heads/develop by this push:
     new d75835170 FINERACT-1330: Pay Charge & withdrawals is violating 
Overdraft conditions on current and past Transactions
d75835170 is described below

commit d75835170a5ce2f05c0ef295fb2e8abd247f1e9c
Author: rrpawar96 <[email protected]>
AuthorDate: Sat Jul 16 01:43:37 2022 +0530

    FINERACT-1330: Pay Charge & withdrawals is violating Overdraft conditions 
on current and past Transactions
---
 .../portfolio/savings/domain/SavingsAccount.java   | 19 +++++--
 .../SavingsAccountTransactionRepository.java       |  8 ++-
 ...countWritePlatformServiceJpaRepositoryImpl.java | 13 ++++-
 .../ClientSavingsIntegrationTest.java              | 58 ++++++++++++++++++++++
 .../common/savings/SavingsAccountHelper.java       |  7 +++
 5 files changed, 99 insertions(+), 6 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
index 79cba8ee1..6fac36276 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
@@ -1521,6 +1521,7 @@ public class SavingsAccount extends 
AbstractPersistableCustom {
             final List<DepositAccountOnHoldTransaction> 
depositAccountOnHoldTransactions, final boolean backdatedTxnsAllowedTill) {
 
         List<SavingsAccountTransaction> transactionsSortedByDate = null;
+        BigDecimal transactionAmount = null;
         if (backdatedTxnsAllowedTill) {
             transactionsSortedByDate = retrieveSortedTransactions();
         } else {
@@ -1535,6 +1536,9 @@ public class SavingsAccount extends 
AbstractPersistableCustom {
         Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
         LocalDate lastSavingsDate = null;
         for (final SavingsAccountTransaction transaction : 
transactionsSortedByDate) {
+
+            transactionAmount = transaction.getAmount();
+
             if (transaction.isNotReversed() && transaction.isCredit()) {
                 runningBalance = 
runningBalance.plus(transaction.getAmount(this.currency));
             } else if (transaction.isNotReversed() && transaction.isDebit()) {
@@ -1573,14 +1577,11 @@ public class SavingsAccount extends 
AbstractPersistableCustom {
                         throw new 
PlatformApiDataValidationException(dataValidationErrors);
                     }
                 }
-
             }
             lastSavingsDate = transaction.transactionLocalDate();
-
         }
 
         BigDecimal withdrawalFee = null;
-        BigDecimal transactionAmount = null;
         if (isOverdraft()) {
             if (runningBalance.minus(minRequiredBalance).isLessThanZero()) {
                 throw new 
InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), 
withdrawalFee, transactionAmount);
@@ -1588,6 +1589,18 @@ public class SavingsAccount extends 
AbstractPersistableCustom {
         }
     }
 
+    public void validateAccountBalanceDoesNotViolateOverdraft(final 
List<SavingsAccountTransaction> savingsAccountTransaction,
+            final BigDecimal amountPaid) {
+        if (savingsAccountTransaction != null) {
+            SavingsAccountTransaction savingsAccountTransactionFirst = 
savingsAccountTransaction.get(0);
+            if (!this.allowOverdraft) {
+                if 
(savingsAccountTransactionFirst.getRunningBalance(this.currency).minus(amountPaid).isLessThanZero())
 {
+                    throw new 
InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), 
null, amountPaid);
+                }
+            }
+        }
+    }
+
     protected boolean isAccountLocked(final LocalDate transactionDate) {
         boolean isLocked = false;
         final boolean accountHasLockedInSetting = this.lockedInUntilDate != 
null;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
index 6d2db4080..e0d03b657 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.domain;
 import java.time.LocalDate;
 import java.util.List;
 import javax.persistence.LockModeType;
+import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Lock;
@@ -47,6 +48,9 @@ public interface SavingsAccountTransactionRepository
     @Lock(LockModeType.PESSIMISTIC_WRITE)
     List<SavingsAccountTransaction> 
findBySavingsAccount(@Param("savingsAccount") SavingsAccount savingsAccount);
 
-    @Query("select sat from SavingsAccountTransaction sat where sat.refNo = 
:refNo")
-    List<SavingsAccountTransaction> findAllTransactionByRefNo(@Param("refNo") 
String refNo);
+    List<SavingsAccountTransaction> findByRefNo(@Param("refNo") String refNo);
+
+    @Query("select sat from SavingsAccountTransaction sat where 
sat.savingsAccount.id = :savingsId and sat.dateOf <= :transactionDate and 
sat.reversed=false")
+    List<SavingsAccountTransaction> 
findBySavingsAccountIdAndLessThanDateOfAndReversedIsFalse(@Param("savingsId") 
Long savingsId,
+            @Param("transactionDate") LocalDate transactionDate, Pageable 
pageable);
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
index fc17fd9bb..89e94e749 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -130,6 +130,9 @@ import 
org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
@@ -718,7 +721,7 @@ public class 
SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
         List<SavingsAccountTransaction> savingsAccountTransactions = null;
         if (isBulk) {
             String transactionRefNo = savingsAccountTransaction.getRefNo();
-            savingsAccountTransactions = 
this.savingsAccountTransactionRepository.findAllTransactionByRefNo(transactionRefNo);
+            savingsAccountTransactions = 
this.savingsAccountTransactionRepository.findByRefNo(transactionRefNo);
             reversal = 
this.savingsAccountDomainService.handleReversal(account, 
savingsAccountTransactions, backdatedTxnsAllowedTill);
         } else {
             reversal = 
this.savingsAccountDomainService.handleReversal(account, 
Collections.singletonList(savingsAccountTransaction),
@@ -1471,6 +1474,13 @@ public class 
SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
         this.savingAccountAssembler.assignSavingAccountHelpers(account);
         final Set<Long> existingTransactionIds = new HashSet<>();
         final Set<Long> existingReversedTransactionIds = new HashSet<>();
+        Pageable sortedByDateAndIdDesc = PageRequest.of(0, 1, 
Sort.by("dateOf", "id").descending());
+
+        List<SavingsAccountTransaction> savingsAccountTransaction = 
this.savingsAccountTransactionRepository
+                
.findBySavingsAccountIdAndLessThanDateOfAndReversedIsFalse(account.getId(), 
transactionDate, sortedByDateAndIdDesc);
+
+        
account.validateAccountBalanceDoesNotViolateOverdraft(savingsAccountTransaction,
 amountPaid);
+
         updateExistingTransactionsDetails(account, existingTransactionIds, 
existingReversedTransactionIds);
         SavingsAccountTransaction chargeTransaction = 
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, 
user,
                 backdatedTxnsAllowedTill, null);
@@ -1488,6 +1498,7 @@ public class 
SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
                     financialYearBeginningMonth, postInterestOnDate, 
backdatedTxnsAllowedTill, postReversals);
         }
         List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions 
= null;
+
         if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
             depositAccountOnHoldTransactions = 
this.depositAccountOnHoldTransactionRepository
                     
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
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 9788a93a9..5e5b65551 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
@@ -2869,6 +2869,64 @@ public class ClientSavingsIntegrationTest {
         assertEquals(balance.toString(), 
requestedTransaction.get("runningBalance").toString(), "Equality check for 
Balance");
     }
 
+    @Test
+    public void testSavingsAccountChargesBackDate() {
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
+        SavingsAccountHelper savingsAccountHelperValidationError = new 
SavingsAccountHelper(this.requestSpec,
+                new ResponseSpecBuilder().build());
+
+        final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec);
+        ClientHelper.verifyClientCreatedOnServer(this.requestSpec, 
this.responseSpec, clientID);
+
+        final String minBalanceForInterestCalculation = null;
+        final String minRequiredBalance = null;
+        final String enforceMinRequiredBalance = "false";
+        final boolean allowOverdraft = false;
+        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(savingsProductID);
+
+        HashMap modifications = 
this.savingsAccountHelper.updateSavingsAccount(clientID, savingsProductID, 
savingsId,
+                ACCOUNT_TYPE_INDIVIDUAL);
+        Assertions.assertTrue(modifications.containsKey("submittedOnDate"));
+
+        HashMap savingsStatusHashMap = 
SavingsStatusChecker.getStatusOfSavings(this.requestSpec, this.responseSpec, 
savingsId);
+        SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.approveSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.activateSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
+
+        final Integer chargeId = ChargesHelper.createCharges(this.requestSpec, 
this.responseSpec,
+                ChargesHelper.getSavingsSpecifiedDueDateJSON());
+        Assertions.assertNotNull(chargeId);
+
+        ArrayList<HashMap> charges = 
this.savingsAccountHelper.getSavingsCharges(savingsId);
+        Assertions.assertTrue(charges == null || charges.size() == 0);
+
+        this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
"05 March 2013", CommonConstants.RESPONSE_RESOURCE_ID);
+
+        this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
"07 March 2013", CommonConstants.RESPONSE_RESOURCE_ID);
+
+        final Integer savingsChargeId = 
this.savingsAccountHelper.addChargesForSavingsWithDueDate(savingsId, chargeId, 
"07 March 2013",
+                200);
+
+        ArrayList<HashMap> savingsAccountErrorData = (ArrayList<HashMap>) 
savingsAccountHelperValidationError
+                .payChargeToSavingsAccount(savingsId, savingsChargeId, "200", 
"06 March 2013", CommonConstants.RESPONSE_ERROR);
+
+        
assertEquals("error.msg.savingsaccount.transaction.insufficient.account.balance",
+                
savingsAccountErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+
+        final Integer payChargeId = 
this.savingsAccountHelper.payCharge(savingsChargeId, savingsId, "200", "07 
March 2013");
+
+        Assertions.assertNotNull(payChargeId);
+    }
+
     @Test
     public void testRunningBalanceAfterWithdrawalWithBackdateConfigurationOn() 
{
         this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
index e76abd6f6..8ce6a5b5b 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
@@ -263,6 +263,13 @@ public class SavingsAccountHelper {
                 getSavingsTransactionPaymentTypeJSON(amount, date, 
paymentType), jsonAttributeToGetback);
     }
 
+    public Object payChargeToSavingsAccount(final Integer savingsID, final 
Integer chargeId, final String amount, String date,
+            String jsonAttributeToGetback) {
+        LOG.info("--------------------------------- PAY SAVINGS CHARGE 
--------------------------------");
+        return performSavingActions(createChargesURL("paycharge", savingsID, 
chargeId), getSavingsPayChargeJSON(amount, date),
+                jsonAttributeToGetback);
+    }
+
     public Integer updateSavingsAccountTransaction(final Integer savingsId, 
final Integer transactionId, final String amount) {
         LOG.info("\n--------------------------------- MODIFY SAVINGS 
TRANSACTION  --------------------------------");
         return (Integer) 
performSavingActions(createAdjustTransactionURL(MODIFY_TRASACTION_COMMAND, 
savingsId, transactionId),

Reply via email to