diff --git a/backend/src/features/subscriptions/domain/subscriptions.service.ts b/backend/src/features/subscriptions/domain/subscriptions.service.ts index f36b562..2daf97b 100644 --- a/backend/src/features/subscriptions/domain/subscriptions.service.ts +++ b/backend/src/features/subscriptions/domain/subscriptions.service.ts @@ -570,11 +570,13 @@ export class SubscriptionsService { } // Update subscription with Stripe subscription ID + // Period dates moved from subscription to items in API 2025-03-31.basil + const item = stripeSubscription.items?.data?.[0]; await this.repository.update(subscription.id, { stripeSubscriptionId: stripeSubscription.id, status: this.mapStripeStatus(stripeSubscription.status), - currentPeriodStart: new Date(stripeSubscription.current_period_start * 1000), - currentPeriodEnd: new Date(stripeSubscription.current_period_end * 1000), + currentPeriodStart: new Date((item?.current_period_start ?? 0) * 1000), + currentPeriodEnd: new Date((item?.current_period_end ?? 0) * 1000), }); // Log event @@ -608,11 +610,13 @@ export class SubscriptionsService { const tier = this.determineTierFromStripeSubscription(stripeSubscription); // Update subscription + // Period dates moved from subscription to items in API 2025-03-31.basil + const item = stripeSubscription.items?.data?.[0]; const updateData: UpdateSubscriptionData = { status: this.mapStripeStatus(stripeSubscription.status), tier, - currentPeriodStart: new Date(stripeSubscription.current_period_start * 1000), - currentPeriodEnd: new Date(stripeSubscription.current_period_end * 1000), + currentPeriodStart: new Date((item?.current_period_start ?? 0) * 1000), + currentPeriodEnd: new Date((item?.current_period_end ?? 0) * 1000), cancelAtPeriodEnd: stripeSubscription.cancel_at_period_end || false, }; @@ -849,6 +853,7 @@ export class SubscriptionsService { switch (stripeStatus) { case 'active': case 'trialing': + case 'incomplete': return 'active'; case 'past_due': return 'past_due'; diff --git a/backend/src/features/subscriptions/external/stripe/stripe.client.ts b/backend/src/features/subscriptions/external/stripe/stripe.client.ts index 1105f1b..26fdb1f 100644 --- a/backend/src/features/subscriptions/external/stripe/stripe.client.ts +++ b/backend/src/features/subscriptions/external/stripe/stripe.client.ts @@ -86,7 +86,7 @@ export class StripeClient { const subscriptionParams: Stripe.SubscriptionCreateParams = { customer: customerId, items: [{ price: priceId }], - payment_behavior: 'default_incomplete', + payment_behavior: 'error_if_incomplete', payment_settings: { save_default_payment_method: 'on_subscription', }, @@ -101,13 +101,16 @@ export class StripeClient { logger.info('Stripe subscription created', { subscriptionId: subscription.id }); + // Period dates moved from subscription to items in API 2025-03-31.basil + const item = subscription.items?.data?.[0]; + return { id: subscription.id, customer: subscription.customer as string, status: subscription.status as StripeSubscription['status'], items: subscription.items, - currentPeriodStart: (subscription as any).current_period_start || 0, - currentPeriodEnd: (subscription as any).current_period_end || 0, + currentPeriodStart: item?.current_period_start ?? 0, + currentPeriodEnd: item?.current_period_end ?? 0, cancelAtPeriodEnd: subscription.cancel_at_period_end, canceledAt: subscription.canceled_at || undefined, created: subscription.created, @@ -148,13 +151,15 @@ export class StripeClient { logger.info('Stripe subscription canceled immediately', { subscriptionId }); } + const item = subscription.items?.data?.[0]; + return { id: subscription.id, customer: subscription.customer as string, status: subscription.status as StripeSubscription['status'], items: subscription.items, - currentPeriodStart: (subscription as any).current_period_start || 0, - currentPeriodEnd: (subscription as any).current_period_end || 0, + currentPeriodStart: item?.current_period_start ?? 0, + currentPeriodEnd: item?.current_period_end ?? 0, cancelAtPeriodEnd: subscription.cancel_at_period_end, canceledAt: subscription.canceled_at || undefined, created: subscription.created, @@ -294,14 +299,15 @@ export class StripeClient { logger.info('Retrieving Stripe subscription', { subscriptionId }); const subscription = await this.stripe.subscriptions.retrieve(subscriptionId); + const item = subscription.items?.data?.[0]; return { id: subscription.id, customer: subscription.customer as string, status: subscription.status as StripeSubscription['status'], items: subscription.items, - currentPeriodStart: (subscription as any).current_period_start || 0, - currentPeriodEnd: (subscription as any).current_period_end || 0, + currentPeriodStart: item?.current_period_start ?? 0, + currentPeriodEnd: item?.current_period_end ?? 0, cancelAtPeriodEnd: subscription.cancel_at_period_end, canceledAt: subscription.canceled_at || undefined, created: subscription.created,