feat: WIP stripe billing refactor update for 2025

pull/715/head
Travis Fischer 2025-05-18 03:11:45 +07:00
rodzic ed0867a3b9
commit 8ea3a4f4b6
4 zmienionych plików z 15 dodań i 12 usunięć

Wyświetl plik

@ -87,10 +87,10 @@ export const consumers = pgTable(
stripeStatus: text(), stripeStatus: text(),
// Main Stripe Subscription id // Main Stripe Subscription id
stripeSubscriptionId: stripeId(), _stripeSubscriptionId: stripeId(),
// [lineItemSlug: string]: string // [lineItemSlug: string]: string
stripeSubscriptionLineItemIdMap: jsonb() _stripeSubscriptionLineItemIdMap: jsonb()
.$type<Record<string, string>>() .$type<Record<string, string>>()
.default({}) .default({})
.notNull(), .notNull(),
@ -132,7 +132,7 @@ export const consumerRelationsSchema: z.ZodType<ConsumerRelationFields> =
z.enum(['user', 'project', 'deployment']) z.enum(['user', 'project', 'deployment'])
export const consumerSelectSchema = createSelectSchema(consumers, { export const consumerSelectSchema = createSelectSchema(consumers, {
stripeSubscriptionLineItemIdMap: z.record(z.string(), z.string()), _stripeSubscriptionLineItemIdMap: z.record(z.string(), z.string()),
deploymentId: (schema) => deploymentId: (schema) =>
schema.refine((id) => validators.deploymentId(id), { schema.refine((id) => validators.deploymentId(id), {
@ -145,6 +145,8 @@ export const consumerSelectSchema = createSelectSchema(consumers, {
}) })
}) })
.omit({ .omit({
_stripeSubscriptionId: true,
_stripeSubscriptionLineItemIdMap: true,
_stripeCustomerId: true _stripeCustomerId: true
}) })
.extend({ .extend({

Wyświetl plik

@ -341,7 +341,7 @@ export const pricingPlanMapSchema = z
export type PricingPlanMap = z.infer<typeof pricingPlanMapSchema> export type PricingPlanMap = z.infer<typeof pricingPlanMapSchema>
// TODO // TODO
// export const stripeSubscriptionLineItemIdMapSchema = z // export const _stripeSubscriptionLineItemIdMapSchema = z
// .record(pricingPlanLineItemHashSchema, z.string().describe('Stripe LineItem id')) // .record(pricingPlanLineItemHashSchema, z.string().describe('Stripe LineItem id'))
// .describe('Map from internal PricingPlanLineItem **hash** to Stripe LineItem id') // .describe('Map from internal PricingPlanLineItem **hash** to Stripe LineItem id')
// .openapi('StripeSubscriptionLineItemMap') // .openapi('StripeSubscriptionLineItemMap')

Wyświetl plik

@ -33,6 +33,7 @@ export async function upsertConsumer(
if (!consumerId) { if (!consumerId) {
assert(projectId, 400, 'Missing required "deploymentId"') assert(projectId, 400, 'Missing required "deploymentId"')
assert(plan, 400, 'Missing required "plan"')
} }
const [{ user, stripeCustomer }, existingConsumer] = await Promise.all([ const [{ user, stripeCustomer }, existingConsumer] = await Promise.all([
@ -113,8 +114,8 @@ export async function upsertConsumer(
;[consumer] = await db.insert(schema.consumers).values({ ;[consumer] = await db.insert(schema.consumers).values({
plan, plan,
userId, userId,
deploymentId,
projectId, projectId,
deploymentId,
// TODO: refactor / improve token generation // TODO: refactor / improve token generation
token: sha256().slice(0, 24), token: sha256().slice(0, 24),
_stripeCustomerId: stripeCustomer.id _stripeCustomerId: stripeCustomer.id

Wyświetl plik

@ -53,17 +53,17 @@ export async function upsertStripeSubscription(
? deployment.pricingPlans.find((pricingPlan) => pricingPlan.slug === plan) ? deployment.pricingPlans.find((pricingPlan) => pricingPlan.slug === plan)
: undefined : undefined
const action: 'create' | 'update' | 'cancel' = consumer.stripeSubscriptionId const action: 'create' | 'update' | 'cancel' = consumer._stripeSubscriptionId
? plan ? plan
? 'update' ? 'update'
: 'cancel' : 'cancel'
: 'create' : 'create'
let subscription: Stripe.Subscription | undefined let subscription: Stripe.Subscription | undefined
if (consumer.stripeSubscriptionId) { if (consumer._stripeSubscriptionId) {
// customer has an existing subscription // customer has an existing subscription
const existing = await stripe.subscriptions.retrieve( const existing = await stripe.subscriptions.retrieve(
consumer.stripeSubscriptionId, consumer._stripeSubscriptionId,
...stripeConnectParams ...stripeConnectParams
) )
const existingItems = existing.items.data const existingItems = existing.items.data
@ -155,7 +155,7 @@ export async function upsertStripeSubscription(
assert( assert(
items.length || !plan, items.length || !plan,
500, 500,
`Error updating stripe subscription "${consumer.stripeSubscriptionId}"` `Error updating stripe subscription "${consumer._stripeSubscriptionId}"`
) )
for (const item of items) { for (const item of items) {
@ -182,7 +182,7 @@ export async function upsertStripeSubscription(
} }
subscription = await stripe.subscriptions.update( subscription = await stripe.subscriptions.update(
consumer.stripeSubscriptionId, consumer._stripeSubscriptionId,
update, update,
...stripeConnectParams ...stripeConnectParams
) )
@ -246,7 +246,7 @@ export async function upsertStripeSubscription(
...stripeConnectParams ...stripeConnectParams
) )
consumer.stripeSubscriptionId = subscription.id consumer._stripeSubscriptionId = subscription.id
} }
assert(subscription, 500, 'Missing stripe subscription') assert(subscription, 500, 'Missing stripe subscription')
@ -258,7 +258,7 @@ export async function upsertStripeSubscription(
consumerUpdate.stripeStatus = subscription.status consumerUpdate.stripeStatus = subscription.status
} else { } else {
// TODO // TODO
consumerUpdate.stripeSubscriptionId = null consumerUpdate._stripeSubscriptionId = null
consumerUpdate.stripeStatus = 'cancelled' consumerUpdate.stripeStatus = 'cancelled'
} }