Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
cwinland committed Jan 19, 2021
1 parent 0fff20a commit fe6de4a
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 75 deletions.
11 changes: 11 additions & 0 deletions DebtPlannerTests/DebtInfoTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,16 @@ public void GetAmortization(string name, double balance, double min, double rate
"\n-------------------------------------------------");
list.ForEach(Console.WriteLine);
}

[TestMethod]
public void CheckMinimumPayment()
{
b8.ForceMinPayment = false;
var am = b8.GetAmortization(1)[0];
am.AppliedPayment.Should().BeLessThan(am.Interest);
b8.ForceMinPayment = true;
var am2 = b8.GetAmortization(1)[0];
am2.AppliedPayment.Should().BeGreaterOrEqualTo(am.Interest / 2);
}
}
}
19 changes: 0 additions & 19 deletions DebtPlannerTests/DebtPlannerTests.cs

This file was deleted.

52 changes: 28 additions & 24 deletions DebtPlannerTests/DebtPortfolioTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace DebtPlannerTests
[TestClass]
public class DebtPortfolioTests : TestBase
{
private DebtPortfolio CreatePortfolio() => new DebtPortfolio { a0, a1, a2, a3, a4, a5, a6, a7, };
private DebtPortfolio CreatePortfolio() => new DebtPortfolio { a0, a1, a2, a3, a4, a5, a6, a7, b8, };

[TestMethod]
public void CreatedPortfolio() => CreatePortfolio().Should().NotBeNull();
Expand All @@ -34,7 +34,7 @@ public void OrderedPortfolio(int xIndex, int aIndex)
[DataRow(0, 80)]
[DataRow(1, 96)]
[DataRow(2, 35)]
[DataRow(3, 168)]
[DataRow(3, 109)]
[DataRow(4, 11)]
[DataRow(5, 26)]
[DataRow(6, 12)]
Expand Down Expand Up @@ -80,7 +80,7 @@ public void PayoffMonths_Max()
{
var p = CreatePortfolio();
var x = p.Max(info => info.PayoffMonths);
x.Should().Be(a3.PayoffMonths);
x.Should().Be(b8.PayoffMonths);
}

[TestMethod]
Expand All @@ -92,35 +92,39 @@ public void PayoffMonths_Min()
}

[TestMethod]
public void Test()
public void Amortization_NeverChanges()
{
var p = CreatePortfolio();
var list = p.GetAmortization();
var l = p.GetAmortization();
var m = p.GetAmortization();
l.ToString().Should().Be(m.ToString());
}

foreach (var (debtInfo, debtAmortizationItems) in list)
{
Console.WriteLine($"\n{debtInfo}");
Console.WriteLine($"\nNumber Payments: {debtAmortizationItems.Count}\n");
[TestMethod]
public void WriteTest()
{
var p = CreatePortfolio();

for (var i = 0; i < debtAmortizationItems.Count; i++)
{
var paymentNum = i + 1;
Console.WriteLine($"Payment {paymentNum,3}: {debtAmortizationItems[i]}");
}
}
Console.WriteLine(p);
}

var maxPayments = list.Values.ToList().Max(x => x.Count);
[TestMethod]
public void ToString_NeverChanges()
{
var p = CreatePortfolio();
var h1 = p.Header;
var h2 = p.Header;
h1.Should().Be(h2);

Console.WriteLine("");
var pay1 = p.Payments;
var pay2 = p.Payments;

for (var i = 0; i < maxPayments; i++)
{
var paymentNum = i + 1;
Console.WriteLine(
$"Payment {paymentNum,3}: {list.Values.Sum(x => x.Count > i ? x[i].Payment : 0),11:C}");
}
pay1.Should().Be(pay2);
var h3 = p.Header;
h2.Should().Be(h3);

Console.WriteLine($"{"Total",11}: {list.Values.Sum(x => x.Sum(y => y.Payment)),11:C}");
var pay3 = p.Payments;
pay2.Should().Be(pay3);
}
}
}
1 change: 1 addition & 0 deletions DebtPlannerTests/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public class TestBase
protected readonly DebtInfo a5 = new DebtInfo("F", 1000, 22, 50);
protected readonly DebtInfo a6 = new DebtInfo("G", 500, 22, 50);
protected readonly DebtInfo a7 = new DebtInfo("H", 0, 50.3, 250);
protected readonly DebtInfo b8 = new DebtInfo("I", balance: 13000, 12, 100);
}
}
21 changes: 21 additions & 0 deletions src/DebtAmortization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Text;

