private DateTime GetLastEndDate(IEnumerable<Installment> schedule, ITrancheConfiguration trancheConfiguration) { var installment = (from i in schedule where i.ExpectedDate <= trancheConfiguration.StartDate select i).LastOrDefault(); if (installment == null) return schedule.First().StartDate; return installment.ExpectedDate; }
public List<Installment> BuildTranche(IEnumerable<Installment> schedule, IScheduleBuilder scheduleBuilder, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var rhc = (IScheduleConfiguration)scheduleConfiguration.Clone(); rhc.Amount = trancheConfiguration.Amount; rhc.NumberOfInstallments = trancheConfiguration.NumberOfInstallments; rhc.GracePeriod = trancheConfiguration.GracePeriod; rhc.InterestRate = trancheConfiguration.InterestRate; rhc.StartDate = trancheConfiguration.StartDate; rhc.PreferredFirstInstallmentDate = trancheConfiguration.PreferredFirstInstallmentDate; var lhc = (IScheduleConfiguration)rhc.Clone(); lhc.Amount = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); if (!trancheConfiguration.ApplyNewInterestRateToOlb) { lhc.InterestRate = scheduleConfiguration.InterestRate; } var lhs = scheduleBuilder.BuildSchedule(lhc); var rhs = scheduleBuilder.BuildSchedule(rhc); var result = new List<Installment>(); // Merge the two schedules var max = Math.Max(lhs.Count, rhs.Count); for (var i = 0; i < max; i++) { var lhi = i >= lhs.Count ? null : lhs[i]; var rhi = i >= rhs.Count ? null : rhs[i]; Installment installment; if (lhi == null) { installment = rhi; } else if (rhi == null) { installment = lhi; } else { installment = new Installment { Number = lhi.Number, StartDate = lhi.StartDate, ExpectedDate = lhi.ExpectedDate, //RepaymentDate = lhi.RepaymentDate, CapitalRepayment = lhi.CapitalRepayment + rhi.CapitalRepayment, InterestsRepayment = lhi.InterestsRepayment + rhi.InterestsRepayment, OLB = lhi.OLB + rhi.OLB, }; } result.Add(installment); } result[0].InterestsRepayment += GetExtraInterest(schedule, scheduleConfiguration, trancheConfiguration); return result; }
private decimal GetExtraInterest(IEnumerable<Installment> schedule, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var days = (trancheConfiguration.StartDate - GetLastEndDate(schedule, trancheConfiguration)).Days; var daysInYear = scheduleConfiguration.YearPolicy.GetNumberOfDays(trancheConfiguration.StartDate); var olb = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); var interest = olb * scheduleConfiguration.InterestRate / 100 * days / daysInYear; return scheduleConfiguration.RoundingPolicy.Round(interest); }
private decimal GetExtraInterest(IEnumerable <Installment> schedule, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var days = (trancheConfiguration.StartDate - GetLastEndDate(schedule, trancheConfiguration)).Days; var daysInYear = scheduleConfiguration.YearPolicy.GetNumberOfDays(trancheConfiguration.StartDate); var olb = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); var interest = olb * scheduleConfiguration.InterestRate / 100 * days / daysInYear; return(scheduleConfiguration.RoundingPolicy.Round(interest)); }
private DateTime GetLastEndDate(IEnumerable <Installment> schedule, ITrancheConfiguration trancheConfiguration) { var installment = (from i in schedule where i.ExpectedDate <= trancheConfiguration.StartDate select i).LastOrDefault(); if (installment == null) { return(schedule.First().StartDate); } return(installment.ExpectedDate); }
public Loan AddTranche(Loan loan, IClient client, ITrancheConfiguration trancheConfiguration, IList<LoanEntryFee> entryFees, PaymentMethod paymentMethod) { using (var connection = _loanManager.GetConnection()) using (var transaction = connection.BeginTransaction()) { try { CheckTranche(trancheConfiguration.StartDate, loan, trancheConfiguration.Amount); var copyOfLoan = SimulateTranche(loan, trancheConfiguration); var startInstallment = copyOfLoan.InstallmentList .FindAll(i => i.ExpectedDate <= trancheConfiguration.StartDate) .LastOrDefault(); var trancheEvent = new TrancheEvent { Amount = trancheConfiguration.Amount, ApplyNewInterest = trancheConfiguration.ApplyNewInterestRateToOlb, Maturity = trancheConfiguration.NumberOfInstallments, StartDate = trancheConfiguration.StartDate, Date = trancheConfiguration.StartDate, InterestRate = trancheConfiguration.InterestRate/100, Number = copyOfLoan.GivenTranches.Count, FirstRepaymentDate = trancheConfiguration.PreferredFirstInstallmentDate, GracePeriod = trancheConfiguration.GracePeriod, StartedFromInstallment = startInstallment == null ? 0 : startInstallment.Number, User = _user, PaymentMethod = paymentMethod }; trancheEvent.User = _user; //insert into table TrancheEvent _ePs.FireEvent(trancheEvent, copyOfLoan, transaction); copyOfLoan.Events.Add(trancheEvent); CallInterceptor(new Dictionary<string, object> { {"Loan", copyOfLoan}, {"Event", trancheEvent}, {"SqlTransaction", transaction} }); // Add entry fee events foreach (var entryFee in entryFees) { if (entryFee.FeeValue == 0) continue; var entryFeeEvent = new LoanEntryFeeEvent { Fee = entryFee.FeeValue, Code = "LEE" + entryFee.ProductEntryFee.Index, DisbursementEventId = trancheEvent.Id, Cancelable = true, User = User.CurrentUser, Date = trancheEvent.Date }; _ePs.FireEvent(entryFeeEvent, copyOfLoan, transaction); copyOfLoan.Events.Add(entryFeeEvent); } var trancheEntryFeeEvent = copyOfLoan.Events.OfType<LoanEntryFeeEvent>() .First(i => i.DisbursementEventId == trancheEvent.Id); if (trancheEntryFeeEvent != null) CallInterceptor(new Dictionary<string, object> { {"Loan", copyOfLoan}, { "Event", new LoanEntryFeeEvent { Id = trancheEntryFeeEvent.Id, Fee = entryFees.Sum(i => i.FeeValue), Code = "LEE0" } }, {"SqlTransaction", transaction} }); ArchiveInstallments(loan, trancheEvent, 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); //Activate the contract if it's closed because of new tranch if (copyOfLoan.Closed) { copyOfLoan.ContractStatus = OContractStatus.Active; copyOfLoan.Closed = false; _loanManager.UpdateLoan(copyOfLoan, transaction); } //in the feature might be combine UpdateLoan + UpdateLoanWithinTranche _loanManager.UpdateLoanWithinTranche( trancheConfiguration.InterestRate/100, copyOfLoan.NbOfInstallments, copyOfLoan, transaction); copyOfLoan.GivenTranches.Add(trancheEvent); transaction.Commit(); SetClientStatus(copyOfLoan, client); return copyOfLoan; } catch { transaction.Rollback(); throw; } } }
public Loan SimulateTranche(Loan loan, ITrancheConfiguration trancheConfiguration) { 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 trancheBuilder = new TrancheBuilder(); var trancheAssembler = new TrancheAssembler(); var copyOfTrancheConfiguration = (ITrancheConfiguration) trancheConfiguration.Clone(); copyOfTrancheConfiguration.InterestRate *= (decimal) scheduleConfiguration.PeriodPolicy.GetNumberOfPeriodsInYear( copyOfTrancheConfiguration.StartDate, scheduleConfiguration.YearPolicy); schedule = trancheAssembler.AssembleTranche( schedule, scheduleConfiguration, copyOfTrancheConfiguration, scheduleBuilder, trancheBuilder); var newSchedule = Mapper.Map<IEnumerable<IInstallment>, List<Installment>>(schedule); foreach (var installment in newSchedule) { var oldInstallment = copyOfLoan.InstallmentList.Find(i => i.Number == installment.Number); if (oldInstallment == null) break; installment.Comment = oldInstallment.Comment; installment.PaidFees = oldInstallment.PaidFees; installment.PaidCommissions = oldInstallment.PaidCommissions; installment.FeesUnpaid = oldInstallment.FeesUnpaid; installment.CommissionsUnpaid = oldInstallment.CommissionsUnpaid; installment.IsPending = oldInstallment.IsPending; //installment.PaidDate = oldInstallment.PaidDate; } copyOfLoan.InstallmentList = newSchedule; copyOfLoan.NbOfInstallments = newSchedule.Count(); copyOfLoan.Amount += trancheConfiguration.Amount; return copyOfLoan; }
private IEnumerable<Installment> BuildTranche(IEnumerable<Installment> schedule,Loan loan, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var copyOfLoan = loan.Copy(); loan.Amount = trancheConfiguration.Amount; loan.NbOfInstallments = trancheConfiguration.NumberOfInstallments; loan.GracePeriod = trancheConfiguration.GracePeriod; loan.InterestRate = trancheConfiguration.InterestRate/100; loan.StartDate = trancheConfiguration.StartDate; loan.FirstInstallmentDate = trancheConfiguration.PreferredFirstInstallmentDate; var rhs = SimulateScheduleCreation(loan); loan.Amount = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); if (!trancheConfiguration.ApplyNewInterestRateToOlb) { loan.InterestRate = copyOfLoan.InterestRate; } var lhs = SimulateScheduleCreation(loan); var result = new List<Installment>(); // Merge the two schedules var max = Math.Max(lhs.Count, rhs.Count); for (var i = 0; i < max; i++) { var lhi = i >= lhs.Count ? null : lhs[i]; var rhi = i >= rhs.Count ? null : rhs[i]; Installment installment; if (lhi == null) { installment = rhi; } else if (rhi == null) { installment = lhi; } else { installment = new Installment { Number = lhi.Number, StartDate = lhi.StartDate, ExpectedDate = lhi.ExpectedDate, //RepaymentDate = lhi.RepaymentDate, CapitalRepayment = lhi.CapitalRepayment + rhi.CapitalRepayment, InterestsRepayment = lhi.InterestsRepayment + rhi.InterestsRepayment, OLB = lhi.OLB + rhi.OLB, }; } result.Add(installment); } result[0].InterestsRepayment += GetExtraInterest(schedule, scheduleConfiguration, trancheConfiguration); return result; }
private List<Installment> AssembleTranche(Loan loan, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var schedule = loan.InstallmentList; var trancheSchedule = BuildTranche(schedule, loan, scheduleConfiguration, trancheConfiguration); // Get an interested paid in advance, whereas "in advance" means after the new tranche date var overpaidInterest = ( from installment in schedule where installment.ExpectedDate > trancheConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterests.Value); // Get the part of the schedule that comes before the tranche date... var newSchedule = from installment in schedule where installment.ExpectedDate <= trancheConfiguration.StartDate select installment; // ...and force close it (set expected equal to paid) var olbDifference = 0m; foreach (var installment in newSchedule) { installment.OLB += olbDifference; olbDifference += installment.CapitalRepayment.Value - installment.PaidCapital.Value; if (!(installment.CapitalRepayment == installment.PaidCapital && installment.InterestsRepayment == installment.PaidInterests)) { installment.PaidDate = trancheConfiguration.StartDate; } installment.CapitalRepayment = installment.PaidCapital; installment.InterestsRepayment = installment.PaidInterests; } // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in trancheSchedule) { installment.Number += increment; } var result = new List<Installment>(); result.AddRange(newSchedule); // Distribute the overpaid interest foreach (var installment in trancheSchedule) { if (installment.InterestsRepayment < overpaidInterest) { installment.PaidInterests = installment.InterestsRepayment; overpaidInterest -= installment.InterestsRepayment.Value; } else { installment.PaidInterests = overpaidInterest; break; } } result.AddRange(trancheSchedule); return result; }
public Loan SimulateTranche(Loan loan, ITrancheConfiguration trancheConfiguration) { var copyOfLoan = loan.Copy(); var scheduleConfiguration = _configurationFactory .Init() .WithLoan(copyOfLoan) .Finish() .GetConfiguration(); var schedule = copyOfLoan.InstallmentList; var scheduleBuilder = new ScheduleBuilder(); var trancheBuilder = new TrancheBuilder(); var trancheAssembler = new TrancheAssembler(); var copyOfTrancheConfiguration = (ITrancheConfiguration)trancheConfiguration.Clone(); var newSchedule = new List<Installment>(); if (loan.Product.ScriptName == null) newSchedule = trancheAssembler.AssembleTranche( schedule, scheduleConfiguration, copyOfTrancheConfiguration, scheduleBuilder, trancheBuilder).ToList(); else newSchedule = AssembleTranche(copyOfLoan, scheduleConfiguration, trancheConfiguration); foreach (var installment in newSchedule) { var oldInstallment = copyOfLoan.InstallmentList.Find(i => i.Number == installment.Number); if (oldInstallment == null) break; installment.Comment = oldInstallment.Comment; installment.PaidFees = oldInstallment.PaidFees; installment.PaidCommissions = oldInstallment.PaidCommissions; installment.FeesUnpaid = oldInstallment.FeesUnpaid; installment.CommissionsUnpaid = oldInstallment.CommissionsUnpaid; installment.IsPending = oldInstallment.IsPending; //installment.PaidDate = oldInstallment.PaidDate; } copyOfLoan.InstallmentList = newSchedule; copyOfLoan.NbOfInstallments = newSchedule.Count(); copyOfLoan.Amount += trancheConfiguration.Amount; return copyOfLoan; }
public IEnumerable <Installment> AssembleTranche( IEnumerable <Installment> schedule, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration, IScheduleBuilder scheduleBuilder, ITrancheBuilder trancheBuilder) { // Build a new combined schedule var trancheSchedule = trancheBuilder.BuildTranche(schedule, scheduleBuilder, scheduleConfiguration, trancheConfiguration); // Get an interested paid in advance, whereas "in advance" means after the new tranche date var overpaidInterest = ( from installment in schedule where installment.ExpectedDate > trancheConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterests.Value); // Get the part of the schedule that comes before the tranche date... var newSchedule = from installment in schedule where installment.ExpectedDate <= trancheConfiguration.StartDate select installment; // ...and force close it (set expected equal to paid) var olbDifference = 0m; foreach (var installment in newSchedule) { installment.OLB += olbDifference; olbDifference += installment.CapitalRepayment.Value - installment.PaidCapital.Value; if (!(installment.CapitalRepayment == installment.PaidCapital && installment.InterestsRepayment == installment.PaidInterests)) { installment.PaidDate = trancheConfiguration.StartDate; } installment.CapitalRepayment = installment.PaidCapital; installment.InterestsRepayment = installment.PaidInterests; } // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in trancheSchedule) { installment.Number += increment; } var result = new List <Installment>(); result.AddRange(newSchedule); // Distribute the overpaid interest foreach (var installment in trancheSchedule) { if (installment.InterestsRepayment < overpaidInterest) { installment.PaidInterests = installment.InterestsRepayment; overpaidInterest -= installment.InterestsRepayment.Value; } else { installment.PaidInterests = overpaidInterest; break; } } result.AddRange(trancheSchedule); return(result); }
public IEnumerable<IInstallment> AssembleTranche( IEnumerable<IInstallment> schedule, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration, IScheduleBuilder scheduleBuilder, ITrancheBuilder trancheBuilder) { // Build a new combined schedule var trancheSchedule = trancheBuilder.BuildTranche(schedule, scheduleBuilder, scheduleConfiguration, trancheConfiguration); // Get an interested paid in advance, whereas "in advance" means after the new tranche date var overpaidInterest = ( from installment in schedule where installment.RepaymentDate > trancheConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterest); // Get the part of the schedule that comes before the tranche date... var newSchedule = from installment in schedule where installment.RepaymentDate <= trancheConfiguration.StartDate select installment; // ...and force close it (set expected equal to paid) var olbDifference = 0m; foreach (var installment in newSchedule) { installment.Olb += olbDifference; olbDifference += installment.Principal - installment.PaidPrincipal; if (!(installment.Principal == installment.PaidPrincipal && installment.Interest == installment.PaidInterest)) { installment.LastPaymentDate = trancheConfiguration.StartDate; } installment.Principal = installment.PaidPrincipal; installment.Interest = installment.PaidInterest; } // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in trancheSchedule) { installment.Number += increment; } var result = new List<IInstallment>(); result.AddRange(newSchedule); // Distribute the overpaid interest foreach (var installment in trancheSchedule) { if (installment.Interest < overpaidInterest) { installment.PaidInterest = installment.Interest; overpaidInterest -= installment.Interest; } else { installment.PaidInterest = overpaidInterest; break; } } result.AddRange(trancheSchedule); return result; }
public List <Installment> BuildTranche(IEnumerable <Installment> schedule, IScheduleBuilder scheduleBuilder, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var rhc = (IScheduleConfiguration)scheduleConfiguration.Clone(); rhc.Amount = trancheConfiguration.Amount; rhc.NumberOfInstallments = trancheConfiguration.NumberOfInstallments; rhc.GracePeriod = trancheConfiguration.GracePeriod; rhc.InterestRate = trancheConfiguration.InterestRate; rhc.StartDate = trancheConfiguration.StartDate; rhc.PreferredFirstInstallmentDate = trancheConfiguration.PreferredFirstInstallmentDate; var lhc = (IScheduleConfiguration)rhc.Clone(); lhc.Amount = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); if (!trancheConfiguration.ApplyNewInterestRateToOlb) { lhc.InterestRate = scheduleConfiguration.InterestRate; } var lhs = scheduleBuilder.BuildSchedule(lhc); var rhs = scheduleBuilder.BuildSchedule(rhc); var result = new List <Installment>(); // Merge the two schedules var max = Math.Max(lhs.Count, rhs.Count); for (var i = 0; i < max; i++) { var lhi = i >= lhs.Count ? null : lhs[i]; var rhi = i >= rhs.Count ? null : rhs[i]; Installment installment; if (lhi == null) { installment = rhi; } else if (rhi == null) { installment = lhi; } else { installment = new Installment { Number = lhi.Number, StartDate = lhi.StartDate, ExpectedDate = lhi.ExpectedDate, //RepaymentDate = lhi.RepaymentDate, CapitalRepayment = lhi.CapitalRepayment + rhi.CapitalRepayment, InterestsRepayment = lhi.InterestsRepayment + rhi.InterestsRepayment, OLB = lhi.OLB + rhi.OLB, }; } result.Add(installment); } result[0].InterestsRepayment += GetExtraInterest(schedule, scheduleConfiguration, trancheConfiguration); return(result); }
public Loan AddTranche(Loan loan, IClient client, ITrancheConfiguration trancheConfiguration) { using (var connection = _loanManager.GetConnection()) using (var transaction = connection.BeginTransaction()) { try { CheckTranche(trancheConfiguration.StartDate, loan, trancheConfiguration.Amount); var copyOfLoan = SimulateTranche(loan, trancheConfiguration); var startInstallment = copyOfLoan.InstallmentList .FindAll(i => i.ExpectedDate <= trancheConfiguration.StartDate) .LastOrDefault(); var trancheEvent = new TrancheEvent { Amount = trancheConfiguration.Amount, ApplyNewInterest = trancheConfiguration.ApplyNewInterestRateToOlb, Maturity = trancheConfiguration.NumberOfInstallments, StartDate = trancheConfiguration.StartDate, Date = trancheConfiguration.StartDate, InterestRate = trancheConfiguration.InterestRate / 100, Number = copyOfLoan.GivenTranches.Count, FirstRepaymentDate = trancheConfiguration.PreferredFirstInstallmentDate, GracePeriod = trancheConfiguration.GracePeriod, StartedFromInstallment = startInstallment == null ? 0 : startInstallment.Number, User = _user, }; trancheEvent.User = _user; //insert into table TrancheEvent _ePs.FireEvent(trancheEvent, copyOfLoan, transaction); ArchiveInstallments(loan, trancheEvent, 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); //Activate the contract if it's closed because of new tranch if (copyOfLoan.Closed) { copyOfLoan.ContractStatus = OContractStatus.Active; copyOfLoan.Closed = false; _loanManager.UpdateLoan(copyOfLoan, transaction); } //in the feature might be combine UpdateLoan + UpdateLoanWithinTranche _loanManager.UpdateLoanWithinTranche( trancheConfiguration.InterestRate / 100, copyOfLoan.NbOfInstallments, copyOfLoan, transaction); copyOfLoan.Events.Add(trancheEvent); copyOfLoan.GivenTranches.Add(trancheEvent); transaction.Commit(); SetClientStatus(copyOfLoan, client); return copyOfLoan; } catch { transaction.Rollback(); throw; } } }