diff --git a/frontend/src/views/loans/LoansView.vue b/frontend/src/views/loans/LoansView.vue index 2bf6d07..219b4dd 100644 --- a/frontend/src/views/loans/LoansView.vue +++ b/frontend/src/views/loans/LoansView.vue @@ -84,7 +84,7 @@
{{ loanDetail.termMonths }} months
-
Origination Date
+
First Payment Date
{{ formatDate(loanDetail.originationDate) }}
@@ -220,9 +220,9 @@ - - + + @@ -289,9 +289,9 @@ const payoffForm = ref({ const loanForm = ref({ originalBalance: 0, interestRate: 0, - termMonths: 360, monthlyPayment: 0, originationDate: '', + maturityDate: '', escrowAmount: null as number | null, extraPayment: null as number | null, }) @@ -326,9 +326,9 @@ async function openSetupDialog() { loanForm.value = { originalBalance: 0, interestRate: 0, - termMonths: 360, monthlyPayment: 0, originationDate: new Date().toISOString().split('T')[0], + maturityDate: '', escrowAmount: null, extraPayment: null, } @@ -338,7 +338,6 @@ async function openSetupDialog() { const { data } = await loansApi.getLoanDefaults(props.id) if (data.originalBalance > 0) loanForm.value.originalBalance = data.originalBalance if (data.interestRate > 0) loanForm.value.interestRate = data.interestRate - if (data.termMonths > 0) loanForm.value.termMonths = data.termMonths prePopulated.value = data.hasSyncData } catch { // Fall back to zero defaults @@ -354,9 +353,9 @@ function openEditDialog() { loanForm.value = { originalBalance: loanDetail.value.originalBalance, interestRate: loanDetail.value.interestRate, - termMonths: loanDetail.value.termMonths, monthlyPayment: loanDetail.value.monthlyPayment, originationDate: loanDetail.value.originationDate.split('T')[0], + maturityDate: loanDetail.value.maturityDate.split('T')[0], escrowAmount: loanDetail.value.escrowAmount, extraPayment: loanDetail.value.extraPayment, } @@ -367,13 +366,17 @@ async function saveLoanDetail() { if (!props.id) return saving.value = true try { - const [year, month, day] = loanForm.value.originationDate.split('-').map(Number) - const maturityDate = new Date(Date.UTC(year, month - 1 + loanForm.value.termMonths, day)) + const [sY, sM, sD] = loanForm.value.originationDate.split('-').map(Number) + const [eY, eM, eD] = loanForm.value.maturityDate.split('-').map(Number) + const termMonths = (eY - sY) * 12 + (eM - sM) + 1 const payload = { - ...loanForm.value, - originationDate: new Date(Date.UTC(year, month - 1, day)).toISOString(), - maturityDate: maturityDate.toISOString(), + originalBalance: loanForm.value.originalBalance, + interestRate: loanForm.value.interestRate, + termMonths, + monthlyPayment: loanForm.value.monthlyPayment, + originationDate: new Date(Date.UTC(sY, sM - 1, sD)).toISOString(), + maturityDate: new Date(Date.UTC(eY, eM - 1, eD)).toISOString(), escrowAmount: loanForm.value.escrowAmount || undefined, extraPayment: loanForm.value.extraPayment || undefined, } diff --git a/src/Purrse.Api/Services/BankSyncService.cs b/src/Purrse.Api/Services/BankSyncService.cs index a9305ee..a32455f 100644 --- a/src/Purrse.Api/Services/BankSyncService.cs +++ b/src/Purrse.Api/Services/BankSyncService.cs @@ -665,20 +665,21 @@ public class BankSyncService : IBankSyncService var originalBalance = liability.OriginalBalance ?? Math.Abs(linked.LastKnownBalance ?? 0); var interestRate = liability.InterestRate ?? 0; var termMonths = liability.TermMonths ?? (liability.LoanType == "Mortgage" ? 360 : 60); - var originationDate = liability.OriginationDate ?? DateTime.UtcNow; + // Plaid gives loan origination date; first payment is typically one month later + var firstPaymentDate = liability.OriginationDate?.AddMonths(1) ?? DateTime.UtcNow; var escrowBalance = liability.EscrowBalance; // Compute monthly payment via amortization formula if not provided var monthlyPayment = liability.MonthlyPayment ?? ComputeMonthlyPayment(originalBalance, interestRate, termMonths); - var maturityDate = liability.MaturityDate ?? originationDate.AddMonths(termMonths); + var maturityDate = liability.MaturityDate ?? firstPaymentDate.AddMonths(termMonths - 1); var request = new CreateLoanDetailRequest( originalBalance, interestRate, termMonths, monthlyPayment, - DateTime.SpecifyKind(originationDate, DateTimeKind.Utc), + DateTime.SpecifyKind(firstPaymentDate, DateTimeKind.Utc), DateTime.SpecifyKind(maturityDate, DateTimeKind.Utc), escrowBalance, null diff --git a/src/Purrse.Api/Services/LoanService.cs b/src/Purrse.Api/Services/LoanService.cs index de6c998..df2bb96 100644 --- a/src/Purrse.Api/Services/LoanService.cs +++ b/src/Purrse.Api/Services/LoanService.cs @@ -187,11 +187,11 @@ public class LoanService : ILoanService var dailyRate = loan.InterestRate / 100m / 365m; var payment = loan.MonthlyPayment - (loan.EscrowAmount ?? 0); var extra = loan.ExtraPayment ?? 0; - var previousDate = loan.OriginationDate; + var previousDate = loan.OriginationDate.AddMonths(-1); for (int i = 1; i <= loan.TermMonths && balance > 0; i++) { - var paymentDate = loan.OriginationDate.AddMonths(i); + var paymentDate = loan.OriginationDate.AddMonths(i - 1); var days = (paymentDate - previousDate).Days; var interest = balance * dailyRate * days; var principal = Math.Min(payment + extra - interest, balance);