| 57 | }); |
| 58 | |
| 59 | async function main() { |
| 60 | // 1. Find the disputed invoice |
| 61 | const invoices = await stripe.invoices.search({ |
| 62 | query: `number:"${DISPUTED_INVOICE_NUMBER}"`, |
| 63 | }); |
| 64 | |
| 65 | if (invoices.data.length === 0) { |
| 66 | console.error(`Invoice ${DISPUTED_INVOICE_NUMBER} not found`); |
| 67 | process.exit(1); |
| 68 | } |
| 69 | |
| 70 | const disputed = invoices.data[0]; |
| 71 | console.log(`Found disputed invoice: ${disputed.id}`); |
| 72 | console.log(` Number: ${disputed.number}`); |
| 73 | console.log(` Status: ${disputed.status}`); |
| 74 | console.log(` Amount: ${(disputed.amount_due / 100).toFixed(2)} ${disputed.currency.toUpperCase()}`); |
| 75 | console.log(` Customer: ${disputed.customer}`); |
| 76 | |
| 77 | const customerId = disputed.customer as string; |
| 78 | const subscriptionId = disputed.subscription as string | null; |
| 79 | |
| 80 | // Find the price — from subscription, line item, or lookup key fallback |
| 81 | let priceId: string | undefined; |
| 82 | if (subscriptionId) { |
| 83 | const subscription = await stripe.subscriptions.retrieve(subscriptionId); |
| 84 | priceId = subscription.items.data[0].price.id; |
| 85 | console.log(` Subscription: ${subscriptionId}`); |
| 86 | } else if (disputed.lines.data[0]?.price?.id) { |
| 87 | priceId = disputed.lines.data[0].price.id; |
| 88 | console.log(` No subscription (standalone invoice)`); |
| 89 | } |
| 90 | |
| 91 | if (!priceId) { |
| 92 | // Standalone invoice with no price ref — resolve from lookup key |
| 93 | const prices = await stripe.prices.list({ lookup_keys: [LOOKUP_KEY], active: true }); |
| 94 | if (prices.data.length === 0) { |
| 95 | console.error(`No active price for lookup key: ${LOOKUP_KEY}`); |
| 96 | process.exit(1); |
| 97 | } |
| 98 | priceId = prices.data[0].id; |
| 99 | console.log(` Resolved price from lookup key: ${LOOKUP_KEY}`); |
| 100 | } |
| 101 | console.log(` Price: ${priceId}`); |
| 102 | console.log(`\nWill void and reissue with PO: ${PO_NUMBER}`); |
| 103 | |
| 104 | if (dryRun) { |
| 105 | console.log('\n--dry-run: Would void invoice and create corrected invoice. Exiting.'); |
| 106 | return; |
| 107 | } |
| 108 | |
| 109 | // 2. Void the disputed invoice |
| 110 | console.log('\nVoiding disputed invoice...'); |
| 111 | await stripe.invoices.voidInvoice(disputed.id); |
| 112 | console.log(' Voided.'); |
| 113 | |
| 114 | // 3. Cancel old subscription if one exists |
| 115 | if (subscriptionId) { |
| 116 | console.log('Canceling old subscription...'); |