Skip to content

Commit c60addc

Browse files
feat: add PlatformOrganizationBillingTasker with sync and trigger.dev versions (calcom#26803)
* feat: add PlatformOrganizationBillingTasker with sync and trigger.dev versions - Create PlatformOrganizationBillingTasker extending Tasker base class - Add sync tasker (PlatformOrganizationBillingSyncTasker) for synchronous execution - Add trigger.dev tasker (PlatformOrganizationBillingTriggerTasker) for async execution - Create trigger.dev task for incrementing subscription usage - Add PlatformOrganizationBillingTaskService with business logic - Add PlatformOrganizationBillingRepository for data access - Add createSubscriptionUsageRecord method to StripeBillingService - Follow BookingEmailAndSmsTasker pattern for consistency Co-Authored-By: morgan@cal.com <morgan@cal.com> * refactor: move repository methods per PR feedback - Move findPlatformOrgByUserId to OrganizationRepository - Create new PlatformBillingRepository for billing queries - Remove PlatformOrganizationBillingRepository (consolidated) - Update task service and trigger.dev task to use new repositories Co-Authored-By: morgan@cal.com <morgan@cal.com> * feat: add DI using @evyweb/ioctopus for platform billing tasker - Create di/tasker/ directory following BookingEmailAndSmsTasker pattern - Add tokens.ts with DI tokens for all billing tasker classes - Add module files for PlatformBillingRepository, TaskService, SyncTasker, TriggerTasker, Tasker - Add container files with getter functions - Update trigger.dev task to use DI container instead of manual instantiation Co-Authored-By: morgan@cal.com <morgan@cal.com> * refactor: add select statement to PlatformBillingRepository.findByTeamId Only select subscriptionId field since that's the only field used by the task service Co-Authored-By: morgan@cal.com <morgan@cal.com> * feat: add NestJS DI modules for platform billing tasker in API v2 - Add platform billing tasker exports to platform-libraries/organizations.ts - Export IBillingProviderService type from platform-libraries - Create StripeBillingProviderService wrapper implementing IBillingProviderService - Create PrismaPlatformBillingRepository extending PlatformBillingRepository - Create NestJS service wrappers for all platform billing tasker classes - Create PlatformBillingTaskerModule with all providers and exports - Update PlatformOrganizationBillingTaskService to use Pick<IBillingProviderService> Co-Authored-By: morgan@cal.com <morgan@cal.com> * feat: handle cancel and reschedule usage * fix: restore IsUserInBillingOrg to billing module providers Co-Authored-By: morgan@cal.com <morgan@cal.com> * chore: add idempotency key * fix: just log error] * fix: logger and typo * fix: address Cubic AI review feedback (high confidence issues) - Fix grammar error: 'Delayed task are' -> 'Delayed tasks are' in PlatformOrganizationBillingSyncTasker.ts (3 occurrences) - Re-throw error after logging in increment-usage.ts to enable trigger.dev retry mechanism Co-Authored-By: unknown <> * fix: remove duplicate code and use DI instead * fix: remove orThrow on find first in findPlatformOrgByUserId * refactor: prevent usage increment task from re-throwing errors --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 38a7fcf commit c60addc

38 files changed

Lines changed: 931 additions & 100 deletions

apps/api/v2/src/config/app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ const loadConfig = (): AppConfig => {
4747
e2e: getEnv("IS_E2E", "false") === "true",
4848
enableSlotsWorkers: getEnv("ENABLE_SLOTS_WORKERS", "true") === "true",
4949
slotsWorkerPoolSize: Number(getEnv("SLOTS_WORKER_POOL_SIZE", "4")),
50+
vercel: getEnv("VERCEL", "false") === "true",
51+
enableAsyncTasker: getEnv("ENABLE_ASYNC_TASKER", "false") === "true",
5052
};
5153
};
5254

apps/api/v2/src/config/type.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ export type AppConfig = {
3535
e2e: boolean;
3636
enableSlotsWorkers: boolean;
3737
slotsWorkerPoolSize: number;
38+
vercel: boolean;
39+
enableAsyncTasker: boolean;
3840
};

apps/api/v2/src/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export type Environment = {
4141
ENABLE_SLOTS_WORKERS: string;
4242
SLOTS_WORKER_POOL_SIZE: string;
4343
USE_POOL: string;
44+
VERCEL: string;
45+
ENABLE_ASYNC_TASKER: string;
4446
};
4547

