Handle missing Braintree customer in GetPaymentMethodQuery

This commit is contained in:
Alex Morask
2026-01-26 12:58:23 -06:00
parent 2a458807a5
commit a6c4f523b9
2 changed files with 51 additions and 6 deletions

View File

@@ -5,6 +5,7 @@ using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Entities;
using Braintree;
using Braintree.Exceptions;
using Microsoft.Extensions.Logging;
using Stripe;
@@ -35,14 +36,27 @@ public class GetPaymentMethodQuery(
// First check for PayPal
if (customer.Metadata.TryGetValue(StripeConstants.MetadataKeys.BraintreeCustomerId, out var braintreeCustomerId))
{
var braintreeCustomer = await braintreeGateway.Customer.FindAsync(braintreeCustomerId);
if (braintreeCustomer.DefaultPaymentMethod is PayPalAccount payPalAccount)
try
{
return new MaskedPayPalAccount { Email = payPalAccount.Email };
}
var braintreeCustomer = await braintreeGateway.Customer.FindAsync(braintreeCustomerId);
logger.LogWarning("Subscriber ({SubscriberID}) has a linked Braintree customer ({BraintreeCustomerId}) with no PayPal account.", subscriber.Id, braintreeCustomerId);
if (braintreeCustomer.DefaultPaymentMethod is PayPalAccount payPalAccount)
{
return new MaskedPayPalAccount { Email = payPalAccount.Email };
}
logger.LogWarning(
"Subscriber ({SubscriberID}) has a linked Braintree customer ({BraintreeCustomerId}) with no PayPal account.",
subscriber.Id,
braintreeCustomerId);
}
catch (NotFoundException)
{
logger.LogWarning(
"Subscriber ({SubscriberID}) is linked to a Braintree Customer ({BraintreeCustomerId}) that does not exist.",
subscriber.Id,
braintreeCustomerId);
}
return null;
}

View File

@@ -5,6 +5,7 @@ using Bit.Core.Billing.Payment.Queries;
using Bit.Core.Billing.Services;
using Bit.Core.Test.Billing.Extensions;
using Braintree;
using Braintree.Exceptions;
using Microsoft.Extensions.Logging;
using NSubstitute;
using NSubstitute.ReturnsExtensions;
@@ -344,4 +345,34 @@ public class GetPaymentMethodQueryTests
var maskedPayPalAccount = maskedPaymentMethod.AsT2;
Assert.Equal("user@gmail.com", maskedPayPalAccount.Email);
}
[Fact]
public async Task Run_BraintreeCustomerNotFound_ReturnsNull()
{
var organization = new Organization
{
Id = Guid.NewGuid()
};
var customer = new Customer
{
InvoiceSettings = new CustomerInvoiceSettings(),
Metadata = new Dictionary<string, string>
{
[MetadataKeys.BraintreeCustomerId] = "non_existent_braintree_customer_id"
}
};
_subscriberService.GetCustomer(organization,
Arg.Is<CustomerGetOptions>(options =>
options.HasExpansions("default_source", "invoice_settings.default_payment_method"))).Returns(customer);
var customerGateway = Substitute.For<ICustomerGateway>();
customerGateway.FindAsync("non_existent_braintree_customer_id").Returns<Braintree.Customer>(_ => throw new NotFoundException());
_braintreeGateway.Customer.Returns(customerGateway);
var maskedPaymentMethod = await _query.Run(organization);
Assert.Null(maskedPaymentMethod);
}
}