const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); const logger = require("../utils/logger"); class StripeService { static async getCheckoutSession(sessionId) { try { return await stripe.checkout.sessions.retrieve(sessionId, { expand: ['setup_intent', 'setup_intent.payment_method'] }); } catch (error) { logger.error("Error retrieving checkout session", { error: error.message, stack: error.stack }); throw error; } } static async createConnectedAccount({ email, country = "US" }) { try { const account = await stripe.accounts.create({ type: "express", email, country, capabilities: { transfers: { requested: true }, }, }); return account; } catch (error) { logger.error("Error creating connected account", { error: error.message, stack: error.stack }); throw error; } } static async createAccountLink(accountId, refreshUrl, returnUrl) { try { const accountLink = await stripe.accountLinks.create({ account: accountId, refresh_url: refreshUrl, return_url: returnUrl, type: "account_onboarding", }); return accountLink; } catch (error) { logger.error("Error creating account link", { error: error.message, stack: error.stack }); throw error; } } static async getAccountStatus(accountId) { try { const account = await stripe.accounts.retrieve(accountId); return { id: account.id, details_submitted: account.details_submitted, payouts_enabled: account.payouts_enabled, capabilities: account.capabilities, requirements: account.requirements, }; } catch (error) { logger.error("Error retrieving account status", { error: error.message, stack: error.stack }); throw error; } } static async createAccountSession(accountId) { try { const accountSession = await stripe.accountSessions.create({ account: accountId, components: { account_onboarding: { enabled: true }, }, }); return accountSession; } catch (error) { logger.error("Error creating account session", { error: error.message, stack: error.stack }); throw error; } } static async createTransfer({ amount, currency = "usd", destination, metadata = {}, }) { try { const transfer = await stripe.transfers.create({ amount: Math.round(amount * 100), // Convert to cents currency, destination, metadata, }); return transfer; } catch (error) { logger.error("Error creating transfer", { error: error.message, stack: error.stack }); throw error; } } static async createRefund({ paymentIntentId, amount, metadata = {}, reason = "requested_by_customer", }) { try { const refund = await stripe.refunds.create({ payment_intent: paymentIntentId, amount: Math.round(amount * 100), // Convert to cents metadata, reason, }); return refund; } catch (error) { logger.error("Error creating refund", { error: error.message, stack: error.stack }); throw error; } } static async getRefund(refundId) { try { return await stripe.refunds.retrieve(refundId); } catch (error) { logger.error("Error retrieving refund", { error: error.message, stack: error.stack }); throw error; } } static async chargePaymentMethod(paymentMethodId, amount, customerId, metadata = {}) { try { // Create a payment intent with the stored payment method const paymentIntent = await stripe.paymentIntents.create({ amount: Math.round(amount * 100), // Convert to cents currency: "usd", payment_method: paymentMethodId, customer: customerId, // Include customer ID confirm: true, // Automatically confirm the payment off_session: true, // Indicate this is an off-session payment return_url: `${process.env.FRONTEND_URL || 'http://localhost:3000'}/payment-complete`, metadata, expand: ['charges.data.payment_method_details'], // Expand to get payment method details }); // Extract payment method details from charges const charge = paymentIntent.charges?.data?.[0]; const paymentMethodDetails = charge?.payment_method_details; // Build payment method info object let paymentMethod = null; if (paymentMethodDetails) { const type = paymentMethodDetails.type; if (type === 'card') { paymentMethod = { type: 'card', brand: paymentMethodDetails.card?.brand || 'card', last4: paymentMethodDetails.card?.last4 || '****', }; } else if (type === 'us_bank_account') { paymentMethod = { type: 'bank', brand: 'bank_account', last4: paymentMethodDetails.us_bank_account?.last4 || '****', }; } else { paymentMethod = { type: type || 'unknown', brand: type || 'payment', last4: null, }; } } return { paymentIntentId: paymentIntent.id, status: paymentIntent.status, clientSecret: paymentIntent.client_secret, paymentMethod: paymentMethod, chargedAt: new Date(paymentIntent.created * 1000), // Convert Unix timestamp to Date amountCharged: amount, // Original amount in dollars }; } catch (error) { logger.error("Error charging payment method", { error: error.message, stack: error.stack }); throw error; } } static async createCustomer({ email, name, metadata = {} }) { try { const customer = await stripe.customers.create({ email, name, metadata, }); return customer; } catch (error) { logger.error("Error creating customer", { error: error.message, stack: error.stack }); throw error; } } static async createSetupCheckoutSession({ customerId, metadata = {} }) { try { const session = await stripe.checkout.sessions.create({ customer: customerId, payment_method_types: ['card', 'us_bank_account', 'link'], mode: 'setup', ui_mode: 'embedded', redirect_on_completion: 'never', metadata: { type: 'payment_method_setup', ...metadata } }); return session; } catch (error) { logger.error("Error creating setup checkout session", { error: error.message, stack: error.stack }); throw error; } } } module.exports = StripeService;