Feat: Filter Transactions from last interest posting date (#1933)
This commit is contained in:
+6
@@ -104,4 +104,10 @@ public interface ConfigurationDomainService {
|
||||
String getAccountMappingForCharge();
|
||||
|
||||
boolean isNextDayFixedDepositInterestTransferEnabledForPeriodEnd();
|
||||
|
||||
boolean retrievePivotDateConfig();
|
||||
|
||||
boolean isRelaxingDaysConfigForPivotDateEnabled();
|
||||
|
||||
Long retrieveRelaxingDaysConfigForPivotDate();
|
||||
}
|
||||
|
||||
+25
@@ -343,6 +343,31 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retrievePivotDateConfig() {
|
||||
final String propertyName = "allow-backdated-transaction-before-interest-posting";
|
||||
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
|
||||
return !property.isEnabled();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelaxingDaysConfigForPivotDateEnabled() {
|
||||
final String propertyName = "allow-backdated-transaction-before-interest-posting-date-for-days";
|
||||
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
|
||||
return property.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long retrieveRelaxingDaysConfigForPivotDate() {
|
||||
final String propertyName = "allow-backdated-transaction-before-interest-posting-date-for-days";
|
||||
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
|
||||
if (property.getValue() == null) {
|
||||
return Long.valueOf(0);
|
||||
}
|
||||
return property.getValue();
|
||||
}
|
||||
|
||||
private GlobalConfigurationPropertyData getGlobalConfigurationPropertyData(final String propertyName) {
|
||||
String identifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
|
||||
String key = identifier + "_" + propertyName;
|
||||
|
||||
+4
-2
@@ -427,6 +427,7 @@ public class InteropServiceImpl implements InteropService {
|
||||
LocalDate transactionDate = transactionDateTime.toLocalDate();
|
||||
DateTimeFormatter fmt = getDateTimeFormatter(command);
|
||||
SavingsAccountTransaction transaction;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
|
||||
if (isDebit) {
|
||||
SavingsAccountTransaction holdTransaction = findTransaction(savingsAccount, transferCode, AMOUNT_HOLD.getValue());
|
||||
@@ -457,10 +458,11 @@ public class InteropServiceImpl implements InteropService {
|
||||
SavingsTransactionBooleanValues transactionValues = new SavingsTransactionBooleanValues(false, true, true, false, false);
|
||||
transaction = savingsAccountService.handleWithdrawal(savingsAccount, fmt, transactionDate, request.getAmount().getAmount(),
|
||||
instance(findPaymentType(), savingsAccount.getExternalId(), null, getRoutingCode(), transferCode, null),
|
||||
transactionValues);
|
||||
transactionValues, backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
transaction = savingsAccountService.handleDeposit(savingsAccount, fmt, transactionDate, request.getAmount().getAmount(),
|
||||
instance(findPaymentType(), savingsAccount.getExternalId(), null, getRoutingCode(), transferCode, null), false, true);
|
||||
instance(findPaymentType(), savingsAccount.getExternalId(), null, getRoutingCode(), transferCode, null), false, true,
|
||||
backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
String note = request.getNote();
|
||||
|
||||
+7
-5
@@ -64,10 +64,11 @@ public class AccountTransferDetailAssembler {
|
||||
public AccountTransferDetails assembleSavingsToSavingsTransfer(final JsonCommand command) {
|
||||
|
||||
final Long fromSavingsId = command.longValueOfParameterNamed(fromAccountIdParamName);
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsId);
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsId, false);
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId, backdatedTxnsAllowedTill);
|
||||
|
||||
return assembleSavingsToSavingsTransfer(command, fromSavingsAccount, toSavingsAccount);
|
||||
|
||||
@@ -76,7 +77,8 @@ public class AccountTransferDetailAssembler {
|
||||
public AccountTransferDetails assembleSavingsToLoanTransfer(final JsonCommand command) {
|
||||
|
||||
final Long fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId);
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId, backdatedTxnsAllowedTill);
|
||||
|
||||
final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId);
|
||||
@@ -89,9 +91,9 @@ public class AccountTransferDetailAssembler {
|
||||
|
||||
final Long fromLoanAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
|
||||
final Loan fromLoanAccount = this.loanAccountAssembler.assembleFrom(fromLoanAccountId);
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId, backdatedTxnsAllowedTill);
|
||||
|
||||
return assembleLoanToSavingsTransfer(command, fromLoanAccount, toSavingsAccount);
|
||||
}
|
||||
|
||||
+3
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.account.service;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.portfolio.account.PortfolioAccountType;
|
||||
@@ -41,6 +42,8 @@ public interface AccountTransfersReadPlatformService {
|
||||
|
||||
Collection<Long> fetchPostInterestTransactionIds(Long accountId);
|
||||
|
||||
Collection<Long> fetchPostInterestTransactionIdsWithPivotDate(Long accountId, Date pivotDate);
|
||||
|
||||
AccountTransferData retrieveRefundByTransferTemplate(Long fromOfficeId, Long fromClientId, Long fromAccountId, Integer fromAccountType,
|
||||
Long toOfficeId, Long toClientId, Long toAccountId, Integer toAccountType);
|
||||
|
||||
|
||||
+11
@@ -26,6 +26,7 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
@@ -265,6 +266,16 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Long> fetchPostInterestTransactionIdsWithPivotDate(final Long accountId, final Date pivotDate) {
|
||||
final String sql = "select att.from_savings_transaction_id from m_account_transfer_transaction att inner join m_account_transfer_details atd on atd.id = att.account_transfer_details_id where atd.from_savings_account_id=? and att.is_reversed = 0 and atd.transfer_type = ? and att.transaction_date >= ?";
|
||||
|
||||
final List<Long> transactionIds = this.jdbcTemplate.queryForList(sql, Long.class, accountId,
|
||||
AccountTransferType.INTEREST_TRANSFER.getValue(), pivotDate);
|
||||
|
||||
return transactionIds;
|
||||
}
|
||||
|
||||
private static final class AccountTransfersMapper implements RowMapper<AccountTransferData> {
|
||||
|
||||
private final String schemaSql;
|
||||
|
||||
+25
-18
@@ -131,22 +131,24 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
boolean isAccountTransfer = true;
|
||||
Long fromLoanAccountId = null;
|
||||
boolean isWithdrawBalance = false;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
|
||||
if (isSavingsToSavingsAccountTransfer(fromAccountType, toAccountType)) {
|
||||
|
||||
fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId);
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId,
|
||||
backdatedTxnsAllowedTill);
|
||||
|
||||
final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer,
|
||||
isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), isInterestTransfer, isWithdrawBalance);
|
||||
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt,
|
||||
transactionDate, transactionAmount, paymentDetail, transactionBooleanValues);
|
||||
transactionDate, transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill);
|
||||
|
||||
final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId, backdatedTxnsAllowedTill);
|
||||
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
|
||||
if (!fromSavingsAccount.getCurrency().getCode().equals(toSavingsAccount.getCurrency().getCode())) {
|
||||
throw new DifferentCurrenciesException(fromSavingsAccount.getCurrency().getCode(),
|
||||
@@ -161,12 +163,13 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
} else if (isSavingsToLoanAccountTransfer(fromAccountType, toAccountType)) {
|
||||
//
|
||||
fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId);
|
||||
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId,
|
||||
backdatedTxnsAllowedTill);
|
||||
|
||||
final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer,
|
||||
isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), isInterestTransfer, isWithdrawBalance);
|
||||
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt,
|
||||
transactionDate, transactionAmount, paymentDetail, transactionBooleanValues);
|
||||
transactionDate, transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill);
|
||||
|
||||
final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId);
|
||||
@@ -194,10 +197,10 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null);
|
||||
|
||||
final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId, backdatedTxnsAllowedTill);
|
||||
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
|
||||
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command,
|
||||
fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction);
|
||||
@@ -288,6 +291,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
Long transferTransactionId = null;
|
||||
final boolean isAccountTransfer = true;
|
||||
final boolean isRegularTransaction = accountTransferDTO.isRegularTransaction();
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
AccountTransferDetails accountTransferDetails = accountTransferDTO.getAccountTransferDetails();
|
||||
if (isSavingsToLoanAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
||||
//
|
||||
@@ -295,7 +299,8 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
Loan toLoanAccount = null;
|
||||
if (accountTransferDetails == null) {
|
||||
if (accountTransferDTO.getFromSavingsAccount() == null) {
|
||||
fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId());
|
||||
fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId(),
|
||||
backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
fromSavingsAccount = accountTransferDTO.getFromSavingsAccount();
|
||||
this.savingsAccountAssembler.setHelpers(fromSavingsAccount);
|
||||
@@ -321,7 +326,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
|
||||
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
|
||||
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
|
||||
accountTransferDTO.getPaymentDetail(), transactionBooleanValues);
|
||||
accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill);
|
||||
|
||||
LoanTransaction loanTransaction = null;
|
||||
|
||||
@@ -351,13 +356,14 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
SavingsAccount toSavingsAccount = null;
|
||||
if (accountTransferDetails == null) {
|
||||
if (accountTransferDTO.getFromSavingsAccount() == null) {
|
||||
fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId());
|
||||
fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId(),
|
||||
backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
fromSavingsAccount = accountTransferDTO.getFromSavingsAccount();
|
||||
this.savingsAccountAssembler.setHelpers(fromSavingsAccount);
|
||||
}
|
||||
if (accountTransferDTO.getToSavingsAccount() == null) {
|
||||
toSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId());
|
||||
toSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId(), false);
|
||||
} else {
|
||||
toSavingsAccount = accountTransferDTO.getToSavingsAccount();
|
||||
this.savingsAccountAssembler.setHelpers(toSavingsAccount);
|
||||
@@ -383,11 +389,11 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
|
||||
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
|
||||
accountTransferDTO.getFmt(), transactionDate, accountTransferDTO.getTransactionAmount(),
|
||||
accountTransferDTO.getPaymentDetail(), transactionBooleanValues);
|
||||
accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill);
|
||||
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
|
||||
accountTransferDTO.getFmt(), transactionDate, accountTransferDTO.getTransactionAmount(),
|
||||
accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction);
|
||||
accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
|
||||
accountTransferDetails = this.accountTransferAssembler.assembleSavingsToSavingsTransfer(accountTransferDTO, fromSavingsAccount,
|
||||
toSavingsAccount, withdrawal, deposit);
|
||||
@@ -405,7 +411,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
fromLoanAccount = accountTransferDTO.getLoan();
|
||||
this.loanAccountAssembler.setHelpers(fromLoanAccount);
|
||||
}
|
||||
toSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId());
|
||||
toSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId(), backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
fromLoanAccount = accountTransferDetails.fromLoanAccount();
|
||||
this.loanAccountAssembler.setHelpers(fromLoanAccount);
|
||||
@@ -426,7 +432,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
|
||||
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
|
||||
accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction);
|
||||
accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(accountTransferDTO, fromLoanAccount,
|
||||
toSavingsAccount, deposit, loanTransaction);
|
||||
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
|
||||
@@ -523,6 +529,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
final Loan fromLoanAccount = this.loanAccountAssembler.assembleFrom(fromLoanAccountId);
|
||||
|
||||
BigDecimal overpaid = this.loanReadPlatformService.retrieveTotalPaidInAdvance(fromLoanAccountId).getPaidInAdvance();
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
|
||||
if (overpaid == null || overpaid.compareTo(BigDecimal.ZERO) == 0 ? Boolean.TRUE
|
||||
: Boolean.FALSE || transactionAmount.floatValue() > overpaid.floatValue()) {
|
||||
@@ -536,10 +543,10 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null);
|
||||
|
||||
final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId);
|
||||
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId, backdatedTxnsAllowedTill);
|
||||
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, true, true);
|
||||
transactionAmount, paymentDetail, true, true, backdatedTxnsAllowedTill);
|
||||
|
||||
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command,
|
||||
fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction);
|
||||
|
||||
+4
-2
@@ -111,12 +111,14 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
|
||||
guarantorCommand.validateForCreate();
|
||||
validateLoanStatus(loan);
|
||||
final List<GuarantorFundingDetails> guarantorFundingDetails = new ArrayList<>();
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
AccountAssociations accountAssociations = null;
|
||||
if (guarantorCommand.getSavingsId() != null) {
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(guarantorCommand.getSavingsId());
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(guarantorCommand.getSavingsId(),
|
||||
backdatedTxnsAllowedTill);
|
||||
validateGuarantorSavingsAccountActivationDateWithLoanSubmittedOnDate(loan, savingsAccount);
|
||||
accountAssociations = AccountAssociations.associateSavingsAccount(loan, savingsAccount,
|
||||
AccountAssociationType.GUARANTOR_ACCOUNT_ASSOCIATION.getValue(), true);
|
||||
AccountAssociationType.GUARANTOR_ACCOUNT_ASSOCIATION.getValue(), backdatedTxnsAllowedTill);
|
||||
|
||||
GuarantorFundingDetails fundingDetails = new GuarantorFundingDetails(accountAssociations,
|
||||
GuarantorFundStatusType.ACTIVE.getValue(), guarantorCommand.getAmount());
|
||||
|
||||
+8
-4
@@ -533,6 +533,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
// Save linked account information
|
||||
SavingsAccount savingsAccount;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
AccountAssociations accountAssociations;
|
||||
final Long savingsAccountId = command.longValueOfParameterNamed("linkAccountId");
|
||||
if (savingsAccountId != null) {
|
||||
@@ -551,8 +552,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
|
||||
if (gsimClientMembers.contains(BigDecimal.valueOf(newLoanApplication.getClientId()))) {
|
||||
savingsAccount = this.savingsAccountAssembler
|
||||
.assembleFrom(clientAccountMappings.get(BigDecimal.valueOf(newLoanApplication.getClientId())).longValue());
|
||||
savingsAccount = this.savingsAccountAssembler.assembleFrom(
|
||||
clientAccountMappings.get(BigDecimal.valueOf(newLoanApplication.getClientId())).longValue(),
|
||||
backdatedTxnsAllowedTill);
|
||||
|
||||
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
|
||||
boolean isActive = true;
|
||||
@@ -565,7 +567,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
} else {
|
||||
|
||||
savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||
savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId, backdatedTxnsAllowedTill);
|
||||
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
|
||||
boolean isActive = true;
|
||||
accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication, savingsAccount,
|
||||
@@ -1156,6 +1158,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
// Save linked account information
|
||||
final String linkAccountIdParamName = "linkAccountId";
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final Long savingsAccountId = command.longValueOfParameterNamed(linkAccountIdParamName);
|
||||
AccountAssociations accountAssociations = this.accountAssociationsRepository.findByLoanIdAndType(loanId,
|
||||
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||
@@ -1181,7 +1184,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
}
|
||||
if (isModified) {
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId,
|
||||
backdatedTxnsAllowedTill);
|
||||
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, existingLoanApplication);
|
||||
if (accountAssociations == null) {
|
||||
boolean isActive = true;
|
||||
|
||||
+1
@@ -86,6 +86,7 @@ public class SavingsApiConstants {
|
||||
public static final String transactionLowerLimitParamName = "transactionLowerLimit";
|
||||
public static final String retailEntriesParamName = "retailEntries";
|
||||
public static final String childAccountIdParamName = "childAccountId";
|
||||
public static final String interestPostedTillDate = "interestPostedTillDate";
|
||||
|
||||
public static final String groupIdParamName = "groupId";
|
||||
public static final String productIdParamName = "productId";
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
|
||||
"interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions",
|
||||
"interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee",
|
||||
"annualFee", onHoldFundsParamName, nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
|
||||
datatables, savingsAmountOnHold, accountMappingForPaymentParamName));
|
||||
datatables, savingsAmountOnHold, accountMappingForPaymentParamName, interestPostedTillDate));
|
||||
|
||||
protected static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(idParamName, "accountId", accountNoParamName, "currency", "amount", dateParamName, paymentDetailDataParamName,
|
||||
|
||||
+4
-1
@@ -44,12 +44,14 @@ public class SavingsAccountSummaryData implements Serializable {
|
||||
private final BigDecimal interestNotPosted;
|
||||
private final LocalDate lastInterestCalculationDate;
|
||||
private final BigDecimal availableBalance;
|
||||
private final LocalDate interestPostedTillDate;
|
||||
|
||||
public SavingsAccountSummaryData(final CurrencyData currency, final BigDecimal totalDeposits, final BigDecimal totalWithdrawals,
|
||||
final BigDecimal totalWithdrawalFees, final BigDecimal totalAnnualFees, final BigDecimal totalInterestEarned,
|
||||
final BigDecimal totalInterestPosted, final BigDecimal accountBalance, final BigDecimal totalFeeCharge,
|
||||
final BigDecimal totalPenaltyCharge, final BigDecimal totalOverdraftInterestDerived, final BigDecimal totalWithholdTax,
|
||||
final BigDecimal interestNotPosted, final LocalDate lastInterestCalculationDate, final BigDecimal availableBalance) {
|
||||
final BigDecimal interestNotPosted, final LocalDate lastInterestCalculationDate, final BigDecimal availableBalance,
|
||||
final LocalDate interestPostedTillDate) {
|
||||
this.currency = currency;
|
||||
this.totalDeposits = totalDeposits;
|
||||
this.totalWithdrawals = totalWithdrawals;
|
||||
@@ -65,5 +67,6 @@ public class SavingsAccountSummaryData implements Serializable {
|
||||
this.interestNotPosted = interestNotPosted;
|
||||
this.lastInterestCalculationDate = lastInterestCalculationDate;
|
||||
this.availableBalance = availableBalance;
|
||||
this.interestPostedTillDate = interestPostedTillDate;
|
||||
}
|
||||
}
|
||||
|
||||
+35
-4
@@ -44,6 +44,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
@@ -56,6 +57,7 @@ import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.apache.fineract.portfolio.savings.exception.TransactionBeforePivotDateNotAllowed;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -67,10 +69,31 @@ public class SavingsAccountTransactionDataValidator {
|
||||
private static final Set<String> SAVINGS_ACCOUNT_HOLD_AMOUNT_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(transactionDateParamName, SavingsApiConstants.dateFormatParamName, SavingsApiConstants.localeParamName,
|
||||
transactionAmountParamName));
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountTransactionDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
public SavingsAccountTransactionDataValidator(final FromJsonHelper fromApiJsonHelper,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
public void validateTransactionWithPivotDate(final LocalDate transactionDate, final SavingsAccount savingsAccount) {
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
|
||||
final boolean isRelaxingDaysConfigOn = this.configurationDomainService.isRelaxingDaysConfigForPivotDateEnabled();
|
||||
|
||||
final Date lastInterestPostingDate = savingsAccount.getSummary().getInterestPostedTillDate();
|
||||
|
||||
if (backdatedTxnsAllowedTill && lastInterestPostingDate != null) {
|
||||
LocalDate pivotDate = LocalDate.ofInstant(lastInterestPostingDate.toInstant(), DateUtils.getDateTimeZoneOfTenant());
|
||||
if (isRelaxingDaysConfigOn) {
|
||||
pivotDate = pivotDate.minusDays(this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate());
|
||||
}
|
||||
if (pivotDate.isAfter(transactionDate)) {
|
||||
throw new TransactionBeforePivotDateNotAllowed(transactionDate, pivotDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validate(final JsonCommand command) {
|
||||
@@ -181,8 +204,8 @@ public class SavingsAccountTransactionDataValidator {
|
||||
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction validateHoldAndAssembleForm(final String json, final SavingsAccount account,
|
||||
final AppUser createdUser) {
|
||||
public SavingsAccountTransaction validateHoldAndAssembleForm(final String json, final SavingsAccount account, final AppUser createdUser,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
@@ -210,7 +233,15 @@ public class SavingsAccountTransactionDataValidator {
|
||||
if (account.getWithdrawableBalance().compareTo(BigDecimal.ZERO) < 0) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId());
|
||||
}
|
||||
LocalDate lastTransactionDate = account.retrieveLastTransactionDate();
|
||||
|
||||
LocalDate lastTransactionDate = null;
|
||||
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
lastTransactionDate = account.retrieveLastTransactionDate();
|
||||
} else {
|
||||
lastTransactionDate = account.retrieveLastTransactionDateWithPivotConfig();
|
||||
}
|
||||
|
||||
// compare two dates now
|
||||
if (lastTransactionDate != null && transactionDate.isBefore(lastTransactionDate)) {
|
||||
baseDataValidator.parameter(SavingsApiConstants.dateParamName).value(lastTransactionDate).failWithCode(
|
||||
|
||||
+10
-6
@@ -115,11 +115,11 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
|
||||
boolean isAccountTransfer = false;
|
||||
boolean isInterestTransfer = false;
|
||||
boolean isWithdrawBalance = false;
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer,
|
||||
isRegularTransaction, applyWithdrawFee, isInterestTransfer, isWithdrawBalance);
|
||||
return this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate, transactionAmount, paymentDetail,
|
||||
transactionBooleanValues);
|
||||
transactionBooleanValues, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -128,8 +128,9 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) {
|
||||
boolean isAccountTransfer = false;
|
||||
boolean isRegularTransaction = false;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
return this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail,
|
||||
isAccountTransfer, isRegularTransaction);
|
||||
isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -146,8 +147,9 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
|
||||
final boolean isPreMatureClosure = false;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
account.updateDepositAmount(transactionAmount);
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
final boolean isAnyActivationChargesDue = isAnyActivationChargesDue(account);
|
||||
@@ -172,8 +174,9 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||
final boolean isRegularTransaction) {
|
||||
boolean isAccountTransfer = false;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -575,10 +578,11 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
|
||||
final Set<Long> existingReversedTransactionIds, boolean isAccountTransfer) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
|
||||
|
||||
+12
-9
@@ -527,8 +527,9 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
final boolean isInterestTransfer = false;
|
||||
final LocalDate postInterestOnDate = null;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate);
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
|
||||
Money interestPostedToDate = Money.zero(this.currency);
|
||||
|
||||
@@ -562,11 +563,12 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
}
|
||||
}
|
||||
}
|
||||
recalucateDailyBalanceDetails = applyWithholdTaxForDepositAccounts(interestPostingUpToDate, recalucateDailyBalanceDetails);
|
||||
recalucateDailyBalanceDetails = applyWithholdTaxForDepositAccounts(interestPostingUpToDate, recalucateDailyBalanceDetails,
|
||||
backdatedTxnsAllowedTill);
|
||||
if (recalucateDailyBalanceDetails) {
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate);
|
||||
recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
@@ -585,6 +587,7 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
|
||||
// post remaining interest
|
||||
final Money remainigInterestToBePosted = interestOnMaturity.minus(interestPostedToDate);
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
if (!remainigInterestToBePosted.isZero()) {
|
||||
final boolean postInterestAsOn = false;
|
||||
final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
||||
@@ -593,12 +596,12 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
recalucateDailyBalance = true;
|
||||
}
|
||||
|
||||
recalucateDailyBalance = applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance);
|
||||
recalucateDailyBalance = applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance, backdatedTxnsAllowedTill);
|
||||
|
||||
if (recalucateDailyBalance) {
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(Money.zero(this.currency), accountCloseDate);
|
||||
recalculateDailyBalances(Money.zero(this.currency), accountCloseDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
this.accountTermAndPreClosure.updateMaturityDetails(this.getAccountBalance(), accountCloseDate);
|
||||
@@ -639,19 +642,19 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
@Override
|
||||
public void postInterest(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postInterestOnDate) {
|
||||
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
|
||||
super.postInterest(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postAsInterestOn) {
|
||||
final LocalDate postAsInterestOn, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
|
||||
return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postAsInterestOn);
|
||||
financialYearBeginningMonth, postAsInterestOn, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
|
||||
|
||||
+16
-13
@@ -539,14 +539,15 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
|
||||
protected void processAccountUponActivation(final DateTimeFormatter fmt, final AppUser user) {
|
||||
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
if (minRequiredOpeningBalance.isGreaterThanZero()) {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationLocalDate(),
|
||||
minRequiredOpeningBalance.getAmount(), null, new Date(), user, accountType);
|
||||
deposit(transactionDTO);
|
||||
deposit(transactionDTO, backdatedTxnsAllowedTill);
|
||||
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(Money.zero(this.currency), DateUtils.getLocalDateOfTenant());
|
||||
recalculateDailyBalances(Money.zero(this.currency), DateUtils.getLocalDateOfTenant(), backdatedTxnsAllowedTill);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,8 +641,9 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate.minusDays(1), isInterestTransfer,
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate);
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
|
||||
Money interestPostedToDate = Money.zero(this.currency);
|
||||
|
||||
@@ -673,11 +675,11 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
}
|
||||
}
|
||||
}
|
||||
applyWithholdTaxForDepositAccounts(interestPostingUpToDate, recalucateDailyBalanceDetails);
|
||||
applyWithholdTaxForDepositAccounts(interestPostingUpToDate, recalucateDailyBalanceDetails, backdatedTxnsAllowedTill);
|
||||
if (recalucateDailyBalanceDetails) {
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate);
|
||||
recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
}
|
||||
@@ -693,6 +695,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
financialYearBeginningMonth);
|
||||
|
||||
boolean recalucateDailyBalance = false;
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
|
||||
// post remaining interest
|
||||
final Money remainigInterestToBePosted = interestOnMaturity.minus(interestPostedToDate);
|
||||
@@ -704,12 +707,12 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
recalucateDailyBalance = true;
|
||||
}
|
||||
|
||||
applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance);
|
||||
applyWithholdTaxForDepositAccounts(accountCloseDate, recalucateDailyBalance, backdatedTxnsAllowedTill);
|
||||
|
||||
if (recalucateDailyBalance) {
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(Money.zero(this.currency), accountCloseDate);
|
||||
recalculateDailyBalances(Money.zero(this.currency), accountCloseDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
@@ -750,19 +753,19 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
@Override
|
||||
public void postInterest(final MathContext mc, final LocalDate postingDate, final boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postInterestAson) {
|
||||
final LocalDate postInterestAson, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
|
||||
super.postInterest(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestAson);
|
||||
financialYearBeginningMonth, postInterestAson, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postAsInterestOn) {
|
||||
final LocalDate postAsInterestOn, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
|
||||
return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postAsInterestOn);
|
||||
financialYearBeginningMonth, postAsInterestOn, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
|
||||
@@ -834,7 +837,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO) {
|
||||
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
if (isAccountMatured()) {
|
||||
final String defaultUserMessage = "Transaction is not allowed. Account is matured.";
|
||||
@@ -872,7 +875,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
final SavingsAccountTransaction transaction = super.deposit(transactionDTO);
|
||||
final SavingsAccountTransaction transaction = super.deposit(transactionDTO, backdatedTxnsAllowedTill);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
+356
-73
@@ -316,6 +316,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
protected SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
|
||||
@Transient
|
||||
protected SavingsHelper savingsHelper;
|
||||
@Transient
|
||||
protected List<SavingsAccountTransaction> savingsAccountTransactions = new ArrayList<>();
|
||||
|
||||
@Column(name = "deposit_type_enum", insertable = false, updatable = false)
|
||||
private Integer depositType;
|
||||
@@ -445,6 +447,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
this.savingsHelper = savingsHelper;
|
||||
}
|
||||
|
||||
public void setSavingsAccountTransactions(final List<SavingsAccountTransaction> savingsAccountTransactions) {
|
||||
this.savingsAccountTransactions.addAll(savingsAccountTransactions);
|
||||
}
|
||||
|
||||
public List<SavingsAccountTransaction> getSavingsAccountTransactionsWithPivotConfig() {
|
||||
return this.savingsAccountTransactions;
|
||||
}
|
||||
|
||||
public String getExternalId() {
|
||||
return externalId;
|
||||
}
|
||||
@@ -487,15 +497,25 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
|
||||
public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postInterestOnDate) {
|
||||
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill) {
|
||||
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate);
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
|
||||
Money interestPostedToDate = Money.zero(this.currency);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
interestPostedToDate = Money.of(this.currency, this.summary.getTotalInterestPosted());
|
||||
}
|
||||
|
||||
boolean recalucateDailyBalanceDetails = false;
|
||||
boolean applyWithHoldTax = isWithHoldTaxApplicableForInterestPosting();
|
||||
final List<SavingsAccountTransaction> withholdTransactions = new ArrayList<>();
|
||||
withholdTransactions.addAll(findWithHoldTransactions());
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
withholdTransactions.addAll(findWithHoldSavingsTransactionsWithPivotConfig());
|
||||
} else {
|
||||
withholdTransactions.addAll(findWithHoldTransactions());
|
||||
}
|
||||
|
||||
for (final PostingPeriod interestPostingPeriod : postingPeriods) {
|
||||
|
||||
@@ -516,9 +536,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(), interestPostingTransactionDate,
|
||||
interestEarnedToBePostedForPeriod.negated(), interestPostingPeriod.isUserPosting());
|
||||
}
|
||||
addTransaction(newPostingTransaction);
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(newPostingTransaction);
|
||||
} else {
|
||||
addTransaction(newPostingTransaction);
|
||||
}
|
||||
if (applyWithHoldTax) {
|
||||
createWithHoldTransaction(interestEarnedToBePostedForPeriod.getAmount(), interestPostingTransactionDate);
|
||||
createWithHoldTransaction(interestEarnedToBePostedForPeriod.getAmount(), interestPostingTransactionDate,
|
||||
backdatedTxnsAllowedTill);
|
||||
}
|
||||
recalucateDailyBalanceDetails = true;
|
||||
} else {
|
||||
@@ -547,9 +572,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated(),
|
||||
interestPostingPeriod.isUserPosting());
|
||||
}
|
||||
addTransaction(newPostingTransaction);
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(newPostingTransaction);
|
||||
} else {
|
||||
addTransaction(newPostingTransaction);
|
||||
}
|
||||
if (applyWithHoldTaxForOldTransaction) {
|
||||
createWithHoldTransaction(interestEarnedToBePostedForPeriod.getAmount(), interestPostingTransactionDate);
|
||||
createWithHoldTransaction(interestEarnedToBePostedForPeriod.getAmount(), interestPostingTransactionDate,
|
||||
backdatedTxnsAllowedTill);
|
||||
}
|
||||
recalucateDailyBalanceDetails = true;
|
||||
}
|
||||
@@ -561,14 +591,27 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
// no openingBalance concept supported yet but probably will to
|
||||
// allow
|
||||
// for migrations.
|
||||
final Money openingAccountBalance = Money.zero(this.currency);
|
||||
Money openingAccountBalance = Money.zero(this.currency);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
if (this.summary.getLastInterestCalculationDate() == null) {
|
||||
openingAccountBalance = Money.zero(this.currency);
|
||||
} else {
|
||||
openingAccountBalance = Money.of(this.currency, this.summary.getRunningBalanceOnPivotDate());
|
||||
}
|
||||
}
|
||||
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(openingAccountBalance, interestPostingUpToDate);
|
||||
recalculateDailyBalances(openingAccountBalance, interestPostingUpToDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
} else {
|
||||
this.summary.updateSummaryWithPivotConfig(this.currency, this.savingsAccountTransactionSummaryWrapper, null,
|
||||
this.savingsAccountTransactions);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> findWithHoldTransactions() {
|
||||
@@ -582,6 +625,17 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return withholdTransactions;
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> findWithHoldSavingsTransactionsWithPivotConfig() {
|
||||
final List<SavingsAccountTransaction> withholdTransactions = new ArrayList<>();
|
||||
List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig();
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
if (transaction.isWithHoldTaxAndNotReversed()) {
|
||||
withholdTransactions.add(transaction);
|
||||
}
|
||||
}
|
||||
return withholdTransactions;
|
||||
}
|
||||
|
||||
private boolean isWithHoldTaxApplicableForInterestPosting() {
|
||||
return this.withHoldTax() && this.depositAccountType().isSavingsDeposit();
|
||||
}
|
||||
@@ -599,6 +653,19 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return postingTransation;
|
||||
}
|
||||
|
||||
protected SavingsAccountTransaction findInterestPostingSavingsTransactionWithPivotConfig(final LocalDate postingDate) {
|
||||
SavingsAccountTransaction postingTransation = null;
|
||||
List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig();
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||
&& transaction.occursOn(postingDate)) {
|
||||
postingTransation = transaction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return postingTransation;
|
||||
}
|
||||
|
||||
protected SavingsAccountTransaction findTransactionFor(final LocalDate postingDate,
|
||||
final List<SavingsAccountTransaction> transactions) {
|
||||
SavingsAccountTransaction transaction = null;
|
||||
@@ -611,7 +678,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
protected boolean createWithHoldTransaction(final BigDecimal amount, final LocalDate date) {
|
||||
protected boolean createWithHoldTransaction(final BigDecimal amount, final LocalDate date, final boolean backdatedTxnsAllowedTill) {
|
||||
boolean isTaxAdded = false;
|
||||
if (this.taxGroup != null && amount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
Map<TaxComponent, BigDecimal> taxSplit = TaxUtils.splitTax(amount, date, this.taxGroup.getTaxGroupMappings(), amount.scale());
|
||||
@@ -619,7 +686,11 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (totalTax.compareTo(BigDecimal.ZERO) > 0) {
|
||||
SavingsAccountTransaction withholdTransaction = SavingsAccountTransaction.withHoldTax(this, office(), date,
|
||||
Money.of(currency, totalTax), taxSplit);
|
||||
addTransaction(withholdTransaction);
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(withholdTransaction);
|
||||
} else {
|
||||
addTransaction(withholdTransaction);
|
||||
}
|
||||
isTaxAdded = true;
|
||||
}
|
||||
}
|
||||
@@ -665,6 +736,18 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return savingsTransaction;
|
||||
}
|
||||
|
||||
protected SavingsAccountTransaction findLastFilteredTransactionWithPivotConfig(final LocalDate date) {
|
||||
SavingsAccountTransaction savingsTransaction = null;
|
||||
List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig();
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
if (transaction.isNotReversed() && transaction.occursOn(date)) {
|
||||
savingsTransaction = transaction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return savingsTransaction;
|
||||
}
|
||||
|
||||
public List<LocalDate> getManualPostingDates() {
|
||||
List<LocalDate> transactions = new ArrayList<>();
|
||||
for (SavingsAccountTransaction trans : this.transactions) {
|
||||
@@ -675,6 +758,16 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
public List<LocalDate> getManualPostingDatesWithPivotConfig() {
|
||||
List<LocalDate> transactions = new ArrayList<>();
|
||||
for (SavingsAccountTransaction trans : this.savingsAccountTransactions) {
|
||||
if (trans.isInterestPosting() && trans.isNotReversed() && trans.isManualTransaction()) {
|
||||
transactions.add(trans.getTransactionLocalDate());
|
||||
}
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* All interest calculation based on END-OF-DAY-BALANCE.
|
||||
*
|
||||
@@ -692,15 +785,22 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
|
||||
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate,
|
||||
boolean isInterestTransfer, final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postInterestOnDate) {
|
||||
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
// no openingBalance concept supported yet but probably will to allow
|
||||
// for migrations.
|
||||
final Money openingAccountBalance = Money.zero(this.currency);
|
||||
Money openingAccountBalance = null;
|
||||
|
||||
// Check global configurations and 'pivot' date is null
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
openingAccountBalance = Money.of(this.currency, this.summary.getRunningBalanceOnPivotDate());
|
||||
} else {
|
||||
openingAccountBalance = Money.zero(this.currency);
|
||||
}
|
||||
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(openingAccountBalance, upToInterestCalculationDate);
|
||||
recalculateDailyBalances(openingAccountBalance, upToInterestCalculationDate, backdatedTxnsAllowedTill);
|
||||
|
||||
// 1. default to calculate interest based on entire history OR
|
||||
// 2. determine latest 'posting period' and find interest credited to
|
||||
@@ -779,7 +879,13 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
isTransferInterestToOtherAccount());
|
||||
|
||||
this.summary.updateFromInterestPeriodSummaries(this.currency, allPostingPeriods);
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
this.summary.updateSummaryWithPivotConfig(this.currency, this.savingsAccountTransactionSummaryWrapper, null,
|
||||
this.savingsAccountTransactions);
|
||||
} else {
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
}
|
||||
|
||||
return allPostingPeriods;
|
||||
}
|
||||
@@ -808,6 +914,29 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return orderedNonInterestPostingTransactions;
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> retreiveOrderedNonInterestPostingSavingsTransactionsWithPivotConfig() {
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = retrieveSortedTransactions();
|
||||
|
||||
final List<SavingsAccountTransaction> orderedNonInterestPostingTransactions = new ArrayList<>();
|
||||
|
||||
for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) {
|
||||
if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||
&& transaction.isNotReversed()) {
|
||||
orderedNonInterestPostingTransactions.add(transaction);
|
||||
}
|
||||
}
|
||||
orderedNonInterestPostingTransactions.sort(new SavingsAccountTransactionComparator());
|
||||
return orderedNonInterestPostingTransactions;
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> retrieveSortedTransactions() {
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = new ArrayList<>();
|
||||
listOfTransactionsSorted.addAll(this.savingsAccountTransactions);
|
||||
final SavingsAccountTransactionComparator transactionComparator = new SavingsAccountTransactionComparator();
|
||||
Collections.sort(listOfTransactionsSorted, transactionComparator);
|
||||
return listOfTransactionsSorted;
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> retreiveListOfTransactions() {
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = new ArrayList<>();
|
||||
listOfTransactionsSorted.addAll(this.transactions);
|
||||
@@ -817,11 +946,19 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return listOfTransactionsSorted;
|
||||
}
|
||||
|
||||
protected void recalculateDailyBalances(final Money openingAccountBalance, final LocalDate interestPostingUpToDate) {
|
||||
protected void recalculateDailyBalances(final Money openingAccountBalance, final LocalDate interestPostingUpToDate,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
Money runningBalance = openingAccountBalance.copy();
|
||||
|
||||
List<SavingsAccountTransaction> accountTransactionsSorted = retreiveListOfTransactions();
|
||||
List<SavingsAccountTransaction> accountTransactionsSorted = null;
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
accountTransactionsSorted = retrieveSortedTransactions();
|
||||
} else {
|
||||
accountTransactionsSorted = retreiveListOfTransactions();
|
||||
}
|
||||
|
||||
boolean isTransactionsModified = false;
|
||||
for (final SavingsAccountTransaction transaction : accountTransactionsSorted) {
|
||||
if (transaction.isReversed()) {
|
||||
@@ -867,7 +1004,11 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
accountTransaction.updateOverdraftAmount(overdraftAmount.getAmount());
|
||||
}
|
||||
accountTransaction.updateRunningBalance(runningBalance);
|
||||
addTransaction(accountTransaction);
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(accountTransaction);
|
||||
} else {
|
||||
addTransaction(accountTransaction);
|
||||
}
|
||||
isTransactionsModified = true;
|
||||
}
|
||||
|
||||
@@ -875,7 +1016,11 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
if (isTransactionsModified) {
|
||||
accountTransactionsSorted = retreiveListOfTransactions();
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
accountTransactionsSorted = retrieveSortedTransactions();
|
||||
} else {
|
||||
accountTransactionsSorted = retreiveListOfTransactions();
|
||||
}
|
||||
}
|
||||
resetAccountTransactionsEndOfDayBalances(accountTransactionsSorted, interestPostingUpToDate);
|
||||
}
|
||||
@@ -896,16 +1041,17 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO) {
|
||||
return deposit(transactionDTO, SavingsAccountTransactionType.DEPOSIT);
|
||||
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO, final boolean backdatedTxnsAllowedTill) {
|
||||
return deposit(transactionDTO, SavingsAccountTransactionType.DEPOSIT, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction dividendPayout(final SavingsAccountTransactionDTO transactionDTO) {
|
||||
return deposit(transactionDTO, SavingsAccountTransactionType.DIVIDEND_PAYOUT);
|
||||
public SavingsAccountTransaction dividendPayout(final SavingsAccountTransactionDTO transactionDTO,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
return deposit(transactionDTO, SavingsAccountTransactionType.DIVIDEND_PAYOUT, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO transactionDTO,
|
||||
final SavingsAccountTransactionType savingsAccountTransactionType) {
|
||||
final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill) {
|
||||
final String resourceTypeName = depositAccountType().resourceName();
|
||||
if (isNotActive()) {
|
||||
final String defaultUserMessage = "Transaction is not allowed. Account is not active.";
|
||||
@@ -950,8 +1096,12 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, office(), transactionDTO.getPaymentDetail(),
|
||||
transactionDTO.getTransactionDate(), amount, transactionDTO.getCreatedDate(), transactionDTO.getAppUser(),
|
||||
savingsAccountTransactionType);
|
||||
addTransaction(transaction);
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(transaction);
|
||||
} else {
|
||||
addTransaction(transaction);
|
||||
}
|
||||
|
||||
if (this.sub_status.equals(SavingsAccountSubStatusEnum.INACTIVE.getValue())
|
||||
|| this.sub_status.equals(SavingsAccountSubStatusEnum.DORMANT.getValue())) {
|
||||
@@ -986,7 +1136,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return startInterestCalculationLocalDate;
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction withdraw(final SavingsAccountTransactionDTO transactionDTO, final boolean applyWithdrawFee) {
|
||||
public SavingsAccountTransaction withdraw(final SavingsAccountTransactionDTO transactionDTO, final boolean applyWithdrawFee,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
if (!isTransactionsAllowed()) {
|
||||
|
||||
@@ -1042,14 +1193,19 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (applyWithdrawFee) {
|
||||
// auto pay withdrawal fee
|
||||
payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate(), transactionDTO.getAppUser(),
|
||||
transactionDTO.getPaymentDetail());
|
||||
transactionDTO.getPaymentDetail(), backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
final Money transactionAmountMoney = Money.of(this.currency, transactionDTO.getTransactionAmount());
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, office(),
|
||||
transactionDTO.getPaymentDetail(), transactionDTO.getTransactionDate(), transactionAmountMoney,
|
||||
transactionDTO.getCreatedDate(), transactionDTO.getAppUser());
|
||||
addTransaction(transaction);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(transaction);
|
||||
} else {
|
||||
addTransaction(transaction);
|
||||
}
|
||||
|
||||
if (this.sub_status.equals(SavingsAccountSubStatusEnum.INACTIVE.getValue())
|
||||
|| this.sub_status.equals(SavingsAccountSubStatusEnum.DORMANT.getValue())) {
|
||||
@@ -1071,8 +1227,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
private void payWithdrawalFee(final BigDecimal transactionAmount, final LocalDate transactionDate, final AppUser user,
|
||||
final PaymentDetail paymentDetail) {
|
||||
|
||||
final PaymentDetail paymentDetail, final boolean backdatedTxnsAllowedTill) {
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
|
||||
if (charge.isWithdrawalFee() && charge.isActive()) {
|
||||
@@ -1089,7 +1244,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
} else if (charge.isEnablePaymentType()) { // normal charge-transaction to specific paymentType
|
||||
if (paymentDetail.getPaymentType().getPaymentName().equals(charge.getCharge().getPaymentType().getPaymentName())) {
|
||||
charge.updateWithdralFeeAmount(transactionAmount);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user,
|
||||
backdatedTxnsAllowedTill);
|
||||
}
|
||||
} else if (!charge.isEnablePaymentType() && charge.isEnableFreeWithdrawal()) { // discount transaction
|
||||
// irrespective of
|
||||
@@ -1098,8 +1254,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
|
||||
} else { // normal-withdraw
|
||||
charge.updateWithdralFeeAmount(transactionAmount);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user,
|
||||
backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1160,13 +1318,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
|
||||
private void countValidation(SavingsAccountCharge charge, final BigDecimal transactionAmount, final LocalDate transactionDate,
|
||||
final AppUser user) {
|
||||
boolean backdatedTxnsAllowedTill = false;
|
||||
if (charge.getFreeWithdrawalCount() < charge.getFrequencyFreeWithdrawalCharge()) {
|
||||
final Integer count = charge.getFreeWithdrawalCount() + 1;
|
||||
charge.setFreeWithdrawalCount(count);
|
||||
charge.updateNoWithdrawalFee();
|
||||
} else {
|
||||
charge.updateWithdralFeeAmount(transactionAmount);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user, backdatedTxnsAllowedTill);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1176,25 +1335,47 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
charge.updateNoWithdrawalFee();
|
||||
}
|
||||
|
||||
public boolean isBeforeLastPostingPeriod(final LocalDate transactionDate) {
|
||||
public boolean isBeforeLastPostingPeriod(final LocalDate transactionDate, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
boolean transactionBeforeLastInterestPosting = false;
|
||||
|
||||
for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||
&& transaction.isAfter(transactionDate)) {
|
||||
transactionBeforeLastInterestPosting = true;
|
||||
break;
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||
&& transaction.isAfter(transactionDate)) {
|
||||
transactionBeforeLastInterestPosting = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.summary.getInterestPostedTillDate() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
transactionBeforeLastInterestPosting = LocalDate
|
||||
.ofInstant(this.summary.getInterestPostedTillDate().toInstant(), DateUtils.getDateTimeZoneOfTenant())
|
||||
.isAfter(transactionDate) ? true : false;
|
||||
}
|
||||
|
||||
return transactionBeforeLastInterestPosting;
|
||||
}
|
||||
|
||||
public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount, final boolean isException,
|
||||
final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions) {
|
||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||
final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
List<SavingsAccountTransaction> transactionsSortedByDate = null;
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
transactionsSortedByDate = retrieveSortedTransactions();
|
||||
} else {
|
||||
transactionsSortedByDate = retreiveListOfTransactions();
|
||||
}
|
||||
|
||||
Money runningBalance = Money.zero(this.currency);
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
runningBalance = Money.of(this.currency, this.summary.getRunningBalanceOnPivotDate());
|
||||
}
|
||||
|
||||
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||
LocalDate lastSavingsDate = null;
|
||||
final BigDecimal withdrawalFee = null;
|
||||
@@ -1255,10 +1436,20 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public void validateAccountBalanceDoesNotBecomeNegative(final String transactionAction,
|
||||
final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions) {
|
||||
final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||
List<SavingsAccountTransaction> transactionsSortedByDate = null;
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
transactionsSortedByDate = retrieveSortedTransactions();
|
||||
} else {
|
||||
transactionsSortedByDate = retreiveListOfTransactions();
|
||||
}
|
||||
Money runningBalance = Money.zero(this.currency);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
runningBalance = Money.of(this.currency, this.summary.getRunningBalanceOnPivotDate());
|
||||
}
|
||||
|
||||
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||
LocalDate lastSavingsDate = null;
|
||||
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
||||
@@ -1586,7 +1777,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final Set<Long> existingTransactionIds,
|
||||
final Set<Long> existingReversedTransactionIds, boolean isAccountTransfer) {
|
||||
final Set<Long> existingReversedTransactionIds, boolean isAccountTransfer, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final Map<String, Object> accountingBridgeData = new LinkedHashMap<>();
|
||||
accountingBridgeData.put("savingsId", getId());
|
||||
@@ -1598,7 +1789,16 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
accountingBridgeData.put("isAccountTransfer", isAccountTransfer);
|
||||
|
||||
final List<Map<String, Object>> newSavingsTransactions = new ArrayList<>();
|
||||
List<SavingsAccountTransaction> trans = getTransactions();
|
||||
|
||||
List<SavingsAccountTransaction> trans = null;
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
trans = getSavingsAccountTransactionsWithPivotConfig();
|
||||
} else {
|
||||
trans = getTransactions();
|
||||
}
|
||||
|
||||
// Adding new transactions to the array
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
if (transaction.isReversed() && !existingReversedTransactionIds.contains(transaction.getId())) {
|
||||
newSavingsTransactions.add(transaction.toMapData(currencyData));
|
||||
@@ -1612,13 +1812,21 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public Collection<Long> findExistingTransactionIds() {
|
||||
|
||||
final Collection<Long> ids = new ArrayList<>();
|
||||
List<SavingsAccountTransaction> trans = getTransactions();
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
ids.add(transaction.getId());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
public Collection<Long> findCurrentTransactionIdsWithPivotDateConfig() {
|
||||
|
||||
final Collection<Long> ids = new ArrayList<>();
|
||||
List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig();
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
ids.add(transaction.getId());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
@@ -1626,6 +1834,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
|
||||
final Collection<Long> ids = new ArrayList<>();
|
||||
List<SavingsAccountTransaction> trans = getTransactions();
|
||||
// time consuming
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
if (transaction.isReversed()) {
|
||||
ids.add(transaction.getId());
|
||||
@@ -1635,6 +1844,18 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public Collection<Long> findCurrentReversedTransactionIdsWithPivotDateConfig() {
|
||||
final Collection<Long> ids = new ArrayList<>();
|
||||
List<SavingsAccountTransaction> trans = getSavingsAccountTransactionsWithPivotConfig();
|
||||
// time consuming
|
||||
for (final SavingsAccountTransaction transaction : trans) {
|
||||
if (transaction.isReversed()) {
|
||||
ids.add(transaction.getId());
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
public void update(final Client client) {
|
||||
this.client = client;
|
||||
}
|
||||
@@ -2090,6 +2311,36 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
}
|
||||
|
||||
public void undoSavingsTransaction(final Long transactionId) {
|
||||
|
||||
SavingsAccountTransaction transactionToUndo = null;
|
||||
for (final SavingsAccountTransaction transaction : this.savingsAccountTransactions) {
|
||||
if (transaction.isIdentifiedBy(transactionId)) {
|
||||
transactionToUndo = transaction;
|
||||
}
|
||||
}
|
||||
|
||||
if (transactionToUndo == null) {
|
||||
throw new SavingsAccountTransactionNotFoundException(this.getId(), transactionId);
|
||||
}
|
||||
|
||||
validateAttemptToUndoTransferRelatedTransactions(transactionToUndo);
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_UNDO_TRANSACTION, transactionToUndo.transactionLocalDate());
|
||||
transactionToUndo.reverse();
|
||||
if (transactionToUndo.isChargeTransaction() || transactionToUndo.isWaiveCharge()) {
|
||||
// undo charge
|
||||
final Set<SavingsAccountChargePaidBy> chargesPaidBy = transactionToUndo.getSavingsAccountChargesPaid();
|
||||
for (final SavingsAccountChargePaidBy savingsAccountChargePaidBy : chargesPaidBy) {
|
||||
final SavingsAccountCharge chargeToUndo = savingsAccountChargePaidBy.getSavingsAccountCharge();
|
||||
if (transactionToUndo.isChargeTransaction()) {
|
||||
chargeToUndo.undoPayment(this.getCurrency(), transactionToUndo.getAmount(this.getCurrency()));
|
||||
} else if (transactionToUndo.isWaiveCharge()) {
|
||||
chargeToUndo.undoWaiver(this.getCurrency(), transactionToUndo.getAmount(this.getCurrency()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Date findLatestAnnualFeeTransactionDueDate() {
|
||||
|
||||
Date nextDueDate = null;
|
||||
@@ -2341,8 +2592,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
charge.updateToNextDueDateFrom(getActivationLocalDate());
|
||||
}
|
||||
|
||||
// auto pay the activation time charges
|
||||
this.payActivationCharges(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, user);
|
||||
// auto pay the activation time charges (No need of checking the pivot date config)
|
||||
this.payActivationCharges(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, user, false);
|
||||
// TODO : AA add activation charges to actual changes list
|
||||
}
|
||||
|
||||
@@ -2366,12 +2617,13 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
private void payActivationCharges(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final AppUser user) {
|
||||
final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
boolean isSavingsChargeApplied = false;
|
||||
for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
|
||||
if (savingsAccountCharge.isSavingsActivation()) {
|
||||
isSavingsChargeApplied = true;
|
||||
payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate(), user);
|
||||
payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate(), user,
|
||||
backdatedTxnsAllowedTill);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2379,14 +2631,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestAsOnDate = null;
|
||||
if (this.isBeforeLastPostingPeriod(getActivationLocalDate())) {
|
||||
if (this.isBeforeLastPostingPeriod(getActivationLocalDate(), backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
this.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestAsOnDate);
|
||||
postInterestAsOnDate, backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
this.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestAsOnDate);
|
||||
financialYearBeginningMonth, postInterestAsOnDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2535,6 +2787,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
this.transactions.add(transaction);
|
||||
}
|
||||
|
||||
public void addTransactionToExisting(final SavingsAccountTransaction transaction) {
|
||||
this.savingsAccountTransactions.add(transaction);
|
||||
}
|
||||
|
||||
public void setStatus(final Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
@@ -2588,7 +2844,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
this.charges.remove(charge);
|
||||
}
|
||||
|
||||
public void waiveCharge(final Long savingsAccountChargeId, final AppUser user) {
|
||||
public void waiveCharge(final Long savingsAccountChargeId, final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
@@ -2639,7 +2895,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
|
||||
// waive charge
|
||||
final Money amountWaived = savingsAccountCharge.waive(getCurrency());
|
||||
handleWaiverChargeTransactions(savingsAccountCharge, amountWaived, user);
|
||||
handleWaiverChargeTransactions(savingsAccountCharge, amountWaived, user, backdatedTxnsAllowedTill);
|
||||
|
||||
}
|
||||
|
||||
@@ -2722,7 +2978,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction payCharge(final SavingsAccountCharge savingsAccountCharge, final BigDecimal amountPaid,
|
||||
final LocalDate transactionDate, final DateTimeFormatter formatter, final AppUser user) {
|
||||
final LocalDate transactionDate, final DateTimeFormatter formatter, final AppUser user,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
@@ -2810,17 +3067,17 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
}
|
||||
|
||||
return this.payCharge(savingsAccountCharge, chargePaid, transactionDate, user);
|
||||
return this.payCharge(savingsAccountCharge, chargePaid, transactionDate, user, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction payCharge(final SavingsAccountCharge savingsAccountCharge, final Money amountPaid,
|
||||
final LocalDate transactionDate, final AppUser user) {
|
||||
final LocalDate transactionDate, final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
savingsAccountCharge.pay(getCurrency(), amountPaid);
|
||||
return handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate, user);
|
||||
return handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate, user, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction handlePayChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount,
|
||||
final LocalDate transactionDate, final AppUser user) {
|
||||
final LocalDate transactionDate, final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
SavingsAccountTransaction chargeTransaction = null;
|
||||
|
||||
if (savingsAccountCharge.isWithdrawalFee()) {
|
||||
@@ -2831,23 +3088,31 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, transactionAmount, user);
|
||||
}
|
||||
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction);
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction, backdatedTxnsAllowedTill);
|
||||
return chargeTransaction;
|
||||
}
|
||||
|
||||
private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount, AppUser user) {
|
||||
private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount, AppUser user,
|
||||
boolean backdatedTxnsAllowedTill) {
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(),
|
||||
DateUtils.getLocalDateOfTenant(), transactionAmount, user);
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction);
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
private void handleChargeTransactions(final SavingsAccountCharge savingsAccountCharge, final SavingsAccountTransaction transaction) {
|
||||
private void handleChargeTransactions(final SavingsAccountCharge savingsAccountCharge, final SavingsAccountTransaction transaction,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
// Provide a link between transaction and savings charge for which
|
||||
// amount is waived.
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(transaction, savingsAccountCharge,
|
||||
transaction.getAmount(this.getCurrency()).getAmount());
|
||||
transaction.getSavingsAccountChargesPaid().add(chargePaidBy);
|
||||
this.transactions.add(transaction);
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
this.savingsAccountTransactions.add(transaction);
|
||||
this.summary.updateSummaryWithPivotConfig(this.currency, this.savingsAccountTransactionSummaryWrapper, transaction,
|
||||
this.savingsAccountTransactions);
|
||||
} else {
|
||||
this.transactions.add(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
private SavingsAccountCharge getCharge(final Long savingsAccountChargeId) {
|
||||
@@ -3069,13 +3334,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
this.withHoldTax = withHoldTax;
|
||||
}
|
||||
|
||||
protected boolean applyWithholdTaxForDepositAccounts(final LocalDate interestPostingUpToDate, boolean recalucateDailyBalance) {
|
||||
protected boolean applyWithholdTaxForDepositAccounts(final LocalDate interestPostingUpToDate, boolean recalucateDailyBalance,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
final List<SavingsAccountTransaction> withholdTransactions = findWithHoldTransactions();
|
||||
SavingsAccountTransaction withholdTransaction = findTransactionFor(interestPostingUpToDate, withholdTransactions);
|
||||
final BigDecimal totalInterestPosted = this.savingsAccountTransactionSummaryWrapper.calculateTotalInterestPosted(this.currency,
|
||||
this.transactions);
|
||||
if (withholdTransaction == null && this.withHoldTax()) {
|
||||
boolean isWithholdTaxAdded = createWithHoldTransaction(totalInterestPosted, interestPostingUpToDate);
|
||||
boolean isWithholdTaxAdded = createWithHoldTransaction(totalInterestPosted, interestPostingUpToDate, backdatedTxnsAllowedTill);
|
||||
recalucateDailyBalance = recalucateDailyBalance || isWithholdTaxAdded;
|
||||
} else {
|
||||
boolean isWithholdTaxAdded = updateWithHoldTransaction(totalInterestPosted, withholdTransaction);
|
||||
@@ -3085,16 +3351,16 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return recalucateDailyBalance;
|
||||
}
|
||||
|
||||
public void setSubStatusInactive(AppUser appUser) {
|
||||
public void setSubStatusInactive(AppUser appUser, final boolean backdatedTxnsAllowedTill) {
|
||||
this.sub_status = SavingsAccountSubStatusEnum.INACTIVE.getValue();
|
||||
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
if (charge.isSavingsNoActivity() && charge.isActive()) {
|
||||
charge.updateWithdralFeeAmount(this.getAccountBalance());
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, appUser);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, appUser, backdatedTxnsAllowedTill);
|
||||
}
|
||||
}
|
||||
recalculateDailyBalances(Money.zero(this.currency), transactionDate);
|
||||
recalculateDailyBalances(Money.zero(this.currency), transactionDate, backdatedTxnsAllowedTill);
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
}
|
||||
|
||||
@@ -3113,10 +3379,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
SavingsAccountTransaction transaction = SavingsAccountTransaction.escheat(this, transactionDate, appUser, postInterestAsOnDate);
|
||||
this.transactions.add(transaction);
|
||||
}
|
||||
recalculateDailyBalances(Money.zero(this.currency), transactionDate);
|
||||
recalculateDailyBalances(Money.zero(this.currency), transactionDate, false);
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
}
|
||||
|
||||
public void loadTransactions() {
|
||||
transactions.size();
|
||||
}
|
||||
|
||||
public void loadLazyCollections() {
|
||||
transactions.size();
|
||||
charges.size();
|
||||
@@ -3355,6 +3625,19 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return lastransactionDate;
|
||||
}
|
||||
|
||||
public LocalDate retrieveLastTransactionDateWithPivotConfig() {
|
||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retrieveSortedTransactions();
|
||||
SavingsAccountTransaction lastTransaction = null;
|
||||
if (transactionsSortedByDate.size() > 0) {
|
||||
lastTransaction = transactionsSortedByDate.get(transactionsSortedByDate.size() - 1);
|
||||
}
|
||||
LocalDate lastransactionDate = null;
|
||||
if (lastTransaction != null) {
|
||||
lastransactionDate = lastTransaction.transactionLocalDate();
|
||||
}
|
||||
return lastransactionDate;
|
||||
}
|
||||
|
||||
public BigDecimal getSavingsHoldAmount() {
|
||||
return this.savingsOnHoldAmount == null ? BigDecimal.ZERO : this.savingsOnHoldAmount;
|
||||
}
|
||||
|
||||
+59
-3
@@ -47,11 +47,15 @@ import com.google.gson.JsonElement;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.organisation.staff.domain.Staff;
|
||||
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||
@@ -74,6 +78,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -89,6 +94,8 @@ public class SavingsAccountAssembler {
|
||||
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
|
||||
private final SavingsAccountChargeAssembler savingsAccountChargeAssembler;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountAssembler(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper,
|
||||
@@ -96,7 +103,8 @@ public class SavingsAccountAssembler {
|
||||
final StaffRepositoryWrapper staffRepository, final SavingsProductRepository savingProductRepository,
|
||||
final SavingsAccountRepositoryWrapper savingsAccountRepository,
|
||||
final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper,
|
||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
|
||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService, final RoutingDataSource dataSource,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
|
||||
this.clientRepository = clientRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
@@ -106,6 +114,8 @@ public class SavingsAccountAssembler {
|
||||
this.savingsAccountChargeAssembler = savingsAccountChargeAssembler;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
savingsHelper = new SavingsHelper(accountTransfersReadPlatformService);
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,12 +317,58 @@ public class SavingsAccountAssembler {
|
||||
return account;
|
||||
}
|
||||
|
||||
public SavingsAccount assembleFrom(final Long savingsId) {
|
||||
final SavingsAccount account = this.savingsAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
public SavingsAccount assembleFrom(final Long savingsId, final boolean backdatedTxnsAllowedTill) {
|
||||
SavingsAccount account = this.savingsAccountRepository.findSavingsWithNotFoundDetection(savingsId, backdatedTxnsAllowedTill);
|
||||
return loadTransactionsToSavingsAccount(account, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
public SavingsAccount loadTransactionsToSavingsAccount(final SavingsAccount account, final boolean backdatedTxnsAllowedTill) {
|
||||
List<SavingsAccountTransaction> savingsAccountTransactions = null;
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
Date pivotDate = account.getSummary().getInterestPostedTillDate();
|
||||
boolean isNotPresent = pivotDate == null ? true : false;
|
||||
if (!isNotPresent) {
|
||||
// Get savings account transactions
|
||||
if (isRelaxingDaysConfigForPivotDateEnabled()) {
|
||||
final Long relaxingDaysForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate();
|
||||
LocalDate interestPostedTillDate = LocalDate.ofInstant(account.getSummary().getInterestPostedTillDate().toInstant(),
|
||||
DateUtils.getDateTimeZoneOfTenant());
|
||||
savingsAccountTransactions = this.savingsAccountRepository.findTransactionsAfterPivotDate(account,
|
||||
Date.from(interestPostedTillDate.minusDays(relaxingDaysForPivotDate)
|
||||
.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()));
|
||||
} else {
|
||||
savingsAccountTransactions = this.savingsAccountRepository.findTransactionsAfterPivotDate(account,
|
||||
account.getSummary().getInterestPostedTillDate());
|
||||
}
|
||||
|
||||
if (savingsAccountTransactions != null && savingsAccountTransactions.size() > 0) {
|
||||
// Update transient variable
|
||||
account.setSavingsAccountTransactions(savingsAccountTransactions);
|
||||
}
|
||||
} else {
|
||||
savingsAccountTransactions = this.savingsAccountRepository.findAllTransactions(account);
|
||||
account.setSavingsAccountTransactions(savingsAccountTransactions);
|
||||
}
|
||||
}
|
||||
|
||||
// Update last running balance on account level
|
||||
if (savingsAccountTransactions != null) {
|
||||
account.getSummary().setRunningBalanceOnPivotDate(savingsAccountTransactions.get(savingsAccountTransactions.size() - 1)
|
||||
.getRunningBalance(account.getCurrency()).getAmount());
|
||||
}
|
||||
|
||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
|
||||
return account;
|
||||
}
|
||||
|
||||
public boolean getPivotConfigStatus() {
|
||||
return this.configurationDomainService.retrievePivotDateConfig();
|
||||
}
|
||||
|
||||
public boolean isRelaxingDaysConfigForPivotDateEnabled() {
|
||||
return this.configurationDomainService.isRelaxingDaysConfigForPivotDateEnabled();
|
||||
}
|
||||
|
||||
public void setHelpers(final SavingsAccount account) {
|
||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
|
||||
}
|
||||
|
||||
+8
-5
@@ -28,13 +28,16 @@ import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
|
||||
public interface SavingsAccountDomainService {
|
||||
|
||||
SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate,
|
||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, SavingsTransactionBooleanValues transactionBooleanValues);
|
||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, SavingsTransactionBooleanValues transactionBooleanValues,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate,
|
||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction);
|
||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
void postJournalEntries(SavingsAccount savingsAccount, Set<Long> existingTransactionIds, Set<Long> existingReversedTransactionIds);
|
||||
|
||||
SavingsAccountTransaction handleDividendPayout(SavingsAccount account, LocalDate transactionDate, BigDecimal transactionAmount);
|
||||
void postJournalEntries(SavingsAccount savingsAccount, Set<Long> existingTransactionIds, Set<Long> existingReversedTransactionIds,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleDividendPayout(SavingsAccount account, LocalDate transactionDate, BigDecimal transactionAmount,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
+67
-28
@@ -82,7 +82,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
@Override
|
||||
public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt,
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||
final SavingsTransactionBooleanValues transactionBooleanValues) {
|
||||
final SavingsTransactionBooleanValues transactionBooleanValues, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
AppUser user = getAppUserIfPresent();
|
||||
account.validateForAccountBlock();
|
||||
@@ -96,32 +96,46 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final LocalDate postInterestOnDate = null;
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
updateTransactionDetailsWithPivotConfig(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
Integer accountType = null;
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, new Date(), user, accountType);
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee());
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee(),
|
||||
backdatedTxnsAllowedTill);
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer(), isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer(),
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate);
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
depositAccountOnHoldTransactions = this.depositAccountOnHoldTransactionRepository
|
||||
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount, transactionBooleanValues.isExceptionForBalanceCheck(),
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, backdatedTxnsAllowedTill);
|
||||
|
||||
saveTransactionToGenerateTransactionId(withdrawal);
|
||||
|
||||
this.savingsAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, transactionBooleanValues.isAccountTransfer());
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, transactionBooleanValues.isAccountTransfer(),
|
||||
backdatedTxnsAllowedTill);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.SAVINGS_WITHDRAWAL,
|
||||
constructEntityMap(BusinessEntity.SAVINGS_TRANSACTION, withdrawal));
|
||||
return withdrawal;
|
||||
@@ -139,19 +153,21 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
@Override
|
||||
public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||
final boolean isAccountTransfer, final boolean isRegularTransaction) {
|
||||
final boolean isAccountTransfer, final boolean isRegularTransaction, final boolean backdatedTxnsAllowedTill) {
|
||||
final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.DEPOSIT;
|
||||
return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction,
|
||||
savingsAccountTransactionType);
|
||||
savingsAccountTransactionType, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||
final boolean isAccountTransfer, final boolean isRegularTransaction,
|
||||
final SavingsAccountTransactionType savingsAccountTransactionType) {
|
||||
final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill) {
|
||||
AppUser user = getAppUserIfPresent();
|
||||
account.validateForAccountBlock();
|
||||
account.validateForCreditBlock();
|
||||
|
||||
// Global configurations
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
@@ -162,27 +178,40 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
boolean isInterestTransfer = false;
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
updateTransactionDetailsWithPivotConfig(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
Integer accountType = null;
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, new Date(), user, accountType);
|
||||
final SavingsAccountTransaction deposit = account.deposit(transactionDTO, savingsAccountTransactionType);
|
||||
final SavingsAccountTransaction deposit = account.deposit(transactionDTO, savingsAccountTransactionType, backdatedTxnsAllowedTill);
|
||||
final LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
saveTransactionToGenerateTransactionId(deposit);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
// Update transactions separately
|
||||
saveUpdatedTransactionsOfSavingsAccount(account.getSavingsAccountTransactionsWithPivotConfig());
|
||||
}
|
||||
|
||||
this.savingsAccountRepository.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.SAVINGS_DEPOSIT,
|
||||
constructEntityMap(BusinessEntity.SAVINGS_TRANSACTION, deposit));
|
||||
return deposit;
|
||||
@@ -190,19 +219,14 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
|
||||
@Override
|
||||
public SavingsAccountTransaction handleDividendPayout(final SavingsAccount account, final LocalDate transactionDate,
|
||||
final BigDecimal transactionAmount) {
|
||||
final BigDecimal transactionAmount, final boolean backdatedTxnsAllowedTill) {
|
||||
final DateTimeFormatter fmt = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final boolean isAccountTransfer = false;
|
||||
final boolean isRegularTransaction = true;
|
||||
final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.DIVIDEND_PAYOUT;
|
||||
return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction,
|
||||
savingsAccountTransactionType);
|
||||
}
|
||||
|
||||
private Long saveTransactionToGenerateTransactionId(final SavingsAccountTransaction transaction) {
|
||||
this.savingsAccountTransactionRepository.save(transaction);
|
||||
return transaction.getId();
|
||||
savingsAccountTransactionType, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
private void updateExistingTransactionsDetails(SavingsAccount account, Set<Long> existingTransactionIds,
|
||||
@@ -211,24 +235,39 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
existingReversedTransactionIds.addAll(account.findExistingReversedTransactionIds());
|
||||
}
|
||||
|
||||
private Long saveTransactionToGenerateTransactionId(final SavingsAccountTransaction transaction) {
|
||||
this.savingsAccountTransactionRepository.save(transaction);
|
||||
return transaction.getId();
|
||||
}
|
||||
|
||||
private void saveUpdatedTransactionsOfSavingsAccount(final List<SavingsAccountTransaction> savingsAccountTransactions) {
|
||||
this.savingsAccountTransactionRepository.saveAll(savingsAccountTransactions);
|
||||
}
|
||||
|
||||
private void updateTransactionDetailsWithPivotConfig(final SavingsAccount account, Set<Long> existingTransactionIds,
|
||||
Set<Long> existingReversedTransactionIds) {
|
||||
existingTransactionIds.addAll(account.findCurrentTransactionIdsWithPivotDateConfig());
|
||||
existingReversedTransactionIds.addAll(account.findCurrentReversedTransactionIdsWithPivotDateConfig());
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final Set<Long> existingTransactionIds,
|
||||
final Set<Long> existingReversedTransactionIds, boolean isAccountTransfer) {
|
||||
final Set<Long> existingReversedTransactionIds, boolean isAccountTransfer, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void postJournalEntries(final SavingsAccount account, final Set<Long> existingTransactionIds,
|
||||
final Set<Long> existingReversedTransactionIds) {
|
||||
final Set<Long> existingReversedTransactionIds, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final boolean isAccountTransfer = false;
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
private Map<BusinessEntity, Object> constructEntityMap(final BusinessEntity entityEvent, Object entity) {
|
||||
|
||||
+6
@@ -19,10 +19,12 @@
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.LockModeType;
|
||||
import org.springframework.data.domain.Page;
|
||||
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;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
@@ -32,6 +34,10 @@ public interface SavingsAccountRepository extends JpaRepository<SavingsAccount,
|
||||
@Query("select s_acc from SavingsAccount s_acc where s_acc.client.id = :clientId")
|
||||
List<SavingsAccount> findSavingAccountByClientId(@Param("clientId") Long clientId);
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
@Query("select sa from SavingsAccount sa where sa.id = :savingsId")
|
||||
SavingsAccount findOneLocked(@Param("savingsId") Long id);
|
||||
|
||||
@Query("select s_acc from SavingsAccount s_acc where s_acc.gsim.id = :gsimId")
|
||||
List<SavingsAccount> findSavingAccountByGsimId(@Param("gsimId") Long gsimId);
|
||||
|
||||
|
||||
+35
-1
@@ -18,13 +18,16 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -43,10 +46,15 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public class SavingsAccountRepositoryWrapper {
|
||||
|
||||
private final SavingsAccountRepository repository;
|
||||
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountRepositoryWrapper(final SavingsAccountRepository repository) {
|
||||
public SavingsAccountRepositoryWrapper(final SavingsAccountRepository repository,
|
||||
final SavingsAccountTransactionRepository savingsAccountTransactionRepository, final RoutingDataSource dataSource) {
|
||||
this.repository = repository;
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@@ -57,6 +65,21 @@ public class SavingsAccountRepositoryWrapper {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public SavingsAccount findSavingsWithNotFoundDetection(final Long savingsId, final boolean backdatedTxnsAllowedTill) {
|
||||
SavingsAccount account = null;
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
account = findOneWithNotFoundDetection(savingsId);
|
||||
} else {
|
||||
account = this.repository.findOneLocked(savingsId);
|
||||
if (account == null) {
|
||||
throw new SavingsAccountNotFoundException(savingsId);
|
||||
}
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public SavingsAccount findOneWithNotFoundDetection(final Long savingsId, final DepositAccountType depositAccountType) {
|
||||
final SavingsAccount account = this.repository.findByIdAndDepositAccountType(savingsId, depositAccountType.getValue());
|
||||
@@ -106,6 +129,17 @@ public class SavingsAccountRepositoryWrapper {
|
||||
return this.repository.findSavingAccountByGsimId(gsimId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<SavingsAccountTransaction> findTransactionsAfterPivotDate(@Param("savingsAccount") SavingsAccount savingsAccount,
|
||||
@Param("date") Date date) {
|
||||
return this.savingsAccountTransactionRepository.findTransactionsAfterPivotDate(savingsAccount, date);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<SavingsAccountTransaction> findAllTransactions(@Param("savingsAccount") SavingsAccount savingsAccount) {
|
||||
return this.savingsAccountTransactionRepository.findBySavingsAccount(savingsAccount);
|
||||
}
|
||||
|
||||
// Root Entity is enough
|
||||
public SavingsAccount findNonClosedAccountByAccountNumber(@Param("accountNumber") String accountNumber) {
|
||||
return this.repository.findNonClosedAccountByAccountNumber(accountNumber);
|
||||
|
||||
+149
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
@@ -31,6 +32,7 @@ import javax.persistence.Transient;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
|
||||
import org.apache.fineract.portfolio.savings.domain.interest.PostingPeriod;
|
||||
|
||||
/**
|
||||
@@ -83,6 +85,14 @@ public final class SavingsAccountSummary {
|
||||
@Column(name = "last_interest_calculation_date")
|
||||
private Date lastInterestCalculationDate;
|
||||
|
||||
// Currently this represents the last interest posting date
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "interest_posted_till_date")
|
||||
private Date interestPostedTillDate;
|
||||
|
||||
@Transient
|
||||
private BigDecimal runningBalanceOnInterestPostingTillDate = BigDecimal.ZERO;
|
||||
|
||||
SavingsAccountSummary() {
|
||||
//
|
||||
}
|
||||
@@ -102,11 +112,130 @@ public final class SavingsAccountSummary {
|
||||
this.totalOverdraftInterestDerived = wrapper.calculateTotalOverdraftInterest(currency, transactions);
|
||||
this.totalWithholdTax = wrapper.calculateTotalWithholdTaxWithdrawal(currency, transactions);
|
||||
|
||||
// boolean isUpdated = false;
|
||||
updateRunningBalanceAndPivotDate(false, transactions, null, null, currency);
|
||||
|
||||
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
|
||||
.minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge)
|
||||
.minus(totalOverdraftInterestDerived).minus(totalWithholdTax).getAmount();
|
||||
}
|
||||
|
||||
public void updateSummaryWithPivotConfig(final MonetaryCurrency currency, final SavingsAccountTransactionSummaryWrapper wrapper,
|
||||
final SavingsAccountTransaction transaction, final List<SavingsAccountTransaction> savingsAccountTransactions) {
|
||||
|
||||
if (transaction != null) {
|
||||
Money transactionAmount = Money.of(currency, transaction.getAmount());
|
||||
switch (SavingsAccountTransactionType.fromInt(transaction.getTypeOf())) {
|
||||
case DEPOSIT:
|
||||
if (transaction.isDepositAndNotReversed() || transaction.isDividendPayoutAndNotReversed()) {
|
||||
this.totalDeposits = Money.of(currency, this.totalDeposits).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).plus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WITHDRAWAL:
|
||||
if (transaction.isWithdrawal() && transaction.isNotReversed()) {
|
||||
this.totalWithdrawals = Money.of(currency, this.totalWithdrawals).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WITHDRAWAL_FEE:
|
||||
if (transaction.isWithdrawalFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
this.totalWithdrawalFees = Money.of(currency, this.totalWithdrawalFees).plus(transactionAmount).getAmount();
|
||||
this.totalFeeCharge = Money.of(currency, this.totalFeeCharge).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case ANNUAL_FEE:
|
||||
if (transaction.isAnnualFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
this.totalAnnualFees = Money.of(currency, this.totalAnnualFees).plus(transactionAmount).getAmount();
|
||||
this.totalFeeCharge = Money.of(currency, this.totalFeeCharge).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WAIVE_CHARGES:
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed()) {
|
||||
this.totalFeeChargesWaived = Money.of(currency, this.totalFeeChargesWaived).plus(transactionAmount.getAmount())
|
||||
.getAmount();
|
||||
} else if (transaction.isWaivePenaltyChargeAndNotReversed()) {
|
||||
this.totalPenaltyChargesWaived = Money.of(currency, this.totalPenaltyChargesWaived)
|
||||
.plus(transactionAmount.getAmount()).getAmount();
|
||||
}
|
||||
break;
|
||||
case PAY_CHARGE:
|
||||
if (transaction.isFeeChargeAndNotReversed()) {
|
||||
this.totalFeeCharge = Money.of(currency, this.totalFeeCharge).plus(transactionAmount).getAmount();
|
||||
} else if (transaction.isPenaltyChargeAndNotReversed()) {
|
||||
this.totalPenaltyCharge = Money.of(currency, this.totalPenaltyCharge).plus(transactionAmount).getAmount();
|
||||
}
|
||||
if (transaction.isFeeChargeAndNotReversed() || transaction.isPenaltyChargeAndNotReversed()) {
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case OVERDRAFT_INTEREST:
|
||||
if (transaction.isOverdraftInterestAndNotReversed()) {
|
||||
this.totalOverdraftInterestDerived = Money.of(currency, this.totalOverdraftInterestDerived).plus(transactionAmount)
|
||||
.getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WITHHOLD_TAX:
|
||||
if (transaction.isWithHoldTaxAndNotReversed()) {
|
||||
this.totalWithholdTax = Money.of(currency, this.totalWithholdTax).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// boolean isUpdated = false;
|
||||
Money interestTotal = Money.of(currency, this.totalInterestPosted);
|
||||
Money withHoldTaxTotal = Money.of(currency, this.totalWithholdTax);
|
||||
|
||||
final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal,
|
||||
withHoldTaxTotal, currency);
|
||||
interestTotal = map.get("interestTotal");
|
||||
withHoldTaxTotal = map.get("withHoldTax");
|
||||
this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero();
|
||||
this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).plus(this.totalInterestPosted).minus(this.totalWithholdTax)
|
||||
.getAmount();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private HashMap<String, Money> updateRunningBalanceAndPivotDate(final boolean backdatedTxnsAllowedTill,
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions, Money interestTotal, Money withHoldTaxTotal,
|
||||
MonetaryCurrency currency) {
|
||||
boolean isUpdated = false;
|
||||
HashMap<String, Money> map = new HashMap<>();
|
||||
for (int i = savingsAccountTransactions.size() - 1; i >= 0; i--) {
|
||||
final SavingsAccountTransaction savingsAccountTransaction = savingsAccountTransactions.get(i);
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed() && !isUpdated) {
|
||||
setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount());
|
||||
setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate());
|
||||
isUpdated = true;
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed()) {
|
||||
interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount(currency));
|
||||
}
|
||||
|
||||
if (savingsAccountTransaction.isWithHoldTaxAndNotReversed()) {
|
||||
withHoldTaxTotal = withHoldTaxTotal.plus(savingsAccountTransaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
map.put("interestTotal", interestTotal);
|
||||
map.put("withHoldTax", withHoldTaxTotal);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List<PostingPeriod> allPostingPeriods) {
|
||||
|
||||
Money totalEarned = Money.zero(currency);
|
||||
@@ -137,4 +266,24 @@ public final class SavingsAccountSummary {
|
||||
return this.totalInterestPosted;
|
||||
}
|
||||
|
||||
public Date getLastInterestCalculationDate() {
|
||||
return this.lastInterestCalculationDate;
|
||||
}
|
||||
|
||||
public void setInterestPostedTillDate(final Date date) {
|
||||
this.interestPostedTillDate = date;
|
||||
}
|
||||
|
||||
public Date getInterestPostedTillDate() {
|
||||
return this.interestPostedTillDate;
|
||||
}
|
||||
|
||||
public void setRunningBalanceOnPivotDate(final BigDecimal runningBalanceOnPivotDate) {
|
||||
this.runningBalanceOnInterestPostingTillDate = runningBalanceOnPivotDate;
|
||||
}
|
||||
|
||||
public BigDecimal getRunningBalanceOnPivotDate() {
|
||||
return this.runningBalanceOnInterestPostingTillDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
@@ -445,6 +445,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
return LocalDate.ofInstant(this.dateOf.toInstant(), DateUtils.getDateTimeZoneOfTenant());
|
||||
}
|
||||
|
||||
public Date getLastTransactionDate() {
|
||||
return this.dateOf;
|
||||
}
|
||||
|
||||
public LocalDate getEndOfBalanceLocalDate() {
|
||||
return balanceEndDate == null ? null : LocalDate.ofInstant(balanceEndDate.toInstant(), DateUtils.getDateTimeZoneOfTenant());
|
||||
}
|
||||
|
||||
+12
@@ -18,8 +18,12 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.persistence.LockModeType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Lock;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
@@ -30,4 +34,12 @@ public interface SavingsAccountTransactionRepository
|
||||
SavingsAccountTransaction findOneByIdAndSavingsAccountId(@Param("transactionId") Long transactionId,
|
||||
@Param("savingsId") Long savingsId);
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
@Query("select st from SavingsAccountTransaction st where st.savingsAccount = :savingsAccount and st.dateOf >= :date order by st.dateOf,st.createdDate,st.id")
|
||||
List<SavingsAccountTransaction> findTransactionsAfterPivotDate(@Param("savingsAccount") SavingsAccount savingsAccount,
|
||||
@Param("date") Date date);
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
List<SavingsAccountTransaction> findBySavingsAccount(@Param("savingsAccount") SavingsAccount savingsAccount);
|
||||
|
||||
}
|
||||
|
||||
+22
@@ -61,6 +61,17 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalInterestPosted(final MonetaryCurrency currency, final BigDecimal currentInterestPosted,
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions) {
|
||||
Money total = Money.of(currency, currentInterestPosted);
|
||||
for (final SavingsAccountTransaction transaction : savingsAccountTransactions) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalWithdrawalFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
@@ -122,6 +133,17 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalOverdraftInterest(MonetaryCurrency currency, BigDecimal overdraftPosted,
|
||||
List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.of(currency, overdraftPosted);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalOverdraftInterest(MonetaryCurrency currency, List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
|
||||
+6
@@ -23,6 +23,7 @@ import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
@@ -176,4 +177,9 @@ public final class SavingsHelper {
|
||||
public Collection<Long> fetchPostInterestTransactionIds(Long accountId) {
|
||||
return this.accountTransfersReadPlatformService.fetchPostInterestTransactionIds(accountId);
|
||||
}
|
||||
|
||||
public Collection<Long> fetchPostInterestTransactionIds(Long accountId, Date pivotDate) {
|
||||
return this.accountTransfersReadPlatformService.fetchPostInterestTransactionIdsWithPivotDate(accountId, pivotDate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.portfolio.savings.exception;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class TransactionBeforePivotDateNotAllowed extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public TransactionBeforePivotDateNotAllowed(final LocalDate date, final LocalDate interestPostingDate) {
|
||||
super("error.msg.savings.transaction.is.not.allowed",
|
||||
"Savings Account transaction date " + date + " should be after the last interest posting date " + interestPostingDate);
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -587,6 +587,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
||||
selectFieldsSqlBuilder.append("sa.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
|
||||
selectFieldsSqlBuilder.append("sa.total_deposits_derived as totalDeposits, ");
|
||||
selectFieldsSqlBuilder.append("sa.total_withdrawals_derived as totalWithdrawals, ");
|
||||
selectFieldsSqlBuilder.append("sa.interest_posted_till_date as interestPostedTillDate, ");
|
||||
selectFieldsSqlBuilder.append("sa.total_withdrawal_fees_derived as totalWithdrawalFees, ");
|
||||
selectFieldsSqlBuilder.append("sa.total_annual_fees_derived as totalAnnualFees, ");
|
||||
selectFieldsSqlBuilder.append("sa.total_interest_earned_derived as totalInterestEarned, ");
|
||||
@@ -739,6 +740,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
||||
final BigDecimal totalPenaltyCharge = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalPenaltyCharge");
|
||||
final BigDecimal totalWithholdTax = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithholdTax");
|
||||
final BigDecimal totalOverdraftInterestDerived = null;
|
||||
final LocalDate interestPostedTillDate = JdbcSupport.getLocalDate(rs, "interestPostedTillDate");
|
||||
|
||||
final boolean withHoldTax = rs.getBoolean("withHoldTax");
|
||||
final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId");
|
||||
@@ -751,7 +753,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
||||
final BigDecimal availableBalance = null;
|
||||
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
|
||||
totalWithdrawalFees, totalAnnualFees, totalInterestEarned, totalInterestPosted, accountBalance, totalFeeCharge,
|
||||
totalPenaltyCharge, totalOverdraftInterestDerived, totalWithholdTax, null, null, availableBalance);
|
||||
totalPenaltyCharge, totalOverdraftInterestDerived, totalWithholdTax, null, null, availableBalance,
|
||||
interestPostedTillDate);
|
||||
|
||||
return DepositAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
|
||||
+38
-36
@@ -244,14 +244,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
if (activationChargeAmount.isGreaterThanZero()) {
|
||||
payActivationCharge(account, user);
|
||||
}
|
||||
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) {
|
||||
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate(), false)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -266,7 +266,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
|
||||
}
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name(),
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, false);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
}
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -295,7 +295,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
for (SavingsAccountCharge savingsAccountCharge : account.charges()) {
|
||||
if (savingsAccountCharge.isSavingsActivation()) {
|
||||
account.payCharge(savingsAccountCharge, savingsAccountCharge.getAmount(account.getCurrency()),
|
||||
account.getActivationLocalDate(), user);
|
||||
account.getActivationLocalDate(), user, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,14 +368,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
account.updateOverduePayments(overdueUptoDate);
|
||||
final boolean isInterestTransfer = false;
|
||||
final LocalDate postInterestOnDate = null;
|
||||
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) {
|
||||
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate(), false)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -384,7 +384,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name(),
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, false);
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
}
|
||||
@@ -527,7 +527,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
|
||||
this.savingAccountRepositoryWrapper.save(account);
|
||||
|
||||
@@ -571,7 +571,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -645,12 +645,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
LocalDate postInterestOnDate = null;
|
||||
checkClientOrGroupActive(account);
|
||||
if (savingsAccountTransaction.isPostInterestCalculationRequired()
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -658,7 +658,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction, depositAccountOnHoldTransactions);
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction, depositAccountOnHoldTransactions,
|
||||
false);
|
||||
// account.activateAccountBasedOnBalance();
|
||||
final boolean isPreMatureClosure = false;
|
||||
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
@@ -745,22 +746,22 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
if (savingsAccountTransaction.isDeposit()) {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
|
||||
transaction = account.deposit(transactionDTO);
|
||||
transaction = account.deposit(transactionDTO, false);
|
||||
} else {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
|
||||
transaction = account.withdraw(transactionDTO, true);
|
||||
transaction = account.withdraw(transactionDTO, true, false);
|
||||
}
|
||||
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
|
||||
boolean isInterestTransfer = false;
|
||||
final LocalDate postInterestOnDate = null;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)
|
||||
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, false)
|
||||
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -768,7 +769,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction, depositAccountOnHoldTransactions);
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction, depositAccountOnHoldTransactions,
|
||||
false);
|
||||
account.activateAccountBasedOnBalance();
|
||||
|
||||
if (savingsAccountTransaction.isDeposit()) {
|
||||
@@ -982,7 +984,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
boolean isInterestTransfer = false;
|
||||
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
|
||||
this.savingsAccountTransactionRepository.save(newTransferTransaction);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
|
||||
@@ -1016,7 +1018,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
|
||||
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
|
||||
@@ -1060,7 +1062,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
|
||||
this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
|
||||
@@ -1209,18 +1211,18 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
account.waiveCharge(savingsAccountChargeId, user);
|
||||
account.waiveCharge(savingsAccountChargeId, user, false);
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), false)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -1229,7 +1231,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction,
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, false);
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
@@ -1348,18 +1350,18 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user);
|
||||
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user, false);
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, false)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -1368,7 +1370,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode(),
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, false);
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
@@ -1436,7 +1438,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
boolean isAccountTransfer = false;
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, false);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -313,6 +313,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sa.withhold_tax as withHoldTax, ");
|
||||
sqlBuilder.append("sa.total_withhold_tax_derived as totalWithholdTax, ");
|
||||
sqlBuilder.append("sa.last_interest_calculation_date as lastInterestCalculationDate, ");
|
||||
sqlBuilder.append("sa.interest_posted_till_date as interestPostedTillDate, ");
|
||||
sqlBuilder.append("sa.total_savings_amount_on_hold as onHoldAmount, ");
|
||||
sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, ");
|
||||
sqlBuilder.append("(select IFNULL(max(sat.transaction_date),sa.activatedon_date) ");
|
||||
@@ -508,6 +509,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final BigDecimal totalOverdraftInterestDerived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs,
|
||||
"totalOverdraftInterestDerived");
|
||||
final BigDecimal totalWithholdTax = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithholdTax");
|
||||
final LocalDate interestPostedTillDate = JdbcSupport.getLocalDate(rs, "interestPostedTillDate");
|
||||
|
||||
final BigDecimal minBalanceForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs,
|
||||
"minBalanceForInterestCalculation");
|
||||
@@ -536,7 +538,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
|
||||
totalWithdrawalFees, totalAnnualFees, totalInterestEarned, totalInterestPosted, accountBalance, totalFeeCharge,
|
||||
totalPenaltyCharge, totalOverdraftInterestDerived, totalWithholdTax, interestNotPosted, lastInterestCalculationDate,
|
||||
availableBalance);
|
||||
availableBalance, interestPostedTillDate);
|
||||
|
||||
final boolean withHoldTax = rs.getBoolean("withHoldTax");
|
||||
final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId");
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult postInterest(JsonCommand command);
|
||||
|
||||
void postInterest(SavingsAccount account, boolean postInterestAs, LocalDate transactionDate);
|
||||
void postInterest(SavingsAccount account, boolean postInterestAs, LocalDate transactionDate, boolean backdatedTxnsAllowedTill);
|
||||
|
||||
CommandProcessingResult blockAccount(Long savingsId);
|
||||
|
||||
|
||||
+190
-89
@@ -239,11 +239,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateActivation(command);
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
|
||||
checkClientOrGroupActive(account);
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Map<String, Object> changes = account.activate(user, command, DateUtils.getLocalDateOfTenant());
|
||||
|
||||
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
|
||||
@@ -253,11 +256,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
||||
processPostActiveActions(account, fmt, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
}
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.SAVINGS_ACTIVATE,
|
||||
constructEntityMap(BusinessEntity.SAVING, account));
|
||||
|
||||
@@ -286,17 +288,20 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (amountForDeposit.isGreaterThanZero()) {
|
||||
boolean isAccountTransfer = false;
|
||||
this.savingsAccountDomainService.handleDeposit(account, fmt, account.getActivationLocalDate(), amountForDeposit.getAmount(),
|
||||
null, isAccountTransfer, isRegularTransaction);
|
||||
null, isAccountTransfer, isRegularTransaction, false);
|
||||
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, user);
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
depositAccountOnHoldTransactions = this.depositAccountOnHoldTransactionRepository
|
||||
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name(),
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, false);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -330,25 +335,30 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingsAccountTransactionDataValidator.validate(command);
|
||||
boolean isGsim = false;
|
||||
|
||||
if (this.savingAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsId).getGsim() != null) {
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
|
||||
|
||||
if (account.getGsim() != null) {
|
||||
isGsim = true;
|
||||
LOG.info("is gsim");
|
||||
}
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transactionDate, account);
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
boolean isAccountTransfer = false;
|
||||
boolean isRegularTransaction = true;
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
||||
|
||||
if (isGsim && (deposit.getId() != null)) {
|
||||
|
||||
@@ -394,9 +404,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingsAccountTransactionDataValidator.validate(command);
|
||||
|
||||
boolean isGsim = false;
|
||||
if (this.savingAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsId).getGsim() != null) {
|
||||
isGsim = true;
|
||||
}
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||
@@ -407,8 +414,17 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
|
||||
|
||||
if (account.getGsim() != null) {
|
||||
isGsim = true;
|
||||
}
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transactionDate, account);
|
||||
|
||||
final boolean isAccountTransfer = false;
|
||||
final boolean isRegularTransaction = true;
|
||||
final boolean isApplyWithdrawFee = true;
|
||||
@@ -417,7 +433,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer,
|
||||
isRegularTransaction, isApplyWithdrawFee, isInterestTransfer, isWithdrawBalance);
|
||||
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, transactionBooleanValues);
|
||||
transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill);
|
||||
|
||||
if (isGsim && (withdrawal.getId() != null)) {
|
||||
GroupSavingsIndividualMonitoring gsim = gsimRepository.findById(account.getGsim().getId()).get();
|
||||
@@ -456,7 +472,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MM yyyy").withZone(DateUtils.getDateTimeZoneOfTenant());
|
||||
|
||||
while (todaysDate.isAfter(savingsAccountCharge.getDueLocalDate())) {
|
||||
this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueLocalDate(), savingsAccountCharge.amount(), fmt, user);
|
||||
this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueLocalDate(), savingsAccountCharge.amount(), fmt, user, false);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -476,14 +492,21 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
|
||||
boolean isInterestTransfer = false;
|
||||
final LocalDate postInterestOnDate = null;
|
||||
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
this.savingsAccountTransactionRepository.saveAll(account.getSavingsAccountTransactionsWithPivotConfig());
|
||||
}
|
||||
|
||||
this.savingAccountRepositoryWrapper.save(account);
|
||||
|
||||
@@ -502,8 +525,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
Long savingsId = command.getSavingsId();
|
||||
final boolean postInterestAs = command.booleanPrimitiveValueOfParameterNamed("isPostInterestAsOn");
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transactionDate, account);
|
||||
|
||||
if (postInterestAs == true) {
|
||||
|
||||
if (transactionDate == null) {
|
||||
@@ -513,7 +541,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (transactionDate.isBefore(account.accountSubmittedOrActivationDate())) {
|
||||
throw new PostInterestAsOnDateException(PostInterestAsOnExceptionType.ACTIVATION_DATE);
|
||||
}
|
||||
List<SavingsAccountTransaction> savingTransactions = account.getTransactions();
|
||||
|
||||
List<SavingsAccountTransaction> savingTransactions = null;
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
savingTransactions = account.getSavingsAccountTransactionsWithPivotConfig();
|
||||
} else {
|
||||
savingTransactions = account.getTransactions();
|
||||
}
|
||||
|
||||
for (SavingsAccountTransaction savingTransaction : savingTransactions) {
|
||||
if (Date.from(transactionDate.atStartOfDay(ZoneId.systemDefault()).toInstant()).before(savingTransaction.getDateOf())) {
|
||||
throw new PostInterestAsOnDateException(PostInterestAsOnExceptionType.LAST_TRANSACTION_DATE);
|
||||
@@ -526,7 +561,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
|
||||
}
|
||||
postInterest(account, postInterestAs, transactionDate);
|
||||
postInterest(account, postInterestAs, transactionDate, backdatedTxnsAllowedTill);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.SAVINGS_POST_INTEREST,
|
||||
constructEntityMap(BusinessEntity.SAVING, account));
|
||||
@@ -541,7 +576,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void postInterest(final SavingsAccount account, final boolean postInterestAs, final LocalDate transactionDate) {
|
||||
public void postInterest(final SavingsAccount account, final boolean postInterestAs, final LocalDate transactionDate,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
@@ -550,7 +586,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|| (account.allowOverdraft() && account.getNominalAnnualInterestRateOverdraft().compareTo(BigDecimal.ZERO) > 0)) {
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
updateSavingsTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
final MathContext mc = new MathContext(10, MoneyHelper.getRoundingMode());
|
||||
boolean isInterestTransfer = false;
|
||||
@@ -558,19 +600,26 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (postInterestAs) {
|
||||
postInterestOnDate = transactionDate;
|
||||
}
|
||||
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
// for generating transaction id's
|
||||
List<SavingsAccountTransaction> transactions = account.getTransactions();
|
||||
for (SavingsAccountTransaction accountTransaction : transactions) {
|
||||
if (accountTransaction.getId() == null) {
|
||||
this.savingsAccountTransactionRepository.save(accountTransaction);
|
||||
postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
List<SavingsAccountTransaction> transactions = account.getTransactions();
|
||||
for (SavingsAccountTransaction accountTransaction : transactions) {
|
||||
if (accountTransaction.getId() == null) {
|
||||
this.savingsAccountTransactionRepository.save(accountTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
this.savingsAccountTransactionRepository.saveAll(account.getSavingsAccountTransactionsWithPivotConfig());
|
||||
}
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, backdatedTxnsAllowedTill);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,7 +631,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -593,6 +642,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId);
|
||||
}
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(savingsAccountTransaction.getTransactionLocalDate(),
|
||||
account);
|
||||
|
||||
if (!allowAccountTransferModification
|
||||
&& this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)) {
|
||||
throw new PlatformServiceUnavailableException("error.msg.saving.account.transfer.transaction.update.not.allowed",
|
||||
@@ -626,22 +678,23 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
LocalDate postInterestOnDate = null;
|
||||
checkClientOrGroupActive(account);
|
||||
if (savingsAccountTransaction.isPostInterestCalculationRequired()
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
depositAccountOnHoldTransactions = this.depositAccountOnHoldTransactionRepository
|
||||
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
|
||||
}
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction, depositAccountOnHoldTransactions);
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction, depositAccountOnHoldTransactions,
|
||||
false);
|
||||
account.activateAccountBasedOnBalance();
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -681,7 +734,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
|
||||
if (account.isNotActive()) {
|
||||
throwValidationForActiveStatus(SavingsApiConstants.adjustTransactionAction);
|
||||
}
|
||||
@@ -691,6 +745,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
@@ -716,29 +771,32 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
|
||||
if (savingsAccountTransaction.isDeposit()) {
|
||||
transaction = account.deposit(transactionDTO);
|
||||
transaction = account.deposit(transactionDTO, false);
|
||||
} else {
|
||||
transaction = account.withdraw(transactionDTO, true);
|
||||
transaction = account.withdraw(transactionDTO, true, false);
|
||||
}
|
||||
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
|
||||
final LocalDate postInterestOnDate = null;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)
|
||||
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, false)
|
||||
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, false);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
depositAccountOnHoldTransactions = this.depositAccountOnHoldTransactionRepository
|
||||
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
|
||||
}
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction, depositAccountOnHoldTransactions);
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction, depositAccountOnHoldTransactions,
|
||||
false);
|
||||
account.activateAccountBasedOnBalance();
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(newtransactionId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -802,7 +860,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult close(final Long savingsId, final JsonCommand command) {
|
||||
final AppUser user = this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
this.savingsAccountTransactionDataValidator.validateClosing(command, account);
|
||||
|
||||
final boolean isLinkedWithAnyActiveLoan = this.accountAssociationsReadPlatformService.isLinkedWithAnyActiveAccount(savingsId);
|
||||
@@ -854,7 +912,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
isRegularTransaction, isApplyWithdrawFee, isInterestTransfer, isWithdrawBalance);
|
||||
|
||||
this.savingsAccountDomainService.handleWithdrawal(account, fmt, closedDate, transactionAmount, paymentDetail,
|
||||
transactionBooleanValues);
|
||||
transactionBooleanValues, false);
|
||||
|
||||
}
|
||||
|
||||
@@ -909,12 +967,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
|
||||
this.savingsAccountTransactionRepository.save(newTransferTransaction);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
|
||||
|
||||
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
|
||||
return newTransferTransaction;
|
||||
}
|
||||
@@ -940,12 +998,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
|
||||
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
|
||||
|
||||
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
|
||||
return withdrawtransferTransaction;
|
||||
}
|
||||
@@ -982,12 +1040,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
LocalDate postInterestOnDate = null;
|
||||
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
|
||||
this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
|
||||
|
||||
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
|
||||
return acceptTransferTransaction;
|
||||
}
|
||||
@@ -1004,7 +1062,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Long savingsAccountId = command.getSavingsId();
|
||||
this.savingsAccountChargeDataValidator.validateAdd(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId, false);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
@@ -1073,7 +1131,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
// SavingsAccount Charge entity
|
||||
final Long savingsChargeId = command.entityId();
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId, false);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(savingsChargeId,
|
||||
@@ -1132,25 +1190,35 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
|
||||
this.savingAccountAssembler.loadTransactionsToSavingsAccount(account, backdatedTxnsAllowedTill);
|
||||
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
account.waiveCharge(savingsAccountChargeId, user);
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
updateSavingsTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
account.waiveCharge(savingsAccountChargeId, user, backdatedTxnsAllowedTill);
|
||||
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
depositAccountOnHoldTransactions = this.depositAccountOnHoldTransactionRepository
|
||||
@@ -1158,11 +1226,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction,
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, backdatedTxnsAllowedTill);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
this.savingsAccountTransactionRepository.saveAll(account.getSavingsAccountTransactionsWithPivotConfig());
|
||||
}
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, backdatedTxnsAllowedTill);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -1178,7 +1250,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
@SuppressWarnings("unused") final JsonCommand command) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId, false);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository
|
||||
.findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId);
|
||||
@@ -1232,7 +1304,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
}
|
||||
|
||||
SavingsAccountTransaction chargeTransaction = this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt, user);
|
||||
final boolean backdatedTxnsAllowedTill = false;
|
||||
|
||||
SavingsAccountTransaction chargeTransaction = this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt, user,
|
||||
backdatedTxnsAllowedTill);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
@@ -1263,13 +1338,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MM yyyy").withZone(DateUtils.getDateTimeZoneOfTenant());
|
||||
|
||||
while (transactionDate.isAfter(savingsAccountCharge.getDueLocalDate()) && savingsAccountCharge.isNotFullyPaid()) {
|
||||
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt, user);
|
||||
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt, user, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
private SavingsAccountTransaction payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate,
|
||||
final BigDecimal amountPaid, final DateTimeFormatter formatter, final AppUser user) {
|
||||
final BigDecimal amountPaid, final DateTimeFormatter formatter, final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
@@ -1281,18 +1356,19 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
SavingsAccountTransaction chargeTransaction = account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user);
|
||||
SavingsAccountTransaction chargeTransaction = account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user,
|
||||
backdatedTxnsAllowedTill);
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate);
|
||||
postInterestOnDate, isInterestTransfer);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
|
||||
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -1301,13 +1377,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode(),
|
||||
depositAccountOnHoldTransactions);
|
||||
depositAccountOnHoldTransactions, backdatedTxnsAllowedTill);
|
||||
|
||||
saveTransactionToGenerateTransactionId(chargeTransaction);
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, backdatedTxnsAllowedTill);
|
||||
|
||||
return chargeTransaction;
|
||||
}
|
||||
@@ -1318,14 +1394,20 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
existingReversedTransactionIds.addAll(account.findExistingReversedTransactionIds());
|
||||
}
|
||||
|
||||
private void updateSavingsTransactionsDetails(SavingsAccount account, Set<Long> existingTransactionIds,
|
||||
Set<Long> existingReversedTransactionIds) {
|
||||
existingTransactionIds.addAll(account.findCurrentTransactionIdsWithPivotDateConfig());
|
||||
existingReversedTransactionIds.addAll(account.findCurrentReversedTransactionIdsWithPivotDateConfig());
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final Set<Long> existingTransactionIds,
|
||||
final Set<Long> existingReversedTransactionIds) {
|
||||
final Set<Long> existingReversedTransactionIds, final boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
boolean isAccountTransfer = false;
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
|
||||
@@ -1502,19 +1584,19 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
@Override
|
||||
@Transactional
|
||||
public void setSubStatusInactive(Long savingsId) {
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.setSubStatusInactive(appuserRepository.fetchSystemUser());
|
||||
account.setSubStatusInactive(appuserRepository.fetchSystemUser(), false);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void setSubStatusDormant(Long savingsId) {
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
account.setSubStatusDormant();
|
||||
this.savingAccountRepositoryWrapper.save(account);
|
||||
}
|
||||
@@ -1522,13 +1604,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
@Override
|
||||
@Transactional
|
||||
public void escheat(Long savingsId) {
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.escheat(appuserRepository.fetchSystemUser());
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
}
|
||||
|
||||
private AppUser getAppUserIfPresent() {
|
||||
@@ -1573,7 +1655,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final Map<String, Object> changes = account.block();
|
||||
@@ -1589,7 +1671,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult unblockAccount(final Long savingsId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final Map<String, Object> changes = account.unblock();
|
||||
@@ -1606,13 +1688,23 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult holdAmount(final Long savingsId, final JsonCommand command) {
|
||||
|
||||
final AppUser submittedBy = this.context.authenticatedUser();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
|
||||
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
SavingsAccountTransaction transacton = this.savingsAccountTransactionDataValidator.validateHoldAndAssembleForm(command.json(),
|
||||
account, submittedBy);
|
||||
account, submittedBy, backdatedTxnsAllowedTill);
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transacton.getTransactionLocalDate(), account);
|
||||
|
||||
this.savingsAccountTransactionRepository.save(transacton);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
// Check again whether transactions are modified
|
||||
this.savingsAccountTransactionRepository.saveAll(account.getSavingsAccountTransactionsWithPivotConfig());
|
||||
}
|
||||
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
return new CommandProcessingResultBuilder().withEntityId(transacton.getId()).withOfficeId(account.officeId())
|
||||
@@ -1629,12 +1721,21 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccountTransaction transaction = this.savingsAccountTransactionDataValidator
|
||||
.validateReleaseAmountAndAssembleForm(holdTransaction, submittedBy);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transaction.getTransactionLocalDate(), account);
|
||||
account.releaseOnHoldAmount(transaction.getAmount());
|
||||
|
||||
this.savingsAccountTransactionRepository.save(transaction);
|
||||
holdTransaction.updateReleaseId(transaction.getId());
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
this.savingsAccountTransactionRepository.saveAll(account.getSavingsAccountTransactionsWithPivotConfig());
|
||||
}
|
||||
|
||||
this.savingAccountRepositoryWrapper.save(account);
|
||||
|
||||
return new CommandProcessingResultBuilder().withEntityId(transaction.getId()).withOfficeId(account.officeId())
|
||||
@@ -1645,7 +1746,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult blockCredits(final Long savingsId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final Map<String, Object> changes = account.blockCredits(account.getSubStatus());
|
||||
@@ -1661,7 +1762,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult unblockCredits(final Long savingsId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final Map<String, Object> changes = account.unblockCredits();
|
||||
@@ -1677,7 +1778,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult blockDebits(final Long savingsId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final Map<String, Object> changes = account.blockDebits(account.getSubStatus());
|
||||
@@ -1693,7 +1794,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult unblockDebits(final Long savingsId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final Map<String, Object> changes = account.unblockDebits();
|
||||
|
||||
+7
-7
@@ -359,7 +359,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<>(20);
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
account.modifyApplication(command, changes);
|
||||
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
@@ -451,7 +451,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
@Override
|
||||
public CommandProcessingResult deleteApplication(final Long savingsId) {
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
if (account.isNotSubmittedAndPendingApproval()) {
|
||||
@@ -515,7 +515,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateApproval(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
|
||||
@@ -581,7 +581,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateForUndo(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
final Map<String, Object> changes = savingsAccount.undoApplicationApproval();
|
||||
@@ -639,7 +639,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateRejection(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
|
||||
@@ -677,7 +677,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateApplicantWithdrawal(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
|
||||
@@ -752,7 +752,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
|
||||
generateAccountNumber(account);
|
||||
// post journal entries for activation charges
|
||||
this.savingsAccountDomainService.postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.savingsAccountDomainService.postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withSavingsId(account.getId()) //
|
||||
|
||||
+5
-2
@@ -25,6 +25,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
|
||||
@@ -54,6 +55,7 @@ public class SavingsSchedularInterestPoster implements Callable<Void> {
|
||||
private SavingsAccountRepositoryWrapper savingsAccountRepository;
|
||||
private SavingsAccountAssembler savingAccountAssembler;
|
||||
private FineractPlatformTenant tenant;
|
||||
private ConfigurationDomainService configurationDomainService;
|
||||
|
||||
public void setSavingsIds(Collection<Long> savingsIds) {
|
||||
this.savingsIds = savingsIds;
|
||||
@@ -82,7 +84,7 @@ public class SavingsSchedularInterestPoster implements Callable<Void> {
|
||||
ThreadLocalContextUtil.setTenant(tenant);
|
||||
Integer maxNumberOfRetries = tenant.getConnection().getMaxRetriesOnDeadlock();
|
||||
Integer maxIntervalBetweenRetries = tenant.getConnection().getMaxIntervalBetweenRetries();
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
|
||||
int i = 0;
|
||||
if (!savingsIds.isEmpty()) {
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
@@ -95,7 +97,8 @@ public class SavingsSchedularInterestPoster implements Callable<Void> {
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(savingsAccount);
|
||||
boolean postInterestAsOn = false;
|
||||
LocalDate transactionDate = null;
|
||||
this.savingsAccountWritePlatformService.postInterest(savingsAccount, postInterestAsOn, transactionDate);
|
||||
this.savingsAccountWritePlatformService.postInterest(savingsAccount, postInterestAsOn, transactionDate,
|
||||
backdatedTxnsAllowedTill);
|
||||
|
||||
numberOfRetries = maxNumberOfRetries + 1;
|
||||
} catch (CannotAcquireLockException | ObjectOptimisticLockingFailureException exception) {
|
||||
|
||||
+2
-2
@@ -50,9 +50,9 @@ public class ShareAccountSchedularServiceImpl implements ShareAccountSchedularSe
|
||||
public void postDividend(final Long dividendDetailId, final Long savingsId) {
|
||||
|
||||
ShareAccountDividendDetails shareAccountDividendDetails = this.shareAccountDividendRepository.findById(dividendDetailId).get();
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsId);
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsId, false);
|
||||
SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountDomainService.handleDividendPayout(savingsAccount,
|
||||
DateUtils.getLocalDateOfTenant(), shareAccountDividendDetails.getAmount());
|
||||
DateUtils.getLocalDateOfTenant(), shareAccountDividendDetails.getAmount(), false);
|
||||
shareAccountDividendDetails.update(ShareAccountDividendStatusType.POSTED.getValue(), savingsAccountTransaction.getId());
|
||||
this.shareAccountDividendRepository.save(shareAccountDividendDetails);
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
|
||||
ALTER TABLE m_savings_account ADD COLUMN interest_posted_till_date DATE NULL DEFAULT NULL;
|
||||
|
||||
insert into c_configuration(name, enabled, value, description) values('allow-backdated-transaction-before-interest-posting', 1, 0, 'Avoid retrieving all transactions in a savings account');
|
||||
|
||||
insert into c_configuration(name, enabled, value, description) values('allow-backdated-transaction-before-interest-posting-date-for-days', 0, 0, 'One time configuration to relax the backdated transactions');
|
||||
+114
@@ -42,6 +42,7 @@ import java.util.Locale;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
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.PaymentTypeHelper;
|
||||
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
||||
import org.apache.fineract.integrationtests.common.TaxComponentHelper;
|
||||
@@ -128,6 +129,115 @@ public class ClientSavingsIntegrationTest {
|
||||
// verifySavingsInterest(savingsInterest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavingsLastTransactionAndRunningBalanceUpdate() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
// Assertions.assertNotNull(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, MINIMUM_OPENING_BALANCE,
|
||||
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 HashMap summaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
this.savingsAccountHelper.calculateInterestForSavings(savingsId);
|
||||
HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
assertEquals(summaryBefore, summary);
|
||||
|
||||
this.savingsAccountHelper.postInterestForSavings(savingsId);
|
||||
|
||||
HashMap summaryAfterPosting = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
|
||||
Assertions.assertNotNull(summaryAfterPosting.get("interestPostedTillDate"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSavingsBackedDatedTransactionsNotAllowed() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
// Assertions.assertNotNull(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, MINIMUM_OPENING_BALANCE,
|
||||
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 HashMap summaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
this.savingsAccountHelper.calculateInterestForSavings(savingsId);
|
||||
HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
assertEquals(summaryBefore, summary);
|
||||
|
||||
this.savingsAccountHelper.postInterestForSavings(savingsId);
|
||||
|
||||
HashMap summaryAfterPosting = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
|
||||
Assertions.assertNotNull(summaryAfterPosting.get("interestPostedTillDate"));
|
||||
|
||||
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec, this.responseSpec, "38", false);
|
||||
|
||||
final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||
final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse);
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(CommonConstants.DATE_FORMAT, Locale.US);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
List dates = (List) summaryAfterPosting.get("interestPostedTillDate");
|
||||
cal.set(Calendar.YEAR, (Integer) dates.get(0));
|
||||
cal.set(Calendar.MONTH, (Integer) dates.get(1) - 1);
|
||||
cal.set(Calendar.DAY_OF_MONTH, (Integer) dates.get(2) - 1);
|
||||
final String depositDate = sdf.format(cal.getTime());
|
||||
LOG.info("-------------------- BackDated Transaction -----------------------------");
|
||||
List<HashMap> error = (List<HashMap>) validationErrorHelper.depositToSavingsAccount(savingsId, "3000", depositDate,
|
||||
CommonConstants.RESPONSE_ERROR);
|
||||
|
||||
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec, this.responseSpec, "38", true);
|
||||
|
||||
// LOG.info(savingsAccountErrorData.get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE).toString());
|
||||
assertEquals("error.msg.savings.transaction.is.not.allowed", error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavingsAccountWithMinBalanceForInterestCalculation() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
@@ -166,6 +276,10 @@ public class ClientSavingsIntegrationTest {
|
||||
|
||||
this.savingsAccountHelper.postInterestForSavings(savingsId);
|
||||
summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
|
||||
// These two fields are getting updated after an interest posting
|
||||
summary.remove("interestPostedTillDate");
|
||||
|
||||
assertEquals(summaryBefore, summary);
|
||||
|
||||
final Object savingsInterest = this.savingsAccountHelper.getSavingsInterest(savingsId);
|
||||
|
||||
+21
-3
@@ -76,6 +76,7 @@ public class GlobalConfigurationHelper {
|
||||
// the future, it needs to be reset here.
|
||||
final Integer configDefaultId = (Integer) configDefault.get("id");
|
||||
final Integer configDefaultValue = (Integer) configDefault.get("value");
|
||||
|
||||
updateValueForGlobalConfiguration(requestSpec, responseSpec, configDefaultId.toString(), configDefaultValue.toString());
|
||||
updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, configDefaultId.toString(),
|
||||
(Boolean) configDefault.get("enabled"));
|
||||
@@ -88,9 +89,9 @@ public class GlobalConfigurationHelper {
|
||||
ArrayList<HashMap> expectedGlobalConfigurations = getAllDefaultGlobalConfigurations();
|
||||
ArrayList<HashMap> actualGlobalConfigurations = getAllGlobalConfigurations(requestSpec, responseSpec);
|
||||
|
||||
// There are currently 32 global configurations.
|
||||
Assertions.assertEquals(33, expectedGlobalConfigurations.size());
|
||||
Assertions.assertEquals(33, actualGlobalConfigurations.size());
|
||||
// There are currently 35 global configurations.
|
||||
Assertions.assertEquals(35, expectedGlobalConfigurations.size());
|
||||
Assertions.assertEquals(35, actualGlobalConfigurations.size());
|
||||
|
||||
for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
|
||||
|
||||
@@ -389,6 +390,23 @@ public class GlobalConfigurationHelper {
|
||||
isNextDayFixedDepositInterestTransferEnabledForPeriodEnd.put("trapDoor", false);
|
||||
defaults.add(isNextDayFixedDepositInterestTransferEnabledForPeriodEnd);
|
||||
|
||||
HashMap<String, Object> isAllowedBackDatedTransactionsBeforeInterestPostingDate = new HashMap<>();
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDate.put("id", 38);
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDate.put("name", "allow-backdated-transaction-before-interest-posting");
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDate.put("value", 0);
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDate.put("enabled", true);
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDate.put("trapDoor", false);
|
||||
defaults.add(isAllowedBackDatedTransactionsBeforeInterestPostingDate);
|
||||
|
||||
HashMap<String, Object> isAllowedBackDatedTransactionsBeforeInterestPostingDateForDays = new HashMap<>();
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDateForDays.put("id", 39);
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDateForDays.put("name",
|
||||
"allow-backdated-transaction-before-interest-posting-date-for-days");
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDateForDays.put("value", 0);
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDateForDays.put("enabled", false);
|
||||
isAllowedBackDatedTransactionsBeforeInterestPostingDateForDays.put("trapDoor", false);
|
||||
defaults.add(isAllowedBackDatedTransactionsBeforeInterestPostingDateForDays);
|
||||
|
||||
return defaults;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -147,8 +147,8 @@ public class SchedulerJobHelper {
|
||||
* @author Michael Vorburger.ch
|
||||
*/
|
||||
public void executeAndAwaitJob(String jobName) {
|
||||
final Duration timeout = Duration.ofMinutes(3);
|
||||
final Duration pause = Duration.ofSeconds(1);
|
||||
final Duration timeout = Duration.ofMinutes(4);
|
||||
final Duration pause = Duration.ofSeconds(2);
|
||||
DateTimeFormatter df = DateTimeFormatter.ISO_INSTANT; // FINERACT-926
|
||||
Instant beforeExecuteTime = now().truncatedTo(ChronoUnit.SECONDS);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user