1
0
mirror of https://github.com/bitwarden/server synced 2025-12-06 00:03:34 +00:00

[PM-21938] Fix: Invoice Payment Issues After Payment Method Updates (#6306)

* Resolve the unpaid issue after valid payment method is added

* Removed the draft status

* Remove draft from the logger msg
This commit is contained in:
cyprain-okeke
2025-09-11 16:04:05 +01:00
committed by GitHub
parent aab50ef5c4
commit c2cf290054
2 changed files with 11 additions and 54 deletions

View File

@@ -580,11 +580,6 @@ public class SubscriberService(
PaymentMethod = token
});
var getExistingSetupIntentsForCustomer = stripeAdapter.SetupIntentList(new SetupIntentListOptions
{
Customer = subscriber.GatewayCustomerId
});
// Find the setup intent for the incoming payment method token.
var setupIntentsForUpdatedPaymentMethod = await getSetupIntentsForUpdatedPaymentMethod;
@@ -597,24 +592,15 @@ public class SubscriberService(
var matchingSetupIntent = setupIntentsForUpdatedPaymentMethod.First();
// Find the customer's existing setup intents that should be canceled.
var existingSetupIntentsForCustomer = (await getExistingSetupIntentsForCustomer)
.Where(si =>
si.Status is "requires_payment_method" or "requires_confirmation" or "requires_action");
// Store the incoming payment method's setup intent ID in the cache for the subscriber so it can be verified later.
await setupIntentCache.Set(subscriber.Id, matchingSetupIntent.Id);
// Cancel the customer's other open setup intents.
var postProcessing = existingSetupIntentsForCustomer.Select(si =>
stripeAdapter.SetupIntentCancel(si.Id,
new SetupIntentCancelOptions { CancellationReason = "abandoned" })).ToList();
// Remove the customer's other attached Stripe payment methods.
postProcessing.Add(RemoveStripePaymentMethodsAsync(customer));
// Remove the customer's Braintree customer ID.
postProcessing.Add(RemoveBraintreeCustomerIdAsync(customer));
var postProcessing = new List<Task>
{
RemoveStripePaymentMethodsAsync(customer),
RemoveBraintreeCustomerIdAsync(customer)
};
await Task.WhenAll(postProcessing);
@@ -622,11 +608,6 @@ public class SubscriberService(
}
case PaymentMethodType.Card:
{
var getExistingSetupIntentsForCustomer = stripeAdapter.SetupIntentList(new SetupIntentListOptions
{
Customer = subscriber.GatewayCustomerId
});
// Remove the customer's other attached Stripe payment methods.
await RemoveStripePaymentMethodsAsync(customer);
@@ -634,16 +615,6 @@ public class SubscriberService(
await stripeAdapter.PaymentMethodAttachAsync(token,
new PaymentMethodAttachOptions { Customer = subscriber.GatewayCustomerId });
// Find the customer's existing setup intents that should be canceled.
var existingSetupIntentsForCustomer = (await getExistingSetupIntentsForCustomer)
.Where(si =>
si.Status is "requires_payment_method" or "requires_confirmation" or "requires_action");
// Cancel the customer's other open setup intents.
var postProcessing = existingSetupIntentsForCustomer.Select(si =>
stripeAdapter.SetupIntentCancel(si.Id,
new SetupIntentCancelOptions { CancellationReason = "abandoned" })).ToList();
var metadata = customer.Metadata;
if (metadata.TryGetValue(BraintreeCustomerIdKey, out var value))
@@ -653,16 +624,14 @@ public class SubscriberService(
}
// Set the customer's default payment method in Stripe and remove their Braintree customer ID.
postProcessing.Add(stripeAdapter.CustomerUpdateAsync(subscriber.GatewayCustomerId, new CustomerUpdateOptions
await stripeAdapter.CustomerUpdateAsync(subscriber.GatewayCustomerId, new CustomerUpdateOptions
{
InvoiceSettings = new CustomerInvoiceSettingsOptions
{
DefaultPaymentMethod = token
},
Metadata = metadata
}));
await Task.WhenAll(postProcessing);
});
break;
}

View File

@@ -1320,12 +1320,6 @@ public class SubscriberServiceTests
stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => options.PaymentMethod == "TOKEN"))
.Returns([matchingSetupIntent]);
stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => options.Customer == provider.GatewayCustomerId))
.Returns([
new SetupIntent { Id = "setup_intent_2", Status = "requires_payment_method" },
new SetupIntent { Id = "setup_intent_3", Status = "succeeded" }
]);
stripeAdapter.CustomerListPaymentMethods(provider.GatewayCustomerId).Returns([
new PaymentMethod { Id = "payment_method_1" }
]);
@@ -1335,8 +1329,8 @@ public class SubscriberServiceTests
await sutProvider.GetDependency<ISetupIntentCache>().Received(1).Set(provider.Id, "setup_intent_1");
await stripeAdapter.Received(1).SetupIntentCancel("setup_intent_2",
Arg.Is<SetupIntentCancelOptions>(options => options.CancellationReason == "abandoned"));
await stripeAdapter.DidNotReceive().SetupIntentCancel(Arg.Any<string>(),
Arg.Any<SetupIntentCancelOptions>());
await stripeAdapter.Received(1).PaymentMethodDetachAsync("payment_method_1");
@@ -1364,12 +1358,6 @@ public class SubscriberServiceTests
}
});
stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => options.Customer == provider.GatewayCustomerId))
.Returns([
new SetupIntent { Id = "setup_intent_2", Status = "requires_payment_method" },
new SetupIntent { Id = "setup_intent_3", Status = "succeeded" }
]);
stripeAdapter.CustomerListPaymentMethods(provider.GatewayCustomerId).Returns([
new PaymentMethod { Id = "payment_method_1" }
]);
@@ -1377,8 +1365,8 @@ public class SubscriberServiceTests
await sutProvider.Sut.UpdatePaymentSource(provider,
new TokenizedPaymentSource(PaymentMethodType.Card, "TOKEN"));
await stripeAdapter.Received(1).SetupIntentCancel("setup_intent_2",
Arg.Is<SetupIntentCancelOptions>(options => options.CancellationReason == "abandoned"));
await stripeAdapter.DidNotReceive().SetupIntentCancel(Arg.Any<string>(),
Arg.Any<SetupIntentCancelOptions>());
await stripeAdapter.Received(1).PaymentMethodDetachAsync("payment_method_1");