Initial commit

This commit is contained in:
2025-09-26 17:34:37 +02:00
commit b96ccfd112
37 changed files with 23138 additions and 0 deletions

145
backend/services/paypal.js Normal file
View File

@@ -0,0 +1,145 @@
const paypal = require('@paypal/checkout-server-sdk');
// PayPal environment setup
function environment() {
const clientId = process.env.PAYPAL_CLIENT_ID;
const clientSecret = process.env.PAYPAL_CLIENT_SECRET;
const mode = process.env.PAYPAL_MODE || 'sandbox';
if (!clientId || !clientSecret) {
throw new Error('PayPal credentials not found in environment variables');
}
return mode === 'live'
? new paypal.core.LiveEnvironment(clientId, clientSecret)
: new paypal.core.SandboxEnvironment(clientId, clientSecret);
}
// PayPal client
function client() {
return new paypal.core.PayPalHttpClient(environment());
}
// Create PayPal order
async function createOrder(orderData) {
try {
const request = new paypal.orders.OrdersCreateRequest();
request.prefer("return=representation");
request.requestBody({
intent: 'CAPTURE',
purchase_units: [{
reference_id: orderData.reference_id,
amount: {
currency_code: orderData.currency || 'USD',
value: orderData.total
},
description: orderData.description || 'Payment from WooCommerce',
custom_id: orderData.wc_order_id,
items: orderData.items || []
}],
application_context: {
brand_name: orderData.brand_name || 'Your Store',
landing_page: 'BILLING',
user_action: 'PAY_NOW',
return_url: `${process.env.FRONTEND_URL}/success`,
cancel_url: `${process.env.FRONTEND_URL}/cancel`
}
});
const order = await client().execute(request);
console.log('PayPal Order Created:', {
id: order.result.id,
status: order.result.status,
amount: orderData.total
});
return {
success: true,
order_id: order.result.id,
status: order.result.status,
links: order.result.links
};
} catch (error) {
console.error('PayPal Create Order Error:', error);
return {
success: false,
error: error.message,
details: error.details || []
};
}
}
// Capture PayPal payment
async function captureOrder(orderId) {
try {
const request = new paypal.orders.OrdersCaptureRequest(orderId);
request.requestBody({});
const capture = await client().execute(request);
console.log('PayPal Order Captured:', {
id: capture.result.id,
status: capture.result.status,
payer_email: capture.result.payer?.email_address
});
return {
success: true,
capture_id: capture.result.id,
status: capture.result.status,
payer: capture.result.payer,
purchase_units: capture.result.purchase_units,
transaction_id: capture.result.purchase_units[0]?.payments?.captures[0]?.id
};
} catch (error) {
console.error('PayPal Capture Order Error:', error);
return {
success: false,
error: error.message,
details: error.details || []
};
}
}
// Get order details
async function getOrderDetails(orderId) {
try {
const request = new paypal.orders.OrdersGetRequest(orderId);
const order = await client().execute(request);
return {
success: true,
order: order.result
};
} catch (error) {
console.error('PayPal Get Order Error:', error);
return {
success: false,
error: error.message
};
}
}
// Verify webhook signature
function verifyWebhookSignature(headers, body, webhookId) {
// This is a simplified version - in production, use PayPal's webhook verification
// For now, we'll do basic validation
const webhookSecret = process.env.WEBHOOK_SECRET;
if (!webhookSecret) {
console.warn('WEBHOOK_SECRET not set - skipping signature verification');
return true;
}
// Add proper webhook signature verification here
// For development, we'll return true
return true;
}
module.exports = {
createOrder,
captureOrder,
getOrderDetails,
verifyWebhookSignature
};

View File

