import type Stripe from "stripe"; import { STRIPE_PRODUCT_TAX_CODE } from "@/lib/credits"; import { prisma } from "@/lib/db"; import { getStripe } from "@/lib/stripe"; /** Enable Stripe Tax only when Dashboard registrations are active (STRIPE_AUTOMATIC_TAX=true). */ export function isStripeAutomaticTaxEnabled(): boolean { return process.env.STRIPE_AUTOMATIC_TAX === "true"; } /** * Shared Checkout Session options required/recommended by Stripe for SaaS: * - client_reference_id for linking * - automatic_tax (opt-in) + customer_update.address when tax is on * - tax_code already set on product_data by callers */ export function checkoutTaxAndReferenceOptions(userId: string): Partial { const opts: Partial = { client_reference_id: userId, }; if (isStripeAutomaticTaxEnabled()) { opts.automatic_tax = { enabled: true }; opts.customer_update = { address: "auto", name: "auto" }; // Collect billing address so tax can be calculated for new/returning customers opts.billing_address_collection = "required"; } return opts; } /** tax_behavior required on Prices when automatic tax is enabled. */ export function priceDataTaxFields(): { tax_behavior?: Stripe.Checkout.SessionCreateParams.LineItem.PriceData["tax_behavior"] } { if (!isStripeAutomaticTaxEnabled()) return {}; // Exclusive: listed prices are pre-tax; VAT/GST added at checkout return { tax_behavior: "exclusive" }; } export function productDataWithTaxCode( name: string, description: string, ): Stripe.Checkout.SessionCreateParams.LineItem.PriceData.ProductData { return { name, description, tax_code: STRIPE_PRODUCT_TAX_CODE, }; } /** Ensure the app user has a Stripe Customer and return its id. */ export async function ensureStripeCustomer(userId: string, email: string): Promise { const dbUser = await prisma.user.findUniqueOrThrow({ where: { id: userId }, select: { stripeCustomerId: true }, }); if (dbUser.stripeCustomerId) return dbUser.stripeCustomerId; const stripe = getStripe(); const customer = await stripe.customers.create({ email, metadata: { userId }, }); await prisma.user.update({ where: { id: userId }, data: { stripeCustomerId: customer.id }, }); return customer.id; }