bot-me / src /bots /services /PayPalService.ts
Mohammed Foud
all
d16c049
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}`);
}
}
}