From 18f015f7fd0ce0a28572009996c688209f326d83 Mon Sep 17 00:00:00 2001 From: sb Date: Tue, 7 Jul 2026 23:08:00 +0900 Subject: [PATCH] =?UTF-8?q?feat(repayment):=20=EB=8C=80=EC=B6=9C=20?= =?UTF-8?q?=EC=9B=94=20=EC=83=81=ED=99=98=EA=B8=88=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EC=8B=9C=20=EC=9B=90=EA=B8=88=C2=B7=EC=9D=B4=EC=9E=90=20?= =?UTF-8?q?=EC=9D=80=ED=96=89=EA=B3=BC=20=EC=A0=95=ED=99=95=20=EC=9D=BC?= =?UTF-8?q?=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 계좌 관리 대출 폼에 '월 상환금(선택)' 입력(원리금균등) - repayment.js: loanPayment 있으면 이자=잔액×이율, 원금=상환금-이자로 상각 → 남은 개월수 추정 오차(±1회) 없이 은행 조회액과 일치. 미입력 시 기존 추정 Co-Authored-By: Claude Opus 4.8 --- src/utils/repayment.js | 19 +++++++++++++++++++ src/views/account/AccountWalletView.vue | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/utils/repayment.js b/src/utils/repayment.js index c44608c..04cf531 100644 --- a/src/utils/repayment.js +++ b/src/utils/repayment.js @@ -71,6 +71,25 @@ export function loanSchedule(w, now = currentYm(), cap = 600) { } // EQUAL_PAYMENT 원리금균등 + // (0) 월 상환금(고정)이 입력돼 있으면 그대로 사용 → 이자=잔액×이율, 원금=상환금-이자 로 은행과 정확히 일치 + const fixed = Number(w.loanPayment) || 0 + if (fixed > 0) { + while (bal > 0 && rows.length < cap) { + const interest = Math.round(bal * r) + let principal = fixed - interest + if (principal <= 0) { + // 상환금이 이자에 못 미침(데이터 이상) → 더 진행 못함 + rows.push({ label: label(y, m), principal: Math.max(0, principal), interest, total: fixed, balance: bal }) + break + } + principal = Math.min(principal, bal) + bal = Math.max(0, bal - principal) + rows.push({ label: label(y, m), principal, interest, total: principal + interest, balance: bal }) + ;({ y, m } = addMonths(y, m, 1)) + } + return { rows, partial: false } + } + // (1) 남은 개월수 n 산출: 최초 상환액으로 역산(loanStart 없어도 정확) → 안되면 loanStart 경과 let n = null if (w.loanAmount && w.loanMonths && r > 0) { diff --git a/src/views/account/AccountWalletView.vue b/src/views/account/AccountWalletView.vue index cff5950..8fac133 100644 --- a/src/views/account/AccountWalletView.vue +++ b/src/views/account/AccountWalletView.vue @@ -62,6 +62,7 @@ const form = reactive({ loanMethod: '', loanMonths: null, loanStart: '', + loanPayment: null, }) const submitting = ref(false) const formError = ref(null) @@ -187,6 +188,7 @@ function openCreate() { loanMethod: '', loanMonths: null, loanStart: '', + loanPayment: null, }) formError.value = null formOpen.value = true @@ -208,6 +210,7 @@ function openEdit(w) { loanMethod: w.loanMethod || '', loanMonths: w.loanMonths ?? null, loanStart: w.loanStart || '', + loanPayment: w.loanPayment ?? null, }) formError.value = null formOpen.value = true @@ -240,6 +243,7 @@ async function submit() { loanMethod: isLoan && form.loanMethod ? form.loanMethod : null, loanMonths: isLoan && form.loanMonths ? Number(form.loanMonths) : null, loanStart: isLoan && form.loanStart ? form.loanStart : null, + loanPayment: isLoan && form.loanPayment ? Number(form.loanPayment) : null, } try { if (editId.value) await accountApi.updateWallet(editId.value, payload) @@ -413,6 +417,13 @@ onBeforeUnmount(destroySortables) + +

+ 원리금균등은 월 상환금을 입력하면 상환표의 원금·이자가 은행 조회액과 정확히 일치합니다. (미입력 시 잔액·개월수로 추정) +

{{ formError }}