diff --git a/frontend/src/views/loans/LoansView.vue b/frontend/src/views/loans/LoansView.vue
index eac7673..418b3c9 100644
--- a/frontend/src/views/loans/LoansView.vue
+++ b/frontend/src/views/loans/LoansView.vue
@@ -104,7 +104,7 @@
- Amounts shown are estimates based on standard monthly compounding. Actual values may differ due to your lender's rounding practices, extra payments, or rate changes.
+ Amounts shown are estimates. Lines of credit and auto loans use daily interest accrual; mortgages and personal loans use standard monthly compounding. Actual values may differ due to payment timing, your lender's rounding practices, extra payments, or rate changes.
diff --git a/src/Purrse.Api/Services/AccountService.cs b/src/Purrse.Api/Services/AccountService.cs
index c2c1831..60816c3 100644
--- a/src/Purrse.Api/Services/AccountService.cs
+++ b/src/Purrse.Api/Services/AccountService.cs
@@ -18,6 +18,7 @@ public class AccountService : IAccountService
public async Task> GetAllAsync(Guid userId)
{
return await _db.Accounts
+ .Include(a => a.LoanDetail)
.Where(a => a.UserId == userId)
.OrderBy(a => a.SortOrder).ThenBy(a => a.Name)
.Select(a => MapToResponse(a))
diff --git a/src/Purrse.Api/Services/LoanService.cs b/src/Purrse.Api/Services/LoanService.cs
index 071326e..78bd8ee 100644
--- a/src/Purrse.Api/Services/LoanService.cs
+++ b/src/Purrse.Api/Services/LoanService.cs
@@ -49,7 +49,7 @@ public class LoanService : ILoanService
ExtraPayment = request.ExtraPayment
};
- var entries = GenerateAmortizationSchedule(loanDetail);
+ var entries = GenerateAmortizationSchedule(loanDetail, account.Type);
loanDetail.AmortizationEntries = entries;
_db.LoanDetails.Add(loanDetail);
@@ -82,7 +82,7 @@ public class LoanService : ILoanService
l.EscrowAmount = request.EscrowAmount;
l.ExtraPayment = request.ExtraPayment;
- var entries = GenerateAmortizationSchedule(l);
+ var entries = GenerateAmortizationSchedule(l, account.Type);
foreach (var entry in entries)
{
entry.LoanDetailId = l.Id;
@@ -118,7 +118,9 @@ public class LoanService : ILoanService
// Build new schedule with extra payments
var balance = Math.Abs(account.Balance);
+ var useDailyAccrual = UsesDailyAccrual(account.Type);
var monthlyRate = l.InterestRate / 100m / 12m;
+ var dailyRate = l.InterestRate / 100m / 365m;
var extraMonthly = request.ExtraMonthlyPayment ?? 0;
var basePayment = l.MonthlyPayment - (l.EscrowAmount ?? 0);
var now = DateTime.UtcNow;
@@ -139,7 +141,18 @@ public class LoanService : ILoanService
paymentNum++;
var paymentDate = startDate.AddMonths(paymentNum);
- var interest = Math.Round(balance * monthlyRate, 2);
+ decimal interest;
+ if (useDailyAccrual)
+ {
+ var prevDate = startDate.AddMonths(paymentNum - 1);
+ var days = (paymentDate - prevDate).Days;
+ interest = Math.Round(balance * dailyRate * days, 2);
+ }
+ else
+ {
+ interest = Math.Round(balance * monthlyRate, 2);
+ }
+
var principal = Math.Min(basePayment + extraMonthly - interest, balance);
if (principal < 0) principal = 0;
@@ -181,18 +194,35 @@ public class LoanService : ILoanService
return new LoanDefaultsResponse(0, interestRate, termMonths, hasSyncData);
}
- private static List GenerateAmortizationSchedule(LoanDetail loan)
+ private static bool UsesDailyAccrual(AccountType type) =>
+ type is AccountType.LineOfCredit or AccountType.AutoLoan;
+
+ private static List GenerateAmortizationSchedule(LoanDetail loan, AccountType accountType)
{
var entries = new List();
var balance = loan.OriginalBalance;
+ var useDailyAccrual = UsesDailyAccrual(accountType);
var monthlyRate = loan.InterestRate / 100m / 12m;
+ var dailyRate = loan.InterestRate / 100m / 365m;
var payment = loan.MonthlyPayment - (loan.EscrowAmount ?? 0);
var extra = loan.ExtraPayment ?? 0;
for (int i = 1; i <= loan.TermMonths && balance > 0; i++)
{
var paymentDate = loan.OriginationDate.AddMonths(i - 1);
- var interest = Math.Round(balance * monthlyRate, 2);
+
+ decimal interest;
+ if (useDailyAccrual)
+ {
+ var prevDate = loan.OriginationDate.AddMonths(i - 2);
+ var days = (paymentDate - prevDate).Days;
+ interest = Math.Round(balance * dailyRate * days, 2);
+ }
+ else
+ {
+ interest = Math.Round(balance * monthlyRate, 2);
+ }
+
var principal = Math.Min(payment + extra - interest, balance);
balance -= principal;
if (balance < 0.01m) balance = 0;