diff --git a/packages/auth/src/auth.ts b/packages/auth/src/auth.ts index fef08877..36ae442c 100644 --- a/packages/auth/src/auth.ts +++ b/packages/auth/src/auth.ts @@ -1,3 +1,5 @@ +import type { Subscription } from "@better-auth/stripe"; +import type Stripe from "stripe"; import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { stripe } from "@better-auth/stripe"; import { ChatOrPushProviderEnum } from "@novu/api/models/components"; @@ -179,19 +181,17 @@ export const initAuth = (db: dbClient) => { freeTrial: { days: 14, onTrialStart: async (subscription) => { - // Called when a trial starts - // @todo: send trial start email - // await sendTrialStartEmail(subscription.referenceId); + await triggerWorkflow(db, "trial-start", subscription); }, - onTrialEnd: async ({ subscription }, request) => { - // Called when a trial ends - // @todo: send trial end email - // await sendTrialEndEmail(user.email); + onTrialEnd: async ({ subscription }) => { + await triggerWorkflow(db, "trial-end", subscription); }, onTrialExpired: async (subscription) => { - // Called when a trial expires without conversion - // @todo: send trial expired email - // await sendTrialExpiredEmail(subscription.referenceId); + await triggerWorkflow( + db, + "trial-expired", + subscription, + ); }, }, }, @@ -203,19 +203,17 @@ export const initAuth = (db: dbClient) => { freeTrial: { days: 14, onTrialStart: async (subscription) => { - // Called when a trial starts - // @todo: send trial start email - // await sendTrialStartEmail(subscription.referenceId); + await triggerWorkflow(db, "trial-start", subscription); }, - onTrialEnd: async ({ subscription }, request) => { - // Called when a trial ends - // @todo: send trial end email - // await sendTrialEndEmail(user.email); + onTrialEnd: async ({ subscription }) => { + await triggerWorkflow(db, "trial-end", subscription); }, onTrialExpired: async (subscription) => { - // Called when a trial expires without conversion - // @todo: send trial expired email - // await sendTrialExpiredEmail(subscription.referenceId); + await triggerWorkflow( + db, + "trial-expired", + subscription, + ); }, }, }, @@ -474,3 +472,34 @@ export const initAuth = (db: dbClient) => { }, }); }; + +async function triggerWorkflow( + db: dbClient, + workflowId: string, + subscription: Subscription, + cancellationDetails?: Stripe.Subscription.CancellationDetails | null, +) { + try { + if (!subscription.stripeCustomerId || !notificationClient) return; + + const user = await userRepo.getByStripeCustomerId( + db, + subscription.stripeCustomerId, + ); + + if (!user || !notificationClient) return; + + await notificationClient.trigger({ + to: { + subscriberId: user.id, + }, + payload: { + ...subscription, + cancellationDetails, + }, + workflowId, + }); + } catch (error) { + console.error("Error triggering workflow", error); + } +} diff --git a/packages/db/src/repository/user.repo.ts b/packages/db/src/repository/user.repo.ts index 193b82d2..b24050db 100644 --- a/packages/db/src/repository/user.repo.ts +++ b/packages/db/src/repository/user.repo.ts @@ -28,6 +28,15 @@ export const getById = async (db: dbClient, userId: string) => { }); }; +export const getByStripeCustomerId = async ( + db: dbClient, + stripeCustomerId: string, +) => { + return await db.query.users.findFirst({ + where: eq(users.stripeCustomerId, stripeCustomerId), + }); +}; + export const getByEmail = (db: dbClient, email: string) => { return db.query.users.findFirst({ columns: { diff --git a/packages/stripe/src/index.ts b/packages/stripe/src/index.ts index d277762d..024ef0ec 100644 --- a/packages/stripe/src/index.ts +++ b/packages/stripe/src/index.ts @@ -71,4 +71,13 @@ export const updateSubscriptionSeats = async ( return updatedSubscription; }; +export const getCancellationDetails = async ( + stripeSubscriptionId: string, +): Promise => { + const stripe = createStripeClient(); + const stripeSubscription = + await stripe.subscriptions.retrieve(stripeSubscriptionId); + return stripeSubscription.cancellation_details ?? null; +}; + export { createStripeClient };