File size: 3,581 Bytes
d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 d16c049 80d4bc1 |
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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
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}`);
}
}
} |