Files
calendar/apps/web/app/api/cron/downgradeUsers/route.ts
T
sean-brydonGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f4abbb2de1 feat: refactor billing to strategy implemention (#27828)
* factory and statergie

* chore: use correct method of DI

* feat: add onchagne

* add logic to HWM stat

* add webhook resolver methods to each statergy

* move seat tracking + webhooks over to own statergy

* Move to factory base approach

* move logic to correct class

* rename create -> createByTeamId

* fix: remove debug `true ||` overrides from IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED

Remove accidentally committed debug overrides that short-circuited
IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED to always be true,
bypassing Stripe credential checks. This would break self-hosted
instances without Stripe configured.

Identified by cubic (https://cubic.dev)

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 13:11:36 -03:00

57 lines
1.7 KiB
TypeScript

import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { z } from "zod";
import { getTeamBillingServiceFactory } from "@calcom/features/ee/billing/di/containers/Billing";
import prisma from "@calcom/prisma";
const querySchema = z.object({
page: z.coerce.number().min(0).optional().default(0),
});
async function postHandler(request: NextRequest) {
const apiKey = request.headers.get("authorization") || request.nextUrl.searchParams.get("apiKey");
if (process.env.CRON_API_KEY !== apiKey) {
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
}
const pageSize = 90; // Adjust this value based on the total number of teams and the available processing time
let { page: pageNumber } = querySchema.parse(Object.fromEntries(request.nextUrl.searchParams));
while (true) {
const teams = await prisma.team.findMany({
where: {
slug: {
not: null,
},
},
select: {
id: true,
metadata: true,
isOrganization: true,
parentId: true,
},
skip: pageNumber * pageSize,
take: pageSize,
});
if (teams.length === 0) {
break;
}
const teamBillingFactory = getTeamBillingServiceFactory();
const teamsBilling = teamBillingFactory.initMany(teams);
const teamBillingPromises = teamsBilling.map((teamBilling) => teamBilling.updateQuantity("sync"));
await Promise.allSettled(teamBillingPromises);
pageNumber++;
}
return NextResponse.json({ ok: true });
}
export const POST = defaultResponderForAppDir(postHandler);