add pr comment changes

This commit is contained in:
Ana Sofia Marin Alexandre 2024-11-21 13:50:31 +01:00
parent e701d1ac2e
commit 73bcb18e18
19 changed files with 73 additions and 38 deletions

View File

@ -10,7 +10,11 @@ import {
import { Response } from 'express'; import { Response } from 'express';
import { WebhookEvent } from 'src/engine/core-modules/billing/enums/webhook-events.enum'; import {
BillingException,
BillingExceptionCode,
} from 'src/engine/core-modules/billing/billing.exception';
import { WebhookEvent } from 'src/engine/core-modules/billing/enums/billing-webhook-events.enum';
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service'; import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
import { BillingWebhookService } from 'src/engine/core-modules/billing/services/billing-webhook.service'; import { BillingWebhookService } from 'src/engine/core-modules/billing/services/billing-webhook.service';
import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service';
@ -62,15 +66,20 @@ export class BillingController {
event.data, event.data,
); );
} }
if (event.type === WebhookEvent.CUSTOMER_ACTIVE_ENTITLEMENT) { if (
event.type === WebhookEvent.CUSTOMER_ACTIVE_ENTITLEMENT_SUMMARY_UPDATED
) {
try { try {
await this.billingWehbookService.processCustomerActiveEntitlement( await this.billingWehbookService.processCustomerActiveEntitlement(
event.data, event.data,
); );
} catch (error) { } catch (error) {
res.status(500).end(); if (
error instanceof BillingException &&
return; error.code === BillingExceptionCode.BILLING_CUSTOMER_NOT_FOUND
) {
res.status(404).end();
}
} }
} }
res.status(200).end(); res.status(200).end();

View File

@ -0,0 +1,14 @@
/* @license Enterprise */
import { CustomException } from 'src/utils/custom-exception';
export class BillingException extends CustomException {
code: BillingExceptionCode;
constructor(message: string, code: BillingExceptionCode) {
super(message, code);
}
}
export enum BillingExceptionCode {
BILLING_CUSTOMER_NOT_FOUND = 'BILLING_CUSTOMER_NOT_FOUND',
}

View File

@ -7,7 +7,7 @@ import { ProductPricesEntity } from 'src/engine/core-modules/billing/dto/product
import { ProductInput } from 'src/engine/core-modules/billing/dto/product.input'; import { ProductInput } from 'src/engine/core-modules/billing/dto/product.input';
import { SessionEntity } from 'src/engine/core-modules/billing/dto/session.entity'; import { SessionEntity } from 'src/engine/core-modules/billing/dto/session.entity';
import { UpdateBillingEntity } from 'src/engine/core-modules/billing/dto/update-billing.entity'; import { UpdateBillingEntity } from 'src/engine/core-modules/billing/dto/update-billing.entity';
import { AvailableProduct } from 'src/engine/core-modules/billing/enums/available-product.enum'; import { AvailableProduct } from 'src/engine/core-modules/billing/enums/billing-available-product.enum';
import { BillingPortalWorkspaceService } from 'src/engine/core-modules/billing/services/billing-portal.workspace-service'; import { BillingPortalWorkspaceService } from 'src/engine/core-modules/billing/services/billing-portal.workspace-service';
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service'; import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service';

View File

