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>
194 lines (169 loc) • 6.82 kB
JavaScript
const axios = require('axios');
const crypto = require('crypto');
class YooKassaClient {
constructor(config) {
const requiredFields = ['shopId', 'secretKey'];
for (let field of requiredFields) {
if (!config[field]) throw new Error(`Missing required field: ${field}`);
}
this.shopId = config.shopId;
this.secretKey = config.secretKey;
this.baseURL = 'https://api.yookassa.ru/v3';
this.client = axios.create({
baseURL: this.baseURL,
auth: {
username: this.shopId,
password: this.secretKey
},
headers: {
'Content-Type': 'application/json',
'Idempotence-Key': this.generateIdempotenceKey()
}
});
}
generateIdempotenceKey() {
return crypto.randomBytes(16).toString('hex');
}
async createPayment(options) {
try {
const orderId = options.orderId || `ORDER-${Date.now()}`;
const paymentData = {
amount: {
value: parseFloat(options.amount).toFixed(2),
currency: options.currency || 'RUB'
},
confirmation: {
type: 'redirect',
return_url: options.successUrl || options.callback_link
},
capture: options.autoCapture !== false,
description: options.description || options.name || 'Payment',
metadata: {
order_id: orderId
},
receipt: options.receipt || undefined
};
// Customer info
if (options.email || options.phone) {
paymentData.receipt = {
customer: {
email: options.email,
phone: options.phone
},
items: options.items || [{
description: paymentData.description,
quantity: '1.00',
amount: paymentData.amount,
vat_code: options.vatCode || 1
}]
};
}
const response = await this.client.post('/payments', paymentData, {
headers: {
'Idempotence-Key': this.generateIdempotenceKey()
}
});
return {
status: 'success',
data: {
id: response.data.id,
url: response.data.confirmation.confirmation_url,
orderId: orderId,
amount: response.data.amount.value,
currency: response.data.amount.currency,
status: response.data.status
}
};
} catch (error) {
throw new Error(`Payment creation error: ${error.response?.data?.description || error.message}`);
}
}
async handleCallback(callbackData) {
try {
const payment = callbackData.object;
if (!payment || !payment.id) {
throw new Error('Invalid callback data');
}
// Verify payment
const verifiedPayment = await this.getPaymentDetails(payment.id);
// Status mapping
const statusMapping = {
'succeeded': 'success',
'pending': 'pending',
'waiting_for_capture': 'pending',
'canceled': 'failed'
};
return {
status: statusMapping[verifiedPayment.status] || 'unknown',
orderId: verifiedPayment.metadata?.order_id || '',
transactionId: verifiedPayment.id,
amount: parseFloat(verifiedPayment.amount.value),
currency: verifiedPayment.amount.currency,
paymentStatus: verifiedPayment.status,
paymentMethod: verifiedPayment.payment_method?.type,
paid: verifiedPayment.paid,
refundable: verifiedPayment.refundable
};
} catch (error) {
throw new Error(`Error in YooKassa callback handling: ${error.message}`);
}
}
async getPaymentDetails(paymentId) {
try {
const response = await this.client.get(`/payments/${paymentId}`);
return response.data;
} catch (error) {
throw new Error(`Error getting payment details: ${error.response?.data?.description || error.message}`);
}
}
async capturePayment(paymentId, options = {}) {
try {
const captureData = {
amount: options.amount ? {
value: parseFloat(options.amount).toFixed(2),
currency: options.currency || 'RUB'
} : undefined
};
const response = await this.client.post(`/payments/${paymentId}/capture`, captureData, {
headers: {
'Idempotence-Key': this.generateIdempotenceKey()
}
});
return response.data;
} catch (error) {
throw new Error(`Error capturing payment: ${error.response?.data?.description || error.message}`);
}
}
async cancelPayment(paymentId) {
try {
const response = await this.client.post(`/payments/${paymentId}/cancel`, {}, {
headers: {
'Idempotence-Key': this.generateIdempotenceKey()
}
});
return response.data;
} catch (error) {
throw new Error(`Error canceling payment: ${error.response?.data?.description || error.message}`);
}
}
async createRefund(paymentId, options = {}) {
try {
const refundData = {
payment_id: paymentId,
amount: {
value: parseFloat(options.amount).toFixed(2),
currency: options.currency || 'RUB'
}
};
const response = await this.client.post('/refunds', refundData, {
headers: {
'Idempotence-Key': this.generateIdempotenceKey()
}
});
return response.data;
} catch (error) {
throw new Error(`Error creating refund: ${error.response?.data?.description || error.message}`);
}
}
}
module.exports = YooKassaClient;