namespace DebtPlanner
{
public class DebtAmortization : List<DebtAmortizationItem> {
/// <inheritdoc />
public override string ToString()
{
var builder = new StringBuilder();

for (var i = 0; i < Count; i++)
{
var paymentNum = i + 1;
builder.AppendLine($"Payment {paymentNum,3}: {this[i]}");
}

return builder.ToString();
}
}
}
2 changes: 1 addition & 1 deletion src/DebtAmortizationItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public DebtAmortizationItem(DebtInfo debt)
debtInfo = debt;
Payment = debt.CurrentPayment;
CurrentBalance = debt.Balance;
MonthlyRate = debt.AverageMonthyPr;
MonthlyRate = Payment >= CurrentBalance ? 0 : debt.AverageMonthyPr;
debtInfo = new DebtInfo(Name, (double)RemainingBalance, debt.Rate, Payment);
}

Expand Down
37 changes: 29 additions & 8 deletions src/DebtInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,30 @@ public class DebtInfo
private readonly double originalBalance;

public string Name { get; }
public double Balance { get; private set; }
public double Balance { get => balance; private set => balance = Math.Round(value, 2); }
private double rate;
public double Rate { get => Balance <= CurrentPayment ? 0 : rate; private set => rate = value; }
public double Rate { get => rate; private set => rate = value; }

public double OriginalMinimum => minimum;

private double minimum;
public double Minimum { get => Math.Min(Balance, minimum); private set => minimum = value; }
private double balance;

public double Minimum
{
get => Math.Min(Balance,
ForceMinPayment
? Math.Max(AverageMonthlyInterest * 1.5, OriginalMinimum)
: OriginalMinimum);
private set => minimum = Math.Round(value, 2);
}

public decimal MinimumPercent => Balance > 0 && Minimum > 0 ? (decimal)Minimum / (decimal)Balance : 0;
public double AdditionalPayment { get; set; } = 0;
public decimal DailyPr => Rate > 0 ? (decimal)Rate / 100 / 365 : 0;
public decimal AverageMonthyPr => Rate > 0 ? (decimal)Rate / 100 / 12 : 0;
public decimal DailyInterest => DailyPr * (decimal)Balance;

public bool ForceMinPayment { get; set; }
public double AverageMonthlyInterest => RoundUp((double)(AverageMonthyPr * (decimal)Balance), 2);

public double CurrentPayment => Balance > 0 ? Math.Min(Minimum + AdditionalPayment, Balance) : 0;
Expand All @@ -35,13 +47,22 @@ public class DebtInfo
? (int)Math.Ceiling(Balance / (CurrentPaymentReduction / 12))
: 0;

public DebtInfo(string name, double balance, double rate, double minPayment)
public DebtInfo(string name, double balance, double rate, double minPayment, bool forceMinPayment = true)
{
ForceMinPayment = forceMinPayment;

Name = name;
Balance = balance;
originalBalance = Balance;
Rate = rate;
Minimum = minPayment;

if (Balance > CurrentPayment &&
CurrentPayment <= AverageMonthlyInterest)
{
throw new ArgumentOutOfRangeException(nameof(minPayment),
$"Current Payment ({CurrentPayment} is too low to pay the interest of {AverageMonthlyInterest}. ");
}
}

public DebtInfo ApplyPayment()
Expand Down Expand Up @@ -69,10 +90,10 @@ public static double RoundUp(double input, int places)
return Math.Ceiling(input * multiplier) / multiplier;
}

