UNPKG

quickpos

Version:

<div align="center"> <h1>💳 QuickPos 🚀</h1> <p><strong>A powerful, multi-gateway payment integration module for Node.js</strong></p> <p>Seamlessly integrate with 50+ payment providers worldwide</p>

249 lines (221 loc) • 9.15 kB
const axios = require('axios'); const crypto = require('crypto'); class CheckoutClient { constructor(config) { const requiredFields = ['secretKey']; for (let field of requiredFields) { if (!config[field]) throw new Error(`Missing required field: ${field}`); } this.secretKey = config.secretKey; this.publicKey = config.publicKey || ''; this.isSandbox = config.sandbox || false; this.URL = this.isSandbox ? 'https://api.sandbox.checkout.com' : 'https://api.checkout.com'; this.client = axios.create({ baseURL: this.URL, headers: { 'Authorization': this.secretKey, 'Content-Type': 'application/json' } }); this.client.interceptors.response.use(response => { return response; }, error => { if (error.response) { throw new Error(`Checkout.com API error: ${error.response.data.error_type || error.message}`); } throw new Error(`Checkout.com API error: ${error.message}`); }); } async createPayment(options) { try { const requestData = { source: { type: options.sourceType || 'token', token: options.token }, amount: Math.round(parseFloat(options.amount) * 100), // Convert to cents currency: options.currency || 'USD', payment_type: options.paymentType || 'Regular', reference: options.reference || options.orderId || `ORDER-${Date.now()}`, description: options.description || options.name || 'Payment', capture: options.capture !== undefined ? options.capture : true, customer: { email: options.customerEmail || options.email, name: options.customerName || options.name || 'Customer' }, billing_descriptor: { name: options.billingName || options.name || 'Product', city: options.billingCity || 'London' }, metadata: { order_id: options.orderId || `ORDER-${Date.now()}`, ...options.metadata }, success_url: options.successUrl || options.callback_link, failure_url: options.failureUrl || options.callback_link }; // If using hosted payment page if (options.useHostedPage) { const response = await this.client.post('/payment-links', { amount: requestData.amount, currency: requestData.currency, reference: requestData.reference, description: requestData.description, customer: requestData.customer, billing: { address: { country: options.billingCountry || 'GB' } }, products: options.products || [{ name: options.name || 'Product', quantity: 1, price: requestData.amount }], metadata: requestData.metadata, return_url: options.returnUrl || options.callback_link, locale: options.locale || 'en-GB' }); return { status: 'success', data: { id: response.data.id, url: response.data._links.redirect.href, reference: requestData.reference, expiresOn: response.data.expires_on } }; } // Direct payment const response = await this.client.post('/payments', requestData); return { status: response.data.approved ? 'success' : 'pending', data: { id: response.data.id, actionId: response.data.action_id, amount: response.data.amount, currency: response.data.currency, approved: response.data.approved, status: response.data.status, reference: response.data.reference, responseCode: response.data.response_code, responseMessage: response.data.response_summary, redirectUrl: response.data._links?.redirect?.href } }; } catch (error) { throw new Error(`Payment creation error: ${error.message}`); } } async getPaymentDetails(paymentId) { try { const response = await this.client.get(`/payments/${paymentId}`); return response.data; } catch (error) { throw new Error(`Payment details error: ${error.message}`); } } async handleCallback(callbackData) { try { const verification = await this.verifyWebhook(callbackData); if (!verification.status) { throw new Error(verification.error.message); } const data = verification.data; // Status mapping const statusMapping = { 'Authorized': 'success', 'Card Verified': 'success', 'Pending': 'pending', 'Declined': 'failed', 'Canceled': 'cancelled', 'Expired': 'expired' }; const eventData = data.data; return { status: statusMapping[eventData.status] || 'unknown', paymentId: eventData.id, actionId: eventData.action_id, orderId: eventData.reference, amount: parseFloat(eventData.amount) / 100, currency: eventData.currency, approved: eventData.approved, paymentStatus: eventData.status, responseCode: eventData.response_code, responseMessage: eventData.response_summary, eventType: data.type }; } catch (error) { throw new Error(`Error in Checkout.com callback handling: ${error.message}`); } } async verifyWebhook(data, signature = null) { try { // Checkout.com webhook signature verification // This is a simplified version - in production, verify the signature if (data.type && data.data) { return { status: true, data: data }; } return { status: false, error: { code: 400, message: 'Invalid webhook data' } }; } catch (error) { return { status: false, error: { code: 500, message: error.message } }; } } async capturePayment(paymentId, amount = null) { try { const requestData = {}; if (amount) { requestData.amount = Math.round(parseFloat(amount) * 100); } const response = await this.client.post(`/payments/${paymentId}/captures`, requestData); return response.data; } catch (error) { throw new Error(`Capture payment error: ${error.message}`); } } async voidPayment(paymentId, reference = null) { try { const requestData = {}; if (reference) { requestData.reference = reference; } const response = await this.client.post(`/payments/${paymentId}/voids`, requestData); return response.data; } catch (error) { throw new Error(`Void payment error: ${error.message}`); } } async refundPayment(paymentId, amount = null, reference = null) { try { const requestData = {}; if (amount) { requestData.amount = Math.round(parseFloat(amount) * 100); } if (reference) { requestData.reference = reference; } const response = await this.client.post(`/payments/${paymentId}/refunds`, requestData); return response.data; } catch (error) { throw new Error(`Refund payment error: ${error.message}`); } } } module.exports = CheckoutClient;