cleaning up MIFOSX-1584
This commit is contained in:
+26
@@ -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);
|
||||
}
|
||||
}
|
||||
-22
@@ -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
-56
@@ -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;
|
||||
@@ -161,16 +161,15 @@ public class LoanScheduleAssembler {
|
||||
final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
|
||||
final LocalDate repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
|
||||
|
||||
final Boolean synchDisbursement = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
|
||||
final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element);
|
||||
Calendar calendar = null;
|
||||
|
||||
|
||||
final String loanTypeParameterName = "loanType";
|
||||
final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
|
||||
|
||||
|
||||
final AccountType loanType = AccountType.fromName(loanTypeStr);
|
||||
|
||||
|
||||
/*
|
||||
* If it is JLG loan then make sure loan frequency is same as
|
||||
@@ -237,20 +236,20 @@ public class LoanScheduleAssembler {
|
||||
/*
|
||||
* If first repayment is not derived and instead directly taken from
|
||||
* input then copy the value of repaymentsStartingFromDate to
|
||||
* calculatedRepaymentsStartingFromDate
|
||||
* calculatedRepaymentsStartingFromDate
|
||||
*
|
||||
* TODO: The reason for this bad code is, LoanApplicationTerms.assembleFrom
|
||||
* takes both repaymentsStartingFromDate and calculatedRepaymentsStartingFromDate
|
||||
* and derived data has precedence over input date,
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
// grace details
|
||||
final Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element);
|
||||
final Integer graceOnInterestPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element);
|
||||
@@ -467,66 +466,62 @@ public class LoanScheduleAssembler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate deriveFirstRepaymentDate(final AccountType loanType, final Integer repaymentEvery,
|
||||
|
||||
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);
|
||||
final LocalDate refernceDateForCalculatingFirstRepaymentDate = expectedDisbursementDate;
|
||||
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){
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
|
||||
|
||||
final LocalDate minimumFirstRepaymentDate = disbursalDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
|
||||
if (firstRepaymentDate.isBefore(minimumFirstRepaymentDate)) { throw new MinDaysBetweenDisbursalAndFirstRepaymentViolationException(
|
||||
disbursalDate, firstRepaymentDate, minimumDaysBetweenDisbursalAndFirstRepayment); }
|
||||
}
|
||||
}
|
||||
+25
-12
@@ -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); }
|
||||
**/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-7
@@ -121,7 +121,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "overdue_days_for_npa", nullable = true)
|
||||
private Integer overdueDaysForNPA;
|
||||
|
||||
|
||||
@Column(name = "min_days_between_disbursal_and_first_repayment", nullable = true)
|
||||
private Integer minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
|
||||
@@ -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;
|
||||
@@ -665,7 +666,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.minimumDaysBetweenDisbursalAndFirstRepayment = newValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update interest recalculation settings
|
||||
*/
|
||||
@@ -809,10 +810,10 @@ 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) {
|
||||
LoanProductBorrowerCycleVariations borrowerCycleVariation = null;
|
||||
for (LoanProductBorrowerCycleVariations cycleVariation : this.borrowerCycleVariations) {
|
||||
|
||||
+5
-5
@@ -104,14 +104,14 @@ public final class LoanProductDataValidator {
|
||||
final Long fundId = this.fromApiJsonHelper.extractLongNamed("fundId", element);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
final Boolean includeInBorrowerCycle = this.fromApiJsonHelper.extractBooleanNamed("includeInBorrowerCycle", element);
|
||||
baseDataValidator.reset().parameter("includeInBorrowerCycle").value(includeInBorrowerCycle).ignoreIfNull()
|
||||
.validateForBooleanValue();
|
||||
|
||||
-2
@@ -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`;
|
||||
Reference in New Issue
Block a user