diff --git a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts index 62258d26f..24879a8aa 100644 --- a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts +++ b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts @@ -210,7 +210,7 @@ const testCases: { { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp }, - { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, diff --git a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts index 2ef0fa64e..95173056b 100644 --- a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts +++ b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts @@ -92,7 +92,6 @@ export const usePageChangeEffectNavigateLocation = () => { onboardingStatus === OnboardingStatus.WORKSPACE_ACTIVATION && !someMatchingLocationOf([ AppPath.CreateWorkspace, - AppPath.PlanRequiredSuccess, AppPath.BookCallDecision, AppPath.BookCall, ]) diff --git a/packages/twenty-front/src/modules/billing/hooks/useHandleCheckoutSession.ts b/packages/twenty-front/src/modules/billing/hooks/useHandleCheckoutSession.ts index fe9940350..a29301560 100644 --- a/packages/twenty-front/src/modules/billing/hooks/useHandleCheckoutSession.ts +++ b/packages/twenty-front/src/modules/billing/hooks/useHandleCheckoutSession.ts @@ -1,5 +1,4 @@ import { useRedirect } from '@/domain-manager/hooks/useRedirect'; -import { SettingsPath } from '@/types/SettingsPath'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; @@ -8,16 +7,17 @@ import { SubscriptionInterval, useCheckoutSessionMutation, } from '~/generated-metadata/graphql'; -import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; export const useHandleCheckoutSession = ({ recurringInterval, plan, requirePaymentMethod, + successUrlPath, }: { recurringInterval: SubscriptionInterval; plan: BillingPlanKey; requirePaymentMethod: boolean; + successUrlPath: string; }) => { const { redirect } = useRedirect(); @@ -32,7 +32,7 @@ export const useHandleCheckoutSession = ({ const { data } = await checkoutSession({ variables: { recurringInterval, - successUrlPath: getSettingsPath(SettingsPath.Billing), + successUrlPath, plan, requirePaymentMethod, }, diff --git a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx index a2a9c0f0c..3f7b6a19f 100644 --- a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx +++ b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx @@ -2,14 +2,17 @@ import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/billing/constants/Bill import { useHandleCheckoutSession } from '@/billing/hooks/useHandleCheckoutSession'; import { InformationBanner } from '@/information-banner/components/InformationBanner'; import { useSettingsPermissionMap } from '@/settings/roles/hooks/useSettingsPermissionMap'; +import { SettingsPath } from '@/types/SettingsPath'; import { t } from '@lingui/core/macro'; import { SettingPermissionType } from '~/generated-metadata/graphql'; +import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; export const InformationBannerNoBillingSubscription = () => { const { handleCheckoutSession, isSubmitting } = useHandleCheckoutSession({ recurringInterval: BILLING_CHECKOUT_SESSION_DEFAULT_VALUE.interval, plan: BILLING_CHECKOUT_SESSION_DEFAULT_VALUE.plan, requirePaymentMethod: true, + successUrlPath: getSettingsPath(SettingsPath.Billing), }); const { [SettingPermissionType.WORKSPACE]: hasPermissionToSubscribe } = diff --git a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx index 347511f5f..90101d8b2 100644 --- a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx +++ b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx @@ -158,6 +158,7 @@ export const ChooseYourPlan = () => { recurringInterval: billingCheckoutSession.interval, plan: billingCheckoutSession.plan, requirePaymentMethod: billingCheckoutSession.requirePaymentMethod, + successUrlPath: AppPath.PlanRequiredSuccess, }); const handleTrialPeriodChange = (withCreditCard: boolean) => { diff --git a/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts b/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts index 4e71d4c29..49dc8319c 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts @@ -1,10 +1,13 @@ /* @license Enterprise */ import { Injectable, Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import Stripe from 'stripe'; import { isDefined } from 'twenty-shared/utils'; +import { Repository } from 'typeorm'; +import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billing-customer.entity'; import { BillingPlanKey } from 'src/engine/core-modules/billing/enums/billing-plan-key.enum'; import { StripeSDKService } from 'src/engine/core-modules/billing/stripe/stripe-sdk/services/stripe-sdk.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; @@ -18,6 +21,8 @@ export class StripeCheckoutService { constructor( private readonly twentyConfigService: TwentyConfigService, private readonly stripeSDKService: StripeSDKService, + @InjectRepository(BillingCustomer, 'core') + private readonly billingCustomerRepository: Repository, ) { if (!this.twentyConfigService.get('IS_BILLING_ENABLED')) { return; @@ -56,6 +61,11 @@ export class StripeCheckoutService { }, }); + await this.billingCustomerRepository.save({ + stripeCustomerId: customer.id, + workspaceId, + }); + stripeCustomerId = customer.id; } diff --git a/packages/twenty-server/src/engine/core-modules/billing/stripe/stripe.module.ts b/packages/twenty-server/src/engine/core-modules/billing/stripe/stripe.module.ts index 8ccfcc018..43594738e 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/stripe/stripe.module.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/stripe/stripe.module.ts @@ -1,7 +1,9 @@ /* @license Enterprise */ import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billing-customer.entity'; import { StripeBillingMeterEventService } from 'src/engine/core-modules/billing/stripe/services/stripe-billing-meter-event.service'; import { StripeBillingMeterService } from 'src/engine/core-modules/billing/stripe/services/stripe-billing-meter.service'; import { StripeBillingPortalService } from 'src/engine/core-modules/billing/stripe/services/stripe-billing-portal.service'; @@ -16,7 +18,11 @@ import { StripeSDKModule } from 'src/engine/core-modules/billing/stripe/stripe-s import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module'; @Module({ - imports: [DomainManagerModule, StripeSDKModule], + imports: [ + DomainManagerModule, + StripeSDKModule, + TypeOrmModule.forFeature([BillingCustomer], 'core'), + ], providers: [ StripeSubscriptionItemService, StripeWebhookService,