@@ -42,6 +42,10 @@ export const webhookRouter = createTRPCRouter({
4242 customerSubscriptionUpdated : webhookProcedure . mutation ( async ( opts ) => {
4343 const subscription = opts . input . event . data . object as Stripe . Subscription ;
4444
45+ if ( subscription . status !== "active" ) {
46+ return ;
47+ }
48+
4549 const customerId =
4650 typeof subscription . customer === "string"
4751 ? subscription . customer
@@ -59,50 +63,77 @@ export const webhookRouter = createTRPCRouter({
5963 } ) ;
6064 }
6165
62- // for (const item of subscription.items.data) {
63- // const feature = getFeatureFromPriceId(item.price.id);
64- // if (!feature) {
65- // continue;
66- // }
67- // const _ws = await opts.ctx.db
68- // .select()
69- // .from(workspace)
70- // .where(eq(workspace.stripeId, customerId))
71- // .get();
72-
73- // const ws = selectWorkspaceSchema.parse(_ws);
74-
75- // const currentValue = ws.limits[feature.feature];
76- // const newValue =
77- // typeof currentValue === "boolean"
78- // ? true
79- // : typeof currentValue === "number"
80- // ? currentValue + 1
81- // : currentValue;
82-
83- // const newLimits = updateAddonInLimits(
84- // ws.limits,
85- // feature.feature,
86- // newValue,
87- // );
88-
89- // await opts.ctx.db
90- // .update(workspace)
91- // .set({
92- // limits: JSON.stringify(newLimits),
93- // })
94- // .where(eq(workspace.id, result.id))
95- // .run();
96- // }
66+ const ws = selectWorkspaceSchema . parse ( result ) ;
67+ const oldPlan = ws . plan ;
9768
98- const customer = await stripe . customers . retrieve ( customerId ) ;
99- if ( ! customer . deleted && customer . email ) {
100- const userResult = await opts . ctx . db
101- . select ( )
102- . from ( user )
103- . where ( eq ( user . email , customer . email ) )
104- . get ( ) ;
105- if ( ! userResult ) return ;
69+ let detectedPlan : ReturnType < typeof getPlanFromPriceId > = undefined ;
70+
71+ for ( const item of subscription . items . data ) {
72+ const plan = getPlanFromPriceId ( item . price . id ) ;
73+ if ( plan ) {
74+ detectedPlan = plan ;
75+ break ;
76+ }
77+ }
78+
79+ if ( ! detectedPlan ) {
80+ return ;
81+ }
82+
83+ await opts . ctx . db
84+ . update ( workspace )
85+ . set ( {
86+ plan : detectedPlan . plan ,
87+ subscriptionId : subscription . id ,
88+ endsAt : new Date ( subscription . current_period_end * 1000 ) ,
89+ paidUntil : new Date ( subscription . current_period_end * 1000 ) ,
90+ limits : JSON . stringify ( getLimits ( detectedPlan . plan ) ) ,
91+ } )
92+ . where ( eq ( workspace . id , result . id ) )
93+ . run ( ) ;
94+
95+ const allActive = await stripe . subscriptions . list ( {
96+ customer : customerId ,
97+ status : "active" ,
98+ } ) ;
99+
100+ for ( const sub of allActive . data ) {
101+ if ( sub . id === subscription . id ) continue ;
102+ try {
103+ await stripe . subscriptions . cancel ( sub . id ) ;
104+ } catch ( e ) {
105+ console . error ( `Failed to cancel duplicate subscription ${ sub . id } :` , e ) ;
106+ }
107+ }
108+
109+ const newPlan = detectedPlan ?. plan ?? oldPlan ;
110+ if ( detectedPlan && newPlan !== oldPlan ) {
111+ const customer = await stripe . customers . retrieve ( customerId ) ;
112+ if ( ! customer . deleted && customer . email ) {
113+ const userResult = await opts . ctx . db
114+ . select ( )
115+ . from ( user )
116+ . where ( eq ( user . email , customer . email ) )
117+ . get ( ) ;
118+ if ( ! userResult ) return ;
119+
120+ const planOrder = [ "free" , "starter" , "team" ] as const ;
121+ const oldIndex = planOrder . indexOf ( oldPlan ?? "free" ) ;
122+ const newIndex = planOrder . indexOf ( newPlan ?? "free" ) ;
123+
124+ const event =
125+ newIndex > oldIndex
126+ ? Events . UpgradeWorkspace
127+ : Events . DowngradeWorkspace ;
128+
129+ const analytics = await setupAnalytics ( {
130+ userId : `usr_${ userResult . id } ` ,
131+ email : userResult . email || undefined ,
132+ workspaceId : String ( result . id ) ,
133+ plan : newPlan ,
134+ } ) ;
135+ await analytics . track ( event ) ;
136+ }
106137 }
107138 } ) ,
108139 sessionCompleted : webhookProcedure . mutation ( async ( opts ) => {
@@ -212,6 +243,15 @@ export const webhookRouter = createTRPCRouter({
212243 ? subscription . customer
213244 : subscription . customer . id ;
214245
246+ const activeSubscriptions = await stripe . subscriptions . list ( {
247+ customer : customerId ,
248+ status : "active" ,
249+ } ) ;
250+
251+ if ( activeSubscriptions . data . length > 0 ) {
252+ return ;
253+ }
254+
215255 const _workspace = await opts . ctx . db . transaction ( async ( tx ) => {
216256 const _workspace = await tx
217257 . update ( workspace )
@@ -312,6 +352,13 @@ export const webhookRouter = createTRPCRouter({
312352 return _workspace ;
313353 } ) ;
314354
355+ if ( ! _workspace [ 0 ] ) {
356+ throw new TRPCError ( {
357+ code : "BAD_REQUEST" ,
358+ message : "Workspace not found" ,
359+ } ) ;
360+ }
361+
315362 const workspaceId = _workspace [ 0 ] . id ;
316363 const customer = await stripe . customers . retrieve ( customerId ) ;
317364
0 commit comments