Implement updateSubscription feature and refactor billing services

This commit introduces the updateSubscription method to the BillingStrategyProviderService, ensuring that subscriptions can be updated within the billing core. Additionally, a refactor has been applied to the BillingGatewayFactoryService and stripe-billing-strategy.service to improve error handling and the robustness of subscription updates. Logging in the webhook route has been adjusted for clarity and the data model has been enhanced.
This commit is contained in:
giancarlo
2024-04-04 20:15:12 +08:00
parent 4a122ee5df
commit 220a23e185
26 changed files with 1499 additions and 993 deletions

View File

@@ -9,6 +9,7 @@ import {
CreateBillingPortalSessionSchema,
ReportBillingUsageSchema,
RetrieveCheckoutSessionSchema,
UpdateSubscriptionParamsSchema,
} from '@kit/billing/schema';
import { Logger } from '@kit/shared/logger';
@@ -198,6 +199,52 @@ export class StripeBillingStrategyService
return { success: true };
}
async updateSubscription(
params: z.infer<typeof UpdateSubscriptionParamsSchema>,
) {
const stripe = await this.stripeProvider();
Logger.info(
{
name: 'billing.stripe',
...params,
},
'Updating subscription...',
);
try {
await stripe.subscriptions.update(params.subscriptionId, {
items: [
{
id: params.subscriptionItemId,
quantity: params.quantity,
},
],
});
Logger.info(
{
name: 'billing.stripe',
...params,
},
'Subscription updated successfully',
);
return { success: true };
} catch (e) {
Logger.error(
{
name: 'billing.stripe',
...params,
error: e,
},
'Failed to update subscription',
);
throw new Error('Failed to update subscription');
}
}
private async stripeProvider(): Promise<Stripe> {
return createStripeClient();
}

View File

@@ -1,6 +1,10 @@
import Stripe from 'stripe';
import { BillingWebhookHandlerService } from '@kit/billing';
import {
BillingConfig,
BillingWebhookHandlerService,
getLineItemTypeById,
} from '@kit/billing';
import { Logger } from '@kit/shared/logger';
import { Database } from '@kit/supabase/database';
@@ -18,6 +22,8 @@ export class StripeWebhookHandlerService
{
private stripe: Stripe | undefined;
constructor(private readonly config: BillingConfig) {}
private readonly provider: Database['public']['Enums']['billing_provider'] =
'stripe';
@@ -134,6 +140,8 @@ export class StripeWebhookHandlerService
const accountId = session.client_reference_id!;
const customerId = session.customer as string;
// if it's a subscription, we need to retrieve the subscription
// and build the payload for the subscription
if (isSubscription) {
const subscriptionId = session.subscription as string;
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
@@ -154,8 +162,10 @@ export class StripeWebhookHandlerService
return onCheckoutCompletedCallback(payload);
} else {
// if it's a one-time payment, we need to retrieve the session
const sessionId = event.data.object.id;
// from the session, we need to retrieve the line items
const sessionWithLineItems = await stripe.checkout.sessions.retrieve(
event.data.object.id,
{
@@ -280,6 +290,7 @@ export class StripeWebhookHandlerService
price_amount: item.price?.unit_amount,
interval: item.price?.recurring?.interval as string,
interval_count: item.price?.recurring?.interval_count as number,
type: getLineItemTypeById(this.config, item.id),
};
});