@ -3,7 +3,7 @@ import { ArgsType, Field } from '@nestjs/graphql';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/subcription-interval.enum'; import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
@ArgsType() @ArgsType()
export class CheckoutSessionInput { export class CheckoutSessionInput {

View File

@ -2,7 +2,7 @@ import { Field, ObjectType } from '@nestjs/graphql';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/subcription-interval.enum'; import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
@ObjectType() @ObjectType()
export class ProductPriceEntity { export class ProductPriceEntity {
@Field(() => SubscriptionInterval) @Field(() => SubscriptionInterval)

View File

@ -2,7 +2,7 @@ import { ArgsType, Field } from '@nestjs/graphql';
import { IsNotEmpty, IsString } from 'class-validator'; import { IsNotEmpty, IsString } from 'class-validator';
import { AvailableProduct } from 'src/engine/core-modules/billing/enums/available-product.enum'; import { AvailableProduct } from 'src/engine/core-modules/billing/enums/billing-available-product.enum';
@ArgsType() @ArgsType()
export class ProductInput { export class ProductInput {

View File

@ -14,7 +14,7 @@ import {
} from 'typeorm'; } from 'typeorm';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { FeatureStripeLookupKey } from 'src/engine/core-modules/billing/enums/feature-stripe-lookup-key.enum'; import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@Entity({ name: 'billingEntitlement', schema: 'core' }) @Entity({ name: 'billingEntitlement', schema: 'core' })
@ObjectType('billingEntitlement') @ObjectType('billingEntitlement')
@ -26,7 +26,7 @@ export class BillingEntitlement {
@Field(() => String) @Field(() => String)
@Column({ nullable: false, type: 'text' }) @Column({ nullable: false, type: 'text' })
key: FeatureStripeLookupKey; key: BillingEntitlementKey;
@Field() @Field()
@Column({ nullable: false, type: 'uuid' }) @Column({ nullable: false, type: 'uuid' })

View File

@ -16,8 +16,8 @@ import {
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity'; import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/subcription-interval.enum'; import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/subcription-status.enum'; import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
registerEnumType(SubscriptionStatus, { name: 'SubscriptionStatus' }); registerEnumType(SubscriptionStatus, { name: 'SubscriptionStatus' });

View File

@ -0,0 +1,3 @@
export enum BillingEntitlementKey {
SSO = 'sso_feat',
}

View File

@ -3,5 +3,5 @@ export enum WebhookEvent {
CUSTOMER_SUBSCRIPTION_UPDATED = 'customer.subscription.updated', CUSTOMER_SUBSCRIPTION_UPDATED = 'customer.subscription.updated',
CUSTOMER_SUBSCRIPTION_DELETED = 'customer.subscription.deleted', CUSTOMER_SUBSCRIPTION_DELETED = 'customer.subscription.deleted',
SETUP_INTENT_SUCCEEDED = 'setup_intent.succeeded', SETUP_INTENT_SUCCEEDED = 'setup_intent.succeeded',
CUSTOMER_ACTIVE_ENTITLEMENT = 'entitlements.active_entitlement_summary.updated', CUSTOMER_ACTIVE_ENTITLEMENT_SUMMARY_UPDATED = 'entitlements.active_entitlement_summary.updated',
} }

View File

@ -1,3 +0,0 @@
export enum FeatureStripeLookupKey {
SSO = 'sso_feat',
}

View File

@ -9,10 +9,10 @@ import { Not, Repository } from 'typeorm';
import { BillingEntitlement } from 'src/engine/core-modules/billing/entities/billing-entitlement.entity'; import { BillingEntitlement } from 'src/engine/core-modules/billing/entities/billing-entitlement.entity';
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { AvailableProduct } from 'src/engine/core-modules/billing/enums/available-product.enum'; import { AvailableProduct } from 'src/engine/core-modules/billing/enums/billing-available-product.enum';
import { FeatureStripeLookupKey } from 'src/engine/core-modules/billing/enums/feature-stripe-lookup-key.enum'; import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/subcription-interval.enum'; import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/subcription-status.enum'; import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum';
import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
@ -99,19 +99,19 @@ export class BillingSubscriptionService {
async getWorkspaceEntitlementByKey( async getWorkspaceEntitlementByKey(
workspaceId: string, workspaceId: string,
lookupKey: FeatureStripeLookupKey, key: BillingEntitlementKey,
) { ) {
const entitlement = await this.billingEntitlementRepository.findOneBy({ const entitlement = await this.billingEntitlementRepository.findOneBy({
workspaceId, workspaceId,
key: lookupKey, key,
value: true, value: true,
}); });
if (!entitlement?.value) { if (!entitlement) {
return false; return false;
} }
return true; return entitlement.value;
} }
async applyBillingSubscription(user: User) { async applyBillingSubscription(user: User) {

View File

@ -4,11 +4,15 @@ import { InjectRepository } from '@nestjs/typeorm';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import {
BillingException,
BillingExceptionCode,
} from 'src/engine/core-modules/billing/billing.exception';
import { BillingEntitlement } from 'src/engine/core-modules/billing/entities/billing-entitlement.entity'; import { BillingEntitlement } from 'src/engine/core-modules/billing/entities/billing-entitlement.entity';
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity'; import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { FeatureStripeLookupKey } from 'src/engine/core-modules/billing/enums/feature-stripe-lookup-key.enum'; import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/subcription-status.enum'; import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum';
import { import {
Workspace, Workspace,
WorkspaceActivationStatus, WorkspaceActivationStatus,
@ -103,22 +107,30 @@ export class BillingWebhookService {
data: Stripe.EntitlementsActiveEntitlementSummaryUpdatedEvent.Data, data: Stripe.EntitlementsActiveEntitlementSummaryUpdatedEvent.Data,
) { ) {
const billingSubscription = const billingSubscription =
await this.billingSubscriptionRepository.findOneOrFail({ await this.billingSubscriptionRepository.findOne({
where: { stripeCustomerId: data.object.customer }, where: { stripeCustomerId: data.object.customer },
}); });
if (!billingSubscription) {
throw new BillingException(
'Billing customer not found',
BillingExceptionCode.BILLING_CUSTOMER_NOT_FOUND,
);
}
const workspaceId = billingSubscription.workspaceId; const workspaceId = billingSubscription.workspaceId;
const stripeCustomerId = data.object.customer; const stripeCustomerId = data.object.customer;
const currentEntitlements = data.object.entitlements.data.map( const activeEntitlementsKeys = data.object.entitlements.data.map(
(item) => item.lookup_key, (entitlement) => entitlement.lookup_key,
); );
await this.billingEntitlementRepository.upsert( await this.billingEntitlementRepository.upsert(
Object.values(FeatureStripeLookupKey).map((key) => { Object.values(BillingEntitlementKey).map((key) => {
return { return {
workspaceId, workspaceId,
key, key,
value: currentEntitlements.includes(key), value: activeEntitlementsKeys.includes(key),
stripeCustomerId, stripeCustomerId,
}; };
}), }),

View File

@ -2,8 +2,8 @@ import { Injectable, Logger } from '@nestjs/common';
import { isDefined } from 'class-validator'; import { isDefined } from 'class-validator';
import { FeatureStripeLookupKey } from 'src/engine/core-modules/billing/enums/feature-stripe-lookup-key.enum'; import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/subcription-status.enum'; import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum';
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service'; import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; 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 { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
@ -56,7 +56,7 @@ export class BillingService {
async verifyWorkspaceEntitlement( async verifyWorkspaceEntitlement(
workspaceId: string, workspaceId: string,
entitlementKey: FeatureStripeLookupKey, entitlementKey: BillingEntitlementKey,
) { ) {
const isBillingEnabled = this.isBillingEnabled(); const isBillingEnabled = this.isBillingEnabled();

View File

@ -4,7 +4,7 @@ import Stripe from 'stripe';
import { ProductPriceEntity } from 'src/engine/core-modules/billing/dto/product-price.entity'; import { ProductPriceEntity } from 'src/engine/core-modules/billing/dto/product-price.entity';
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity'; import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
import { AvailableProduct } from 'src/engine/core-modules/billing/enums/available-product.enum'; import { AvailableProduct } from 'src/engine/core-modules/billing/enums/billing-available-product.enum';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { User } from 'src/engine/core-modules/user/user.entity'; import { User } from 'src/engine/core-modules/user/user.entity';

View File

@ -6,7 +6,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Issuer } from 'openid-client'; import { Issuer } from 'openid-client';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { FeatureStripeLookupKey } from 'src/engine/core-modules/billing/enums/feature-stripe-lookup-key.enum'; import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service'; import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; 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 { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
@ -30,7 +30,7 @@ import { User } from 'src/engine/core-modules/user/user.entity';
@Injectable() @Injectable()
export class SSOService { export class SSOService {
private readonly featureLookUpKey = 'sso_feat' as FeatureStripeLookupKey; private readonly featureLookUpKey = 'sso_feat' as BillingEntitlementKey;
constructor( constructor(
@InjectRepository(FeatureFlagEntity, 'core') @InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>, private readonly featureFlagRepository: Repository<FeatureFlagEntity>,