deprocate getProductPrices query in front end (#10397)
**TLDR:** Deprecate getProductPrices in the frontEnd and replace it with BillingBaseProductPrices. **In order to test:** - Have the environment variable IS_BILLING_ENABLED set to true and add the other required environment variables for Billing to work - Do a database reset (to ensure that the new feature flag is properly added and that the billing tables are created) - Run the command: npx nx run twenty-server:command billing:sync-plans-data (if you don't do that the products and prices will not be present in the database) - Run the server , the frontend, the worker, and the stripe listen command (stripe listen --forward-to http://localhost:3000/billing/webhooks) - Buy a subscription for acme workspace the choose your plan should be using the new front end endpoint
This commit is contained in:
committed by
GitHub
parent
e838dfc68b
commit
4d7e52ef25
@ -7,10 +7,8 @@ import { GraphQLError } from 'graphql';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
import { BillingCheckoutSessionInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-checkout-session.input';
|
||||
import { BillingProductInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-product.input';
|
||||
import { BillingSessionInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-session.input';
|
||||
import { BillingPlanOutput } from 'src/engine/core-modules/billing/dtos/outputs/billing-plan.output';
|
||||
import { BillingProductPricesOutput } from 'src/engine/core-modules/billing/dtos/outputs/billing-product-prices.output';
|
||||
import { BillingSessionOutput } from 'src/engine/core-modules/billing/dtos/outputs/billing-session.output';
|
||||
import { BillingUpdateOutput } from 'src/engine/core-modules/billing/dtos/outputs/billing-update.output';
|
||||
import { AvailableProduct } from 'src/engine/core-modules/billing/enums/billing-available-product.enum';
|
||||
@ -48,28 +46,13 @@ export class BillingResolver {
|
||||
constructor(
|
||||
private readonly billingSubscriptionService: BillingSubscriptionService,
|
||||
private readonly billingPortalWorkspaceService: BillingPortalWorkspaceService,
|
||||
private readonly stripePriceService: StripePriceService,
|
||||
private readonly billingPlanService: BillingPlanService,
|
||||
private readonly stripePriceService: StripePriceService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly billingService: BillingService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
) {}
|
||||
|
||||
@Query(() => BillingProductPricesOutput)
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
async getProductPrices(
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
@Args() { product }: BillingProductInput,
|
||||
) {
|
||||
const productPrices =
|
||||
await this.stripePriceService.getStripePrices(product);
|
||||
|
||||
return {
|
||||
totalNumberOfPrices: productPrices.length,
|
||||
productPrices,
|
||||
};
|
||||
}
|
||||
|
||||
@Query(() => BillingSessionOutput)
|
||||
@UseGuards(
|
||||
WorkspaceAuthGuard,
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
|
||||
import { BillingUsageType } from 'src/engine/core-modules/billing/enums/billing-usage-type.enum';
|
||||
|
||||
@ObjectType()
|
||||
export class BillingPriceLicensedDTO {
|
||||
@ -14,4 +15,7 @@ export class BillingPriceLicensedDTO {
|
||||
|
||||
@Field(() => String)
|
||||
stripePriceId: string;
|
||||
|
||||
@Field(() => BillingUsageType)
|
||||
priceUsageType: BillingUsageType.LICENSED;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import { Field, ObjectType } from '@nestjs/graphql';
|
||||
import { BillingPriceTierDTO } from 'src/engine/core-modules/billing/dtos/billing-price-tier.dto';
|
||||
import { BillingPriceTiersMode } from 'src/engine/core-modules/billing/enums/billing-price-tiers-mode.enum';
|
||||
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
|
||||
import { BillingUsageType } from 'src/engine/core-modules/billing/enums/billing-usage-type.enum';
|
||||
|
||||
@ObjectType()
|
||||
export class BillingPriceMeteredDTO {
|
||||
@ -19,4 +20,7 @@ export class BillingPriceMeteredDTO {
|
||||
|
||||
@Field(() => String)
|
||||
stripePriceId: string;
|
||||
|
||||
@Field(() => BillingUsageType)
|
||||
priceUsageType: BillingUsageType.METERED;
|
||||
}
|
||||
|
||||
@ -4,12 +4,12 @@ import { createUnionType } from '@nestjs/graphql';
|
||||
|
||||
import { BillingPriceLicensedDTO } from 'src/engine/core-modules/billing/dtos/billing-price-licensed.dto';
|
||||
import { BillingPriceMeteredDTO } from 'src/engine/core-modules/billing/dtos/billing-price-metered.dto';
|
||||
|
||||
import { BillingUsageType } from 'src/engine/core-modules/billing/enums/billing-usage-type.enum';
|
||||
export const BillingPriceUnionDTO = createUnionType({
|
||||
name: 'BillingPriceUnionDTO',
|
||||
types: () => [BillingPriceLicensedDTO, BillingPriceMeteredDTO],
|
||||
resolveType(value) {
|
||||
if ('unitAmount' in value) {
|
||||
if (value.priceUsageType === BillingUsageType.LICENSED) {
|
||||
return BillingPriceLicensedDTO;
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,6 @@ export class BillingProductDTO {
|
||||
@Field(() => BillingUsageType)
|
||||
type: BillingUsageType;
|
||||
|
||||
@Field(() => [BillingPriceUnionDTO], { nullable: 'items' })
|
||||
prices: Array<BillingPriceLicensedDTO | BillingPriceMeteredDTO>;
|
||||
@Field(() => [BillingPriceUnionDTO])
|
||||
prices: Array<BillingPriceLicensedDTO> | Array<BillingPriceMeteredDTO>;
|
||||
}
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
/* @license Enterprise */
|
||||
|
||||
import { Field, Int, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { BillingProductPriceDTO } from 'src/engine/core-modules/billing/dtos/billing-product-price.dto';
|
||||
|
||||
@ObjectType()
|
||||
export class BillingProductPricesOutput {
|
||||
@Field(() => Int)
|
||||
totalNumberOfPrices: number;
|
||||
|
||||
@Field(() => [BillingProductPriceDTO])
|
||||
productPrices: BillingProductPriceDTO[];
|
||||
}
|
||||
@ -85,7 +85,7 @@ export class BillingPlanService {
|
||||
|
||||
if (!baseProduct) {
|
||||
throw new BillingException(
|
||||
'Base product not found',
|
||||
'Base product not found, did you run the billing:sync-products command?',
|
||||
BillingExceptionCode.BILLING_PRODUCT_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ import { BillingProductService } from 'src/engine/core-modules/billing/services/
|
||||
import { StripePriceService } from 'src/engine/core-modules/billing/stripe/services/stripe-price.service';
|
||||
import { StripeSubscriptionItemService } from 'src/engine/core-modules/billing/stripe/services/stripe-subscription-item.service';
|
||||
import { StripeSubscriptionService } from 'src/engine/core-modules/billing/stripe/services/stripe-subscription.service';
|
||||
import { getPlanKeyFromSubscription } from 'src/engine/core-modules/billing/utils/get-plan-key-from-subscription.util';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
@ -176,8 +177,9 @@ export class BillingSubscriptionService {
|
||||
);
|
||||
|
||||
if (isBillingPlansEnabled) {
|
||||
const planKey = getPlanKeyFromSubscription(billingSubscription);
|
||||
const billingProductsByPlan =
|
||||
await this.billingProductService.getProductsByPlan(BillingPlanKey.PRO);
|
||||
await this.billingProductService.getProductsByPlan(planKey);
|
||||
const pricesPerPlanArray =
|
||||
this.billingProductService.getProductPricesByInterval({
|
||||
interval: newInterval,
|
||||
|
||||
@ -19,6 +19,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
interval: SubscriptionInterval.Month,
|
||||
unitAmount: 1000,
|
||||
stripePriceId: 'price_base1',
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -31,6 +32,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
interval: SubscriptionInterval.Year,
|
||||
unitAmount: 2000,
|
||||
stripePriceId: 'price_licensed1',
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -51,6 +53,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
},
|
||||
],
|
||||
stripePriceId: 'price_metered1',
|
||||
priceUsageType: BillingUsageType.METERED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -71,6 +74,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
interval: SubscriptionInterval.Month,
|
||||
unitAmount: 1000,
|
||||
stripePriceId: 'price_base1',
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
type: BillingUsageType.LICENSED,
|
||||
@ -79,6 +83,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
recurringInterval: SubscriptionInterval.Month,
|
||||
unitAmount: 1000,
|
||||
stripePriceId: 'price_base1',
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -91,6 +96,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
interval: SubscriptionInterval.Year,
|
||||
unitAmount: 2000,
|
||||
stripePriceId: 'price_licensed1',
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
type: BillingUsageType.LICENSED,
|
||||
@ -99,6 +105,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
recurringInterval: SubscriptionInterval.Year,
|
||||
unitAmount: 2000,
|
||||
stripePriceId: 'price_licensed1',
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -119,6 +126,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
},
|
||||
],
|
||||
stripePriceId: 'price_metered1',
|
||||
priceUsageType: BillingUsageType.METERED,
|
||||
},
|
||||
],
|
||||
type: BillingUsageType.METERED,
|
||||
@ -134,6 +142,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
],
|
||||
recurringInterval: SubscriptionInterval.Month,
|
||||
stripePriceId: 'price_metered1',
|
||||
priceUsageType: BillingUsageType.METERED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -152,6 +161,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
interval: null,
|
||||
unitAmount: null,
|
||||
stripePriceId: null,
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -166,6 +176,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
tiersMode: null,
|
||||
tiers: null,
|
||||
stripePriceId: null,
|
||||
priceUsageType: BillingUsageType.METERED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -186,6 +197,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
interval: null,
|
||||
unitAmount: null,
|
||||
stripePriceId: null,
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
type: BillingUsageType.LICENSED,
|
||||
@ -194,6 +206,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
recurringInterval: SubscriptionInterval.Month,
|
||||
unitAmount: 0,
|
||||
stripePriceId: null,
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -208,6 +221,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
tiersMode: null,
|
||||
tiers: null,
|
||||
stripePriceId: null,
|
||||
priceUsageType: BillingUsageType.METERED,
|
||||
},
|
||||
],
|
||||
type: BillingUsageType.METERED,
|
||||
@ -217,6 +231,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
|
||||
tiers: [],
|
||||
recurringInterval: SubscriptionInterval.Month,
|
||||
stripePriceId: null,
|
||||
priceUsageType: BillingUsageType.METERED,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -58,6 +58,7 @@ const formatBillingDatabasePriceToMeteredPriceDTO = (
|
||||
})) ?? [],
|
||||
recurringInterval: billingPrice?.interval ?? SubscriptionInterval.Month,
|
||||
stripePriceId: billingPrice?.stripePriceId,
|
||||
priceUsageType: BillingUsageType.METERED,
|
||||
};
|
||||
};
|
||||
|
||||
@ -68,5 +69,6 @@ const formatBillingDatabasePriceToLicensedPriceDTO = (
|
||||
recurringInterval: billingPrice?.interval ?? SubscriptionInterval.Month,
|
||||
unitAmount: billingPrice?.unitAmount ?? 0,
|
||||
stripePriceId: billingPrice?.stripePriceId,
|
||||
priceUsageType: BillingUsageType.LICENSED,
|
||||
};
|
||||
};
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||
import { BillingPlanKey } from 'src/engine/core-modules/billing/enums/billing-plan-key.enum';
|
||||
|
||||
export const getPlanKeyFromSubscription = (
|
||||
subscription: BillingSubscription,
|
||||
): BillingPlanKey => {
|
||||
const planKey = subscription.metadata?.planKey;
|
||||
|
||||
switch (planKey) {
|
||||
case 'PRO':
|
||||
return BillingPlanKey.PRO;
|
||||
case 'ENTERPRISE':
|
||||
return BillingPlanKey.ENTERPRISE;
|
||||
default:
|
||||
return BillingPlanKey.PRO;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user