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;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
@@ -18,14 +19,17 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
@Table(name = "m_portfolio_account_associations")
|
||||
public class AccountAssociations extends AbstractPersistable<Long> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_account_id", nullable = true)
|
||||
private Loan loanAccount;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "savings_account_id", nullable = true)
|
||||
private SavingsAccount savingsAccount;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "linked_loan_account_id", nullable = true)
|
||||
private Loan linkedLoanAccount;
|
||||
@@ -34,22 +38,29 @@ public class AccountAssociations extends AbstractPersistable<Long> {
|
||||
@JoinColumn(name = "linked_savings_account_id", nullable = true)
|
||||
private SavingsAccount linkedSavingsAccount;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "association_type_enum", nullable = false)
|
||||
private Integer associationType;
|
||||
|
||||
protected AccountAssociations() {}
|
||||
|
||||
private AccountAssociations(final Loan loanAccount, final SavingsAccount savingsAccount, final Loan linkedLoanAccount,
|
||||
final SavingsAccount linkedSavingsAccount) {
|
||||
final SavingsAccount linkedSavingsAccount, final Integer associationType) {
|
||||
this.loanAccount = loanAccount;
|
||||
this.savingsAccount = savingsAccount;
|
||||
this.linkedLoanAccount = linkedLoanAccount;
|
||||
this.linkedSavingsAccount = linkedSavingsAccount;
|
||||
this.associationType = associationType;
|
||||
}
|
||||
|
||||
public static AccountAssociations associateSavingsAccount(final Loan loan, final SavingsAccount savingsAccount) {
|
||||
return new AccountAssociations(loan, null, null, savingsAccount);
|
||||
public static AccountAssociations associateSavingsAccount(final Loan loan, final SavingsAccount savingsAccount,
|
||||
final Integer associationType) {
|
||||
return new AccountAssociations(loan, null, null, savingsAccount, associationType);
|
||||
}
|
||||
|
||||
public static AccountAssociations associateSavingsAccount(final SavingsAccount savingsAccount, final SavingsAccount linkedSavingsAccount) {
|
||||
return new AccountAssociations(null, savingsAccount, null, linkedSavingsAccount);
|
||||
public static AccountAssociations associateSavingsAccount(final SavingsAccount savingsAccount,
|
||||
final SavingsAccount linkedSavingsAccount, final Integer associationType) {
|
||||
return new AccountAssociations(null, savingsAccount, null, linkedSavingsAccount, associationType);
|
||||
}
|
||||
|
||||
public SavingsAccount linkedSavingsAccount() {
|
||||
|
||||
+7
-2
@@ -5,13 +5,18 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.account.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.account.data.AccountAssociationsData;
|
||||
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||
|
||||
public interface AccountAssociationsReadPlatformService {
|
||||
|
||||
public PortfolioAccountData retriveLoanAssociation(final Long loanId);
|
||||
public PortfolioAccountData retriveLoanLinkedAssociation(final Long loanId);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+25
-9
@@ -7,12 +7,14 @@ package org.mifosplatform.portfolio.account.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.portfolio.account.data.AccountAssociationsData;
|
||||
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.savings.domain.SavingsAccountStatusType;
|
||||
import org.slf4j.Logger;
|
||||
@@ -35,12 +37,13 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
|
||||
}
|
||||
|
||||
@Override
|
||||
public PortfolioAccountData retriveLoanAssociation(final Long loanId) {
|
||||
public PortfolioAccountData retriveLoanLinkedAssociation(final Long loanId) {
|
||||
PortfolioAccountData linkedAccount = null;
|
||||
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 {
|
||||
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) {
|
||||
linkedAccount = accountAssociationsData.linkedAccount();
|
||||
}
|
||||
@@ -49,14 +52,27 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
|
||||
}
|
||||
return linkedAccount;
|
||||
}
|
||||
|
||||
|
||||
@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;
|
||||
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 {
|
||||
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) {
|
||||
linkedAccount = accountAssociationsData.linkedAccount();
|
||||
}
|
||||
@@ -74,7 +90,7 @@ public class AccountAssociationsReadPlatformServiceImpl implements AccountAssoci
|
||||
|
||||
final List<Integer> statusList = this.jdbcTemplate.queryForList(sql, Integer.class, savingsId);
|
||||
for (final Integer status : statusList) {
|
||||
if(status !=null){
|
||||
if (status != null) {
|
||||
final LoanStatus loanStatus = LoanStatus.fromInt(status);
|
||||
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);
|
||||
for (final Integer status : savstatusList) {
|
||||
if(status !=null){
|
||||
if (status != null) {
|
||||
final SavingsAccountStatusType saveStatus = SavingsAccountStatusType.fromInt(status);
|
||||
if (saveStatus.isActiveOrAwaitingApprovalOrDisbursal() || saveStatus.isUnderTransfer()) { return true; }
|
||||
}
|
||||
|
||||
+2
-2
@@ -405,7 +405,7 @@ public class LoansApiResource {
|
||||
|
||||
if (associationParameters.contains("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")) {
|
||||
mandatoryResponseParameters.add("linkedAccount");
|
||||
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
||||
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||
}
|
||||
if (loanBasicDetails.groupId() != null) {
|
||||
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.security.service.PlatformSecurityContext;
|
||||
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.AccountAssociationsRepository;
|
||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||
@@ -254,7 +255,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
|
||||
final AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication,
|
||||
savingsAccount);
|
||||
savingsAccount, AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||
this.accountAssociationsRepository.save(accountAssociations);
|
||||
}
|
||||
|
||||
@@ -589,7 +590,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, existingLoanApplication);
|
||||
if (accountAssociations == null) {
|
||||
accountAssociations = AccountAssociations.associateSavingsAccount(existingLoanApplication, savingsAccount);
|
||||
accountAssociations = AccountAssociations.associateSavingsAccount(existingLoanApplication, savingsAccount,
|
||||
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||
} else {
|
||||
accountAssociations.updateLinkedSavingsAccount(savingsAccount);
|
||||
}
|
||||
|
||||
+8
-8
@@ -361,7 +361,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
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 boolean isRegularTransaction = true;
|
||||
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate, entrySet.getValue(),
|
||||
@@ -560,7 +560,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
||||
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan
|
||||
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loan
|
||||
.getId());
|
||||
final SavingsAccount fromSavingsAccount = null;
|
||||
final boolean isRegularTransaction = true;
|
||||
@@ -1312,7 +1312,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
|
||||
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loan
|
||||
.getId());
|
||||
if (portfolioAccountData == null) {
|
||||
final String errorMessage = loanCharge.name() + "Charge requires linked savings account for payment";
|
||||
@@ -1579,7 +1579,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
amount = chargePerInstallment.getAmountOutstanding();
|
||||
}
|
||||
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||
if (portfolioAccountData == null) {
|
||||
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
|
||||
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
|
||||
@@ -1609,7 +1609,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
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) {
|
||||
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());
|
||||
@@ -1641,7 +1641,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
|
||||
if (!installmentChargeData.getDueDate().isAfter(new LocalDate())) {
|
||||
if (portfolioAccountData == null) {
|
||||
portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(chargeData
|
||||
portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(chargeData
|
||||
.getLoanId());
|
||||
}
|
||||
final SavingsAccount fromSavingsAccount = null;
|
||||
@@ -1656,7 +1656,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(new LocalDate())) {
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||
.retriveLoanAssociation(chargeData.getLoanId());
|
||||
.retriveLoanLinkedAssociation(chargeData.getLoanId());
|
||||
final SavingsAccount fromSavingsAccount = null;
|
||||
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(),
|
||||
chargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
|
||||
@@ -2469,7 +2469,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
amount = chargePerInstallment.getAmountOutstanding();
|
||||
}
|
||||
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||
if (portfolioAccountData == null) {
|
||||
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
|
||||
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 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";
|
||||
|
||||
}
|
||||
|
||||
+21
-6
@@ -135,6 +135,9 @@ public class LoanProductData {
|
||||
private final Integer maxTrancheCount;
|
||||
private final BigDecimal outstandingLoanBalance;
|
||||
|
||||
private final Boolean holdGuaranteeFunds;
|
||||
private final LoanProductGuaranteeData productGuaranteeData;
|
||||
|
||||
/**
|
||||
* Used when returning lookup information about loan product for dropdowns.
|
||||
*/
|
||||
@@ -182,6 +185,8 @@ public class LoanProductData {
|
||||
final Boolean multiDisburseLoan = null;
|
||||
final Integer maxTrancheCount = null;
|
||||
final BigDecimal outstandingLoanBalance = null;
|
||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||
final Boolean holdGuaranteeFunds = false;
|
||||
|
||||
final EnumOptionData daysInMonthType = null;
|
||||
final EnumOptionData daysInYearType = null;
|
||||
@@ -197,7 +202,7 @@ public class LoanProductData {
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment);
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData);
|
||||
}
|
||||
|
||||
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 LoanProductInterestRecalculationData interestRecalculationData = 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,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -260,7 +267,7 @@ public class LoanProductData {
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment);
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData);
|
||||
}
|
||||
|
||||
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
|
||||
@@ -321,7 +328,8 @@ public class LoanProductData {
|
||||
final LoanProductInterestRecalculationData interestRecalculationData = LoanProductInterestRecalculationData
|
||||
.sensibleDefaultsForNewLoanProductCreation();
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||
|
||||
final Boolean holdGuaranteeFunds = false;
|
||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -331,7 +339,8 @@ public class LoanProductData {
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId,
|
||||
principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle,
|
||||
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,
|
||||
@@ -362,7 +371,8 @@ public class LoanProductData {
|
||||
Integer maxTrancheCount, BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing,
|
||||
final Integer overdueDaysForNPA, final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType,
|
||||
final boolean isInterestRecalculationEnabled, final LoanProductInterestRecalculationData interestRecalculationData,
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, boolean holdGuaranteeFunds,
|
||||
LoanProductGuaranteeData loanProductGuaranteeData) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -433,12 +443,15 @@ public class LoanProductData {
|
||||
this.daysInYearType = daysInYearType;
|
||||
this.isInterestRecalculationEnabled = isInterestRecalculationEnabled;
|
||||
this.interestRecalculationData = interestRecalculationData;
|
||||
this.holdGuaranteeFunds = holdGuaranteeFunds;
|
||||
this.productGuaranteeData = loanProductGuaranteeData;
|
||||
|
||||
this.daysInMonthTypeOptions = null;
|
||||
this.daysInYearTypeOptions = null;
|
||||
this.interestRecalculationCompoundingTypeOptions = null;
|
||||
this.rescheduleStrategyTypeOptions = null;
|
||||
this.interestRecalculationFrequencyTypeOptions = null;
|
||||
|
||||
}
|
||||
|
||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||
@@ -515,7 +528,7 @@ public class LoanProductData {
|
||||
this.multiDisburseLoan = productData.multiDisburseLoan;
|
||||
this.maxTrancheCount = productData.maxTrancheCount;
|
||||
this.outstandingLoanBalance = productData.outstandingLoanBalance;
|
||||
this.minimumDaysBetweenDisbursalAndFirstRepayment = productData.minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
this.minimumDaysBetweenDisbursalAndFirstRepayment = productData.minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
|
||||
this.amortizationTypeOptions = amortizationTypeOptions;
|
||||
this.interestTypeOptions = interestTypeOptions;
|
||||
@@ -533,6 +546,8 @@ public class LoanProductData {
|
||||
this.daysInYearType = productData.daysInYearType;
|
||||
this.isInterestRecalculationEnabled = productData.isInterestRecalculationEnabled;
|
||||
this.interestRecalculationData = productData.interestRecalculationData;
|
||||
this.holdGuaranteeFunds = productData.holdGuaranteeFunds;
|
||||
this.productGuaranteeData = productData.productGuaranteeData;
|
||||
|
||||
this.daysInMonthTypeOptions = daysInMonthTypeOptions;
|
||||
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)
|
||||
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,
|
||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
||||
|
||||
@@ -211,6 +218,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
if (isInterestRecalculationEnabled) {
|
||||
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,
|
||||
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
||||
annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType,
|
||||
@@ -218,12 +232,18 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle,
|
||||
startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount,
|
||||
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment);
|
||||
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||
holdGuarantorFunds, loanProductGuaranteeDetails);
|
||||
|
||||
}
|
||||
|
||||
public void updateLoanProductForInterestRecalculationDetails() {
|
||||
this.productInterestRecalculationDetails.updateProduct(this);
|
||||
public void updateLoanProductInRelatedClasses() {
|
||||
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 boolean isInterestRecalculationEnabled,
|
||||
final LoanProductInterestRecalculationDetails productInterestRecalculationDetails,
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final boolean holdGuarantorFunds,
|
||||
final LoanProductGuaranteeDetails loanProductGuaranteeDetails) {
|
||||
this.fund = fund;
|
||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||
this.name = name.trim();
|
||||
@@ -487,6 +508,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
this.overdueDaysForNPA = overdueDaysForNPA;
|
||||
this.productInterestRecalculationDetails = productInterestRecalculationDetails;
|
||||
this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
this.holdGuaranteeFunds = holdGuarantorFunds;
|
||||
this.loanProductGuaranteeDetails = loanProductGuaranteeDetails;
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
@@ -690,6 +713,30 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -929,4 +976,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
public LoanProductInterestRecalculationDetails getProductInterestRecalculationDetails() {
|
||||
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.recalculationRestFrequencyIntervalParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
||||
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment));
|
||||
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, LoanProductConstants.mandatoryGuaranteeParamName,
|
||||
LoanProductConstants.holdGuaranteeFundsParamName, LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||
LoanProductConstants.minimumGuaranteeFromOwnFundsParamName));
|
||||
|
||||
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
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 4);
|
||||
@@ -704,16 +720,31 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
|
||||
// Interest recalculation settings
|
||||
Boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled();
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.isInterestRecalculationEnabledParameterName, element)) {
|
||||
final Boolean isInterestRecalculationEnabled = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
isInterestRecalculationEnabled = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
LoanProductConstants.isInterestRecalculationEnabledParameterName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.isInterestRecalculationEnabledParameterName)
|
||||
.value(isInterestRecalculationEnabled).notNull().isOneOfTheseValues(true, false);
|
||||
}
|
||||
|
||||
if (isInterestRecalculationEnabled != null) {
|
||||
if (isInterestRecalculationEnabled.booleanValue()) {
|
||||
validateInterestRecalculationParams(element, baseDataValidator, loanProduct);
|
||||
}
|
||||
if (isInterestRecalculationEnabled != null) {
|
||||
if (isInterestRecalculationEnabled) {
|
||||
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.loanproduct.data.LoanProductBorrowerCycleVariationData;
|
||||
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.domain.LoanProductParamType;
|
||||
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.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
||||
+ "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 "
|
||||
+ " from m_product_loan lp "
|
||||
+ " 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_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"
|
||||
+ " 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 graceOnArrearsAgeing = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnArrearsAgeing");
|
||||
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 EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId);
|
||||
@@ -256,6 +262,17 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
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,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
|
||||
@@ -265,7 +282,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
|
||||
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
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,
|
||||
this.aprCalculator);
|
||||
if (loanproduct.isInterestRecalculationEnabled()) {
|
||||
loanproduct.updateLoanProductForInterestRecalculationDetails();
|
||||
}
|
||||
loanproduct.updateLoanProductInRelatedClasses();
|
||||
|
||||
this.loanProductRepository.save(loanproduct);
|
||||
|
||||
|
||||
+1
-1
@@ -209,7 +209,7 @@ public class FixedDepositAccountsApiResource {
|
||||
|
||||
if (associationParameters.contains(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)
|
||||
private BigDecimal minRequiredBalance;
|
||||
|
||||
@Column(name = "on_hold_funds_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal onHoldFunds;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "start_interest_calculation_date")
|
||||
protected Date startInterestCalculationDate;
|
||||
@@ -854,6 +857,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount, final boolean isWithdrawBalance) {
|
||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||
Money runningBalance = Money.zero(this.currency);
|
||||
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
||||
if (transaction.isNotReversed() && transaction.isCredit()) {
|
||||
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
||||
@@ -866,21 +870,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final BigDecimal withdrawalFee = null;
|
||||
// deal with potential minRequiredBalance and
|
||||
// enforceMinRequiredBalance
|
||||
if (!isWithdrawBalance && this.minRequiredBalance != null && this.enforceMinRequiredBalance && transaction.isWithdrawal()) {
|
||||
if (runningBalance.minus(this.minRequiredBalance).isLessThanZero()) { throw new InsufficientAccountBalanceException(
|
||||
if (!isWithdrawBalance && transaction.isDebit()) {
|
||||
if (runningBalance.minus(minRequiredBalance).isLessThanZero()) { throw new InsufficientAccountBalanceException(
|
||||
"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();
|
||||
Money runningBalance = Money.zero(this.currency);
|
||||
|
||||
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
||||
if (transaction.isNotReversed() && transaction.isCredit()) {
|
||||
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
||||
@@ -896,24 +890,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
||||
}
|
||||
|
||||
if (runningBalance.isLessThanZero()) {
|
||||
//
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(depositAccountType()
|
||||
.resourceName() + transactionAction);
|
||||
|
||||
if (this.allowOverdraft) {
|
||||
Money limit = runningBalance.zero();
|
||||
if (this.overdraftLimit != null) {
|
||||
limit = limit.plus(this.overdraftLimit);
|
||||
}
|
||||
if (limit.plus(runningBalance).isLessThanZero()) {
|
||||
// enforceMinRequiredBalance
|
||||
if (transaction.isDebit()) {
|
||||
if (runningBalance.minus(minRequiredBalance).isLessThanZero()) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(depositAccountType().resourceName() + transactionAction);
|
||||
if (this.allowOverdraft) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.exceeding.overdraft.limit");
|
||||
} else {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative");
|
||||
}
|
||||
} else {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2430,4 +2420,15 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
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;
|
||||
if (command.parameterExists(overdraftLimitParamName)) {
|
||||
if (command.parameterExists(minRequiredBalanceParamName)) {
|
||||
minRequiredBalance = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minRequiredBalanceParamName);
|
||||
} else {
|
||||
minRequiredBalance = product.minRequiredBalance();
|
||||
|
||||
+2
-2
@@ -196,7 +196,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
if (amountForDeposit.isGreaterThanZero()) {
|
||||
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||
.retriveSavingsAssociation(savingsId);
|
||||
.retriveSavingsLinkedAssociation(savingsId);
|
||||
|
||||
if (portfolioAccountData == null) {
|
||||
final PaymentDetail paymentDetail = null;
|
||||
@@ -274,7 +274,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
Money amountForDeposit = account.activateWithBalance();
|
||||
if (amountForDeposit.isGreaterThanZero()) {
|
||||
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||
.retriveSavingsAssociation(savingsId);
|
||||
.retriveSavingsLinkedAssociation(savingsId);
|
||||
if (portfolioAccountData == null) {
|
||||
this.depositAccountDomainService.handleRDDeposit(account, fmt, account.getActivationLocalDate(),
|
||||
amountForDeposit.getAmount(), null, isRegularTransaction);
|
||||
|
||||
+88
-90
@@ -33,6 +33,7 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
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.AccountAssociationsRepository;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
@@ -115,8 +116,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
final FixedDepositAccountRepository fixedDepositAccountRepository,
|
||||
final RecurringDepositAccountRepository recurringDepositAccountRepository,
|
||||
final AccountAssociationsRepository accountAssociationsRepository, final FromJsonHelper fromJsonHelper,
|
||||
final CalendarInstanceRepository calendarInstanceRepository,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
this.depositAccountAssembler = depositAccountAssembler;
|
||||
@@ -171,11 +171,10 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
try {
|
||||
this.depositAccountDataValidator.validateFixedDepositForSubmit(command.json());
|
||||
final AppUser submittedBy = this.context.authenticatedUser();
|
||||
|
||||
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService
|
||||
.retrieveFinancialYearBeginningMonth();
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
final FixedDepositAccount account = (FixedDepositAccount) this.depositAccountAssembler.assembleFrom(command, submittedBy,
|
||||
DepositAccountType.FIXED_DEPOSIT);
|
||||
@@ -183,8 +182,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
final boolean isPreMatureClosure = false;
|
||||
|
||||
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth);
|
||||
this.fixedDepositAccountRepository.save(account);
|
||||
|
||||
if (account.isAccountNumberRequiresAutoGeneration()) {
|
||||
@@ -201,7 +200,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(savingsAccountId,
|
||||
DepositAccountType.SAVINGS_DEPOSIT);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -227,11 +227,10 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
try {
|
||||
this.depositAccountDataValidator.validateRecurringDepositForSubmit(command.json());
|
||||
final AppUser submittedBy = this.context.authenticatedUser();
|
||||
|
||||
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService
|
||||
.retrieveFinancialYearBeginningMonth();
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(command,
|
||||
submittedBy, DepositAccountType.RECURRING_DEPOSIT);
|
||||
@@ -257,8 +256,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
frequency = frequency == -1 ? 1 : frequency;
|
||||
account.generateSchedule(frequencyType, frequency, calendar);
|
||||
final boolean isPreMatureClosure = false;
|
||||
account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth);
|
||||
account.validateApplicableInterestRate();
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
@@ -334,11 +333,10 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
public CommandProcessingResult modifyFDApplication(final Long accountId, final JsonCommand command) {
|
||||
try {
|
||||
this.depositAccountDataValidator.validateFixedDepositForUpdate(command.json());
|
||||
|
||||
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService
|
||||
.retrieveFinancialYearBeginningMonth();
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<>(20);
|
||||
|
||||
@@ -353,79 +351,10 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
final boolean isPreMatureClosure = false;
|
||||
account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
|
||||
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);
|
||||
|
||||
// Save linked account information
|
||||
@@ -458,7 +387,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
DepositAccountType.SAVINGS_DEPOSIT);
|
||||
this.depositAccountDataValidator.validatelinkedSavingsAccount(savingsAccount, account);
|
||||
if (accountAssociations == null) {
|
||||
accountAssociations = AccountAssociations.associateSavingsAccount(account, savingsAccount);
|
||||
accountAssociations = AccountAssociations.associateSavingsAccount(account, savingsAccount,
|
||||
AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
|
||||
} else {
|
||||
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) {
|
||||
|
||||
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