Initial OSS scaffold from Songs2VID (pre-strip)
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
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<Stripe.Checkout.SessionCreateParams> {
|
||||
const opts: Partial<Stripe.Checkout.SessionCreateParams> = {
|
||||
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<string> {
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user