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); } }
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); } }
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); }
@Override public JLGCollectionSheetData generateGroupCollectionSheet( final Long groupId, final JsonQuery query) { this.collectionSheetGenerateCommandFromApiJsonDeserializer.validateForGenerateCollectionSheet( query.json()); final Long calendarId = query.longValueOfParameterNamed(calendarIdParamName); final LocalDate transactionDate = query.localDateValueOfParameterNamed(transactionDateParamName); final DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); final String transactionDateStr = df.format(transactionDate.toDate()); final Calendar calendar = this.calendarRepositoryWrapper.findOneWithNotFoundDetection(calendarId); // check if transaction against calendar effective from date if (!calendar.isValidRecurringDate(transactionDate)) { throw new NotValidRecurringDateException( "collectionsheet", "The date '" + transactionDate + "' is not a valid meeting date.", transactionDate); } final AppUser currentUser = this.context.authenticatedUser(); final String hierarchy = currentUser.getOffice().getHierarchy(); final String officeHierarchy = hierarchy + "%"; final GroupGeneralData group = this.groupReadPlatformService.retrieveOne(groupId); final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper(); // entityType should be center if it's within a center final CalendarEntityType entityType = (group.isChildGroup()) ? CalendarEntityType.CENTERS : CalendarEntityType.GROUPS; final SqlParameterSource namedParameters = new MapSqlParameterSource() .addValue("dueDate", transactionDateStr) .addValue("groupId", group.getId()) .addValue("officeHierarchy", officeHierarchy) .addValue("entityTypeId", entityType.getValue()); final Collection<JLGCollectionSheetFlatData> collectionSheetFlatDatas = this.namedParameterjdbcTemplate.query( mapper.collectionSheetSchema(false), namedParameters, mapper); // loan data for collection sheet JLGCollectionSheetData collectionSheetData = buildJLGCollectionSheet(transactionDate, collectionSheetFlatDatas); // mandatory savings data for collection sheet Collection<JLGGroupData> groupsWithSavingsData = this.namedParameterjdbcTemplate.query( mandatorySavingsExtractor.collectionSheetSchema(false), namedParameters, mandatorySavingsExtractor); // merge savings data into loan data mergeSavingsGroupDataIntoCollectionsheetData(groupsWithSavingsData, collectionSheetData); collectionSheetData = JLGCollectionSheetData.withSavingsProducts( collectionSheetData, retrieveSavingsProducts(groupsWithSavingsData)); return collectionSheetData; }