121 lines
5.2 KiB
C#
121 lines
5.2 KiB
C#
using ReserveManagementSystemLib.Models;
|
|
|
|
namespace ReserveManagementSystemApi.Helpers
|
|
{
|
|
public class LoanCalculationHelper
|
|
{
|
|
private decimal _daysInterest;
|
|
private LoanReserve loanReserve = new LoanReserve();
|
|
|
|
public LoanCalculationHelper()
|
|
{
|
|
|
|
}
|
|
public LoanReserve CalculateBuyDown(CalculationConfig cc)
|
|
{
|
|
// Case - Buy down Below Threshold where difference in rates is less than or equal to 0.25 percent
|
|
if (cc.BuydownRateDifference() <= cc.NoReserveThreshold()) //we already know it's positive
|
|
{
|
|
loanReserve.ReserveAmount = 0;
|
|
loanReserve.ReserveTypeMessage = "No Reserve";
|
|
loanReserve.FlatFeePaid = false;
|
|
return loanReserve;
|
|
}
|
|
|
|
// Case - This is a regular Buy Down
|
|
_daysInterest = cc.BuydownRateDifference() / 100 * cc.DaysToFirstPmt() * cc.LoanData().LoanAmount /
|
|
365 * (decimal)Math.Pow(1 + (double)cc.LoanData().ContractRate / 100, (double)cc.LoanData().Term / 12);
|
|
|
|
loanReserve.ReserveAmount = -(cc.BuyFinanceCharge - cc.ContractFinanceCharge + _daysInterest);
|
|
loanReserve.ReserveTypeMessage = "Buy Down Reserve";
|
|
loanReserve.FlatFeePaid = false;
|
|
return loanReserve;
|
|
}
|
|
|
|
public LoanReserve CalculateNoMarkup(CalculationConfig cc)
|
|
{
|
|
// Case - Contract rate is equal to the Buy rate
|
|
_daysInterest = cc.StdRate() * cc.DaysToFirstPmt() * cc.LoanData().LoanAmount /
|
|
365 * (decimal)Math.Pow(1 + (double)cc.LoanData().ContractRate / 100, (double)cc.LoanData().Term / 12);
|
|
|
|
loanReserve.ReserveAmount = (cc.ContractFinanceCharge - cc.BuyFinanceCharge + _daysInterest);
|
|
loanReserve.ReserveTypeMessage = "No Reserve";
|
|
loanReserve.FlatFeePaid = false;
|
|
return loanReserve;
|
|
}
|
|
|
|
public LoanReserve CalculateStandardMarkup(CalculationConfig cc)
|
|
{
|
|
// Case - Contract rate is greater than Buy rate
|
|
_daysInterest = (1 - cc.ReserveDiscount()/100) * cc.StdRate() / 100 * cc.DaysToFirstPmt() * cc.LoanData().LoanAmount /
|
|
365 * (decimal)Math.Pow(1 + (double)cc.LoanData().ContractRate / 100, (double)cc.LoanData().Term / 12);
|
|
|
|
loanReserve.ReserveAmount = ((1 - cc.ReserveDiscount() / 100) * (cc.ContractFinanceCharge - cc.BuyFinanceCharge) + _daysInterest);
|
|
|
|
if ((double)cc.StdRate() <= 2.5)
|
|
{
|
|
loanReserve.ReserveTypeMessage = "Standard Reserve";
|
|
}
|
|
else
|
|
{
|
|
loanReserve.ReserveTypeMessage = "Standard Reserve - Exceeds Max Markup";
|
|
}
|
|
return loanReserve;
|
|
}
|
|
|
|
public LoanReserve AssignFlatFee(LoanReserve loanReserve, CalculationConfig cc)
|
|
{
|
|
loanReserve.FlatFeePaid = false;
|
|
if (loanReserve.ReserveAmount < (cc.FlatFeePercent() / 100 * cc._loanData.LoanAmount * (1 - cc.ReserveDiscount() / 100)))
|
|
{
|
|
loanReserve.ReserveAmount = (cc.FlatFeePercent() / 100 * cc._loanData.LoanAmount * (1 - cc.ReserveDiscount() / 100));
|
|
loanReserve.ReserveTypeMessage = "Flat Fee Reserve";
|
|
loanReserve.FlatFeePaid = true;
|
|
}
|
|
|
|
return loanReserve;
|
|
}
|
|
|
|
public decimal FinanceCharge(int term, decimal loanAmount, decimal rate)
|
|
{
|
|
if (rate == 0) { return 0; }
|
|
double paymentRate = (double)rate / (double)1200;
|
|
decimal rateFactor = (decimal)Math.Pow((1 + paymentRate), (double)term);
|
|
return (loanAmount * term * rate / 1200 * rateFactor) / (rateFactor - 1) - loanAmount;
|
|
}
|
|
|
|
internal DateTime GetLastChargebackDate(DateTime loanDate, DateTime firstPmtDate, int numOfChargebackPayments, Int16? numOfChargebackDays)
|
|
{
|
|
// in rare cases that date from loan date is most recent, check table values and compare between loan date vs. first payment date
|
|
int result = DateTime.Compare(loanDate.AddDays((Double)numOfChargebackDays), firstPmtDate.AddMonths(numOfChargebackPayments - 1));
|
|
if (result > 0)
|
|
{
|
|
return loanDate.AddDays((Double)numOfChargebackDays); //Loan Date is most recent
|
|
}
|
|
return firstPmtDate.AddMonths(numOfChargebackPayments - 1);
|
|
}
|
|
|
|
internal decimal CalculateChargeback(decimal reserve, int term, int remainingMonths)
|
|
{
|
|
return reserve * MonthFactor(remainingMonths) / MonthFactor(term);
|
|
}
|
|
|
|
private decimal MonthFactor(int numberOfMonths)
|
|
{
|
|
return numberOfMonths * (numberOfMonths + 1) / 2;
|
|
}
|
|
|
|
public int GetRemainingMonths(Loan loanData)
|
|
{
|
|
if (loanData.PaidLoanDate >= loanData.FinalPmtDate)
|
|
return 0;
|
|
|
|
var monthsOccurred = (loanData.PaidLoanDate.Value - loanData.FirstPmtDate).TotalDays / (365) * 12 + 1;
|
|
|
|
var remainingMonths = (int)(loanData.Term - Math.Round((decimal)monthsOccurred, 0));
|
|
return remainingMonths;
|
|
}
|
|
|
|
}
|
|
}
|