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

adamsaghy 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 2ac1445dba Confirm existance of elements before accessing them
2ac1445dba is described below

commit 2ac1445dbaea3457cfa5e298f4e9f29707a6c150
Author: Wilfred Kigenyi <[email protected]>
AuthorDate: Mon Dec 2 00:38:11 2024 +0300

    Confirm existance of elements before accessing them
---
 .../portfolio/savings/domain/SavingsAccount.java   |   7 +-
 .../ClientSavingsIntegrationTest.java              | 314 +++++++++++++++++++++
 2 files changed, 320 insertions(+), 1 deletion(-)

diff --git 
a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
 
b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
index bfd94a1ead..59bba2100a 100644
--- 
a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
+++ 
b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
@@ -1593,13 +1593,18 @@ public class SavingsAccount extends 
AbstractAuditableWithUTCDateTimeCustom<Long>
 
     public void validateAccountBalanceDoesNotViolateOverdraft(final 
List<SavingsAccountTransaction> savingsAccountTransaction,
             final BigDecimal amountPaid) {
-        if (savingsAccountTransaction != null) {
+        if (savingsAccountTransaction != null && 
savingsAccountTransaction.size() > 0) {
             SavingsAccountTransaction savingsAccountTransactionFirst = 
savingsAccountTransaction.get(0);
             if (!this.allowOverdraft) {
                 if 
(savingsAccountTransactionFirst.getRunningBalance(this.currency).minus(amountPaid).isLessThanZero())
 {
                     throw new 
InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), 
null, amountPaid);
                 }
             }
+
+        } else {
+            if (!this.allowOverdraft) {
+                throw new 
InsufficientAccountBalanceException("transactionAmount", BigDecimal.ZERO, null, 
amountPaid);
+            }
         }
     }
 
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 115ce14b43..15d6655c40 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
@@ -3184,6 +3184,320 @@ public class ClientSavingsIntegrationTest {
                 error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
     }
 
