/** * Stripe Integration for LandveX Operations * * Handles: * - Payment method setup (card, autogiro) * - Subscription billing * - Invoice generation * - Webhook handling */ import https from 'https'; const STRIPE_API_KEY = process.env.STRIPE_SECRET_KEY; const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET; function stripeRequest(method, path, data = null) { return new Promise((resolve, reject) => { if (!STRIPE_API_KEY) { reject(new Error('Stripe not configured')); return; } const options = { hostname: 'api.stripe.com', port: 443, path: `/v1${path}`, method, headers: { 'Authorization': `Bearer ${STRIPE_API_KEY}`, 'Content-Type': 'application/x-www-form-urlencoded', }, }; const req = https.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { const json = JSON.parse(body); if (json.error) reject(json.error); else resolve(json); } catch (e) { resolve(body); } }); }); req.on('error', reject); if (data) { const params = new URLSearchParams(data); req.write(params.toString()); } req.end(); }); } // Create a customer export async function createCustomer(email, name, metadata = {}) { return stripeRequest('POST', '/customers', { email, name, ...Object.entries(metadata).reduce((acc, [k, v]) => ({ ...acc, [`metadata[${k}]`]: v }), {}), }); } // Create a payment intent export async function createPaymentIntent(amount, currency, customerId, metadata = {}) { return stripeRequest('POST', '/payment_intents', { amount: Math.round(amount * 100), // Convert to cents currency: currency.toLowerCase(), customer: customerId, automatic_payment_methods: { enabled: true }, ...Object.entries(metadata).reduce((acc, [k, v]) => ({ ...acc, [`metadata[${k}]`]: v }), {}), }); } // Create a subscription export async function createSubscription(customerId, priceId, metadata = {}) { return stripeRequest('POST', '/subscriptions', { customer: customerId, items: [{ price: priceId }], payment_behavior: 'default_incomplete', expand: ['latest_invoice.payment_intent'], ...Object.entries(metadata).reduce((acc, [k, v]) => ({ ...acc, [`metadata[${k}]`]: v }), {}), }); } // Create a setup intent for saving payment methods export async function createSetupIntent(customerId) { return stripeRequest('POST', '/setup_intents', { customer: customerId, usage: 'off_session', }); } // List payment methods for a customer export async function listPaymentMethods(customerId, type = 'card') { return stripeRequest('GET', `/customers/${customerId}/payment_methods?type=${type}`); } // Create invoice export async function createInvoice(customerId, autoAdvance = true) { return stripeRequest('POST', '/invoices', { customer: customerId, auto_advance: autoAdvance, }); } // Add invoice item export async function createInvoiceItem(customerId, amount, currency, description) { return stripeRequest('POST', '/invoiceitems', { customer: customerId, amount: Math.round(amount * 100), currency: currency.toLowerCase(), description, }); } // Finalize and send invoice export async function finalizeInvoice(invoiceId) { return stripeRequest('POST', `/invoices/${invoiceId}/finalize`); } // Verify webhook signature export function verifyWebhookSignature(payload, signature) { // In production, use Stripe's official library // This is a simplified version if (!STRIPE_WEBHOOK_SECRET) { return { valid: false, error: 'Webhook secret not configured' }; } // For now, accept all webhooks in development if (process.env.NODE_ENV === 'development') { return { valid: true }; } return { valid: false, error: 'Webhook verification not implemented' }; } // Handle webhook events export async function handleWebhookEvent(event) { switch (event.type) { case 'payment_intent.succeeded': console.log('Payment succeeded:', event.data.object.id); return { status: 'success', paymentIntent: event.data.object.id }; case 'payment_intent.payment_failed': console.log('Payment failed:', event.data.object.id); return { status: 'failed', paymentIntent: event.data.object.id, error: event.data.object.last_payment_error }; case 'invoice.paid': console.log('Invoice paid:', event.data.object.id); return { status: 'paid', invoice: event.data.object.id }; case 'invoice.payment_failed': console.log('Invoice payment failed:', event.data.object.id); return { status: 'failed', invoice: event.data.object.id }; case 'customer.subscription.created': console.log('Subscription created:', event.data.object.id); return { status: 'created', subscription: event.data.object.id }; case 'customer.subscription.deleted': console.log('Subscription cancelled:', event.data.object.id); return { status: 'cancelled', subscription: event.data.object.id }; default: console.log('Unhandled event:', event.type); return { status: 'unhandled', type: event.type }; } } console.log('Stripe module loaded (API key:', STRIPE_API_KEY ? 'configured' : 'NOT CONFIGURED', ')');