using Bit.Core.AdminConsole.Entities; using Bit.Core.Billing.Constants; using Bit.Core.Billing.Payment.Queries; using Bit.Core.Billing.Services; using Bit.Core.Test.Billing.Extensions; using NSubstitute; using NSubstitute.ReturnsExtensions; using Stripe; using Xunit; namespace Bit.Core.Test.Billing.Payment.Queries; using static StripeConstants; public class HasPaymentMethodQueryTests { private readonly IStripeAdapter _stripeAdapter = Substitute.For(); private readonly ISubscriberService _subscriberService = Substitute.For(); private readonly HasPaymentMethodQuery _query; public HasPaymentMethodQueryTests() { _query = new HasPaymentMethodQuery( _stripeAdapter, _subscriberService); } [Fact] public async Task Run_NoCustomer_ReturnsFalse() { var organization = new Organization { Id = Guid.NewGuid() }; _subscriberService.GetCustomer(organization).ReturnsNull(); var hasPaymentMethod = await _query.Run(organization); Assert.False(hasPaymentMethod); } [Fact] public async Task Run_NoPaymentMethod_ReturnsFalse() { var organization = new Organization { Id = Guid.NewGuid() }; var customer = new Customer { Id = "cus_123", InvoiceSettings = new CustomerInvoiceSettings(), Metadata = new Dictionary() }; _subscriberService.GetCustomer(organization).Returns(customer); var hasPaymentMethod = await _query.Run(organization); Assert.False(hasPaymentMethod); } [Fact] public async Task Run_HasDefaultPaymentMethodId_ReturnsTrue() { var organization = new Organization { Id = Guid.NewGuid() }; var customer = new Customer { Id = "cus_123", InvoiceSettings = new CustomerInvoiceSettings { DefaultPaymentMethodId = "pm_123" }, Metadata = new Dictionary() }; _subscriberService.GetCustomer(organization).Returns(customer); var hasPaymentMethod = await _query.Run(organization); Assert.True(hasPaymentMethod); } [Fact] public async Task Run_HasDefaultSourceId_ReturnsTrue() { var organization = new Organization { Id = Guid.NewGuid() }; var customer = new Customer { Id = "cus_123", DefaultSourceId = "card_123", InvoiceSettings = new CustomerInvoiceSettings(), Metadata = new Dictionary() }; _subscriberService.GetCustomer(organization).Returns(customer); var hasPaymentMethod = await _query.Run(organization); Assert.True(hasPaymentMethod); } [Fact] public async Task Run_HasUnverifiedBankAccount_ReturnsTrue() { var organization = new Organization { Id = Guid.NewGuid() }; var customer = new Customer { Id = "cus_123", InvoiceSettings = new CustomerInvoiceSettings(), Metadata = new Dictionary() }; _subscriberService.GetCustomer(organization).Returns(customer); _stripeAdapter .ListSetupIntentsAsync(Arg.Is(options => options.Customer == customer.Id && options.HasExpansions("data.payment_method"))) .Returns( [ new SetupIntent { Status = "requires_action", NextAction = new SetupIntentNextAction { VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits() }, PaymentMethod = new PaymentMethod { UsBankAccount = new PaymentMethodUsBankAccount() } } ]); var hasPaymentMethod = await _query.Run(organization); Assert.True(hasPaymentMethod); } [Fact] public async Task Run_HasBraintreeCustomerId_ReturnsTrue() { var organization = new Organization { Id = Guid.NewGuid() }; var customer = new Customer { Id = "cus_123", InvoiceSettings = new CustomerInvoiceSettings(), Metadata = new Dictionary { [MetadataKeys.BraintreeCustomerId] = "braintree_customer_id" } }; _subscriberService.GetCustomer(organization).Returns(customer); var hasPaymentMethod = await _query.Run(organization); Assert.True(hasPaymentMethod); } [Fact] public async Task Run_NoSetupIntents_ReturnsFalse() { var organization = new Organization { Id = Guid.NewGuid() }; var customer = new Customer { Id = "cus_123", InvoiceSettings = new CustomerInvoiceSettings(), Metadata = new Dictionary() }; _subscriberService.GetCustomer(organization).Returns(customer); _stripeAdapter .ListSetupIntentsAsync(Arg.Is(options => options.Customer == customer.Id && options.HasExpansions("data.payment_method"))) .Returns(new List()); var hasPaymentMethod = await _query.Run(organization); Assert.False(hasPaymentMethod); } [Fact] public async Task Run_SetupIntentNotBankAccount_ReturnsFalse() { var organization = new Organization { Id = Guid.NewGuid() }; var customer = new Customer { Id = "cus_123", InvoiceSettings = new CustomerInvoiceSettings(), Metadata = new Dictionary() }; _subscriberService.GetCustomer(organization).Returns(customer); _stripeAdapter .ListSetupIntentsAsync(Arg.Is(options => options.Customer == customer.Id && options.HasExpansions("data.payment_method"))) .Returns( [ new SetupIntent { PaymentMethod = new PaymentMethod { Type = "card" }, Status = "succeeded" } ]); var hasPaymentMethod = await _query.Run(organization); Assert.False(hasPaymentMethod); } }