From eeb19f8c80ca4cc3f474414414b889d9400f8210 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Mar 2026 19:47:47 +0000 Subject: [PATCH 1/2] Initial plan From 4cfe27e09a3bd239e81c4fb4fbd3674e731e1a26 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Mar 2026 20:00:22 +0000 Subject: [PATCH 2/2] Fix cancel subscription error by adding Stripe customer lookup fallback Co-authored-by: ardalis <782127+ardalis@users.noreply.github.com> --- ...StripePaymentHandlerSubscriptionService.cs | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/DevBetterWeb.Infrastructure/PaymentHandler/StripePaymentHandler/StripePaymentHandlerSubscriptionService.cs b/src/DevBetterWeb.Infrastructure/PaymentHandler/StripePaymentHandler/StripePaymentHandlerSubscriptionService.cs index 165e7e3f6..7eb53835b 100644 --- a/src/DevBetterWeb.Infrastructure/PaymentHandler/StripePaymentHandler/StripePaymentHandlerSubscriptionService.cs +++ b/src/DevBetterWeb.Infrastructure/PaymentHandler/StripePaymentHandler/StripePaymentHandlerSubscriptionService.cs @@ -14,16 +14,19 @@ namespace DevBetterWeb.Infrastructure.PaymentHandler.StripePaymentHandler; public class StripePaymentHandlerSubscriptionService : IPaymentHandlerSubscription { private readonly SubscriptionService _subscriptionService; + private readonly CustomerService _customerService; private readonly IPaymentHandlerSubscriptionCreationService _paymentHandlerSubscriptionCreationService; private readonly IRepository _invitationRepository; private readonly IAppLogger _logger; public StripePaymentHandlerSubscriptionService(SubscriptionService subscriptionService, + CustomerService customerService, IPaymentHandlerSubscriptionCreationService paymentHandlerSubscriptionCreationService, IRepository invitationRepository, IAppLogger logger) { _subscriptionService = subscriptionService; + _customerService = customerService; _paymentHandlerSubscriptionCreationService = paymentHandlerSubscriptionCreationService; _invitationRepository = invitationRepository; _logger = logger; @@ -31,17 +34,53 @@ public StripePaymentHandlerSubscriptionService(SubscriptionService subscriptionS public async Task CancelSubscriptionAtPeriodEnd(string customerEmail) { - var spec = new InactiveInvitationByEmailSpec(customerEmail); - var invite = await _invitationRepository.FirstOrDefaultAsync(spec); - if (invite is null) throw new InvitationNotFoundException(customerEmail); - var subscriptionId = invite.PaymentHandlerSubscriptionId; + var subscriptionId = await GetSubscriptionIdForEmailAsync(customerEmail); var subscriptionCancelOptions = new SubscriptionUpdateOptions { CancelAtPeriodEnd = true, }; - _subscriptionService.Update(subscriptionId, subscriptionCancelOptions); + await _subscriptionService.UpdateAsync(subscriptionId, subscriptionCancelOptions); + } + + private async Task GetSubscriptionIdForEmailAsync(string customerEmail) + { + var spec = new InactiveInvitationByEmailSpec(customerEmail); + var invite = await _invitationRepository.FirstOrDefaultAsync(spec); + + if (invite != null && !string.IsNullOrEmpty(invite.PaymentHandlerSubscriptionId)) + { + return invite.PaymentHandlerSubscriptionId; + } + + _logger.LogWarning($"No inactive invitation with a valid subscription ID found for {customerEmail}. Falling back to Stripe customer lookup."); + + var customerListOptions = new CustomerListOptions + { + Email = customerEmail.ToLower(), + Limit = 1, + }; + var customers = await _customerService.ListAsync(customerListOptions); + if (customers.Data.Count == 0) + { + throw new InvitationNotFoundException(customerEmail); + } + + var customerId = customers.Data[0].Id; + var subscriptionListOptions = new SubscriptionListOptions + { + Customer = customerId, + Status = "active", + Limit = 1, + }; + var subscriptions = await _subscriptionService.ListAsync(subscriptionListOptions); + if (subscriptions.Data.Count == 0) + { + throw new InvitationNotFoundException(customerEmail); + } + + return subscriptions.Data[0].Id; } public IPaymentHandlerSubscriptionDTO CreateSubscription(string customerId, string priceId, string paymentMethodId)