4648
export const getEnv = <K extends keyof Environment>(key: K, fallback?: Environment[K]): Environment[K] => {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Module, Scope } from "@nestjs/common";
2+
import { Logger } from "@/lib/logger.bridge";
3+
import { PrismaPlatformBillingRepository } from "@/lib/repositories/prisma-platform-billing.repository";
4+
import { StripeBillingProviderService } from "@/lib/services/stripe-billing-provider.service";
5+
import { PlatformBillingSyncTaskerService } from "@/lib/services/tasker/platform-billing-sync-tasker.service";
6+
import { PlatformBillingTaskService } from "@/lib/services/tasker/platform-billing-task.service";
7+
import { PlatformBillingTasker } from "@/lib/services/tasker/platform-billing-tasker.service";
8+
import { PlatformBillingTriggerTaskerService } from "@/lib/services/tasker/platform-billing-trigger-tasker.service";
9+
import { OrganizationsModule } from "@/modules/organizations/organizations.module";
10+
import { PrismaModule } from "@/modules/prisma/prisma.module";
11+
import { StripeModule } from "@/modules/stripe/stripe.module";
12+
13+
@Module({
14+
imports: [PrismaModule, StripeModule, OrganizationsModule],
15+
providers: [
16+
PrismaPlatformBillingRepository,
17+
StripeBillingProviderService,
18+
{
19+
provide: Logger,
20+
useFactory: () => {
21+
return new Logger();
22+
},
23+
scope: Scope.TRANSIENT,
24+
},
25+
PlatformBillingTaskService,
26+
PlatformBillingSyncTaskerService,
27+
PlatformBillingTriggerTaskerService,
28+
PlatformBillingTasker,
29+
],
30+
exports: [PlatformBillingTasker],
31+
})
32+
export class PlatformBillingTaskerModule {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
2+
import { Injectable } from "@nestjs/common";
3+
4+
import { PlatformBillingRepository } from "@calcom/platform-libraries/organizations";
5+
import type { PrismaClient } from "@calcom/prisma";
6+
7+
@Injectable()
8+
export class PrismaPlatformBillingRepository extends PlatformBillingRepository {
9+
constructor(dbWrite: PrismaWriteService) {
10+
super(dbWrite.prisma as unknown as PrismaClient);
11+
}
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { StripeBillingService } from "@calcom/platform-libraries";
2+
import type { IBillingProviderService } from "@calcom/platform-libraries/organizations";
3+
import { Injectable } from "@nestjs/common";
4+
import { StripeService } from "@/modules/stripe/stripe.service";
5+
6+
@Injectable()
7+
export class StripeBillingProviderService
8+
extends StripeBillingService
9+
implements Pick<IBillingProviderService, "createSubscriptionUsageRecord">
10+
{
11+
constructor(readonly stripeService: StripeService) {
12+
super(stripeService.getStripe());
13+
}
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Logger } from "@/lib/logger.bridge";
2+
import { PlatformBillingTaskService } from "@/lib/services/tasker/platform-billing-task.service";
3+
import { Injectable } from "@nestjs/common";
4+
5+
import { PlatformOrganizationBillingSyncTasker as BasePlatformOrganizationBillingSyncTasker } from "@calcom/platform-libraries/organizations";
6+
7+
@Injectable()
8+
export class PlatformBillingSyncTaskerService extends BasePlatformOrganizationBillingSyncTasker {
9+
constructor(billingTaskService: PlatformBillingTaskService, logger: Logger) {
10+
super({
11+
logger,
12+
billingTaskService,
13+
});
14+
}
15+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Logger } from "@/lib/logger.bridge";
2+
import { PrismaPlatformBillingRepository } from "@/lib/repositories/prisma-platform-billing.repository";
3+
import { StripeBillingProviderService } from "@/lib/services/stripe-billing-provider.service";
4+
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
5+
import { Injectable } from "@nestjs/common";
6+
7+
import { PlatformOrganizationBillingTaskService as BasePlatformOrganizationBillingTaskService } from "@calcom/platform-libraries/organizations";
8+
9+
@Injectable()
10+
export class PlatformBillingTaskService extends BasePlatformOrganizationBillingTaskService {
11+
constructor(
12+
organizationRepository: OrganizationsRepository,
13+
platformBillingRepository: PrismaPlatformBillingRepository,
14+
billingProviderService: StripeBillingProviderService,
15+
logger: Logger
16+
) {
17+
super({
18+
logger,
19+
organizationRepository,
20+
platformBillingRepository,
21+
billingProviderService,
22+
});
23+
}
24+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { PlatformOrganizationBillingTasker as BasePlatformOrganizationBillingTasker } from "@calcom/platform-libraries/organizations";
2+
import { Injectable } from "@nestjs/common";
3+
import { Logger } from "@/lib/logger.bridge";
4+
import { PlatformBillingSyncTaskerService } from "@/lib/services/tasker/platform-billing-sync-tasker.service";
5+
import { PlatformBillingTriggerTaskerService } from "@/lib/services/tasker/platform-billing-trigger-tasker.service";
6+
7+
@Injectable()
8+
export class PlatformBillingTasker extends BasePlatformOrganizationBillingTasker {
9+
constructor(
10+
syncTasker: PlatformBillingSyncTaskerService,
11+
asyncTasker: PlatformBillingTriggerTaskerService,
12+
logger: Logger
13+
) {
14+
super({
15+
logger,
16+
asyncTasker: asyncTasker,
17+
syncTasker: syncTasker,
18+
});
19+
}
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Logger } from "@/lib/logger.bridge";
2+
import { Injectable } from "@nestjs/common";
3+
4+
import { PlatformOrganizationBillingTriggerTasker as BasePlatformOrganizationBillingTriggerTasker } from "@calcom/platform-libraries/organizations";
5+
6+
@Injectable()
7+
export class PlatformBillingTriggerTaskerService extends BasePlatformOrganizationBillingTriggerTasker {
8+
constructor(logger: Logger) {
9+
super({
10+
logger,
11+
});
12+
}
13+
}

0 commit comments

Comments
 (0)