@@ -0,0 +1,204 @@
const axios = require('axios');
const https = require('https');
class WooCommerceService {
constructor() {
this.baseURL = process.env.WOOCOMMERCE_URL;
this.consumerKey = process.env.WOOCOMMERCE_CONSUMER_KEY;
this.consumerSecret = process.env.WOOCOMMERCE_CONSUMER_SECRET;
if (!this.baseURL || !this.consumerKey || !this.consumerSecret) {
console.warn('WooCommerce credentials not fully configured');
}
// Create HTTPS agent that ignores SSL errors in development
const httpsAgent = new https.Agent({
rejectUnauthorized: process.env.NODE_ENV === 'production'
});
this.client = axios.create({
baseURL: `${this.baseURL}/wp-json/wc/v3`,
auth: {
username: this.consumerKey,
password: this.consumerSecret
},
timeout: 10000,
httpsAgent: httpsAgent,
// Additional options for SSL issues
headers: {
'User-Agent': 'PaymentWebsite/1.0'
}
});
}
// Get order details from WooCommerce
async getOrder(orderId) {
try {
const response = await this.client.get(`/orders/${orderId}`);
console.log('WooCommerce Order Retrieved:', {
id: response.data.id,
status: response.data.status,
total: response.data.total
});
return {
success: true,
order: response.data
};
} catch (error) {
console.error('WooCommerce Get Order Error:', {
orderId,
error: error.response?.data || error.message
});
return {
success: false,
error: error.response?.data?.message || error.message
};
}
}
// Update order status in WooCommerce
async updateOrderStatus(orderId, status, transactionId = null) {
try {
const updateData = {
status: status
};
// Add transaction ID if payment was successful
if (transactionId) {
updateData.transaction_id = transactionId;
updateData.meta_data = [
{
key: '_paypal_transaction_id',
value: transactionId
}
];
}
const response = await this.client.put(`/orders/${orderId}`, updateData);
console.log('WooCommerce Order Updated:', {
id: response.data.id,
status: response.data.status,
transaction_id: transactionId
});
return {
success: true,
order: response.data
};
} catch (error) {
console.error('WooCommerce Update Order Error:', {
orderId,
status,
error: error.response?.data || error.message
});
return {
success: false,
error: error.response?.data?.message || error.message
};
}
}
// Add order note
async addOrderNote(orderId, note, customerNote = false) {
try {
const response = await this.client.post(`/orders/${orderId}/notes`, {
note: note,
customer_note: customerNote
});
console.log('Order note added:', {
orderId,
noteId: response.data.id
});
return {
success: true,
note: response.data
};
} catch (error) {
console.error('Add Order Note Error:', {
orderId,
error: error.response?.data || error.message
});
return {
success: false,
error: error.response?.data?.message || error.message
};
}
}
// Process payment completion
async completePayment(orderId, paypalData) {
try {
// Update order to processing/completed
const updateResult = await this.updateOrderStatus(
orderId,
'processing', // or 'completed' based on your workflow
paypalData.transaction_id
);
if (!updateResult.success) {
throw new Error(updateResult.error);
}
// Add payment note
const noteText = `Payment completed via PayPal. Transaction ID: ${paypalData.transaction_id}. Payer Email: ${paypalData.payer?.email_address || 'N/A'}`;
await this.addOrderNote(orderId, noteText, false);
return {
success: true,
message: 'Payment completed and order updated'
};
} catch (error) {
console.error('Complete Payment Error:', {
orderId,
error: error.message
});
return {
success: false,
error: error.message
};
}
}
// Handle payment failure
async failPayment(orderId, reason) {
try {
// Update order to failed
const updateResult = await this.updateOrderStatus(orderId, 'failed');
if (!updateResult.success) {
throw new Error(updateResult.error);
}
// Add failure note
const noteText = `Payment failed: ${reason}`;
await this.addOrderNote(orderId, noteText, false);
return {
success: true,
message: 'Order marked as failed'
};
} catch (error) {
console.error('Fail Payment Error:', {
orderId,
error: error.message
});
return {
success: false,
error: error.message
};
}
}
}
module.exports = new WooCommerceService();