public Loan SimulateRescheduling(Loan loan, ScheduleConfiguration rescheduleConfiguration) { var copyOfLoan = loan.Copy(); var scheduleConfiguration = _configurationFactory .Init() .WithLoan(copyOfLoan) .Finish() .GetConfiguration(); var schedule = Mapper.Map<IEnumerable<Installment>, IEnumerable<IInstallment>>(copyOfLoan.InstallmentList); var scheduleBuilder = new ScheduleBuilder(); var rescheduleAssembler = new RescheduleAssembler(); var copyOfRescheduleConfiguration = (IScheduleConfiguration) rescheduleConfiguration.Clone(); copyOfRescheduleConfiguration.InterestRate *= (decimal) scheduleConfiguration.PeriodPolicy.GetNumberOfPeriodsInYear( copyOfRescheduleConfiguration.StartDate, scheduleConfiguration.YearPolicy); schedule = rescheduleAssembler.AssembleRescheduling( schedule, scheduleConfiguration, copyOfRescheduleConfiguration, scheduleBuilder, loan.CalculateActualOlb().Value); var newSchedule = Mapper.Map<IEnumerable<IInstallment>, List<Installment>>(schedule); copyOfLoan.InstallmentList = newSchedule; copyOfLoan.NbOfInstallments = newSchedule.Count(); return copyOfLoan; }
private List<Installment> AssembleRescheduling(Loan loan, ScheduleConfiguration rescheduleConfiguration, IScheduleConfiguration scheduleConfiguration) { var copyOfLoan = loan.Copy();; var schedule = copyOfLoan.InstallmentList; // Build a new combined schedule // 1. To close all active installments before date of rescheduling. // Get the part of the schedule that comes before the rescheduling date... var newSchedule = from installment in schedule where installment.ExpectedDate <= rescheduleConfiguration.StartDate select installment; // Get overpaid principal = sum of paid principal after the rescheduling date... var overpaidPrincipal = ( from installment in schedule where installment.PaidDate > rescheduleConfiguration.StartDate select installment ).Sum(installment => installment.PaidCapital.Value); //Add overpaid principal to paid principal of the last installment before the rescheduling if (newSchedule.Any()) newSchedule.Last().PaidCapital += overpaidPrincipal; // Close all active installments before date of rescheduling var olbDifference = 0m; foreach (var installment in newSchedule) { installment.OLB += olbDifference; olbDifference += installment.CapitalRepayment.Value - installment.PaidCapital.Value; installment.CapitalRepayment = installment.PaidCapital; installment.InterestsRepayment = installment.PaidInterests; } // 2. To store amounts of interest paid, those for installments after date of rescheduling. var overpaidInterest = ( from installment in schedule where installment.ExpectedDate > rescheduleConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterests.Value); // 3. To get total of first calculated interest. It will be interest between last closed installment and date of rescheduling // plus interest between date of rescheduling and first repayment date // To calculate extra interest for used days. // For the case when date of rescheduling < date of first installment var currentOlb = loan.CalculateActualOlb().Value; var usedDays = 0; if (newSchedule.Any()) { usedDays = (rescheduleConfiguration.StartDate - newSchedule.Last().ExpectedDate).Days; } var daysInYear = scheduleConfiguration.YearPolicy.GetNumberOfDays(rescheduleConfiguration.StartDate); var extraInterest = currentOlb * scheduleConfiguration.InterestRate / 100 * usedDays / daysInYear; // To calculate interest between date of rescheduling and first repayment date. var daysTillRepayment = (rescheduleConfiguration.PreferredFirstInstallmentDate - rescheduleConfiguration.StartDate).Days; decimal firstInterest = 0; if (rescheduleConfiguration.GracePeriod == 0 || rescheduleConfiguration.ChargeInterestDuringGracePeriod) firstInterest = currentOlb*rescheduleConfiguration.InterestRate/100*daysTillRepayment/ scheduleConfiguration.PeriodPolicy.GetNumberOfDays( rescheduleConfiguration.PreferredFirstInstallmentDate); copyOfLoan.Amount = currentOlb; copyOfLoan.InterestRate = rescheduleConfiguration.InterestRate/100; copyOfLoan.NbOfInstallments = rescheduleConfiguration.NumberOfInstallments; copyOfLoan.GracePeriod = rescheduleConfiguration.GracePeriod; copyOfLoan.StartDate = rescheduleConfiguration.StartDate; copyOfLoan.FirstInstallmentDate = rescheduleConfiguration.PreferredFirstInstallmentDate; copyOfLoan.Product.ChargeInterestWithinGracePeriod = rescheduleConfiguration.ChargeInterestDuringGracePeriod; rescheduleConfiguration.RoundingPolicy = scheduleConfiguration.RoundingPolicy; var rescheduled = SimulateScheduleCreation(copyOfLoan); // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in rescheduled) { installment.Number += increment; } // Distribute the extra and overpaid interest if (rescheduleConfiguration.GracePeriod > 0 && !rescheduleConfiguration.ChargeInterestDuringGracePeriod) rescheduled[rescheduleConfiguration.GracePeriod].InterestsRepayment += rescheduleConfiguration.RoundingPolicy.Round(extraInterest); else rescheduled.First().InterestsRepayment = rescheduleConfiguration.RoundingPolicy.Round(firstInterest + extraInterest); foreach (var installment in rescheduled) { if (installment.InterestsRepayment < overpaidInterest) { installment.PaidInterests = installment.InterestsRepayment; overpaidInterest -= installment.InterestsRepayment.Value; } else { installment.PaidInterests = overpaidInterest; break; } } var result = new List<Installment>(); result.AddRange(newSchedule); result.AddRange(rescheduled); return result; }
public Loan Reschedule(Loan loan, IClient client, ScheduleConfiguration rescheduleConfiguration) { using (var connection = _loanManager.GetConnection()) using (var transaction = connection.BeginTransaction()) { try { var copyOfLoan = SimulateRescheduling(loan, rescheduleConfiguration); var rescheduleLoanEvent = new RescheduleLoanEvent { Amount = copyOfLoan.CalculateActualOlb(), Date = rescheduleConfiguration.StartDate, ClientType = client.Type, Interest = rescheduleConfiguration.InterestRate, BadLoan = loan.BadLoan, NbOfMaturity = rescheduleConfiguration.NumberOfInstallments, GracePeriod = rescheduleConfiguration.GracePeriod, ChargeInterestDuringGracePeriod = rescheduleConfiguration.ChargeInterestDuringGracePeriod, InstallmentNumber = copyOfLoan.GetLastFullyRepaidInstallment() == null ? 1 : copyOfLoan.GetLastFullyRepaidInstallment().Number + 1, PreferredFirstInstallmentDate = rescheduleConfiguration.PreferredFirstInstallmentDate, User = _user, PreviousInterestRate = rescheduleConfiguration.PreviousInterestRate, }; //insert into table TrancheEvent _ePs.FireEvent(rescheduleLoanEvent, copyOfLoan, transaction); ArchiveInstallments(loan, rescheduleLoanEvent, transaction); //delete all the old installments of the table Installments _instalmentManager.DeleteInstallments(loan.Id, transaction); //insert all the new installments in the table Installments _instalmentManager.AddInstallments(copyOfLoan.InstallmentList, copyOfLoan.Id, transaction); copyOfLoan.Events.Add(rescheduleLoanEvent); transaction.Commit(); SetClientStatus(copyOfLoan, client); return copyOfLoan; } catch { transaction.Rollback(); throw; } } }
public Loan SimulateRescheduling(Loan loan, ScheduleConfiguration rescheduleConfiguration) { var copyOfLoan = loan.Copy(); var scheduleConfiguration = _configurationFactory .Init() .WithLoan(copyOfLoan) .Finish() .GetConfiguration(); var schedule = copyOfLoan.InstallmentList; var scheduleBuilder = new ScheduleBuilder(); var rescheduleAssembler = new RescheduleAssembler(); var copyOfRescheduleConfiguration = (IScheduleConfiguration)rescheduleConfiguration.Clone(); if (loan.Product.ScriptName == null) schedule = rescheduleAssembler.AssembleRescheduling( schedule, scheduleConfiguration, copyOfRescheduleConfiguration, scheduleBuilder, loan.CalculateActualOlb().Value).ToList(); else schedule = AssembleRescheduling(loan, rescheduleConfiguration, scheduleConfiguration); copyOfLoan.InstallmentList = schedule; copyOfLoan.NbOfInstallments = schedule.Count(); return copyOfLoan; }