( invoice: Stripe.Invoice, handlerName: string )
| 131 | } |
| 132 | |
| 133 | async function resolveInvoiceSubscription( |
| 134 | invoice: Stripe.Invoice, |
| 135 | handlerName: string |
| 136 | ): Promise<ResolvedInvoiceSubscription | null> { |
| 137 | const subscriptionContext = resolveInvoiceSubscriptionContext(invoice) |
| 138 | |
| 139 | if (!subscriptionContext.stripeSubscriptionId) { |
| 140 | logger.info('No subscription found on invoice; skipping handler', { |
| 141 | handlerName, |
| 142 | invoiceId: invoice.id, |
| 143 | invoiceType: subscriptionContext.invoiceType, |
| 144 | resolutionSource: subscriptionContext.resolutionSource, |
| 145 | }) |
| 146 | return null |
| 147 | } |
| 148 | |
| 149 | const records = await db |
| 150 | .select() |
| 151 | .from(subscriptionTable) |
| 152 | .where(eq(subscriptionTable.stripeSubscriptionId, subscriptionContext.stripeSubscriptionId)) |
| 153 | .limit(1) |
| 154 | |
| 155 | if (records.length === 0) { |
| 156 | logger.warn('Subscription not found in database for invoice', { |
| 157 | handlerName, |
| 158 | invoiceId: invoice.id, |
| 159 | invoiceType: subscriptionContext.invoiceType, |
| 160 | resolutionSource: subscriptionContext.resolutionSource, |
| 161 | stripeSubscriptionId: subscriptionContext.stripeSubscriptionId, |
| 162 | }) |
| 163 | return null |
| 164 | } |
| 165 | |
| 166 | return { |
| 167 | ...subscriptionContext, |
| 168 | stripeSubscriptionId: subscriptionContext.stripeSubscriptionId, |
| 169 | sub: records[0], |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | /** |
| 174 | * Create a billing portal URL for a Stripe customer |
no test coverage detected