Spaces:
Paused
Paused
| import { BotContext } from '../types/botTypes'; | |
| import axios from 'axios'; | |
| import { createLogger } from '../../utils/logger'; | |
| const logger = createLogger('PayPalService'); | |
| // PayPal API Response Types | |
| interface PayPalLink { | |
| href: string; | |
| rel: string; | |
| method: string; | |
| } | |
| interface PayPalOrder { | |
| id: string; | |
| status: string; | |
| links: PayPalLink[]; | |
| } | |
| interface PayPalTokenResponse { | |
| access_token: string; | |
| token_type: string; | |
| expires_in: number; | |
| } | |
| export class PayPalService { | |
| private static instance: PayPalService; | |
| private readonly clientId: string; | |
| private readonly clientSecret: string; | |
| private readonly isProduction: boolean; | |
| private constructor(ctx: BotContext) { | |
| this.clientId = ctx.botData?.paypal_client_id || ''; | |
| this.clientSecret = ctx.botData?.paypal_client_secret || ''; | |
| this.isProduction = ctx.botData?.settings?.paypal_environment === 'production'; | |
| } | |
| public static getInstance(ctx: BotContext): PayPalService { | |
| if (!PayPalService.instance) { | |
| PayPalService.instance = new PayPalService(ctx); | |
| } | |
| return PayPalService.instance; | |
| } | |
| async createPaymentLink(userId: string, amount: number): Promise<string> { | |
| try { | |
| const accessToken = await this.getAccessToken(); | |
| const order = await this.createPayPalOrder(amount, userId); | |
| // Find the approval URL from the order links | |
| const approvalLink = order.links.find(link => link.rel === 'approve'); | |
| if (!approvalLink) { | |
| throw new Error('No approval URL found in PayPal order'); | |
| } | |
| return approvalLink.href; | |
| } catch (error: any) { | |
| logger.error(`Error creating PayPal payment link: ${error.message}`); | |
| throw new Error(`Failed to create payment link: ${error.message}`); | |
| } | |
| } | |
| private async createPayPalOrder(amount: number, paymentId: string): Promise<PayPalOrder> { | |
| try { | |
| const accessToken = await this.getAccessToken(); | |
| const baseUrl = this.isProduction | |
| ? 'https://api-m.paypal.com' | |
| : 'https://api-m.sandbox.paypal.com'; | |
| const response = await axios.post( | |
| `${baseUrl}/v2/checkout/orders`, | |
| { | |
| intent: 'CAPTURE', | |
| purchase_units: [{ | |
| amount: { | |
| currency_code: 'USD', | |
| value: amount.toString() | |
| }, | |
| custom_id: paymentId | |
| }] | |
| }, | |
| { | |
| headers: { | |
| 'Authorization': `Bearer ${accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| return response.data; | |
| } catch (error: any) { | |
| logger.error(`Error creating PayPal order: ${error.message}`); | |
| throw new Error(`Failed to create PayPal order: ${error.message}`); | |
| } | |
| } | |
| private async getAccessToken(): Promise<string> { | |
| try { | |
| const baseUrl = this.isProduction | |
| ? 'https://api-m.paypal.com' | |
| : 'https://api-m.sandbox.paypal.com'; | |
| const response = await axios.post( | |
| `${baseUrl}/v1/oauth2/token`, | |
| 'grant_type=client_credentials', | |
| { | |
| headers: { | |
| 'Authorization': `Basic ${Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64')}`, | |
| 'Content-Type': 'application/x-www-form-urlencoded' | |
| } | |
| } | |
| ); | |
| const data = response.data as PayPalTokenResponse; | |
| return data.access_token; | |
| } catch (error: any) { | |
| logger.error(`Error getting PayPal access token: ${error.message}`); | |
| throw new Error(`Failed to get PayPal access token: ${error.message}`); | |
| } | |
| } | |
| } |