Handle membership updates in Stripe (#5992)
This commit is contained in:
@@ -1,9 +1,17 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { getStripeCustomerIdFromUserId } from "@calcom/app-store/stripepayment/lib/customer";
|
||||
import stripe from "@calcom/app-store/stripepayment/lib/server";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
const teamPaymentMetadataSchema = z.object({
|
||||
paymentId: z.string(),
|
||||
subscriptionId: z.string(),
|
||||
subscriptionItemId: z.string(),
|
||||
});
|
||||
|
||||
/** Used to prevent double charges for the same team */
|
||||
export const checkIfTeamPaymentRequired = async ({ teamId = -1 }) => {
|
||||
const team = await prisma.team.findUniqueOrThrow({
|
||||
@@ -56,21 +64,43 @@ export const purchaseTeamSubscription = async (input: { teamId: number; seats: n
|
||||
return { url: session.url };
|
||||
};
|
||||
|
||||
const getTeamWithPaymentMetadata = async (teamId: number) => {
|
||||
const team = await prisma.team.findUniqueOrThrow({
|
||||
where: { id: teamId },
|
||||
select: { metadata: true, members: true },
|
||||
});
|
||||
const metadata = teamPaymentMetadataSchema.parse(team.metadata);
|
||||
return { ...team, metadata };
|
||||
};
|
||||
|
||||
export const cancelTeamSubscriptionFromStripe = async (teamId: number) => {
|
||||
try {
|
||||
const team = await prisma.team.findUniqueOrThrow({
|
||||
where: { id: teamId },
|
||||
select: { metadata: true },
|
||||
});
|
||||
const metadata = teamMetadataSchema.parse(team.metadata);
|
||||
if (!metadata?.subscriptionId)
|
||||
throw Error(
|
||||
`Couldn't cancelTeamSubscriptionFromStripe, Team id: ${teamId} didn't have a subscriptionId`
|
||||
);
|
||||
return await stripe.subscriptions.cancel(metadata.subscriptionId);
|
||||
const team = await getTeamWithPaymentMetadata(teamId);
|
||||
const { subscriptionId } = team.metadata;
|
||||
return await stripe.subscriptions.cancel(subscriptionId);
|
||||
} catch (error) {
|
||||
let message = "Unknown error on cancelTeamSubscriptionFromStripe";
|
||||
if (error instanceof Error) message = error.message;
|
||||
console.error(message);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateQuantitySubscriptionFromStripe = async (teamId: number) => {
|
||||
try {
|
||||
const { url } = await checkIfTeamPaymentRequired({ teamId });
|
||||
/**
|
||||
* If there's no pending checkout URL it means that this team has not been paid.
|
||||
* We cannot update the subscription yet, this will be handled on publish/checkout.
|
||||
**/
|
||||
if (!url) return;
|
||||
const team = await getTeamWithPaymentMetadata(teamId);
|
||||
const { subscriptionId, subscriptionItemId } = team.metadata;
|
||||
await stripe.subscriptions.update(subscriptionId, {
|
||||
items: [{ quantity: team.members.length, id: subscriptionItemId }],
|
||||
});
|
||||
} catch (error) {
|
||||
let message = "Unknown error on updateQuantitySubscriptionFromStripe";
|
||||
if (error instanceof Error) message = error.message;
|
||||
console.error(message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,8 +8,9 @@ import { sendTeamInviteEmail } from "@calcom/emails";
|
||||
import {
|
||||
cancelTeamSubscriptionFromStripe,
|
||||
purchaseTeamSubscription,
|
||||
updateQuantitySubscriptionFromStripe,
|
||||
} from "@calcom/features/ee/teams/lib/payments";
|
||||
import { HOSTED_CAL_FEATURES, IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import { getTeamWithMembers, isTeamAdmin, isTeamMember, isTeamOwner } from "@calcom/lib/server/queries/teams";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
@@ -242,8 +243,7 @@ export const viewerTeamsRouter = router({
|
||||
|
||||
// Sync Services
|
||||
closeComDeleteTeamMembership(membership.user);
|
||||
// @TODO: Update with new logic
|
||||
// if (HOSTED_CAL_FEATURES) await removeSeat(ctx.user.id, input.teamId, input.memberId);
|
||||
if (IS_TEAM_BILLING_ENABLED) await updateQuantitySubscriptionFromStripe(input.teamId);
|
||||
}),
|
||||
inviteMember: authedProcedure
|
||||
.input(
|
||||
@@ -354,13 +354,7 @@ export const viewerTeamsRouter = router({
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: Update with new logic
|
||||
// try {
|
||||
// if (HOSTED_CAL_FEATURES) await addSeat(ctx.user.id, team.id, inviteeUserId);
|
||||
// } catch (e) {
|
||||
// console.log(e);
|
||||
// }
|
||||
if (IS_TEAM_BILLING_ENABLED) await updateQuantitySubscriptionFromStripe(input.teamId);
|
||||
}),
|
||||
acceptOrLeave: authedProcedure
|
||||
.input(
|
||||
@@ -392,10 +386,6 @@ export const viewerTeamsRouter = router({
|
||||
include: { team: true },
|
||||
});
|
||||
|
||||
// TODO: disable if not hosted by Cal
|
||||
// @TODO: Update with new logic
|
||||
// if (teamOwner) await removeSeat(teamOwner.userId, input.teamId, ctx.user.id);
|
||||
|
||||
const membership = await ctx.prisma.membership.delete({
|
||||
where: {
|
||||
userId_teamId: { userId: ctx.user.id, teamId: input.teamId },
|
||||
|
||||
Reference in New Issue
Block a user