MIFOSX-1641: Added capture of guarantee details for loan product and added constrain on savings withdraw
This commit is contained in:
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.account.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representation of loan status states.
|
||||||
|
*/
|
||||||
|
public enum AccountAssociationType {
|
||||||
|
|
||||||
|
INVALID(0, "accountAssociationType.invalid"), //
|
||||||
|
LINKED_ACCOUNT_ASSOCIATION(1, "accountAssociationType.loan.account.association"), //
|
||||||
|
GUARANTOR_ACCOUNT_ASSOCIATION(2, "accountAssociationType.guarantor.account.association"); //
|
||||||
|
|
||||||
|
private final Integer value;
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
public static AccountAssociationType fromInt(final Integer statusValue) {
|
||||||
|
|
||||||
|
AccountAssociationType enumeration = AccountAssociationType.INVALID;
|
||||||
|
switch (statusValue) {
|
||||||
|
case 1:
|
||||||
|
enumeration = AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
enumeration = AccountAssociationType.GUARANTOR_ACCOUNT_ASSOCIATION;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return enumeration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AccountAssociationType(final Integer value, final String code) {
|
||||||
|
this.value = value;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStateOf(final AccountAssociationType state) {
|
||||||
|
return this.value.equals(state.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLinkedAccountAssociation() {
|
||||||
|
return this.value.equals(AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGuarantorAccountAssociation() {
|
||||||
|
return this.value.equals(AccountAssociationType.GUARANTOR_ACCOUNT_ASSOCIATION.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+16
-5
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.account.domain;
|
package org.mifosplatform.portfolio.account.domain;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
@@ -18,14 +19,17 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
|||||||
@Table(name = "m_portfolio_account_associations")
|
@Table(name = "m_portfolio_account_associations")
|
||||||
public class AccountAssociations extends AbstractPersistable<Long> {
|
public class AccountAssociations extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "loan_account_id", nullable = true)
|
@JoinColumn(name = "loan_account_id", nullable = true)
|
||||||
private Loan loanAccount;
|
private Loan loanAccount;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "savings_account_id", nullable = true)
|
@JoinColumn(name = "savings_account_id", nullable = true)
|
||||||
private SavingsAccount savingsAccount;
|
private SavingsAccount savingsAccount;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "linked_loan_account_id", nullable = true)
|
@JoinColumn(name = "linked_loan_account_id", nullable = true)
|
||||||
private Loan linkedLoanAccount;
|
private Loan linkedLoanAccount;
|
||||||
@@ -34,22 +38,29 @@ public class AccountAssociations extends AbstractPersistable<Long> {
|
|||||||
@JoinColumn(name = "linked_savings_account_id", nullable = true)
|
@JoinColumn(name = "linked_savings_account_id", nullable = true)
|
||||||
private SavingsAccount linkedSavingsAccount;
|
private SavingsAccount linkedSavingsAccount;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "association_type_enum", nullable = false)
|
||||||
|
private Integer associationType;
|
||||||
|
|
||||||
protected AccountAssociations() {}
|
protected AccountAssociations() {}
|
||||||
|
|
||||||
private AccountAssociations(final Loan loanAccount, final SavingsAccount savingsAccount, final Loan linkedLoanAccount,
|
private AccountAssociations(final Loan loanAccount, final SavingsAccount savingsAccount, final Loan linkedLoanAccount,
|
||||||
final SavingsAccount linkedSavingsAccount) {
|
final SavingsAccount linkedSavingsAccount, final Integer associationType) {
|
||||||
this.loanAccount = loanAccount;
|
this.loanAccount = loanAccount;
|
||||||
this.savingsAccount = savingsAccount;
|
this.savingsAccount = savingsAccount;
|
||||||
this.linkedLoanAccount = linkedLoanAccount;
|
this.linkedLoanAccount = linkedLoanAccount;
|
||||||
this.linkedSavingsAccount = linkedSavingsAccount;
|
this.linkedSavingsAccount = linkedSavingsAccount;
|
||||||
|
this.associationType = associationType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AccountAssociations associateSavingsAccount(final Loan loan, final SavingsAccount savingsAccount) {
|
public static AccountAssociations associateSavingsAccount(final Loan loan, final SavingsAccount savingsAccount,
|
||||||
return new AccountAssociations(loan, null, null, savingsAccount);
|
final Integer associationType) {
|
||||||
|
return new AccountAssociations(loan, null, null, savingsAccount, associationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AccountAssociations associateSavingsAccount(final SavingsAccount savingsAccount, final SavingsAccount linkedSavingsAccount) {
|
public static AccountAssociations associateSavingsAccount(final SavingsAccount savingsAccount,
|
||||||
return new AccountAssociations(null, savingsAccount, null, linkedSavingsAccount);
|
final SavingsAccount linkedSavingsAccount, final Integer associationType) {
|
||||||
|
return new AccountAssociations(null, savingsAccount, null, linkedSavingsAccount, associationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SavingsAccount linkedSavingsAccount() {
|
public SavingsAccount linkedSavingsAccount() {
|
||||||
|
|||||||
+7
-2
@@ -5,13 +5,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.account.service;
|
package org.mifosplatform.portfolio.account.service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.account.data.AccountAssociationsData;
|
||||||
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||||
|
|
||||||
public interface AccountAssociationsReadPlatformService {
|
public interface AccountAssociationsReadPlatformService {
|
||||||
|
|
||||||
public PortfolioAccountData retriveLoanAssociation(final Long loanId);
|
public PortfolioAccountData retriveLoanLinkedAssociation(final Long loanId);
|
||||||
|
|
||||||
public boolean isLinkedWithAnyActiveAccount(final Long savingsId);
|
public boolean isLinkedWithAnyActiveAccount(final Long savingsId);
|
||||||
|
|
||||||
public PortfolioAccountData retriveSavingsAssociation(final Long savingsId);
|
public PortfolioAccountData retriveSavingsLinkedAssociation(final Long savingsId);
|
||||||
|
|
||||||
|
public Collection<AccountAssociationsData> retriveLoanAssociations(Long loanId, Integer associationType);
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-8
@@ -7,12 +7,14 @@ package org.mifosplatform.portfolio.account.service;
|
|||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||||
import org.mifosplatform.portfolio.account.data.AccountAssociationsData;
|
import org.mifosplatform.portfolio.account.data.AccountAssociationsData;
|
||||||
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||||
|
import org.mifosplatform.portfolio.account.domain.AccountAssociationType;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -35,12 +37,13 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PortfolioAccountData retriveLoanAssociation(final Long loanId) {
|
public PortfolioAccountData retriveLoanLinkedAssociation(final Long loanId) {
|
||||||
PortfolioAccountData linkedAccount = null;
|
PortfolioAccountData linkedAccount = null;
|
||||||
final AccountAssociationsMapper mapper = new AccountAssociationsMapper();
|
final AccountAssociationsMapper mapper = new AccountAssociationsMapper();
|
||||||
final String sql = "select " + mapper.schema() + " where aa.loan_account_id = ? ";
|
final String sql = "select " + mapper.schema() + " where aa.loan_account_id = ? and aa.association_type_enum = ?";
|
||||||
try {
|
try {
|
||||||
final AccountAssociationsData accountAssociationsData = this.jdbcTemplate.queryForObject(sql, mapper, loanId);
|
final AccountAssociationsData accountAssociationsData = this.jdbcTemplate.queryForObject(sql, mapper, loanId,
|
||||||
|
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||||
if (accountAssociationsData != null) {
|
if (accountAssociationsData != null) {
|
||||||
linkedAccount = accountAssociationsData.linkedAccount();
|
linkedAccount = accountAssociationsData.linkedAccount();
|
||||||
}
|
}
|
||||||
@@ -51,12 +54,25 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PortfolioAccountData retriveSavingsAssociation(final Long savingsId) {
|
public Collection<AccountAssociationsData> retriveLoanAssociations(final Long loanId, final Integer associationType) {
|
||||||
|
final AccountAssociationsMapper mapper = new AccountAssociationsMapper();
|
||||||
|
final String sql = "select " + mapper.schema() + " where aa.loan_account_id = ? and aa.association_type_enum = ?";
|
||||||
|
try {
|
||||||
|
return this.jdbcTemplate.query(sql, mapper, loanId, associationType);
|
||||||
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PortfolioAccountData retriveSavingsLinkedAssociation(final Long savingsId) {
|
||||||
PortfolioAccountData linkedAccount = null;
|
PortfolioAccountData linkedAccount = null;
|
||||||
final AccountAssociationsMapper mapper = new AccountAssociationsMapper();
|
final AccountAssociationsMapper mapper = new AccountAssociationsMapper();
|
||||||
final String sql = "select " + mapper.schema() + " where aa.savings_account_id = ? ";
|
final String sql = "select " + mapper.schema() + " where aa.savings_account_id = ? and aa.association_type_enum = ?";
|
||||||
try {
|
try {
|
||||||
final AccountAssociationsData accountAssociationsData = this.jdbcTemplate.queryForObject(sql, mapper, savingsId);
|
final AccountAssociationsData accountAssociationsData = this.jdbcTemplate.queryForObject(sql, mapper, savingsId,
|
||||||
|
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||||
if (accountAssociationsData != null) {
|
if (accountAssociationsData != null) {
|
||||||
linkedAccount = accountAssociationsData.linkedAccount();
|
linkedAccount = accountAssociationsData.linkedAccount();
|
||||||
}
|
}
|
||||||
@@ -74,7 +90,7 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
|
|||||||
|
|
||||||
final List<Integer> statusList = this.jdbcTemplate.queryForList(sql, Integer.class, savingsId);
|
final List<Integer> statusList = this.jdbcTemplate.queryForList(sql, Integer.class, savingsId);
|
||||||
for (final Integer status : statusList) {
|
for (final Integer status : statusList) {
|
||||||
if(status !=null){
|
if (status != null) {
|
||||||
final LoanStatus loanStatus = LoanStatus.fromInt(status);
|
final LoanStatus loanStatus = LoanStatus.fromInt(status);
|
||||||
if (loanStatus.isActiveOrAwaitingApprovalOrDisbursal() || loanStatus.isUnderTransfer()) { return true; }
|
if (loanStatus.isActiveOrAwaitingApprovalOrDisbursal() || loanStatus.isUnderTransfer()) { return true; }
|
||||||
}
|
}
|
||||||
@@ -86,7 +102,7 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
|
|||||||
|
|
||||||
final List<Integer> savstatusList = this.jdbcTemplate.queryForList(savsql, Integer.class, savingsId);
|
final List<Integer> savstatusList = this.jdbcTemplate.queryForList(savsql, Integer.class, savingsId);
|
||||||
for (final Integer status : savstatusList) {
|
for (final Integer status : savstatusList) {
|
||||||
if(status !=null){
|
if (status != null) {
|
||||||
final SavingsAccountStatusType saveStatus = SavingsAccountStatusType.fromInt(status);
|
final SavingsAccountStatusType saveStatus = SavingsAccountStatusType.fromInt(status);
|
||||||
if (saveStatus.isActiveOrAwaitingApprovalOrDisbursal() || saveStatus.isUnderTransfer()) { return true; }
|
if (saveStatus.isActiveOrAwaitingApprovalOrDisbursal() || saveStatus.isUnderTransfer()) { return true; }
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -405,7 +405,7 @@ public class LoansApiResource {
|
|||||||
|
|
||||||
if (associationParameters.contains("linkedAccount")) {
|
if (associationParameters.contains("linkedAccount")) {
|
||||||
mandatoryResponseParameters.add("linkedAccount");
|
mandatoryResponseParameters.add("linkedAccount");
|
||||||
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -460,7 +460,7 @@ public class LoansApiResource {
|
|||||||
|
|
||||||
if (!associationParameters.contains("linkedAccount")) {
|
if (!associationParameters.contains("linkedAccount")) {
|
||||||
mandatoryResponseParameters.add("linkedAccount");
|
mandatoryResponseParameters.add("linkedAccount");
|
||||||
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||||
}
|
}
|
||||||
if (loanBasicDetails.groupId() != null) {
|
if (loanBasicDetails.groupId() != null) {
|
||||||
calendarOptions = this.loanReadPlatformService.retrieveCalendars(loanBasicDetails.groupId());
|
calendarOptions = this.loanReadPlatformService.retrieveCalendars(loanBasicDetails.groupId());
|
||||||
|
|||||||
+4
-2
@@ -26,6 +26,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityExce
|
|||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||||
|
import org.mifosplatform.portfolio.account.domain.AccountAssociationType;
|
||||||
import org.mifosplatform.portfolio.account.domain.AccountAssociations;
|
import org.mifosplatform.portfolio.account.domain.AccountAssociations;
|
||||||
import org.mifosplatform.portfolio.account.domain.AccountAssociationsRepository;
|
import org.mifosplatform.portfolio.account.domain.AccountAssociationsRepository;
|
||||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||||
@@ -254,7 +255,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||||
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
|
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
|
||||||
final AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication,
|
final AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication,
|
||||||
savingsAccount);
|
savingsAccount, AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||||
this.accountAssociationsRepository.save(accountAssociations);
|
this.accountAssociationsRepository.save(accountAssociations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,7 +590,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||||
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, existingLoanApplication);
|
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, existingLoanApplication);
|
||||||
if (accountAssociations == null) {
|
if (accountAssociations == null) {
|
||||||
accountAssociations = AccountAssociations.associateSavingsAccount(existingLoanApplication, savingsAccount);
|
accountAssociations = AccountAssociations.associateSavingsAccount(existingLoanApplication, savingsAccount,
|
||||||
|
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||||
} else {
|
} else {
|
||||||
accountAssociations.updateLinkedSavingsAccount(savingsAccount);
|
accountAssociations.updateLinkedSavingsAccount(savingsAccount);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -361,7 +361,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final Locale locale = command.extractLocale();
|
final Locale locale = command.extractLocale();
|
||||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
||||||
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||||
final SavingsAccount fromSavingsAccount = null;
|
final SavingsAccount fromSavingsAccount = null;
|
||||||
final boolean isRegularTransaction = true;
|
final boolean isRegularTransaction = true;
|
||||||
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate, entrySet.getValue(),
|
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate, entrySet.getValue(),
|
||||||
@@ -560,7 +560,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final Locale locale = command.extractLocale();
|
final Locale locale = command.extractLocale();
|
||||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
||||||
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan
|
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loan
|
||||||
.getId());
|
.getId());
|
||||||
final SavingsAccount fromSavingsAccount = null;
|
final SavingsAccount fromSavingsAccount = null;
|
||||||
final boolean isRegularTransaction = true;
|
final boolean isRegularTransaction = true;
|
||||||
@@ -1312,7 +1312,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan
|
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loan
|
||||||
.getId());
|
.getId());
|
||||||
if (portfolioAccountData == null) {
|
if (portfolioAccountData == null) {
|
||||||
final String errorMessage = loanCharge.name() + "Charge requires linked savings account for payment";
|
final String errorMessage = loanCharge.name() + "Charge requires linked savings account for payment";
|
||||||
@@ -1579,7 +1579,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
amount = chargePerInstallment.getAmountOutstanding();
|
amount = chargePerInstallment.getAmountOutstanding();
|
||||||
}
|
}
|
||||||
|
|
||||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||||
if (portfolioAccountData == null) {
|
if (portfolioAccountData == null) {
|
||||||
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
|
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
|
||||||
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
|
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
|
||||||
@@ -1609,7 +1609,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final Locale locale = command.extractLocale();
|
final Locale locale = command.extractLocale();
|
||||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan.getId());
|
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loan.getId());
|
||||||
if (portfolioAccountData == null) {
|
if (portfolioAccountData == null) {
|
||||||
final String errorMessage = "Disburse Loan with id:" + loan.getId() + " requires linked savings account for payment";
|
final String errorMessage = "Disburse Loan with id:" + loan.getId() + " requires linked savings account for payment";
|
||||||
throw new LinkedAccountRequiredException("loan.disburse.to.savings", errorMessage, loan.getId());
|
throw new LinkedAccountRequiredException("loan.disburse.to.savings", errorMessage, loan.getId());
|
||||||
@@ -1641,7 +1641,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
|
for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
|
||||||
if (!installmentChargeData.getDueDate().isAfter(new LocalDate())) {
|
if (!installmentChargeData.getDueDate().isAfter(new LocalDate())) {
|
||||||
if (portfolioAccountData == null) {
|
if (portfolioAccountData == null) {
|
||||||
portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(chargeData
|
portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(chargeData
|
||||||
.getLoanId());
|
.getLoanId());
|
||||||
}
|
}
|
||||||
final SavingsAccount fromSavingsAccount = null;
|
final SavingsAccount fromSavingsAccount = null;
|
||||||
@@ -1656,7 +1656,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(new LocalDate())) {
|
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(new LocalDate())) {
|
||||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||||
.retriveLoanAssociation(chargeData.getLoanId());
|
.retriveLoanLinkedAssociation(chargeData.getLoanId());
|
||||||
final SavingsAccount fromSavingsAccount = null;
|
final SavingsAccount fromSavingsAccount = null;
|
||||||
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(),
|
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(),
|
||||||
chargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
|
chargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
|
||||||
@@ -2469,7 +2469,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
amount = chargePerInstallment.getAmountOutstanding();
|
amount = chargePerInstallment.getAmountOutstanding();
|
||||||
}
|
}
|
||||||
|
|
||||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||||
if (portfolioAccountData == null) {
|
if (portfolioAccountData == null) {
|
||||||
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
|
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
|
||||||
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
|
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
|
||||||
|
|||||||
+6
@@ -72,4 +72,10 @@ public interface LoanProductConstants {
|
|||||||
public static final String recalculationRestFrequencyIntervalParameterName = "recalculationRestFrequencyInterval";
|
public static final String recalculationRestFrequencyIntervalParameterName = "recalculationRestFrequencyInterval";
|
||||||
public static final String recalculationRestFrequencyDateParamName = "recalculationRestFrequencyDate";
|
public static final String recalculationRestFrequencyDateParamName = "recalculationRestFrequencyDate";
|
||||||
|
|
||||||
|
// Guarantee related
|
||||||
|
public static final String holdGuaranteeFundsParamName = "holdGuaranteeFunds";
|
||||||
|
public static final String mandatoryGuaranteeParamName = "mandatoryGuarantee";
|
||||||
|
public static final String minimumGuaranteeFromOwnFundsParamName = "minimumGuaranteeFromOwnFunds";
|
||||||
|
public static final String minimumGuaranteeFromGuarantorParamName = "minimumGuaranteeFromGuarantor";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-5
@@ -135,6 +135,9 @@ public class LoanProductData {
|
|||||||
private final Integer maxTrancheCount;
|
private final Integer maxTrancheCount;
|
||||||
private final BigDecimal outstandingLoanBalance;
|
private final BigDecimal outstandingLoanBalance;
|
||||||
|
|
||||||
|
private final Boolean holdGuaranteeFunds;
|
||||||
|
private final LoanProductGuaranteeData productGuaranteeData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when returning lookup information about loan product for dropdowns.
|
* Used when returning lookup information about loan product for dropdowns.
|
||||||
*/
|
*/
|
||||||
@@ -182,6 +185,8 @@ public class LoanProductData {
|
|||||||
final Boolean multiDisburseLoan = null;
|
final Boolean multiDisburseLoan = null;
|
||||||
final Integer maxTrancheCount = null;
|
final Integer maxTrancheCount = null;
|
||||||
final BigDecimal outstandingLoanBalance = null;
|
final BigDecimal outstandingLoanBalance = null;
|
||||||
|
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||||
|
final Boolean holdGuaranteeFunds = false;
|
||||||
|
|
||||||
final EnumOptionData daysInMonthType = null;
|
final EnumOptionData daysInMonthType = null;
|
||||||
final EnumOptionData daysInYearType = null;
|
final EnumOptionData daysInYearType = null;
|
||||||
@@ -197,7 +202,7 @@ public class LoanProductData {
|
|||||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment);
|
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanProductData lookupWithCurrency(final Long id, final String name, final CurrencyData currency) {
|
public static LoanProductData lookupWithCurrency(final Long id, final String name, final CurrencyData currency) {
|
||||||
@@ -251,6 +256,8 @@ public class LoanProductData {
|
|||||||
final boolean isInterestRecalculationEnabled = false;
|
final boolean isInterestRecalculationEnabled = false;
|
||||||
final LoanProductInterestRecalculationData interestRecalculationData = null;
|
final LoanProductInterestRecalculationData interestRecalculationData = null;
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||||
|
final Boolean holdGuaranteeFunds = false;
|
||||||
|
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -260,7 +267,7 @@ public class LoanProductData {
|
|||||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment);
|
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
|
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
|
||||||
@@ -321,7 +328,8 @@ public class LoanProductData {
|
|||||||
final LoanProductInterestRecalculationData interestRecalculationData = LoanProductInterestRecalculationData
|
final LoanProductInterestRecalculationData interestRecalculationData = LoanProductInterestRecalculationData
|
||||||
.sensibleDefaultsForNewLoanProductCreation();
|
.sensibleDefaultsForNewLoanProductCreation();
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||||
|
final Boolean holdGuaranteeFunds = false;
|
||||||
|
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -331,7 +339,8 @@ public class LoanProductData {
|
|||||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId,
|
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId,
|
||||||
principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle,
|
principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle,
|
||||||
multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType,
|
multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType,
|
||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment);
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||||
|
holdGuaranteeFunds, productGuaranteeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
|
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
|
||||||
@@ -362,7 +371,8 @@ public class LoanProductData {
|
|||||||
Integer maxTrancheCount, BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing,
|
Integer maxTrancheCount, BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing,
|
||||||
final Integer overdueDaysForNPA, final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType,
|
final Integer overdueDaysForNPA, final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType,
|
||||||
final boolean isInterestRecalculationEnabled, final LoanProductInterestRecalculationData interestRecalculationData,
|
final boolean isInterestRecalculationEnabled, final LoanProductInterestRecalculationData interestRecalculationData,
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, boolean holdGuaranteeFunds,
|
||||||
|
LoanProductGuaranteeData loanProductGuaranteeData) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
@@ -433,12 +443,15 @@ public class LoanProductData {
|
|||||||
this.daysInYearType = daysInYearType;
|
this.daysInYearType = daysInYearType;
|
||||||
this.isInterestRecalculationEnabled = isInterestRecalculationEnabled;
|
this.isInterestRecalculationEnabled = isInterestRecalculationEnabled;
|
||||||
this.interestRecalculationData = interestRecalculationData;
|
this.interestRecalculationData = interestRecalculationData;
|
||||||
|
this.holdGuaranteeFunds = holdGuaranteeFunds;
|
||||||
|
this.productGuaranteeData = loanProductGuaranteeData;
|
||||||
|
|
||||||
this.daysInMonthTypeOptions = null;
|
this.daysInMonthTypeOptions = null;
|
||||||
this.daysInYearTypeOptions = null;
|
this.daysInYearTypeOptions = null;
|
||||||
this.interestRecalculationCompoundingTypeOptions = null;
|
this.interestRecalculationCompoundingTypeOptions = null;
|
||||||
this.rescheduleStrategyTypeOptions = null;
|
this.rescheduleStrategyTypeOptions = null;
|
||||||
this.interestRecalculationFrequencyTypeOptions = null;
|
this.interestRecalculationFrequencyTypeOptions = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||||
@@ -533,6 +546,8 @@ public class LoanProductData {
|
|||||||
this.daysInYearType = productData.daysInYearType;
|
this.daysInYearType = productData.daysInYearType;
|
||||||
this.isInterestRecalculationEnabled = productData.isInterestRecalculationEnabled;
|
this.isInterestRecalculationEnabled = productData.isInterestRecalculationEnabled;
|
||||||
this.interestRecalculationData = productData.interestRecalculationData;
|
this.interestRecalculationData = productData.interestRecalculationData;
|
||||||
|
this.holdGuaranteeFunds = productData.holdGuaranteeFunds;
|
||||||
|
this.productGuaranteeData = productData.productGuaranteeData;
|
||||||
|
|
||||||
this.daysInMonthTypeOptions = daysInMonthTypeOptions;
|
this.daysInMonthTypeOptions = daysInMonthTypeOptions;
|
||||||
this.daysInYearTypeOptions = daysInYearTypeOptions;
|
this.daysInYearTypeOptions = daysInYearTypeOptions;
|
||||||
|
|||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.loanproduct.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class LoanProductGuaranteeData {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long id;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long productId;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final BigDecimal mandatoryGuarantee;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final BigDecimal minimumGuaranteeFromOwnFunds;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final BigDecimal minimumGuaranteeFromGuarantor;
|
||||||
|
|
||||||
|
public static LoanProductGuaranteeData instance(final Long id, final Long productId, final BigDecimal mandatoryGuarantee,
|
||||||
|
final BigDecimal minimumGuaranteeFromOwnFunds, final BigDecimal minimumGuaranteeFromGuarantor) {
|
||||||
|
return new LoanProductGuaranteeData(id, productId, mandatoryGuarantee, minimumGuaranteeFromOwnFunds, minimumGuaranteeFromGuarantor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LoanProductGuaranteeData sensibleDefaultsForNewLoanProductCreation() {
|
||||||
|
return new LoanProductGuaranteeData(null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanProductGuaranteeData(final Long id, final Long productId, final BigDecimal mandatoryGuarantee,
|
||||||
|
final BigDecimal minimumGuaranteeFromOwnFunds, final BigDecimal minimumGuaranteeFromGuarantor) {
|
||||||
|
this.id = id;
|
||||||
|
this.productId = productId;
|
||||||
|
this.mandatoryGuarantee = mandatoryGuarantee;
|
||||||
|
this.minimumGuaranteeFromGuarantor = minimumGuaranteeFromGuarantor;
|
||||||
|
this.minimumGuaranteeFromOwnFunds = minimumGuaranteeFromOwnFunds;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+60
-4
@@ -129,6 +129,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loanProduct", optional = true, orphanRemoval = true)
|
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loanProduct", optional = true, orphanRemoval = true)
|
||||||
private LoanProductInterestRecalculationDetails productInterestRecalculationDetails;
|
private LoanProductInterestRecalculationDetails productInterestRecalculationDetails;
|
||||||
|
|
||||||
|
@Column(name = "hold_guarantee_funds")
|
||||||
|
private boolean holdGuaranteeFunds;
|
||||||
|
|
||||||
|
@LazyCollection(LazyCollectionOption.FALSE)
|
||||||
|
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loanProduct", optional = true, orphanRemoval = true)
|
||||||
|
private LoanProductGuaranteeDetails loanProductGuaranteeDetails;
|
||||||
|
|
||||||
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
||||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
||||||
|
|
||||||
@@ -211,6 +218,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
if (isInterestRecalculationEnabled) {
|
if (isInterestRecalculationEnabled) {
|
||||||
interestRecalculationSettings = LoanProductInterestRecalculationDetails.createFrom(command);
|
interestRecalculationSettings = LoanProductInterestRecalculationDetails.createFrom(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean holdGuarantorFunds = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName);
|
||||||
|
LoanProductGuaranteeDetails loanProductGuaranteeDetails = null;
|
||||||
|
if (holdGuarantorFunds) {
|
||||||
|
loanProductGuaranteeDetails = LoanProductGuaranteeDetails.createFrom(command);
|
||||||
|
}
|
||||||
|
|
||||||
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
||||||
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
||||||
annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType,
|
annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType,
|
||||||
@@ -218,12 +232,18 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle,
|
graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle,
|
||||||
startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount,
|
startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount,
|
||||||
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
|
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
|
||||||
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment);
|
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||||
|
holdGuarantorFunds, loanProductGuaranteeDetails);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateLoanProductForInterestRecalculationDetails() {
|
public void updateLoanProductInRelatedClasses() {
|
||||||
this.productInterestRecalculationDetails.updateProduct(this);
|
if (this.isInterestRecalculationEnabled()) {
|
||||||
|
this.productInterestRecalculationDetails.updateProduct(this);
|
||||||
|
}
|
||||||
|
if (this.holdGuaranteeFunds) {
|
||||||
|
this.loanProductGuaranteeDetails.updateProduct(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -437,7 +457,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
final Integer overdueDaysForNPA, final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType,
|
final Integer overdueDaysForNPA, final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType,
|
||||||
final boolean isInterestRecalculationEnabled,
|
final boolean isInterestRecalculationEnabled,
|
||||||
final LoanProductInterestRecalculationDetails productInterestRecalculationDetails,
|
final LoanProductInterestRecalculationDetails productInterestRecalculationDetails,
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final boolean holdGuarantorFunds,
|
||||||
|
final LoanProductGuaranteeDetails loanProductGuaranteeDetails) {
|
||||||
this.fund = fund;
|
this.fund = fund;
|
||||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||||
this.name = name.trim();
|
this.name = name.trim();
|
||||||
@@ -487,6 +508,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
this.overdueDaysForNPA = overdueDaysForNPA;
|
this.overdueDaysForNPA = overdueDaysForNPA;
|
||||||
this.productInterestRecalculationDetails = productInterestRecalculationDetails;
|
this.productInterestRecalculationDetails = productInterestRecalculationDetails;
|
||||||
this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment;
|
this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||||
|
this.holdGuaranteeFunds = holdGuarantorFunds;
|
||||||
|
this.loanProductGuaranteeDetails = loanProductGuaranteeDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonetaryCurrency getCurrency() {
|
public MonetaryCurrency getCurrency() {
|
||||||
@@ -690,6 +713,30 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
this.productInterestRecalculationDetails.update(command, actualChanges, localeAsInput);
|
this.productInterestRecalculationDetails.update(command, actualChanges, localeAsInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName, this.holdGuaranteeFunds)) {
|
||||||
|
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName);
|
||||||
|
actualChanges.put(LoanProductConstants.holdGuaranteeFundsParamName, newValue);
|
||||||
|
this.holdGuaranteeFunds = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualChanges.containsKey(LoanProductConstants.holdGuaranteeFundsParamName)) {
|
||||||
|
if (this.holdGuaranteeFunds) {
|
||||||
|
this.loanProductGuaranteeDetails = LoanProductGuaranteeDetails.createFrom(command);
|
||||||
|
this.loanProductGuaranteeDetails.updateProduct(this);
|
||||||
|
actualChanges.put(LoanProductConstants.mandatoryGuaranteeParamName,
|
||||||
|
this.loanProductGuaranteeDetails.getMandatoryGuarantee());
|
||||||
|
actualChanges.put(LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||||
|
this.loanProductGuaranteeDetails.getMinimumGuaranteeFromGuarantor());
|
||||||
|
actualChanges.put(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
|
||||||
|
this.loanProductGuaranteeDetails.getMinimumGuaranteeFromOwnFunds());
|
||||||
|
} else {
|
||||||
|
this.loanProductGuaranteeDetails = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (this.holdGuaranteeFunds) {
|
||||||
|
this.loanProductGuaranteeDetails.update(command, actualChanges);
|
||||||
|
}
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,4 +976,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
public LoanProductInterestRecalculationDetails getProductInterestRecalculationDetails() {
|
public LoanProductInterestRecalculationDetails getProductInterestRecalculationDetails() {
|
||||||
return this.productInterestRecalculationDetails;
|
return this.productInterestRecalculationDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isHoldGuaranteeFundsEnabled() {
|
||||||
|
return this.holdGuaranteeFunds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public LoanProductGuaranteeDetails getLoanProductGuaranteeDetails() {
|
||||||
|
return this.loanProductGuaranteeDetails;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.loanproduct.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||||
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity for capturing interest recalculation settings
|
||||||
|
*
|
||||||
|
* @author conflux
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_product_loan_guarantee_details")
|
||||||
|
public class LoanProductGuaranteeDetails extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "loan_product_id", nullable = false)
|
||||||
|
private LoanProduct loanProduct;
|
||||||
|
|
||||||
|
@Column(name = "mandatory_guarantee", scale = 6, precision = 19, nullable = false)
|
||||||
|
private BigDecimal mandatoryGuarantee;
|
||||||
|
|
||||||
|
@Column(name = "minimum_guarantee_from_own_funds", scale = 6, precision = 19, nullable = false)
|
||||||
|
private BigDecimal minimumGuaranteeFromOwnFunds;
|
||||||
|
|
||||||
|
@Column(name = "minimum_guarantee_from_guarantor_funds", scale = 6, precision = 19, nullable = false)
|
||||||
|
private BigDecimal minimumGuaranteeFromGuarantor;
|
||||||
|
|
||||||
|
protected LoanProductGuaranteeDetails() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LoanProductGuaranteeDetails createFrom(final JsonCommand command) {
|
||||||
|
|
||||||
|
final BigDecimal mandatoryGuarantee = command.bigDecimalValueOfParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName);
|
||||||
|
final BigDecimal minimumGuaranteeFromGuarantor = command
|
||||||
|
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName);
|
||||||
|
final BigDecimal minimumGuaranteeFromOwnFunds = command
|
||||||
|
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName);
|
||||||
|
|
||||||
|
return new LoanProductGuaranteeDetails(mandatoryGuarantee, minimumGuaranteeFromOwnFunds, minimumGuaranteeFromGuarantor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanProductGuaranteeDetails(final BigDecimal mandatoryGuarantee, final BigDecimal minimumGuaranteeFromOwnFunds,
|
||||||
|
final BigDecimal minimumGuaranteeFromGuarantor) {
|
||||||
|
this.mandatoryGuarantee = mandatoryGuarantee;
|
||||||
|
this.minimumGuaranteeFromGuarantor = minimumGuaranteeFromGuarantor;
|
||||||
|
this.minimumGuaranteeFromOwnFunds = minimumGuaranteeFromOwnFunds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateProduct(final LoanProduct loanProduct) {
|
||||||
|
this.loanProduct = loanProduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
|
||||||
|
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName, this.mandatoryGuarantee)) {
|
||||||
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName);
|
||||||
|
actualChanges.put(LoanProductConstants.mandatoryGuaranteeParamName, newValue);
|
||||||
|
this.mandatoryGuarantee = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||||
|
this.minimumGuaranteeFromGuarantor)) {
|
||||||
|
final BigDecimal newValue = command
|
||||||
|
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName);
|
||||||
|
actualChanges.put(LoanProductConstants.minimumGuaranteeFromGuarantorParamName, newValue);
|
||||||
|
this.minimumGuaranteeFromGuarantor = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
|
||||||
|
this.minimumGuaranteeFromOwnFunds)) {
|
||||||
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName);
|
||||||
|
actualChanges.put(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, newValue);
|
||||||
|
this.minimumGuaranteeFromOwnFunds = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public BigDecimal getMandatoryGuarantee() {
|
||||||
|
return this.mandatoryGuarantee;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public BigDecimal getMinimumGuaranteeFromOwnFunds() {
|
||||||
|
return this.minimumGuaranteeFromOwnFunds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public BigDecimal getMinimumGuaranteeFromGuarantor() {
|
||||||
|
return this.minimumGuaranteeFromGuarantor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+82
-6
@@ -71,7 +71,9 @@ public final class LoanProductDataValidator {
|
|||||||
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||||
LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
|
LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
|
||||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
||||||
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment));
|
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, LoanProductConstants.mandatoryGuaranteeParamName,
|
||||||
|
LoanProductConstants.holdGuaranteeFundsParamName, LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||||
|
LoanProductConstants.minimumGuaranteeFromOwnFundsParamName));
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
@@ -309,6 +311,20 @@ public final class LoanProductDataValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guarantee Funds
|
||||||
|
Boolean holdGuaranteeFunds = false;
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.holdGuaranteeFundsParamName, element)) {
|
||||||
|
holdGuaranteeFunds = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.holdGuaranteeFundsParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.holdGuaranteeFundsParamName).value(holdGuaranteeFunds).notNull()
|
||||||
|
.isOneOfTheseValues(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holdGuaranteeFunds != null) {
|
||||||
|
if (holdGuaranteeFunds) {
|
||||||
|
validateGuaranteeParams(element, baseDataValidator, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// accounting related data validation
|
// accounting related data validation
|
||||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 4);
|
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 4);
|
||||||
@@ -704,16 +720,31 @@ public final class LoanProductDataValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Interest recalculation settings
|
// Interest recalculation settings
|
||||||
|
Boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled();
|
||||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.isInterestRecalculationEnabledParameterName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.isInterestRecalculationEnabledParameterName, element)) {
|
||||||
final Boolean isInterestRecalculationEnabled = this.fromApiJsonHelper.extractBooleanNamed(
|
isInterestRecalculationEnabled = this.fromApiJsonHelper.extractBooleanNamed(
|
||||||
LoanProductConstants.isInterestRecalculationEnabledParameterName, element);
|
LoanProductConstants.isInterestRecalculationEnabledParameterName, element);
|
||||||
baseDataValidator.reset().parameter(LoanProductConstants.isInterestRecalculationEnabledParameterName)
|
baseDataValidator.reset().parameter(LoanProductConstants.isInterestRecalculationEnabledParameterName)
|
||||||
.value(isInterestRecalculationEnabled).notNull().isOneOfTheseValues(true, false);
|
.value(isInterestRecalculationEnabled).notNull().isOneOfTheseValues(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (isInterestRecalculationEnabled != null) {
|
if (isInterestRecalculationEnabled != null) {
|
||||||
if (isInterestRecalculationEnabled.booleanValue()) {
|
if (isInterestRecalculationEnabled) {
|
||||||
validateInterestRecalculationParams(element, baseDataValidator, loanProduct);
|
validateInterestRecalculationParams(element, baseDataValidator, loanProduct);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guarantee Funds
|
||||||
|
Boolean holdGuaranteeFunds = loanProduct.isHoldGuaranteeFundsEnabled();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.holdGuaranteeFundsParamName, element)) {
|
||||||
|
holdGuaranteeFunds = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.holdGuaranteeFundsParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.holdGuaranteeFundsParamName).value(holdGuaranteeFunds).notNull()
|
||||||
|
.isOneOfTheseValues(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holdGuaranteeFunds != null) {
|
||||||
|
if (holdGuaranteeFunds) {
|
||||||
|
validateGuaranteeParams(element, baseDataValidator, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1279,4 +1310,49 @@ public final class LoanProductDataValidator {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateGuaranteeParams(final JsonElement element, final DataValidatorBuilder baseDataValidator,
|
||||||
|
final LoanProduct loanProduct) {
|
||||||
|
BigDecimal mandatoryGuarantee = BigDecimal.ZERO;
|
||||||
|
BigDecimal minimumGuaranteeFromOwnFunds = BigDecimal.ZERO;
|
||||||
|
BigDecimal minimumGuaranteeFromGuarantor = BigDecimal.ZERO;
|
||||||
|
if (loanProduct != null) {
|
||||||
|
mandatoryGuarantee = loanProduct.getLoanProductGuaranteeDetails().getMandatoryGuarantee();
|
||||||
|
minimumGuaranteeFromOwnFunds = loanProduct.getLoanProductGuaranteeDetails().getMinimumGuaranteeFromOwnFunds();
|
||||||
|
minimumGuaranteeFromGuarantor = loanProduct.getLoanProductGuaranteeDetails().getMinimumGuaranteeFromGuarantor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loanProduct == null || this.fromApiJsonHelper.parameterExists(LoanProductConstants.mandatoryGuaranteeParamName, element)) {
|
||||||
|
mandatoryGuarantee = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanProductConstants.mandatoryGuaranteeParamName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.mandatoryGuaranteeParamName).value(mandatoryGuarantee).notNull();
|
||||||
|
if (mandatoryGuarantee == null) {
|
||||||
|
mandatoryGuarantee = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loanProduct == null
|
||||||
|
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.minimumGuaranteeFromGuarantorParamName, element)) {
|
||||||
|
minimumGuaranteeFromGuarantor = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
||||||
|
LoanProductConstants.minimumGuaranteeFromGuarantorParamName, element);
|
||||||
|
if (minimumGuaranteeFromGuarantor == null) {
|
||||||
|
minimumGuaranteeFromGuarantor = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loanProduct == null
|
||||||
|
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, element)) {
|
||||||
|
minimumGuaranteeFromOwnFunds = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
||||||
|
LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, element);
|
||||||
|
if (minimumGuaranteeFromOwnFunds == null) {
|
||||||
|
minimumGuaranteeFromOwnFunds = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mandatoryGuarantee.compareTo(minimumGuaranteeFromOwnFunds.add(minimumGuaranteeFromGuarantor)) == -1) {
|
||||||
|
baseDataValidator.parameter(LoanProductConstants.mandatoryGuaranteeParamName).failWithCode(
|
||||||
|
"must.be.greter.than.sum.of.min.funds");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+19
-2
@@ -24,6 +24,7 @@ import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
|
|||||||
import org.mifosplatform.portfolio.common.service.CommonEnumerations;
|
import org.mifosplatform.portfolio.common.service.CommonEnumerations;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductGuaranteeData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductInterestRecalculationData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductInterestRecalculationData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductParamType;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductParamType;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
@@ -128,10 +129,14 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
|
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
|
||||||
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
||||||
+ "lpr.rest_freqency_date as restFrequencyDate, "
|
+ "lpr.rest_freqency_date as restFrequencyDate, "
|
||||||
|
+ "lp.hold_guarantee_funds as holdGuaranteeFunds, "
|
||||||
|
+ "lpg.id as lpgId, lpg.mandatory_guarantee as mandatoryGuarantee, "
|
||||||
|
+ "lpg.minimum_guarantee_from_own_funds as minimumGuaranteeFromOwnFunds, lpg.minimum_guarantee_from_guarantor_funds as minimumGuaranteeFromGuarantor, "
|
||||||
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, lp.external_id as externalId "
|
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, lp.external_id as externalId "
|
||||||
+ " from m_product_loan lp "
|
+ " from m_product_loan lp "
|
||||||
+ " left join m_fund f on f.id = lp.fund_id "
|
+ " left join m_fund f on f.id = lp.fund_id "
|
||||||
+ " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id "
|
+ " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id "
|
||||||
|
+ " left join m_product_loan_guarantee_details lpg on lpg.loan_product_id=lp.id "
|
||||||
+ " left join ref_loan_transaction_processing_strategy ltps on ltps.id = lp.loan_transaction_strategy_id"
|
+ " left join ref_loan_transaction_processing_strategy ltps on ltps.id = lp.loan_transaction_strategy_id"
|
||||||
+ " join m_currency curr on curr.code = lp.currency_code";
|
+ " join m_currency curr on curr.code = lp.currency_code";
|
||||||
}
|
}
|
||||||
@@ -173,7 +178,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
final Integer graceOnInterestCharged = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnInterestCharged");
|
final Integer graceOnInterestCharged = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnInterestCharged");
|
||||||
final Integer graceOnArrearsAgeing = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnArrearsAgeing");
|
final Integer graceOnArrearsAgeing = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnArrearsAgeing");
|
||||||
final Integer overdueDaysForNPA = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "overdueDaysForNPA");
|
final Integer overdueDaysForNPA = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "overdueDaysForNPA");
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = JdbcSupport.getInteger(rs,"minimumDaysBetweenDisbursalAndFirstRepayment");
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = JdbcSupport.getInteger(rs,
|
||||||
|
"minimumDaysBetweenDisbursalAndFirstRepayment");
|
||||||
|
|
||||||
final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
|
final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
|
||||||
final EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId);
|
final EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId);
|
||||||
@@ -256,6 +262,17 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
restFrequencyDate);
|
restFrequencyDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean holdGuaranteeFunds = rs.getBoolean("holdGuaranteeFunds");
|
||||||
|
LoanProductGuaranteeData loanProductGuaranteeData = null;
|
||||||
|
if (holdGuaranteeFunds) {
|
||||||
|
final Long lpgId = JdbcSupport.getLong(rs, "lpgId");
|
||||||
|
final BigDecimal mandatoryGuarantee = rs.getBigDecimal("mandatoryGuarantee");
|
||||||
|
final BigDecimal minimumGuaranteeFromOwnFunds = rs.getBigDecimal("minimumGuaranteeFromOwnFunds");
|
||||||
|
final BigDecimal minimumGuaranteeFromGuarantor = rs.getBigDecimal("minimumGuaranteeFromGuarantor");
|
||||||
|
loanProductGuaranteeData = LoanProductGuaranteeData.instance(lpgId, id, mandatoryGuarantee, minimumGuaranteeFromOwnFunds,
|
||||||
|
minimumGuaranteeFromGuarantor);
|
||||||
|
}
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
|
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
|
||||||
@@ -265,7 +282,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
|
closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
|
||||||
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment);
|
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -92,9 +92,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
|
|
||||||
final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command,
|
final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command,
|
||||||
this.aprCalculator);
|
this.aprCalculator);
|
||||||
if (loanproduct.isInterestRecalculationEnabled()) {
|
loanproduct.updateLoanProductInRelatedClasses();
|
||||||
loanproduct.updateLoanProductForInterestRecalculationDetails();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loanProductRepository.save(loanproduct);
|
this.loanProductRepository.save(loanproduct);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -209,7 +209,7 @@ public class FixedDepositAccountsApiResource {
|
|||||||
|
|
||||||
if (associationParameters.contains(SavingsApiConstants.linkedAccount)) {
|
if (associationParameters.contains(SavingsApiConstants.linkedAccount)) {
|
||||||
mandatoryResponseParameters.add(SavingsApiConstants.linkedAccount);
|
mandatoryResponseParameters.add(SavingsApiConstants.linkedAccount);
|
||||||
linkedAccount = this.accountAssociationsReadPlatformService.retriveSavingsAssociation(accountId);
|
linkedAccount = this.accountAssociationsReadPlatformService.retriveSavingsLinkedAssociation(accountId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-28
@@ -249,6 +249,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "min_required_balance", scale = 6, precision = 19, nullable = true)
|
@Column(name = "min_required_balance", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal minRequiredBalance;
|
private BigDecimal minRequiredBalance;
|
||||||
|
|
||||||
|
@Column(name = "on_hold_funds_derived", scale = 6, precision = 19, nullable = true)
|
||||||
|
private BigDecimal onHoldFunds;
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
@Temporal(TemporalType.DATE)
|
||||||
@Column(name = "start_interest_calculation_date")
|
@Column(name = "start_interest_calculation_date")
|
||||||
protected Date startInterestCalculationDate;
|
protected Date startInterestCalculationDate;
|
||||||
@@ -854,6 +857,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount, final boolean isWithdrawBalance) {
|
public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount, final boolean isWithdrawBalance) {
|
||||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||||
Money runningBalance = Money.zero(this.currency);
|
Money runningBalance = Money.zero(this.currency);
|
||||||
|
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||||
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
||||||
if (transaction.isNotReversed() && transaction.isCredit()) {
|
if (transaction.isNotReversed() && transaction.isCredit()) {
|
||||||
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
||||||
@@ -866,21 +870,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
final BigDecimal withdrawalFee = null;
|
final BigDecimal withdrawalFee = null;
|
||||||
// deal with potential minRequiredBalance and
|
// deal with potential minRequiredBalance and
|
||||||
// enforceMinRequiredBalance
|
// enforceMinRequiredBalance
|
||||||
if (!isWithdrawBalance && this.minRequiredBalance != null && this.enforceMinRequiredBalance && transaction.isWithdrawal()) {
|
if (!isWithdrawBalance && transaction.isDebit()) {
|
||||||
if (runningBalance.minus(this.minRequiredBalance).isLessThanZero()) { throw new InsufficientAccountBalanceException(
|
if (runningBalance.minus(minRequiredBalance).isLessThanZero()) { throw new InsufficientAccountBalanceException(
|
||||||
"transactionAmount", getAccountBalance(), withdrawalFee, transactionAmount); }
|
"transactionAmount", getAccountBalance(), withdrawalFee, transactionAmount); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runningBalance.isLessThanZero()) {
|
|
||||||
Money limit = runningBalance.zero();
|
|
||||||
if (this.allowOverdraft) {
|
|
||||||
if (this.overdraftLimit != null) {
|
|
||||||
limit = limit.plus(this.overdraftLimit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (limit.plus(runningBalance).isLessThanZero()) { throw new InsufficientAccountBalanceException("transactionAmount",
|
|
||||||
getAccountBalance(), withdrawalFee, transactionAmount); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,7 +882,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||||
Money runningBalance = Money.zero(this.currency);
|
Money runningBalance = Money.zero(this.currency);
|
||||||
|
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||||
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
||||||
if (transaction.isNotReversed() && transaction.isCredit()) {
|
if (transaction.isNotReversed() && transaction.isCredit()) {
|
||||||
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
||||||
@@ -896,24 +890,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runningBalance.isLessThanZero()) {
|
// enforceMinRequiredBalance
|
||||||
//
|
if (transaction.isDebit()) {
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
if (runningBalance.minus(minRequiredBalance).isLessThanZero()) {
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(depositAccountType()
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
.resourceName() + transactionAction);
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||||
|
.resource(depositAccountType().resourceName() + transactionAction);
|
||||||
if (this.allowOverdraft) {
|
if (this.allowOverdraft) {
|
||||||
Money limit = runningBalance.zero();
|
|
||||||
if (this.overdraftLimit != null) {
|
|
||||||
limit = limit.plus(this.overdraftLimit);
|
|
||||||
}
|
|
||||||
if (limit.plus(runningBalance).isLessThanZero()) {
|
|
||||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.exceeding.overdraft.limit");
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.exceeding.overdraft.limit");
|
||||||
|
} else {
|
||||||
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative");
|
||||||
}
|
}
|
||||||
} else {
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative");
|
|
||||||
}
|
}
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2430,4 +2420,15 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
return savingsAccountCharge;
|
return savingsAccountCharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Money minRequiredBalanceDerived(final MonetaryCurrency currency) {
|
||||||
|
Money minReqBalance = Money.of(currency, this.onHoldFunds);
|
||||||
|
if (this.enforceMinRequiredBalance) {
|
||||||
|
minReqBalance = minReqBalance.plus(this.minRequiredBalance);
|
||||||
|
}
|
||||||
|
if (this.allowOverdraft) {
|
||||||
|
minReqBalance = minReqBalance.minus(this.overdraftLimit);
|
||||||
|
}
|
||||||
|
return minReqBalance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -231,7 +231,7 @@ public class SavingsAccountAssembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal minRequiredBalance = null;
|
BigDecimal minRequiredBalance = null;
|
||||||
if (command.parameterExists(overdraftLimitParamName)) {
|
if (command.parameterExists(minRequiredBalanceParamName)) {
|
||||||
minRequiredBalance = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minRequiredBalanceParamName);
|
minRequiredBalance = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minRequiredBalanceParamName);
|
||||||
} else {
|
} else {
|
||||||
minRequiredBalance = product.minRequiredBalance();
|
minRequiredBalance = product.minRequiredBalance();
|
||||||
|
|||||||
+2
-2
@@ -196,7 +196,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
|||||||
if (amountForDeposit.isGreaterThanZero()) {
|
if (amountForDeposit.isGreaterThanZero()) {
|
||||||
|
|
||||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||||
.retriveSavingsAssociation(savingsId);
|
.retriveSavingsLinkedAssociation(savingsId);
|
||||||
|
|
||||||
if (portfolioAccountData == null) {
|
if (portfolioAccountData == null) {
|
||||||
final PaymentDetail paymentDetail = null;
|
final PaymentDetail paymentDetail = null;
|
||||||
@@ -274,7 +274,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
|||||||
Money amountForDeposit = account.activateWithBalance();
|
Money amountForDeposit = account.activateWithBalance();
|
||||||
if (amountForDeposit.isGreaterThanZero()) {
|
if (amountForDeposit.isGreaterThanZero()) {
|
||||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||||
.retriveSavingsAssociation(savingsId);
|
.retriveSavingsLinkedAssociation(savingsId);
|
||||||
if (portfolioAccountData == null) {
|
if (portfolioAccountData == null) {
|
||||||
this.depositAccountDomainService.handleRDDeposit(account, fmt, account.getActivationLocalDate(),
|
this.depositAccountDomainService.handleRDDeposit(account, fmt, account.getActivationLocalDate(),
|
||||||
amountForDeposit.getAmount(), null, isRegularTransaction);
|
amountForDeposit.getAmount(), null, isRegularTransaction);
|
||||||
|
|||||||
+85
-87
@@ -33,6 +33,7 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
|
|||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||||
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
|
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
|
||||||
|
import org.mifosplatform.portfolio.account.domain.AccountAssociationType;
|
||||||
import org.mifosplatform.portfolio.account.domain.AccountAssociations;
|
import org.mifosplatform.portfolio.account.domain.AccountAssociations;
|
||||||
import org.mifosplatform.portfolio.account.domain.AccountAssociationsRepository;
|
import org.mifosplatform.portfolio.account.domain.AccountAssociationsRepository;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||||
@@ -115,8 +116,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
final FixedDepositAccountRepository fixedDepositAccountRepository,
|
final FixedDepositAccountRepository fixedDepositAccountRepository,
|
||||||
final RecurringDepositAccountRepository recurringDepositAccountRepository,
|
final RecurringDepositAccountRepository recurringDepositAccountRepository,
|
||||||
final AccountAssociationsRepository accountAssociationsRepository, final FromJsonHelper fromJsonHelper,
|
final AccountAssociationsRepository accountAssociationsRepository, final FromJsonHelper fromJsonHelper,
|
||||||
final CalendarInstanceRepository calendarInstanceRepository,
|
final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService) {
|
||||||
final ConfigurationDomainService configurationDomainService) {
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.savingAccountRepository = savingAccountRepository;
|
this.savingAccountRepository = savingAccountRepository;
|
||||||
this.depositAccountAssembler = depositAccountAssembler;
|
this.depositAccountAssembler = depositAccountAssembler;
|
||||||
@@ -173,9 +173,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
final AppUser submittedBy = this.context.authenticatedUser();
|
final AppUser submittedBy = this.context.authenticatedUser();
|
||||||
|
|
||||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||||
final Integer financialYearBeginningMonth = this.configurationDomainService
|
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||||
.retrieveFinancialYearBeginningMonth();
|
|
||||||
|
|
||||||
final FixedDepositAccount account = (FixedDepositAccount) this.depositAccountAssembler.assembleFrom(command, submittedBy,
|
final FixedDepositAccount account = (FixedDepositAccount) this.depositAccountAssembler.assembleFrom(command, submittedBy,
|
||||||
DepositAccountType.FIXED_DEPOSIT);
|
DepositAccountType.FIXED_DEPOSIT);
|
||||||
@@ -183,8 +182,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
final MathContext mc = MathContext.DECIMAL64;
|
final MathContext mc = MathContext.DECIMAL64;
|
||||||
final boolean isPreMatureClosure = false;
|
final boolean isPreMatureClosure = false;
|
||||||
|
|
||||||
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
|
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
financialYearBeginningMonth);
|
||||||
this.fixedDepositAccountRepository.save(account);
|
this.fixedDepositAccountRepository.save(account);
|
||||||
|
|
||||||
if (account.isAccountNumberRequiresAutoGeneration()) {
|
if (account.isAccountNumberRequiresAutoGeneration()) {
|
||||||
@@ -201,7 +200,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(savingsAccountId,
|
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(savingsAccountId,
|
||||||
DepositAccountType.SAVINGS_DEPOSIT);
|
DepositAccountType.SAVINGS_DEPOSIT);
|
||||||
this.depositAccountDataValidator.validatelinkedSavingsAccount(savingsAccount, account);
|
this.depositAccountDataValidator.validatelinkedSavingsAccount(savingsAccount, account);
|
||||||
final AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(account, savingsAccount);
|
final AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(account, savingsAccount,
|
||||||
|
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||||
this.accountAssociationsRepository.save(accountAssociations);
|
this.accountAssociationsRepository.save(accountAssociations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +229,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
final AppUser submittedBy = this.context.authenticatedUser();
|
final AppUser submittedBy = this.context.authenticatedUser();
|
||||||
|
|
||||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||||
final Integer financialYearBeginningMonth = this.configurationDomainService
|
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||||
.retrieveFinancialYearBeginningMonth();
|
|
||||||
|
|
||||||
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(command,
|
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(command,
|
||||||
submittedBy, DepositAccountType.RECURRING_DEPOSIT);
|
submittedBy, DepositAccountType.RECURRING_DEPOSIT);
|
||||||
@@ -257,8 +256,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
frequency = frequency == -1 ? 1 : frequency;
|
frequency = frequency == -1 ? 1 : frequency;
|
||||||
account.generateSchedule(frequencyType, frequency, calendar);
|
account.generateSchedule(frequencyType, frequency, calendar);
|
||||||
final boolean isPreMatureClosure = false;
|
final boolean isPreMatureClosure = false;
|
||||||
account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
|
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
financialYearBeginningMonth);
|
||||||
account.validateApplicableInterestRate();
|
account.validateApplicableInterestRate();
|
||||||
this.savingAccountRepository.save(account);
|
this.savingAccountRepository.save(account);
|
||||||
|
|
||||||
@@ -336,9 +335,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
this.depositAccountDataValidator.validateFixedDepositForUpdate(command.json());
|
this.depositAccountDataValidator.validateFixedDepositForUpdate(command.json());
|
||||||
|
|
||||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||||
final Integer financialYearBeginningMonth = this.configurationDomainService
|
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||||
.retrieveFinancialYearBeginningMonth();
|
|
||||||
|
|
||||||
final Map<String, Object> changes = new LinkedHashMap<>(20);
|
final Map<String, Object> changes = new LinkedHashMap<>(20);
|
||||||
|
|
||||||
@@ -353,79 +351,10 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
final MathContext mc = MathContext.DECIMAL64;
|
final MathContext mc = MathContext.DECIMAL64;
|
||||||
final boolean isPreMatureClosure = false;
|
final boolean isPreMatureClosure = false;
|
||||||
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
|
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
|
||||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||||
this.savingAccountRepository.save(account);
|
this.savingAccountRepository.save(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
|
||||||
.withCommandId(command.commandId()) //
|
|
||||||
.withEntityId(accountId) //
|
|
||||||
.withOfficeId(account.officeId()) //
|
|
||||||
.withClientId(account.clientId()) //
|
|
||||||
.withGroupId(account.groupId()) //
|
|
||||||
.withSavingsId(accountId) //
|
|
||||||
.with(changes) //
|
|
||||||
.build();
|
|
||||||
} catch (final DataAccessException dve) {
|
|
||||||
handleDataIntegrityIssues(command, dve);
|
|
||||||
return new CommandProcessingResult(Long.valueOf(-1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional
|
|
||||||
@Override
|
|
||||||
public CommandProcessingResult modifyRDApplication(final Long accountId, final JsonCommand command) {
|
|
||||||
try {
|
|
||||||
this.depositAccountDataValidator.validateRecurringDepositForUpdate(command.json());
|
|
||||||
|
|
||||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
|
||||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
|
||||||
final Integer financialYearBeginningMonth = this.configurationDomainService
|
|
||||||
.retrieveFinancialYearBeginningMonth();
|
|
||||||
|
|
||||||
final Map<String, Object> changes = new LinkedHashMap<>(20);
|
|
||||||
|
|
||||||
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(accountId,
|
|
||||||
DepositAccountType.RECURRING_DEPOSIT);
|
|
||||||
checkClientOrGroupActive(account);
|
|
||||||
account.modifyApplication(command, changes);
|
|
||||||
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), DepositAccountType.RECURRING_DEPOSIT.resourceName());
|
|
||||||
|
|
||||||
if (!changes.isEmpty()) {
|
|
||||||
updateFDAndRDCommonChanges(changes, command, account);
|
|
||||||
final MathContext mc = MathContext.DECIMAL64;
|
|
||||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
|
||||||
accountId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
|
|
||||||
final Calendar calendar = calendarInstance.getCalendar();
|
|
||||||
final PeriodFrequencyType frequencyType = CalendarFrequencyType.from(CalendarUtils.getFrequency(calendar.getRecurrence()));
|
|
||||||
Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence());
|
|
||||||
frequency = frequency == -1 ? 1 : frequency;
|
|
||||||
account.generateSchedule(frequencyType, frequency, calendar);
|
|
||||||
final boolean isPreMatureClosure = false;
|
|
||||||
account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
|
|
||||||
isSavingsInterestPostingAtCurrentPeriodEnd,
|
|
||||||
financialYearBeginningMonth);
|
|
||||||
account.validateApplicableInterestRate();
|
|
||||||
this.savingAccountRepository.save(account);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// update calendar details
|
|
||||||
if (!account.isCalendarInherited()) {
|
|
||||||
final LocalDate calendarStartDate = account.depositStartDate();
|
|
||||||
final Integer frequencyType = command.integerValueSansLocaleOfParameterNamed(recurringFrequencyTypeParamName);
|
|
||||||
final PeriodFrequencyType periodFrequencyType = PeriodFrequencyType.fromInt(frequencyType);
|
|
||||||
final Integer frequency = command.integerValueSansLocaleOfParameterNamed(recurringFrequencyParamName);
|
|
||||||
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
|
|
||||||
|
|
||||||
CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
|
||||||
accountId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
|
|
||||||
Calendar calendar = calendarInstance.getCalendar();
|
|
||||||
calendar.updateRepeatingCalendar(calendarStartDate, CalendarFrequencyType.from(periodFrequencyType), frequency,
|
|
||||||
repeatsOnDay);
|
|
||||||
this.calendarInstanceRepository.save(calendarInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isLinkedAccRequired = command.booleanPrimitiveValueOfParameterNamed(transferInterestToSavingsParamName);
|
boolean isLinkedAccRequired = command.booleanPrimitiveValueOfParameterNamed(transferInterestToSavingsParamName);
|
||||||
|
|
||||||
// Save linked account information
|
// Save linked account information
|
||||||
@@ -458,7 +387,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
DepositAccountType.SAVINGS_DEPOSIT);
|
DepositAccountType.SAVINGS_DEPOSIT);
|
||||||
this.depositAccountDataValidator.validatelinkedSavingsAccount(savingsAccount, account);
|
this.depositAccountDataValidator.validatelinkedSavingsAccount(savingsAccount, account);
|
||||||
if (accountAssociations == null) {
|
if (accountAssociations == null) {
|
||||||
accountAssociations = AccountAssociations.associateSavingsAccount(account, savingsAccount);
|
accountAssociations = AccountAssociations.associateSavingsAccount(account, savingsAccount,
|
||||||
|
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||||
} else {
|
} else {
|
||||||
accountAssociations.updateLinkedSavingsAccount(savingsAccount);
|
accountAssociations.updateLinkedSavingsAccount(savingsAccount);
|
||||||
}
|
}
|
||||||
@@ -482,6 +412,74 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult modifyRDApplication(final Long accountId, final JsonCommand command) {
|
||||||
|
try {
|
||||||
|
this.depositAccountDataValidator.validateRecurringDepositForUpdate(command.json());
|
||||||
|
|
||||||
|
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||||
|
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||||
|
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||||
|
|
||||||
|
final Map<String, Object> changes = new LinkedHashMap<>(20);
|
||||||
|
|
||||||
|
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(accountId,
|
||||||
|
DepositAccountType.RECURRING_DEPOSIT);
|
||||||
|
checkClientOrGroupActive(account);
|
||||||
|
account.modifyApplication(command, changes);
|
||||||
|
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), DepositAccountType.RECURRING_DEPOSIT.resourceName());
|
||||||
|
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
updateFDAndRDCommonChanges(changes, command, account);
|
||||||
|
final MathContext mc = MathContext.DECIMAL64;
|
||||||
|
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
||||||
|
accountId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
|
||||||
|
final Calendar calendar = calendarInstance.getCalendar();
|
||||||
|
final PeriodFrequencyType frequencyType = CalendarFrequencyType.from(CalendarUtils.getFrequency(calendar.getRecurrence()));
|
||||||
|
Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence());
|
||||||
|
frequency = frequency == -1 ? 1 : frequency;
|
||||||
|
account.generateSchedule(frequencyType, frequency, calendar);
|
||||||
|
final boolean isPreMatureClosure = false;
|
||||||
|
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||||
|
financialYearBeginningMonth);
|
||||||
|
account.validateApplicableInterestRate();
|
||||||
|
this.savingAccountRepository.save(account);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// update calendar details
|
||||||
|
if (!account.isCalendarInherited()) {
|
||||||
|
final LocalDate calendarStartDate = account.depositStartDate();
|
||||||
|
final Integer frequencyType = command.integerValueSansLocaleOfParameterNamed(recurringFrequencyTypeParamName);
|
||||||
|
final PeriodFrequencyType periodFrequencyType = PeriodFrequencyType.fromInt(frequencyType);
|
||||||
|
final Integer frequency = command.integerValueSansLocaleOfParameterNamed(recurringFrequencyParamName);
|
||||||
|
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
|
||||||
|
|
||||||
|
CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
||||||
|
accountId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
|
||||||
|
Calendar calendar = calendarInstance.getCalendar();
|
||||||
|
calendar.updateRepeatingCalendar(calendarStartDate, CalendarFrequencyType.from(periodFrequencyType), frequency,
|
||||||
|
repeatsOnDay);
|
||||||
|
this.calendarInstanceRepository.save(calendarInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(accountId) //
|
||||||
|
.withOfficeId(account.officeId()) //
|
||||||
|
.withClientId(account.clientId()) //
|
||||||
|
.withGroupId(account.groupId()) //
|
||||||
|
.withSavingsId(accountId) //
|
||||||
|
.with(changes) //
|
||||||
|
.build();
|
||||||
|
} catch (final DataAccessException dve) {
|
||||||
|
handleDataIntegrityIssues(command, dve);
|
||||||
|
return new CommandProcessingResult(Long.valueOf(-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateFDAndRDCommonChanges(final Map<String, Object> changes, final JsonCommand command, final SavingsAccount account) {
|
private void updateFDAndRDCommonChanges(final Map<String, Object> changes, final JsonCommand command, final SavingsAccount account) {
|
||||||
|
|
||||||
if (changes.containsKey(SavingsApiConstants.clientIdParamName)) {
|
if (changes.containsKey(SavingsApiConstants.clientIdParamName)) {
|
||||||
|
|||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
ALTER TABLE `m_savings_account`
|
||||||
|
ADD COLUMN `on_hold_funds_derived` DECIMAL(19,6) NULL DEFAULT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `m_portfolio_account_associations`
|
||||||
|
ADD COLUMN `association_type_enum` SMALLINT(1) NOT NULL DEFAULT '1';
|
||||||
|
|
||||||
|
CREATE TABLE `m_product_loan_guarantee_details` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`loan_product_id` BIGINT(20) NOT NULL,
|
||||||
|
`mandatory_guarantee` DECIMAL(19,5) NOT NULL,
|
||||||
|
`minimum_guarantee_from_own_funds` DECIMAL(19,5) NULL,
|
||||||
|
`minimum_guarantee_from_guarantor_funds` DECIMAL(19,5) NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
CONSTRAINT `FK_guarantee_details_loan_product` FOREIGN KEY (`loan_product_id`) REFERENCES `m_product_loan` (`id`)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `m_product_loan`
|
||||||
|
ADD COLUMN `hold_guarantee_funds` TINYINT(1) NOT NULL DEFAULT '0';
|
||||||
Reference in New Issue
Block a user