+    @Test
+    public void 
testSavingsAccountWithdrawalWithoutPriorTransactionsWithoutOverdraft() {
+        final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd 
MMMM yyyy", Locale.US);
+
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
+        final ResponseSpecification errorResponse = new 
ResponseSpecBuilder().expectStatusCode(403).build();
+        final SavingsAccountHelper validationErrorHelper = new 
SavingsAccountHelper(this.requestSpec, errorResponse);
+
+        /***
+         * Create a client to apply for savings account (overdraft account).
+         */
+        final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec);
+        ClientHelper.verifyClientCreatedOnServer(this.requestSpec, 
this.responseSpec, clientID);
+        // Assertions.assertNotNull(clientID);
+        final String minBalanceForInterestCalculation = null;
+
+        /***
+         * Create savings product with zero opening balance and overdraft 
disabled
+         */
+        final String zeroOpeningBalance = "0.0";
+        final String minRequiredBalance = null;
+        final String enforceMinRequiredBalance = "false";
+        final boolean allowOverdraft = false;
+        final Integer savingsProductID = 
createSavingsProduct(this.requestSpec, this.responseSpec, zeroOpeningBalance,
+                minBalanceForInterestCalculation, minRequiredBalance, 
enforceMinRequiredBalance, allowOverdraft);
+        Assertions.assertNotNull(savingsProductID);
+
+        /***
+         * Apply for Savings account
+         */
+        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);
+
+        /***
+         * Approve the savings account
+         */
+        savingsStatusHashMap = 
this.savingsAccountHelper.approveSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
+
+        LocalDate todaysDate = Utils.getLocalDateOfTenant();
+        todaysDate = todaysDate.minusMonths(1);
+        todaysDate = todaysDate.withDayOfMonth(1);
+        final String ACTIVATION_DATE = dateFormat.format(todaysDate);
+        final Integer lastDayOfMonth = todaysDate.lengthOfMonth();
+        todaysDate = todaysDate.withDayOfMonth(lastDayOfMonth);
+        final String TRANSACTION_DATE = dateFormat.format(todaysDate);
+
+        /***
+         * Activate the application and verify account status
+         *
+         * @param activationDate
+         *            this value is every time first day of previous month
+         */
+        savingsStatusHashMap = activateSavingsAccount(savingsId, 
ACTIVATION_DATE);
+        SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
+
+        Float balance = Float.parseFloat(zeroOpeningBalance);
+
+        /***
+         * Attempt a withdrawal transaction, verify an exception will be 
thrown since there are no prior transactions to
+         * this transaction
+         */
+        ArrayList<HashMap> savingsAccountErrorData = (ArrayList<HashMap>) 
validationErrorHelper.withdrawalFromSavingsAccount(savingsId,
+                WITHDRAW_AMOUNT, TRANSACTION_DATE, 
CommonConstants.RESPONSE_ERROR);
+        
assertEquals("error.msg.savingsaccount.transaction.insufficient.account.balance",
+                
savingsAccountErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+    }
+
+    @Test
+    public void 
testWithdrawalWithPriorTransactionsWithOverdraft_AMT_GT_Balance() {
+        final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd 
MMMM yyyy", Locale.US);
+
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
+        final ResponseSpecification errorResponse = new 
ResponseSpecBuilder().expectStatusCode(400).build();
+        final SavingsAccountHelper validationErrorHelper = new 
SavingsAccountHelper(this.requestSpec, errorResponse);
+
+        /***
+         * Create a client to apply for savings account (overdraft account).
+         */
+        final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec);
+        ClientHelper.verifyClientCreatedOnServer(this.requestSpec, 
this.responseSpec, clientID);
+        // Assertions.assertNotNull(clientID);
+        final String minBalanceForInterestCalculation = null;
+
+        /***
+         * Create savings product with zero opening balance and overdraft 
enabled
+         */
+        final String nonZeroOpeningBalance = "500.00";
+        final String minRequiredBalance = null;
+        final String enforceMinRequiredBalance = "false";
+        final boolean allowOverdraft = true;
+        final Integer savingsProductID = 
createSavingsProduct(this.requestSpec, this.responseSpec, nonZeroOpeningBalance,
+                minBalanceForInterestCalculation, minRequiredBalance, 
enforceMinRequiredBalance, allowOverdraft);
+        Assertions.assertNotNull(savingsProductID);
+
+        /***
+         * Apply for Savings account
+         */
+        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);
+
+        /***
+         * Approve the savings account
+         */
+        savingsStatusHashMap = 
this.savingsAccountHelper.approveSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
+
+        LocalDate todaysDate = Utils.getLocalDateOfTenant();
+        todaysDate = todaysDate.minusMonths(1);
+        todaysDate = todaysDate.withDayOfMonth(1);
+        final String ACTIVATION_DATE = dateFormat.format(todaysDate);
+        final Integer lastDayOfMonth = todaysDate.lengthOfMonth();
+        todaysDate = todaysDate.withDayOfMonth(lastDayOfMonth);
+
+        /***
+         * Activate the application and verify account status
+         *
+         * @param activationDate
+         *            this value is every time first day of previous month
+         */
+        savingsStatusHashMap = activateSavingsAccount(savingsId, 
ACTIVATION_DATE);
+        SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
+
+        Float balance = Float.parseFloat(nonZeroOpeningBalance);
+
+        /***
+         * Attempt a withdrawal transaction, verify an exception will be 
thrown since there are no prior transactions to
+         * this transaction
+         */
+        /***
+         * Perform withdraw transaction, verify account balance(account 
balance will go to negative as no deposits are
+         * there prior to this transaction)
+         */
+        Integer withdrawTransactionId = (Integer) 
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
WITHDRAW_AMOUNT,
+                ACTIVATION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
+        HashMap withdrawTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
withdrawTransactionId);
+        balance -= Float.parseFloat(WITHDRAW_AMOUNT);
+        assertEquals(Float.parseFloat(WITHDRAW_AMOUNT), 
withdrawTransaction.get("amount"), "Verifying Withdrawal Amount");
+        assertEquals(balance, withdrawTransaction.get("runningBalance"), 
"Verifying Balance after Withdrawal");
+
+    }
+
+    @Test
+    public void 
testWithdrawalWithPriorTransactionsWithOverdraft_AMT_LT_Balance() {
+        final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd 
MMMM yyyy", Locale.US);
+
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
+        final ResponseSpecification errorResponse = new 
ResponseSpecBuilder().expectStatusCode(400).build();
+        final SavingsAccountHelper validationErrorHelper = new 
SavingsAccountHelper(this.requestSpec, errorResponse);
+
+        /***
+         * Create a client to apply for savings account (overdraft account).
+         */
+        final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec);
+        ClientHelper.verifyClientCreatedOnServer(this.requestSpec, 
this.responseSpec, clientID);
+        // Assertions.assertNotNull(clientID);
+        final String minBalanceForInterestCalculation = null;
+
+        /***
+         * Create savings product with zero opening balance and overdraft 
enabled
+         */
+        final String nonZeroOpeningBalance = "2000";
+        final String minRequiredBalance = null;
+        final String enforceMinRequiredBalance = "false";
+        final boolean allowOverdraft = false;
+        final Integer savingsProductID = 
createSavingsProduct(this.requestSpec, this.responseSpec, nonZeroOpeningBalance,
+                minBalanceForInterestCalculation, minRequiredBalance, 
enforceMinRequiredBalance, allowOverdraft);
+        Assertions.assertNotNull(savingsProductID);
+
+        /***
+         * Apply for Savings account
+         */
+        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);
+
+        /***
+         * Approve the savings account
+         */
+        savingsStatusHashMap = 
this.savingsAccountHelper.approveSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
+
+        LocalDate todaysDate = Utils.getLocalDateOfTenant();
+        todaysDate = todaysDate.minusMonths(1);
+        todaysDate = todaysDate.withDayOfMonth(1);
+        final String ACTIVATION_DATE = dateFormat.format(todaysDate);
+
+        /***
+         * Activate the application and verify account status
+         *
+         * @param activationDate
+         *            this value is every time first day of previous month
+         */
+        savingsStatusHashMap = activateSavingsAccount(savingsId, 
ACTIVATION_DATE);
+        SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
+
+        Float balance = Float.parseFloat(nonZeroOpeningBalance);
+
+        /***
+         * Attempt a withdrawal transaction, verify an exception will be 
thrown since there are no prior transactions to
+         * this transaction
+         */
+        /***
+         * Perform withdraw transaction, verify account balance(account 
balance will go to negative as no deposits are
+         * there prior to this transaction)
+         */
+        Integer withdrawTransactionId = (Integer) 
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
WITHDRAW_AMOUNT,
+                ACTIVATION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
+        HashMap withdrawTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
withdrawTransactionId);
+        balance -= Float.parseFloat(WITHDRAW_AMOUNT);
+        assertEquals(Float.parseFloat(WITHDRAW_AMOUNT), 
withdrawTransaction.get("amount"), "Verifying Withdrawal Amount");
+        assertEquals(balance, withdrawTransaction.get("runningBalance"), 
"Verifying Balance after Withdrawal");
+
+    }
+
+    @Test
+    public void 
testWithdrawalWithPriorTransactionsWithOverdraft_AMT_EQ_Balance() {
+        final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd 
MMMM yyyy", Locale.US);
+
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
+        final ResponseSpecification errorResponse = new 
ResponseSpecBuilder().expectStatusCode(400).build();
+        final SavingsAccountHelper validationErrorHelper = new 
SavingsAccountHelper(this.requestSpec, errorResponse);
+
+        /***
+         * Create a client to apply for savings account (overdraft account).
+         */
+        final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec);
+        ClientHelper.verifyClientCreatedOnServer(this.requestSpec, 
this.responseSpec, clientID);
+        // Assertions.assertNotNull(clientID);
+        final String minBalanceForInterestCalculation = null;
+
+        /***
+         * Create savings product with zero opening balance and overdraft 
enabled
+         */
+        final String nonZeroOpeningBalance = "1000";
+        final String minRequiredBalance = null;
+        final String enforceMinRequiredBalance = "false";
+        final boolean allowOverdraft = false;
+        final Integer savingsProductID = 
createSavingsProduct(this.requestSpec, this.responseSpec, nonZeroOpeningBalance,
+                minBalanceForInterestCalculation, minRequiredBalance, 
enforceMinRequiredBalance, allowOverdraft);
+        Assertions.assertNotNull(savingsProductID);
+
+        /***
+         * Apply for Savings account
+         */
+        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);
+
+        /***
+         * Approve the savings account
+         */
+        savingsStatusHashMap = 
this.savingsAccountHelper.approveSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
+
+        LocalDate todaysDate = Utils.getLocalDateOfTenant();
+        todaysDate = todaysDate.minusMonths(1);
+        todaysDate = todaysDate.withDayOfMonth(1);
+        final String ACTIVATION_DATE = dateFormat.format(todaysDate);
+
+        /***
+         * Activate the application and verify account status
+         *
+         * @param activationDate
+         *            this value is every time first day of previous month
+         */
+        savingsStatusHashMap = activateSavingsAccount(savingsId, 
ACTIVATION_DATE);
+        SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
+
+        Float balance = Float.parseFloat(nonZeroOpeningBalance);
+
+        /***
+         * Attempt a withdrawal transaction, verify an exception will be 
thrown since there are no prior transactions to
+         * this transaction
+         */
+        /***
+         * Perform withdraw transaction, verify account balance(account 
balance will go to negative as no deposits are
+         * there prior to this transaction)
+         */
+        Integer withdrawTransactionId = (Integer) 
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
WITHDRAW_AMOUNT,
+                ACTIVATION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
+        HashMap withdrawTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
withdrawTransactionId);
+        balance -= Float.parseFloat(WITHDRAW_AMOUNT);
+        assertEquals(Float.parseFloat(WITHDRAW_AMOUNT), 
withdrawTransaction.get("amount"), "Verifying Withdrawal Amount");
+        assertEquals(balance, withdrawTransaction.get("runningBalance"), 
"Verifying Balance after Withdrawal");
+
+    }
+
     private Integer createSavingsAccountDailyPostingOverdraft(final Integer 
clientID, final String startDate) {
         final Integer savingsProductID = 
createSavingsProductDailyPostingOverdraft();
         Assertions.assertNotNull(savingsProductID);

Reply via email to