Handle membership updates in Stripe (#5992)

This commit is contained in:
Omar López
2022-12-13 12:43:37 +00:00
committed by GitHub
parent 68c7425922
commit da0bdfacae
2 changed files with 44 additions and 24 deletions
+40 -10
View File
@@ -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);
}
};
+4 -14
View File
@@ -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 },