public List<DebtAmortizationItem> GetAmortization(
public DebtAmortization GetAmortization(
int? numberOfPayments = null, List<Tuple<int, double>> additionalPayments = null)
{
var result = new List<DebtAmortizationItem>();
var result = new DebtAmortization();
var currentDebt = this;
var paymentsMade = 0;

Expand All @@ -86,7 +107,7 @@ public List<DebtAmortizationItem> GetAmortization(
if (additionalPayment != null &&
GetAmortization().Count <= additionalPayment.Item1)
{
return GetAmortization();
return GetAmortization(numberOfPayments);
}

while (currentDebt.Balance > 0 &&
Expand Down
6 changes: 0 additions & 6 deletions src/DebtPlanner.cs

This file was deleted.

89 changes: 72 additions & 17 deletions src/DebtPortfolio.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DebtPlanner
{
public class DebtPortfolio : List<DebtInfo>
{
public List<DebtInfo> PaidList => this.Where(info => info.Balance == 0).ToList();
public List<DebtInfo> UnPaidList => this.Where(info => info.Balance > 0).ToList();

public List<List<DebtAmortizationItem>> Amortizations =>
UnPaidList.Select(info => info.GetAmortization()).ToList();

public double AmountPaid => PaidList.Sum(info => info.OriginalMinimum);
public int MaxLength => UnPaidList.Max(x => x.GetAmortization().Count);

public Dictionary<DebtInfo, List<DebtAmortizationItem>> GetAmortization()
public Dictionary<DebtInfo, DebtAmortization> GetAmortization()
{
// Get First Am
// Get Second Am
// Change Second Am starting after last First Am
var amList = new Dictionary<DebtInfo, List<DebtAmortizationItem>>();
var orderedList = UnPaidList.OrderBy(info => info.GetAmortization().Count).ToList();
var working = orderedList[0];
var amList = new Dictionary<DebtInfo, DebtAmortization>();
var orderedList = new SortedList<int, DebtInfo>();
this.Where(info => info.Balance > 0)
.ToList()
.ForEach(x =>
{
var item = new DebtInfo(x.Name,
x.Balance,
x.Rate,
x.OriginalMinimum,
x.ForceMinPayment);
var aCount = item.GetAmortization().Count;
orderedList.Add(aCount, item);
});
var working = orderedList.FirstOrDefault().Value;
var workingAm = working.GetAmortization();
var workingAmount = working.OriginalMinimum;
var additionalAmounts =
Expand All @@ -32,7 +33,7 @@ public Dictionary<DebtInfo, List<DebtAmortizationItem>> GetAmortization()

while (orderedList.Count > 0)
{
var item = orderedList[0];
var item = orderedList.FirstOrDefault().Value;
var am = item.GetAmortization(null, additionalAmounts);
item.AdditionalPayment = am.Max(x => x.Payment) - item.Minimum;
amList.Add(item, am);
Expand All @@ -43,5 +44,59 @@ public Dictionary<DebtInfo, List<DebtAmortizationItem>> GetAmortization()

return amList;
}

public string Header
{
get
{
var builder = new StringBuilder();

foreach (var keyValuePair in GetAmortization())
{
var debtInfo = keyValuePair.Key;
var debtAmortization = keyValuePair.Value;
builder.AppendLine($"\n{debtInfo}");
builder.AppendLine($"\nNumber Payments: {debtAmortization.Count}\n");
builder.AppendLine(debtAmortization.ToString());
}

return builder.ToString();
}
}

public string Payments
{
get
{
var list = GetAmortization();
var builder = new StringBuilder();

var maxPayments = list.Values.ToList().Max(x => x.Count);

for (var i = 0; i < maxPayments; i++)
{
var paymentNum = i + 1;
builder.AppendLine(
$"Payment {paymentNum,3}: {list.Values.Sum(x => x.Count > i ? x[i].Payment : 0),11:C}");
}

builder.AppendLine($"{"Total",11}: {list.Values.Sum(x => x.Sum(y => y.Payment)),11:C}");

return builder.ToString();
}
}

/// <inheritdoc />
public override string ToString()
{
var builder = new StringBuilder();

builder.AppendLine(Header);

builder.AppendLine("");
builder.AppendLine(Payments);

return builder.ToString();
}
}
}

0 comments on commit fe6de4a

Please sign in to comment.