Billing - Fix subscription_schedule release (#16669)

At subscription_schedule released, a subscription_schedule.update event
is received in webhook stripe controller but not handled. [Sentry event
example

](https://twenty-v7.sentry.io/issues/6606854024/events/e737c528a55048e5981756a4fad9028f/)

Payload example ⬇️ 
```
{
  "object": {
    "id": "sub_sched_1SfeABHDlIZyMfEDBhgJUCN2",
    "object": "subscription_schedule",
     ....
    "phases": [
      {
        "add_invoice_items": [],
        "application_fee_percent": null,
        "automatic_tax": {
          "disabled_reason": null,
          "enabled": false,
          "liability": null
        },
        "billing_cycle_anchor": null,
        "billing_thresholds": {
          "amount_gte": 10000,
          "reset_billing_cycle_anchor": false
        },
        "collection_method": "charge_automatically",
        "coupon": null,
        "currency": "usd",
        "default_payment_method": null,
        "default_tax_rates": [],
        "description": null,
        "discounts": [],
        "end_date": 1768731003,
        "invoice_settings": {
          "account_tax_ids": null,
          "days_until_due": null,
          "issuer": {
            "type": "self"
          }
        },
        "items": [
          {
            "billing_thresholds": null,
            "discounts": [],
            "metadata": {},
            "plan": "price_1SChAfHDlIZyMfEDCP3pGHHv",
            "price": "price_1SChAfHDlIZyMfEDCP3pGHHv",
            "quantity": 1,
            "tax_rates": []
          },
          {
            "billing_thresholds": null,
            "discounts": [],
            "metadata": {},
            "plan": "price_1SChAaHDlIZyMfEDkGCDIIjm",
            "price": "price_1SChAaHDlIZyMfEDkGCDIIjm",
            "tax_rates": []
          }
        ],
        "metadata": {},
        "on_behalf_of": null,
        "proration_behavior": "none",
        "start_date": 1766053422,
        "transfer_data": null,
        "trial_end": null
      }
    ],
    "released_at": 1768731003,
    "released_subscription": "sub_1Sfe0oHDlIZyMfEDs1lYui6v", // here !
    "subscription": null,
    "test_clock": "clock_1SfeT1HDlIZyMfEDNnlhPmOM"
  },
  "previous_attributes": {
    "released_subscription": null,
    "subscription": "sub_1Sfe0oHDlIZyMfEDs1lYui6v"
  }
}
```

related to https://github.com/twentyhq/twenty/issues/16573
This commit is contained in:
Etienne
2025-12-18 15:57:56 +01:00
committed by GitHub
parent 01ffca0cef
commit e93187fded
@@ -3,13 +3,13 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import Stripe from 'stripe';
import { isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { transformStripeSubscriptionScheduleEventToDatabaseSubscriptionPhase } from 'src/engine/core-modules/billing-webhook/utils/transform-stripe-subscription-schedule-event-to-database-subscription-phase.util';
import { BillingSubscriptionEntity } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { StripeSubscriptionScheduleService } from 'src/engine/core-modules/billing/stripe/services/stripe-subscription-schedule.service';
import { transformStripeSubscriptionScheduleEventToDatabaseSubscriptionPhase } from 'src/engine/core-modules/billing-webhook/utils/transform-stripe-subscription-schedule-event-to-database-subscription-phase.util';
@Injectable()
export class BillingWebhookSubscriptionScheduleService {
@@ -30,6 +30,24 @@ export class BillingWebhookSubscriptionScheduleService {
) {
const schedule = data.object as Stripe.SubscriptionSchedule;
if (
isDefined(schedule.released_subscription) &&
schedule.status === 'released'
) {
await this.billingSubscriptionRepository.update(
{ stripeSubscriptionId: schedule.released_subscription },
{
phases: [],
},
);
return {
stripeSubscriptionId: schedule.released_subscription,
phasesCount: 0,
scheduleId: schedule.id,
};
}
if (!isDefined(schedule.subscription)) {
throw new Error('Subscription is not defined');
}