fix(payment-instalments): move zero-allocation guard before allocateForPayment#209
Conversation
…orPayment persist call\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
🤖 SJMS-Agent dispatched — action: |
|
@copilot resolve the merge conflicts in this pull request |
…t-zero-allocation-guard # Conflicts: # docs/KNOWN_ISSUES.md # server/src/__tests__/unit/payment-instalments.service.test.ts # server/src/api/payment-instalments/payment-instalments.service.ts Co-authored-by: RJK134 <167345619+RJK134@users.noreply.github.com>
Merge conflicts resolved in b30bbec. There were three conflicted files, all minor differences between the branch and the two upstream commits that landed on
No logic changes were required. |
|
🤖 SJMS-Agent dispatched — action: |
Summary
recordPaymentin the Phase 18D bridge calledpaymentService.allocateForPayment(withpersist: true) before checking whether the account had open charges. When the post-hoc guard fired (allocation.totalAllocated === 0), the 18C transaction had already committed:StudentAccount.balancedecremented,totalCreditsincremented, ChargeLine/Invoice updates written. ThrowingValidationErrorat that point left the ledger mutated but the instalment stuck inPENDING, requiring manual reversal.Root cause
The guard at
payment-instalments.service.ts:223(allocation.totalAllocated === 0) ran afterallocateForPaymenthad already committed all side-effects. There was no way to undo those writes without a rollback mechanism that does not exist in this bridge.Fix
Move the guard before
allocateForPayment. UsechargeLineRepo.findOpenForAccountto check whether the account has any open charges. If the set is empty, throwValidationErrorimmediately — no DB mutations have occurred.force: truebypasses the check (administrative settlement path).Tests
allocateForPaymentis NOT called when the guard fires.force: truebypasses the check.beforeEachto mockchargeLineRepo.findOpenForAccountwith a non-empty result by default, and reset mocks properly between tests.Acceptance criteria
npx tsc --noEmit→ 0 errorsexpect(mockedPaymentsService.allocateForPayment).not.toHaveBeenCalled())force: truecorrectly bypasses the guarddocs/KNOWN_ISSUES.mdKnown Issues resolved
recordPaymentguard fires post-allocation, leaving ledger in inconsistent state🤖 Generated with Claude Code