From a42715834beea4e1cc7d7927b79714279ed4762a Mon Sep 17 00:00:00 2001 From: sb Date: Tue, 7 Jul 2026 22:43:49 +0900 Subject: [PATCH] =?UTF-8?q?fix(repayment):=20=EC=9B=90=EB=A6=AC=EA=B8=88?= =?UTF-8?q?=EA=B7=A0=EB=93=B1=20=EB=82=A8=EC=9D=80=20=ED=9A=8C=EC=B0=A8?= =?UTF-8?q?=EB=A5=BC=20=EC=9E=94=EC=95=A1=EC=9C=BC=EB=A1=9C=20=EC=97=AD?= =?UTF-8?q?=EC=82=B0=20+=20=EB=9D=BC=EB=B2=A8=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 대출(loanStart 없음)이 남은 회차=전체(60회)로 나오던 문제 수정: 현재 잔액과 최초 상환액으로 남은 개월수 역산(날짜 정보 불필요) - '이번 달 상환' → '이번 달 상환 예정금액', 금액 앞 '이번 달' 제거 - '남은 N회' → '남은 회차 N회' Co-Authored-By: Claude Opus 4.8 --- src/utils/repayment.js | 23 ++++++++++++++++----- src/views/account/RepaymentScheduleView.vue | 6 +++--- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/utils/repayment.js b/src/utils/repayment.js index c0718f7..756a945 100644 --- a/src/utils/repayment.js +++ b/src/utils/repayment.js @@ -71,19 +71,32 @@ export function loanSchedule(w, now = currentYm(), cap = 600) { } // EQUAL_PAYMENT 원리금균등: 매월 상환액 고정 - if (!nRem) { - // 총개월 정보 없음 → 이번 달 이자만 안내(원금 분리 불가) + // 남은 개월수는 '현재 잔액 + 최초 상환액'으로 역산 → loanStart 없어도 정확(기존 대출 대응) + let n = null + let payment = null + if (w.loanAmount && w.loanMonths && r > 0) { + const origPay = (Number(w.loanAmount) * r) / (1 - Math.pow(1 + r, -Number(w.loanMonths))) + payment = Math.round(origPay) + // bal = origPay·(1-(1+r)^-n)/r → n = -ln(1 - bal·r/origPay) / ln(1+r) + const ratio = 1 - (bal * r) / origPay + if (ratio > 0 && ratio < 1) { + n = Math.min(Number(w.loanMonths), Math.max(1, Math.ceil(-Math.log(ratio) / Math.log(1 + r) - 1e-9))) + } + } + if (n == null) n = nRem // 잔액 역산 불가 시 loanStart 경과 기반 + if (n == null) { + // 개월·원금 정보 부족 → 이번 달 이자만 안내(원금 분리 불가) const interest = Math.round(bal * r) return { rows: [{ label: label(y, m), principal: null, interest, total: null, balance: bal }], partial: true, } } - const payment = r > 0 ? Math.round((bal * r) / (1 - Math.pow(1 + r, -nRem))) : Math.round(bal / nRem) - for (let i = 0; i < nRem && bal > 0 && rows.length < cap; i++) { + if (payment == null) payment = r > 0 ? Math.round((bal * r) / (1 - Math.pow(1 + r, -n))) : Math.round(bal / n) + for (let i = 0; i < n && bal > 0 && rows.length < cap; i++) { const interest = Math.round(bal * r) let principal = payment - interest - if (i === nRem - 1 || principal > bal) principal = bal // 마지막 회차 잔액 정산 + if (i === n - 1 || principal > bal) 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)) diff --git a/src/views/account/RepaymentScheduleView.vue b/src/views/account/RepaymentScheduleView.vue index cefcc40..b76a6e0 100644 --- a/src/views/account/RepaymentScheduleView.vue +++ b/src/views/account/RepaymentScheduleView.vue @@ -129,7 +129,7 @@ function toggle(id) {
- 이번 달 상환 + 이번 달 상환 예정금액 {{ won(thisMonth.t) }} 원금 {{ won(thisMonth.p) }} · 이자 {{ won(thisMonth.i) }}
@@ -157,8 +157,8 @@ function toggle(id) { {{ it.sub }} - 이번 달 {{ won(itemThisMonth(it)) }} - 남은 {{ it.rows.length }}회 · {{ won(itemRemain(it)) }} + {{ won(itemThisMonth(it)) }} + 남은 회차 {{ it.rows.length }}회 · {{ won(itemRemain(it)) }} {{ expanded.has(it.id) ? '▾' : '▸' }}