use of org.mifos.accounts.util.helpers.InstallmentDate 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);
}
use of org.mifos.accounts.util.helpers.InstallmentDate in project head by mifos.
the class IndividualLoanScheduleFactory method createUnroundedLoanSchedulesFromInstallments.
private List<LoanScheduleEntity> createUnroundedLoanSchedulesFromInstallments(List<InstallmentDate> installmentDates, Money loanInterest, Money loanAmount, ScheduledEvent meetingScheduledEvent, List<InstallmentPrincipalAndInterest> principalWithInterestInstallments, List<AccountFeesEntity> accountFees, CustomerBO customer) {
List<LoanScheduleEntity> unroundedLoanSchedules = new ArrayList<LoanScheduleEntity>();
List<AccountFeesEntity> accountFeesWithNoTimeOfDibursementFees = new ArrayList<AccountFeesEntity>();
List<FeeInstallment> feeInstallments = new ArrayList<FeeInstallment>();
if (!accountFees.isEmpty()) {
InstallmentFeeCalculatorFactory installmentFeeCalculatorFactory = new InstallmentFeeCalculatorFactoryImpl();
for (AccountFeesEntity accountFeesEntity : accountFees) {
RateAmountFlag feeType = accountFeesEntity.getFees().getFeeType();
InstallmentFeeCalculator installmentFeeCalculator = installmentFeeCalculatorFactory.create(this.feeDao, feeType);
Double feeAmountOrRate = accountFeesEntity.getFeeAmount();
Money accountFeeAmount = installmentFeeCalculator.calculate(feeAmountOrRate, loanAmount, loanInterest, accountFeesEntity.getFees());
accountFeesEntity.setAccountFeeAmount(accountFeeAmount);
if (!accountFeesEntity.isTimeOfDisbursement()) {
accountFeesWithNoTimeOfDibursementFees.add(accountFeesEntity);
}
}
feeInstallments = FeeInstallment.createMergedFeeInstallments(meetingScheduledEvent, accountFeesWithNoTimeOfDibursementFees, installmentDates.size());
}
int installmentIndex = 0;
for (InstallmentDate installmentDate1 : installmentDates) {
InstallmentPrincipalAndInterest em = principalWithInterestInstallments.get(installmentIndex);
LoanScheduleEntity loanScheduleEntity = new LoanScheduleEntity(null, customer, installmentDate1.getInstallmentId(), new java.sql.Date(installmentDate1.getInstallmentDueDate().getTime()), PaymentStatus.UNPAID, em.getPrincipal(), em.getInterest());
for (FeeInstallment feeInstallment : feeInstallments) {
if (feeInstallment.getInstallmentId().equals(installmentDate1.getInstallmentId())) {
LoanFeeScheduleEntity loanFeeScheduleEntity = new LoanFeeScheduleEntity(loanScheduleEntity, feeInstallment.getAccountFeesEntity().getFees(), feeInstallment.getAccountFeesEntity(), feeInstallment.getAccountFee());
loanScheduleEntity.addAccountFeesAction(loanFeeScheduleEntity);
}
}
unroundedLoanSchedules.add(loanScheduleEntity);
installmentIndex++;
}
return unroundedLoanSchedules;
}
use of org.mifos.accounts.util.helpers.InstallmentDate in project head by mifos.
the class CustomerAccountBO method generateMeetingSchedule.
/**
* @deprecated - use static factory methods for creating {@link CustomerAccountBO} and inject in installment dates.
*/
@Deprecated
private void generateMeetingSchedule() throws AccountException {
// generate dates that adjust for holidays
List<InstallmentDate> installmentDates = getInstallmentDates(getCustomer().getCustomerMeeting().getMeeting(), (short) 10, (short) 0);
// generate dates without adjusting for holidays
List<InstallmentDate> nonAdjustedInstallmentDates = getInstallmentDates(getCustomer().getCustomerMeeting().getMeeting(), (short) 10, (short) 0, false, true);
logger.debug("RepamentSchedular:getRepaymentSchedule , installment dates obtained ");
List<FeeInstallment> feeInstallmentList = mergeFeeInstallments(getFeeInstallments(installmentDates, nonAdjustedInstallmentDates));
logger.debug("RepamentSchedular:getRepaymentSchedule , fee installment obtained ");
for (InstallmentDate installmentDate : installmentDates) {
CustomerScheduleEntity customerScheduleEntity = new CustomerScheduleEntity(this, getCustomer(), installmentDate.getInstallmentId(), new java.sql.Date(installmentDate.getInstallmentDueDate().getTime()), PaymentStatus.UNPAID);
addAccountActionDate(customerScheduleEntity);
for (FeeInstallment feeInstallment : feeInstallmentList) {
if (feeInstallment.getInstallmentId().equals(installmentDate.getInstallmentId())) {
CustomerFeeScheduleEntity customerFeeScheduleEntity = new CustomerFeeScheduleEntity(customerScheduleEntity, feeInstallment.getAccountFeesEntity().getFees(), feeInstallment.getAccountFeesEntity(), feeInstallment.getAccountFee());
customerScheduleEntity.addAccountFeesAction(customerFeeScheduleEntity);
}
}
}
logger.debug("RepamentSchedular:getRepaymentSchedule , repayment schedule generated ");
}
use of org.mifos.accounts.util.helpers.InstallmentDate in project head by mifos.
the class CustomerAccountBO method applyOneTimeFee.
private void applyOneTimeFee(final FeeBO fee, final Money charge, final AccountActionDateEntity accountActionDateEntity) throws AccountException {
CustomerScheduleEntity customerScheduleEntity = (CustomerScheduleEntity) accountActionDateEntity;
AccountFeesEntity accountFee = new AccountFeesEntity(this, fee, charge.getAmountDoubleValue(), FeeStatus.ACTIVE.getValue(), new DateTimeService().getCurrentJavaDateTime(), null);
List<AccountActionDateEntity> customerScheduleList = new ArrayList<AccountActionDateEntity>();
customerScheduleList.add(customerScheduleEntity);
List<InstallmentDate> installmentDates = new ArrayList<InstallmentDate>();
installmentDates.add(new InstallmentDate(accountActionDateEntity.getInstallmentId(), accountActionDateEntity.getActionDate()));
List<FeeInstallment> feeInstallmentList = new ArrayList<FeeInstallment>();
feeInstallmentList.add(handleOneTime(accountFee, installmentDates));
Money totalFeeAmountApplied = applyFeeToInstallments(feeInstallmentList, customerScheduleList);
updateCustomerActivity(fee.getFeeId(), totalFeeAmountApplied, fee.getFeeName() + AccountConstants.APPLIED);
accountFee.setFeeStatus(FeeStatus.ACTIVE);
}
use of org.mifos.accounts.util.helpers.InstallmentDate 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();
}
Aggregations