Merge pull request #446 from goutham-M/mifosx-499

reactivate feature is added
This commit is contained in:
Vishwas Babu A J
2013-07-11 07:33:08 -07:00
9 changed files with 175 additions and 18 deletions
@@ -0,0 +1,2 @@
alter table `m_product_loan` add column `start_date` DATE NULL DEFAULT NULL ,
add column `close_date` DATE NULL DEFAULT NULL ;
@@ -12,6 +12,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.api.JsonQuery; import org.mifosplatform.infrastructure.core.api.JsonQuery;
@@ -45,6 +46,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTrans
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus; import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper; import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted; import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified; import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException; import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
@@ -149,6 +151,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId); final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); } if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
validateSubmittedOnDate(command, loanProduct);
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator, loanProduct); this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator, loanProduct);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
@@ -539,4 +543,23 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
return loan; return loan;
} }
private void validateSubmittedOnDate(final JsonCommand command, final LoanProduct loanProduct) {
final LocalDate startDate = loanProduct.getStartDate();
final LocalDate closeDate = loanProduct.getCloseDate();
final LocalDate submittedOnDate = command.localDateValueOfParameterNamed("submittedOnDate");
String defaultUserMessage = "";
if (startDate != null && submittedOnDate.isBefore(startDate)) {
defaultUserMessage = "submittedOnDate cannot be before the loan product startDate.";
throw new LoanApplicationDateException("submitted.on.date.cannot.be.before.the.loan.product.start.date", defaultUserMessage,
submittedOnDate.toString(), startDate.toString());
}
if (closeDate != null && submittedOnDate.isAfter(closeDate)) {
defaultUserMessage = "submittedOnDate cannot be after the loan product closeDate.";
throw new LoanApplicationDateException("submitted.on.date.cannot.be.after.the.loan.product.close.date", defaultUserMessage,
submittedOnDate.toString(), closeDate.toString());
}
}
} }
@@ -11,6 +11,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.joda.time.LocalDate;
import org.mifosplatform.accounting.common.AccountingEnumerations; import org.mifosplatform.accounting.common.AccountingEnumerations;
import org.mifosplatform.accounting.common.AccountingRuleType; import org.mifosplatform.accounting.common.AccountingRuleType;
import org.mifosplatform.accounting.glaccount.data.GLAccountData; import org.mifosplatform.accounting.glaccount.data.GLAccountData;
@@ -38,7 +39,9 @@ public class LoanProductData {
private final Long fundId; private final Long fundId;
private final String fundName; private final String fundName;
private final boolean includeInBorrowerCycle; private final boolean includeInBorrowerCycle;
private final LocalDate startDate;
private final LocalDate closeDate;
private final String status;
// terms // terms
private final CurrencyData currency; private final CurrencyData currency;
private final BigDecimal principal; private final BigDecimal principal;
@@ -129,13 +132,15 @@ public class LoanProductData {
final Collection<ChargeData> charges = null; final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = null; final EnumOptionData accountingType = null;
final boolean includeInBorrowerCycle = false; final boolean includeInBorrowerCycle = false;
final LocalDate startDate = null;
final LocalDate closeDate = null;
final String status = null;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
accountingType, includeInBorrowerCycle); accountingType, includeInBorrowerCycle, startDate, closeDate, status);
} }
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) {
@@ -168,13 +173,16 @@ public class LoanProductData {
final Collection<ChargeData> charges = null; final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = null; final EnumOptionData accountingType = null;
final boolean includeInBorrowerCycle = false; final boolean includeInBorrowerCycle = false;
final LocalDate startDate = null;
final LocalDate closeDate = null;
final String status = null;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
accountingType, includeInBorrowerCycle); accountingType, includeInBorrowerCycle, startDate, closeDate, status);
} }
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() { public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
@@ -213,13 +221,16 @@ public class LoanProductData {
final Collection<ChargeData> charges = null; final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = AccountingEnumerations.accountingRuleType(AccountingRuleType.NONE); final EnumOptionData accountingType = AccountingEnumerations.accountingRuleType(AccountingRuleType.NONE);
final boolean includeInBorrowerCycle = false; final boolean includeInBorrowerCycle = false;
final LocalDate startDate = null;
final LocalDate closeDate = null;
final String status = null;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
accountingType, includeInBorrowerCycle); accountingType, includeInBorrowerCycle, startDate, closeDate, status);
} }
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings, public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
@@ -242,7 +253,8 @@ public class LoanProductData {
final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName, final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName,
final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName, final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final Collection<ChargeData> charges, final EnumOptionData accountingType, final boolean includeInBorrowerCycle) { final Collection<ChargeData> charges, final EnumOptionData accountingType, final boolean includeInBorrowerCycle,
final LocalDate startDate, final LocalDate closeDate, final String status) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.description = description; this.description = description;
@@ -274,6 +286,9 @@ public class LoanProductData {
this.charges = charges; this.charges = charges;
this.accountingRule = accountingType; this.accountingRule = accountingType;
this.includeInBorrowerCycle = includeInBorrowerCycle; this.includeInBorrowerCycle = includeInBorrowerCycle;
this.startDate = startDate;
this.closeDate = closeDate;
this.status = status;
this.chargeOptions = null; this.chargeOptions = null;
this.penaltyOptions = null; this.penaltyOptions = null;
@@ -325,6 +340,9 @@ public class LoanProductData {
this.amortizationType = productData.amortizationType; this.amortizationType = productData.amortizationType;
this.interestType = productData.interestType; this.interestType = productData.interestType;
this.interestCalculationPeriodType = productData.interestCalculationPeriodType; this.interestCalculationPeriodType = productData.interestCalculationPeriodType;
this.startDate = productData.startDate;
this.closeDate = productData.closeDate;
this.status = productData.status;
this.charges = nullIfEmpty(productData.charges()); this.charges = nullIfEmpty(productData.charges());
this.accountingRule = productData.accountingRule; this.accountingRule = productData.accountingRule;
@@ -6,6 +6,7 @@
package org.mifosplatform.portfolio.loanproduct.domain; package org.mifosplatform.portfolio.loanproduct.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -19,9 +20,12 @@ import javax.persistence.JoinTable;
import javax.persistence.ManyToMany; import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.accounting.common.AccountingRuleType; import org.mifosplatform.accounting.common.AccountingRuleType;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
@@ -76,6 +80,14 @@ public class LoanProduct extends AbstractPersistable<Long> {
@Column(name = "include_in_borrower_cycle") @Column(name = "include_in_borrower_cycle")
private boolean includeInBorrowerCycle; private boolean includeInBorrowerCycle;
@Column(name = "start_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date startDate;
@Column(name = "close_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date closeDate;
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) {
@@ -116,11 +128,14 @@ public class LoanProduct extends AbstractPersistable<Long> {
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule")); final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
final boolean includeInBorrowerCycle = command.booleanPrimitiveValueOfParameterNamed("includeInBorrowerCycle"); final boolean includeInBorrowerCycle = command.booleanPrimitiveValueOfParameterNamed("includeInBorrowerCycle");
final LocalDate startDate = command.localDateValueOfParameterNamed("startDate");
final LocalDate closeDate = command.localDateValueOfParameterNamed("closeDate");
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, description, currency, principal, minPrincipal, maxPrincipal, return new LoanProduct(fund, loanTransactionProcessingStrategy, name, description, currency, principal, minPrincipal, maxPrincipal,
interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate,
interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType, numberOfRepayments, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle); amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle, startDate, closeDate);
} }
protected LoanProduct() { protected LoanProduct() {
@@ -139,7 +154,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments, final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges,
final AccountingRuleType accountingRuleType, final boolean includeInBorrowerCycle) { final AccountingRuleType accountingRuleType, final boolean includeInBorrowerCycle, final LocalDate startDate,
final LocalDate closeDate) {
this.fund = fund; this.fund = fund;
this.transactionProcessingStrategy = transactionProcessingStrategy; this.transactionProcessingStrategy = transactionProcessingStrategy;
this.name = name.trim(); this.name = name.trim();
@@ -168,6 +184,14 @@ public class LoanProduct extends AbstractPersistable<Long> {
this.accountingRule = accountingRuleType.getValue(); this.accountingRule = accountingRuleType.getValue();
} }
this.includeInBorrowerCycle = includeInBorrowerCycle; this.includeInBorrowerCycle = includeInBorrowerCycle;
if (startDate != null) {
this.startDate = startDate.toDateMidnight().toDate();
}
if (closeDate != null) {
this.closeDate = closeDate.toDateMidnight().toDate();
}
} }
public MonetaryCurrency getCurrency() { public MonetaryCurrency getCurrency() {
@@ -270,6 +294,41 @@ public class LoanProduct extends AbstractPersistable<Long> {
this.includeInBorrowerCycle = newValue; this.includeInBorrowerCycle = newValue;
} }
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
final String localeParamName = "locale";
final String dateFormatParamName = "dateFormat";
final String startDateParamName = "startDate";
if (command.isChangeInLocalDateParameterNamed(startDateParamName, getStartDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName);
actualChanges.put(startDateParamName, valueAsInput);
actualChanges.put(dateFormatParamName, dateFormatAsInput);
actualChanges.put(localeParamName, localeAsInput);
final LocalDate newValue = command.localDateValueOfParameterNamed(startDateParamName);
if (newValue != null) {
this.startDate = newValue.toDate();
} else {
this.startDate = null;
}
}
final String closeDateParamName = "closeDate";
if (command.isChangeInLocalDateParameterNamed(closeDateParamName, getCloseDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(closeDateParamName);
actualChanges.put(closeDateParamName, valueAsInput);
actualChanges.put(dateFormatParamName, dateFormatAsInput);
actualChanges.put(localeParamName, localeAsInput);
final LocalDate newValue = command.localDateValueOfParameterNamed(closeDateParamName);
if (newValue != null) {
this.closeDate = newValue.toDate();
} else {
this.closeDate = null;
}
}
return actualChanges; return actualChanges;
} }
@@ -333,4 +392,21 @@ public class LoanProduct extends AbstractPersistable<Long> {
public boolean isIncludeInBorrowerCycle() { public boolean isIncludeInBorrowerCycle() {
return this.includeInBorrowerCycle; return this.includeInBorrowerCycle;
} }
public LocalDate getStartDate() {
LocalDate startLocalDate = null;
if (this.startDate != null) {
startLocalDate = LocalDate.fromDateFields(this.startDate);
}
return startLocalDate;
}
public LocalDate getCloseDate() {
LocalDate closeLocalDate = null;
if (this.closeDate != null) {
closeLocalDate = LocalDate.fromDateFields(this.closeDate);
}
return closeLocalDate;
}
} }
@@ -0,0 +1,13 @@
package org.mifosplatform.portfolio.loanproduct.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class LoanProductDateException extends AbstractPlatformDomainRuleException {
public LoanProductDateException(Object... defaultUserMessageArgs) {
super("error.msg.loan.product.close.date.cannot.be.before.start.date.close.date",
"Loan product close date cannot be before the start date", defaultUserMessageArgs);
}
}
@@ -38,12 +38,12 @@ public final class LoanProductDataValidator {
/** /**
* The parameters supported for this command. * The parameters supported for this command.
*/ */
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("locale", "name", "description", "fundId", private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("locale", "dateFormat", "name", "description", "fundId",
"currencyCode", "digitsAfterDecimal", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "numberOfRepayments", "currencyCode", "digitsAfterDecimal", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "numberOfRepayments",
"minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod",
"minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment", "interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment",
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule","includeInBorrowerCycle", "graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule","includeInBorrowerCycle", "startDate", "closeDate",
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
@@ -10,9 +10,11 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.accounting.common.AccountingEnumerations; import org.mifosplatform.accounting.common.AccountingEnumerations;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
@@ -103,7 +105,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, " + "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, "
+ "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged," + "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged,"
+ "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, " + "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, "
+ "lp.accounting_type as accountingType, lp.include_in_borrower_cycle as includeInBorrowerCycle, " + "lp.accounting_type as accountingType, lp.include_in_borrower_cycle as includeInBorrowerCycle, lp.start_date as startDate, lp.close_date as closeDate, "
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol " + "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol "
+ " 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"
@@ -170,13 +172,21 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
.interestCalculationPeriodType(interestCalculationPeriodTypeId); .interestCalculationPeriodType(interestCalculationPeriodTypeId);
final boolean includeInBorrowerCycle = rs.getBoolean("includeInBorrowerCycle"); final boolean includeInBorrowerCycle = rs.getBoolean("includeInBorrowerCycle");
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
final LocalDate closeDate = JdbcSupport.getLocalDate(rs, "closeDate");
String status = "";
if (closeDate != null && closeDate.isBefore(DateUtils.getLocalDateOfTenant())) {
status = "loanProduct.inActive";
} else {
status = "loanProduct.active";
}
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName,
transactionStrategyId, transactionStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, transactionStrategyId, transactionStrategyName, graceOnPrincipalPayment, graceOnInterestPayment,
graceOnInterestCharged, this.charges, accountingRuleType, includeInBorrowerCycle); graceOnInterestCharged, this.charges, accountingRuleType, includeInBorrowerCycle, startDate, closeDate, status);
} }
} }
@@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.joda.time.LocalDate;
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService; import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -27,6 +28,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException; import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductDateException;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductDataValidator; import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductDataValidator;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -78,6 +80,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
this.context.authenticatedUser(); this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForCreate(command.json()); this.fromApiJsonDeserializer.validateForCreate(command.json());
validateInputDates(command);
final Fund fund = findFundByIdIfProvided(command.longValueOfParameterNamed("fundId")); final Fund fund = findFundByIdIfProvided(command.longValueOfParameterNamed("fundId"));
@@ -136,6 +139,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
if (product == null) { throw new LoanProductNotFoundException(loanProductId); } if (product == null) { throw new LoanProductNotFoundException(loanProductId); }
this.fromApiJsonDeserializer.validateForUpdate(command.json(), product); this.fromApiJsonDeserializer.validateForUpdate(command.json(), product);
validateInputDates(command);
final Map<String, Object> changes = product.update(command, this.aprCalculator); final Map<String, Object> changes = product.update(command, this.aprCalculator);
@@ -238,6 +242,17 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
"Unknown data integrity issue with resource."); "Unknown data integrity issue with resource.");
} }
private void validateInputDates(final JsonCommand command) {
final LocalDate startDate = command.localDateValueOfParameterNamed("startDate");
final LocalDate closeDate = command.localDateValueOfParameterNamed("closeDate");
if (startDate != null && closeDate != null) {
if (closeDate.isBefore(startDate)) {
throw new LoanProductDateException(startDate.toString(), closeDate.toString());
}
}
}
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) { private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
logger.error(dve.getMessage(), dve); logger.error(dve.getMessage(), dve);
} }