diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java index fc82350ce..d99dcd95f 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionData.java @@ -115,24 +115,26 @@ public final class SavingsAccountTransactionData implements Serializable { final Money amount, final boolean isManualTransaction) { final boolean isReversed = false; final Boolean lienTransaction = false; + final LocalDate submittedOnDate = DateUtils.getBusinessLocalDate(); final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.INTEREST_POSTING; SavingsAccountTransactionEnumData savingsAccountTransactionEnumData = new SavingsAccountTransactionEnumData( savingsAccountTransactionType.getValue().longValue(), savingsAccountTransactionType.getCode(), savingsAccountTransactionType.getValue().toString()); return new SavingsAccountTransactionData(amount.getAmount(), date, savingsAccount.getId(), savingsAccountTransactionEnumData, - isReversed, null, isManualTransaction, lienTransaction); + isReversed, null, isManualTransaction, lienTransaction, submittedOnDate); } public static SavingsAccountTransactionData overdraftInterest(final SavingsAccountData savingsAccount, final LocalDate date, final Money amount, final boolean isManualTransaction) { final boolean isReversed = false; final Boolean lienTransaction = false; + final LocalDate submittedOnDate = DateUtils.getBusinessLocalDate(); final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.OVERDRAFT_INTEREST; SavingsAccountTransactionEnumData savingsAccountTransactionEnumData = new SavingsAccountTransactionEnumData( savingsAccountTransactionType.getValue().longValue(), savingsAccountTransactionType.getCode(), savingsAccountTransactionType.getValue().toString()); return new SavingsAccountTransactionData(amount.getAmount(), date, savingsAccount.getId(), savingsAccountTransactionEnumData, - isReversed, null, isManualTransaction, lienTransaction); + isReversed, null, isManualTransaction, lienTransaction, submittedOnDate); } public boolean isInterestPostingAndNotReversed() { @@ -305,14 +307,14 @@ public final class SavingsAccountTransactionData implements Serializable { private SavingsAccountTransactionData(final Long savingsId, final Long officeId, final PaymentDetailData paymentDetailData, final SavingsAccountTransactionEnumData savingsAccountTransactionType, final LocalDate transactionDate, - final LocalDate createdDate, final BigDecimal amount, final boolean isReversed, final Long userId, + final LocalDate submittedOnDate, final BigDecimal amount, final boolean isReversed, final Long userId, final boolean isManualTransaction, final Boolean lienTransaction) { this.savingsAccountId = savingsId; this.paymentDetailData = paymentDetailData; this.transactionType = savingsAccountTransactionType; this.entryType = transactionType == null ? null : transactionType.getTransactionTypeEnum().getEntryType(); this.transactionDate = transactionDate; - this.submittedOnDate = createdDate; + this.submittedOnDate = submittedOnDate; this.amount = amount; this.isManualTransaction = isManualTransaction; this.lienTransaction = lienTransaction; @@ -435,12 +437,13 @@ public final class SavingsAccountTransactionData implements Serializable { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; + final LocalDate submittedOnDate = DateUtils.getBusinessLocalDate(); SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.WITHHOLD_TAX; SavingsAccountTransactionEnumData transactionType = new SavingsAccountTransactionEnumData( savingsAccountTransactionType.getValue().longValue(), savingsAccountTransactionType.getCode(), savingsAccountTransactionType.getValue().toString()); SavingsAccountTransactionData accountTransaction = new SavingsAccountTransactionData(amount.getAmount(), date, - savingsAccount.getId(), transactionType, isReversed, null, isManualTransaction, lienTransaction); + savingsAccount.getId(), transactionType, isReversed, null, isManualTransaction, lienTransaction, submittedOnDate); updateTaxDetails(taxDetails, accountTransaction); return accountTransaction; } @@ -509,7 +512,7 @@ public final class SavingsAccountTransactionData implements Serializable { private SavingsAccountTransactionData(BigDecimal transactionAmount, LocalDate transactionDate, Long savingsAccountId, SavingsAccountTransactionEnumData transactionType, boolean isReversed, String locale, boolean isManualTransaction, - final Boolean lienTransaction) { + final Boolean lienTransaction, final LocalDate submittedOnDate) { this.id = null; this.transactionType = transactionType; this.entryType = transactionType == null ? null : transactionType.getTransactionTypeEnum().getEntryType(); @@ -523,7 +526,7 @@ public final class SavingsAccountTransactionData implements Serializable { this.runningBalance = null; this.reversed = isReversed; this.transfer = null; - this.submittedOnDate = transactionDate; + this.submittedOnDate = submittedOnDate; this.interestedPostedAsOn = false; this.rowIndex = null; this.savingsAccountId = savingsAccountId; @@ -673,11 +676,11 @@ public final class SavingsAccountTransactionData implements Serializable { final PaymentDetailData paymentDetailData, final Long savingsId, final String savingsAccountNo, final LocalDate date, final CurrencyData currency, final BigDecimal amount, final BigDecimal outstandingChargeAmount, final BigDecimal runningBalance, final boolean reversed, final AccountTransferData transfer, final boolean interestedPostedAsOn, - final String submittedByUsername, final String note) { + final String submittedByUsername, final String note, final LocalDate submittedOnDate) { final Collection paymentTypeOptions = null; return new SavingsAccountTransactionData(id, transactionType, paymentDetailData, savingsId, savingsAccountNo, date, currency, amount, outstandingChargeAmount, runningBalance, reversed, transfer, paymentTypeOptions, interestedPostedAsOn, - submittedByUsername, note, false); + submittedByUsername, note, false, submittedOnDate); } public static SavingsAccountTransactionData create(final Long id, final SavingsAccountTransactionEnumData transactionType, @@ -715,30 +718,32 @@ public final class SavingsAccountTransactionData implements Serializable { final Boolean lienTransaction = false; return new SavingsAccountTransactionData(id, transactionType, paymentDetailData, savingsId, savingsAccountNo, defaultLocalDate, currency, amount, outstandingChargeAmount, runningBalance, reversed, null, null, interestedPostedAsOn, submittedByUsername, - note, lienTransaction); + note, lienTransaction, defaultLocalDate); } public static SavingsAccountTransactionData templateOnTop(final SavingsAccountTransactionData savingsAccountTransactionData, final Collection paymentTypeOptions) { - return new SavingsAccountTransactionData(savingsAccountTransactionData.id, savingsAccountTransactionData.transactionType, - savingsAccountTransactionData.paymentDetailData, savingsAccountTransactionData.accountId, - savingsAccountTransactionData.accountNo, savingsAccountTransactionData.date, savingsAccountTransactionData.currency, - savingsAccountTransactionData.amount, savingsAccountTransactionData.outstandingChargeAmount, - savingsAccountTransactionData.runningBalance, savingsAccountTransactionData.reversed, - savingsAccountTransactionData.transfer, paymentTypeOptions, savingsAccountTransactionData.interestedPostedAsOn, - savingsAccountTransactionData.submittedByUsername, savingsAccountTransactionData.note, - savingsAccountTransactionData.lienTransaction); + return new SavingsAccountTransactionData(savingsAccountTransactionData.getId(), savingsAccountTransactionData.getTransactionType(), + savingsAccountTransactionData.getPaymentDetailData(), savingsAccountTransactionData.getAccountId(), + savingsAccountTransactionData.getAccountNo(), savingsAccountTransactionData.getDate(), + savingsAccountTransactionData.getCurrency(), savingsAccountTransactionData.getAmount(), + savingsAccountTransactionData.getOutstandingChargeAmount(), savingsAccountTransactionData.getRunningBalance(), + savingsAccountTransactionData.isReversed(), savingsAccountTransactionData.getTransfer(), paymentTypeOptions, + savingsAccountTransactionData.isInterestedPostedAsOn(), savingsAccountTransactionData.getSubmittedByUsername(), + savingsAccountTransactionData.getNote(), savingsAccountTransactionData.getLienTransaction(), + savingsAccountTransactionData.getSubmittedOnDate()); } private SavingsAccountTransactionData(final Long id, final SavingsAccountTransactionEnumData transactionType, final PaymentDetailData paymentDetailData, final Long savingsId, final String savingsAccountNo, final LocalDate date, final CurrencyData currency, final BigDecimal amount, final BigDecimal outstandingChargeAmount, final BigDecimal runningBalance, final boolean reversed, final AccountTransferData transfer, final Collection paymentTypeOptions, - final boolean interestedPostedAsOn, final String submittedByUsername, final String note, final Boolean lienTransaction) { + final boolean interestedPostedAsOn, final String submittedByUsername, final String note, final Boolean lienTransaction, + final LocalDate submittedOnDate) { this(id, transactionType, paymentDetailData, savingsId, savingsAccountNo, date, currency, amount, outstandingChargeAmount, - runningBalance, reversed, transfer, paymentTypeOptions, date, interestedPostedAsOn, submittedByUsername, note, null, null, - lienTransaction, null, null); + runningBalance, reversed, transfer, paymentTypeOptions, submittedOnDate, interestedPostedAsOn, submittedByUsername, note, + null, null, lienTransaction, null, null); } private SavingsAccountTransactionData(final Long id, final SavingsAccountTransactionEnumData transactionType, @@ -787,14 +792,15 @@ public final class SavingsAccountTransactionData implements Serializable { final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations .transactionType(SavingsAccountTransactionType.WITHDRAWAL.getValue()); - return new SavingsAccountTransactionData(savingsAccountTransactionData.id, transactionType, - savingsAccountTransactionData.paymentDetailData, savingsAccountTransactionData.accountId, - savingsAccountTransactionData.accountNo, currentDate, savingsAccountTransactionData.currency, - savingsAccountTransactionData.amount, savingsAccountTransactionData.outstandingChargeAmount, - savingsAccountTransactionData.runningBalance, savingsAccountTransactionData.reversed, - savingsAccountTransactionData.transfer, savingsAccountTransactionData.paymentTypeOptions, - savingsAccountTransactionData.interestedPostedAsOn, savingsAccountTransactionData.submittedByUsername, - savingsAccountTransactionData.note, savingsAccountTransactionData.lienTransaction); + return new SavingsAccountTransactionData(savingsAccountTransactionData.getId(), transactionType, + savingsAccountTransactionData.getPaymentDetailData(), savingsAccountTransactionData.getAccountId(), + savingsAccountTransactionData.getAccountNo(), currentDate, savingsAccountTransactionData.getCurrency(), + savingsAccountTransactionData.getAmount(), savingsAccountTransactionData.getOutstandingChargeAmount(), + savingsAccountTransactionData.getRunningBalance(), savingsAccountTransactionData.isReversed(), + savingsAccountTransactionData.getTransfer(), savingsAccountTransactionData.getPaymentTypeOptions(), + savingsAccountTransactionData.isInterestedPostedAsOn(), savingsAccountTransactionData.getSubmittedByUsername(), + savingsAccountTransactionData.getNote(), savingsAccountTransactionData.getLienTransaction(), + savingsAccountTransactionData.getSubmittedOnDate()); } public void setId(final Long id) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java index 490e7f50a..2f33cbf4e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java @@ -149,6 +149,25 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom { this.createdDate = null; } + private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, + final Integer typeOf, final LocalDate transactionLocalDate, final LocalDateTime createdDate, final BigDecimal amount, + final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction, + final String refNo) { + this.savingsAccount = savingsAccount; + this.office = office; + this.typeOf = typeOf; + this.dateOf = transactionLocalDate; + this.amount = amount; + this.reversed = isReversed; + this.paymentDetail = paymentDetail; + this.createdDate = createdDate; + this.submittedOnDate = DateUtils.getBusinessLocalDate(); + this.appUser = appUser; + this.isManualTransaction = isManualTransaction; + this.lienTransaction = lienTransaction; + this.refNo = refNo; + } + public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, final LocalDate date, final Money amount, LocalDateTime createdDate, final AppUser appUser, final String refNo) { @@ -226,14 +245,6 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom { isReversed, appUser, isManualTransaction, lienTransaction, refNo); } - public static SavingsAccountTransaction from(final Integer transactionTypeEnum, final LocalDate transactionDate, - final BigDecimal amount, final boolean isReversed, final BigDecimal runningBalance, final BigDecimal cumulativeBalance, - final LocalDate balanceEndDate, final Integer balanceNumberOfDays, final BigDecimal overdraftAmount, - final LocalDateTime createdDate, final boolean isManualTransaction, final Long releaseIdOfHoldAmountTransaction) { - return new SavingsAccountTransaction(transactionTypeEnum, transactionDate, amount, isReversed, runningBalance, cumulativeBalance, - balanceEndDate, balanceNumberOfDays, overdraftAmount, createdDate, isManualTransaction, releaseIdOfHoldAmountTransaction); - } - public static SavingsAccountTransaction waiver(final SavingsAccount savingsAccount, final Office office, final LocalDate date, final Money amount, final AppUser appUser) { final boolean isReversed = false; @@ -336,44 +347,6 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom { isManualTransaction, lienTransaction, refNo); } - private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, - final Integer typeOf, final LocalDate transactionLocalDate, final LocalDateTime createdDate, final BigDecimal amount, - final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction, - final String refNo) { - this.savingsAccount = savingsAccount; - this.office = office; - this.typeOf = typeOf; - this.dateOf = transactionLocalDate; - this.amount = amount; - this.reversed = isReversed; - this.paymentDetail = paymentDetail; - this.createdDate = createdDate; - this.submittedOnDate = DateUtils.getBusinessLocalDate(); - this.appUser = appUser; - this.isManualTransaction = isManualTransaction; - this.lienTransaction = lienTransaction; - this.refNo = refNo; - } - - private SavingsAccountTransaction(final Integer transactionTypeEnum, final LocalDate transactionDate, final BigDecimal amount, - final boolean isReversed, final BigDecimal runningBalance, final BigDecimal cumulativeBalance, final LocalDate balanceEndDate, - final Integer balanceNumberOfDays, final BigDecimal overdraftAmount, final LocalDateTime createdDate, - final boolean isManualTransaction, final Long releaseIdOfHoldAmountTransaction) { - this.typeOf = transactionTypeEnum; - this.dateOf = transactionDate; - this.amount = amount; - this.reversed = isReversed; - this.runningBalance = runningBalance; - this.cumulativeBalance = cumulativeBalance; - this.balanceEndDate = balanceEndDate; - this.balanceNumberOfDays = balanceNumberOfDays; - this.overdraftAmount = overdraftAmount; - this.createdDate = createdDate; - this.submittedOnDate = DateUtils.getBusinessLocalDate(); - this.isManualTransaction = isManualTransaction; - this.releaseIdOfHoldAmountTransaction = releaseIdOfHoldAmountTransaction; - } - public static SavingsAccountTransaction holdAmount(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, final LocalDate date, final Money amount, LocalDateTime createdDate, final AppUser appUser, final Boolean lienTransaction) { @@ -921,6 +894,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom { return this.createdDate; } + public LocalDate getSubmittedOnDate() { + return submittedOnDate; + } + public boolean getIsManualTransaction() { return this.isManualTransaction; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java index 0ed3fffba..c9698b5ad 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java @@ -1131,6 +1131,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead public static final String TO_TRANSFER_REVERSED = "toTransferReversed"; public static final String TO_TRANSFER_DESCRIPTION = "toTransferDescription"; public static final String SUBMITTED_BY_USERNAME = "submittedByUsername"; + public static final String SUBMITTED_ON_DATE = "submittedOnDate"; private final String schemaSql; SavingsAccountTransactionsMapper() { @@ -1139,6 +1140,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead sqlBuilder.append("tr.id as transactionId, tr.transaction_type_enum as transactionType, "); sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount,"); sqlBuilder.append("tr.running_balance_derived as runningBalance, tr.is_reversed as reversed,"); + sqlBuilder.append("tr.submitted_on_date as submittedOnDate,"); sqlBuilder.append("fromtran.id as fromTransferId, fromtran.is_reversed as fromTransferReversed,"); sqlBuilder.append("fromtran.transaction_date as fromTransferDate, fromtran.amount as fromTransferAmount,"); sqlBuilder.append("fromtran.description as fromTransferDescription,"); @@ -1176,6 +1178,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations.transactionType(transactionTypeInt); final LocalDate date = JdbcSupport.getLocalDate(rs, TRANSACTION_DATE); + final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, SUBMITTED_ON_DATE); final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, TRANSACTION_AMOUNT); final BigDecimal outstandingChargeAmount = null; final BigDecimal runningBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, RUNNING_BALANCE); @@ -1233,7 +1236,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead final String submittedByUsername = rs.getString(SUBMITTED_BY_USERNAME); final String note = null; return SavingsAccountTransactionData.create(id, transactionType, paymentDetailData, savingsId, accountNo, date, currency, - amount, outstandingChargeAmount, runningBalance, reversed, transfer, postInterestAsOn, submittedByUsername, note); + amount, outstandingChargeAmount, runningBalance, reversed, transfer, postInterestAsOn, submittedByUsername, note, + submittedOnDate); } } @@ -1662,9 +1666,10 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead final boolean postInterestAsOn = false; final String submittedByUsername = null; final String note = null; + final LocalDate submittedOnDate = DateUtils.getBusinessLocalDate(); return SavingsAccountTransactionData.create(savingsId, transactionType, paymentDetailData, savingsId, accountNo, duedate, currency, dueamount, outstandingChargeAmount, runningBalance, false, transfer, postInterestAsOn, submittedByUsername, - note); + note, submittedOnDate); } } 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 0bce93194..2a757b5e1 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 @@ -351,7 +351,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("sp.accounting_type as accountingType, "); sqlBuilder.append("tr.id as transactionId, tr.transaction_type_enum as transactionType, "); sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount,"); - sqlBuilder.append("tr.created_date as createdDate,tr.cumulative_balance_derived as cumulativeBalance,"); + sqlBuilder.append("tr.submitted_on_date as transSubmittedOnDate,tr.cumulative_balance_derived as cumulativeBalance,"); sqlBuilder.append("tr.running_balance_derived as runningBalance, tr.is_reversed as reversed,"); sqlBuilder.append("tr.balance_end_date_derived as balanceEndDate, tr.overdraft_amount_derived as overdraftAmount,"); sqlBuilder.append("tr.is_manual as manualTransaction,tr.office_id as officeId, "); @@ -600,7 +600,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final LocalDate date = JdbcSupport.getLocalDate(rs, "transactionDate"); final LocalDate balanceEndDate = JdbcSupport.getLocalDate(rs, "balanceEndDate"); - final LocalDate transSubmittedOnDate = JdbcSupport.getLocalDate(rs, "createdDate"); + final LocalDate transSubmittedOnDate = JdbcSupport.getLocalDate(rs, "transSubmittedOnDate"); final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "transactionAmount"); final BigDecimal overdraftAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "overdraftAmount"); final BigDecimal outstandingChargeAmount = null; @@ -1324,7 +1324,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount,"); sqlBuilder.append(" tr.release_id_of_hold_amount as releaseTransactionId,"); sqlBuilder.append(" tr.reason_for_block as reasonForBlock,"); - sqlBuilder.append("tr.created_date as submittedOnDate,"); + sqlBuilder.append(" tr.submitted_on_date as submittedOnDate,"); sqlBuilder.append(" au.username as submittedByUsername, "); sqlBuilder.append(" nt.note as transactionNote, "); sqlBuilder.append("tr.running_balance_derived as runningBalance, tr.is_reversed as reversed,"); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java new file mode 100644 index 000000000..ad52b84b1 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java @@ -0,0 +1,156 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.integrationtests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.integrationtests.common.BusinessDateHelper; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.CommonConstants; +import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper; +import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper; +import org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@SuppressWarnings({ "rawtypes" }) +public class SavingsAccountTransactionTest { + + public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL"; + public static final String DEFAULT_DATE_FORMAT = "dd MMM yyyy"; + final String startDateString = "03 June 2023"; + final String depositDateString = "05 June 2023"; + final String withdrawDateString = "10 June 2023"; + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + private SavingsProductHelper savingsProductHelper; + private SavingsAccountHelper savingsAccountHelper; + + @BeforeEach + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + this.savingsProductHelper = new SavingsProductHelper(); + } + + @Test + public void verifySavingsTransactionSubmittedOnDateAndTransactionDate() throws JsonProcessingException { + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + try { + enableBusinessDate(requestSpec, responseSpec, true); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, today); + + LocalDate depositDate = Utils.getDateAsLocalDate(depositDateString); + LocalDate withdrawDate = Utils.getDateAsLocalDate(withdrawDateString); + + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDateString); + Assertions.assertNotNull(clientID); + + final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDateString); + Assertions.assertNotNull(savingsId); + + performSavingsTransaction(savingsId, "100", depositDate, true); + performSavingsTransaction(savingsId, "50", withdrawDate, false); + } finally { + enableBusinessDate(requestSpec, responseSpec, false); + } + + } + + private void enableBusinessDate(RequestSpecification requestSpec, ResponseSpecification responseSpec, boolean enable) { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, enable); + } + + private void performSavingsTransaction(Integer savingsId, String amount, LocalDate transactionDate, boolean isDeposit) { + String transactionType = isDeposit ? "Deposit" : "Withdrawal"; + Integer transactionId = isDeposit + ? (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, amount, depositDateString, + CommonConstants.RESPONSE_RESOURCE_ID) + : (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, amount, withdrawDateString, + CommonConstants.RESPONSE_RESOURCE_ID); + + Assertions.assertNotNull(transactionId); + + HashMap transaction = savingsAccountHelper.getSavingsTransaction(savingsId, transactionId); + Assertions.assertNotNull(transaction); + + assertEquals(transactionId, (Integer) transaction.get("id"), "Check Savings " + transactionType + " Transaction"); + LocalDate transactionDateFromResponse = extractLocalDate(transaction, "date"); + assertTrue(transactionDate.compareTo(transactionDateFromResponse) == 0, + "Transaction Date check for Savings " + transactionType + " Transaction"); + LocalDate submittedOnDate = extractLocalDate(transaction, "submittedOnDate"); + assertTrue(LocalDate.now(ZoneId.systemDefault()).compareTo(submittedOnDate) == 0, + "Submitted On Date check for Savings " + transactionType + " Transaction"); + } + + private LocalDate extractLocalDate(HashMap transactionMap, String fieldName) { + List dateStringList = (List) transactionMap.get(fieldName); + LocalDate extractedDate = dateStringList.stream() + .collect(Collectors.collectingAndThen(Collectors.toList(), list -> LocalDate.of(list.get(0), list.get(1), list.get(2)))); + return extractedDate; + } + + private Integer createSavingsAccountDailyPosting(final Integer clientID, final String startDate) { + final Integer savingsProductID = createSavingsProductDailyPosting(); + Assertions.assertNotNull(savingsProductID); + final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplicationOnDate(clientID, savingsProductID, + ACCOUNT_TYPE_INDIVIDUAL, startDate); + Assertions.assertNotNull(savingsId); + HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavingsOnDate(savingsId, startDate); + SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap); + savingsStatusHashMap = this.savingsAccountHelper.activateSavingsAccount(savingsId, startDate); + SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); + return savingsId; + } + + private Integer createSavingsProductDailyPosting() { + final String savingsProductJSON = this.savingsProductHelper.withInterestCompoundingPeriodTypeAsDaily() + .withInterestPostingPeriodTypeAsDaily().withInterestCalculationPeriodTypeAsDailyBalance().build(); + return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); + } + + // Reset configuration fields + @AfterEach + public void tearDown() { + GlobalConfigurationHelper.resetAllDefaultGlobalConfigurations(this.requestSpec, this.responseSpec); + GlobalConfigurationHelper.verifyAllDefaultGlobalConfigurations(this.requestSpec, this.responseSpec); + } + +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingIntegrationTest.java index 3fe166a36..6597f6ed9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingIntegrationTest.java @@ -19,15 +19,22 @@ package org.apache.fineract.integrationtests; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; +import java.time.LocalDate; +import java.time.ZoneId; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.integrationtests.common.BusinessDateHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.CommonConstants; import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; @@ -65,27 +72,38 @@ public class SavingsInterestPostingIntegrationTest { @Test public void testSavingsDailyInterestPosting() { - // client activation, savings activation and 1st transaction date - final String startDate = "01 November 2021"; - final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); - Assertions.assertNotNull(clientID); + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + try { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, true); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, today); + // client activation, savings activation and 1st transaction date + final String startDate = "01 November 2021"; + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); + Assertions.assertNotNull(clientID); - final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDate); + final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDate); - this.savingsAccountHelper.depositToSavingsAccount(savingsId, "1000", startDate, CommonConstants.RESPONSE_RESOURCE_ID); + this.savingsAccountHelper.depositToSavingsAccount(savingsId, "1000", startDate, CommonConstants.RESPONSE_RESOURCE_ID); - /*** - * Perform Post interest transaction and verify the posted transaction date - */ - this.savingsAccountHelper.postInterestForSavings(savingsId); - HashMap accountDetails = this.savingsAccountHelper.getSavingsDetails(savingsId); - ArrayList> transactions = (ArrayList>) accountDetails.get("transactions"); - HashMap interestPostingTransaction = transactions.get(transactions.size() - 2); - for (Map.Entry entry : interestPostingTransaction.entrySet()) { - LOG.info("{} - {}", entry.getKey(), entry.getValue().toString()); + /*** + * Perform Post interest transaction and verify the posted transaction date + */ + this.savingsAccountHelper.postInterestForSavings(savingsId); + HashMap accountDetails = this.savingsAccountHelper.getSavingsDetails(savingsId); + ArrayList> transactions = (ArrayList>) accountDetails.get("transactions"); + HashMap interestPostingTransaction = transactions.get(transactions.size() - 2); + for (Map.Entry entry : interestPostingTransaction.entrySet()) { + LOG.info("{} - {}", entry.getKey(), entry.getValue().toString()); + } + assertEquals("0.274", interestPostingTransaction.get("amount").toString(), "Equality check for interest posted amount"); + assertEquals("[2021, 11, 2]", interestPostingTransaction.get("date").toString(), "Date check for Interest Posting transaction"); + List submittedOnDateStringList = (List) interestPostingTransaction.get("submittedOnDate"); + LocalDate submittedOnDate = submittedOnDateStringList.stream().collect( + Collectors.collectingAndThen(Collectors.toList(), list -> LocalDate.of(list.get(0), list.get(1), list.get(2)))); + assertTrue(submittedOnDate.compareTo(today) == 0, "Submitted On Date check for Interest Posting transaction"); + } finally { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, false); } - assertEquals("0.274", interestPostingTransaction.get("amount").toString(), "Equality check for interest posted amount"); - assertEquals("[2021, 11, 2]", interestPostingTransaction.get("date").toString(), "Date check for Interest Posting transaction"); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingJobIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingJobIntegrationTest.java index e0a1a51f8..5876d53a7 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingJobIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsInterestPostingJobIntegrationTest.java @@ -19,15 +19,22 @@ package org.apache.fineract.integrationtests; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; +import java.time.LocalDate; +import java.time.ZoneId; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.integrationtests.common.BusinessDateHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.CommonConstants; import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; @@ -142,29 +149,41 @@ public class SavingsInterestPostingJobIntegrationTest { @Test public void testSavingsDailyInterestPostingJob() { - // client activation, savings activation and 1st transaction date - final String startDate = "10 April 2022"; - final String jobName = "Post Interest For Savings"; - final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); - Assertions.assertNotNull(clientID); + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + try { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, true); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, today); + // client activation, savings activation and 1st transaction date + final String startDate = "10 April 2022"; + final String jobName = "Post Interest For Savings"; + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate); + Assertions.assertNotNull(clientID); - final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDate); + final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDate); - this.savingsAccountHelper.depositToSavingsAccount(savingsId, "10000", startDate, CommonConstants.RESPONSE_RESOURCE_ID); + this.savingsAccountHelper.depositToSavingsAccount(savingsId, "10000", startDate, CommonConstants.RESPONSE_RESOURCE_ID); - /*** - * Runs Post interest posting job and verify the new account created with accounting configuration set as none - * is picked up by job - */ - this.scheduleJobHelper.executeAndAwaitJob(jobName); - Object transactionObj = this.savingsAccountHelper.getSavingsDetails(savingsId, "transactions"); - ArrayList> transactions = (ArrayList>) transactionObj; - HashMap interestPostingTransaction = transactions.get(transactions.size() - 3); - for (Map.Entry entry : interestPostingTransaction.entrySet()) { - LOG.info("{} - {}", entry.getKey(), entry.getValue().toString()); + /*** + * Runs Post interest posting job and verify the new account created with accounting configuration set as + * none is picked up by job + */ + this.scheduleJobHelper.executeAndAwaitJob(jobName); + Object transactionObj = this.savingsAccountHelper.getSavingsDetails(savingsId, "transactions"); + ArrayList> transactions = (ArrayList>) transactionObj; + HashMap interestPostingTransaction = transactions.get(transactions.size() - 3); + for (Map.Entry entry : interestPostingTransaction.entrySet()) { + LOG.info("{} - {}", entry.getKey(), entry.getValue().toString()); + } + assertEquals("2.7405", interestPostingTransaction.get("amount").toString(), "Equality check for interest posted amount"); + assertEquals("[2022, 4, 12]", interestPostingTransaction.get("date").toString(), "Date check for Interest Posting transaction"); + List submittedOnDateStringList = (List) interestPostingTransaction.get("submittedOnDate"); + LocalDate submittedOnDate = submittedOnDateStringList.stream().collect( + Collectors.collectingAndThen(Collectors.toList(), list -> LocalDate.of(list.get(0), list.get(1), list.get(2)))); + assertTrue(submittedOnDate.compareTo(today) == 0, "Submitted On Date check for Interest Posting transaction"); + } finally { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, false); } - assertEquals("2.7405", interestPostingTransaction.get("amount").toString(), "Equality check for interest posted amount"); - assertEquals("[2022, 4, 12]", interestPostingTransaction.get("date").toString(), "Date check for Interest Posting transaction"); + } @Test