- Update StripeConnectOnboarding component with embedded flow - Add new Stripe routes and service methods for embedded onboarding - Update EarningsStatus and EarningsDashboard to support new flow - Add required frontend dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
231 lines
6.6 KiB
JavaScript
231 lines
6.6 KiB
JavaScript
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;
|