changes to transfer funds from overpaid account

This commit is contained in:
Pramod Nuthakki
2013-08-29 16:17:43 +05:30
parent 8286801eac
commit 82821cedec
18 changed files with 378 additions and 64 deletions
@@ -54,11 +54,13 @@ public class AccountTransferData {
final Collection<EnumOptionData> toAccountTypeOptions, final Collection<PortfolioAccountData> toAccountOptions) { final Collection<EnumOptionData> toAccountTypeOptions, final Collection<PortfolioAccountData> toAccountOptions) {
final Long id = null; final Long id = null;
CurrencyData currency = null; CurrencyData currency = null;
BigDecimal transferAmount = BigDecimal.ZERO;
if (fromAccount != null) { if (fromAccount != null) {
currency = fromAccount.currency(); currency = fromAccount.currency();
if(fromAccount.getAmtForTransfer() != null){
transferAmount = fromAccount.getAmtForTransfer();
}
} }
final BigDecimal transferAmount = BigDecimal.ZERO;
final String transferDescription = null; final String transferDescription = null;
final Boolean reversed = null; final Boolean reversed = null;
return new AccountTransferData(id, reversed, fromOffice, fromClient, fromAccountType, fromAccount, currency, transferAmount, return new AccountTransferData(id, reversed, fromOffice, fromClient, fromAccountType, fromAccount, currency, transferAmount,
@@ -5,6 +5,8 @@
*/ */
package org.mifosplatform.portfolio.account.data; package org.mifosplatform.portfolio.account.data;
import java.math.BigDecimal;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
@@ -27,9 +29,10 @@ public class PortfolioAccountData {
private final Long fieldOfficerId; private final Long fieldOfficerId;
private final String fieldOfficerName; private final String fieldOfficerName;
private final CurrencyData currency; private final CurrencyData currency;
private final BigDecimal amtForTransfer;
public static PortfolioAccountData lookup(final Long accountId, final String accountNo) { public static PortfolioAccountData lookup(final Long accountId, final String accountNo) {
return new PortfolioAccountData(accountId, accountNo, null, null, null, null, null, null, null, null, null, null); return new PortfolioAccountData(accountId, accountNo, null, null, null, null, null, null, null, null, null, null, null);
} }
public PortfolioAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName, public PortfolioAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName,
@@ -47,6 +50,25 @@ public class PortfolioAccountData {
this.fieldOfficerId = fieldofficerId; this.fieldOfficerId = fieldofficerId;
this.fieldOfficerName = fieldofficerName; this.fieldOfficerName = fieldofficerName;
this.currency = currency; this.currency = currency;
this.amtForTransfer = null;
}
public PortfolioAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName,
final Long clientId, final String clientName, final Long productId, final String productName, final Long fieldofficerId,
final String fieldofficerName, final CurrencyData currency, final BigDecimal amtForTransfer) {
this.id = id;
this.accountNo = accountNo;
this.externalId = externalId;
this.groupId = groupId;
this.groupName = groupName;
this.clientId = clientId;
this.clientName = clientName;
this.productId = productId;
this.productName = productName;
this.fieldOfficerId = fieldofficerId;
this.fieldOfficerName = fieldofficerName;
this.currency = currency;
this.amtForTransfer = amtForTransfer;
} }
@Override @Override
@@ -56,12 +78,14 @@ public class PortfolioAccountData {
if (obj == this) { return true; } if (obj == this) { return true; }
if (obj.getClass() != getClass()) { return false; } if (obj.getClass() != getClass()) { return false; }
final PortfolioAccountData rhs = (PortfolioAccountData) obj; final PortfolioAccountData rhs = (PortfolioAccountData) obj;
return new EqualsBuilder().append(this.id, rhs.id).append(this.accountNo, rhs.accountNo).append(this.productId, rhs.productId).append(this.productName, rhs.productName).isEquals(); return new EqualsBuilder().append(this.id, rhs.id).append(this.accountNo, rhs.accountNo).append(this.productId, rhs.productId)
.append(this.productName, rhs.productName).isEquals();
} }
@Override @Override
public int hashCode() { public int hashCode() {
return new HashCodeBuilder(17, 37).append(this.id).append(this.accountNo).append(this.productId).append(this.productName).toHashCode(); return new HashCodeBuilder(17, 37).append(this.id).append(this.accountNo).append(this.productId).append(this.productName)
.toHashCode();
} }
public Long clientId() { public Long clientId() {
@@ -75,4 +99,8 @@ public class PortfolioAccountData {
public String currencyCode() { public String currencyCode() {
return this.currency.code(); return this.currency.code();
} }
public BigDecimal getAmtForTransfer() {
return this.amtForTransfer;
}
} }
@@ -68,12 +68,20 @@ public class AccountTransfer extends AbstractPersistable<Long> {
@JoinColumn(name = "to_loan_account_id", nullable = true) @JoinColumn(name = "to_loan_account_id", nullable = true)
private Loan toLoanAccount; private Loan toLoanAccount;
@ManyToOne
@JoinColumn(name = "from_loan_account_id", nullable = true)
private Loan fromLoanAccount;
@ManyToOne @ManyToOne
@JoinColumn(name = "to_loan_transaction_id", nullable = true) @JoinColumn(name = "to_loan_transaction_id", nullable = true)
private LoanTransaction toLoanTransaction; private LoanTransaction toLoanTransaction;
@ManyToOne
@JoinColumn(name = "from_loan_transaction_id", nullable = true)
private LoanTransaction fromLoanTransaction;
@Column(name = "is_reversed", nullable = false) @Column(name = "is_reversed", nullable = false)
private final boolean reversed = false; private boolean reversed = false;
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "transaction_date") @Column(name = "transaction_date")
@@ -93,16 +101,23 @@ public class AccountTransfer extends AbstractPersistable<Long> {
final SavingsAccountTransaction withdrawal, final SavingsAccountTransaction deposit, final LocalDate transactionDate, final SavingsAccountTransaction withdrawal, final SavingsAccountTransaction deposit, final LocalDate transactionDate,
final Money transactionAmount, final String description) { final Money transactionAmount, final String description) {
return new AccountTransfer(fromOffice, fromClient, fromSavingsAccount, toOffice, toClient, toSavingsAccount, null, withdrawal, return new AccountTransfer(fromOffice, fromClient, fromSavingsAccount, null, toOffice, toClient, toSavingsAccount, null,
deposit, null, transactionDate, transactionAmount, description); withdrawal, deposit, null, null, transactionDate, transactionAmount, description);
} }
public static AccountTransfer savingsToLoanTransfer(final Office fromOffice, final Client fromClient, public static AccountTransfer savingsToLoanTransfer(final Office fromOffice, final Client fromClient,
final SavingsAccount fromSavingsAccount, final Office toOffice, final Client toClient, final Loan toLoanAccount, final SavingsAccount fromSavingsAccount, final Office toOffice, final Client toClient, final Loan toLoanAccount,
final SavingsAccountTransaction withdrawal, final LoanTransaction loanRepaymentTransaction, final LocalDate transactionDate, final SavingsAccountTransaction withdrawal, final LoanTransaction loanRepaymentTransaction, final LocalDate transactionDate,
final Money transactionAmount, final String description) { final Money transactionAmount, final String description) {
return new AccountTransfer(fromOffice, fromClient, fromSavingsAccount, toOffice, toClient, null, toLoanAccount, withdrawal, null, return new AccountTransfer(fromOffice, fromClient, fromSavingsAccount, null, toOffice, toClient, null, toLoanAccount, withdrawal,
loanRepaymentTransaction, transactionDate, transactionAmount, description); null, loanRepaymentTransaction, null, transactionDate, transactionAmount, description);
}
public static AccountTransfer LoanTosavingsTransfer(final Office fromOffice, final Client fromClient, final Loan fromLoanAccount,
final Office toOffice, final Client toClient, final SavingsAccount toSavingsAccount, final SavingsAccountTransaction deposit,
final LoanTransaction loanRefundTransaction, final LocalDate transactionDate, final Money transactionAmount, final String description) {
return new AccountTransfer(fromOffice, fromClient, null, fromLoanAccount, toOffice, toClient, toSavingsAccount, null, null,
deposit, null, loanRefundTransaction, transactionDate, transactionAmount, description);
} }
protected AccountTransfer() { protected AccountTransfer() {
@@ -110,13 +125,15 @@ public class AccountTransfer extends AbstractPersistable<Long> {
} }
private AccountTransfer(final Office fromOffice, final Client fromClient, final SavingsAccount fromSavingsAccount, private AccountTransfer(final Office fromOffice, final Client fromClient, final SavingsAccount fromSavingsAccount,
final Office toOffice, final Client toClient, final SavingsAccount toSavingsAccount, final Loan toLoanAccount, final Loan fromLoanAccount, final Office toOffice, final Client toClient, final SavingsAccount toSavingsAccount,
final SavingsAccountTransaction withdrawal, final SavingsAccountTransaction deposit, final Loan toLoanAccount, final SavingsAccountTransaction withdrawal, final SavingsAccountTransaction deposit,
final LoanTransaction loanRepaymentTransaction, final LocalDate transactionDate, final Money transactionAmount, final LoanTransaction loanRepaymentTransaction, LoanTransaction loanRefundTransaction, final LocalDate transactionDate,
final String description) { final Money transactionAmount, final String description) {
this.fromOffice = fromOffice; this.fromOffice = fromOffice;
this.fromClient = fromClient; this.fromClient = fromClient;
this.fromAccount = fromSavingsAccount; this.fromAccount = fromSavingsAccount;
this.fromLoanAccount = fromLoanAccount;
this.fromLoanTransaction = loanRefundTransaction;
this.toOffice = toOffice; this.toOffice = toOffice;
this.toClient = toClient; this.toClient = toClient;
this.toSavingsAccount = toSavingsAccount; this.toSavingsAccount = toSavingsAccount;
@@ -129,4 +146,38 @@ public class AccountTransfer extends AbstractPersistable<Long> {
this.amount = transactionAmount.getAmountDefaultedToNullIfZero(); this.amount = transactionAmount.getAmountDefaultedToNullIfZero();
this.description = description; this.description = description;
} }
public LoanTransaction getFromLoanTransaction() {
return this.fromLoanTransaction;
}
public SavingsAccountTransaction getFromTransaction() {
return this.fromTransaction;
}
public LoanTransaction getToLoanTransaction() {
return this.toLoanTransaction;
}
public SavingsAccountTransaction getToSavingsTransaction() {
return this.toSavingsTransaction;
}
public void reverse() {
this.reversed = true;
}
public SavingsAccount getToSavingsAccount() {
return this.toSavingsAccount;
}
public SavingsAccount getFromAccount() {
return this.fromAccount;
}
} }
@@ -111,4 +111,32 @@ public class AccountTransferAssembler {
return AccountTransfer.savingsToLoanTransfer(fromOffice, fromClient, fromSavingsAccount, toOffice, toClient, toLoanAccount, return AccountTransfer.savingsToLoanTransfer(fromOffice, fromClient, fromSavingsAccount, toOffice, toClient, toLoanAccount,
withdrawal, loanRepaymentTransaction, transactionDate, transactionMonetaryAmount, description); withdrawal, loanRepaymentTransaction, transactionDate, transactionMonetaryAmount, description);
} }
public AccountTransfer assembleLoanToSavingsTransfer(final JsonCommand command, final Loan fromLoanAccount,
final SavingsAccount toSavingsAccount, final SavingsAccountTransaction deposit, final LoanTransaction loanRefundTransaction) {
final JsonElement element = command.parsedJson();
final Long fromOfficeId = this.fromApiJsonHelper.extractLongNamed(fromOfficeIdParamName, element);
final Office fromOffice = this.officeRepository.findOne(fromOfficeId);
final Long fromClientId = this.fromApiJsonHelper.extractLongNamed(fromClientIdParamName, element);
final Client fromClient = this.clientRepository.findOneWithNotFoundDetection(fromClientId);
final Long toOfficeId = this.fromApiJsonHelper.extractLongNamed(toOfficeIdParamName, element);
final Office toOffice = this.officeRepository.findOne(toOfficeId);
final Long toClientId = this.fromApiJsonHelper.extractLongNamed(toClientIdParamName, element);
final Client toClient = this.clientRepository.findOneWithNotFoundDetection(toClientId);
final LocalDate transactionDate = command.localDateValueOfParameterNamed(transferDateParamName);
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed(transferAmountParamName);
final Money transactionMonetaryAmount = Money.of(toSavingsAccount.getCurrency(), transactionAmount);
final String description = command.stringValueOfParameterNamed(transferDescriptionParamName);
return AccountTransfer.LoanTosavingsTransfer(fromOffice, fromClient, fromLoanAccount, toOffice, toClient, toSavingsAccount,
deposit, loanRefundTransaction, transactionDate, transactionMonetaryAmount, description);
}
} }
@@ -5,9 +5,15 @@
*/ */
package org.mifosplatform.portfolio.account.domain; package org.mifosplatform.portfolio.account.domain;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface AccountTransferRepository extends JpaRepository<AccountTransfer, Long>, JpaSpecificationExecutor<AccountTransfer> { public interface AccountTransferRepository extends JpaRepository<AccountTransfer, Long>, JpaSpecificationExecutor<AccountTransfer> {
@Query("from AccountTransfer at where at.fromLoanAccount.id= :accountNumber and at.reversed=false")
List<AccountTransfer> findByLoanId(@Param("accountNumber") Long accountNumber);
} }
@@ -13,7 +13,6 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.commands.exception.UnsupportedCommandException;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
@@ -70,23 +69,20 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
final EnumOptionData loanAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN); final EnumOptionData loanAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN);
final EnumOptionData savingsAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS); final EnumOptionData savingsAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS);
final Collection<EnumOptionData> fromAccountTypeOptions = Arrays.asList(savingsAccountType);
final Collection<EnumOptionData> toAccountTypeOptions = Arrays.asList(loanAccountType, savingsAccountType);
// TODO - remove this after doing overpaid loan to savings transfers
Integer mostRelevantFromAccountType = fromAccountType; Integer mostRelevantFromAccountType = fromAccountType;
if (mostRelevantFromAccountType == null) { final Collection<EnumOptionData> fromAccountTypeOptions = Arrays.asList(savingsAccountType, loanAccountType);
mostRelevantFromAccountType = 2; // savings final Collection<EnumOptionData> toAccountTypeOptions;
if (mostRelevantFromAccountType == 1) {
// overpaid loan amt transfer to savings account
toAccountTypeOptions = Arrays.asList(savingsAccountType);
} else {
toAccountTypeOptions = Arrays.asList(loanAccountType, savingsAccountType);
} }
final Integer mostRelevantToAccountType = toAccountType; final Integer mostRelevantToAccountType = toAccountType;
final EnumOptionData fromAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantFromAccountType); final EnumOptionData fromAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantFromAccountType);
final EnumOptionData toAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantToAccountType); final EnumOptionData toAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantToAccountType);
// check for now that only savings account type is passed and used.
if (mostRelevantFromAccountType != 2) { throw new UnsupportedCommandException("transferFromLoanAccountNotSupported"); }
// from settings // from settings
OfficeData fromOffice = null; OfficeData fromOffice = null;
ClientData fromClient = null; ClientData fromClient = null;
@@ -106,21 +102,28 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
Long mostRelevantToOfficeId = toOfficeId; Long mostRelevantToOfficeId = toOfficeId;
Long mostRelevantToClientId = toClientId; Long mostRelevantToClientId = toClientId;
if (fromAccountId != null && mostRelevantFromAccountType == 2) { if (fromAccountId != null) {
fromAccount = this.portfolioAccountReadPlatformService.retrieveOne(fromAccountId, PortfolioAccountType.SAVINGS.getValue()); Integer accountType;
if (mostRelevantFromAccountType == 1) {
accountType = PortfolioAccountType.LOAN.getValue();
} else {
accountType = PortfolioAccountType.SAVINGS.getValue();
}
fromAccount = this.portfolioAccountReadPlatformService.retrieveOne(fromAccountId, accountType);
// override provided fromClient with client of account // override provided fromClient with client of account
mostRelevantFromClientId = fromAccount.clientId(); mostRelevantFromClientId = fromAccount.clientId();
} else if (fromAccountId != null && mostRelevantFromAccountType == 1) { // loans
// fetch loan account
} }
if (mostRelevantFromClientId != null) { if (mostRelevantFromClientId != null) {
fromClient = this.clientReadPlatformService.retrieveOne(mostRelevantFromClientId); fromClient = this.clientReadPlatformService.retrieveOne(mostRelevantFromClientId);
mostRelevantFromOfficeId = fromClient.officeId(); mostRelevantFromOfficeId = fromClient.officeId();
long[] loanStatus = null;
if (mostRelevantFromAccountType == 1) {
loanStatus = new long[] { 300, 700 };
}
fromAccountOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(mostRelevantFromAccountType, fromAccountOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(mostRelevantFromAccountType,
mostRelevantFromClientId); mostRelevantFromClientId, loanStatus);
} }
Collection<OfficeData> fromOfficeOptions = null; Collection<OfficeData> fromOfficeOptions = null;
@@ -137,7 +140,8 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
Collection<ClientData> toClientOptions = null; Collection<ClientData> toClientOptions = null;
if (toAccountId != null && fromAccount != null) { if (toAccountId != null && fromAccount != null) {
toAccount = this.portfolioAccountReadPlatformService.retrieveOne(toAccountId, mostRelevantToAccountType, fromAccount.currencyCode()); toAccount = this.portfolioAccountReadPlatformService.retrieveOne(toAccountId, mostRelevantToAccountType,
fromAccount.currencyCode());
mostRelevantToClientId = toAccount.clientId(); mostRelevantToClientId = toAccount.clientId();
} }
@@ -173,7 +177,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
final String currencyCode = excludeThisAccountFromOptions != null ? excludeThisAccountFromOptions.currencyCode() : null; final String currencyCode = excludeThisAccountFromOptions != null ? excludeThisAccountFromOptions.currencyCode() : null;
Collection<PortfolioAccountData> accountOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(toAccountType, Collection<PortfolioAccountData> accountOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(toAccountType,
toClientId, currencyCode); toClientId, currencyCode, null);
if (!CollectionUtils.isEmpty(accountOptions)) { if (!CollectionUtils.isEmpty(accountOptions)) {
accountOptions.remove(excludeThisAccountFromOptions); accountOptions.remove(excludeThisAccountFromOptions);
} else { } else {
@@ -7,8 +7,11 @@ package org.mifosplatform.portfolio.account.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.account.PortfolioAccountType;
public interface AccountTransfersWritePlatformService { public interface AccountTransfersWritePlatformService {
CommandProcessingResult create(JsonCommand command); CommandProcessingResult create(JsonCommand command);
void reverseTransfers(Long accountNumber, PortfolioAccountType accountTypeId);
} }
@@ -13,6 +13,7 @@ import static org.mifosplatform.portfolio.account.AccountTransfersApiConstants.t
import static org.mifosplatform.portfolio.account.AccountTransfersApiConstants.transferDateParamName; import static org.mifosplatform.portfolio.account.AccountTransfersApiConstants.transferDateParamName;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@@ -35,6 +36,7 @@ import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler; import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountDomainService; import org.mifosplatform.portfolio.savings.domain.SavingsAccountDomainService;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction; import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -49,12 +51,14 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
private final SavingsAccountDomainService savingsAccountDomainService; private final SavingsAccountDomainService savingsAccountDomainService;
private final LoanAssembler loanAccountAssembler; private final LoanAssembler loanAccountAssembler;
private final LoanAccountDomainService loanAccountDomainService; private final LoanAccountDomainService loanAccountDomainService;
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
@Autowired @Autowired
public AccountTransfersWritePlatformServiceImpl(final AccountTransfersDataValidator accountTransfersDataValidator, public AccountTransfersWritePlatformServiceImpl(final AccountTransfersDataValidator accountTransfersDataValidator,
final AccountTransferAssembler accountTransferAssembler, final AccountTransferRepository accountTransferRepository, final AccountTransferAssembler accountTransferAssembler, final AccountTransferRepository accountTransferRepository,
final SavingsAccountAssembler savingsAccountAssembler, final SavingsAccountDomainService savingsAccountDomainService, final SavingsAccountAssembler savingsAccountAssembler, final SavingsAccountDomainService savingsAccountDomainService,
final LoanAssembler loanAssembler, final LoanAccountDomainService loanAccountDomainService) { final LoanAssembler loanAssembler, final LoanAccountDomainService loanAccountDomainService,
final SavingsAccountWritePlatformService savingsAccountWritePlatformService) {
this.accountTransfersDataValidator = accountTransfersDataValidator; this.accountTransfersDataValidator = accountTransfersDataValidator;
this.accountTransferAssembler = accountTransferAssembler; this.accountTransferAssembler = accountTransferAssembler;
this.accountTransferRepository = accountTransferRepository; this.accountTransferRepository = accountTransferRepository;
@@ -62,6 +66,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
this.savingsAccountDomainService = savingsAccountDomainService; this.savingsAccountDomainService = savingsAccountDomainService;
this.loanAccountAssembler = loanAssembler; this.loanAccountAssembler = loanAssembler;
this.loanAccountDomainService = loanAccountDomainService; this.loanAccountDomainService = loanAccountDomainService;
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
} }
@Transactional @Transactional
@@ -124,7 +129,27 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
transferTransactionId = transferTransaction.getId(); transferTransactionId = transferTransaction.getId();
} else if (isLoanToSavingsAccountTransfer(fromAccountType, toAccountType)) { } else if (isLoanToSavingsAccountTransfer(fromAccountType, toAccountType)) {
// FIXME - kw - ADD overpaid loan to savings account transfer support. // FIXME - kw - ADD overpaid loan to savings account transfer
// support.
//
final Long fromLoanAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
final Loan fromLoanAccount = this.loanAccountAssembler.assembleFrom(fromLoanAccountId);
final LoanTransaction loanRefundTransaction = this.loanAccountDomainService.makeRefund(fromLoanAccountId,
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null);
final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId);
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt,
transactionDate, transactionAmount, paymentDetail);
final AccountTransfer transferTransaction = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command,
fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction);
this.accountTransferRepository.saveAndFlush(transferTransaction);
transferTransactionId = transferTransaction.getId();
} else { } else {
} }
@@ -139,6 +164,25 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
return builder.build(); return builder.build();
} }
@Override
@Transactional
public void reverseTransfers(Long accountNumber, PortfolioAccountType accountTypeId) {
List<AccountTransfer> acccountTransfers = null;
if (accountTypeId.isLoanAccount()) {
acccountTransfers = this.accountTransferRepository.findByLoanId(accountNumber);
}
if (acccountTransfers != null && acccountTransfers.size() > 0) {
for (AccountTransfer accountTransfer : acccountTransfers) {
this.loanAccountDomainService.reverseTransfer(accountTransfer.getFromLoanTransaction());
this.savingsAccountWritePlatformService.undoTransaction(accountTransfer.getToSavingsAccount().getId(), accountTransfer
.getToSavingsTransaction().getId());
accountTransfer.reverse();
this.accountTransferRepository.save(accountTransfer);
}
}
}
private boolean isLoanToSavingsAccountTransfer(final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType) { private boolean isLoanToSavingsAccountTransfer(final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType) {
return fromAccountType.isLoanAccount() && toAccountType.isSavingsAccount(); return fromAccountType.isLoanAccount() && toAccountType.isSavingsAccount();
} }
@@ -15,7 +15,7 @@ public interface PortfolioAccountReadPlatformService {
PortfolioAccountData retrieveOne(Long accountId, Integer accountTypeId, String currencyCode); PortfolioAccountData retrieveOne(Long accountId, Integer accountTypeId, String currencyCode);
Collection<PortfolioAccountData> retrieveAllForLookup(Integer toAccountType, Long toClientId); Collection<PortfolioAccountData> retrieveAllForLookup(Integer toAccountType, Long toClientId, long[] accountStatus);
Collection<PortfolioAccountData> retrieveAllForLookup(Integer toAccountType, Long toClientId, String currencyCode); Collection<PortfolioAccountData> retrieveAllForLookup(Integer toAccountType, Long toClientId, String currencyCode, long[] accountStatus);
} }
@@ -5,6 +5,7 @@
*/ */
package org.mifosplatform.portfolio.account.service; package org.mifosplatform.portfolio.account.service;
import java.math.BigDecimal;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
@@ -45,24 +46,24 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
@Override @Override
public PortfolioAccountData retrieveOne(final Long accountId, final Integer accountTypeId, final String currencyCode) { public PortfolioAccountData retrieveOne(final Long accountId, final Integer accountTypeId, final String currencyCode) {
Object[] sqlParams = new Object[] {accountId}; Object[] sqlParams = new Object[] { accountId };
PortfolioAccountData accountData = null; PortfolioAccountData accountData = null;
try { try {
String sql = null; String sql = null;
final PortfolioAccountType accountType = PortfolioAccountType.fromInt(accountTypeId); final PortfolioAccountType accountType = PortfolioAccountType.fromInt(accountTypeId);
switch (accountType) { switch (accountType) {
case INVALID: case INVALID:
break; break;
case LOAN: case LOAN:
sql = "select " + this.loanAccountMapper.schema() + " where la.id = ?"; sql = "select " + this.loanAccountMapper.schema() + " where la.id = ?";
if (currencyCode != null) { if (currencyCode != null) {
sql += " and la.currency_code = ?"; sql += " and la.currency_code = ?";
sqlParams = new Object[] {accountId, currencyCode}; sqlParams = new Object[] { accountId, currencyCode };
} }
accountData = this.jdbcTemplate.queryForObject(sql, this.savingsAccountMapper, sqlParams); accountData = this.jdbcTemplate.queryForObject(sql, this.loanAccountMapper, sqlParams);
break; break;
case SAVINGS: case SAVINGS:
sql = "select " + this.savingsAccountMapper.schema() + " where sa.id = ?"; sql = "select " + this.savingsAccountMapper.schema() + " where sa.id = ?";
if (currencyCode != null) { if (currencyCode != null) {
@@ -71,9 +72,9 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
} }
accountData = this.jdbcTemplate.queryForObject(sql, this.savingsAccountMapper, sqlParams); accountData = this.jdbcTemplate.queryForObject(sql, this.savingsAccountMapper, sqlParams);
break; break;
default: default:
break; break;
} }
} catch (final EmptyResultDataAccessException e) { } catch (final EmptyResultDataAccessException e) {
throw new AccountTransferNotFoundException(accountId); throw new AccountTransferNotFoundException(accountId);
@@ -83,40 +84,50 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
} }
@Override @Override
public Collection<PortfolioAccountData> retrieveAllForLookup(final Integer accountTypeId, final Long clientId) { public Collection<PortfolioAccountData> retrieveAllForLookup(final Integer accountTypeId, final Long clientId, long[] accountStatus) {
return retrieveAllForLookup(accountTypeId, clientId, null); return retrieveAllForLookup(accountTypeId, clientId, null, accountStatus);
} }
@Override @Override
public Collection<PortfolioAccountData> retrieveAllForLookup(final Integer accountTypeId, final Long clientId, final String currencyCode) { public Collection<PortfolioAccountData> retrieveAllForLookup(final Integer accountTypeId, final Long clientId,
final String currencyCode, long[] accountStatus) {
Object[] sqlParams = new Object[] {clientId}; Object[] sqlParams = new Object[] { clientId };
Collection<PortfolioAccountData> accounts = null; Collection<PortfolioAccountData> accounts = null;
String sql = null; String sql = null;
String defaultAccountStatus = "300";
if (accountStatus != null) {
for (long status : accountStatus) {
defaultAccountStatus += ", " + status;
}
defaultAccountStatus = defaultAccountStatus.substring(defaultAccountStatus.indexOf(",")+1);
}
final PortfolioAccountType accountType = PortfolioAccountType.fromInt(accountTypeId); final PortfolioAccountType accountType = PortfolioAccountType.fromInt(accountTypeId);
switch (accountType) { switch (accountType) {
case INVALID: case INVALID:
break; break;
case LOAN: case LOAN:
sql = "select " + this.loanAccountMapper.schema() + " where la.client_id = ? and la.loan_status_id = 300"; sql = "select " + this.loanAccountMapper.schema() + " where la.client_id = ? and la.loan_status_id in ("
+ defaultAccountStatus.toString() + ")";
if (currencyCode != null) { if (currencyCode != null) {
sql += " and la.currency_code = ?"; sql += " and la.currency_code = ?";
sqlParams = new Object[] {clientId, currencyCode}; sqlParams = new Object[] { clientId, currencyCode };
} }
accounts = this.jdbcTemplate.query(sql, this.loanAccountMapper, sqlParams); accounts = this.jdbcTemplate.query(sql, this.loanAccountMapper, sqlParams);
break; break;
case SAVINGS: case SAVINGS:
sql = "select " + this.savingsAccountMapper.schema() + " where sa.client_id = ? and sa.status_enum = 300"; sql = "select " + this.savingsAccountMapper.schema() + " where sa.client_id = ? and sa.status_enum in ("
+ defaultAccountStatus.toString() + ")";
if (currencyCode != null) { if (currencyCode != null) {
sql += " and sa.currency_code = ?"; sql += " and sa.currency_code = ?";
sqlParams = new Object[] {clientId, currencyCode}; sqlParams = new Object[] { clientId, currencyCode };
} }
accounts = this.jdbcTemplate.query(sql, this.savingsAccountMapper, sqlParams); accounts = this.jdbcTemplate.query(sql, this.savingsAccountMapper, sqlParams);
break; break;
default: default:
break; break;
} }
return accounts; return accounts;
@@ -198,6 +209,7 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
sqlBuilder.append("s.id as fieldOfficerId, s.display_name as fieldOfficerName, "); sqlBuilder.append("s.id as fieldOfficerId, s.display_name as fieldOfficerName, ");
sqlBuilder.append("la.currency_code as currencyCode, la.currency_digits as currencyDigits,"); sqlBuilder.append("la.currency_code as currencyCode, la.currency_digits as currencyDigits,");
sqlBuilder.append("la.currency_multiplesof as inMultiplesOf, "); sqlBuilder.append("la.currency_multiplesof as inMultiplesOf, ");
sqlBuilder.append("la.total_overpaid_derived as totalOverpaid, ");
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol "); sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol ");
sqlBuilder.append("from m_loan la "); sqlBuilder.append("from m_loan la ");
@@ -238,11 +250,12 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol"); final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits"); final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final Integer inMulitplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf"); final Integer inMulitplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
final BigDecimal amtForTransfer = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalOverpaid");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMulitplesOf, final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMulitplesOf,
currencyDisplaySymbol, currencyNameCode); currencyDisplaySymbol, currencyNameCode);
return new PortfolioAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, return new PortfolioAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
fieldOfficerId, fieldOfficerName, currency); fieldOfficerId, fieldOfficerName, currency, amtForTransfer);
} }
} }
} }
@@ -1528,6 +1528,42 @@ public class Loan extends AbstractPersistable<Long> {
return changedTransactionDetail; return changedTransactionDetail;
} }
public void makeRefund(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final WorkingDays workingDays,
final boolean allowTransactionsOnNonWorkingDay) {
validateRepaymentDateIsOnHoliday(loanTransaction.getTransactionDate(), allowTransactionsOnHoliday, holidays);
validateRepaymentDateIsOnNonWorkingDay(loanTransaction.getTransactionDate(), workingDays, allowTransactionsOnNonWorkingDay);
existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
if (status().isOverpaid()) {
if (this.totalOverpaid.compareTo(loanTransaction.getAmount(getCurrency()).getAmount()) == -1) {
final String errorMessage = "The refund amount must be less than or equal to overpaid amount ";
throw new InvalidLoanStateTransitionException("transaction", "is.exceeding.overpaid.amount", errorMessage, totalOverpaid,
loanTransaction.getAmount(getCurrency()).getAmount());
} else if (!isAfterLatRepayment(loanTransaction, loanTransactions)) {
final String errorMessage = "Transfer funds is allowed only after last repayment date";
throw new InvalidLoanStateTransitionException("transaction", "is.not.after.repayment.date", errorMessage);
}
} else {
final String errorMessage = "Transfer funds is allowed only for loan accounts with overpaid status ";
throw new InvalidLoanStateTransitionException("transaction", "is.not.a.overpaid.loan", errorMessage);
}
this.totalOverpaid = this.totalOverpaid.subtract(loanTransaction.getAmount(getCurrency()).getAmount());
if (this.totalOverpaid.compareTo(BigDecimal.ZERO) == 0) {
handleLoanRepaymentInFull(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
}
loanTransaction.updateLoan(this);
if (loanTransaction.isNotZero(loanCurrency())) {
this.loanTransactions.add(loanTransaction);
}
}
private ChangedTransactionDetail handleRepaymentOrWaiverTransaction(final LoanTransaction loanTransaction, private ChangedTransactionDetail handleRepaymentOrWaiverTransaction(final LoanTransaction loanTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction) { final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction) {
@@ -1656,6 +1692,22 @@ public class Loan extends AbstractPersistable<Long> {
return isChronologicallyLatestRepaymentOrWaiver; return isChronologicallyLatestRepaymentOrWaiver;
} }
private boolean isAfterLatRepayment(final LoanTransaction loanTransaction, final List<LoanTransaction> loanTransactions) {
boolean isAfterLatRepayment = true;
final LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
for (final LoanTransaction previousTransaction : loanTransactions) {
if (previousTransaction.isRepayment() && previousTransaction.isNotReversed()) {
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
isAfterLatRepayment = false;
break;
}
}
}
return isAfterLatRepayment;
}
private boolean isChronologicallyLatestTransaction(final LoanTransaction loanTransaction, final List<LoanTransaction> loanTransactions) { private boolean isChronologicallyLatestTransaction(final LoanTransaction loanTransaction, final List<LoanTransaction> loanTransactions) {
boolean isChronologicallyLatestRepaymentOrWaiver = true; boolean isChronologicallyLatestRepaymentOrWaiver = true;
@@ -1794,7 +1846,7 @@ public class Loan extends AbstractPersistable<Long> {
private Money calculateTotalOverpayment() { private Money calculateTotalOverpayment() {
final Money totalPaidInRepayments = getTotalPaidInRepayments(); Money totalPaidInRepayments = getTotalPaidInRepayments();
final MonetaryCurrency currency = loanCurrency(); final MonetaryCurrency currency = loanCurrency();
Money cumulativeTotalPaidOnInstallments = Money.zero(currency); Money cumulativeTotalPaidOnInstallments = Money.zero(currency);
@@ -1809,6 +1861,12 @@ public class Loan extends AbstractPersistable<Long> {
cumulativeTotalWaivedOnInstallments = cumulativeTotalWaivedOnInstallments.plus(scheduledRepayment.getInterestWaived(currency)); cumulativeTotalWaivedOnInstallments = cumulativeTotalWaivedOnInstallments.plus(scheduledRepayment.getInterestWaived(currency));
} }
for (LoanTransaction loanTransaction : this.loanTransactions) {
if (loanTransaction.isRefund() && !loanTransaction.isReversed()) {
totalPaidInRepayments = totalPaidInRepayments.minus(loanTransaction.getAmount(currency));
}
}
// if total paid in transactions doesnt match repayment schedule then // if total paid in transactions doesnt match repayment schedule then
// theres an overpayment. // theres an overpayment.
return totalPaidInRepayments.minus(cumulativeTotalPaidOnInstallments); return totalPaidInRepayments.minus(cumulativeTotalPaidOnInstallments);
@@ -15,4 +15,9 @@ public interface LoanAccountDomainService {
LoanTransaction makeRepayment(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate, LoanTransaction makeRepayment(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId); BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId);
LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId);
void reverseTransfer(LoanTransaction loanTransaction);
} }
@@ -163,4 +163,49 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
if (group.isNotActive()) { throw new GroupNotActiveException(group.getId()); } if (group.isNotActive()) { throw new GroupNotActiveException(group.getId()); }
} }
} }
@Override
public LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId) {
final Loan loan = this.loanAccountAssembler.assembleFrom(accountId);
checkClientOrGroupActive(loan);
final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final Money refundAmount = Money.of(loan.getCurrency(), transactionAmount);
final LoanTransaction newRefundTransaction = LoanTransaction.refund(loan.getOffice(), refundAmount, paymentDetail, transactionDate,
txnExternalId);
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
final List<Holiday> holidays = this.holidayRepository
.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate.toDate());
final WorkingDays workingDays = this.workingDaysRepository.findOne();
final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
loan.makeRefund(newRefundTransaction, defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds,
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
this.loanTransactionRepository.save(newRefundTransaction);
this.loanRepository.save(loan);
if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.loanTransactionNote(loan, newRefundTransaction, noteText);
this.noteRepository.save(note);
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
builderResult.withEntityId(newRefundTransaction.getId()) //
.withOfficeId(loan.getOfficeId()) //
.withClientId(loan.getClientId()) //
.withGroupId(loan.getGroupId()); //
return newRefundTransaction;
}
@Override
public void reverseTransfer(LoanTransaction loanTransaction) {
loanTransaction.reverse();
this.loanTransactionRepository.save(loanTransaction);
}
} }
@@ -135,4 +135,8 @@ public enum LoanStatus {
public boolean isUnderTransfer() { public boolean isUnderTransfer() {
return isTransferInProgress() || isTransferOnHold(); return isTransferInProgress() || isTransferOnHold();
} }
public boolean isOverpaid(){
return this.value.equals(LoanStatus.OVERPAID.getValue());
}
} }
@@ -137,6 +137,11 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
.getTotalPenaltyChargesOutstanding(), false, null); .getTotalPenaltyChargesOutstanding(), false, null);
} }
public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final String externalId) {
return new LoanTransaction(null, office, LoanTransactionType.REFUND, paymentDetail, amount.getAmount(), paymentDate, externalId);
}
public static LoanTransaction copyTransactionProperties(LoanTransaction loanTransaction) { public static LoanTransaction copyTransactionProperties(LoanTransaction loanTransaction) {
return new LoanTransaction(loanTransaction.loan, loanTransaction.office, loanTransaction.typeOf, loanTransaction.dateOf, return new LoanTransaction(loanTransaction.loan, loanTransaction.office, loanTransaction.typeOf, loanTransaction.dateOf,
loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion, loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion,
@@ -447,4 +452,8 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
return externalId; return externalId;
} }
public boolean isRefund(){
return LoanTransactionType.REFUND.equals(getTypeOf()) && isNotReversed();
}
} }
@@ -32,7 +32,9 @@ public enum LoanTransactionType {
INITIATE_TRANSFER(12, "loanTransactionType.initiateTransfer"), // INITIATE_TRANSFER(12, "loanTransactionType.initiateTransfer"), //
APPROVE_TRANSFER(13, "loanTransactionType.approveTransfer"), // APPROVE_TRANSFER(13, "loanTransactionType.approveTransfer"), //
WITHDRAW_TRANSFER(14, "loanTransactionType.withdrawTransfer"), // WITHDRAW_TRANSFER(14, "loanTransactionType.withdrawTransfer"), //
REJECT_TRANSFER(15, "loanTransactionType.rejectTransfer"); REJECT_TRANSFER(15, "loanTransactionType.rejectTransfer"),
REFUND(16,"loanTransactionType.refund");
private final Integer value; private final Integer value;
private final String code; private final String code;
@@ -101,6 +103,9 @@ public enum LoanTransactionType {
case 15: case 15:
loanTransactionType = LoanTransactionType.REJECT_TRANSFER; loanTransactionType = LoanTransactionType.REJECT_TRANSFER;
break; break;
case 16:
loanTransactionType = LoanTransactionType.REFUND;
break;
default: default:
loanTransactionType = LoanTransactionType.INVALID; loanTransactionType = LoanTransactionType.INVALID;
break; break;
@@ -34,6 +34,8 @@ import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays; import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.mifosplatform.portfolio.account.PortfolioAccountType;
import org.mifosplatform.portfolio.account.service.AccountTransfersWritePlatformService;
import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
import org.mifosplatform.portfolio.calendar.domain.Calendar; import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType; import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
@@ -113,6 +115,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final ConfigurationDomainService configurationDomainService; private final ConfigurationDomainService configurationDomainService;
private final WorkingDaysRepositoryWrapper workingDaysRepository; private final WorkingDaysRepositoryWrapper workingDaysRepository;
private final LoanProductReadPlatformService loanProductReadPlatformService; private final LoanProductReadPlatformService loanProductReadPlatformService;
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
@Autowired @Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -126,7 +129,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository, final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository,
final PaymentDetailWritePlatformService paymentDetailWritePlatformService, final HolidayRepository holidayRepository, final PaymentDetailWritePlatformService paymentDetailWritePlatformService, final HolidayRepository holidayRepository,
final ConfigurationDomainService configurationDomainService, final WorkingDaysRepositoryWrapper workingDaysRepository, final ConfigurationDomainService configurationDomainService, final WorkingDaysRepositoryWrapper workingDaysRepository,
final LoanProductReadPlatformService loanProductReadPlatformService) { final LoanProductReadPlatformService loanProductReadPlatformService,
final AccountTransfersWritePlatformService accountTransfersWritePlatformService) {
this.context = context; this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator; this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler; this.loanAssembler = loanAssembler;
@@ -146,6 +150,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.workingDaysRepository = workingDaysRepository; this.workingDaysRepository = workingDaysRepository;
this.loanProductReadPlatformService = loanProductReadPlatformService; this.loanProductReadPlatformService = loanProductReadPlatformService;
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
} }
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -477,7 +482,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
this.loanRepository.save(loan); this.loanRepository.save(loan);
final String noteText = command.stringValueOfParameterNamed("note"); final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) { if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText); changes.put("note", noteText);
@@ -493,6 +497,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
this.noteRepository.save(note); this.noteRepository.save(note);
} }
this.accountTransfersWritePlatformService.reverseTransfers(loanId, PortfolioAccountType.LOAN);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
@@ -298,6 +298,10 @@ public class LoanEnumerations {
optionData = new LoanTransactionEnumData(LoanTransactionType.REJECT_TRANSFER.getValue().longValue(), optionData = new LoanTransactionEnumData(LoanTransactionType.REJECT_TRANSFER.getValue().longValue(),
LoanTransactionType.REJECT_TRANSFER.getCode(), "Transfer Rejected"); LoanTransactionType.REJECT_TRANSFER.getCode(), "Transfer Rejected");
break; break;
case REFUND:
optionData = new LoanTransactionEnumData(LoanTransactionType.REFUND.getValue().longValue(),
LoanTransactionType.REFUND.getCode(), "Transfer Refund");
break;
default: default:
break; break;
} }