Merge pull request #462 from ashok-conflux/MIFOSX-551

Fixed MIFOSX-551 issue
This commit is contained in:
Vishwas Babu A J
2013-07-19 01:35:56 -07:00
5 changed files with 35 additions and 34 deletions
@@ -1317,7 +1317,7 @@ public class Loan extends AbstractPersistable<Long> {
public Map<String, Object> disburse(final LoanScheduleGeneratorFactory loanScheduleFactory, final AppUser currentUser, public Map<String, Object> disburse(final LoanScheduleGeneratorFactory loanScheduleFactory, final AppUser currentUser,
final JsonCommand command, final ApplicationCurrency currency, final List<Long> existingTransactionIds, final JsonCommand command, final ApplicationCurrency currency, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds, final Map<String, Object> actualChanges, final PaymentDetail paymentDetail, final List<Long> existingReversedTransactionIds, final Map<String, Object> actualChanges, final PaymentDetail paymentDetail,
final LocalDate firstRepaymentMeetingDate, final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) { final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
updateLoanToPreDisbursalState(); updateLoanToPreDisbursalState();
@@ -1347,7 +1347,7 @@ public class Loan extends AbstractPersistable<Long> {
handleDisbursementTransaction(paymentDetail, actualDisbursementDate); handleDisbursementTransaction(paymentDetail, actualDisbursementDate);
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) { if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate)) {
regenerateRepaymentSchedule(loanScheduleFactory, currency, firstRepaymentMeetingDate, isHolidayEnabled, holidays, workingDays); regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays);
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate); updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
} else { } else {
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate); updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
@@ -1374,7 +1374,7 @@ public class Loan extends AbstractPersistable<Long> {
* details/state. * details/state.
*/ */
private void regenerateRepaymentSchedule(final LoanScheduleGeneratorFactory loanScheduleFactory, private void regenerateRepaymentSchedule(final LoanScheduleGeneratorFactory loanScheduleFactory,
final ApplicationCurrency applicationCurrency, final LocalDate firstRepaymentMeetingDate, final boolean isHolidayEnabled, final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled,
final List<Holiday> holidays, final WorkingDays workingDays) { final List<Holiday> holidays, final WorkingDays workingDays) {
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod(); final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
@@ -1385,13 +1385,8 @@ public class Loan extends AbstractPersistable<Long> {
final Integer loanTermFrequency = this.termFrequency; final Integer loanTermFrequency = this.termFrequency;
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType); final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
// If ExpectedFirstRepaymentOnDate is null and repayment is synced with
// meeting then use firstRepaymentMeetingDate
// to generate repayment schedule dates
final LocalDate firstRepaymentOnDate = (getExpectedFirstRepaymentOnDate() == null) ? firstRepaymentMeetingDate
: getExpectedFirstRepaymentOnDate();
LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency,
loanTermPeriodFrequencyType, getDisbursementDate(), firstRepaymentOnDate, getInArrearsTolerance(), loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), calculatedRepaymentsStartingFromDate, getInArrearsTolerance(),
this.loanRepaymentScheduleDetail); this.loanRepaymentScheduleDetail);
LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, this.charges, isHolidayEnabled, holidays, workingDays); LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, this.charges, isHolidayEnabled, holidays, workingDays);
@@ -26,7 +26,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
final List<LocalDate> dueRepaymentPeriodDates = new ArrayList<LocalDate>(numberOfRepayments); final List<LocalDate> dueRepaymentPeriodDates = new ArrayList<LocalDate>(numberOfRepayments);
LocalDate startDate = loanApplicationTerms.getExpectedDisbursementDate(); LocalDate startDate = loanApplicationTerms.getExpectedDisbursementDate();
final LocalDate firstRepaymentPeriodDate = loanApplicationTerms.getRepaymentsStartingFromLocalDate(); final LocalDate firstRepaymentPeriodDate = loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate();
for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments; repaymentPeriod++) { for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments; repaymentPeriod++) {
@@ -38,7 +38,7 @@ public final class LoanApplicationTerms {
private final Money principal; private final Money principal;
private final LocalDate expectedDisbursementDate; private final LocalDate expectedDisbursementDate;
private final LocalDate repaymentsStartingFromDate; private final LocalDate repaymentsStartingFromDate;
private final LocalDate calculatedRepaymentsStartingFromDate;
/** /**
* Integer representing the number of 'repayment frequencies' or * Integer representing the number of 'repayment frequencies' or
* installments where 'grace' should apply to the principal component of a * installments where 'grace' should apply to the principal component of a
@@ -88,21 +88,22 @@ public final class LoanApplicationTerms {
final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principalMoney, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principalMoney,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, final Integer graceOnPrincipalPayment, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
final LocalDate calculatedRepaymentsStartingFromDate, final Integer graceOnPrincipalPayment,
final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate,
final Money inArrearsTolerance) { final Money inArrearsTolerance) {
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType,
annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, expectedDisbursementDate, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, expectedDisbursementDate,
repaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment,
interestChargedFromDate, inArrearsTolerance); graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance);
} }
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final LocalDate expectedDisbursementDate, final PeriodFrequencyType loanTermPeriodFrequencyType, final LocalDate expectedDisbursementDate,
final LocalDate repaymentsStartingFromDate, final Money inArrearsTolerance, final LocalDate repaymentsStartingFromDate, final LocalDate calculatedRepaymentsStartingFromDate,
final LoanProductRelatedDetail loanProductRelatedDetail) { final Money inArrearsTolerance, final LoanProductRelatedDetail loanProductRelatedDetail) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments(); final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery(); final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -125,8 +126,8 @@ public final class LoanApplicationTerms {
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod, repaymentEvery, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney,
expectedDisbursementDate, repaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment,
graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance); graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance);
} }
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency, private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
@@ -135,9 +136,9 @@ public final class LoanApplicationTerms {
final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principal, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principal,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, final Integer principalGrace, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
final Integer interestPaymentGrace, final Integer interestChargingGrace, final LocalDate interestChargedFromDate, final LocalDate calculatedRepaymentsStartingFromDate, final Integer principalGrace, final Integer interestPaymentGrace,
final Money inArrearsTolerance) { final Integer interestChargingGrace, final LocalDate interestChargedFromDate, final Money inArrearsTolerance) {
this.currency = currency; this.currency = currency;
this.loanTermFrequency = loanTermFrequency; this.loanTermFrequency = loanTermFrequency;
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType; this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
@@ -155,7 +156,8 @@ public final class LoanApplicationTerms {
this.principal = principal; this.principal = principal;
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementDate = expectedDisbursementDate;
this.repaymentsStartingFromDate = repaymentsStartingFromDate; this.repaymentsStartingFromDate = repaymentsStartingFromDate;
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
this.principalGrace = principalGrace; this.principalGrace = principalGrace;
this.interestPaymentGrace = interestPaymentGrace; this.interestPaymentGrace = interestPaymentGrace;
this.interestChargingGrace = interestChargingGrace; this.interestChargingGrace = interestChargingGrace;
@@ -685,6 +687,10 @@ public final class LoanApplicationTerms {
return this.repaymentsStartingFromDate; return this.repaymentsStartingFromDate;
} }
public LocalDate getCalculatedRepaymentsStartingFromLocalDate() {
return this.calculatedRepaymentsStartingFromDate;
}
public Money getPrincipal() { public Money getPrincipal() {
return this.principal; return this.principal;
} }
@@ -139,8 +139,8 @@ public class LoanScheduleAssembler {
final Money principalMoney = Money.of(currency, principal); final Money principalMoney = Money.of(currency, principal);
final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element); final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
LocalDate repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element); final LocalDate repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
final Boolean synchDisbursement = fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element); final Boolean synchDisbursement = fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element); final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element);
Calendar calendar = null; Calendar calendar = null;
@@ -163,11 +163,11 @@ public class LoanScheduleAssembler {
// TODO : AA - Is it require to reset repaymentsStartingFromDate or // TODO : AA - Is it require to reset repaymentsStartingFromDate or
// set only if it is not provided (or null) // set only if it is not provided (or null)
// Currently provided repaymentsStartingFromDate takes precedence over system generated next meeting date // Currently provided repaymentsStartingFromDate takes precedence over system generated next meeting date
if (repaymentsStartingFromDate == null) { if (calculatedRepaymentsStartingFromDate == null) {
// FIXME: AA - Possibility of having next meeting date immediately after disbursement date, // FIXME: AA - Possibility of having next meeting date immediately after disbursement date,
// need to have minimum number of days gap between disbursement and first repayment date. // need to have minimum number of days gap between disbursement and first repayment date.
final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType); final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
repaymentsStartingFromDate = CalendarHelper.getFirstRepaymentMeetingDate(calendar, expectedDisbursementDate, calculatedRepaymentsStartingFromDate = CalendarHelper.getFirstRepaymentMeetingDate(calendar, expectedDisbursementDate,
repaymentEvery, frequency); repaymentEvery, frequency);
} else {// validate user provided repaymentsStartFromDate } else {// validate user provided repaymentsStartFromDate
validateRepaymentsStartDateWithMeetingDates(repaymentsStartingFromDate, calendar); validateRepaymentsStartDateWithMeetingDates(repaymentsStartingFromDate, calendar);
@@ -186,7 +186,7 @@ public class LoanScheduleAssembler {
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod, repaymentEvery, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney,
expectedDisbursementDate, repaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment,
graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney); graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney);
} }
@@ -176,14 +176,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
// Recalculate first repayment date based in actual disbursement date. // Recalculate first repayment date based in actual disbursement date.
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
final LocalDate firstRepaymentMeetingDate = getFirstRepaymentMeetingDate(actualDisbursementDate, loan, calendarInstance); final LocalDate calculatedRepaymentsStartingFromDate = getCalculatedRepaymentsStartingFromDate(actualDisbursementDate, loan, calendarInstance);
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), actualDisbursementDate.toDate()); final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), actualDisbursementDate.toDate());
final WorkingDays workingDays = this.workingDaysRepository.findOne(); final WorkingDays workingDays = this.workingDaysRepository.findOne();
updateLoanCounters(loan, actualDisbursementDate); updateLoanCounters(loan, actualDisbursementDate);
loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, existingTransactionIds, loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, existingTransactionIds,
existingReversedTransactionIds, changes, paymentDetail, firstRepaymentMeetingDate, isHolidayEnabled, holidays, workingDays); existingReversedTransactionIds, changes, paymentDetail, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays);
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -208,15 +208,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.build(); .build();
} }
private LocalDate getFirstRepaymentMeetingDate(final LocalDate actualDisbursementDate, final Loan loan, private LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
final CalendarInstance calendarInstance) { final CalendarInstance calendarInstance) {
final Calendar calendar = (calendarInstance == null) ? null : calendarInstance.getCalendar(); final Calendar calendar = (calendarInstance == null) ? null : calendarInstance.getCalendar();
LocalDate firstRepaymentMeetingDate = null; LocalDate calculatedRepaymentsStartingFromDate = loan.getExpectedFirstRepaymentOnDate();
if (calendar != null) {// sync repayments if (calendar != null) {// sync repayments
// TODO: AA - user provided first repayment date takes precedence // TODO: AA - user provided first repayment date takes precedence
// over recalculated meeting date // over recalculated meeting date
if (loan.getExpectedFirstRepaymentOnDate() == null) { if (calculatedRepaymentsStartingFromDate == null) {
// FIXME: AA - Possibility of having next meeting date // FIXME: AA - Possibility of having next meeting date
// immediately after disbursement date, // immediately after disbursement date,
// need to have minimum number of days gap between disbursement // need to have minimum number of days gap between disbursement
@@ -227,12 +227,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Integer repayEvery = repaymentScheduleDetails.getRepayEvery(); final Integer repayEvery = repaymentScheduleDetails.getRepayEvery();
final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentScheduleDetails final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentScheduleDetails
.getRepaymentPeriodFrequencyType()); .getRepaymentPeriodFrequencyType());
firstRepaymentMeetingDate = CalendarHelper.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate, repayEvery, calculatedRepaymentsStartingFromDate = CalendarHelper.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate, repayEvery,
frequency); frequency);
} }
} }
} }
return firstRepaymentMeetingDate; return calculatedRepaymentsStartingFromDate;
} }
/**** /****