diff --git a/.github/workflows/cron-downgradeUsers.yml b/.github/workflows/cron-downgradeUsers.yml index 8e3b9411b8..c4a782f0d5 100644 --- a/.github/workflows/cron-downgradeUsers.yml +++ b/.github/workflows/cron-downgradeUsers.yml @@ -1,11 +1,12 @@ name: Cron - downgradeUsers on: + workflow_dispatch: # "Scheduled workflows run on the latest commit on the default or base branch." # — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule schedule: - # Runs “At minute 0, 15, 30, and 45.” (see https://crontab.guru) - - cron: "0,15,30,45 * * * *" + # Runs “Every month at 1st (see https://crontab.guru) + - cron: "0 0 1 * *" jobs: cron-downgradeUsers: env: diff --git a/apps/web/pages/api/cron/downgradeUsers.ts b/apps/web/pages/api/cron/downgradeUsers.ts index 63f270e975..a0a7995176 100644 --- a/apps/web/pages/api/cron/downgradeUsers.ts +++ b/apps/web/pages/api/cron/downgradeUsers.ts @@ -1,5 +1,8 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import { updateQuantitySubscriptionFromStripe } from "@calcom/features/ee/teams/lib/payments"; +import prisma from "@calcom/prisma"; + export default async function handler(req: NextApiRequest, res: NextApiResponse) { const apiKey = req.headers.authorization || req.query.apiKey; if (process.env.CRON_API_KEY !== apiKey) { @@ -11,10 +14,35 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return; } - /** - * TODO: - * Remove this endpoint - */ + const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + const pageSize = 90; // Adjust this value based on the total number of teams and the available processing time + let pageNumber = 0; + + while (true) { + const teams = await prisma.team.findMany({ + where: { + slug: { + not: null, + }, + }, + select: { + id: true, + }, + skip: pageNumber * pageSize, + take: pageSize, + }); + + if (teams.length === 0) { + break; + } + + for (const team of teams) { + await updateQuantitySubscriptionFromStripe(team.id); + await delay(100); // Adjust the delay as needed to avoid rate limiting + } + + pageNumber++; + } res.json({ ok: true }); } diff --git a/packages/features/ee/teams/lib/payments.ts b/packages/features/ee/teams/lib/payments.ts index 6b2535c53b..d7197eab87 100644 --- a/packages/features/ee/teams/lib/payments.ts +++ b/packages/features/ee/teams/lib/payments.ts @@ -98,6 +98,9 @@ export const updateQuantitySubscriptionFromStripe = async (teamId: number) => { await stripe.subscriptions.update(subscriptionId, { items: [{ quantity: team.members.length, id: subscriptionItemId }], }); + console.info( + `Updated subscription ${subscriptionId} for team ${teamId} to ${team.members.length} seats.` + ); } catch (error) { let message = "Unknown error on updateQuantitySubscriptionFromStripe"; if (error instanceof Error) message = error.message;