fix: bill all events in BillingUsageService.billUsage() instead of only the first one (#16650)

## Summary

Fixes a bug where `BillingUsageService.billUsage()` only sent the first
event from the `billingEvents` array to Stripe, silently ignoring all
subsequent events.

## Bug Description

The `billUsage()` method accepts an array of `BillingUsageEvent[]` but
was only processing `billingEvents[0]`, causing:
- Customers to be undercharged for their usage
- Revenue loss due to unbilled events
- Incorrect usage tracking

## Fix

Changed the implementation to use `Promise.all()` to send all events in
the array concurrently to Stripe.

## Before
```typescript
await this.stripeBillingMeterEventService.sendBillingMeterEvent({
  eventName: billingEvents[0].eventName,  // Only first event
  value: billingEvents[0].value,
  stripeCustomerId: workspaceStripeCustomer.stripeCustomerId,
  dimensions: billingEvents[0].dimensions,
});
```

## After
```typescript
await Promise.all(
  billingEvents.map((event) =>
    this.stripeBillingMeterEventService.sendBillingMeterEvent({
      eventName: event.eventName,
      value: event.value,
      stripeCustomerId: workspaceStripeCustomer.stripeCustomerId,
      dimensions: event.dimensions,
    }),
  ),
);
```
This commit is contained in:
Félix Malfait
2025-12-18 08:38:15 +01:00
committed by GitHub
parent 4e15f7fe13
commit 6682d4eb02
@@ -67,12 +67,16 @@ export class BillingUsageService {
}
try {
await this.stripeBillingMeterEventService.sendBillingMeterEvent({
eventName: billingEvents[0].eventName,
value: billingEvents[0].value,
stripeCustomerId: workspaceStripeCustomer.stripeCustomerId,
dimensions: billingEvents[0].dimensions,
});
await Promise.all(
billingEvents.map((event) =>
this.stripeBillingMeterEventService.sendBillingMeterEvent({
eventName: event.eventName,
value: event.value,
stripeCustomerId: workspaceStripeCustomer.stripeCustomerId,
dimensions: event.dimensions,
}),
),
);
} catch (error) {
throw new BillingException(
`Failed to send billing meter events to Stripe: ${error}`,