blob: 58dfc01bae365274d113e4e9af43a8d82d36b854 [file] [log] [blame]
/**
* 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.account.service;
import static org.apache.fineract.portfolio.account.AccountDetailConstants.fromAccountIdParamName;
import static org.apache.fineract.portfolio.account.AccountDetailConstants.fromAccountTypeParamName;
import static org.apache.fineract.portfolio.account.AccountDetailConstants.toAccountIdParamName;
import static org.apache.fineract.portfolio.account.AccountDetailConstants.toAccountTypeParamName;
import static org.apache.fineract.portfolio.account.api.AccountTransfersApiConstants.transferAmountParamName;
import static org.apache.fineract.portfolio.account.api.AccountTransfersApiConstants.transferDateParamName;
import com.google.common.collect.Lists;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.portfolio.account.PortfolioAccountType;
import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
import org.apache.fineract.portfolio.account.data.AccountTransfersDataValidator;
import org.apache.fineract.portfolio.account.domain.AccountTransferAssembler;
import org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository;
import org.apache.fineract.portfolio.account.domain.AccountTransferDetails;
import org.apache.fineract.portfolio.account.domain.AccountTransferRepository;
import org.apache.fineract.portfolio.account.domain.AccountTransferTransaction;
import org.apache.fineract.portfolio.account.domain.AccountTransferType;
import org.apache.fineract.portfolio.account.exception.DifferentCurrenciesException;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.exception.InvalidPaidInAdvanceAmountException;
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
import org.apache.fineract.portfolio.savings.domain.GSIMRepositoy;
import org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
public class AccountTransfersWritePlatformServiceImpl implements AccountTransfersWritePlatformService {
private final AccountTransfersDataValidator accountTransfersDataValidator;
private final AccountTransferAssembler accountTransferAssembler;
private final AccountTransferRepository accountTransferRepository;
private final SavingsAccountAssembler savingsAccountAssembler;
private final SavingsAccountDomainService savingsAccountDomainService;
private final LoanAssembler loanAccountAssembler;
private final LoanAccountDomainService loanAccountDomainService;
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
private final AccountTransferDetailRepository accountTransferDetailRepository;
private final LoanReadPlatformService loanReadPlatformService;
private final GSIMRepositoy gsimRepository;
private final ConfigurationDomainService configurationDomainService;
private final ExternalIdFactory externalIdFactory;
private final FineractProperties fineractProperties;
@Transactional
@Override
public CommandProcessingResult create(final JsonCommand command) {
boolean isRegularTransaction = true;
this.accountTransfersDataValidator.validate(command);
final LocalDate transactionDate = command.localDateValueOfParameterNamed(transferDateParamName);
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed(transferAmountParamName);
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
final Integer fromAccountTypeId = command.integerValueSansLocaleOfParameterNamed(fromAccountTypeParamName);
final PortfolioAccountType fromAccountType = PortfolioAccountType.fromInt(fromAccountTypeId);
final Integer toAccountTypeId = command.integerValueSansLocaleOfParameterNamed(toAccountTypeParamName);
final PortfolioAccountType toAccountType = PortfolioAccountType.fromInt(toAccountTypeId);
final PaymentDetail paymentDetail = null;
Long fromSavingsAccountId = null;
Long transferDetailId = null;
boolean isInterestTransfer = false;
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,
backdatedTxnsAllowedTill);
final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer,
isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), isInterestTransfer, isWithdrawBalance);
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt,
transactionDate, transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill);
final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName);
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId, backdatedTxnsAllowedTill);
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate,
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
if (!fromSavingsAccount.getCurrency().getCode().equals(toSavingsAccount.getCurrency().getCode())) {
throw new DifferentCurrenciesException(fromSavingsAccount.getCurrency().getCode(),
toSavingsAccount.getCurrency().getCode());
}
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleSavingsToSavingsTransfer(command,
fromSavingsAccount, toSavingsAccount, withdrawal, deposit);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferDetailId = accountTransferDetails.getId();
} else if (isSavingsToLoanAccountTransfer(fromAccountType, toAccountType)) {
//
fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
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, backdatedTxnsAllowedTill);
final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId);
final Boolean isHolidayValidationDone = false;
final HolidayDetailDTO holidayDetailDto = null;
final boolean isRecoveryRepayment = false;
final String chargeRefundChargeType = null;
ExternalId externalId = externalIdFactory.create();
final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.REPAYMENT,
toLoanAccount, transactionDate, transactionAmount, paymentDetail, null, externalId, isRecoveryRepayment,
chargeRefundChargeType, isAccountTransfer, holidayDetailDto, isHolidayValidationDone);
toLoanAccount = loanRepaymentTransaction.getLoan();
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(command,
fromSavingsAccount, toLoanAccount, withdrawal, loanRepaymentTransaction);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferDetailId = accountTransferDetails.getId();
} else if (isLoanToSavingsAccountTransfer(fromAccountType, toAccountType)) {
// FIXME - kw - ADD overpaid loan to savings account transfer
// support.
fromLoanAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
final Loan fromLoanAccount = this.loanAccountAssembler.assembleFrom(fromLoanAccountId);
ExternalId externalId = externalIdFactory.create();
final LoanTransaction loanRefundTransaction = this.loanAccountDomainService.makeRefund(fromLoanAccountId,
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, externalId);
final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId, backdatedTxnsAllowedTill);
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate,
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command,
fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferDetailId = accountTransferDetails.getId();
}
final CommandProcessingResultBuilder builder = new CommandProcessingResultBuilder().withEntityId(transferDetailId);
if (fromAccountType.isSavingsAccount()) {
builder.withSavingsId(fromSavingsAccountId);
}
if (fromAccountType.isLoanAccount()) {
builder.withLoanId(fromLoanAccountId);
}
return builder.build();
}
@Override
@Transactional
public void reverseTransfersWithFromAccountType(final Long accountNumber, final PortfolioAccountType accountTypeId) {
List<AccountTransferTransaction> acccountTransfers = null;
if (accountTypeId.isLoanAccount()) {
acccountTransfers = this.accountTransferRepository.findByFromLoanId(accountNumber);
}
if (acccountTransfers != null && acccountTransfers.size() > 0) {
undoTransactions(acccountTransfers);
}
}
@Override
@Transactional
public void reverseTransfersWithFromAccountTransactions(final Collection<Long> fromTransactionIds,
final PortfolioAccountType accountTypeId) {
List<AccountTransferTransaction> acccountTransfers = new ArrayList<>();
if (accountTypeId.isLoanAccount()) {
List<List<Long>> partitions = Lists.partition(fromTransactionIds.stream().toList(),
fineractProperties.getQuery().getInClauseParameterSizeLimit());
partitions.forEach(partition -> acccountTransfers.addAll(this.accountTransferRepository.findByFromLoanTransactions(partition)));
}
if (acccountTransfers.size() > 0) {
undoTransactions(acccountTransfers);
}
}
@Override
@Transactional
public void reverseAllTransactions(final Long accountId, final PortfolioAccountType accountTypeId) {
List<AccountTransferTransaction> acccountTransfers = null;
if (accountTypeId.isLoanAccount()) {
acccountTransfers = this.accountTransferRepository.findAllByLoanId(accountId);
}
if (acccountTransfers != null && acccountTransfers.size() > 0) {
undoTransactions(acccountTransfers);
}
}
/**
* @param acccountTransfers
*/
private void undoTransactions(final List<AccountTransferTransaction> acccountTransfers) {
for (final AccountTransferTransaction accountTransfer : acccountTransfers) {
if (accountTransfer.getFromLoanTransaction() != null) {
this.loanAccountDomainService.reverseTransfer(accountTransfer.getFromLoanTransaction());
}
if (accountTransfer.getToLoanTransaction() != null) {
this.loanAccountDomainService.reverseTransfer(accountTransfer.getToLoanTransaction());
}
if (accountTransfer.getFromTransaction() != null) {
this.savingsAccountWritePlatformService.undoTransaction(
accountTransfer.accountTransferDetails().fromSavingsAccount().getId(), accountTransfer.getFromTransaction().getId(),
true);
}
if (accountTransfer.getToSavingsTransaction() != null) {
this.savingsAccountWritePlatformService.undoTransaction(accountTransfer.accountTransferDetails().toSavingsAccount().getId(),
accountTransfer.getToSavingsTransaction().getId(), true);
}
accountTransfer.reverse();
this.accountTransferRepository.save(accountTransfer);
}
}
@Override
@Transactional
public Long transferFunds(final AccountTransferDTO accountTransferDTO) {
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())) {
//
SavingsAccount fromSavingsAccount = null;
Loan toLoanAccount = null;
if (accountTransferDetails == null) {
if (accountTransferDTO.getFromSavingsAccount() == null) {
fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId(),
backdatedTxnsAllowedTill);
} else {
fromSavingsAccount = accountTransferDTO.getFromSavingsAccount();
this.savingsAccountAssembler.setHelpers(fromSavingsAccount);
}
if (accountTransferDTO.getLoan() == null) {
toLoanAccount = this.loanAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId());
} else {
toLoanAccount = accountTransferDTO.getLoan();
this.loanAccountAssembler.setHelpers(toLoanAccount);
}
} else {
fromSavingsAccount = accountTransferDetails.fromSavingsAccount();
this.savingsAccountAssembler.setHelpers(fromSavingsAccount);
toLoanAccount = accountTransferDetails.toLoanAccount();
this.loanAccountAssembler.setHelpers(toLoanAccount);
}
final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer,
isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(),
AccountTransferType.fromInt(accountTransferDTO.getTransferType()).isInterestTransfer(),
accountTransferDTO.isExceptionForBalanceCheck());
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill);
LoanTransaction loanTransaction;
ExternalId txnExternalId = accountTransferDTO.getTxnExternalId();
// Safety net (it might need to generate new one)
ExternalId externalId = externalIdFactory.create(txnExternalId.getValue());
if (AccountTransferType.fromInt(accountTransferDTO.getTransferType()).isChargePayment()) {
loanTransaction = this.loanAccountDomainService.makeChargePayment(toLoanAccount, accountTransferDTO.getChargeId(),
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), null, externalId, accountTransferDTO.getToTransferType(),
accountTransferDTO.getLoanInstallmentNumber());
} else if (AccountTransferType.fromInt(accountTransferDTO.getTransferType()).isLoanDownPayment()) {
final boolean isRecoveryRepayment = false;
final Boolean isHolidayValidationDone = false;
final HolidayDetailDTO holidayDetailDto = null;
final String chargeRefundChargeType = null;
loanTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.DOWN_PAYMENT, toLoanAccount,
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), null, externalId, isRecoveryRepayment, chargeRefundChargeType,
isAccountTransfer, holidayDetailDto, isHolidayValidationDone);
toLoanAccount = loanTransaction.getLoan();
} else {
final boolean isRecoveryRepayment = false;
final Boolean isHolidayValidationDone = false;
final HolidayDetailDTO holidayDetailDto = null;
final String chargeRefundChargeType = null;
loanTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.REPAYMENT, toLoanAccount,
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), null, externalId, isRecoveryRepayment, chargeRefundChargeType,
isAccountTransfer, holidayDetailDto, isHolidayValidationDone);
toLoanAccount = loanTransaction.getLoan();
}
accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(accountTransferDTO, fromSavingsAccount,
toLoanAccount, withdrawal, loanTransaction);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferTransactionId = accountTransferDetails.getId();
} else if (isSavingsToSavingsAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
SavingsAccount fromSavingsAccount;
SavingsAccount toSavingsAccount;
if (accountTransferDetails == null) {
if (accountTransferDTO.getFromSavingsAccount() == null) {
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(), false);
} else {
toSavingsAccount = accountTransferDTO.getToSavingsAccount();
this.savingsAccountAssembler.setHelpers(toSavingsAccount);
}
} else {
fromSavingsAccount = accountTransferDetails.fromSavingsAccount();
this.savingsAccountAssembler.setHelpers(fromSavingsAccount);
toSavingsAccount = accountTransferDetails.toSavingsAccount();
this.savingsAccountAssembler.setHelpers(toSavingsAccount);
}
final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer,
isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(),
AccountTransferType.fromInt(accountTransferDTO.getTransferType()).isInterestTransfer(),
accountTransferDTO.isExceptionForBalanceCheck());
LocalDate transactionDate = accountTransferDTO.getTransactionDate();
if (configurationDomainService.isSavingsInterestPostingAtCurrentPeriodEnd()
&& configurationDomainService.isNextDayFixedDepositInterestTransferEnabledForPeriodEnd()
&& AccountTransferType.fromInt(accountTransferDTO.getTransferType()).isInterestTransfer()) {
transactionDate = transactionDate.plusDays(1);
}
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
accountTransferDTO.getFmt(), transactionDate, accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill);
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
accountTransferDTO.getFmt(), transactionDate, accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
accountTransferDetails = this.accountTransferAssembler.assembleSavingsToSavingsTransfer(accountTransferDTO, fromSavingsAccount,
toSavingsAccount, withdrawal, deposit);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferTransactionId = accountTransferDetails.getId();
} else if (isLoanToSavingsAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
Loan fromLoanAccount = null;
SavingsAccount toSavingsAccount = null;
if (accountTransferDetails == null) {
if (accountTransferDTO.getLoan() == null) {
fromLoanAccount = this.loanAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId());
} else {
fromLoanAccount = accountTransferDTO.getLoan();
this.loanAccountAssembler.setHelpers(fromLoanAccount);
}
toSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId(), backdatedTxnsAllowedTill);
} else {
fromLoanAccount = accountTransferDetails.fromLoanAccount();
this.loanAccountAssembler.setHelpers(fromLoanAccount);
toSavingsAccount = accountTransferDetails.toSavingsAccount();
this.savingsAccountAssembler.setHelpers(toSavingsAccount);
}
LoanTransaction loanTransaction = null;
ExternalId txnExternalId = accountTransferDTO.getTxnExternalId();
// Safety net (it might need to generate new one)
ExternalId externalId = externalIdFactory.create(txnExternalId.getValue());
if (LoanTransactionType.DISBURSEMENT.getValue().equals(accountTransferDTO.getFromTransferType())) {
loanTransaction = this.loanAccountDomainService.makeDisburseTransaction(accountTransferDTO.getFromAccountId(),
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), accountTransferDTO.getNoteText(), externalId);
} else {
loanTransaction = this.loanAccountDomainService.makeRefund(accountTransferDTO.getFromAccountId(),
new CommandProcessingResultBuilder(), accountTransferDTO.getTransactionDate(),
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(), accountTransferDTO.getNoteText(),
externalId);
}
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(accountTransferDTO, fromLoanAccount,
toSavingsAccount, deposit, loanTransaction);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferTransactionId = accountTransferDetails.getId();
// if the savings account is GSIM, update its parent as well
if (toSavingsAccount.getGsim() != null) {
GroupSavingsIndividualMonitoring gsim = gsimRepository.findById(toSavingsAccount.getGsim().getId()).orElseThrow();
BigDecimal currentBalance = gsim.getParentDeposit();
BigDecimal newBalance = currentBalance.add(accountTransferDTO.getTransactionAmount());
gsim.setParentDeposit(newBalance);
gsimRepository.save(gsim);
}
} else {
throw new GeneralPlatformDomainRuleException("error.msg.accounttransfer.loan.to.loan.not.supported",
"Account transfer from loan to another loan is not supported");
}
return transferTransactionId;
}
@Override
public AccountTransferDetails repayLoanWithTopup(AccountTransferDTO accountTransferDTO) {
final boolean isAccountTransfer = true;
Loan fromLoanAccount = null;
if (accountTransferDTO.getFromLoan() == null) {
fromLoanAccount = this.loanAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId());
} else {
fromLoanAccount = accountTransferDTO.getFromLoan();
this.loanAccountAssembler.setHelpers(fromLoanAccount);
}
Loan toLoanAccount = null;
if (accountTransferDTO.getToLoan() == null) {
toLoanAccount = this.loanAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId());
} else {
toLoanAccount = accountTransferDTO.getToLoan();
this.loanAccountAssembler.setHelpers(toLoanAccount);
}
ExternalId externalIdForDisbursement = accountTransferDTO.getTxnExternalId();
LoanTransaction disburseTransaction = this.loanAccountDomainService.makeDisburseTransaction(accountTransferDTO.getFromAccountId(),
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
accountTransferDTO.getNoteText(), externalIdForDisbursement, true);
final String chargeRefundChargeType = null;
ExternalId externalIdForRepayment = externalIdFactory.create();
LoanTransaction repayTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.REPAYMENT, toLoanAccount,
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
null, externalIdForRepayment, false, chargeRefundChargeType, isAccountTransfer, null, false, true);
AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToLoanTransfer(accountTransferDTO,
fromLoanAccount, toLoanAccount, disburseTransaction, repayTransaction);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
return accountTransferDetails;
}
@Override
@Transactional
public void updateLoanTransaction(final Long loanTransactionId, final LoanTransaction newLoanTransaction) {
final AccountTransferTransaction transferTransaction = this.accountTransferRepository.findByToLoanTransactionId(loanTransactionId);
if (transferTransaction != null) {
transferTransaction.updateToLoanTransaction(newLoanTransaction);
this.accountTransferRepository.save(transferTransaction);
}
}
private boolean isLoanToSavingsAccountTransfer(final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType) {
return fromAccountType.isLoanAccount() && toAccountType.isSavingsAccount();
}
private boolean isSavingsToLoanAccountTransfer(final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType) {
return fromAccountType.isSavingsAccount() && toAccountType.isLoanAccount();
}
private boolean isSavingsToSavingsAccountTransfer(final PortfolioAccountType fromAccountType,
final PortfolioAccountType toAccountType) {
return fromAccountType.isSavingsAccount() && toAccountType.isSavingsAccount();
}
@Override
@Transactional
public CommandProcessingResult refundByTransfer(JsonCommand command) {
// TODO Auto-generated method stub
this.accountTransfersDataValidator.validate(command);
final LocalDate transactionDate = command.localDateValueOfParameterNamed(transferDateParamName);
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed(transferAmountParamName);
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
final PaymentDetail paymentDetail = null;
Long transferTransactionId = null;
final Long fromLoanAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
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 || transactionAmount.floatValue() > overpaid.floatValue()) {
if (overpaid == null) {
overpaid = BigDecimal.ZERO;
}
throw new InvalidPaidInAdvanceAmountException(overpaid.toPlainString());
}
ExternalId externalId = externalIdFactory.create();
final LoanTransaction loanRefundTransaction = this.loanAccountDomainService.makeRefundForActiveLoan(fromLoanAccountId,
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, externalId);
final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId, backdatedTxnsAllowedTill);
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate,
transactionAmount, paymentDetail, true, true, backdatedTxnsAllowedTill);
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command,
fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferTransactionId = accountTransferDetails.getId();
final CommandProcessingResultBuilder builder = new CommandProcessingResultBuilder().withEntityId(transferTransactionId);
// if (fromAccountType.isSavingsAccount()) {
builder.withSavingsId(toSavingsAccountId);
// }
return builder.build();
}
}