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:
@@ -1,10 +1,13 @@
|
||||
import api from './api'
|
||||
import type { LoanDetail, PayoffScenario } from '@/types'
|
||||
import type { LoanDefaults, LoanDetail, PayoffScenario } from '@/types'
|
||||
|
||||
export const loansApi = {
|
||||
getLoanDetail: (accountId: string) =>
|
||||
api.get<LoanDetail>(`/loans/${accountId}/amortization`),
|
||||
|
||||
getLoanDefaults: (accountId: string) =>
|
||||
api.get<LoanDefaults>(`/loans/${accountId}/defaults`),
|
||||
|
||||
createLoanDetail: (accountId: string, data: any) =>
|
||||
api.post<LoanDetail>(`/loans/${accountId}`, data),
|
||||
|
||||
|
||||
@@ -236,6 +236,13 @@ export interface PayoffScenario {
|
||||
newSchedule: AmortizationEntry[]
|
||||
}
|
||||
|
||||
export interface LoanDefaults {
|
||||
originalBalance: number
|
||||
interestRate: number
|
||||
termMonths: number
|
||||
hasSyncData: boolean
|
||||
}
|
||||
|
||||
export interface ImportUploadResponse {
|
||||
batchId: string
|
||||
totalTransactions: number
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user