Search in sources :

Example 36 with ScheduledEvent

use of org.mifos.schedule.ScheduledEvent in project head by mifos.

the class IndividualLoanScheduleFactory method create.

@Override
public LoanSchedule create(LocalDate disbursementDate, List<DateTime> loanScheduleDates, List<Number> totalInstallmentAmounts, LoanOfferingBO loanProduct, CustomerBO customer, MeetingBO loanMeeting, Money loanAmount, Double interestRate, Integer interestDays, Integer gracePeriodDuration, List<AccountFeesEntity> accountFees) {
    GraceType graceType = loanProduct.getGraceType();
    InterestType interestType = loanProduct.getInterestType();
    boolean variableInstallmentLoanProduct = loanProduct.isVariableInstallmentsAllowed();
    boolean roundingDifferenceInFirstPayment = loanProduct.isRoundingDifferenceInFirstPayment();
    Integer numberOfInstallments = loanScheduleDates.size();
    RecurringScheduledEventFactory scheduledEventFactory = new RecurringScheduledEventFactoryImpl();
    ScheduledEvent meetingScheduledEvent = scheduledEventFactory.createScheduledEventFrom(loanMeeting);
    Integer installmentNumber = 1;
    List<InstallmentDate> dueInstallmentDates = new ArrayList<InstallmentDate>();
    for (DateTime scheduledDate : loanScheduleDates) {
        dueInstallmentDates.add(new InstallmentDate(installmentNumber.shortValue(), scheduledDate.toLocalDate().toDateMidnight().toDate()));
        installmentNumber++;
    }
    if (loanProduct.isPrinDueLastInst()) {
        // Principal due on last installment has been cut, so throw an exception if we reach this code.
        throw new BusinessRuleException(AccountConstants.NOT_SUPPORTED_EMI_GENERATION);
    }
    // loan interest calculation for various interest calculation algorithms
    LoanDecliningInterestAnnualPeriodCalculator decliningInterestAnnualPeriodCalculator = new LoanDecliningInterestAnnualPeriodCalculatorFactory().create(loanMeeting.getRecurrenceType());
    Double decliningInterestAnnualPeriod = decliningInterestAnnualPeriodCalculator.calculate(loanMeeting.getRecurAfter().intValue(), interestDays);
    Double interestFractionalRatePerInstallment = interestRate / decliningInterestAnnualPeriod / 100;
    LoanDurationInAccountingYearsCalculator loanDurationInAccountingYearsCalculator = new LoanDurationInAccountingYearsCalculatorFactory().create(loanMeeting.getRecurrenceType());
    Double durationInYears = loanDurationInAccountingYearsCalculator.calculate(loanMeeting.getRecurAfter().intValue(), numberOfInstallments, interestDays);
    List<Money> totalInstallmentAmountsAsMoney = new ArrayList<Money>();
    for (Number totalInstallmentAmount : totalInstallmentAmounts) {
        Money totalAmount = new Money(loanAmount.getCurrency(), BigDecimal.valueOf(totalInstallmentAmount.doubleValue()));
        totalInstallmentAmountsAsMoney.add(totalAmount);
    }
    LoanInterestCalculationDetails loanInterestCalculationDetails = new LoanInterestCalculationDetails(loanAmount, interestRate, graceType, gracePeriodDuration, numberOfInstallments, durationInYears, interestFractionalRatePerInstallment, disbursementDate, loanScheduleDates);
    loanInterestCalculationDetails.setTotalInstallmentAmounts(totalInstallmentAmountsAsMoney);
    LoanInterestCalculatorFactory loanInterestCalculatorFactory = new LoanInterestCalculatorFactoryImpl();
    LoanInterestCalculator loanInterestCalculator = loanInterestCalculatorFactory.create(interestType, variableInstallmentLoanProduct);
    Money loanInterest = loanInterestCalculator.calculate(loanInterestCalculationDetails);
    // end of loan Interest creation
    EqualInstallmentGeneratorFactory equalInstallmentGeneratorFactory = new EqualInstallmentGeneratorFactoryImpl();
    PrincipalWithInterestGenerator equalInstallmentGenerator = equalInstallmentGeneratorFactory.create(interestType, loanInterest, variableInstallmentLoanProduct);
    List<InstallmentPrincipalAndInterest> EMIInstallments = equalInstallmentGenerator.generateEqualInstallments(loanInterestCalculationDetails);
    List<LoanScheduleEntity> unroundedLoanSchedules = createUnroundedLoanSchedulesFromInstallments(dueInstallmentDates, loanInterest, loanAmount, meetingScheduledEvent, EMIInstallments, accountFees, customer);
    Money rawAmount = calculateTotalFeesAndInterestForLoanSchedules(unroundedLoanSchedules, loanAmount.getCurrency(), accountFees);
    List<LoanScheduleEntity> allExistingLoanSchedules = new ArrayList<LoanScheduleEntity>();
    List<LoanScheduleEntity> finalisedLoanSchedules = new ArrayList<LoanScheduleEntity>(unroundedLoanSchedules);
    if (variableInstallmentLoanProduct && totalInstallmentAmounts.isEmpty()) {
        // only round inital loan schedule of variable installments product.
        LoanScheduleRounder loanScheduleInstallmentRounder = new VariableInstallmentLoanScheduleRounder();
        finalisedLoanSchedules = loanScheduleInstallmentRounder.round(graceType, gracePeriodDuration.shortValue(), loanAmount, interestType, unroundedLoanSchedules, allExistingLoanSchedules);
    } else if (!variableInstallmentLoanProduct && roundingDifferenceInFirstPayment) {
        LoanScheduleRounderHelper loanScheduleRounderHelper = new DefaultLoanScheduleRounderHelper();
        LoanScheduleRounder loanScheduleInstallmentRounder = new FirstInstallmentRoudingDifferenceLoanScheduleRounder(loanScheduleRounderHelper);
        finalisedLoanSchedules = loanScheduleInstallmentRounder.round(graceType, gracePeriodDuration.shortValue(), loanAmount, interestType, unroundedLoanSchedules, allExistingLoanSchedules);
    } else if (!variableInstallmentLoanProduct) {
        LoanScheduleRounderHelper loanScheduleRounderHelper = new DefaultLoanScheduleRounderHelper();
        LoanScheduleRounder loanScheduleInstallmentRounder = new DefaultLoanScheduleRounder(loanScheduleRounderHelper);
        finalisedLoanSchedules = loanScheduleInstallmentRounder.round(graceType, gracePeriodDuration.shortValue(), loanAmount, interestType, unroundedLoanSchedules, allExistingLoanSchedules);
    }
    return new LoanSchedule(finalisedLoanSchedules, rawAmount);
}
Also used : LoanScheduleEntity(org.mifos.accounts.loan.business.LoanScheduleEntity) ArrayList(java.util.ArrayList) DateTime(org.joda.time.DateTime) InstallmentDate(org.mifos.accounts.util.helpers.InstallmentDate) Money(org.mifos.framework.util.helpers.Money) BusinessRuleException(org.mifos.service.BusinessRuleException) GraceType(org.mifos.accounts.productdefinition.util.helpers.GraceType) ScheduledEvent(org.mifos.schedule.ScheduledEvent) InterestType(org.mifos.accounts.productdefinition.util.helpers.InterestType) InstallmentPrincipalAndInterest(org.mifos.accounts.loan.util.helpers.InstallmentPrincipalAndInterest)

