// Script to post test income and verify overdue payment const { PrismaClient } = require('@prisma/client'); const { randomUUID } = require('crypto'); async function main() { const prisma = new PrismaClient(); try { const user = await prisma.user.findUnique({ where: { email: 'test@skymoney.com' } }); if (!user) { console.log('āŒ Test user not found. Run create-test-user.cjs first.'); return; } console.log('āœ… Found test user:', user.email); // Check overdue status BEFORE posting income const plansBefore = await prisma.fixedPlan.findMany({ where: { userId: user.id }, select: { id: true, name: true, totalCents: true, fundedCents: true, isOverdue: true, overdueAmount: true, }, }); console.log('\nšŸ“‹ Plans BEFORE income:'); for (const plan of plansBefore) { console.log(` ${plan.name}: $${Number(plan.fundedCents) / 100}/$${Number(plan.totalCents) / 100} (Overdue: ${plan.isOverdue ? `$${Number(plan.overdueAmount) / 100}` : 'NO'})`); } // Post $1000 income - should pay $500 to overdue first, then allocate $500 normally const incomeAmount = 100000; // $1000 in cents console.log(`\nšŸ’° Posting income: $${incomeAmount / 100}`); const incomeId = randomUUID(); const now = new Date().toISOString(); // Simulate what the allocateIncome function does const result = await prisma.$transaction(async (tx) => { await tx.incomeEvent.create({ data: { id: incomeId, userId: user.id, postedAt: now, amountCents: BigInt(incomeAmount), note: 'Test income for overdue payment', }, }); // Find overdue plans const overduePlans = await tx.fixedPlan.findMany({ where: { userId: user.id, isOverdue: true, overdueAmount: { gt: 0 }, }, orderBy: { overdueSince: 'asc' }, }); console.log(`\nšŸ” Found ${overduePlans.length} overdue plan(s)`); let remaining = incomeAmount; for (const plan of overduePlans) { if (remaining <= 0) break; const overdueAmount = Number(plan.overdueAmount); const amountToPay = Math.min(overdueAmount, remaining); console.log(` Paying $${amountToPay / 100} to ${plan.name} (was $${overdueAmount / 100} overdue)`); // Create allocation await tx.allocation.create({ data: { userId: user.id, kind: 'fixed', toId: plan.id, amountCents: BigInt(amountToPay), incomeId, }, }); // Update plan const newOverdueAmount = overdueAmount - amountToPay; await tx.fixedPlan.update({ where: { id: plan.id }, data: { fundedCents: (plan.fundedCents ?? 0n) + BigInt(amountToPay), currentFundedCents: (plan.currentFundedCents ?? plan.fundedCents ?? 0n) + BigInt(amountToPay), overdueAmount: newOverdueAmount, isOverdue: newOverdueAmount > 0, lastFundingDate: new Date(now), }, }); remaining -= amountToPay; } return { remaining }; }); console.log(`\nšŸ’µ Remaining after overdue payments: $${result.remaining / 100}`); // Check overdue status AFTER posting income const plansAfter = await prisma.fixedPlan.findMany({ where: { userId: user.id }, select: { id: true, name: true, totalCents: true, fundedCents: true, isOverdue: true, overdueAmount: true, }, }); console.log('\nšŸ“‹ Plans AFTER income:'); for (const plan of plansAfter) { console.log(` ${plan.name}: $${Number(plan.fundedCents) / 100}/$${Number(plan.totalCents) / 100} (Overdue: ${plan.isOverdue ? `$${Number(plan.overdueAmount) / 100}` : 'NO'})`); } } finally { await prisma.$disconnect(); } } main();