* Get payment method details from Stripe invoice
( invoice: Stripe.Invoice )
| 193 | * Get payment method details from Stripe invoice |
| 194 | */ |
| 195 | async function getPaymentMethodDetails( |
| 196 | invoice: Stripe.Invoice |
| 197 | ): Promise<{ lastFourDigits?: string; failureReason?: string }> { |
| 198 | let lastFourDigits: string | undefined |
| 199 | let failureReason: string | undefined |
| 200 | |
| 201 | // Try to get last 4 digits from payment method |
| 202 | try { |
| 203 | const stripe = requireStripeClient() |
| 204 | |
| 205 | // Try to get from default payment method |
| 206 | if (invoice.default_payment_method && typeof invoice.default_payment_method === 'string') { |
| 207 | const paymentMethod = await stripe.paymentMethods.retrieve(invoice.default_payment_method) |
| 208 | if (paymentMethod.card?.last4) { |
| 209 | lastFourDigits = paymentMethod.card.last4 |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | // If no default payment method, try getting from customer's default |
| 214 | if (!lastFourDigits && invoice.customer && typeof invoice.customer === 'string') { |
| 215 | const customer = await stripe.customers.retrieve(invoice.customer) |
| 216 | if (customer && !('deleted' in customer)) { |
| 217 | const defaultPm = customer.invoice_settings?.default_payment_method |
| 218 | if (defaultPm && typeof defaultPm === 'string') { |
| 219 | const paymentMethod = await stripe.paymentMethods.retrieve(defaultPm) |
| 220 | if (paymentMethod.card?.last4) { |
| 221 | lastFourDigits = paymentMethod.card.last4 |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | } |
| 226 | } catch (error) { |
| 227 | logger.warn('Failed to retrieve payment method details', { error, invoiceId: invoice.id }) |
| 228 | } |
| 229 | |
| 230 | // Get failure message - check multiple sources |
| 231 | if (invoice.last_finalization_error?.message) { |
| 232 | failureReason = invoice.last_finalization_error.message |
| 233 | } |
| 234 | |
| 235 | // If not found, check the payments array (requires expand: ['payments']) |
| 236 | if (!failureReason && invoice.payments?.data) { |
| 237 | const defaultPayment = invoice.payments.data.find((p) => p.is_default) |
| 238 | const payment = defaultPayment || invoice.payments.data[0] |
| 239 | |
| 240 | if (payment?.payment) { |
| 241 | try { |
| 242 | const stripe = requireStripeClient() |
| 243 | |
| 244 | if (payment.payment.type === 'payment_intent' && payment.payment.payment_intent) { |
| 245 | const piId = |
| 246 | typeof payment.payment.payment_intent === 'string' |
| 247 | ? payment.payment.payment_intent |
| 248 | : payment.payment.payment_intent.id |
| 249 | |
| 250 | const paymentIntent = await stripe.paymentIntents.retrieve(piId) |
| 251 | if (paymentIntent.last_payment_error?.message) { |
| 252 | failureReason = paymentIntent.last_payment_error.message |
no test coverage detected