fix(loans): offer Pay EMI on the earliest unpaid installment, inside its pay window - #47
Open
parameshjava wants to merge 2 commits into
Open
fix(loans): offer Pay EMI on the earliest unpaid installment, inside its pay window#47parameshjava wants to merge 2 commits into
parameshjava wants to merge 2 commits into
Conversation
Two "Pay EMI" buttons appeared on a loan whose schedule had just been moved back to its correct month. Both were correct under the old rule — an installment became payable on the 1st of its accrual month, so on 7 August both #1 (accruing in July) and #2 (accruing in August) qualified — but offering them together let an admin settle #2 while #1 was still outstanding. A paid row stranded between unpaid ones is a state several things handle badly: the schedule reads out of order, re-pricing has to skip around it, and the date-shift repair refuses outright once anything is settled. payEmi has no ordering check of its own, so nothing prevented it. The accrual-month rule is unchanged; it now applies to the earliest unpaid installment alone. A member can still pay within the current cycle before the 10th, they just cannot skip one — and paying genuinely ahead of schedule is what Prepay is for. The rule moves out of the page and into `payableInstallmentIds` in emi-due.ts alongside the other EMI-due tallies, so it is testable and there is one definition of "payable" rather than an inline filter. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Payable used to mean "the 1st of the accrual month has passed", which opened the button up to 40 days before the due date. Settling an EMI that early does the member no good at all — payEmi charges exactly what the installment says, so it moves cash without touching the interest. Money offered that far ahead belongs in a prepayment, which reduces the principal and does cut the interest. An installment is now collectable from 15 days before it falls due, or the 1st of the month it falls due in, whichever comes first. The 15-day window is the rule; the month clause keeps an installment dated late in a month collectable from the start of that month rather than only in its last fortnight. Anything past its due date is trivially inside the window, so arrears stay collectable however old — the window bounds how far AHEAD an EMI can be settled, not how far behind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No migration. Two rules for when Pay EMI appears on
/admin/loans/[loan_number].Rule 1 — earliest unpaid installment only
Two buttons showed on a loan whose schedule had just been moved back to its correct month. Both were correct under the old rule, but offering them together let an admin settle #2 while #1 was still outstanding, and
payEmihas no ordering check of its own. A paid row stranded between unpaid ones is a state several things handle badly:Rule 2 — inside the pay window
Payable used to mean "the 1st of the accrual month has passed", which opened the button as much as 40 days before the due date. Settling that early does the member no good:
payEmicharges exactly what the installment says, so it moves cash without touching the interest.(the ₹1,00,000 / 8% / 12-month case, two installments paid)
An installment is now collectable from 15 days before it falls due, or the 1st of the month it falls due in — whichever comes first. The 15-day window is the rule; the month clause keeps an installment dated late in a month collectable from the start of that month rather than only in its last fortnight.
Worked through, for a schedule due on the 10th:
Arrears are unaffected. Anything past its due date is trivially inside the window, so an overdue installment stays collectable however old — the window bounds how far ahead an EMI can be settled, not how far behind. Catching up on two missed months still works: settle the earliest and the next one's button appears immediately.
Where the rule lives
Out of an inline filter in
page.tsxand intopayableInstallmentIds/payWindowOpensOninemi-due.ts, beside the other EMI-due tallies — one definition of "payable", and testable.Testing
emi-payable.test.ts— 14 cases: the window opening 15 days out and at the month start when that comes first, month and year boundary rolls, nothing offered beyond the window, offered from the opening day, only the earliest even when a later one is inside its own window, advancing once the earliest is paid, arrears collectable a year late, part-paid offered, paid/waived skipped when picking the earliest, nothing when all settled, picked by due date rather than row order, and an empty schedule.npm test352 passing ·npm run lintclean (one pre-existing warning) ·npm run buildpasses.🤖 Generated with Claude Code