Example 37 with ScheduledEvent

use of org.mifos.schedule.ScheduledEvent in project head by mifos.

the class CustomerAccountBO method generateNextSetOfMeetingDates.

public void generateNextSetOfMeetingDates(ScheduledDateGeneration scheduleGenerationStrategy) {
    Short lastInstallmentId = Short.valueOf("0");
    if (getLastInstallmentId() != null) {
        lastInstallmentId = getLastInstallmentId();
    }
    AccountActionDateEntity lastInstallment = getAccountActionDate(lastInstallmentId);
    MeetingBO meeting = getCustomer().getCustomerMeetingValue();
    ScheduledEvent scheduledEvent = ScheduledEventFactory.createScheduledEventFrom(meeting);
    Date lastInstallmentDate = new Date();
    if (lastInstallment != null) {
        lastInstallmentDate = lastInstallment.getActionDate();
    }
    /*
         * Generate more scheduled dates starting with the date of the last generated installment.
         * This ensures that the customer's meeting recurrence is taken into account. But then
         * skip the first date when adding account actions because it's already there.
         */
    DateTime dateOfLastInstallment = new DateTime(lastInstallmentDate).toDateMidnight().toDateTime();
    List<DateTime> scheduledDates = scheduleGenerationStrategy.generateScheduledDates(numberOfMeetingDatesToGenerate + 1, dateOfLastInstallment, scheduledEvent, true);
    int count = 1;
    for (DateTime installmentDate : allButFirst(scheduledDates)) {
        CustomerScheduleEntity customerScheduleEntity = new CustomerScheduleEntity(this, getCustomer(), Short.valueOf(String.valueOf(count + lastInstallmentId)), new java.sql.Date(installmentDate.toDate().getTime()), PaymentStatus.UNPAID);
        count++;
        addAccountActionDate(customerScheduleEntity);
    }
    applyPeriodicFeesToNextSetOfMeetingDates();
}
Also used : AccountActionDateEntity(org.mifos.accounts.business.AccountActionDateEntity) DailyScheduledEvent(org.mifos.schedule.internal.DailyScheduledEvent) ScheduledEvent(org.mifos.schedule.ScheduledEvent) MeetingBO(org.mifos.application.meeting.business.MeetingBO) Date(java.util.Date) InstallmentDate(org.mifos.accounts.util.helpers.InstallmentDate) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime)

