Пример #1
0
 private void validateDisbursementDateWithMeetingDates(
     final LocalDate expectedDisbursementDate, final Calendar calendar) {
   // disbursement date should fall on a meeting date
   if (!CalendarHelper.isValidRedurringDate(
       calendar.getRecurrence(), calendar.getStartDateLocalDate(), expectedDisbursementDate)) {
     final String errorMessage =
         "Expected disbursement date '"
             + expectedDisbursementDate
             + "' do not fall on a meeting date";
     throw new LoanApplicationDateException(
         "disbursement.date.do.not.match.meeting.date", errorMessage, expectedDisbursementDate);
   }
 }
Пример #2
0
 private void validateRepaymentsStartDateWithMeetingDates(
     final LocalDate repaymentsStartingFromDate, final Calendar calendar) {
   if (repaymentsStartingFromDate != null
       && !CalendarHelper.isValidRedurringDate(
           calendar.getRecurrence(),
           calendar.getStartDateLocalDate(),
           repaymentsStartingFromDate)) {
     final String errorMessage =
         "First repayment date '" + repaymentsStartingFromDate + "' do not fall on a meeting date";
     throw new LoanApplicationDateException(
         "first.repayment.date.do.not.match.meeting.date",
         errorMessage,
         repaymentsStartingFromDate);
   }
 }
Пример #3
0
  private LoanApplicationTerms assembleLoanApplicationTermsFrom(
      final JsonElement element, final LoanProduct loanProduct) {

    final MonetaryCurrency currency = loanProduct.getCurrency();
    final ApplicationCurrency applicationCurrency =
        this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);

    // loan terms
    final Integer loanTermFrequency =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequency", element);
    final Integer loanTermFrequencyType =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequencyType", element);
    final PeriodFrequencyType loanTermPeriodFrequencyType =
        PeriodFrequencyType.fromInt(loanTermFrequencyType);

    final Integer numberOfRepayments =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
    final Integer repaymentEvery =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element);
    final Integer repaymentFrequencyType =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element);
    final PeriodFrequencyType repaymentPeriodFrequencyType =
        PeriodFrequencyType.fromInt(repaymentFrequencyType);

    final Integer amortizationType =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element);
    final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(amortizationType);

    // interest terms
    final Integer interestType =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
    final InterestMethod interestMethod = InterestMethod.fromInt(interestType);

    final Integer interestCalculationPeriodType =
        fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType", element);
    final InterestCalculationPeriodMethod interestCalculationPeriodMethod =
        InterestCalculationPeriodMethod.fromInt(interestCalculationPeriodType);

    final BigDecimal interestRatePerPeriod =
        fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
    final PeriodFrequencyType interestRatePeriodFrequencyType =
        loanProduct.getInterestPeriodFrequencyType();

    final BigDecimal annualNominalInterestRate =
        this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRatePerPeriod);

    // disbursement details
    final BigDecimal principal =
        this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
    final Money principalMoney = Money.of(currency, principal);

    final LocalDate expectedDisbursementDate =
        this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
    final LocalDate repaymentsStartingFromDate =
        this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
    LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
    final Boolean synchDisbursement =
        fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
    final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element);
    Calendar calendar = null;
    if ((synchDisbursement != null && synchDisbursement.booleanValue())
        || (calendarId != null && calendarId != 0)) {
      calendar = this.calendarRepository.findOne(calendarId);
      if (calendar == null) {
        throw new CalendarNotFoundException(calendarId);
      }

      // validate repayment frequency and interval with meeting frequency and interval
      PeriodFrequencyType meetingPeriodFrequency =
          CalendarHelper.getMeetingPeriodFrequencyType(calendar.getRecurrence());
      validateRepaymentFrequencyIsSameAsMeetingFrequency(
          meetingPeriodFrequency.getValue(),
          repaymentFrequencyType,
          CalendarHelper.getInterval(calendar.getRecurrence()),
          repaymentEvery);
    }

    if (synchDisbursement != null && synchDisbursement.booleanValue()) {
      validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar);
    }

    // if calendar is attached (not null) then reschedule repayment dates according to meeting
    if (null != calendar) {
      // TODO : AA - Is it require to reset repaymentsStartingFromDate or
      // set only if it is not provided (or null)
      // Currently provided repaymentsStartingFromDate takes precedence over system generated next
      // meeting date
      if (calculatedRepaymentsStartingFromDate == null) {
        // 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.
        final String frequency =
            CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
        calculatedRepaymentsStartingFromDate =
            CalendarHelper.getFirstRepaymentMeetingDate(
                calendar, expectedDisbursementDate, repaymentEvery, frequency);
      } else { // validate user provided repaymentsStartFromDate
        validateRepaymentsStartDateWithMeetingDates(repaymentsStartingFromDate, calendar);
      }
    }
    // grace details
    final Integer graceOnPrincipalPayment =
        this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element);
    final Integer graceOnInterestPayment =
        this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element);
    final Integer graceOnInterestCharged =
        this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestCharged", element);
    final LocalDate interestChargedFromDate =
        fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);

    // other
    final BigDecimal inArrearsTolerance =
        this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
    final Money inArrearsToleranceMoney = Money.of(currency, inArrearsTolerance);

    return LoanApplicationTerms.assembleFrom(
        applicationCurrency,
        loanTermFrequency,
        loanTermPeriodFrequencyType,
        numberOfRepayments,
        repaymentEvery,
        repaymentPeriodFrequencyType,
        amortizationMethod,
        interestMethod,
        interestRatePerPeriod,
        interestRatePeriodFrequencyType,
        annualNominalInterestRate,
        interestCalculationPeriodMethod,
        principalMoney,
        expectedDisbursementDate,
        repaymentsStartingFromDate,
        calculatedRepaymentsStartingFromDate,
        graceOnPrincipalPayment,
        graceOnInterestPayment,
        graceOnInterestCharged,
        interestChargedFromDate,
        inArrearsToleranceMoney);
  }