List of usage examples for org.joda.time LocalDate equals
public boolean equals(Object partial)
From source file:org.libreplan.business.planner.entities.ResourceAllocation.java
License:Open Source License
private EffortDuration getAssignedDuration(List<? extends DayAssignment> assignments, final IntraDayDate startInclusive, final IntraDayDate endExclusive) { final IntraDayDate allocationStart = getIntraDayStartDate(); return EffortDuration.sum(assignments, new IEffortFrom<DayAssignment>() { @Override/*from w w w . j av a 2 s .c o m*/ public EffortDuration from(DayAssignment value) { return getPartialDay(value, startInclusive, endExclusive).limitWorkingDay(value.getDuration()); } private PartialDay getPartialDay(DayAssignment assignment, IntraDayDate startInclusive, IntraDayDate endExclusive) { LocalDate assignmentDay = assignment.getDay(); LocalDate startDate = startInclusive.getDate(); LocalDate endDate = endExclusive.getDate(); PartialDay result = PartialDay.wholeDay(assignment.getDay()); if (assignmentDay.equals(startDate)) { result = new PartialDay(startInclusive, result.getEnd()); } if (assignmentDay.equals(endDate)) { result = new PartialDay(result.getStart(), endExclusive); } return adjustPartialDayToAllocationStart(result); } // If the start of the allocation is in the middle of a day, its work also starts later, // so the PartialDay must be moved to earlier so it doesn't limit the duration more that it should private PartialDay adjustPartialDayToAllocationStart(PartialDay day) { PartialDay result = day; if (allocationStart.areSameDay(day.getDate())) { EffortDuration substractingAtStart = day.getStart().getEffortDuration(); EffortDuration newSubstractionAtStart = substractingAtStart .minus(EffortDuration.min(substractingAtStart, allocationStart.getEffortDuration())); IntraDayDate newStart = IntraDayDate.create(day.getDate(), newSubstractionAtStart); result = new PartialDay(newStart, day.getEnd()); } return result; } }); }
From source file:org.libreplan.business.resources.entities.Interval.java
License:Open Source License
public static Interval range(LocalDate start, LocalDate end) { Validate.notNull(start, "start date must be not null"); if (end == null) { return from(start); }/*w ww.java 2 s.c om*/ if (start.equals(end)) { return point(start); } return new Range(start, end); }
From source file:org.libreplan.business.resources.entities.Interval.java
License:Open Source License
private boolean dateEquals(LocalDate date1, LocalDate date2) { return date1 == date2 || (date1 != null && date2 != null && date1.equals(date2)); }
From source file:org.libreplan.business.workingday.IntraDayDate.java
License:Open Source License
public static IntraDayDate convert(LocalDate date, IntraDayDate morePreciseAlternative) { LocalDate morePreciseDate = morePreciseAlternative.getDate(); if (morePreciseDate.equals(date)) { return morePreciseAlternative; }//from w w w.ja v a 2 s . c o m return startOfDay(date); }
From source file:org.libreplan.web.limitingresources.ManualAllocationController.java
License:Open Source License
/** * Checks if date is a valid day within gap. * A day is valid within a gap if it is included between gap.startTime and the last day from which is * possible to start doing an allocation (endAllocationDate). * * If date is valid, returns DateAndHour in gap associated with that date. * * @param date/* w w w. j ava 2 s.c o m*/ * @param gap * @return {@link DateAndHour} */ private DateAndHour getValidDayInGap(LocalDate date, Gap gap) { final DateAndHour endAllocationDate = endAllocationDates.get(gap); final LocalDate start = gap.getStartTime().getDate(); final LocalDate end = endAllocationDate != null ? endAllocationDate.getDate() : null; if (start.equals(date)) { return gap.getStartTime(); } if (end != null && end.equals(date)) { return endAllocationDate; } if ((start.compareTo(date) <= 0 && (end == null || end.compareTo(date) >= 0))) { return new DateAndHour(date, 0); } return null; }
From source file:org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AbstractLoanScheduleGenerator.java
License:Mozilla Public License
private LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, final Collection<RecalculationDetail> transactions, final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate) { final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency(); // 1. generate list of proposed schedule due dates final LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, holidayDetailDTO);//from ww w . j a v a 2 s. c om loanApplicationTerms.updateLoanEndDate(loanEndDate); // 2. determine the total charges due at time of disbursement final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loanCharges); // 3. setup variables for tracking important facts required for loan // schedule generation. Money principalDisbursed = loanApplicationTerms.getPrincipal(); final MonetaryCurrency currency = principalDisbursed.getCurrency(); final int numberOfRepayments = loanApplicationTerms.getNumberOfRepayments(); // variables for cumulative totals int loanTermInDays = Integer.valueOf(0); final BigDecimal totalPrincipalPaid = BigDecimal.ZERO; BigDecimal totalFeeChargesCharged = chargesDueAtTimeOfDisbursement; BigDecimal totalPenaltyChargesCharged = BigDecimal.ZERO; BigDecimal totalRepaymentExpected = chargesDueAtTimeOfDisbursement; final BigDecimal totalOutstanding = BigDecimal.ZERO; Money totalCumulativePrincipal = principalDisbursed.zero(); Money totalCumulativeInterest = principalDisbursed.zero(); Money totalOutstandingInterestPaymentDueToGrace = principalDisbursed.zero(); final Collection<LoanScheduleModelPeriod> periods = createNewLoanScheduleListWithDisbursementDetails( numberOfRepayments, loanApplicationTerms, chargesDueAtTimeOfDisbursement); // 4. Determine the total interest owed over the full loan for FLAT // interest method . Money totalInterestChargedForFullLoanTerm = loanApplicationTerms .calculateTotalInterestCharged(this.paymentPeriodsInOneYearCalculator, mc); LocalDate periodStartDate = loanApplicationTerms.getExpectedDisbursementDate(); LocalDate actualRepaymentDate = periodStartDate; boolean isFirstRepayment = true; LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(periodStartDate, loanApplicationTerms, isFirstRepayment); final LocalDate idealDisbursementDate = this.scheduledDateGenerator .idealDisbursementDateBasedOnFirstRepaymentDate( loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate); LocalDate periodStartDateApplicableForInterest = periodStartDate; // Actual period Number as per the schedule int periodNumber = 1; // Actual period Number and interest only repayments int instalmentNumber = 1; Money outstandingBalance = principalDisbursed; // disbursement map for tranche details(will added to outstanding // balance as per the start date) final Map<LocalDate, Money> disburseDetailMap = new HashMap<>(); if (loanApplicationTerms.isMultiDisburseLoan()) { // fetches the first tranche amount and also updates other tranche // details to map BigDecimal disburseAmt = getDisbursementAmount(loanApplicationTerms, periodStartDate, periods, chargesDueAtTimeOfDisbursement, disburseDetailMap, isInterestRecalculationRequired(loanApplicationTerms, transactions)); principalDisbursed = principalDisbursed.zero().plus(disburseAmt); loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().zero().plus(disburseAmt)); outstandingBalance = outstandingBalance.zero().plus(disburseAmt); } // charges which depends on total loan interest will be added to this // set and handled separately after all installments generated final Set<LoanCharge> nonCompoundingCharges = seperateTotalCompoundingPercentageCharges(loanCharges); // total outstanding balance as per rest for interest calculation. Money outstandingBalanceAsPerRest = outstandingBalance; // early payments will be added here and as per the selected strategy // action will be performed on this value Money reducePrincipal = totalCumulativePrincipal.zero(); // principal changes will be added along with date(after applying rest) // from when these amounts will effect the outstanding balance for // interest calculation final Map<LocalDate, Money> principalPortionMap = new HashMap<>(); // compounding(principal) amounts will be added along with // date(after applying compounding frequency) // from when these amounts will effect the outstanding balance for // interest calculation final Map<LocalDate, Money> latePaymentMap = new HashMap<>(); final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>(); LocalDate currentDate = DateUtils.getLocalDateOfTenant(); LocalDate lastRestDate = currentDate; if (loanApplicationTerms.getRestCalendarInstance() != null) { lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO); } // compounding(interest/Fee) amounts will be added along with // date(after applying compounding frequency) // from when these amounts will effect the outstanding balance for // interest calculation final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>(); final Map<LocalDate, TreeMap<LocalDate, Money>> compoundingDateVariations = new HashMap<>(); boolean isNextRepaymentAvailable = true; Boolean extendTermForDailyRepayments = false; if (holidayDetailDTO.getWorkingDays().getExtendTermForDailyRepayments() == true && loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.DAYS && loanApplicationTerms.getRepaymentEvery() == 1) { holidayDetailDTO.getWorkingDays() .setRepaymentReschedulingType(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY.getValue()); extendTermForDailyRepayments = true; } while (!outstandingBalance.isZero() || !disburseDetailMap.isEmpty()) { actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms, isFirstRepayment); isFirstRepayment = false; LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms, holidayDetailDTO); if (!latePaymentMap.isEmpty()) { populateCompoundingDatesInPeriod(periodStartDate, scheduledDueDate, currentDate, loanApplicationTerms, holidayDetailDTO, compoundingMap, loanCharges, currency); compoundingDateVariations.put(periodStartDate, new TreeMap<>(compoundingMap)); } if (extendTermForDailyRepayments) { actualRepaymentDate = scheduledDueDate; } // calculated interest start date for the period periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms, periodStartDate, idealDisbursementDate, periodStartDateApplicableForInterest); int daysInPeriodApplicableForInterest = Days .daysBetween(periodStartDateApplicableForInterest, scheduledDueDate).getDays(); if (scheduleTillDate != null && !scheduledDueDate.isBefore(scheduleTillDate)) { scheduledDueDate = scheduleTillDate; isNextRepaymentAvailable = false; } // populates the collection with transactions till the due date of // the period for interest recalculation enabled loans Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod( loanApplicationTerms, scheduledDueDate, transactions); double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator .calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, scheduledDueDate, loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery()); if (loanApplicationTerms.isMultiDisburseLoan()) { // Updates fixed emi amount as the date if multiple amounts // provided loanApplicationTerms.setFixedEmiAmountForPeriod(scheduledDueDate); for (Map.Entry<LocalDate, Money> disburseDetail : disburseDetailMap.entrySet()) { if (disburseDetail.getKey().isAfter(periodStartDate) && !disburseDetail.getKey().isAfter(scheduledDueDate)) { // validation check for amount not exceeds specified max // amount as per the configuration if (loanApplicationTerms.getMaxOutstandingBalance() != null && outstandingBalance.plus(disburseDetail.getValue()) .isGreaterThan(loanApplicationTerms.getMaxOutstandingBalance())) { String errorMsg = "Outstanding balance must not exceed the amount: " + loanApplicationTerms.getMaxOutstandingBalance(); throw new MultiDisbursementOutstandingAmoutException(errorMsg, loanApplicationTerms.getMaxOutstandingBalance().getAmount(), disburseDetail.getValue()); } // creates and add disbursement detail to the repayments // period final LoanScheduleModelDisbursementPeriod disbursementPeriod = LoanScheduleModelDisbursementPeriod .disbursement(disburseDetail.getKey(), disburseDetail.getValue(), chargesDueAtTimeOfDisbursement); periods.add(disbursementPeriod); // updates actual outstanding balance with new // disbursement detail outstandingBalance = outstandingBalance.plus(disburseDetail.getValue()); principalDisbursed = principalDisbursed.plus(disburseDetail.getValue()); loanApplicationTerms .setPrincipal(loanApplicationTerms.getPrincipal().plus(disburseDetail.getValue())); } } } // Adds new interest repayment to the schedule as per the repayment // transaction processor configuration // will be added only if there is a loan repayment between the // period for interest first repayment strategies Money earlyPaidAmount = Money.zero(currency); LoanScheduleModelPeriod lastInstallment = null; if (isInterestRecalculationRequired(loanApplicationTerms, transactions)) { boolean checkForOutstanding = true; List<RecalculationDetail> unprocessedTransactions = new ArrayList<>(); LoanScheduleModelPeriod installment = null; for (RecalculationDetail detail : applicableTransactions) { if (detail.isProcessed()) { continue; } boolean updateLatePaymentMap = false; if (detail.getTransactionDate().isBefore(scheduledDueDate)) { if (loanRepaymentScheduleTransactionProcessor != null && loanRepaymentScheduleTransactionProcessor .isInterestFirstRepaymentScheduleTransactionProcessor()) { List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail); if (!detail.getTransactionDate().isEqual(periodStartDate)) { int periodDays = Days.daysBetween(periodStartDate, detail.getTransactionDate()) .getDays(); // calculates period start date for interest // calculation as per the configuration periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod( loanApplicationTerms, periodStartDate, idealDisbursementDate, periodStartDateApplicableForInterest); int daysInPeriodApplicable = Days.daysBetween(periodStartDateApplicableForInterest, detail.getTransactionDate()).getDays(); Money interestForThisinstallment = Money.zero(currency); if (daysInPeriodApplicable > 0) { // 5 determine interest till the transaction // date if (!compoundingDateVariations .containsKey(periodStartDateApplicableForInterest)) { compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap)); } PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest, totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc, mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap, periodStartDateApplicableForInterest, detail.getTransactionDate(), daysInPeriodApplicableForInterest); interestForThisinstallment = principalInterestForThisPeriod.interest(); totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod .interestPaymentDueToGrace(); } Money principalForThisPeriod = principalDisbursed.zero(); // applies all the applicable charges to the // newly // created installment PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod, interestForThisinstallment, null); Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate, detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true); Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin( periodStartDate, detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true); // 8. sum up real totalInstallmentDue from // components final Money totalInstallmentDue = principalForThisPeriod .plus(interestForThisinstallment).plus(feeChargesForInstallment) .plus(penaltyChargesForInstallment); // 9. create repayment period from parts installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate, detail.getTransactionDate(), principalForThisPeriod, outstandingBalance, interestForThisinstallment, feeChargesForInstallment, penaltyChargesForInstallment, totalInstallmentDue, true); periods.add(installment); // update outstanding balance for interest // calculation as per the rest outstandingBalanceAsPerRest = updateBalanceForInterestCalculation( principalPortionMap, detail.getTransactionDate(), outstandingBalanceAsPerRest, false); outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(disburseDetailMap, detail.getTransactionDate(), outstandingBalanceAsPerRest, true); // handle cumulative fields loanTermInDays += periodDays; totalRepaymentExpected = totalRepaymentExpected .add(totalInstallmentDue.getAmount()); totalCumulativeInterest = totalCumulativeInterest.plus(interestForThisinstallment); totalFeeChargesCharged = totalFeeChargesCharged .add(feeChargesForInstallment.getAmount()); totalPenaltyChargesCharged = totalPenaltyChargesCharged .add(penaltyChargesForInstallment.getAmount()); periodStartDate = detail.getTransactionDate(); periodStartDateApplicableForInterest = periodStartDate; updateLatePaymentMap = true; instalmentNumber++; // creates and insert Loan repayment schedule // for // the period addLoanRepaymentScheduleInstallment(installments, installment); } else if (installment == null) { installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1); } // applies the transaction as per transaction // strategy // on scheduled installments to identify the // unprocessed(early payment ) amounts Money unprocessed = loanRepaymentScheduleTransactionProcessor .handleRepaymentSchedule(currentTransactions, currency, installments); if (unprocessed.isGreaterThanZero()) { if (loanApplicationTerms.getPreClosureInterestCalculationStrategy() .calculateTillRestFrequencyEnabled()) { LocalDate applicableDate = getNextRestScheduleDate( detail.getTransactionDate().minusDays(1), loanApplicationTerms, holidayDetailDTO); checkForOutstanding = detail.getTransactionDate().isEqual(applicableDate); } // reduces actual outstanding balance outstandingBalance = outstandingBalance.minus(unprocessed); // if outstanding balance becomes less than zero // then adjusts the princiapal Money addToPrinciapal = Money.zero(currency); if (!outstandingBalance.isGreaterThanZero()) { addToPrinciapal = addToPrinciapal.plus(outstandingBalance); outstandingBalance = outstandingBalance.zero(); lastInstallment = installment; } // updates principal portion map with the early // payment amounts and applicable date as per // rest updatePrincipalPaidPortionToMap(loanApplicationTerms, holidayDetailDTO, principalPortionMap, installment, detail, unprocessed.plus(addToPrinciapal), installments); totalRepaymentExpected = totalRepaymentExpected .add(unprocessed.plus(addToPrinciapal).getAmount()); totalCumulativePrincipal = totalCumulativePrincipal .plus(unprocessed.plus(addToPrinciapal)); // method applies early payment strategy reducePrincipal = reducePrincipal.plus(unprocessed); reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal); } // identify late payments and add compounding // details to // map for interest calculation updateLatePaidAmountsToPrincipalMap(principalPortionMap, detail.getTransaction(), latePaymentMap, compoundingMap, loanApplicationTerms, currency, holidayDetailDTO, lastRestDate); compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap)); if (updateLatePaymentMap) { updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate, installments, true, lastRestDate, compoundingMap); } } else if (loanRepaymentScheduleTransactionProcessor != null) { LocalDate applicableDate = getNextRestScheduleDate( detail.getTransactionDate().minusDays(1), loanApplicationTerms, holidayDetailDTO); if (applicableDate.isBefore(scheduledDueDate)) { List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail); Money unprocessed = loanRepaymentScheduleTransactionProcessor .handleRepaymentSchedule(currentTransactions, currency, installments); Money arrears = fetchCompoundedArrears(loanApplicationTerms, currency, detail.getTransaction()); if (unprocessed.isGreaterThanZero()) { arrears = getTotalAmount(latePaymentMap, currency); updateMapWithAmount(principalPortionMap, unprocessed, applicableDate); earlyPaidAmount = earlyPaidAmount.plus(unprocessed); // this check is to identify pre-closure and // apply interest calculation as per // configuration if (!outstandingBalance.isGreaterThan(unprocessed) && !loanApplicationTerms.getPreClosureInterestCalculationStrategy() .calculateTillRestFrequencyEnabled()) { LocalDate calculateTill = detail.getTransactionDate(); if (!compoundingDateVariations .containsKey(periodStartDateApplicableForInterest)) { compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap)); } PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest, totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc, mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap, periodStartDateApplicableForInterest, calculateTill, daysInPeriodApplicableForInterest); if (!principalInterestForThisPeriod.interest() .plus(principalInterestForThisPeriod.interestPaymentDueToGrace()) .plus(outstandingBalance).isGreaterThan(unprocessed)) { earlyPaidAmount = earlyPaidAmount.minus(unprocessed); updateMapWithAmount(principalPortionMap, unprocessed.negated(), applicableDate); LoanTransaction loanTransaction = LoanTransaction.repayment(null, unprocessed, null, detail.getTransactionDate(), null, DateUtils.getLocalDateTimeOfTenant(), null); RecalculationDetail recalculationDetail = new RecalculationDetail( detail.getTransactionDate(), loanTransaction); unprocessedTransactions.add(recalculationDetail); break; } } LoanTransaction loanTransaction = LoanTransaction.repayment(null, unprocessed, null, scheduledDueDate, null, DateUtils.getLocalDateTimeOfTenant(), null); RecalculationDetail recalculationDetail = new RecalculationDetail( scheduledDueDate, loanTransaction); unprocessedTransactions.add(recalculationDetail); checkForOutstanding = false; outstandingBalance = outstandingBalance.minus(unprocessed); // if outstanding balance becomes less than // zero // then adjusts the princiapal Money addToPrinciapal = Money.zero(currency); if (outstandingBalance.isLessThanZero()) { addToPrinciapal = addToPrinciapal.plus(outstandingBalance); outstandingBalance = outstandingBalance.zero(); updateMapWithAmount(principalPortionMap, addToPrinciapal, applicableDate); earlyPaidAmount = earlyPaidAmount.plus(addToPrinciapal); } } LocalDate tillDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO); if (arrears.isGreaterThanZero() && applicableDate.isBefore(tillDate)) { updateLatePaidAmountsToPrincipalMap(principalPortionMap, detail.getTransaction(), latePaymentMap, compoundingMap, loanApplicationTerms, currency, holidayDetailDTO, lastRestDate); compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap)); } } } } } applicableTransactions.addAll(unprocessedTransactions); if (checkForOutstanding && outstandingBalance.isZero() && disburseDetailMap.isEmpty()) { continue; } } int periodDays = Days.daysBetween(periodStartDate, scheduledDueDate).getDays(); periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms, periodStartDate, idealDisbursementDate, periodStartDateApplicableForInterest); // backup for pre-close transaction if (compoundingDateVariations.containsKey(periodStartDateApplicableForInterest)) { compoundingMap.clear(); compoundingMap.putAll(compoundingDateVariations.get(periodStartDateApplicableForInterest)); } else { compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap)); } // 5 determine principal,interest of repayment period PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest, totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc, mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap, periodStartDateApplicableForInterest, scheduledDueDate, daysInPeriodApplicableForInterest); if (loanApplicationTerms.getFixedEmiAmount() != null && loanApplicationTerms.getFixedEmiAmount() .compareTo(principalInterestForThisPeriod.interest().getAmount()) != 1) { String errorMsg = "EMI amount must be greter than : " + principalInterestForThisPeriod.interest().getAmount(); throw new MultiDisbursementEmiAmountException(errorMsg, principalInterestForThisPeriod.interest().getAmount(), loanApplicationTerms.getFixedEmiAmount()); } // update cumulative fields for principal & interest Money interestForThisinstallment = principalInterestForThisPeriod.interest(); Money lastTotalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace; totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace(); Money principalForThisPeriod = principalInterestForThisPeriod.principal(); if (principalForThisPeriod.isZero()) { loanApplicationTerms.resetFixedEmiAmount(); } // applies early payments on principal portion if (principalForThisPeriod.isGreaterThan(reducePrincipal)) { principalForThisPeriod = principalForThisPeriod.minus(reducePrincipal); reducePrincipal = reducePrincipal.zero(); } else { reducePrincipal = reducePrincipal.minus(principalForThisPeriod); principalForThisPeriod = principalForThisPeriod.zero(); } // earlyPaidAmount is already subtracted from balancereducePrincipal // reducePrincipal.plus(unprocessed); Money reducedBalance = earlyPaidAmount; earlyPaidAmount = earlyPaidAmount.minus(principalForThisPeriod); if (earlyPaidAmount.isGreaterThanZero()) { reducePrincipal = reducePrincipal.plus(earlyPaidAmount); reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal); principalForThisPeriod = principalForThisPeriod.plus(earlyPaidAmount); } // 6. update outstandingLoanBlance using current period // 'principalDue' outstandingBalance = outstandingBalance.minus(principalForThisPeriod.minus(reducedBalance)); if (outstandingBalance.isLessThanZero() || !isNextRepaymentAvailable) { principalForThisPeriod = principalForThisPeriod.plus(outstandingBalance); outstandingBalance = outstandingBalance.zero(); } // applies charges for the period PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod, interestForThisinstallment, null); Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges, currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true); Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges, currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true); totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount()); totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount()); // 8. sum up real totalInstallmentDue from components final Money totalInstallmentDue = principalForThisPeriod.plus(interestForThisinstallment) .plus(feeChargesForInstallment).plus(penaltyChargesForInstallment); // if previous installment is last then add interest to same // installment if (lastInstallment != null && principalForThisPeriod.isZero()) { lastInstallment.addInterestAmount(interestForThisinstallment); continue; } // 9. create repayment period from parts LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate, scheduledDueDate, principalForThisPeriod, outstandingBalance, interestForThisinstallment, feeChargesForInstallment, penaltyChargesForInstallment, totalInstallmentDue, false); // apply loan transactions on installments to identify early/late // payments for interest recalculation if (isInterestRecalculationRequired(loanApplicationTerms, transactions) && loanRepaymentScheduleTransactionProcessor != null) { Money principalProcessed = Money.zero(currency); addLoanRepaymentScheduleInstallment(installments, installment); for (RecalculationDetail detail : applicableTransactions) { if (!detail.isProcessed()) { List<LoanTransaction> currentTransactions = new ArrayList<>(2); currentTransactions.add(detail.getTransaction()); // applies the transaction as per transaction strategy // on scheduled installments to identify the // unprocessed(early payment ) amounts Money unprocessed = loanRepaymentScheduleTransactionProcessor .handleRepaymentSchedule(currentTransactions, currency, installments); if (unprocessed.isGreaterThanZero()) { outstandingBalance = outstandingBalance.minus(unprocessed); // pre closure check and processing if (outstandingBalance.isLessThan(interestForThisinstallment) && !scheduledDueDate.equals(detail.getTransactionDate())) { LocalDate calculateTill = detail.getTransactionDate(); if (loanApplicationTerms.getPreClosureInterestCalculationStrategy() .calculateTillRestFrequencyEnabled()) { calculateTill = getNextRestScheduleDate(calculateTill.minusDays(1), loanApplicationTerms, holidayDetailDTO); } if (compoundingDateVariations.containsKey(periodStartDateApplicableForInterest)) { compoundingMap.clear(); compoundingMap.putAll( compoundingDateVariations.get(periodStartDateApplicableForInterest)); } PrincipalInterest interestTillDate = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm, lastTotalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc, mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap, periodStartDateApplicableForInterest, calculateTill, daysInPeriodApplicableForInterest); Money diff = interestForThisinstallment.minus(interestTillDate.interest()); if (!outstandingBalance.minus(diff).isGreaterThanZero()) { outstandingBalance = outstandingBalance.minus(diff); interestForThisinstallment = interestForThisinstallment.minus(diff); principalForThisPeriod = principalForThisPeriod.plus(diff); final Money totalDue = principalForThisPeriod// .plus(interestForThisinstallment); // 9. create and replaces repayment period // from parts installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate, detail.getTransactionDate(), principalForThisPeriod, outstandingBalance, interestForThisinstallment, feeChargesForInstallment, penaltyChargesForInstallment, totalDue, false); totalOutstandingInterestPaymentDueToGrace = interestTillDate .interestPaymentDueToGrace(); } } Money addToPrinciapal = Money.zero(currency); if (outstandingBalance.isLessThanZero()) { addToPrinciapal = addToPrinciapal.plus(outstandingBalance); outstandingBalance = outstandingBalance.zero(); } // updates principal portion map with the early // payment amounts and applicable date as per rest updatePrincipalPaidPortionToMap(loanApplicationTerms, holidayDetailDTO, principalPortionMap, installment, detail, unprocessed.plus(addToPrinciapal), installments); totalRepaymentExpected = totalRepaymentExpected .add(unprocessed.plus(addToPrinciapal).getAmount()); totalCumulativePrincipal = totalCumulativePrincipal .plus(unprocessed.plus(addToPrinciapal)); reducePrincipal = reducePrincipal.plus(unprocessed); reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal); principalForThisPeriod = principalForThisPeriod.plus(unprocessed.plus(addToPrinciapal)); principalProcessed = principalProcessed.plus(unprocessed.plus(addToPrinciapal)); } } } updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate, installments, true, lastRestDate, compoundingMap); principalForThisPeriod = principalForThisPeriod.minus(principalProcessed); } periods.add(installment); // Updates principal paid map with efective date for reducing // the amount from outstanding balance(interest calculation) LocalDate amountApplicableDate = installment.periodDueDate(); if (loanApplicationTerms.isInterestRecalculationEnabled()) { amountApplicableDate = getNextRestScheduleDate(installment.periodDueDate().minusDays(1), loanApplicationTerms, holidayDetailDTO); } updateMapWithAmount(principalPortionMap, principalForThisPeriod.minus(reducedBalance), amountApplicableDate); // update outstanding balance for interest calculation outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap, scheduledDueDate, outstandingBalanceAsPerRest, false); outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(disburseDetailMap, scheduledDueDate, outstandingBalanceAsPerRest, true); // handle cumulative fields loanTermInDays += periodDays; totalCumulativePrincipal = totalCumulativePrincipal.plus(principalForThisPeriod); totalCumulativeInterest = totalCumulativeInterest.plus(interestForThisinstallment); totalRepaymentExpected = totalRepaymentExpected.add(totalInstallmentDue.getAmount()); periodStartDate = scheduledDueDate; periodStartDateApplicableForInterest = periodStartDate; instalmentNumber++; periodNumber++; compoundingDateVariations.clear(); } // this condition is to add the interest from grace period if not // already applied. if (totalOutstandingInterestPaymentDueToGrace.isGreaterThanZero()) { LoanScheduleModelPeriod installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1); installment.addInterestAmount(totalOutstandingInterestPaymentDueToGrace); totalRepaymentExpected = totalRepaymentExpected .add(totalOutstandingInterestPaymentDueToGrace.getAmount()); totalCumulativeInterest = totalCumulativeInterest.plus(totalOutstandingInterestPaymentDueToGrace); totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace.zero(); } // 7. determine fees and penalties for charges which depends on total // loan interest for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) { if (loanScheduleModelPeriod.isRepaymentPeriod()) { PrincipalInterest principalInterest = new PrincipalInterest( Money.of(currency, loanScheduleModelPeriod.principalDue()), Money.of(currency, loanScheduleModelPeriod.interestDue()), null); Money feeChargesForInstallment = cumulativeFeeChargesDueWithin( loanScheduleModelPeriod.periodFromDate(), loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent()); Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin( loanScheduleModelPeriod.periodFromDate(), loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent()); totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount()); totalPenaltyChargesCharged = totalPenaltyChargesCharged .add(penaltyChargesForInstallment.getAmount()); totalRepaymentExpected = totalRepaymentExpected.add(feeChargesForInstallment.getAmount()) .add(penaltyChargesForInstallment.getAmount()); loanScheduleModelPeriod.addLoanCharges(feeChargesForInstallment.getAmount(), penaltyChargesForInstallment.getAmount()); } } // this block is to add extra re-payment schedules with interest portion // if the loan not paid with in loan term if (scheduleTillDate != null) { currentDate = scheduleTillDate; } if (isInterestRecalculationRequired(loanApplicationTerms, transactions) && latePaymentMap.size() > 0 && currentDate.isAfter(periodStartDate)) { Money totalInterest = addInterestOnlyRepaymentScheduleForCurrentdate(mc, loanApplicationTerms, holidayDetailDTO, currency, periods, periodStartDate, actualRepaymentDate, instalmentNumber, latePaymentMap, currentDate, loanRepaymentScheduleTransactionProcessor, principalPortionMap, compoundingMap, transactions, installments, loanCharges); totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest); } loanApplicationTerms.resetFixedEmiAmount(); return LoanScheduleModel.from(periods, applicationCurrency, loanTermInDays, principalDisbursed, totalCumulativePrincipal.getAmount(), totalPrincipalPaid, totalCumulativeInterest.getAmount(), totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected, totalOutstanding); }
From source file:org.mifosplatform.portfolio.savings.domain.SavingsAccount.java
License:Mozilla Public License
public void payCharge(final SavingsAccountCharge savingsAccountCharge, final BigDecimal amountPaid, final LocalDate transactionDate, final DateTimeFormatter formatter, final AppUser user) { final List<ApiParameterError> dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) .resource(SAVINGS_ACCOUNT_RESOURCE_NAME); if (isClosed()) { baseDataValidator.reset()// w w w.ja v a2 s. co m .failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } if (isNotActive()) { baseDataValidator.reset() .failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } if (savingsAccountCharge.isNotActive()) { baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("charge.is.not.active"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } if (getActivationLocalDate() != null && transactionDate.isBefore(getActivationLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName) .value(getActivationLocalDate().toString(formatter)) .failWithCodeNoParameterAddedToErrorCode("transaction.before.activationDate"); throw new PlatformApiDataValidationException(dataValidationErrors); } if (DateUtils.isDateInTheFuture(transactionDate)) { baseDataValidator.reset().parameter(dueAsOfDateParamName) .value(getSubmittedOnLocalDate().toString(formatter)) .failWithCodeNoParameterAddedToErrorCode("transaction.is.futureDate"); throw new PlatformApiDataValidationException(dataValidationErrors); } if (savingsAccountCharge.isSavingsActivation()) { baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( "transaction.not.valid.cannot.pay.activation.time.charge.is.automated"); throw new PlatformApiDataValidationException(dataValidationErrors); } if (savingsAccountCharge.isAnnualFee()) { final LocalDate annualFeeDueDate = savingsAccountCharge.getDueLocalDate(); if (annualFeeDueDate == null) { baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("no.annualfee.settings"); throw new PlatformApiDataValidationException(dataValidationErrors); } if (!annualFeeDueDate.equals(transactionDate)) { baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("invalid.date"); throw new PlatformApiDataValidationException(dataValidationErrors); } Date currentAnnualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate(); if (currentAnnualFeeNextDueDate != null && new LocalDate(currentAnnualFeeNextDueDate).isEqual(transactionDate)) { baseDataValidator.reset().parameter("dueDate").value(transactionDate.toString(formatter)) .failWithCodeNoParameterAddedToErrorCode("transaction.exists.on.date"); throw new PlatformApiDataValidationException(dataValidationErrors); } } // validate charge is not already paid or waived if (savingsAccountCharge.isWaived()) { baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( "transaction.invalid.account.charge.is.already.waived"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } else if (savingsAccountCharge.isPaid()) { baseDataValidator.reset() .failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } final Money chargePaid = Money.of(currency, amountPaid); if (!savingsAccountCharge.getAmountOutstanding(getCurrency()).isGreaterThanOrEqualTo(chargePaid)) { baseDataValidator.reset() .failWithCodeNoParameterAddedToErrorCode("transaction.invalid.charge.amount.paid.in.access"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } this.payCharge(savingsAccountCharge, chargePaid, transactionDate, user); }
From source file:org.projectbuendia.client.ui.chart.LocalizedChartDataGridAdapter.java
License:Apache License
private String formatColumnHeader(String columnId) { DateTime dateTime = DateTime.parse(columnId).withChronology(mChronology); LocalDate date = dateTime.toLocalDate(); Resources res = mContext.getResources(); int admitDay = Dates.dayNumberSince(mAdmissionDate, date); String admitDayLabel = (admitDay >= 1) ? res.getString(R.string.day_n, admitDay) : ""; String dateString = date.toString("d MMM"); String dateLabel = date.equals(mToday) ? res.getString(R.string.today_date, dateString) : dateString; // The column header has two lines of text: the first line gives the day number since // admission and the second line gives the calendar date. Pending feedback from the field // on its importance, the symptom onset day number could also be shown in the column // header in a different colour. This would be done by constructing HTML and using // Html.fromHtml() to produce a Spanned object that will be rendered by the TextView. return admitDayLabel + "\n" + dateLabel; }
From source file:org.projectbuendia.client.ui.dialogs.OrderExecutionDialogFragment.java
License:Apache License
void updateUi(boolean orderExecutedNow) { Bundle args = getArguments();// w ww .j a v a 2s .co m LocalDate date = new DateTime(Utils.getLong(args, "intervalStartMillis")).toLocalDate(); List<DateTime> executionTimes = new ArrayList<>(); for (long millis : args.getLongArray("executionTimes")) { executionTimes.add(new DateTime(millis)); } // Show what was ordered and when the order started. mOrderInstructions.setText(args.getString("instructions")); DateTime start = Utils.getDateTime(args, "orderStartMillis"); mOrderStartTime.setText(getResources().getString(R.string.order_started_on_date_at_time, Utils.toShortString(start.toLocalDate()), Utils.toTimeOfDayString(start))); // Describe how many times the order was executed during the selected interval. int count = executionTimes.size() + (orderExecutedNow ? 1 : 0); boolean plural = count != 1; mOrderExecutionCount.setText(Html.fromHtml(getResources().getString( date.equals(LocalDate.now()) ? (plural ? R.string.order_execution_today_plural_html : R.string.order_execution_today_singular_html) : (plural ? R.string.order_execution_historical_plural_html : R.string.order_execution_historical_singular_html), count, Utils.toShortString(date)))); // Show the list of times that the order was executed during the selected interval. boolean editable = args.getBoolean("editable"); Utils.showIf(mOrderExecutionList, executionTimes.size() > 0 || editable); List<String> htmlItems = new ArrayList<>(); for (DateTime executionTime : executionTimes) { htmlItems.add(Utils.toTimeOfDayString(executionTime)); } if (editable) { DateTime encounterTime = Utils.getDateTime(args, "encounterTimeMillis"); htmlItems.add( orderExecutedNow ? "<b>" + Utils.toTimeOfDayString(encounterTime) + "</b>" : "<b> </b>"); // keep total height stable } mOrderExecutionList.setText(Html.fromHtml(Joiner.on("<br>").join(htmlItems))); }
From source file:org.smartdeveloperhub.harvesters.it.testing.generator.ProjectActivityGenerator.java
License:Apache License
private boolean isInFlight(final Issue issue, final LocalDate today) { if (issue.getCreationDate().toLocalDate().equals(today)) { return true; }//from ww w .j a v a 2 s .c o m if (issue.getChanges() == null) { return false; } final Entry changeSet = Iterables.getLast(issue.getChanges().getEntries()); if (changeSet == null) { return false; } final LocalDate lastChangeDate = changeSet.getTimeStamp().toLocalDate(); return lastChangeDate.equals(today); }