Skip to content

Commit 039bca4

Browse files
committed
FINERACT-1971: Fix wrong due date calculation when loan got submitted
1 parent 2b9e114 commit 039bca4

File tree

4 files changed

+390
-98
lines changed

4 files changed

+390
-98
lines changed

fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,12 @@ private LoanApplicationTerms(final ApplicationCurrency currency, final Integer l
431431
this.variationsDataWrapper = new LoanTermVariationsDataWrapper(loanTermVariations);
432432
this.actualNumberOfRepayments = numberOfRepayments + getLoanTermVariations().adjustNumberOfRepayments();
433433
this.adjustPrincipalForFlatLoans = principal.zero();
434-
if (this.calculatedRepaymentsStartingFromDate == null) {
435-
this.seedDate = this.expectedDisbursementDate;
434+
// We only change the seed date if `repaymentStartingFromDate was provided`
435+
if (this.repaymentsStartingFromDate == null) {
436+
this.seedDate = repaymentStartDateType.isDisbursementDate() ? expectedDisbursementDate : submittedOnDate;
436437
} else {
437-
this.seedDate = this.calculatedRepaymentsStartingFromDate;
438+
// When we change the seed date we are taking the `repaymentsStartingFromDate`
439+
this.seedDate = repaymentsStartingFromDate;
438440
}
439441
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
440442
this.isInterestChargedFromDateSameAsDisbursalDateEnabled = isInterestChargedFromDateSameAsDisbursalDateEnabled;

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,16 @@ private LoanApplicationTerms assembleLoanApplicationTermsFrom(final JsonElement
274274
* If user has not passed the first repayments date then then derive the same based on loan type.
275275
*/
276276
if (calculatedRepaymentsStartingFromDate == null) {
277+
LocalDate tmpCalculatedRepaymentsStartingFromDate = deriveFirstRepaymentDate(loanType, repaymentEvery, expectedDisbursementDate,
278+
repaymentPeriodFrequencyType, 0, calendar, submittedOnDate, repaymentStartDateType);
277279
calculatedRepaymentsStartingFromDate = deriveFirstRepaymentDate(loanType, repaymentEvery, expectedDisbursementDate,
278280
repaymentPeriodFrequencyType, loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment(), calendar, submittedOnDate,
279281
repaymentStartDateType);
282+
// If calculated repayment start date does not match due to minimum days between disbursal and first
283+
// repayment rule, we set repaymentsStartingFromDate (which will be used as seed date later)
284+
if (!tmpCalculatedRepaymentsStartingFromDate.equals(calculatedRepaymentsStartingFromDate)) {
285+
repaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
286+
}
280287
}
281288

282289
/*
@@ -1102,39 +1109,26 @@ private LocalDate deriveFirstRepaymentDate(final AccountType loanType, final Int
11021109
final RepaymentStartDateType repaymentStartDateType) {
11031110
LocalDate derivedFirstRepayment = null;
11041111

1105-
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = RepaymentStartDateType.DISBURSEMENT_DATE.equals(
1106-
repaymentStartDateType) ? expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment) : submittedOnDate;
1107-
1112+
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = expectedDisbursementDate
1113+
.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
1114+
final LocalDate seedDate = repaymentStartDateType.isDisbursementDate() ? expectedDisbursementDate : submittedOnDate;
11081115
if (calendar != null) {
1109-
derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate, expectedDisbursementDate,
1110-
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate,
1111-
repaymentStartDateType);
1116+
derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate, seedDate,
1117+
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate);
11121118
} else { // Individual or group account, or JLG not linked to a meeting
11131119
LocalDate dateBasedOnRepaymentFrequency;
11141120
// Derive the first repayment date as greater date among
11151121
// (disbursement date + plus frequency) or
11161122
// (disbursement date + minimum between disbursal and first
11171123
// repayment )
11181124
if (repaymentPeriodFrequencyType.isDaily()) {
1119-
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
1120-
? expectedDisbursementDate.plusDays(repaymentEvery)
1121-
: submittedOnDate.plusDays(repaymentEvery);
1122-
1125+
dateBasedOnRepaymentFrequency = seedDate.plusDays(repaymentEvery);
11231126
} else if (repaymentPeriodFrequencyType.isWeekly()) {
1124-
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
1125-
? expectedDisbursementDate.plusWeeks(repaymentEvery)
1126-
: submittedOnDate.plusWeeks(repaymentEvery);
1127-
1127+
dateBasedOnRepaymentFrequency = seedDate.plusWeeks(repaymentEvery);
11281128
} else if (repaymentPeriodFrequencyType.isMonthly()) {
1129-
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
1130-
? expectedDisbursementDate.plusMonths(repaymentEvery)
1131-
: submittedOnDate.plusMonths(repaymentEvery);
1132-
1129+
dateBasedOnRepaymentFrequency = seedDate.plusMonths(repaymentEvery);
11331130
} else { // yearly loan
1134-
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
1135-
? expectedDisbursementDate.plusYears(repaymentEvery)
1136-
: submittedOnDate.plusYears(repaymentEvery);
1137-
1131+
dateBasedOnRepaymentFrequency = seedDate.plusYears(repaymentEvery);
11381132
}
11391133
derivedFirstRepayment = DateUtils.isAfter(dateBasedOnRepaymentFrequency,
11401134
dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment) ? dateBasedOnRepaymentFrequency
@@ -1146,20 +1140,16 @@ private LocalDate deriveFirstRepaymentDate(final AccountType loanType, final Int
11461140

11471141
private LocalDate deriveFirstRepaymentDateForLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
11481142
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
1149-
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar, final LocalDate submittedOnDate,
1150-
final RepaymentStartDateType repaymentStartDateType) {
1143+
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar, final LocalDate submittedOnDate) {
11511144
boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
11521145
int numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
11531146
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
11541147
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
11551148
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
1156-
final LocalDate minimumFirstRepaymentDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
1157-
? expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment)
1158-
: submittedOnDate;
1149+
final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
11591150
return DateUtils.isBefore(minimumFirstRepaymentDate, derivedFirstRepayment) ? derivedFirstRepayment
11601151
: deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate, derivedFirstRepayment,
1161-
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate,
1162-
repaymentStartDateType);
1152+
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate);
11631153
}
11641154

11651155
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,

0 commit comments

Comments
 (0)