diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts index 4be921b78c0..491faaec7e2 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts @@ -10,13 +10,19 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { BillingResolver } from 'src/engine/core-modules/billing/billing.resolver'; import { BillingWorkspaceMemberListener } from 'src/engine/core-modules/billing/listeners/billing-workspace-member.listener'; import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; @Module({ imports: [ StripeModule, UserWorkspaceModule, TypeOrmModule.forFeature( - [BillingSubscription, BillingSubscriptionItem, Workspace], + [ + BillingSubscription, + BillingSubscriptionItem, + Workspace, + FeatureFlagEntity, + ], 'core', ), ], diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts index 14de7386103..c3d475dba38 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts @@ -17,6 +17,10 @@ import { ProductPriceEntity } from 'src/engine/core-modules/billing/dto/product- import { User } from 'src/engine/core-modules/user/user.entity'; import { assert } from 'src/utils/assert'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; export enum AvailableProduct { BasePlan = 'base-plan', @@ -38,12 +42,26 @@ export class BillingService { private readonly environmentService: EnvironmentService, @InjectRepository(BillingSubscription, 'core') private readonly billingSubscriptionRepository: Repository, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository, @InjectRepository(BillingSubscriptionItem, 'core') private readonly billingSubscriptionItemRepository: Repository, @InjectRepository(Workspace, 'core') private readonly workspaceRepository: Repository, ) {} + async isBillingEnabledForWorkspace(workspaceId: string) { + const isFreeAccessEnabled = await this.featureFlagRepository.findOneBy({ + workspaceId, + key: FeatureFlagKeys.IsFreeAccessEnabled, + value: true, + }); + + return ( + !isFreeAccessEnabled && this.environmentService.get('IS_BILLING_ENABLED') + ); + } + getProductStripeId(product: AvailableProduct) { if (product === AvailableProduct.BasePlan) { return this.environmentService.get('BILLING_STRIPE_BASE_PLAN_PRODUCT_ID'); diff --git a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts index ae945d309b8..32f70758f4a 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts @@ -9,15 +9,15 @@ import { UpdateSubscriptionJob, UpdateSubscriptionJobData, } from 'src/engine/core-modules/billing/jobs/update-subscription.job'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { BillingService } from 'src/engine/core-modules/billing/billing.service'; @Injectable() export class BillingWorkspaceMemberListener { constructor( @InjectMessageQueue(MessageQueue.billingQueue) private readonly messageQueueService: MessageQueueService, - private readonly environmentService: EnvironmentService, + private readonly billingService: BillingService, ) {} @OnEvent('workspaceMember.created') @@ -25,7 +25,12 @@ export class BillingWorkspaceMemberListener { async handleCreateOrDeleteEvent( payload: ObjectRecordCreateEvent, ) { - if (!this.environmentService.get('IS_BILLING_ENABLED')) { + const isBillingEnabledForWorkspace = + await this.billingService.isBillingEnabledForWorkspace( + payload.workspaceId, + ); + + if (!isBillingEnabledForWorkspace) { return; } diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts index 782431984c2..a036cafee61 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts @@ -1,5 +1,4 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; import { OnboardingResolver } from 'src/engine/core-modules/onboarding/onboarding.resolver'; @@ -9,7 +8,6 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; -import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; @Module({ imports: [ @@ -19,7 +17,6 @@ import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature- KeyValuePairModule, EnvironmentModule, BillingModule, - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), ], exports: [OnboardingService], providers: [OnboardingService, OnboardingResolver], diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts index f4b8118507b..61fe5a14872 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts @@ -1,7 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Repository } from 'typeorm'; import { KeyValuePairService } from 'src/engine/core-modules/key-value-pair/key-value-pair.service'; import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum'; @@ -18,10 +15,6 @@ import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inje import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { SubscriptionStatus } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; import { isDefined } from 'src/utils/is-defined'; -import { - FeatureFlagEntity, - FeatureFlagKeys, -} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { BillingService } from 'src/engine/core-modules/billing/billing.service'; enum OnboardingStepValues { @@ -50,21 +43,15 @@ export class OnboardingService { private readonly connectedAccountRepository: ConnectedAccountRepository, @InjectWorkspaceRepository(WorkspaceMemberWorkspaceEntity) private readonly workspaceMemberRepository: WorkspaceRepository, - @InjectRepository(FeatureFlagEntity, 'core') - private readonly featureFlagRepository: Repository, ) {} private async isSubscriptionIncompleteOnboardingStatus(user: User) { - const isFreeAccessEnabled = await this.featureFlagRepository.findOneBy({ - workspaceId: user.defaultWorkspaceId, - key: FeatureFlagKeys.IsFreeAccessEnabled, - value: true, - }); + const isBillingEnabledForWorkspace = + await this.billingService.isBillingEnabledForWorkspace( + user.defaultWorkspaceId, + ); - if ( - isFreeAccessEnabled || - !this.environmentService.get('IS_BILLING_ENABLED') - ) { + if (!isBillingEnabledForWorkspace) { return false; }