Files
boc/packages/operations/src/stripe.mjs
T
Bernt aee0f09db8 landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar
- Vision: Identify-modell, FAISS, OCR alla testade
- API: Alla 7 integrationstester passerade
- Upplösare: Entitetsupplösning verifierad
2026-07-05 06:41:32 +00:00

176 lines
5.3 KiB
JavaScript

/**
* 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', ')');