Example 38 with ScheduledEvent

use of org.mifos.schedule.ScheduledEvent in project head by mifos.

the class CustomerAccountBO method regenerateFutureInstallments.

@Override
protected void regenerateFutureInstallments(final AccountActionDateEntity nextInstallment, final List<Days> workingDays, final List<Holiday> holidays) throws AccountException {
    int numberOfInstallmentsToGenerate = getLastInstallmentId();
    MeetingBO meeting = getMeetingForAccount();
    ScheduledEvent scheduledEvent = ScheduledEventFactory.createScheduledEventFrom(meeting);
    LocalDate currentDate = new LocalDate();
    LocalDate thisIntervalStartDate = meeting.startDateForMeetingInterval(currentDate);
    LocalDate nextMatchingDate = new LocalDate(scheduledEvent.nextEventDateAfter(thisIntervalStartDate.toDateTimeAtStartOfDay()));
    DateTime futureIntervalStartDate = meeting.startDateForMeetingInterval(nextMatchingDate).toDateTimeAtStartOfDay();
    ScheduledDateGeneration dateGeneration = new HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration(workingDays, holidays);
    List<DateTime> meetingDates = dateGeneration.generateScheduledDates(numberOfInstallmentsToGenerate, futureIntervalStartDate, scheduledEvent, true);
    updateSchedule(nextInstallment.getInstallmentId(), meetingDates);
}
Also used : DailyScheduledEvent(org.mifos.schedule.internal.DailyScheduledEvent) ScheduledEvent(org.mifos.schedule.ScheduledEvent) HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration(org.mifos.schedule.internal.HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration) ScheduledDateGeneration(org.mifos.schedule.ScheduledDateGeneration) MeetingBO(org.mifos.application.meeting.business.MeetingBO) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration(org.mifos.schedule.internal.HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration)

Aggregations

ScheduledEvent (org.mifos.schedule.ScheduledEvent)38 DateTime (org.joda.time.DateTime)23 LocalDate (org.joda.time.LocalDate)16 ArrayList (java.util.ArrayList)14 AccountFeesEntity (org.mifos.accounts.business.AccountFeesEntity)13 Test (org.junit.Test)12 FeeInstallment (org.mifos.accounts.util.helpers.FeeInstallment)12 ScheduledDateGeneration (org.mifos.schedule.ScheduledDateGeneration)12 HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration (org.mifos.schedule.internal.HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration)12 Date (java.util.Date)11 AccountActionDateEntity (org.mifos.accounts.business.AccountActionDateEntity)11 AmountFeeBO (org.mifos.accounts.fees.business.AmountFeeBO)10 FeeBO (org.mifos.accounts.fees.business.FeeBO)9 ScheduledEventBuilder (org.mifos.domain.builders.ScheduledEventBuilder)9 InstallmentDate (org.mifos.accounts.util.helpers.InstallmentDate)8 MeetingBO (org.mifos.application.meeting.business.MeetingBO)7 InterestScheduledEvent (org.mifos.accounts.savings.interest.schedule.InterestScheduledEvent)6 HolidayDao (org.mifos.application.holiday.persistence.HolidayDao)5 Days (org.joda.time.Days)4 Holiday (org.mifos.application.holiday.business.Holiday)4