chore(billing) - remove feature flag (#20531)
- remove feature flag - remove old enforce cap usage logic
This commit is contained in:
-21
@@ -16,7 +16,6 @@ import { type Response } from 'express';
|
||||
import Stripe from 'stripe';
|
||||
|
||||
import { BillingWebhookAlertService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-alert.service';
|
||||
import { BillingWebhookCreditGrantService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-credit-grant.service';
|
||||
import { BillingWebhookCustomerService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-customer.service';
|
||||
import { BillingWebhookEntitlementService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-entitlement.service';
|
||||
import { BillingWebhookInvoiceService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-invoice.service';
|
||||
@@ -51,7 +50,6 @@ export class BillingWebhookController {
|
||||
private readonly billingWebhookInvoiceService: BillingWebhookInvoiceService,
|
||||
private readonly billingWebhookCustomerService: BillingWebhookCustomerService,
|
||||
private readonly billingWebhookSubscriptionScheduleService: BillingWebhookSubscriptionScheduleService,
|
||||
private readonly billingWebhookCreditGrantService: BillingWebhookCreditGrantService,
|
||||
) {}
|
||||
|
||||
@Post(['webhooks/stripe'])
|
||||
@@ -154,25 +152,6 @@ export class BillingWebhookController {
|
||||
);
|
||||
}
|
||||
|
||||
case BillingWebhookEvent.CREDIT_GRANT_CREATED:
|
||||
case BillingWebhookEvent.CREDIT_GRANT_UPDATED: {
|
||||
const customer = event.data.object.customer;
|
||||
// customer can be string ID, Customer object, or DeletedCustomer object
|
||||
const stripeCustomerId =
|
||||
typeof customer === 'string' ? customer : customer?.id;
|
||||
|
||||
if (!stripeCustomerId) {
|
||||
throw new BillingException(
|
||||
'Customer ID is required for credit grant events',
|
||||
BillingExceptionCode.BILLING_CUSTOMER_EVENT_WORKSPACE_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return await this.billingWebhookCreditGrantService.processStripeEvent(
|
||||
stripeCustomerId,
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
||||
-2
@@ -4,7 +4,6 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
|
||||
import { BillingWebhookController } from 'src/engine/core-modules/billing-webhook/billing-webhook.controller';
|
||||
import { BillingWebhookAlertService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-alert.service';
|
||||
import { BillingWebhookCreditGrantService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-credit-grant.service';
|
||||
import { BillingWebhookCustomerService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-customer.service';
|
||||
import { BillingWebhookEntitlementService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-entitlement.service';
|
||||
import { BillingWebhookInvoiceService } from 'src/engine/core-modules/billing-webhook/services/billing-webhook-invoice.service';
|
||||
@@ -65,7 +64,6 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
|
||||
BillingWebhookSubscriptionService,
|
||||
BillingWebhookSubscriptionScheduleService,
|
||||
BillingWebhookEntitlementService,
|
||||
BillingWebhookCreditGrantService,
|
||||
],
|
||||
})
|
||||
export class BillingWebhookModule {}
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/* @license Enterprise */
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { BillingCustomerEntity } from 'src/engine/core-modules/billing/entities/billing-customer.entity';
|
||||
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
|
||||
import { MeteredCreditService } from 'src/engine/core-modules/billing/services/metered-credit.service';
|
||||
|
||||
@Injectable()
|
||||
export class BillingWebhookCreditGrantService {
|
||||
constructor(
|
||||
private readonly meteredCreditService: MeteredCreditService,
|
||||
private readonly billingSubscriptionService: BillingSubscriptionService,
|
||||
@InjectRepository(BillingCustomerEntity)
|
||||
private readonly billingCustomerRepository: Repository<BillingCustomerEntity>,
|
||||
) {}
|
||||
|
||||
async processStripeEvent(stripeCustomerId: string): Promise<void> {
|
||||
const subscription =
|
||||
await this.billingSubscriptionService.getCurrentBillingSubscription({
|
||||
stripeCustomerId,
|
||||
});
|
||||
|
||||
if (!isDefined(subscription)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const meteredPricingInfo =
|
||||
await this.meteredCreditService.getMeteredPricingInfo(subscription.id);
|
||||
|
||||
if (isDefined(meteredPricingInfo)) {
|
||||
const creditBalanceMicro =
|
||||
await this.meteredCreditService.getCreditBalance(
|
||||
stripeCustomerId,
|
||||
meteredPricingInfo.unitPriceCents,
|
||||
);
|
||||
|
||||
await this.billingCustomerRepository.update(
|
||||
{ stripeCustomerId },
|
||||
{ creditBalanceMicro },
|
||||
);
|
||||
}
|
||||
|
||||
await this.meteredCreditService.recreateBillingAlertForSubscription(
|
||||
subscription,
|
||||
);
|
||||
}
|
||||
}
|
||||
+8
-81
@@ -1,8 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { addMonths, addYears } from 'date-fns';
|
||||
import { FeatureFlagKey } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||
import { type Repository } from 'typeorm';
|
||||
@@ -19,13 +17,11 @@ import {
|
||||
import { BillingCustomerEntity } from 'src/engine/core-modules/billing/entities/billing-customer.entity';
|
||||
import { BillingSubscriptionItemEntity } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
||||
import { BillingSubscriptionEntity } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
|
||||
import { BillingWebhookEvent } from 'src/engine/core-modules/billing/enums/billing-webhook-events.enum';
|
||||
import { BillingCreditRolloverService } from 'src/engine/core-modules/billing/services/billing-credit-rollover.service';
|
||||
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
|
||||
import { MeteredCreditService } from 'src/engine/core-modules/billing/services/metered-credit.service';
|
||||
import { ResourceCreditService } from 'src/engine/core-modules/billing/services/resource-credit.service';
|
||||
import { StripeInvoiceService } from 'src/engine/core-modules/billing/stripe/services/stripe-invoice.service';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
const SUBSCRIPTION_CYCLE_BILLING_REASON = 'subscription_cycle';
|
||||
@@ -43,9 +39,8 @@ export class BillingWebhookInvoiceService {
|
||||
private readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
private readonly billingSubscriptionService: BillingSubscriptionService,
|
||||
private readonly billingCreditRolloverService: BillingCreditRolloverService,
|
||||
private readonly meteredCreditService: MeteredCreditService,
|
||||
private readonly resourceCreditService: ResourceCreditService,
|
||||
private readonly stripeInvoiceService: StripeInvoiceService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly auditService: AuditService,
|
||||
) {}
|
||||
|
||||
@@ -115,85 +110,28 @@ export class BillingWebhookInvoiceService {
|
||||
Math.abs(periodStart - trialEnd) <= TRIAL_END_TOLERANCE_SECONDS;
|
||||
|
||||
if (periodStart && !isFirstPeriodAfterTrial) {
|
||||
await this.processRollover(
|
||||
subscription,
|
||||
new Date(periodStart * 1000),
|
||||
new Date(periodEnd * 1000),
|
||||
);
|
||||
}
|
||||
|
||||
const isV2 = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_BILLING_V2_ENABLED,
|
||||
subscription.workspaceId,
|
||||
);
|
||||
|
||||
if (!isV2) {
|
||||
// Pass the new period start (which is the invoiced period's end) for alert threshold calculation
|
||||
await this.meteredCreditService.recreateBillingAlertForSubscription(
|
||||
subscription,
|
||||
new Date(periodEnd * 1000),
|
||||
);
|
||||
await this.processRollover(subscription, new Date(periodStart * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
private async processRollover(
|
||||
subscription: BillingSubscriptionEntity,
|
||||
invoicedPeriodStart: Date,
|
||||
invoicedPeriodEnd: Date,
|
||||
): Promise<void> {
|
||||
const isV2 = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_BILLING_V2_ENABLED,
|
||||
subscription.workspaceId,
|
||||
);
|
||||
|
||||
if (isV2) {
|
||||
const v2Params =
|
||||
await this.meteredCreditService.getResourceCreditRolloverParameters(
|
||||
subscription.id,
|
||||
);
|
||||
|
||||
if (!isDefined(v2Params)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.billingCreditRolloverService.processRolloverOnPeriodTransitionV2(
|
||||
{
|
||||
workspaceId: subscription.workspaceId,
|
||||
stripeCustomerId: subscription.stripeCustomerId,
|
||||
tierQuantity: v2Params.tierQuantity,
|
||||
previousPeriodStart: invoicedPeriodStart,
|
||||
},
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const rolloverParams =
|
||||
await this.meteredCreditService.getMeteredRolloverParameters(
|
||||
const params =
|
||||
await this.resourceCreditService.getResourceCreditRolloverParameters(
|
||||
subscription.id,
|
||||
);
|
||||
|
||||
if (!isDefined(rolloverParams)) {
|
||||
if (!isDefined(params)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The invoice covers the period that just ended (invoicedPeriodStart to invoicedPeriodEnd)
|
||||
// We need to calculate unused credits from this period and roll them over
|
||||
// Credits should expire at the end of the NEXT period
|
||||
const nextPeriodEnd = this.calculateNextPeriodEnd(
|
||||
invoicedPeriodEnd,
|
||||
subscription.interval,
|
||||
);
|
||||
|
||||
await this.billingCreditRolloverService.processRolloverOnPeriodTransition({
|
||||
workspaceId: subscription.workspaceId,
|
||||
stripeCustomerId: subscription.stripeCustomerId,
|
||||
subscriptionId: subscription.id,
|
||||
stripeMeterId: rolloverParams.stripeMeterId,
|
||||
tierQuantity: params.tierQuantity,
|
||||
previousPeriodStart: invoicedPeriodStart,
|
||||
previousPeriodEnd: invoicedPeriodEnd,
|
||||
newPeriodEnd: nextPeriodEnd,
|
||||
tierQuantity: rolloverParams.tierQuantity,
|
||||
unitPriceCents: rolloverParams.unitPriceCents,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -284,15 +222,4 @@ export class BillingWebhookInvoiceService {
|
||||
suspendedAt: new Date(),
|
||||
});
|
||||
}
|
||||
|
||||
private calculateNextPeriodEnd(
|
||||
periodEnd: Date,
|
||||
interval: SubscriptionInterval,
|
||||
): Date {
|
||||
if (interval === SubscriptionInterval.Year) {
|
||||
return addYears(periodEnd, 1);
|
||||
}
|
||||
|
||||
return addMonths(periodEnd, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user