Private
Public Access
1
0

Auto-populate loan details from Plaid liabilities and pre-fill setup form

Fetch loan data (mortgage/student) from Plaid's Liabilities API during sync
and auto-create LoanDetail records. For accounts without liabilities data,
pre-populate the setup form with balance, interest rate, and smart term
defaults. Also fixes maturity date computation in the frontend form.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-02-14 16:23:49 -05:00
parent a689681872
commit 3bb9c688ed
10 changed files with 237 additions and 4 deletions
+25 -2
View File
@@ -215,6 +215,9 @@
<v-card>
<v-card-title>{{ editingLoan ? 'Edit' : 'Set Up' }} Loan Details</v-card-title>
<v-card-text>
<v-alert v-if="prePopulated && !editingLoan" type="info" variant="tonal" density="compact" class="mb-4">
Some fields have been pre-populated from your bank sync data. Please review and adjust as needed.
</v-alert>
<v-text-field v-model.number="loanForm.originalBalance" label="Original Balance" type="number" prefix="$" />
<v-text-field v-model.number="loanForm.interestRate" label="Interest Rate (%)" type="number" suffix="%" step="0.125" />
<v-text-field v-model.number="loanForm.termMonths" label="Term (months)" type="number" />
@@ -242,7 +245,7 @@ import { useRouter } from 'vue-router'
import { loansApi } from '@/services/loans'
import { useAccountsStore } from '@/stores/accounts'
import { formatCurrency, formatDate, accountTypeIcon } from '@/utils/formatters'
import type { LoanDetail, PayoffScenario } from '@/types'
import type { LoanDefaults, LoanDetail, PayoffScenario } from '@/types'
const props = defineProps<{ id?: string }>()
const router = useRouter()
@@ -256,6 +259,7 @@ const calculatingPayoff = ref(false)
const showLoanDialog = ref(false)
const showSetup = ref(false)
const editingLoan = ref(false)
const prePopulated = ref(false)
const snackbar = ref(false)
const snackbarText = ref('')
const snackbarColor = ref('success')
@@ -316,8 +320,9 @@ async function loadLoanDetail() {
}
}
function openSetupDialog() {
async function openSetupDialog() {
editingLoan.value = false
prePopulated.value = false
loanForm.value = {
originalBalance: 0,
interestRate: 0,
@@ -327,6 +332,19 @@ function openSetupDialog() {
escrowAmount: null,
extraPayment: null,
}
if (props.id) {
try {
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
}
}
showLoanDialog.value = true
}
@@ -349,8 +367,13 @@ async function saveLoanDetail() {
if (!props.id) return
saving.value = true
try {
const originDate = new Date(loanForm.value.originationDate)
const maturityDate = new Date(originDate)
maturityDate.setMonth(maturityDate.getMonth() + loanForm.value.termMonths)
const payload = {
...loanForm.value,
maturityDate: maturityDate.toISOString(),
escrowAmount: loanForm.value.escrowAmount || undefined,
extraPayment: loanForm.value.extraPayment || undefined,
}