From 52ad789e7a131a23074c4687908a28c30efb2f37 Mon Sep 17 00:00:00 2001 From: Etienne <45695613+etiennejouan@users.noreply.github.com> Date: Mon, 19 May 2025 13:37:18 +0200 Subject: [PATCH] fix billingCustomer stripeId fetching (#12116) ### Context Several 'Customer not found' errors arrived in Sentry, all coming from webhook-entitlement.service, at subscription creation (coinciding with customer creation 99% of the time). Stripe sends many events to update/create customer, subscription, entitlement, ... All these events are handle in parallel but customer.created stripe event arrived first and few seconds after subscription.created and entitlements.active_entitlement_summary.updated Issue happens at entitlements.active_entitlement_summary.updated handling. It checks for customer existence through subscription. But subscription can be not created yet at this moment. ### Solution Check directly for customer existence in billingCustomer table. Not sure it will fix the error because of the parallel handling of Stripe event, but should still be better. ### Tested - Workspace creation - Subscription upgrade (check for entitlement update) closes https://github.com/twentyhq/twenty/issues/11960 --- .../billing-webhook-entitlement.service.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/billing/webhooks/services/billing-webhook-entitlement.service.ts b/packages/twenty-server/src/engine/core-modules/billing/webhooks/services/billing-webhook-entitlement.service.ts index b6d37ea2b..000bf3316 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/webhooks/services/billing-webhook-entitlement.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/webhooks/services/billing-webhook-entitlement.service.ts @@ -1,6 +1,6 @@ /* @license Enterprise */ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import Stripe from 'stripe'; @@ -10,15 +10,14 @@ import { BillingException, BillingExceptionCode, } from 'src/engine/core-modules/billing/billing.exception'; +import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billing-customer.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 { transformStripeEntitlementUpdatedEventToDatabaseEntitlement } from 'src/engine/core-modules/billing/webhooks/utils/transform-stripe-entitlement-updated-event-to-database-entitlement.util'; @Injectable() export class BillingWebhookEntitlementService { - protected readonly logger = new Logger(BillingWebhookEntitlementService.name); constructor( - @InjectRepository(BillingSubscription, 'core') - private readonly billingSubscriptionRepository: Repository, + @InjectRepository(BillingCustomer, 'core') + private readonly billingCustomerRepository: Repository, @InjectRepository(BillingEntitlement, 'core') private readonly billingEntitlementRepository: Repository, ) {} @@ -26,19 +25,18 @@ export class BillingWebhookEntitlementService { async processStripeEvent( data: Stripe.EntitlementsActiveEntitlementSummaryUpdatedEvent.Data, ) { - const billingSubscription = - await this.billingSubscriptionRepository.findOne({ - where: { stripeCustomerId: data.object.customer }, - }); + const billingCustomer = await this.billingCustomerRepository.findOne({ + where: { stripeCustomerId: data.object.customer }, + }); - if (!billingSubscription) { + if (!billingCustomer) { throw new BillingException( 'Billing customer not found', BillingExceptionCode.BILLING_CUSTOMER_NOT_FOUND, ); } - const workspaceId = billingSubscription.workspaceId; + const workspaceId = billingCustomer.workspaceId; await this.billingEntitlementRepository.upsert( transformStripeEntitlementUpdatedEventToDatabaseEntitlement(