Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 12x 12x 4x 4x 4x 4x 2x 2x 2x 2x 1x 1x 1x 1x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x | import { Injectable, Logger } from '@nestjs/common'
import { IncomingHttpHeaders } from 'http'
import { ConfigService } from '@nestjs/config'
import Stripe from 'stripe'
import {
PaymentProvider,
CreatePaymentIntentResult,
PaymentConfig,
} from '../interfaces/payment-provider.interface'
import { StripeProviderConfig } from '@fundraising/white-labeling'
@Injectable()
export class StripeService implements PaymentProvider {
private readonly logger = new Logger(StripeService.name)
constructor(private configService: ConfigService) {}
private getClient(config?: PaymentConfig): Stripe {
const stripeConfig = config as StripeProviderConfig
const secretKey =
stripeConfig?.secretKey || this.configService.get<string>('STRIPE_SECRET_KEY')
Iif (!secretKey) {
this.logger.error('Stripe Secret Key is missing (Check DB Config or ENV)')
throw new Error('Stripe Secret Key is not configured')
}
return new Stripe(secretKey, {
apiVersion: '2025-12-15.clover', // Updated to match SDK version
})
}
/**
* Creates a Stripe PaymentIntent for the specified amount.
* @param amount Amount in cents (smallest currency unit)
* @param currency Currency code (default: 'usd')
* @param metadata Additional metadata to attach to the intent
* @returns Object containing the clientSecret and intent ID
*/
async createPaymentIntent(
amount: number,
currency: string = 'usd',
metadata: Record<string, any> = {},
config?: PaymentConfig,
): Promise<CreatePaymentIntentResult> {
try {
const stripe = this.getClient(config)
const paymentIntent = await stripe.paymentIntents.create({
amount, // Amount in cents
currency,
metadata,
automatic_payment_methods: {
enabled: true,
},
})
if (!paymentIntent.client_secret) {
throw new Error('Failed to retrieve client secret from Stripe')
}
return {
clientSecret: paymentIntent.client_secret,
id: paymentIntent.id,
}
} catch (error) {
this.logger.error(`Error creating payment intent: ${error.message}`)
throw error
}
}
constructEventFromPayload(
headers: IncomingHttpHeaders | string,
payload: Buffer,
config?: PaymentConfig,
) {
const stripeConfig = config as StripeProviderConfig
const webhookSecret =
stripeConfig?.webhookSecret || this.configService.get<string>('STRIPE_WEBHOOK_SECRET')
Iif (!webhookSecret) {
throw new Error('STRIPE_WEBHOOK_SECRET is not configured')
}
const signature = typeof headers === 'string' ? headers : headers?.['stripe-signature']
if (!signature) {
return Promise.reject(new Error('Missing stripe-signature header'))
}
const stripe = this.getClient(config)
return Promise.resolve(stripe.webhooks.constructEvent(payload, signature, webhookSecret))
}
async refundDonation(paymentIntentId: string, config?: PaymentConfig): Promise<any> {
try {
const stripe = this.getClient(config)
return await stripe.refunds.create({
payment_intent: paymentIntentId,
})
} catch (error) {
this.logger.error(`Error refunding donation ${paymentIntentId}: ${error.message}`)
throw error
}
}
}
|