cleaning up MIFOSX-1584

This commit is contained in:
Vishwas Babu A J
2014-11-05 23:58:03 +05:30
parent a8c733100b
commit f1e9c2800b
7 changed files with 115 additions and 104 deletions
@@ -0,0 +1,26 @@
/**
* 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.loanaccount.exception;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when a number of days
* between disbursal date and firstRepayment is less than
* minimumDaysBetweenDisbursalAndFirstRepayment
*
*/
public class MinDaysBetweenDisbursalAndFirstRepaymentViolationException extends AbstractPlatformDomainRuleException {
public MinDaysBetweenDisbursalAndFirstRepaymentViolationException(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,
Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
super("error.msg.loan.days.between.first.repayment.and.disbursal.are.less.than.minimum.allowed.numbers",
"Number of days between loan disbursal (" + disbursalDate + ") and first repayment (" + firstRepaymentDate
+ ") can't be less than (" + minimumDaysBetweenDisbursalAndFirstRepayment + ").", disbursalDate,
firstRepaymentDate, minimumDaysBetweenDisbursalAndFirstRepayment);
}
}
@@ -1,22 +0,0 @@
/**
* 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.loanaccount.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when a number of days between disbursal date and firstRepayment is less than
* minimumDaysBetweenDisbursalAndFirstRepayment
*
*/
public class MinimumDaysBetweenDisbursalAndFirstRepaymentRuleException extends AbstractPlatformDomainRuleException {
public MinimumDaysBetweenDisbursalAndFirstRepaymentRuleException(final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super("validation.msg.loan.days.between.first.repayment.and.disbursal.are.less than.minimum.number.of.days.required",
defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -51,7 +51,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.mifosplatform.portfolio.loanaccount.exception.MinimumDaysBetweenDisbursalAndFirstRepaymentRuleException;
import org.mifosplatform.portfolio.loanaccount.exception.MinDaysBetweenDisbursalAndFirstRepaymentViolationException;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
@@ -171,7 +171,6 @@ public class LoanScheduleAssembler {
final AccountType loanType = AccountType.fromName(loanTypeStr);
/*
* If it is JLG loan then make sure loan frequency is same as
* Group/Center meeting frequency or multiple of it. TODO: Check should
@@ -239,13 +238,13 @@ public class LoanScheduleAssembler {
* input then copy the value of repaymentsStartingFromDate to
* calculatedRepaymentsStartingFromDate
*
* TODO: The reason for this bad code is, LoanApplicationTerms.assembleFrom
* takes both repaymentsStartingFromDate and calculatedRepaymentsStartingFromDate
* TODO: The reason for this bad code is,
* LoanApplicationTerms.assembleFrom takes both
* repaymentsStartingFromDate and calculatedRepaymentsStartingFromDate
* and derived data has precedence over input date,
*
* FIXME:LoanApplicationTerms.assembleFrom should take only one
* "first repayment date" than taking two dates with same purpose.
*
*/
if (!isRepaymentsStartingFromDateDerived) {
calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
@@ -470,63 +469,59 @@ public class LoanScheduleAssembler {
private LocalDate deriveFirstRepaymentDate(final AccountType loanType, final Integer repaymentEvery,
final LocalDate expectedDisbursementDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar){
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar) {
LocalDate derivedFirstRepayment = null;
LocalDate dateBasedOnRepaymentFrequency = null;
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
LocalDate dateBasedOnRepaymentFrequency;
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = expectedDisbursementDate
.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
if (loanType.isIndividualAccount() || loanType.isGroupAccount()) {
// Derive the first repayment date as greater date among (disbursement date + plus frequency) or
// (disbursement date + minimum between disbursal and first repayment )
// Derive the first repayment date as greater date among
// (disbursement date + plus frequency) or
// (disbursement date + minimum between disbursal and first
// repayment )
if (repaymentPeriodFrequencyType.isDaily()) {
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusDays(repaymentEvery);
}
else if(repaymentPeriodFrequencyType.isWeekly()){
} else if (repaymentPeriodFrequencyType.isWeekly()) {
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusWeeks(repaymentEvery);
}
else if (repaymentPeriodFrequencyType.isMonthly()) {
} else if (repaymentPeriodFrequencyType.isMonthly()) {
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusMonths(repaymentEvery);
}
else if (repaymentPeriodFrequencyType.isYearly()){
} else if (repaymentPeriodFrequencyType.isYearly()) {
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusYears(repaymentEvery);
}
derivedFirstRepayment = dateBasedOnRepaymentFrequency.isAfter(dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment)?dateBasedOnRepaymentFrequency:dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment;
}
else if(loanType.isJLGAccount()){
derivedFirstRepayment = dateBasedOnRepaymentFrequency.isAfter(dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment) ? dateBasedOnRepaymentFrequency
: dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment;
} else if (loanType.isJLGAccount()) {
final LocalDate refernceDateForCalculatingFirstRepaymentDate = expectedDisbursementDate;
derivedFirstRepayment = deriveFirstRepaymentDateForJLGLoans(repaymentEvery, expectedDisbursementDate,refernceDateForCalculatingFirstRepaymentDate,
repaymentPeriodFrequencyType,minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
derivedFirstRepayment = deriveFirstRepaymentDateForJLGLoans(repaymentEvery, expectedDisbursementDate,
refernceDateForCalculatingFirstRepaymentDate, repaymentPeriodFrequencyType,
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
}
return derivedFirstRepayment;
}
private LocalDate deriveFirstRepaymentDateForJLGLoans(final Integer repaymentEvery,
final LocalDate expectedDisbursementDate, final LocalDate refernceDateForCalculatingFirstRepaymentDate,
final PeriodFrequencyType repaymentPeriodFrequencyType,final Integer minimumDaysBetweenDisbursalAndFirstRepayment,
final Calendar calendar){
private LocalDate deriveFirstRepaymentDateForJLGLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar) {
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar, refernceDateForCalculatingFirstRepaymentDate,
repaymentEvery, frequency);
final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment
:deriveFirstRepaymentDateForJLGLoans(repaymentEvery, expectedDisbursementDate,derivedFirstRepayment, repaymentPeriodFrequencyType,
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency);
final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment : deriveFirstRepaymentDateForJLGLoans(
repaymentEvery, expectedDisbursementDate, derivedFirstRepayment, repaymentPeriodFrequencyType,
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
}
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate,
final LocalDate firstRepaymentDate, final Integer minimumDaysBetweenDisbursalAndFirstRepayment){
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
final LocalDate minimumFirstRepaymentDate = disbursalDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
if(firstRepaymentDate.isBefore(minimumFirstRepaymentDate)){
final String errorMessage = "Number of days between disbursal date (" + disbursalDate + ") and first repayment date ("
+ firstRepaymentDate + ") can't be less than minimumDaysBetweenDisbursalAndFirstRepayment ("
+ minimumDaysBetweenDisbursalAndFirstRepayment + ")." ;
throw new MinimumDaysBetweenDisbursalAndFirstRepaymentRuleException(errorMessage);
}
final LocalDate minimumFirstRepaymentDate = disbursalDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
if (firstRepaymentDate.isBefore(minimumFirstRepaymentDate)) { throw new MinDaysBetweenDisbursalAndFirstRepaymentViolationException(
disbursalDate, firstRepaymentDate, minimumDaysBetweenDisbursalAndFirstRepayment); }
}
}
@@ -112,19 +112,32 @@ public final class LoanApplicationCommandFromApiJsonHelper {
if (loanType.isJLGAccount()) {
baseDataValidator.reset().parameter("clientId").value(clientId).notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("groupId").value(groupId).notNull().longGreaterThanZero();
/**
* these validations should be carried out based on Global
* configurations, commenting them for now
**/
// if it is JLG loan then must have a meeting details (calendar)
final String calendarIdParameterName = "calendarId";
final Long calendarId = this.fromApiJsonHelper.extractLongNamed(calendarIdParameterName, element);
baseDataValidator.reset().parameter(calendarIdParameterName).value(calendarId).notNull().integerGreaterThanZero();
// if it is JLG loan then must have a syncDisbursement
final String syncDisbursementParameterName = "syncDisbursementWithMeeting";
final Boolean syncDisbursement = this.fromApiJsonHelper.extractBooleanNamed(syncDisbursementParameterName, element);
if (syncDisbursement == null) {
baseDataValidator.reset().parameter(syncDisbursementParameterName).value(syncDisbursement).trueOrFalseRequired(false);
}
/**
* // if it is JLG loan then must have a meeting details
* (calendar) final String calendarIdParameterName =
* "calendarId"; final Long calendarId =
* this.fromApiJsonHelper.extractLongNamed
* (calendarIdParameterName, element);
* baseDataValidator.reset().
* parameter(calendarIdParameterName).value
* (calendarId).notNull().integerGreaterThanZero();
*
* // if it is JLG loan then must have a syncDisbursement final
* String syncDisbursementParameterName =
* "syncDisbursementWithMeeting"; final Boolean syncDisbursement
* = this.fromApiJsonHelper.extractBooleanNamed(
* syncDisbursementParameterName, element);
*
* if (syncDisbursement == null) {
* baseDataValidator.reset().parameter
* (syncDisbursementParameterName
* ).value(syncDisbursement).trueOrFalseRequired(false); }
**/
}
}
@@ -168,7 +168,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
final Integer graceOnInterestPayment = command.integerValueOfParameterNamed("graceOnInterestPayment");
final Integer graceOnInterestCharged = command.integerValueOfParameterNamed("graceOnInterestCharged");
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = command
.integerValueOfParameterNamed("minimumDaysBetweenDisbursalAndFirstRepayment");
.integerValueOfParameterNamed(LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment);
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
final boolean includeInBorrowerCycle = command.booleanPrimitiveValueOfParameterNamed("includeInBorrowerCycle");
@@ -435,7 +435,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations, final boolean multiDisburseLoan,
final Integer maxTrancheCount, final BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing,
final Integer overdueDaysForNPA, final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType,
final boolean isInterestRecalculationEnabled, final LoanProductInterestRecalculationDetails productInterestRecalculationDetails,
final boolean isInterestRecalculationEnabled,
final LoanProductInterestRecalculationDetails productInterestRecalculationDetails,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
this.fund = fund;
this.transactionProcessingStrategy = transactionProcessingStrategy;
@@ -809,8 +810,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
return this.loanProductRelatedDetail.isInterestRecalculationEnabled();
}
public Integer getMinimumDaysBetweenDisbursalAndFirstRepayment(){
return this.minimumDaysBetweenDisbursalAndFirstRepayment == null?0:this.minimumDaysBetweenDisbursalAndFirstRepayment;
public Integer getMinimumDaysBetweenDisbursalAndFirstRepayment() {
return this.minimumDaysBetweenDisbursalAndFirstRepayment == null ? 0 : this.minimumDaysBetweenDisbursalAndFirstRepayment;
}
public LoanProductBorrowerCycleVariations fetchLoanProductBorrowerCycleVariationById(Long id) {
@@ -105,10 +105,10 @@ public final class LoanProductDataValidator {
baseDataValidator.reset().parameter("fundId").value(fundId).ignoreIfNull().integerGreaterThanZero();
}
if (this.fromApiJsonHelper.parameterExists("minimumDaysBetweenDisbursalAndFirstRepayment", element)) {
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, element)) {
final Long minimumDaysBetweenDisbursalAndFirstRepayment = this.fromApiJsonHelper.extractLongNamed(
"minimumDaysBetweenDisbursalAndFirstRepayment", element);
baseDataValidator.reset().parameter("minimumDaysBetweenDisbursalAndFirstRepayment")
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, element);
baseDataValidator.reset().parameter(LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment)
.value(minimumDaysBetweenDisbursalAndFirstRepayment).ignoreIfNull().integerGreaterThanZero();
}
@@ -1,2 +0,0 @@
ALTER TABLE `m_product_loan`
ADD COLUMN `min_days_between_disbursal_and_first_repayment` INT(3) NULL AFTER `interest_recalculation_enabled`;