1
0
mirror of https://github.com/bitwarden/server synced 2025-12-21 18:53:41 +00:00

[PM-24616] refactor stripe adapter (#6527)

* move billing services+tests to billing namespaces

* reorganized methods in file and added comment headers

* renamed StripeAdapter methods for better clarity

* clean up redundant qualifiers

* Upgrade Stripe.net to v48.4.0

* Update PreviewTaxAmountCommand

* Remove unused UpcomingInvoiceOptionExtensions

* Added SubscriptionExtensions with GetCurrentPeriodEnd

* Update PremiumUserBillingService

* Update OrganizationBillingService

* Update GetOrganizationWarningsQuery

* Update BillingHistoryInfo

* Update SubscriptionInfo

* Remove unused Sql Billing folder

* Update StripeAdapter

* Update StripePaymentService

* Update InvoiceCreatedHandler

* Update PaymentFailedHandler

* Update PaymentSucceededHandler

* Update ProviderEventService

* Update StripeEventUtilityService

* Update SubscriptionDeletedHandler

* Update SubscriptionUpdatedHandler

* Update UpcomingInvoiceHandler

* Update ProviderSubscriptionResponse

* Remove unused Stripe Subscriptions Admin Tool

* Update RemoveOrganizationFromProviderCommand

* Update ProviderBillingService

* Update RemoveOrganizatinoFromProviderCommandTests

* Update PreviewTaxAmountCommandTests

* Update GetCloudOrganizationLicenseQueryTests

* Update GetOrganizationWarningsQueryTests

* Update StripePaymentServiceTests

* Update ProviderBillingControllerTests

* Update ProviderEventServiceTests

* Update SubscriptionDeletedHandlerTests

* Update SubscriptionUpdatedHandlerTests

* Resolve Billing test failures

I completely removed tests for the StripeEventService as they were using a system I setup a while back that read JSON files of the Stripe event structure. I did not anticipate how frequently these structures would change with each API version and the cost of trying to update these specific JSON files to test a very static data retrieval service far outweigh the benefit.

* Resolve Core test failures

* Run dotnet format

* Remove unused provider migration

* Fixed failing tests

* Run dotnet format

* Replace the old webhook secret key with new one (#6223)

* Fix compilation failures in additions

* Run dotnet format

* Bump Stripe API version

* Fix recent addition: CreatePremiumCloudHostedSubscriptionCommand

* Fix new code in main according to Stripe update

* Fix InvoiceExtensions

* Bump SDK version to match API Version

* cleanup

* fixing items missed after the merge

* use expression body for all simple returns

* forgot fixes, format, and pr feedback

* claude pr feedback

* pr feedback and cleanup

* more claude feedback

---------

Co-authored-by: Alex Morask <amorask@bitwarden.com>
Co-authored-by: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com>
This commit is contained in:
Kyle Denney
2025-12-12 15:32:43 -06:00
committed by GitHub
parent 196e555116
commit 99e1326039
100 changed files with 941 additions and 1016 deletions

1
.gitignore vendored
View File

@@ -234,6 +234,7 @@ bitwarden_license/src/Sso/Sso.zip
/identity.json /identity.json
/api.json /api.json
/api.public.json /api.public.json
.serena/
# Serena # Serena
.serena/ .serena/

View File

@@ -113,7 +113,7 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
await _providerBillingService.CreateCustomerForClientOrganization(provider, organization); await _providerBillingService.CreateCustomerForClientOrganization(provider, organization);
} }
var customer = await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, new CustomerUpdateOptions var customer = await _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, new CustomerUpdateOptions
{ {
Description = string.Empty, Description = string.Empty,
Email = organization.BillingEmail, Email = organization.BillingEmail,
@@ -138,7 +138,7 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
subscriptionCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }; subscriptionCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
var subscription = await _stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions); var subscription = await _stripeAdapter.CreateSubscriptionAsync(subscriptionCreateOptions);
organization.GatewaySubscriptionId = subscription.Id; organization.GatewaySubscriptionId = subscription.Id;
organization.Status = OrganizationStatusType.Created; organization.Status = OrganizationStatusType.Created;
@@ -148,27 +148,26 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
} }
else if (organization.IsStripeEnabled()) else if (organization.IsStripeEnabled())
{ {
var subscription = await _stripeAdapter.SubscriptionGetAsync(organization.GatewaySubscriptionId, new SubscriptionGetOptions var subscription = await _stripeAdapter.GetSubscriptionAsync(organization.GatewaySubscriptionId, new SubscriptionGetOptions
{ {
Expand = ["customer"] Expand = ["customer"]
}); });
if (subscription.Status is StripeConstants.SubscriptionStatus.Canceled or StripeConstants.SubscriptionStatus.IncompleteExpired) if (subscription.Status is StripeConstants.SubscriptionStatus.Canceled or StripeConstants.SubscriptionStatus.IncompleteExpired)
{ {
return; return;
} }
await _stripeAdapter.CustomerUpdateAsync(subscription.CustomerId, new CustomerUpdateOptions await _stripeAdapter.UpdateCustomerAsync(subscription.CustomerId, new CustomerUpdateOptions
{ {
Email = organization.BillingEmail Email = organization.BillingEmail
}); });
if (subscription.Customer.Discount?.Coupon != null) if (subscription.Customer.Discount?.Coupon != null)
{ {
await _stripeAdapter.CustomerDeleteDiscountAsync(subscription.CustomerId); await _stripeAdapter.DeleteCustomerDiscountAsync(subscription.CustomerId);
} }
await _stripeAdapter.SubscriptionUpdateAsync(organization.GatewaySubscriptionId, new SubscriptionUpdateOptions await _stripeAdapter.UpdateSubscriptionAsync(organization.GatewaySubscriptionId, new SubscriptionUpdateOptions
{ {
CollectionMethod = StripeConstants.CollectionMethod.SendInvoice, CollectionMethod = StripeConstants.CollectionMethod.SendInvoice,
DaysUntilDue = 30, DaysUntilDue = 30,

View File

@@ -15,6 +15,7 @@ using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Providers.Services; using Bit.Core.Billing.Providers.Services;
using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@@ -427,7 +428,7 @@ public class ProviderService : IProviderService
if (!string.IsNullOrEmpty(organization.GatewayCustomerId)) if (!string.IsNullOrEmpty(organization.GatewayCustomerId))
{ {
await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, new CustomerUpdateOptions await _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, new CustomerUpdateOptions
{ {
Email = provider.BillingEmail Email = provider.BillingEmail
}); });
@@ -487,7 +488,7 @@ public class ProviderService : IProviderService
private async Task<SubscriptionItem> GetSubscriptionItemAsync(string subscriptionId, string oldPlanId) private async Task<SubscriptionItem> GetSubscriptionItemAsync(string subscriptionId, string oldPlanId)
{ {
var subscriptionDetails = await _stripeAdapter.SubscriptionGetAsync(subscriptionId); var subscriptionDetails = await _stripeAdapter.GetSubscriptionAsync(subscriptionId);
return subscriptionDetails.Items.Data.FirstOrDefault(item => item.Price.Id == oldPlanId); return subscriptionDetails.Items.Data.FirstOrDefault(item => item.Price.Id == oldPlanId);
} }
@@ -497,7 +498,7 @@ public class ProviderService : IProviderService
{ {
if (subscriptionItem.Price.Id != extractedPlanType) if (subscriptionItem.Price.Id != extractedPlanType)
{ {
await _stripeAdapter.SubscriptionUpdateAsync(subscriptionItem.Subscription, await _stripeAdapter.UpdateSubscriptionAsync(subscriptionItem.Subscription,
new Stripe.SubscriptionUpdateOptions new Stripe.SubscriptionUpdateOptions
{ {
Items = new List<Stripe.SubscriptionItemOptions> Items = new List<Stripe.SubscriptionItemOptions>

View File

@@ -4,7 +4,6 @@ using Bit.Core.Billing.Providers.Models;
using Bit.Core.Billing.Providers.Queries; using Bit.Core.Billing.Providers.Queries;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Services;
using Stripe; using Stripe;
using Stripe.Tax; using Stripe.Tax;
@@ -76,8 +75,8 @@ public class GetProviderWarningsQuery(
// Get active and scheduled registrations // Get active and scheduled registrations
var registrations = (await Task.WhenAll( var registrations = (await Task.WhenAll(
stripeAdapter.TaxRegistrationsListAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Active }), stripeAdapter.ListTaxRegistrationsAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Active }),
stripeAdapter.TaxRegistrationsListAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Scheduled }))) stripeAdapter.ListTaxRegistrationsAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Scheduled })))
.SelectMany(registrations => registrations.Data); .SelectMany(registrations => registrations.Data);
// Find the matching registration for the customer // Find the matching registration for the customer

View File

@@ -101,7 +101,7 @@ public class BusinessUnitConverter(
providerUser.Status = ProviderUserStatusType.Confirmed; providerUser.Status = ProviderUserStatusType.Confirmed;
// Stripe requires that we clear all the custom fields from the invoice settings if we want to replace them. // Stripe requires that we clear all the custom fields from the invoice settings if we want to replace them.
await stripeAdapter.CustomerUpdateAsync(subscription.CustomerId, new CustomerUpdateOptions await stripeAdapter.UpdateCustomerAsync(subscription.CustomerId, new CustomerUpdateOptions
{ {
InvoiceSettings = new CustomerInvoiceSettingsOptions InvoiceSettings = new CustomerInvoiceSettingsOptions
{ {
@@ -116,7 +116,7 @@ public class BusinessUnitConverter(
["convertedFrom"] = organization.Id.ToString() ["convertedFrom"] = organization.Id.ToString()
}; };
var updateCustomer = stripeAdapter.CustomerUpdateAsync(subscription.CustomerId, new CustomerUpdateOptions var updateCustomer = stripeAdapter.UpdateCustomerAsync(subscription.CustomerId, new CustomerUpdateOptions
{ {
InvoiceSettings = new CustomerInvoiceSettingsOptions InvoiceSettings = new CustomerInvoiceSettingsOptions
{ {
@@ -148,7 +148,7 @@ public class BusinessUnitConverter(
// Replace the existing password manager price with the new business unit price. // Replace the existing password manager price with the new business unit price.
var updateSubscription = var updateSubscription =
stripeAdapter.SubscriptionUpdateAsync(subscription.Id, stripeAdapter.UpdateSubscriptionAsync(subscription.Id,
new SubscriptionUpdateOptions new SubscriptionUpdateOptions
{ {
Items = [ Items = [

View File

@@ -61,11 +61,11 @@ public class ProviderBillingService(
Organization organization, Organization organization,
string key) string key)
{ {
await stripeAdapter.SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await stripeAdapter.UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
new SubscriptionUpdateOptions { CancelAtPeriodEnd = false }); new SubscriptionUpdateOptions { CancelAtPeriodEnd = false });
var subscription = var subscription =
await stripeAdapter.SubscriptionCancelAsync(organization.GatewaySubscriptionId, await stripeAdapter.CancelSubscriptionAsync(organization.GatewaySubscriptionId,
new SubscriptionCancelOptions new SubscriptionCancelOptions
{ {
CancellationDetails = new SubscriptionCancellationDetailsOptions CancellationDetails = new SubscriptionCancellationDetailsOptions
@@ -83,7 +83,7 @@ public class ProviderBillingService(
if (!wasTrialing && subscription.LatestInvoice.Status == InvoiceStatus.Draft) if (!wasTrialing && subscription.LatestInvoice.Status == InvoiceStatus.Draft)
{ {
await stripeAdapter.InvoiceFinalizeInvoiceAsync(subscription.LatestInvoiceId, await stripeAdapter.FinalizeInvoiceAsync(subscription.LatestInvoiceId,
new InvoiceFinalizeOptions { AutoAdvance = true }); new InvoiceFinalizeOptions { AutoAdvance = true });
} }
@@ -138,7 +138,7 @@ public class ProviderBillingService(
if (clientCustomer.Balance != 0) if (clientCustomer.Balance != 0)
{ {
await stripeAdapter.CustomerBalanceTransactionCreate(provider.GatewayCustomerId, await stripeAdapter.CreateCustomerBalanceTransactionAsync(provider.GatewayCustomerId,
new CustomerBalanceTransactionCreateOptions new CustomerBalanceTransactionCreateOptions
{ {
Amount = clientCustomer.Balance, Amount = clientCustomer.Balance,
@@ -187,7 +187,7 @@ public class ProviderBillingService(
] ]
}; };
await stripeAdapter.SubscriptionUpdateAsync(provider.GatewaySubscriptionId, updateOptions); await stripeAdapter.UpdateSubscriptionAsync(provider.GatewaySubscriptionId, updateOptions);
// Refactor later to ?ChangeClientPlanCommand? (ProviderPlanId, ProviderId, OrganizationId) // Refactor later to ?ChangeClientPlanCommand? (ProviderPlanId, ProviderId, OrganizationId)
// 1. Retrieve PlanType and PlanName for ProviderPlan // 1. Retrieve PlanType and PlanName for ProviderPlan
@@ -275,7 +275,7 @@ public class ProviderBillingService(
customerCreateOptions.TaxExempt = TaxExempt.Reverse; customerCreateOptions.TaxExempt = TaxExempt.Reverse;
} }
var customer = await stripeAdapter.CustomerCreateAsync(customerCreateOptions); var customer = await stripeAdapter.CreateCustomerAsync(customerCreateOptions);
organization.GatewayCustomerId = customer.Id; organization.GatewayCustomerId = customer.Id;
@@ -525,7 +525,7 @@ public class ProviderBillingService(
case TokenizablePaymentMethodType.BankAccount: case TokenizablePaymentMethodType.BankAccount:
{ {
var setupIntent = var setupIntent =
(await stripeAdapter.SetupIntentList(new SetupIntentListOptions (await stripeAdapter.ListSetupIntentsAsync(new SetupIntentListOptions
{ {
PaymentMethod = paymentMethod.Token PaymentMethod = paymentMethod.Token
})) }))
@@ -558,7 +558,7 @@ public class ProviderBillingService(
try try
{ {
return await stripeAdapter.CustomerCreateAsync(options); return await stripeAdapter.CreateCustomerAsync(options);
} }
catch (StripeException stripeException) when (stripeException.StripeError?.Code == ErrorCodes.TaxIdInvalid) catch (StripeException stripeException) when (stripeException.StripeError?.Code == ErrorCodes.TaxIdInvalid)
{ {
@@ -580,7 +580,7 @@ public class ProviderBillingService(
case TokenizablePaymentMethodType.BankAccount: case TokenizablePaymentMethodType.BankAccount:
{ {
var setupIntentId = await setupIntentCache.GetSetupIntentIdForSubscriber(provider.Id); var setupIntentId = await setupIntentCache.GetSetupIntentIdForSubscriber(provider.Id);
await stripeAdapter.SetupIntentCancel(setupIntentId, await stripeAdapter.CancelSetupIntentAsync(setupIntentId,
new SetupIntentCancelOptions { CancellationReason = "abandoned" }); new SetupIntentCancelOptions { CancellationReason = "abandoned" });
await setupIntentCache.RemoveSetupIntentForSubscriber(provider.Id); await setupIntentCache.RemoveSetupIntentForSubscriber(provider.Id);
break; break;
@@ -638,7 +638,7 @@ public class ProviderBillingService(
var setupIntentId = await setupIntentCache.GetSetupIntentIdForSubscriber(provider.Id); var setupIntentId = await setupIntentCache.GetSetupIntentIdForSubscriber(provider.Id);
var setupIntent = !string.IsNullOrEmpty(setupIntentId) var setupIntent = !string.IsNullOrEmpty(setupIntentId)
? await stripeAdapter.SetupIntentGet(setupIntentId, ? await stripeAdapter.GetSetupIntentAsync(setupIntentId,
new SetupIntentGetOptions { Expand = ["payment_method"] }) new SetupIntentGetOptions { Expand = ["payment_method"] })
: null; : null;
@@ -673,7 +673,7 @@ public class ProviderBillingService(
try try
{ {
var subscription = await stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions); var subscription = await stripeAdapter.CreateSubscriptionAsync(subscriptionCreateOptions);
if (subscription is if (subscription is
{ {
@@ -708,7 +708,7 @@ public class ProviderBillingService(
subscriberService.UpdatePaymentSource(provider, tokenizedPaymentSource), subscriberService.UpdatePaymentSource(provider, tokenizedPaymentSource),
subscriberService.UpdateTaxInformation(provider, taxInformation)); subscriberService.UpdateTaxInformation(provider, taxInformation));
await stripeAdapter.SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
new SubscriptionUpdateOptions { CollectionMethod = CollectionMethod.ChargeAutomatically }); new SubscriptionUpdateOptions { CollectionMethod = CollectionMethod.ChargeAutomatically });
} }
@@ -791,7 +791,7 @@ public class ProviderBillingService(
if (subscriptionItemOptionsList.Count > 0) if (subscriptionItemOptionsList.Count > 0)
{ {
await stripeAdapter.SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
new SubscriptionUpdateOptions { Items = subscriptionItemOptionsList }); new SubscriptionUpdateOptions { Items = subscriptionItemOptionsList });
} }
} }
@@ -807,7 +807,7 @@ public class ProviderBillingService(
var item = subscription.Items.First(item => item.Price.Id == priceId); var item = subscription.Items.First(item => item.Price.Id == priceId);
await stripeAdapter.SubscriptionUpdateAsync(provider.GatewaySubscriptionId, new SubscriptionUpdateOptions await stripeAdapter.UpdateSubscriptionAsync(provider.GatewaySubscriptionId, new SubscriptionUpdateOptions
{ {
Items = Items =
[ [

View File

@@ -8,6 +8,7 @@ using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.E
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
using Bit.Core.AdminConsole.Utilities.Commands; using Bit.Core.AdminConsole.Utilities.Commands;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
@@ -24,7 +25,7 @@ public class PostUserCommand(
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IOrganizationService organizationService, IOrganizationService organizationService,
IPaymentService paymentService, IStripePaymentService paymentService,
IScimContext scimContext, IScimContext scimContext,
IFeatureService featureService, IFeatureService featureService,
IInviteOrganizationUsersCommand inviteOrganizationUsersCommand, IInviteOrganizationUsersCommand inviteOrganizationUsersCommand,

View File

@@ -131,7 +131,7 @@ public class RemoveOrganizationFromProviderCommandTests
Arg.Is<IEnumerable<string>>(emails => emails.FirstOrDefault() == "a@example.com")); Arg.Is<IEnumerable<string>>(emails => emails.FirstOrDefault() == "a@example.com"));
await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs()
.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()); .UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -156,7 +156,7 @@ public class RemoveOrganizationFromProviderCommandTests
"b@example.com" "b@example.com"
]); ]);
sutProvider.GetDependency<IStripeAdapter>().SubscriptionGetAsync(organization.GatewaySubscriptionId, Arg.Is<SubscriptionGetOptions>( sutProvider.GetDependency<IStripeAdapter>().GetSubscriptionAsync(organization.GatewaySubscriptionId, Arg.Is<SubscriptionGetOptions>(
options => options.Expand.Contains("customer"))) options => options.Expand.Contains("customer")))
.Returns(GetSubscription(organization.GatewaySubscriptionId, organization.GatewayCustomerId)); .Returns(GetSubscription(organization.GatewaySubscriptionId, organization.GatewayCustomerId));
@@ -164,12 +164,14 @@ public class RemoveOrganizationFromProviderCommandTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
await stripeAdapter.Received(1).CustomerUpdateAsync(organization.GatewayCustomerId, await stripeAdapter.Received(1).UpdateCustomerAsync(organization.GatewayCustomerId,
Arg.Is<CustomerUpdateOptions>(options => options.Email == "a@example.com")); Arg.Is<CustomerUpdateOptions>(options => options.Email == "a@example.com"));
await stripeAdapter.Received(1).CustomerDeleteDiscountAsync(organization.GatewayCustomerId); await stripeAdapter.Received(1).DeleteCustomerDiscountAsync(organization.GatewayCustomerId);
await stripeAdapter.Received(1).SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await stripeAdapter.Received(1).DeleteCustomerDiscountAsync(organization.GatewayCustomerId);
await stripeAdapter.Received(1).UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => Arg.Is<SubscriptionUpdateOptions>(options =>
options.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice && options.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice &&
options.DaysUntilDue == 30)); options.DaysUntilDue == 30));
@@ -226,7 +228,7 @@ public class RemoveOrganizationFromProviderCommandTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Description == string.Empty && options.Description == string.Empty &&
options.Email == organization.BillingEmail && options.Email == organization.BillingEmail &&
options.Expand[0] == "tax" && options.Expand[0] == "tax" &&
@@ -239,14 +241,14 @@ public class RemoveOrganizationFromProviderCommandTests
} }
}); });
stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(new Subscription stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(new Subscription
{ {
Id = "subscription_id" Id = "subscription_id"
}); });
await sutProvider.Sut.RemoveOrganizationFromProvider(provider, providerOrganization, organization); await sutProvider.Sut.RemoveOrganizationFromProvider(provider, providerOrganization, organization);
await stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Is<SubscriptionCreateOptions>(options => await stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Is<SubscriptionCreateOptions>(options =>
options.Customer == organization.GatewayCustomerId && options.Customer == organization.GatewayCustomerId &&
options.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice && options.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice &&
options.DaysUntilDue == 30 && options.DaysUntilDue == 30 &&
@@ -315,7 +317,7 @@ public class RemoveOrganizationFromProviderCommandTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Description == string.Empty && options.Description == string.Empty &&
options.Email == organization.BillingEmail && options.Email == organization.BillingEmail &&
options.Expand[0] == "tax" && options.Expand[0] == "tax" &&
@@ -328,14 +330,14 @@ public class RemoveOrganizationFromProviderCommandTests
} }
}); });
stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(new Subscription stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(new Subscription
{ {
Id = "subscription_id" Id = "subscription_id"
}); });
await sutProvider.Sut.RemoveOrganizationFromProvider(provider, providerOrganization, organization); await sutProvider.Sut.RemoveOrganizationFromProvider(provider, providerOrganization, organization);
await stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Is<SubscriptionCreateOptions>(options => await stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Is<SubscriptionCreateOptions>(options =>
options.Customer == organization.GatewayCustomerId && options.Customer == organization.GatewayCustomerId &&
options.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice && options.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice &&
options.DaysUntilDue == 30 && options.DaysUntilDue == 30 &&
@@ -434,7 +436,7 @@ public class RemoveOrganizationFromProviderCommandTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Any<CustomerUpdateOptions>()) stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Any<CustomerUpdateOptions>())
.Returns(new Customer .Returns(new Customer
{ {
Id = "customer_id", Id = "customer_id",
@@ -444,7 +446,7 @@ public class RemoveOrganizationFromProviderCommandTests
} }
}); });
stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(new Subscription stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(new Subscription
{ {
Id = "new_subscription_id" Id = "new_subscription_id"
}); });

View File

@@ -12,6 +12,7 @@ using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Providers.Services; using Bit.Core.Billing.Providers.Services;
using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@@ -757,7 +758,7 @@ public class ProviderServiceTests
await organizationRepository.Received(1) await organizationRepository.Received(1)
.ReplaceAsync(Arg.Is<Organization>(org => org.BillingEmail == provider.BillingEmail)); .ReplaceAsync(Arg.Is<Organization>(org => org.BillingEmail == provider.BillingEmail));
await sutProvider.GetDependency<IStripeAdapter>().Received(1).CustomerUpdateAsync( await sutProvider.GetDependency<IStripeAdapter>().Received(1).UpdateCustomerAsync(
organization.GatewayCustomerId, organization.GatewayCustomerId,
Arg.Is<CustomerUpdateOptions>(options => options.Email == provider.BillingEmail)); Arg.Is<CustomerUpdateOptions>(options => options.Email == provider.BillingEmail));
@@ -828,9 +829,9 @@ public class ProviderServiceTests
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization); sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
var subscriptionItem = GetSubscription(organization.GatewaySubscriptionId); var subscriptionItem = GetSubscription(organization.GatewaySubscriptionId);
sutProvider.GetDependency<IStripeAdapter>().SubscriptionGetAsync(organization.GatewaySubscriptionId) sutProvider.GetDependency<IStripeAdapter>().GetSubscriptionAsync(organization.GatewaySubscriptionId)
.Returns(GetSubscription(organization.GatewaySubscriptionId)); .Returns(GetSubscription(organization.GatewaySubscriptionId));
await sutProvider.GetDependency<IStripeAdapter>().SubscriptionUpdateAsync( await sutProvider.GetDependency<IStripeAdapter>().UpdateSubscriptionAsync(
organization.GatewaySubscriptionId, SubscriptionUpdateRequest(expectedPlanId, subscriptionItem)); organization.GatewaySubscriptionId, SubscriptionUpdateRequest(expectedPlanId, subscriptionItem));
await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key); await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key);

View File

@@ -3,7 +3,6 @@ using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.Billing.Constants; using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
@@ -63,7 +62,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> { Data = [] }); .Returns(new StripeList<Registration> { Data = [] });
var response = await sutProvider.Sut.Run(provider); var response = await sutProvider.Sut.Run(provider);
@@ -95,7 +94,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> { Data = [] }); .Returns(new StripeList<Registration> { Data = [] });
var response = await sutProvider.Sut.Run(provider); var response = await sutProvider.Sut.Run(provider);
@@ -129,7 +128,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(false); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(false);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> { Data = [] }); .Returns(new StripeList<Registration> { Data = [] });
var response = await sutProvider.Sut.Run(provider); var response = await sutProvider.Sut.Run(provider);
@@ -163,7 +162,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> { Data = [] }); .Returns(new StripeList<Registration> { Data = [] });
var response = await sutProvider.Sut.Run(provider); var response = await sutProvider.Sut.Run(provider);
@@ -224,7 +223,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "GB" }] Data = [new Registration { Country = "GB" }]
@@ -257,7 +256,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "CA" }] Data = [new Registration { Country = "CA" }]
@@ -296,7 +295,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "CA" }] Data = [new Registration { Country = "CA" }]
@@ -338,7 +337,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "CA" }] Data = [new Registration { Country = "CA" }]
@@ -383,7 +382,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "CA" }] Data = [new Registration { Country = "CA" }]
@@ -428,7 +427,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "CA" }] Data = [new Registration { Country = "CA" }]
@@ -461,7 +460,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Is<RegistrationListOptions>(opt => opt.Status == TaxRegistrationStatus.Active)) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Is<RegistrationListOptions>(opt => opt.Status == TaxRegistrationStatus.Active))
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [ Data = [
@@ -470,7 +469,7 @@ public class GetProviderWarningsQueryTests
new Registration { Country = "FR" } new Registration { Country = "FR" }
] ]
}); });
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Is<RegistrationListOptions>(opt => opt.Status == TaxRegistrationStatus.Scheduled)) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Is<RegistrationListOptions>(opt => opt.Status == TaxRegistrationStatus.Scheduled))
.Returns(new StripeList<Registration> { Data = [] }); .Returns(new StripeList<Registration> { Data = [] });
var response = await sutProvider.Sut.Run(provider); var response = await sutProvider.Sut.Run(provider);
@@ -505,7 +504,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "CA" }] Data = [new Registration { Country = "CA" }]
@@ -543,7 +542,7 @@ public class GetProviderWarningsQueryTests
}); });
sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ProviderProviderAdmin(provider.Id).Returns(true);
sutProvider.GetDependency<IStripeAdapter>().TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) sutProvider.GetDependency<IStripeAdapter>().ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = [new Registration { Country = "US" }] Data = [new Registration { Country = "US" }]

View File

@@ -144,11 +144,11 @@ public class BusinessUnitConverterTests
await businessUnitConverter.FinalizeConversion(organization, userId, token, providerKey, organizationKey); await businessUnitConverter.FinalizeConversion(organization, userId, token, providerKey, organizationKey);
await _stripeAdapter.Received(2).CustomerUpdateAsync(subscription.CustomerId, Arg.Any<CustomerUpdateOptions>()); await _stripeAdapter.Received(2).UpdateCustomerAsync(subscription.CustomerId, Arg.Any<CustomerUpdateOptions>());
var updatedPriceId = ProviderPriceAdapter.GetActivePriceId(provider, enterpriseAnnually.Type); var updatedPriceId = ProviderPriceAdapter.GetActivePriceId(provider, enterpriseAnnually.Type);
await _stripeAdapter.Received(1).SubscriptionUpdateAsync(subscription.Id, Arg.Is<SubscriptionUpdateOptions>( await _stripeAdapter.Received(1).UpdateSubscriptionAsync(subscription.Id, Arg.Is<SubscriptionUpdateOptions>(
arguments => arguments =>
arguments.Items.Count == 2 && arguments.Items.Count == 2 &&
arguments.Items[0].Id == "subscription_item_id" && arguments.Items[0].Id == "subscription_item_id" &&

View File

@@ -20,7 +20,6 @@ using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Test.Billing.Mocks; using Bit.Core.Test.Billing.Mocks;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
@@ -85,7 +84,7 @@ public class ProviderBillingServiceTests
// Assert // Assert
await providerPlanRepository.Received(0).ReplaceAsync(Arg.Any<ProviderPlan>()); await providerPlanRepository.Received(0).ReplaceAsync(Arg.Any<ProviderPlan>());
await stripeAdapter.Received(0).SubscriptionUpdateAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>()); await stripeAdapter.Received(0).UpdateSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -113,7 +112,7 @@ public class ProviderBillingServiceTests
// Assert // Assert
await providerPlanRepository.Received(0).ReplaceAsync(Arg.Any<ProviderPlan>()); await providerPlanRepository.Received(0).ReplaceAsync(Arg.Any<ProviderPlan>());
await stripeAdapter.Received(0).SubscriptionUpdateAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>()); await stripeAdapter.Received(0).UpdateSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -180,14 +179,14 @@ public class ProviderBillingServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
await stripeAdapter.Received(1) await stripeAdapter.Received(1)
.SubscriptionUpdateAsync( .UpdateSubscriptionAsync(
Arg.Is(provider.GatewaySubscriptionId), Arg.Is(provider.GatewaySubscriptionId),
Arg.Is<SubscriptionUpdateOptions>(p => Arg.Is<SubscriptionUpdateOptions>(p =>
p.Items.Count(si => si.Id == "si_ent_annual" && si.Deleted == true) == 1)); p.Items.Count(si => si.Id == "si_ent_annual" && si.Deleted == true) == 1));
var newPlanCfg = MockPlans.Get(command.NewPlan); var newPlanCfg = MockPlans.Get(command.NewPlan);
await stripeAdapter.Received(1) await stripeAdapter.Received(1)
.SubscriptionUpdateAsync( .UpdateSubscriptionAsync(
Arg.Is(provider.GatewaySubscriptionId), Arg.Is(provider.GatewaySubscriptionId),
Arg.Is<SubscriptionUpdateOptions>(p => Arg.Is<SubscriptionUpdateOptions>(p =>
p.Items.Count(si => p.Items.Count(si =>
@@ -268,7 +267,7 @@ public class ProviderBillingServiceTests
CloudRegion = "US" CloudRegion = "US"
}); });
sutProvider.GetDependency<IStripeAdapter>().CustomerCreateAsync(Arg.Is<CustomerCreateOptions>( sutProvider.GetDependency<IStripeAdapter>().CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(
options => options =>
options.Address.Country == providerCustomer.Address.Country && options.Address.Country == providerCustomer.Address.Country &&
options.Address.PostalCode == providerCustomer.Address.PostalCode && options.Address.PostalCode == providerCustomer.Address.PostalCode &&
@@ -288,7 +287,7 @@ public class ProviderBillingServiceTests
await sutProvider.Sut.CreateCustomerForClientOrganization(provider, organization); await sutProvider.Sut.CreateCustomerForClientOrganization(provider, organization);
await sutProvider.GetDependency<IStripeAdapter>().Received(1).CustomerCreateAsync(Arg.Is<CustomerCreateOptions>( await sutProvider.GetDependency<IStripeAdapter>().Received(1).CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(
options => options =>
options.Address.Country == providerCustomer.Address.Country && options.Address.Country == providerCustomer.Address.Country &&
options.Address.PostalCode == providerCustomer.Address.PostalCode && options.Address.PostalCode == providerCustomer.Address.PostalCode &&
@@ -349,7 +348,7 @@ public class ProviderBillingServiceTests
CloudRegion = "US" CloudRegion = "US"
}); });
sutProvider.GetDependency<IStripeAdapter>().CustomerCreateAsync(Arg.Is<CustomerCreateOptions>( sutProvider.GetDependency<IStripeAdapter>().CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(
options => options =>
options.Address.Country == providerCustomer.Address.Country && options.Address.Country == providerCustomer.Address.Country &&
options.Address.PostalCode == providerCustomer.Address.PostalCode && options.Address.PostalCode == providerCustomer.Address.PostalCode &&
@@ -370,7 +369,7 @@ public class ProviderBillingServiceTests
await sutProvider.Sut.CreateCustomerForClientOrganization(provider, organization); await sutProvider.Sut.CreateCustomerForClientOrganization(provider, organization);
await sutProvider.GetDependency<IStripeAdapter>().Received(1).CustomerCreateAsync(Arg.Is<CustomerCreateOptions>( await sutProvider.GetDependency<IStripeAdapter>().Received(1).CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(
options => options =>
options.Address.Country == providerCustomer.Address.Country && options.Address.Country == providerCustomer.Address.Country &&
options.Address.PostalCode == providerCustomer.Address.PostalCode && options.Address.PostalCode == providerCustomer.Address.PostalCode &&
@@ -535,7 +534,7 @@ public class ProviderBillingServiceTests
await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, 10); await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, 10);
// 50 assigned seats + 10 seat scale up = 60 seats, well below the 100 minimum // 50 assigned seats + 10 seat scale up = 60 seats, well below the 100 minimum
await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs().SubscriptionUpdateAsync( await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs().UpdateSubscriptionAsync(
Arg.Any<string>(), Arg.Any<string>(),
Arg.Any<SubscriptionUpdateOptions>()); Arg.Any<SubscriptionUpdateOptions>());
@@ -619,7 +618,7 @@ public class ProviderBillingServiceTests
await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, 10); await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, 10);
// 95 current + 10 seat scale = 105 seats, 5 above the minimum // 95 current + 10 seat scale = 105 seats, 5 above the minimum
await sutProvider.GetDependency<IStripeAdapter>().Received(1).SubscriptionUpdateAsync( await sutProvider.GetDependency<IStripeAdapter>().Received(1).UpdateSubscriptionAsync(
provider.GatewaySubscriptionId, provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>( Arg.Is<SubscriptionUpdateOptions>(
options => options =>
@@ -707,7 +706,7 @@ public class ProviderBillingServiceTests
await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, 10); await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, 10);
// 110 current + 10 seat scale up = 120 seats // 110 current + 10 seat scale up = 120 seats
await sutProvider.GetDependency<IStripeAdapter>().Received(1).SubscriptionUpdateAsync( await sutProvider.GetDependency<IStripeAdapter>().Received(1).UpdateSubscriptionAsync(
provider.GatewaySubscriptionId, provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>( Arg.Is<SubscriptionUpdateOptions>(
options => options =>
@@ -795,7 +794,7 @@ public class ProviderBillingServiceTests
await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, -30); await sutProvider.Sut.ScaleSeats(provider, PlanType.TeamsMonthly, -30);
// 110 seats - 30 scale down seats = 80 seats, below the 100 seat minimum. // 110 seats - 30 scale down seats = 80 seats, below the 100 seat minimum.
await sutProvider.GetDependency<IStripeAdapter>().Received(1).SubscriptionUpdateAsync( await sutProvider.GetDependency<IStripeAdapter>().Received(1).UpdateSubscriptionAsync(
provider.GatewaySubscriptionId, provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>( Arg.Is<SubscriptionUpdateOptions>(
options => options =>
@@ -914,12 +913,12 @@ public class ProviderBillingServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.BankAccount, Token = "token" }; var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.BankAccount, Token = "token" };
stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => stripeAdapter.ListSetupIntentsAsync(Arg.Is<SetupIntentListOptions>(options =>
options.PaymentMethod == tokenizedPaymentMethod.Token)).Returns([ options.PaymentMethod == tokenizedPaymentMethod.Token)).Returns([
new SetupIntent { Id = "setup_intent_id" } new SetupIntent { Id = "setup_intent_id" }
]); ]);
stripeAdapter.CustomerCreateAsync(Arg.Is<CustomerCreateOptions>(o => stripeAdapter.CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(o =>
o.Address.Country == billingAddress.Country && o.Address.Country == billingAddress.Country &&
o.Address.PostalCode == billingAddress.PostalCode && o.Address.PostalCode == billingAddress.PostalCode &&
o.Address.Line1 == billingAddress.Line1 && o.Address.Line1 == billingAddress.Line1 &&
@@ -942,7 +941,7 @@ public class ProviderBillingServiceTests
await sutProvider.GetDependency<ISetupIntentCache>().Received(1).Set(provider.Id, "setup_intent_id"); await sutProvider.GetDependency<ISetupIntentCache>().Received(1).Set(provider.Id, "setup_intent_id");
await stripeAdapter.Received(1).SetupIntentCancel("setup_intent_id", Arg.Is<SetupIntentCancelOptions>(options => await stripeAdapter.Received(1).CancelSetupIntentAsync("setup_intent_id", Arg.Is<SetupIntentCancelOptions>(options =>
options.CancellationReason == "abandoned")); options.CancellationReason == "abandoned"));
await sutProvider.GetDependency<ISetupIntentCache>().Received(1).RemoveSetupIntentForSubscriber(provider.Id); await sutProvider.GetDependency<ISetupIntentCache>().Received(1).RemoveSetupIntentForSubscriber(provider.Id);
@@ -964,7 +963,7 @@ public class ProviderBillingServiceTests
sutProvider.GetDependency<ISubscriberService>().CreateBraintreeCustomer(provider, tokenizedPaymentMethod.Token) sutProvider.GetDependency<ISubscriberService>().CreateBraintreeCustomer(provider, tokenizedPaymentMethod.Token)
.Returns("braintree_customer_id"); .Returns("braintree_customer_id");
stripeAdapter.CustomerCreateAsync(Arg.Is<CustomerCreateOptions>(o => stripeAdapter.CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(o =>
o.Address.Country == billingAddress.Country && o.Address.Country == billingAddress.Country &&
o.Address.PostalCode == billingAddress.PostalCode && o.Address.PostalCode == billingAddress.PostalCode &&
o.Address.Line1 == billingAddress.Line1 && o.Address.Line1 == billingAddress.Line1 &&
@@ -1007,12 +1006,12 @@ public class ProviderBillingServiceTests
var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.BankAccount, Token = "token" }; var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.BankAccount, Token = "token" };
stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => stripeAdapter.ListSetupIntentsAsync(Arg.Is<SetupIntentListOptions>(options =>
options.PaymentMethod == tokenizedPaymentMethod.Token)).Returns([ options.PaymentMethod == tokenizedPaymentMethod.Token)).Returns([
new SetupIntent { Id = "setup_intent_id" } new SetupIntent { Id = "setup_intent_id" }
]); ]);
stripeAdapter.CustomerCreateAsync(Arg.Is<CustomerCreateOptions>(o => stripeAdapter.CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(o =>
o.Address.Country == billingAddress.Country && o.Address.Country == billingAddress.Country &&
o.Address.PostalCode == billingAddress.PostalCode && o.Address.PostalCode == billingAddress.PostalCode &&
o.Address.Line1 == billingAddress.Line1 && o.Address.Line1 == billingAddress.Line1 &&
@@ -1058,7 +1057,7 @@ public class ProviderBillingServiceTests
sutProvider.GetDependency<ISubscriberService>().CreateBraintreeCustomer(provider, tokenizedPaymentMethod.Token) sutProvider.GetDependency<ISubscriberService>().CreateBraintreeCustomer(provider, tokenizedPaymentMethod.Token)
.Returns("braintree_customer_id"); .Returns("braintree_customer_id");
stripeAdapter.CustomerCreateAsync(Arg.Is<CustomerCreateOptions>(o => stripeAdapter.CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(o =>
o.Address.Country == billingAddress.Country && o.Address.Country == billingAddress.Country &&
o.Address.PostalCode == billingAddress.PostalCode && o.Address.PostalCode == billingAddress.PostalCode &&
o.Address.Line1 == billingAddress.Line1 && o.Address.Line1 == billingAddress.Line1 &&
@@ -1100,7 +1099,7 @@ public class ProviderBillingServiceTests
var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.Card, Token = "token" }; var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.Card, Token = "token" };
stripeAdapter.CustomerCreateAsync(Arg.Is<CustomerCreateOptions>(o => stripeAdapter.CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(o =>
o.Address.Country == billingAddress.Country && o.Address.Country == billingAddress.Country &&
o.Address.PostalCode == billingAddress.PostalCode && o.Address.PostalCode == billingAddress.PostalCode &&
o.Address.Line1 == billingAddress.Line1 && o.Address.Line1 == billingAddress.Line1 &&
@@ -1142,7 +1141,7 @@ public class ProviderBillingServiceTests
var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.Card, Token = "token" }; var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.Card, Token = "token" };
stripeAdapter.CustomerCreateAsync(Arg.Is<CustomerCreateOptions>(o => stripeAdapter.CreateCustomerAsync(Arg.Is<CustomerCreateOptions>(o =>
o.Address.Country == billingAddress.Country && o.Address.Country == billingAddress.Country &&
o.Address.PostalCode == billingAddress.PostalCode && o.Address.PostalCode == billingAddress.PostalCode &&
o.Address.Line1 == billingAddress.Line1 && o.Address.Line1 == billingAddress.Line1 &&
@@ -1178,7 +1177,7 @@ public class ProviderBillingServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.Card, Token = "token" }; var tokenizedPaymentMethod = new TokenizedPaymentMethod { Type = TokenizablePaymentMethodType.Card, Token = "token" };
stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()) stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>())
.Throws(new StripeException("Invalid tax ID") { StripeError = new StripeError { Code = "tax_id_invalid" } }); .Throws(new StripeException("Invalid tax ID") { StripeError = new StripeError { Code = "tax_id_invalid" } });
var actual = await Assert.ThrowsAsync<BadRequestException>(async () => var actual = await Assert.ThrowsAsync<BadRequestException>(async () =>
@@ -1216,7 +1215,7 @@ public class ProviderBillingServiceTests
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); .CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1244,7 +1243,7 @@ public class ProviderBillingServiceTests
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); .CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1272,7 +1271,7 @@ public class ProviderBillingServiceTests
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); .CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1323,7 +1322,7 @@ public class ProviderBillingServiceTests
sutProvider.GetDependency<IProviderPlanRepository>().GetByProviderId(provider.Id) sutProvider.GetDependency<IProviderPlanRepository>().GetByProviderId(provider.Id)
.Returns(providerPlans); .Returns(providerPlans);
sutProvider.GetDependency<IStripeAdapter>().SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()) sutProvider.GetDependency<IStripeAdapter>().CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>())
.Returns( .Returns(
new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Incomplete }); new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Incomplete });
@@ -1381,7 +1380,7 @@ public class ProviderBillingServiceTests
var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active }; var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active };
sutProvider.GetDependency<IStripeAdapter>().SubscriptionCreateAsync(Arg.Is<SubscriptionCreateOptions>( sutProvider.GetDependency<IStripeAdapter>().CreateSubscriptionAsync(Arg.Is<SubscriptionCreateOptions>(
sub => sub =>
sub.AutomaticTax.Enabled == true && sub.AutomaticTax.Enabled == true &&
sub.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice && sub.CollectionMethod == StripeConstants.CollectionMethod.SendInvoice &&
@@ -1458,7 +1457,7 @@ public class ProviderBillingServiceTests
var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active }; var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active };
sutProvider.GetDependency<IStripeAdapter>().SubscriptionCreateAsync(Arg.Is<SubscriptionCreateOptions>( sutProvider.GetDependency<IStripeAdapter>().CreateSubscriptionAsync(Arg.Is<SubscriptionCreateOptions>(
sub => sub =>
sub.AutomaticTax.Enabled == true && sub.AutomaticTax.Enabled == true &&
sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically && sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically &&
@@ -1538,7 +1537,7 @@ public class ProviderBillingServiceTests
sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(provider.Id).Returns(setupIntentId); sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(provider.Id).Returns(setupIntentId);
sutProvider.GetDependency<IStripeAdapter>().SetupIntentGet(setupIntentId, Arg.Is<SetupIntentGetOptions>(options => sutProvider.GetDependency<IStripeAdapter>().GetSetupIntentAsync(setupIntentId, Arg.Is<SetupIntentGetOptions>(options =>
options.Expand.Contains("payment_method"))).Returns(new SetupIntent options.Expand.Contains("payment_method"))).Returns(new SetupIntent
{ {
Id = setupIntentId, Id = setupIntentId,
@@ -1553,7 +1552,7 @@ public class ProviderBillingServiceTests
} }
}); });
sutProvider.GetDependency<IStripeAdapter>().SubscriptionCreateAsync(Arg.Is<SubscriptionCreateOptions>( sutProvider.GetDependency<IStripeAdapter>().CreateSubscriptionAsync(Arg.Is<SubscriptionCreateOptions>(
sub => sub =>
sub.AutomaticTax.Enabled == true && sub.AutomaticTax.Enabled == true &&
sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically && sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically &&
@@ -1635,7 +1634,7 @@ public class ProviderBillingServiceTests
var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active }; var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active };
sutProvider.GetDependency<IStripeAdapter>().SubscriptionCreateAsync(Arg.Is<SubscriptionCreateOptions>( sutProvider.GetDependency<IStripeAdapter>().CreateSubscriptionAsync(Arg.Is<SubscriptionCreateOptions>(
sub => sub =>
sub.AutomaticTax.Enabled == true && sub.AutomaticTax.Enabled == true &&
sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically && sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically &&
@@ -1713,7 +1712,7 @@ public class ProviderBillingServiceTests
var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active }; var expected = new Subscription { Id = "subscription_id", Status = StripeConstants.SubscriptionStatus.Active };
sutProvider.GetDependency<IStripeAdapter>().SubscriptionCreateAsync(Arg.Is<SubscriptionCreateOptions>( sutProvider.GetDependency<IStripeAdapter>().CreateSubscriptionAsync(Arg.Is<SubscriptionCreateOptions>(
sub => sub =>
sub.AutomaticTax.Enabled == true && sub.AutomaticTax.Enabled == true &&
sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically && sub.CollectionMethod == StripeConstants.CollectionMethod.ChargeAutomatically &&
@@ -1828,7 +1827,7 @@ public class ProviderBillingServiceTests
await providerPlanRepository.Received(1).ReplaceAsync(Arg.Is<ProviderPlan>( await providerPlanRepository.Received(1).ReplaceAsync(Arg.Is<ProviderPlan>(
providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 20 && providerPlan.PurchasedSeats == 5)); providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 20 && providerPlan.PurchasedSeats == 5));
await stripeAdapter.Received(1).SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.Received(1).UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>( Arg.Is<SubscriptionUpdateOptions>(
options => options =>
options.Items.Count == 2 && options.Items.Count == 2 &&
@@ -1908,7 +1907,7 @@ public class ProviderBillingServiceTests
await providerPlanRepository.Received(1).ReplaceAsync(Arg.Is<ProviderPlan>( await providerPlanRepository.Received(1).ReplaceAsync(Arg.Is<ProviderPlan>(
providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 50)); providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 50));
await stripeAdapter.Received(1).SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.Received(1).UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>( Arg.Is<SubscriptionUpdateOptions>(
options => options =>
options.Items.Count == 2 && options.Items.Count == 2 &&
@@ -1989,7 +1988,7 @@ public class ProviderBillingServiceTests
providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 60 && providerPlan.PurchasedSeats == 10)); providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 60 && providerPlan.PurchasedSeats == 10));
await stripeAdapter.DidNotReceiveWithAnyArgs() await stripeAdapter.DidNotReceiveWithAnyArgs()
.SubscriptionUpdateAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>()); .UpdateSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -2062,7 +2061,7 @@ public class ProviderBillingServiceTests
await providerPlanRepository.Received(1).ReplaceAsync(Arg.Is<ProviderPlan>( await providerPlanRepository.Received(1).ReplaceAsync(Arg.Is<ProviderPlan>(
providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 80 && providerPlan.PurchasedSeats == 0)); providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly && providerPlan.SeatMinimum == 80 && providerPlan.PurchasedSeats == 0));
await stripeAdapter.Received(1).SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.Received(1).UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>( Arg.Is<SubscriptionUpdateOptions>(
options => options =>
options.Items.Count == 2 && options.Items.Count == 2 &&
@@ -2142,7 +2141,7 @@ public class ProviderBillingServiceTests
await providerPlanRepository.DidNotReceive().ReplaceAsync(Arg.Is<ProviderPlan>( await providerPlanRepository.DidNotReceive().ReplaceAsync(Arg.Is<ProviderPlan>(
providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly)); providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly));
await stripeAdapter.Received(1).SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.Received(1).UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>( Arg.Is<SubscriptionUpdateOptions>(
options => options =>
options.Items.Count == 1 && options.Items.Count == 1 &&

View File

@@ -1,4 +1,5 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
@@ -36,7 +37,7 @@ public class PostUserCommandTests
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(organization); sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(organization);
sutProvider.GetDependency<IPaymentService>().HasSecretsManagerStandalone(organization).Returns(true); sutProvider.GetDependency<IStripePaymentService>().HasSecretsManagerStandalone(organization).Returns(true);
sutProvider.GetDependency<IOrganizationService>() sutProvider.GetDependency<IOrganizationService>()
.InviteUserAsync(organizationId, .InviteUserAsync(organizationId,

View File

@@ -16,6 +16,7 @@ using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Extensions; using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Providers.Services; using Bit.Core.Billing.Providers.Services;
using Bit.Core.Billing.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.OrganizationConnectionConfigs; using Bit.Core.Models.OrganizationConnectionConfigs;
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
@@ -41,7 +42,7 @@ public class OrganizationsController : Controller
private readonly ICollectionRepository _collectionRepository; private readonly ICollectionRepository _collectionRepository;
private readonly IGroupRepository _groupRepository; private readonly IGroupRepository _groupRepository;
private readonly IPolicyRepository _policyRepository; private readonly IPolicyRepository _policyRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IApplicationCacheService _applicationCacheService; private readonly IApplicationCacheService _applicationCacheService;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
private readonly IProviderRepository _providerRepository; private readonly IProviderRepository _providerRepository;
@@ -66,7 +67,7 @@ public class OrganizationsController : Controller
ICollectionRepository collectionRepository, ICollectionRepository collectionRepository,
IGroupRepository groupRepository, IGroupRepository groupRepository,
IPolicyRepository policyRepository, IPolicyRepository policyRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
IApplicationCacheService applicationCacheService, IApplicationCacheService applicationCacheService,
GlobalSettings globalSettings, GlobalSettings globalSettings,
IProviderRepository providerRepository, IProviderRepository providerRepository,

View File

@@ -339,11 +339,11 @@ public class ProvidersController : Controller
]); ]);
await _providerBillingService.UpdateSeatMinimums(updateMspSeatMinimumsCommand); await _providerBillingService.UpdateSeatMinimums(updateMspSeatMinimumsCommand);
var customer = await _stripeAdapter.CustomerGetAsync(provider.GatewayCustomerId); var customer = await _stripeAdapter.GetCustomerAsync(provider.GatewayCustomerId);
if (model.PayByInvoice != customer.ApprovedToPayByInvoice()) if (model.PayByInvoice != customer.ApprovedToPayByInvoice())
{ {
var approvedToPayByInvoice = model.PayByInvoice ? "1" : "0"; var approvedToPayByInvoice = model.PayByInvoice ? "1" : "0";
await _stripeAdapter.CustomerUpdateAsync(customer.Id, new CustomerUpdateOptions await _stripeAdapter.UpdateCustomerAsync(customer.Id, new CustomerUpdateOptions
{ {
Metadata = new Dictionary<string, string> Metadata = new Dictionary<string, string>
{ {

View File

@@ -8,6 +8,7 @@ using Bit.Admin.Utilities;
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Organizations.Queries; using Bit.Core.Billing.Organizations.Queries;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Platform.Installations; using Bit.Core.Platform.Installations;
using Bit.Core.Repositories; using Bit.Core.Repositories;

View File

@@ -5,6 +5,7 @@ using Bit.Admin.Models;
using Bit.Admin.Services; using Bit.Admin.Services;
using Bit.Admin.Utilities; using Bit.Admin.Utilities;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces; using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
using Bit.Core.Billing.Services;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
@@ -20,7 +21,7 @@ public class UsersController : Controller
{ {
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly ICipherRepository _cipherRepository; private readonly ICipherRepository _cipherRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
private readonly IAccessControlService _accessControlService; private readonly IAccessControlService _accessControlService;
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery; private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
@@ -30,7 +31,7 @@ public class UsersController : Controller
public UsersController( public UsersController(
IUserRepository userRepository, IUserRepository userRepository,
ICipherRepository cipherRepository, ICipherRepository cipherRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
GlobalSettings globalSettings, GlobalSettings globalSettings,
IAccessControlService accessControlService, IAccessControlService accessControlService,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery, ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,

View File

@@ -6,6 +6,7 @@ using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces; using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
@@ -24,7 +25,7 @@ public class MembersController : Controller
private readonly ICurrentContext _currentContext; private readonly ICurrentContext _currentContext;
private readonly IUpdateOrganizationUserCommand _updateOrganizationUserCommand; private readonly IUpdateOrganizationUserCommand _updateOrganizationUserCommand;
private readonly IUpdateOrganizationUserGroupsCommand _updateOrganizationUserGroupsCommand; private readonly IUpdateOrganizationUserGroupsCommand _updateOrganizationUserGroupsCommand;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery; private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand; private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand;
@@ -37,7 +38,7 @@ public class MembersController : Controller
ICurrentContext currentContext, ICurrentContext currentContext,
IUpdateOrganizationUserCommand updateOrganizationUserCommand, IUpdateOrganizationUserCommand updateOrganizationUserCommand,
IUpdateOrganizationUserGroupsCommand updateOrganizationUserGroupsCommand, IUpdateOrganizationUserGroupsCommand updateOrganizationUserGroupsCommand,
IPaymentService paymentService, IStripePaymentService paymentService,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery, ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
IRemoveOrganizationUserCommand removeOrganizationUserCommand, IRemoveOrganizationUserCommand removeOrganizationUserCommand,

View File

@@ -10,7 +10,7 @@ namespace Bit.Api.Billing.Controllers;
[Route("accounts/billing")] [Route("accounts/billing")]
[Authorize("Application")] [Authorize("Application")]
public class AccountsBillingController( public class AccountsBillingController(
IPaymentService paymentService, IStripePaymentService paymentService,
IUserService userService, IUserService userService,
IPaymentHistoryService paymentHistoryService) : Controller IPaymentHistoryService paymentHistoryService) : Controller
{ {

View File

@@ -79,7 +79,7 @@ public class AccountsController(
[HttpGet("subscription")] [HttpGet("subscription")]
public async Task<SubscriptionResponseModel> GetSubscriptionAsync( public async Task<SubscriptionResponseModel> GetSubscriptionAsync(
[FromServices] GlobalSettings globalSettings, [FromServices] GlobalSettings globalSettings,
[FromServices] IPaymentService paymentService) [FromServices] IStripePaymentService paymentService)
{ {
var user = await userService.GetUserByPrincipalAsync(User); var user = await userService.GetUserByPrincipalAsync(User);
if (user == null) if (user == null)

View File

@@ -5,7 +5,6 @@ using Bit.Core.Billing.Providers.Services;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -19,7 +18,7 @@ public class OrganizationBillingController(
ICurrentContext currentContext, ICurrentContext currentContext,
IOrganizationBillingService organizationBillingService, IOrganizationBillingService organizationBillingService,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
IPaymentHistoryService paymentHistoryService) : BaseBillingController IPaymentHistoryService paymentHistoryService) : BaseBillingController
{ {
// TODO: Remove when pm-25379-use-new-organization-metadata-structure is removed. // TODO: Remove when pm-25379-use-new-organization-metadata-structure is removed.

View File

@@ -36,7 +36,7 @@ public class OrganizationsController(
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IOrganizationService organizationService, IOrganizationService organizationService,
IUserService userService, IUserService userService,
IPaymentService paymentService, IStripePaymentService paymentService,
ICurrentContext currentContext, ICurrentContext currentContext,
IGetCloudOrganizationLicenseQuery getCloudOrganizationLicenseQuery, IGetCloudOrganizationLicenseQuery getCloudOrganizationLicenseQuery,
GlobalSettings globalSettings, GlobalSettings globalSettings,

View File

@@ -43,7 +43,7 @@ public class ProviderBillingController(
return result; return result;
} }
var invoices = await stripeAdapter.InvoiceListAsync(new StripeInvoiceListOptions var invoices = await stripeAdapter.ListInvoicesAsync(new StripeInvoiceListOptions
{ {
Customer = provider.GatewayCustomerId Customer = provider.GatewayCustomerId
}); });
@@ -87,7 +87,7 @@ public class ProviderBillingController(
return result; return result;
} }
var subscription = await stripeAdapter.SubscriptionGetAsync(provider.GatewaySubscriptionId, var subscription = await stripeAdapter.GetSubscriptionAsync(provider.GatewaySubscriptionId,
new SubscriptionGetOptions { Expand = ["customer.tax_ids", "discounts", "test_clock"] }); new SubscriptionGetOptions { Expand = ["customer.tax_ids", "discounts", "test_clock"] });
var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id); var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id);
@@ -96,7 +96,7 @@ public class ProviderBillingController(
{ {
var plan = await pricingClient.GetPlanOrThrow(providerPlan.PlanType); var plan = await pricingClient.GetPlanOrThrow(providerPlan.PlanType);
var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, plan.Type); var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, plan.Type);
var price = await stripeAdapter.PriceGetAsync(priceId); var price = await stripeAdapter.GetPriceAsync(priceId);
var unitAmount = price.UnitAmountDecimal.HasValue var unitAmount = price.UnitAmountDecimal.HasValue
? price.UnitAmountDecimal.Value / 100M ? price.UnitAmountDecimal.Value / 100M

View File

@@ -1,5 +1,5 @@
using Bit.Core.Billing.Tax.Services; using Bit.Core.Billing.Services;
using Bit.Core.Services; using Bit.Core.Billing.Tax.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -28,7 +28,7 @@ public class StripeController(
Usage = "off_session" Usage = "off_session"
}; };
var setupIntent = await stripeAdapter.SetupIntentCreate(options); var setupIntent = await stripeAdapter.CreateSetupIntentAsync(options);
return TypedResults.Ok(setupIntent.ClientSecret); return TypedResults.Ok(setupIntent.ClientSecret);
} }
@@ -43,7 +43,7 @@ public class StripeController(
Usage = "off_session" Usage = "off_session"
}; };
var setupIntent = await stripeAdapter.SetupIntentCreate(options); var setupIntent = await stripeAdapter.CreateSetupIntentAsync(options);
return TypedResults.Ok(setupIntent.ClientSecret); return TypedResults.Ok(setupIntent.ClientSecret);
} }

View File

@@ -29,7 +29,7 @@ public class BitPayController(
IUserRepository userRepository, IUserRepository userRepository,
IProviderRepository providerRepository, IProviderRepository providerRepository,
IMailService mailService, IMailService mailService,
IPaymentService paymentService, IStripePaymentService paymentService,
ILogger<BitPayController> logger, ILogger<BitPayController> logger,
IPremiumUserBillingService premiumUserBillingService) IPremiumUserBillingService premiumUserBillingService)
: Controller : Controller

View File

@@ -23,7 +23,7 @@ public class PayPalController : Controller
private readonly ILogger<PayPalController> _logger; private readonly ILogger<PayPalController> _logger;
private readonly IMailService _mailService; private readonly IMailService _mailService;
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly ITransactionRepository _transactionRepository; private readonly ITransactionRepository _transactionRepository;
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IProviderRepository _providerRepository; private readonly IProviderRepository _providerRepository;
@@ -34,7 +34,7 @@ public class PayPalController : Controller
ILogger<PayPalController> logger, ILogger<PayPalController> logger,
IMailService mailService, IMailService mailService,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
ITransactionRepository transactionRepository, ITransactionRepository transactionRepository,
IUserRepository userRepository, IUserRepository userRepository,
IProviderRepository providerRepository, IProviderRepository providerRepository,

View File

@@ -2,8 +2,8 @@
using Bit.Core.AdminConsole.Entities.Provider; using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Caches; using Bit.Core.Billing.Caches;
using Bit.Core.Billing.Services;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using OneOf; using OneOf;
using Stripe; using Stripe;
using Event = Stripe.Event; using Event = Stripe.Event;
@@ -59,10 +59,10 @@ public class SetupIntentSucceededHandler(
return; return;
} }
await stripeAdapter.PaymentMethodAttachAsync(paymentMethod.Id, await stripeAdapter.AttachPaymentMethodAsync(paymentMethod.Id,
new PaymentMethodAttachOptions { Customer = customerId }); new PaymentMethodAttachOptions { Customer = customerId });
await stripeAdapter.CustomerUpdateAsync(customerId, new CustomerUpdateOptions await stripeAdapter.UpdateCustomerAsync(customerId, new CustomerUpdateOptions
{ {
InvoiceSettings = new CustomerInvoiceSettingsOptions InvoiceSettings = new CustomerInvoiceSettingsOptions
{ {

View File

@@ -2,6 +2,7 @@
using Bit.Core.AdminConsole.Models.Business; using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
@@ -18,7 +19,7 @@ public class ImportOrganizationUsersAndGroupsCommand : IImportOrganizationUsersA
{ {
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IGroupRepository _groupRepository; private readonly IGroupRepository _groupRepository;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly IOrganizationService _organizationService; private readonly IOrganizationService _organizationService;
@@ -27,7 +28,7 @@ public class ImportOrganizationUsersAndGroupsCommand : IImportOrganizationUsersA
public ImportOrganizationUsersAndGroupsCommand(IOrganizationRepository organizationRepository, public ImportOrganizationUsersAndGroupsCommand(IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
IGroupRepository groupRepository, IGroupRepository groupRepository,
IEventService eventService, IEventService eventService,
IOrganizationService organizationService) IOrganizationService organizationService)

View File

@@ -2,10 +2,10 @@
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
using Bit.Core.AdminConsole.Utilities.Errors; using Bit.Core.AdminConsole.Utilities.Errors;
using Bit.Core.AdminConsole.Utilities.Validation; using Bit.Core.AdminConsole.Utilities.Validation;
using Bit.Core.Billing.Services;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
@@ -15,7 +15,7 @@ public class InviteOrganizationUsersValidator(
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IInviteUsersPasswordManagerValidator inviteUsersPasswordManagerValidator, IInviteUsersPasswordManagerValidator inviteUsersPasswordManagerValidator,
IUpdateSecretsManagerSubscriptionCommand secretsManagerSubscriptionCommand, IUpdateSecretsManagerSubscriptionCommand secretsManagerSubscriptionCommand,
IPaymentService paymentService) : IInviteUsersValidator IStripePaymentService paymentService) : IInviteUsersValidator
{ {
public async Task<ValidationResult<InviteOrganizationUsersValidationRequest>> ValidateAsync( public async Task<ValidationResult<InviteOrganizationUsersValidationRequest>> ValidateAsync(
InviteOrganizationUsersValidationRequest request) InviteOrganizationUsersValidationRequest request)

View File

@@ -9,8 +9,8 @@ using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.V
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Provider; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Provider;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Utilities.Validation; using Bit.Core.AdminConsole.Utilities.Validation;
using Bit.Core.Billing.Services;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
@@ -22,7 +22,7 @@ public class InviteUsersPasswordManagerValidator(
IInviteUsersEnvironmentValidator inviteUsersEnvironmentValidator, IInviteUsersEnvironmentValidator inviteUsersEnvironmentValidator,
IInviteUsersOrganizationValidator inviteUsersOrganizationValidator, IInviteUsersOrganizationValidator inviteUsersOrganizationValidator,
IProviderRepository providerRepository, IProviderRepository providerRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
IOrganizationRepository organizationRepository IOrganizationRepository organizationRepository
) : IInviteUsersPasswordManagerValidator ) : IInviteUsersPasswordManagerValidator
{ {

View File

@@ -8,6 +8,7 @@ using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Organizations.Models; using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Organizations.Services; using Bit.Core.Billing.Organizations.Services;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
@@ -33,7 +34,7 @@ public interface ICloudOrganizationSignUpCommand
public class CloudOrganizationSignUpCommand( public class CloudOrganizationSignUpCommand(
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IOrganizationBillingService organizationBillingService, IOrganizationBillingService organizationBillingService,
IPaymentService paymentService, IStripePaymentService paymentService,
IPolicyService policyService, IPolicyService policyService,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IOrganizationApiKeyRepository organizationApiKeyRepository, IOrganizationApiKeyRepository organizationApiKeyRepository,

View File

@@ -2,6 +2,7 @@
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Repositories; using Bit.Core.Auth.Repositories;
using Bit.Core.Billing.Services;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
@@ -12,13 +13,13 @@ public class OrganizationDeleteCommand : IOrganizationDeleteCommand
{ {
private readonly IApplicationCacheService _applicationCacheService; private readonly IApplicationCacheService _applicationCacheService;
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly ISsoConfigRepository _ssoConfigRepository; private readonly ISsoConfigRepository _ssoConfigRepository;
public OrganizationDeleteCommand( public OrganizationDeleteCommand(
IApplicationCacheService applicationCacheService, IApplicationCacheService applicationCacheService,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
ISsoConfigRepository ssoConfigRepository) ISsoConfigRepository ssoConfigRepository)
{ {
_applicationCacheService = applicationCacheService; _applicationCacheService = applicationCacheService;

View File

@@ -1,6 +1,7 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@@ -39,7 +40,7 @@ public class ResellerClientOrganizationSignUpCommand : IResellerClientOrganizati
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly ISendOrganizationInvitesCommand _sendOrganizationInvitesCommand; private readonly ISendOrganizationInvitesCommand _sendOrganizationInvitesCommand;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
public ResellerClientOrganizationSignUpCommand( public ResellerClientOrganizationSignUpCommand(
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
@@ -48,7 +49,7 @@ public class ResellerClientOrganizationSignUpCommand : IResellerClientOrganizati
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IEventService eventService, IEventService eventService,
ISendOrganizationInvitesCommand sendOrganizationInvitesCommand, ISendOrganizationInvitesCommand sendOrganizationInvitesCommand,
IPaymentService paymentService) IStripePaymentService paymentService)
{ {
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_organizationApiKeyRepository = organizationApiKeyRepository; _organizationApiKeyRepository = organizationApiKeyRepository;

View File

@@ -30,7 +30,7 @@ public class SelfHostedOrganizationSignUpCommand : ISelfHostedOrganizationSignUp
private readonly ILicensingService _licensingService; private readonly ILicensingService _licensingService;
private readonly IPolicyService _policyService; private readonly IPolicyService _policyService;
private readonly IGlobalSettings _globalSettings; private readonly IGlobalSettings _globalSettings;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
public SelfHostedOrganizationSignUpCommand( public SelfHostedOrganizationSignUpCommand(
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
@@ -44,7 +44,7 @@ public class SelfHostedOrganizationSignUpCommand : ISelfHostedOrganizationSignUp
ILicensingService licensingService, ILicensingService licensingService,
IPolicyService policyService, IPolicyService policyService,
IGlobalSettings globalSettings, IGlobalSettings globalSettings,
IPaymentService paymentService) IStripePaymentService paymentService)
{ {
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository; _organizationUserRepository = organizationUserRepository;

View File

@@ -1,12 +1,12 @@
using Bit.Core.AdminConsole.Models.Data.Organizations; using Bit.Core.AdminConsole.Models.Data.Organizations;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.Billing.Services;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations; namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
public class UpdateOrganizationSubscriptionCommand(IPaymentService paymentService, public class UpdateOrganizationSubscriptionCommand(IStripePaymentService paymentService,
IOrganizationRepository repository, IOrganizationRepository repository,
TimeProvider timeProvider, TimeProvider timeProvider,
ILogger<UpdateOrganizationSubscriptionCommand> logger) : IUpdateOrganizationSubscriptionCommand ILogger<UpdateOrganizationSubscriptionCommand> logger) : IUpdateOrganizationSubscriptionCommand

View File

@@ -21,6 +21,7 @@ using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Extensions; using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@@ -47,7 +48,7 @@ public class OrganizationService : IOrganizationService
private readonly IPushNotificationService _pushNotificationService; private readonly IPushNotificationService _pushNotificationService;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly IApplicationCacheService _applicationCacheService; private readonly IApplicationCacheService _applicationCacheService;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IPolicyRepository _policyRepository; private readonly IPolicyRepository _policyRepository;
private readonly IPolicyService _policyService; private readonly IPolicyService _policyService;
private readonly ISsoUserRepository _ssoUserRepository; private readonly ISsoUserRepository _ssoUserRepository;
@@ -74,7 +75,7 @@ public class OrganizationService : IOrganizationService
IPushNotificationService pushNotificationService, IPushNotificationService pushNotificationService,
IEventService eventService, IEventService eventService,
IApplicationCacheService applicationCacheService, IApplicationCacheService applicationCacheService,
IPaymentService paymentService, IStripePaymentService paymentService,
IPolicyRepository policyRepository, IPolicyRepository policyRepository,
IPolicyService policyService, IPolicyService policyService,
ISsoUserRepository ssoUserRepository, ISsoUserRepository ssoUserRepository,
@@ -358,7 +359,7 @@ public class OrganizationService : IOrganizationService
{ {
var newDisplayName = organization.DisplayName(); var newDisplayName = organization.DisplayName();
await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, await _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
Email = organization.BillingEmail, Email = organization.BillingEmail,

View File

@@ -7,8 +7,8 @@ using Bit.Core.Billing.Models;
using Bit.Core.Billing.Organizations.Models; using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using OneOf; using OneOf;
using Stripe; using Stripe;
@@ -125,7 +125,7 @@ public class PreviewOrganizationTaxCommand(
options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items }; options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items };
var invoice = await stripeAdapter.InvoiceCreatePreviewAsync(options); var invoice = await stripeAdapter.CreateInvoicePreviewAsync(options);
return GetAmounts(invoice); return GetAmounts(invoice);
}); });
@@ -165,7 +165,7 @@ public class PreviewOrganizationTaxCommand(
options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items }; options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items };
var invoice = await stripeAdapter.InvoiceCreatePreviewAsync(options); var invoice = await stripeAdapter.CreateInvoicePreviewAsync(options);
return GetAmounts(invoice); return GetAmounts(invoice);
} }
else else
@@ -181,7 +181,7 @@ public class PreviewOrganizationTaxCommand(
var options = GetBaseOptions(billingAddress, planChange.Tier != ProductTierType.Families); var options = GetBaseOptions(billingAddress, planChange.Tier != ProductTierType.Families);
var subscription = await stripeAdapter.SubscriptionGetAsync(organization.GatewaySubscriptionId, var subscription = await stripeAdapter.GetSubscriptionAsync(organization.GatewaySubscriptionId,
new SubscriptionGetOptions { Expand = ["customer"] }); new SubscriptionGetOptions { Expand = ["customer"] });
if (subscription.Customer.Discount != null) if (subscription.Customer.Discount != null)
@@ -259,7 +259,7 @@ public class PreviewOrganizationTaxCommand(
options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items }; options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items };
var invoice = await stripeAdapter.InvoiceCreatePreviewAsync(options); var invoice = await stripeAdapter.CreateInvoicePreviewAsync(options);
return GetAmounts(invoice); return GetAmounts(invoice);
} }
}); });
@@ -278,7 +278,7 @@ public class PreviewOrganizationTaxCommand(
return new BadRequest("Organization does not have a subscription."); return new BadRequest("Organization does not have a subscription.");
} }
var subscription = await stripeAdapter.SubscriptionGetAsync(organization.GatewaySubscriptionId, var subscription = await stripeAdapter.GetSubscriptionAsync(organization.GatewaySubscriptionId,
new SubscriptionGetOptions { Expand = ["customer.tax_ids"] }); new SubscriptionGetOptions { Expand = ["customer.tax_ids"] });
var options = GetBaseOptions(subscription.Customer, var options = GetBaseOptions(subscription.Customer,
@@ -336,7 +336,7 @@ public class PreviewOrganizationTaxCommand(
options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items }; options.SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = items };
var invoice = await stripeAdapter.InvoiceCreatePreviewAsync(options); var invoice = await stripeAdapter.CreateInvoicePreviewAsync(options);
return GetAmounts(invoice); return GetAmounts(invoice);
}); });

View File

@@ -22,14 +22,14 @@ public interface IGetCloudOrganizationLicenseQuery
public class GetCloudOrganizationLicenseQuery : IGetCloudOrganizationLicenseQuery public class GetCloudOrganizationLicenseQuery : IGetCloudOrganizationLicenseQuery
{ {
private readonly IInstallationRepository _installationRepository; private readonly IInstallationRepository _installationRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly ILicensingService _licensingService; private readonly ILicensingService _licensingService;
private readonly IProviderRepository _providerRepository; private readonly IProviderRepository _providerRepository;
private readonly IFeatureService _featureService; private readonly IFeatureService _featureService;
public GetCloudOrganizationLicenseQuery( public GetCloudOrganizationLicenseQuery(
IInstallationRepository installationRepository, IInstallationRepository installationRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
ILicensingService licensingService, ILicensingService licensingService,
IProviderRepository providerRepository, IProviderRepository providerRepository,
IFeatureService featureService) IFeatureService featureService)

View File

@@ -9,7 +9,6 @@ using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Payment.Queries; using Bit.Core.Billing.Payment.Queries;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Services;
using Stripe; using Stripe;
using Stripe.Tax; using Stripe.Tax;
@@ -201,7 +200,7 @@ public class GetOrganizationWarningsQuery(
// ReSharper disable once InvertIf // ReSharper disable once InvertIf
if (subscription.Status == SubscriptionStatus.PastDue) if (subscription.Status == SubscriptionStatus.PastDue)
{ {
var openInvoices = await stripeAdapter.InvoiceSearchAsync(new InvoiceSearchOptions var openInvoices = await stripeAdapter.SearchInvoiceAsync(new InvoiceSearchOptions
{ {
Query = $"subscription:'{subscription.Id}' status:'open'" Query = $"subscription:'{subscription.Id}' status:'open'"
}); });
@@ -257,8 +256,8 @@ public class GetOrganizationWarningsQuery(
// Get active and scheduled registrations // Get active and scheduled registrations
var registrations = (await Task.WhenAll( var registrations = (await Task.WhenAll(
stripeAdapter.TaxRegistrationsListAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Active }), stripeAdapter.ListTaxRegistrationsAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Active }),
stripeAdapter.TaxRegistrationsListAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Scheduled }))) stripeAdapter.ListTaxRegistrationsAsync(new RegistrationListOptions { Status = TaxRegistrationStatus.Scheduled })))
.SelectMany(registrations => registrations.Data); .SelectMany(registrations => registrations.Data);
// Find the matching registration for the customer // Find the matching registration for the customer

View File

@@ -14,7 +14,6 @@ using Bit.Core.Billing.Tax.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Braintree; using Braintree;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -161,7 +160,7 @@ public class OrganizationBillingService(
try try
{ {
// Update the subscription in Stripe // Update the subscription in Stripe
await stripeAdapter.SubscriptionUpdateAsync(subscription.Id, updateOptions); await stripeAdapter.UpdateSubscriptionAsync(subscription.Id, updateOptions);
organization.PlanType = newPlan.Type; organization.PlanType = newPlan.Type;
await organizationRepository.ReplaceAsync(organization); await organizationRepository.ReplaceAsync(organization);
} }
@@ -185,7 +184,7 @@ public class OrganizationBillingService(
var newDisplayName = organization.DisplayName(); var newDisplayName = organization.DisplayName();
await stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, await stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
Email = organization.BillingEmail, Email = organization.BillingEmail,
@@ -324,7 +323,7 @@ public class OrganizationBillingService(
case PaymentMethodType.BankAccount: case PaymentMethodType.BankAccount:
{ {
var setupIntent = var setupIntent =
(await stripeAdapter.SetupIntentList(new SetupIntentListOptions { PaymentMethod = paymentMethodToken })) (await stripeAdapter.ListSetupIntentsAsync(new SetupIntentListOptions { PaymentMethod = paymentMethodToken }))
.FirstOrDefault(); .FirstOrDefault();
if (setupIntent == null) if (setupIntent == null)
@@ -358,7 +357,7 @@ public class OrganizationBillingService(
try try
{ {
var customer = await stripeAdapter.CustomerCreateAsync(customerCreateOptions); var customer = await stripeAdapter.CreateCustomerAsync(customerCreateOptions);
organization.Gateway = GatewayType.Stripe; organization.Gateway = GatewayType.Stripe;
organization.GatewayCustomerId = customer.Id; organization.GatewayCustomerId = customer.Id;
@@ -509,7 +508,7 @@ public class OrganizationBillingService(
subscriptionCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }; subscriptionCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
} }
var subscription = await stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions); var subscription = await stripeAdapter.CreateSubscriptionAsync(subscriptionCreateOptions);
organization.GatewaySubscriptionId = subscription.Id; organization.GatewaySubscriptionId = subscription.Id;
await organizationRepository.ReplaceAsync(organization); await organizationRepository.ReplaceAsync(organization);
@@ -537,14 +536,14 @@ public class OrganizationBillingService(
customer = customer switch customer = customer switch
{ {
{ Address.Country: not Core.Constants.CountryAbbreviations.UnitedStates, TaxExempt: not StripeConstants.TaxExempt.Reverse } => await { Address.Country: not Core.Constants.CountryAbbreviations.UnitedStates, TaxExempt: not StripeConstants.TaxExempt.Reverse } => await
stripeAdapter.CustomerUpdateAsync(customer.Id, stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
Expand = expansions, Expand = expansions,
TaxExempt = StripeConstants.TaxExempt.Reverse TaxExempt = StripeConstants.TaxExempt.Reverse
}), }),
{ Address.Country: Core.Constants.CountryAbbreviations.UnitedStates, TaxExempt: StripeConstants.TaxExempt.Reverse } => await { Address.Country: Core.Constants.CountryAbbreviations.UnitedStates, TaxExempt: StripeConstants.TaxExempt.Reverse } => await
stripeAdapter.CustomerUpdateAsync(customer.Id, stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
Expand = expansions, Expand = expansions,
@@ -603,7 +602,7 @@ public class OrganizationBillingService(
} }
} }
}; };
await stripeAdapter.SubscriptionUpdateAsync(organization.GatewaySubscriptionId, options); await stripeAdapter.UpdateSubscriptionAsync(organization.GatewaySubscriptionId, options);
} }
} }

View File

@@ -4,7 +4,6 @@ using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Stripe; using Stripe;
@@ -46,7 +45,7 @@ public class UpdateBillingAddressCommand(
BillingAddress billingAddress) BillingAddress billingAddress)
{ {
var customer = var customer =
await stripeAdapter.CustomerUpdateAsync(subscriber.GatewayCustomerId, await stripeAdapter.UpdateCustomerAsync(subscriber.GatewayCustomerId,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
Address = new AddressOptions Address = new AddressOptions
@@ -71,7 +70,7 @@ public class UpdateBillingAddressCommand(
BillingAddress billingAddress) BillingAddress billingAddress)
{ {
var customer = var customer =
await stripeAdapter.CustomerUpdateAsync(subscriber.GatewayCustomerId, await stripeAdapter.UpdateCustomerAsync(subscriber.GatewayCustomerId,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
Address = new AddressOptions Address = new AddressOptions
@@ -92,7 +91,7 @@ public class UpdateBillingAddressCommand(
await EnableAutomaticTaxAsync(subscriber, customer); await EnableAutomaticTaxAsync(subscriber, customer);
var deleteExistingTaxIds = customer.TaxIds?.Any() ?? false var deleteExistingTaxIds = customer.TaxIds?.Any() ?? false
? customer.TaxIds.Select(taxId => stripeAdapter.TaxIdDeleteAsync(customer.Id, taxId.Id)).ToList() ? customer.TaxIds.Select(taxId => stripeAdapter.DeleteTaxIdAsync(customer.Id, taxId.Id)).ToList()
: []; : [];
if (billingAddress.TaxId == null) if (billingAddress.TaxId == null)
@@ -101,12 +100,12 @@ public class UpdateBillingAddressCommand(
return BillingAddress.From(customer.Address); return BillingAddress.From(customer.Address);
} }
var updatedTaxId = await stripeAdapter.TaxIdCreateAsync(customer.Id, var updatedTaxId = await stripeAdapter.CreateTaxIdAsync(customer.Id,
new TaxIdCreateOptions { Type = billingAddress.TaxId.Code, Value = billingAddress.TaxId.Value }); new TaxIdCreateOptions { Type = billingAddress.TaxId.Code, Value = billingAddress.TaxId.Value });
if (billingAddress.TaxId.Code == StripeConstants.TaxIdType.SpanishNIF) if (billingAddress.TaxId.Code == StripeConstants.TaxIdType.SpanishNIF)
{ {
updatedTaxId = await stripeAdapter.TaxIdCreateAsync(customer.Id, updatedTaxId = await stripeAdapter.CreateTaxIdAsync(customer.Id,
new TaxIdCreateOptions new TaxIdCreateOptions
{ {
Type = StripeConstants.TaxIdType.EUVAT, Type = StripeConstants.TaxIdType.EUVAT,
@@ -130,7 +129,7 @@ public class UpdateBillingAddressCommand(
if (subscription is { AutomaticTax.Enabled: false }) if (subscription is { AutomaticTax.Enabled: false })
{ {
await stripeAdapter.SubscriptionUpdateAsync(subscriber.GatewaySubscriptionId, await stripeAdapter.UpdateSubscriptionAsync(subscriber.GatewaySubscriptionId,
new SubscriptionUpdateOptions new SubscriptionUpdateOptions
{ {
AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true } AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }

View File

@@ -4,7 +4,6 @@ using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Braintree; using Braintree;
@@ -56,7 +55,7 @@ public class UpdatePaymentMethodCommand(
if (billingAddress != null && customer.Address is not { Country: not null, PostalCode: not null }) if (billingAddress != null && customer.Address is not { Country: not null, PostalCode: not null })
{ {
await stripeAdapter.CustomerUpdateAsync(customer.Id, await stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
Address = new AddressOptions Address = new AddressOptions
@@ -75,7 +74,7 @@ public class UpdatePaymentMethodCommand(
Customer customer, Customer customer,
string token) string token)
{ {
var setupIntents = await stripeAdapter.SetupIntentList(new SetupIntentListOptions var setupIntents = await stripeAdapter.ListSetupIntentsAsync(new SetupIntentListOptions
{ {
Expand = ["data.payment_method"], Expand = ["data.payment_method"],
PaymentMethod = token PaymentMethod = token
@@ -104,9 +103,9 @@ public class UpdatePaymentMethodCommand(
Customer customer, Customer customer,
string token) string token)
{ {
var paymentMethod = await stripeAdapter.PaymentMethodAttachAsync(token, new PaymentMethodAttachOptions { Customer = customer.Id }); var paymentMethod = await stripeAdapter.AttachPaymentMethodAsync(token, new PaymentMethodAttachOptions { Customer = customer.Id });
await stripeAdapter.CustomerUpdateAsync(customer.Id, await stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions new CustomerUpdateOptions
{ {
InvoiceSettings = new CustomerInvoiceSettingsOptions { DefaultPaymentMethod = token } InvoiceSettings = new CustomerInvoiceSettingsOptions { DefaultPaymentMethod = token }
@@ -139,7 +138,7 @@ public class UpdatePaymentMethodCommand(
[StripeConstants.MetadataKeys.BraintreeCustomerId] = braintreeCustomer.Id [StripeConstants.MetadataKeys.BraintreeCustomerId] = braintreeCustomer.Id
}; };
await stripeAdapter.CustomerUpdateAsync(customer.Id, new CustomerUpdateOptions { Metadata = metadata }); await stripeAdapter.UpdateCustomerAsync(customer.Id, new CustomerUpdateOptions { Metadata = metadata });
} }
var payPalAccount = braintreeCustomer.DefaultPaymentMethod as PayPalAccount; var payPalAccount = braintreeCustomer.DefaultPaymentMethod as PayPalAccount;
@@ -204,7 +203,7 @@ public class UpdatePaymentMethodCommand(
[StripeConstants.MetadataKeys.BraintreeCustomerId] = string.Empty [StripeConstants.MetadataKeys.BraintreeCustomerId] = string.Empty
}; };
await stripeAdapter.CustomerUpdateAsync(customer.Id, new CustomerUpdateOptions { Metadata = metadata }); await stripeAdapter.UpdateCustomerAsync(customer.Id, new CustomerUpdateOptions { Metadata = metadata });
} }
} }
} }

View File

@@ -4,7 +4,6 @@ using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Services;
using Braintree; using Braintree;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Stripe; using Stripe;
@@ -53,7 +52,7 @@ public class GetPaymentMethodQuery(
if (!string.IsNullOrEmpty(setupIntentId)) if (!string.IsNullOrEmpty(setupIntentId))
{ {
var setupIntent = await stripeAdapter.SetupIntentGet(setupIntentId, new SetupIntentGetOptions var setupIntent = await stripeAdapter.GetSetupIntentAsync(setupIntentId, new SetupIntentGetOptions
{ {
Expand = ["payment_method"] Expand = ["payment_method"]
}); });

View File

@@ -3,7 +3,6 @@ using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Extensions; using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Services;
using Stripe; using Stripe;
namespace Bit.Core.Billing.Payment.Queries; namespace Bit.Core.Billing.Payment.Queries;
@@ -48,7 +47,7 @@ public class HasPaymentMethodQuery(
return false; return false;
} }
var setupIntent = await stripeAdapter.SetupIntentGet(setupIntentId, new SetupIntentGetOptions var setupIntent = await stripeAdapter.GetSetupIntentAsync(setupIntentId, new SetupIntentGetOptions
{ {
Expand = ["payment_method"] Expand = ["payment_method"]
}); });

View File

@@ -210,7 +210,7 @@ public class CreatePremiumCloudHostedSubscriptionCommand(
case TokenizablePaymentMethodType.BankAccount: case TokenizablePaymentMethodType.BankAccount:
{ {
var setupIntent = var setupIntent =
(await stripeAdapter.SetupIntentList(new SetupIntentListOptions { PaymentMethod = tokenizedPaymentMethod.Token })) (await stripeAdapter.ListSetupIntentsAsync(new SetupIntentListOptions { PaymentMethod = tokenizedPaymentMethod.Token }))
.FirstOrDefault(); .FirstOrDefault();
if (setupIntent == null) if (setupIntent == null)
@@ -243,7 +243,7 @@ public class CreatePremiumCloudHostedSubscriptionCommand(
try try
{ {
return await stripeAdapter.CustomerCreateAsync(customerCreateOptions); return await stripeAdapter.CreateCustomerAsync(customerCreateOptions);
} }
catch catch
{ {
@@ -300,7 +300,7 @@ public class CreatePremiumCloudHostedSubscriptionCommand(
ValidateLocation = ValidateTaxLocationTiming.Immediately ValidateLocation = ValidateTaxLocationTiming.Immediately
} }
}; };
return await stripeAdapter.CustomerUpdateAsync(customer.Id, options); return await stripeAdapter.UpdateCustomerAsync(customer.Id, options);
} }
private async Task<Subscription> CreateSubscriptionAsync( private async Task<Subscription> CreateSubscriptionAsync(
@@ -349,11 +349,11 @@ public class CreatePremiumCloudHostedSubscriptionCommand(
OffSession = true OffSession = true
}; };
var subscription = await stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions); var subscription = await stripeAdapter.CreateSubscriptionAsync(subscriptionCreateOptions);
if (usingPayPal) if (usingPayPal)
{ {
await stripeAdapter.InvoiceUpdateAsync(subscription.LatestInvoiceId, new InvoiceUpdateOptions await stripeAdapter.UpdateInvoiceAsync(subscription.LatestInvoiceId, new InvoiceUpdateOptions
{ {
AutoAdvance = false AutoAdvance = false
}); });

View File

@@ -1,7 +1,7 @@
using Bit.Core.Billing.Commands; using Bit.Core.Billing.Commands;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Services; using Bit.Core.Billing.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Stripe; using Stripe;
@@ -56,7 +56,7 @@ public class PreviewPremiumTaxCommand(
}); });
} }
var invoice = await stripeAdapter.InvoiceCreatePreviewAsync(options); var invoice = await stripeAdapter.CreateInvoicePreviewAsync(options);
return GetAmounts(invoice); return GetAmounts(invoice);
}); });

View File

@@ -0,0 +1,50 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
using Bit.Core.Models.BitStripe;
using Stripe;
using Stripe.Tax;
namespace Bit.Core.Billing.Services;
public interface IStripeAdapter
{
Task<Customer> CreateCustomerAsync(CustomerCreateOptions customerCreateOptions);
Task<Customer> GetCustomerAsync(string id, CustomerGetOptions options = null);
Task<Customer> UpdateCustomerAsync(string id, CustomerUpdateOptions options = null);
Task<Customer> DeleteCustomerAsync(string id);
Task<List<PaymentMethod>> ListCustomerPaymentMethodsAsync(string id, CustomerPaymentMethodListOptions options = null);
Task<CustomerBalanceTransaction> CreateCustomerBalanceTransactionAsync(string customerId,
CustomerBalanceTransactionCreateOptions options);
Task<Subscription> CreateSubscriptionAsync(SubscriptionCreateOptions subscriptionCreateOptions);
Task<Subscription> GetSubscriptionAsync(string id, SubscriptionGetOptions options = null);
Task<StripeList<Registration>> ListTaxRegistrationsAsync(RegistrationListOptions options = null);
Task DeleteCustomerDiscountAsync(string customerId, CustomerDeleteDiscountOptions options = null);
Task<Subscription> UpdateSubscriptionAsync(string id, SubscriptionUpdateOptions options = null);
Task<Subscription> CancelSubscriptionAsync(string id, SubscriptionCancelOptions options = null);
Task<Invoice> GetInvoiceAsync(string id, InvoiceGetOptions options);
Task<List<Invoice>> ListInvoicesAsync(StripeInvoiceListOptions options);
Task<Invoice> CreateInvoicePreviewAsync(InvoiceCreatePreviewOptions options);
Task<List<Invoice>> SearchInvoiceAsync(InvoiceSearchOptions options);
Task<Invoice> UpdateInvoiceAsync(string id, InvoiceUpdateOptions options);
Task<Invoice> FinalizeInvoiceAsync(string id, InvoiceFinalizeOptions options);
Task<Invoice> SendInvoiceAsync(string id, InvoiceSendOptions options);
Task<Invoice> PayInvoiceAsync(string id, InvoicePayOptions options = null);
Task<Invoice> DeleteInvoiceAsync(string id, InvoiceDeleteOptions options = null);
Task<Invoice> VoidInvoiceAsync(string id, InvoiceVoidOptions options = null);
IEnumerable<PaymentMethod> ListPaymentMethodsAutoPaging(PaymentMethodListOptions options);
IAsyncEnumerable<PaymentMethod> ListPaymentMethodsAutoPagingAsync(PaymentMethodListOptions options);
Task<PaymentMethod> AttachPaymentMethodAsync(string id, PaymentMethodAttachOptions options = null);
Task<PaymentMethod> DetachPaymentMethodAsync(string id, PaymentMethodDetachOptions options = null);
Task<TaxId> CreateTaxIdAsync(string id, TaxIdCreateOptions options);
Task<TaxId> DeleteTaxIdAsync(string customerId, string taxIdId, TaxIdDeleteOptions options = null);
Task<StripeList<Charge>> ListChargesAsync(ChargeListOptions options);
Task<Refund> CreateRefundAsync(RefundCreateOptions options);
Task<Card> DeleteCardAsync(string customerId, string cardId, CardDeleteOptions options = null);
Task<BankAccount> DeleteBankAccountAsync(string customerId, string bankAccount, BankAccountDeleteOptions options = null);
Task<SetupIntent> CreateSetupIntentAsync(SetupIntentCreateOptions options);
Task<List<SetupIntent>> ListSetupIntentsAsync(SetupIntentListOptions options);
Task CancelSetupIntentAsync(string id, SetupIntentCancelOptions options = null);
Task<SetupIntent> GetSetupIntentAsync(string id, SetupIntentGetOptions options = null);
Task<Price> GetPriceAsync(string id, PriceGetOptions options = null);
}

View File

@@ -8,9 +8,9 @@ using Bit.Core.Entities;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.StaticStore; using Bit.Core.Models.StaticStore;
namespace Bit.Core.Services; namespace Bit.Core.Billing.Services;
public interface IPaymentService public interface IStripePaymentService
{ {
Task CancelAndRecoverChargesAsync(ISubscriber subscriber); Task CancelAndRecoverChargesAsync(ISubscriber subscriber);
Task SponsorOrganizationAsync(Organization org, OrganizationSponsorship sponsorship); Task SponsorOrganizationAsync(Organization org, OrganizationSponsorship sponsorship);

View File

@@ -0,0 +1,6 @@
namespace Bit.Core.Billing.Services;
public interface IStripeSyncService
{
Task UpdateCustomerEmailAddressAsync(string gatewayCustomerId, string emailAddress);
}

View File

@@ -4,7 +4,6 @@ using Bit.Core.Billing.Models;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Models.BitStripe; using Bit.Core.Models.BitStripe;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
namespace Bit.Core.Billing.Services.Implementations; namespace Bit.Core.Billing.Services.Implementations;
@@ -23,7 +22,7 @@ public class PaymentHistoryService(
return Array.Empty<BillingHistoryInfo.BillingInvoice>(); return Array.Empty<BillingHistoryInfo.BillingInvoice>();
} }
var invoices = await stripeAdapter.InvoiceListAsync(new StripeInvoiceListOptions var invoices = await stripeAdapter.ListInvoicesAsync(new StripeInvoiceListOptions
{ {
Customer = subscriber.GatewayCustomerId, Customer = subscriber.GatewayCustomerId,
Limit = pageSize, Limit = pageSize,

View File

@@ -12,7 +12,6 @@ using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Braintree; using Braintree;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -68,7 +67,7 @@ public class PremiumUserBillingService(
} }
}; };
customer = await stripeAdapter.CustomerCreateAsync(options); customer = await stripeAdapter.CreateCustomerAsync(options);
user.Gateway = GatewayType.Stripe; user.Gateway = GatewayType.Stripe;
user.GatewayCustomerId = customer.Id; user.GatewayCustomerId = customer.Id;
@@ -81,7 +80,7 @@ public class PremiumUserBillingService(
Balance = customer.Balance + credit Balance = customer.Balance + credit
}; };
await stripeAdapter.CustomerUpdateAsync(customer.Id, options); await stripeAdapter.UpdateCustomerAsync(customer.Id, options);
} }
} }
@@ -227,7 +226,7 @@ public class PremiumUserBillingService(
case PaymentMethodType.BankAccount: case PaymentMethodType.BankAccount:
{ {
var setupIntent = var setupIntent =
(await stripeAdapter.SetupIntentList(new SetupIntentListOptions { PaymentMethod = paymentMethodToken })) (await stripeAdapter.ListSetupIntentsAsync(new SetupIntentListOptions { PaymentMethod = paymentMethodToken }))
.FirstOrDefault(); .FirstOrDefault();
if (setupIntent == null) if (setupIntent == null)
@@ -260,7 +259,7 @@ public class PremiumUserBillingService(
try try
{ {
return await stripeAdapter.CustomerCreateAsync(customerCreateOptions); return await stripeAdapter.CreateCustomerAsync(customerCreateOptions);
} }
catch (StripeException stripeException) when (stripeException.StripeError?.Code == catch (StripeException stripeException) when (stripeException.StripeError?.Code ==
StripeConstants.ErrorCodes.CustomerTaxLocationInvalid) StripeConstants.ErrorCodes.CustomerTaxLocationInvalid)
@@ -347,11 +346,11 @@ public class PremiumUserBillingService(
OffSession = true OffSession = true
}; };
var subscription = await stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions); var subscription = await stripeAdapter.CreateSubscriptionAsync(subscriptionCreateOptions);
if (usingPayPal) if (usingPayPal)
{ {
await stripeAdapter.InvoiceUpdateAsync(subscription.LatestInvoiceId, new InvoiceUpdateOptions await stripeAdapter.UpdateInvoiceAsync(subscription.LatestInvoiceId, new InvoiceUpdateOptions
{ {
AutoAdvance = false AutoAdvance = false
}); });
@@ -387,6 +386,6 @@ public class PremiumUserBillingService(
} }
}; };
return await stripeAdapter.CustomerUpdateAsync(customer.Id, options); return await stripeAdapter.UpdateCustomerAsync(customer.Id, options);
} }
} }

View File

@@ -0,0 +1,209 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
using Bit.Core.Models.BitStripe;
using Stripe;
using Stripe.Tax;
using Stripe.TestHelpers;
using CustomerService = Stripe.CustomerService;
using RefundService = Stripe.RefundService;
namespace Bit.Core.Billing.Services.Implementations;
public class StripeAdapter : IStripeAdapter
{
private readonly CustomerService _customerService;
private readonly SubscriptionService _subscriptionService;
private readonly InvoiceService _invoiceService;
private readonly PaymentMethodService _paymentMethodService;
private readonly TaxIdService _taxIdService;
private readonly ChargeService _chargeService;
private readonly RefundService _refundService;
private readonly CardService _cardService;
private readonly BankAccountService _bankAccountService;
private readonly PriceService _priceService;
private readonly SetupIntentService _setupIntentService;
private readonly TestClockService _testClockService;
private readonly CustomerBalanceTransactionService _customerBalanceTransactionService;
private readonly RegistrationService _taxRegistrationService;
public StripeAdapter()
{
_customerService = new CustomerService();
_subscriptionService = new SubscriptionService();
_invoiceService = new InvoiceService();
_paymentMethodService = new PaymentMethodService();
_taxIdService = new TaxIdService();
_chargeService = new ChargeService();
_refundService = new RefundService();
_cardService = new CardService();
_bankAccountService = new BankAccountService();
_priceService = new PriceService();
_setupIntentService = new SetupIntentService();
_testClockService = new TestClockService();
_customerBalanceTransactionService = new CustomerBalanceTransactionService();
_taxRegistrationService = new RegistrationService();
}
/**************
** CUSTOMER **
**************/
public Task<Customer> CreateCustomerAsync(CustomerCreateOptions options) =>
_customerService.CreateAsync(options);
public Task DeleteCustomerDiscountAsync(string customerId, CustomerDeleteDiscountOptions options = null) =>
_customerService.DeleteDiscountAsync(customerId, options);
public Task<Customer> GetCustomerAsync(string id, CustomerGetOptions options = null) =>
_customerService.GetAsync(id, options);
public Task<Customer> UpdateCustomerAsync(string id, CustomerUpdateOptions options = null) =>
_customerService.UpdateAsync(id, options);
public Task<Customer> DeleteCustomerAsync(string id) =>
_customerService.DeleteAsync(id);
public async Task<List<PaymentMethod>> ListCustomerPaymentMethodsAsync(string id,
CustomerPaymentMethodListOptions options = null)
{
var paymentMethods = await _customerService.ListPaymentMethodsAsync(id, options);
return paymentMethods.Data;
}
public Task<CustomerBalanceTransaction> CreateCustomerBalanceTransactionAsync(string customerId,
CustomerBalanceTransactionCreateOptions options) =>
_customerBalanceTransactionService.CreateAsync(customerId, options);
/******************
** SUBSCRIPTION **
******************/
public Task<Subscription> CreateSubscriptionAsync(SubscriptionCreateOptions options) =>
_subscriptionService.CreateAsync(options);
public Task<Subscription> GetSubscriptionAsync(string id, SubscriptionGetOptions options = null) =>
_subscriptionService.GetAsync(id, options);
public Task<Subscription> UpdateSubscriptionAsync(string id,
SubscriptionUpdateOptions options = null) =>
_subscriptionService.UpdateAsync(id, options);
public Task<Subscription> CancelSubscriptionAsync(string id, SubscriptionCancelOptions options = null) =>
_subscriptionService.CancelAsync(id, options);
/*************
** INVOICE **
*************/
public Task<Invoice> GetInvoiceAsync(string id, InvoiceGetOptions options) =>
_invoiceService.GetAsync(id, options);
public async Task<List<Invoice>> ListInvoicesAsync(StripeInvoiceListOptions options)
{
if (!options.SelectAll)
{
return (await _invoiceService.ListAsync(options.ToInvoiceListOptions())).Data;
}
options.Limit = 100;
var invoices = new List<Invoice>();
await foreach (var invoice in _invoiceService.ListAutoPagingAsync(options.ToInvoiceListOptions()))
{
invoices.Add(invoice);
}
return invoices;
}
public Task<Invoice> CreateInvoicePreviewAsync(InvoiceCreatePreviewOptions options) =>
_invoiceService.CreatePreviewAsync(options);
public async Task<List<Invoice>> SearchInvoiceAsync(InvoiceSearchOptions options) =>
(await _invoiceService.SearchAsync(options)).Data;
public Task<Invoice> UpdateInvoiceAsync(string id, InvoiceUpdateOptions options) =>
_invoiceService.UpdateAsync(id, options);
public Task<Invoice> FinalizeInvoiceAsync(string id, InvoiceFinalizeOptions options) =>
_invoiceService.FinalizeInvoiceAsync(id, options);
public Task<Invoice> SendInvoiceAsync(string id, InvoiceSendOptions options) =>
_invoiceService.SendInvoiceAsync(id, options);
public Task<Invoice> PayInvoiceAsync(string id, InvoicePayOptions options = null) =>
_invoiceService.PayAsync(id, options);
public Task<Invoice> DeleteInvoiceAsync(string id, InvoiceDeleteOptions options = null) =>
_invoiceService.DeleteAsync(id, options);
public Task<Invoice> VoidInvoiceAsync(string id, InvoiceVoidOptions options = null) =>
_invoiceService.VoidInvoiceAsync(id, options);
/********************
** PAYMENT METHOD **
********************/
public IEnumerable<PaymentMethod> ListPaymentMethodsAutoPaging(PaymentMethodListOptions options) =>
_paymentMethodService.ListAutoPaging(options);
public IAsyncEnumerable<PaymentMethod> ListPaymentMethodsAutoPagingAsync(PaymentMethodListOptions options)
=> _paymentMethodService.ListAutoPagingAsync(options);
public Task<PaymentMethod> AttachPaymentMethodAsync(string id, PaymentMethodAttachOptions options = null) =>
_paymentMethodService.AttachAsync(id, options);
public Task<PaymentMethod> DetachPaymentMethodAsync(string id, PaymentMethodDetachOptions options = null) =>
_paymentMethodService.DetachAsync(id, options);
/************
** TAX ID **
************/
public Task<TaxId> CreateTaxIdAsync(string id, TaxIdCreateOptions options) =>
_taxIdService.CreateAsync(id, options);
public Task<TaxId> DeleteTaxIdAsync(string customerId, string taxIdId,
TaxIdDeleteOptions options = null) =>
_taxIdService.DeleteAsync(customerId, taxIdId, options);
/******************
** BANK ACCOUNT **
******************/
public Task<BankAccount> DeleteBankAccountAsync(string customerId, string bankAccount, BankAccountDeleteOptions options = null) =>
_bankAccountService.DeleteAsync(customerId, bankAccount, options);
/***********
** PRICE **
***********/
public Task<Price> GetPriceAsync(string id, PriceGetOptions options = null) =>
_priceService.GetAsync(id, options);
/******************
** SETUP INTENT **
******************/
public Task<SetupIntent> CreateSetupIntentAsync(SetupIntentCreateOptions options) =>
_setupIntentService.CreateAsync(options);
public async Task<List<SetupIntent>> ListSetupIntentsAsync(SetupIntentListOptions options) =>
(await _setupIntentService.ListAsync(options)).Data;
public Task CancelSetupIntentAsync(string id, SetupIntentCancelOptions options = null) =>
_setupIntentService.CancelAsync(id, options);
public Task<SetupIntent> GetSetupIntentAsync(string id, SetupIntentGetOptions options = null) =>
_setupIntentService.GetAsync(id, options);
/*******************
** MISCELLANEOUS **
*******************/
public Task<StripeList<Charge>> ListChargesAsync(ChargeListOptions options) =>
_chargeService.ListAsync(options);
public Task<StripeList<Registration>> ListTaxRegistrationsAsync(RegistrationListOptions options = null) =>
_taxRegistrationService.ListAsync(options);
public Task<Refund> CreateRefundAsync(RefundCreateOptions options) =>
_refundService.CreateAsync(options);
public Task<Card> DeleteCardAsync(string customerId, string cardId, CardDeleteOptions options = null) =>
_cardService.DeleteAsync(customerId, cardId, options);
}

View File

@@ -21,9 +21,9 @@ using Stripe;
using PaymentMethod = Stripe.PaymentMethod; using PaymentMethod = Stripe.PaymentMethod;
using StaticStore = Bit.Core.Models.StaticStore; using StaticStore = Bit.Core.Models.StaticStore;
namespace Bit.Core.Services; namespace Bit.Core.Billing.Services.Implementations;
public class StripePaymentService : IPaymentService public class StripePaymentService : IStripePaymentService
{ {
private const string SecretsManagerStandaloneDiscountId = "sm-standalone"; private const string SecretsManagerStandaloneDiscountId = "sm-standalone";
@@ -64,7 +64,7 @@ public class StripePaymentService : IPaymentService
await FinalizeSubscriptionChangeAsync(org, subscriptionUpdate, true); await FinalizeSubscriptionChangeAsync(org, subscriptionUpdate, true);
var sub = await _stripeAdapter.SubscriptionGetAsync(org.GatewaySubscriptionId); var sub = await _stripeAdapter.GetSubscriptionAsync(org.GatewaySubscriptionId);
org.ExpirationDate = sub.GetCurrentPeriodEnd(); org.ExpirationDate = sub.GetCurrentPeriodEnd();
if (sponsorship is not null) if (sponsorship is not null)
@@ -84,7 +84,7 @@ public class StripePaymentService : IPaymentService
{ {
// remember, when in doubt, throw // remember, when in doubt, throw
var subGetOptions = new SubscriptionGetOptions { Expand = ["customer.tax", "customer.tax_ids"] }; var subGetOptions = new SubscriptionGetOptions { Expand = ["customer.tax", "customer.tax_ids"] };
var sub = await _stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subGetOptions); var sub = await _stripeAdapter.GetSubscriptionAsync(subscriber.GatewaySubscriptionId, subGetOptions);
if (sub == null) if (sub == null)
{ {
throw new GatewayException("Subscription not found."); throw new GatewayException("Subscription not found.");
@@ -107,7 +107,7 @@ public class StripePaymentService : IPaymentService
var subUpdateOptions = new SubscriptionUpdateOptions var subUpdateOptions = new SubscriptionUpdateOptions
{ {
Items = updatedItemOptions, Items = updatedItemOptions,
ProrationBehavior = invoiceNow ? Constants.AlwaysInvoice : Constants.CreateProrations, ProrationBehavior = invoiceNow ? Core.Constants.AlwaysInvoice : Core.Constants.CreateProrations,
DaysUntilDue = daysUntilDue ?? 1, DaysUntilDue = daysUntilDue ?? 1,
CollectionMethod = "send_invoice" CollectionMethod = "send_invoice"
}; };
@@ -121,11 +121,11 @@ public class StripePaymentService : IPaymentService
{ {
if (sub.Customer is if (sub.Customer is
{ {
Address.Country: not Constants.CountryAbbreviations.UnitedStates, Address.Country: not Core.Constants.CountryAbbreviations.UnitedStates,
TaxExempt: not StripeConstants.TaxExempt.Reverse TaxExempt: not StripeConstants.TaxExempt.Reverse
}) })
{ {
await _stripeAdapter.CustomerUpdateAsync(sub.CustomerId, await _stripeAdapter.UpdateCustomerAsync(sub.CustomerId,
new CustomerUpdateOptions { TaxExempt = StripeConstants.TaxExempt.Reverse }); new CustomerUpdateOptions { TaxExempt = StripeConstants.TaxExempt.Reverse });
} }
@@ -141,9 +141,9 @@ public class StripePaymentService : IPaymentService
string paymentIntentClientSecret = null; string paymentIntentClientSecret = null;
try try
{ {
var subResponse = await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, subUpdateOptions); var subResponse = await _stripeAdapter.UpdateSubscriptionAsync(sub.Id, subUpdateOptions);
var invoice = await _stripeAdapter.InvoiceGetAsync(subResponse?.LatestInvoiceId, new InvoiceGetOptions()); var invoice = await _stripeAdapter.GetInvoiceAsync(subResponse?.LatestInvoiceId, new InvoiceGetOptions());
if (invoice == null) if (invoice == null)
{ {
throw new BadRequestException("Unable to locate draft invoice for subscription update."); throw new BadRequestException("Unable to locate draft invoice for subscription update.");
@@ -162,9 +162,9 @@ public class StripePaymentService : IPaymentService
} }
else else
{ {
invoice = await _stripeAdapter.InvoiceFinalizeInvoiceAsync(subResponse.LatestInvoiceId, invoice = await _stripeAdapter.FinalizeInvoiceAsync(subResponse.LatestInvoiceId,
new InvoiceFinalizeOptions { AutoAdvance = false, }); new InvoiceFinalizeOptions { AutoAdvance = false, });
await _stripeAdapter.InvoiceSendInvoiceAsync(invoice.Id, new InvoiceSendOptions()); await _stripeAdapter.SendInvoiceAsync(invoice.Id, new InvoiceSendOptions());
paymentIntentClientSecret = null; paymentIntentClientSecret = null;
} }
} }
@@ -172,7 +172,7 @@ public class StripePaymentService : IPaymentService
catch catch
{ {
// Need to revert the subscription // Need to revert the subscription
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new SubscriptionUpdateOptions await _stripeAdapter.UpdateSubscriptionAsync(sub.Id, new SubscriptionUpdateOptions
{ {
Items = subscriptionUpdate.RevertItemsOptions(sub), Items = subscriptionUpdate.RevertItemsOptions(sub),
// This proration behavior prevents a false "credit" from // This proration behavior prevents a false "credit" from
@@ -187,7 +187,7 @@ public class StripePaymentService : IPaymentService
else if (invoice.Status != StripeConstants.InvoiceStatus.Paid) else if (invoice.Status != StripeConstants.InvoiceStatus.Paid)
{ {
// Pay invoice with no charge to the customer this completes the invoice immediately without waiting the scheduled 1h // Pay invoice with no charge to the customer this completes the invoice immediately without waiting the scheduled 1h
invoice = await _stripeAdapter.InvoicePayAsync(subResponse.LatestInvoiceId); invoice = await _stripeAdapter.PayInvoiceAsync(subResponse.LatestInvoiceId);
paymentIntentClientSecret = null; paymentIntentClientSecret = null;
} }
} }
@@ -196,7 +196,7 @@ public class StripePaymentService : IPaymentService
// Change back the subscription collection method and/or days until due // Change back the subscription collection method and/or days until due
if (collectionMethod != "send_invoice" || daysUntilDue == null) if (collectionMethod != "send_invoice" || daysUntilDue == null)
{ {
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, await _stripeAdapter.UpdateSubscriptionAsync(sub.Id,
new SubscriptionUpdateOptions new SubscriptionUpdateOptions
{ {
CollectionMethod = collectionMethod, CollectionMethod = collectionMethod,
@@ -204,14 +204,14 @@ public class StripePaymentService : IPaymentService
}); });
} }
var customer = await _stripeAdapter.CustomerGetAsync(sub.CustomerId); var customer = await _stripeAdapter.GetCustomerAsync(sub.CustomerId);
var newCoupon = customer.Discount?.Coupon?.Id; var newCoupon = customer.Discount?.Coupon?.Id;
if (!string.IsNullOrEmpty(existingCoupon) && string.IsNullOrEmpty(newCoupon)) if (!string.IsNullOrEmpty(existingCoupon) && string.IsNullOrEmpty(newCoupon))
{ {
// Re-add the lost coupon due to the update. // Re-add the lost coupon due to the update.
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new SubscriptionUpdateOptions await _stripeAdapter.UpdateSubscriptionAsync(sub.Id, new SubscriptionUpdateOptions
{ {
Discounts = Discounts =
[ [
@@ -284,7 +284,7 @@ public class StripePaymentService : IPaymentService
{ {
if (!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId)) if (!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{ {
await _stripeAdapter.SubscriptionCancelAsync(subscriber.GatewaySubscriptionId, await _stripeAdapter.CancelSubscriptionAsync(subscriber.GatewaySubscriptionId,
new SubscriptionCancelOptions()); new SubscriptionCancelOptions());
} }
@@ -293,7 +293,7 @@ public class StripePaymentService : IPaymentService
return; return;
} }
var customer = await _stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId); var customer = await _stripeAdapter.GetCustomerAsync(subscriber.GatewayCustomerId);
if (customer == null) if (customer == null)
{ {
return; return;
@@ -318,7 +318,7 @@ public class StripePaymentService : IPaymentService
} }
else else
{ {
var charges = await _stripeAdapter.ChargeListAsync(new ChargeListOptions var charges = await _stripeAdapter.ListChargesAsync(new ChargeListOptions
{ {
Customer = subscriber.GatewayCustomerId Customer = subscriber.GatewayCustomerId
}); });
@@ -327,12 +327,12 @@ public class StripePaymentService : IPaymentService
{ {
foreach (var charge in charges.Data.Where(c => c.Captured && !c.Refunded)) foreach (var charge in charges.Data.Where(c => c.Captured && !c.Refunded))
{ {
await _stripeAdapter.RefundCreateAsync(new RefundCreateOptions { Charge = charge.Id }); await _stripeAdapter.CreateRefundAsync(new RefundCreateOptions { Charge = charge.Id });
} }
} }
} }
await _stripeAdapter.CustomerDeleteAsync(subscriber.GatewayCustomerId); await _stripeAdapter.DeleteCustomerAsync(subscriber.GatewayCustomerId);
} }
public async Task<string> PayInvoiceAfterSubscriptionChangeAsync(ISubscriber subscriber, Invoice invoice) public async Task<string> PayInvoiceAfterSubscriptionChangeAsync(ISubscriber subscriber, Invoice invoice)
@@ -340,7 +340,7 @@ public class StripePaymentService : IPaymentService
var customerOptions = new CustomerGetOptions(); var customerOptions = new CustomerGetOptions();
customerOptions.AddExpand("default_source"); customerOptions.AddExpand("default_source");
customerOptions.AddExpand("invoice_settings.default_payment_method"); customerOptions.AddExpand("invoice_settings.default_payment_method");
var customer = await _stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerOptions); var customer = await _stripeAdapter.GetCustomerAsync(subscriber.GatewayCustomerId, customerOptions);
string paymentIntentClientSecret = null; string paymentIntentClientSecret = null;
@@ -360,13 +360,13 @@ public class StripePaymentService : IPaymentService
// We're going to delete this draft invoice, it can't be paid // We're going to delete this draft invoice, it can't be paid
try try
{ {
await _stripeAdapter.InvoiceDeleteAsync(invoice.Id); await _stripeAdapter.DeleteInvoiceAsync(invoice.Id);
} }
catch catch
{ {
await _stripeAdapter.InvoiceFinalizeInvoiceAsync(invoice.Id, await _stripeAdapter.FinalizeInvoiceAsync(invoice.Id,
new InvoiceFinalizeOptions { AutoAdvance = false }); new InvoiceFinalizeOptions { AutoAdvance = false });
await _stripeAdapter.InvoiceVoidInvoiceAsync(invoice.Id); await _stripeAdapter.VoidInvoiceAsync(invoice.Id);
} }
throw new BadRequestException("No payment method is available."); throw new BadRequestException("No payment method is available.");
@@ -379,7 +379,7 @@ public class StripePaymentService : IPaymentService
{ {
// Finalize the invoice (from Draft) w/o auto-advance so we // Finalize the invoice (from Draft) w/o auto-advance so we
// can attempt payment manually. // can attempt payment manually.
invoice = await _stripeAdapter.InvoiceFinalizeInvoiceAsync(invoice.Id, invoice = await _stripeAdapter.FinalizeInvoiceAsync(invoice.Id,
new InvoiceFinalizeOptions { AutoAdvance = false, }); new InvoiceFinalizeOptions { AutoAdvance = false, });
var invoicePayOptions = new InvoicePayOptions { PaymentMethod = cardPaymentMethodId, }; var invoicePayOptions = new InvoicePayOptions { PaymentMethod = cardPaymentMethodId, };
if (customer?.Metadata?.ContainsKey("btCustomerId") ?? false) if (customer?.Metadata?.ContainsKey("btCustomerId") ?? false)
@@ -414,7 +414,7 @@ public class StripePaymentService : IPaymentService
} }
braintreeTransaction = transactionResult.Target; braintreeTransaction = transactionResult.Target;
invoice = await _stripeAdapter.InvoiceUpdateAsync(invoice.Id, new InvoiceUpdateOptions invoice = await _stripeAdapter.UpdateInvoiceAsync(invoice.Id, new InvoiceUpdateOptions
{ {
Metadata = new Dictionary<string, string> Metadata = new Dictionary<string, string>
{ {
@@ -428,7 +428,7 @@ public class StripePaymentService : IPaymentService
try try
{ {
invoice = await _stripeAdapter.InvoicePayAsync(invoice.Id, invoicePayOptions); invoice = await _stripeAdapter.PayInvoiceAsync(invoice.Id, invoicePayOptions);
} }
catch (StripeException e) catch (StripeException e)
{ {
@@ -438,7 +438,7 @@ public class StripePaymentService : IPaymentService
// SCA required, get intent client secret // SCA required, get intent client secret
var invoiceGetOptions = new InvoiceGetOptions(); var invoiceGetOptions = new InvoiceGetOptions();
invoiceGetOptions.AddExpand("confirmation_secret"); invoiceGetOptions.AddExpand("confirmation_secret");
invoice = await _stripeAdapter.InvoiceGetAsync(invoice.Id, invoiceGetOptions); invoice = await _stripeAdapter.GetInvoiceAsync(invoice.Id, invoiceGetOptions);
paymentIntentClientSecret = invoice?.ConfirmationSecret?.ClientSecret; paymentIntentClientSecret = invoice?.ConfirmationSecret?.ClientSecret;
} }
else else
@@ -462,7 +462,7 @@ public class StripePaymentService : IPaymentService
return paymentIntentClientSecret; return paymentIntentClientSecret;
} }
invoice = await _stripeAdapter.InvoiceVoidInvoiceAsync(invoice.Id, new InvoiceVoidOptions()); invoice = await _stripeAdapter.VoidInvoiceAsync(invoice.Id, new InvoiceVoidOptions());
// HACK: Workaround for customer balance credit // HACK: Workaround for customer balance credit
if (invoice.StartingBalance < 0) if (invoice.StartingBalance < 0)
@@ -470,12 +470,12 @@ public class StripePaymentService : IPaymentService
// Customer had a balance applied to this invoice. Since we can't fully trust Stripe to // Customer had a balance applied to this invoice. Since we can't fully trust Stripe to
// credit it back to the customer (even though their docs claim they will), we need to // credit it back to the customer (even though their docs claim they will), we need to
// check that balance against the current customer balance and determine if it needs to be re-applied // check that balance against the current customer balance and determine if it needs to be re-applied
customer = await _stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerOptions); customer = await _stripeAdapter.GetCustomerAsync(subscriber.GatewayCustomerId, customerOptions);
// Assumption: Customer balance should now be $0, otherwise payment would not have failed. // Assumption: Customer balance should now be $0, otherwise payment would not have failed.
if (customer.Balance == 0) if (customer.Balance == 0)
{ {
await _stripeAdapter.CustomerUpdateAsync(customer.Id, await _stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions { Balance = invoice.StartingBalance }); new CustomerUpdateOptions { Balance = invoice.StartingBalance });
} }
} }
@@ -506,7 +506,7 @@ public class StripePaymentService : IPaymentService
throw new GatewayException("No subscription."); throw new GatewayException("No subscription.");
} }
var sub = await _stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId); var sub = await _stripeAdapter.GetSubscriptionAsync(subscriber.GatewaySubscriptionId);
if (sub == null) if (sub == null)
{ {
throw new GatewayException("Subscription was not found."); throw new GatewayException("Subscription was not found.");
@@ -522,9 +522,9 @@ public class StripePaymentService : IPaymentService
try try
{ {
var canceledSub = endOfPeriod var canceledSub = endOfPeriod
? await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, ? await _stripeAdapter.UpdateSubscriptionAsync(sub.Id,
new SubscriptionUpdateOptions { CancelAtPeriodEnd = true }) new SubscriptionUpdateOptions { CancelAtPeriodEnd = true })
: await _stripeAdapter.SubscriptionCancelAsync(sub.Id, new SubscriptionCancelOptions()); : await _stripeAdapter.CancelSubscriptionAsync(sub.Id, new SubscriptionCancelOptions());
if (!canceledSub.CanceledAt.HasValue) if (!canceledSub.CanceledAt.HasValue)
{ {
throw new GatewayException("Unable to cancel subscription."); throw new GatewayException("Unable to cancel subscription.");
@@ -551,7 +551,7 @@ public class StripePaymentService : IPaymentService
throw new GatewayException("No subscription."); throw new GatewayException("No subscription.");
} }
var sub = await _stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId); var sub = await _stripeAdapter.GetSubscriptionAsync(subscriber.GatewaySubscriptionId);
if (sub == null) if (sub == null)
{ {
throw new GatewayException("Subscription was not found."); throw new GatewayException("Subscription was not found.");
@@ -563,7 +563,7 @@ public class StripePaymentService : IPaymentService
throw new GatewayException("Subscription is not marked for cancellation."); throw new GatewayException("Subscription is not marked for cancellation.");
} }
var updatedSub = await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, var updatedSub = await _stripeAdapter.UpdateSubscriptionAsync(sub.Id,
new SubscriptionUpdateOptions { CancelAtPeriodEnd = false }); new SubscriptionUpdateOptions { CancelAtPeriodEnd = false });
if (updatedSub.CanceledAt.HasValue) if (updatedSub.CanceledAt.HasValue)
{ {
@@ -578,11 +578,11 @@ public class StripePaymentService : IPaymentService
!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId); !string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId);
if (customerExists) if (customerExists)
{ {
customer = await _stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId); customer = await _stripeAdapter.GetCustomerAsync(subscriber.GatewayCustomerId);
} }
else else
{ {
customer = await _stripeAdapter.CustomerCreateAsync(new CustomerCreateOptions customer = await _stripeAdapter.CreateCustomerAsync(new CustomerCreateOptions
{ {
Email = subscriber.BillingEmailAddress(), Email = subscriber.BillingEmailAddress(),
Description = subscriber.BillingName(), Description = subscriber.BillingName(),
@@ -591,9 +591,8 @@ public class StripePaymentService : IPaymentService
subscriber.GatewayCustomerId = customer.Id; subscriber.GatewayCustomerId = customer.Id;
} }
await _stripeAdapter.CustomerUpdateAsync(customer.Id, await _stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions { Balance = customer.Balance - (long)(creditAmount * 100) }); new CustomerUpdateOptions { Balance = customer.Balance - (long)(creditAmount * 100) });
return !customerExists; return !customerExists;
} }
@@ -630,7 +629,7 @@ public class StripePaymentService : IPaymentService
return subscriptionInfo; return subscriptionInfo;
} }
var subscription = await _stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, var subscription = await _stripeAdapter.GetSubscriptionAsync(subscriber.GatewaySubscriptionId,
new SubscriptionGetOptions { Expand = ["customer.discount.coupon.applies_to", "discounts.coupon.applies_to", "test_clock"] }); new SubscriptionGetOptions { Expand = ["customer.discount.coupon.applies_to", "discounts.coupon.applies_to", "test_clock"] });
if (subscription == null) if (subscription == null)
@@ -675,7 +674,7 @@ public class StripePaymentService : IPaymentService
Subscription = subscriber.GatewaySubscriptionId Subscription = subscriber.GatewaySubscriptionId
}; };
var upcomingInvoice = await _stripeAdapter.InvoiceCreatePreviewAsync(invoiceCreatePreviewOptions); var upcomingInvoice = await _stripeAdapter.CreateInvoicePreviewAsync(invoiceCreatePreviewOptions);
if (upcomingInvoice != null) if (upcomingInvoice != null)
{ {
@@ -726,7 +725,7 @@ public class StripePaymentService : IPaymentService
return false; return false;
} }
var customer = await _stripeAdapter.CustomerGetAsync(gatewayCustomerId); var customer = await _stripeAdapter.GetCustomerAsync(gatewayCustomerId);
return customer?.Discount?.Coupon?.Id == SecretsManagerStandaloneDiscountId; return customer?.Discount?.Coupon?.Id == SecretsManagerStandaloneDiscountId;
} }
@@ -738,7 +737,7 @@ public class StripePaymentService : IPaymentService
return (null, null); return (null, null);
} }
var openInvoices = await _stripeAdapter.InvoiceSearchAsync(new InvoiceSearchOptions var openInvoices = await _stripeAdapter.SearchInvoiceAsync(new InvoiceSearchOptions
{ {
Query = $"subscription:'{subscription.Id}' status:'open'" Query = $"subscription:'{subscription.Id}' status:'open'"
}); });
@@ -774,7 +773,7 @@ public class StripePaymentService : IPaymentService
private PaymentMethod GetLatestCardPaymentMethod(string customerId) private PaymentMethod GetLatestCardPaymentMethod(string customerId)
{ {
var cardPaymentMethods = _stripeAdapter.PaymentMethodListAutoPaging( var cardPaymentMethods = _stripeAdapter.ListPaymentMethodsAutoPaging(
new PaymentMethodListOptions { Customer = customerId, Type = "card" }); new PaymentMethodListOptions { Customer = customerId, Type = "card" });
return cardPaymentMethods.OrderByDescending(m => m.Created).FirstOrDefault(); return cardPaymentMethods.OrderByDescending(m => m.Created).FirstOrDefault();
} }
@@ -837,7 +836,7 @@ public class StripePaymentService : IPaymentService
Customer customer = null; Customer customer = null;
try try
{ {
customer = await _stripeAdapter.CustomerGetAsync(gatewayCustomerId, options); customer = await _stripeAdapter.GetCustomerAsync(gatewayCustomerId, options);
} }
catch (StripeException) catch (StripeException)
{ {
@@ -870,21 +869,21 @@ public class StripePaymentService : IPaymentService
try try
{ {
var paidInvoicesTask = _stripeAdapter.InvoiceListAsync(new StripeInvoiceListOptions var paidInvoicesTask = _stripeAdapter.ListInvoicesAsync(new StripeInvoiceListOptions
{ {
Customer = customer.Id, Customer = customer.Id,
SelectAll = !limit.HasValue, SelectAll = !limit.HasValue,
Limit = limit, Limit = limit,
Status = "paid" Status = "paid"
}); });
var openInvoicesTask = _stripeAdapter.InvoiceListAsync(new StripeInvoiceListOptions var openInvoicesTask = _stripeAdapter.ListInvoicesAsync(new StripeInvoiceListOptions
{ {
Customer = customer.Id, Customer = customer.Id,
SelectAll = !limit.HasValue, SelectAll = !limit.HasValue,
Limit = limit, Limit = limit,
Status = "open" Status = "open"
}); });
var uncollectibleInvoicesTask = _stripeAdapter.InvoiceListAsync(new StripeInvoiceListOptions var uncollectibleInvoicesTask = _stripeAdapter.ListInvoicesAsync(new StripeInvoiceListOptions
{ {
Customer = customer.Id, Customer = customer.Id,
SelectAll = !limit.HasValue, SelectAll = !limit.HasValue,

View File

@@ -1,6 +1,6 @@
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
namespace Bit.Core.Services; namespace Bit.Core.Billing.Services.Implementations;
public class StripeSyncService : IStripeSyncService public class StripeSyncService : IStripeSyncService
{ {
@@ -11,7 +11,7 @@ public class StripeSyncService : IStripeSyncService
_stripeAdapter = stripeAdapter; _stripeAdapter = stripeAdapter;
} }
public async Task UpdateCustomerEmailAddress(string gatewayCustomerId, string emailAddress) public async Task UpdateCustomerEmailAddressAsync(string gatewayCustomerId, string emailAddress)
{ {
if (string.IsNullOrWhiteSpace(gatewayCustomerId)) if (string.IsNullOrWhiteSpace(gatewayCustomerId))
{ {
@@ -23,9 +23,9 @@ public class StripeSyncService : IStripeSyncService
throw new InvalidEmailException(); throw new InvalidEmailException();
} }
var customer = await _stripeAdapter.CustomerGetAsync(gatewayCustomerId); var customer = await _stripeAdapter.GetCustomerAsync(gatewayCustomerId);
await _stripeAdapter.CustomerUpdateAsync(customer.Id, await _stripeAdapter.UpdateCustomerAsync(customer.Id,
new Stripe.CustomerUpdateOptions { Email = emailAddress }); new Stripe.CustomerUpdateOptions { Email = emailAddress });
} }
} }

View File

@@ -15,7 +15,6 @@ using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Braintree; using Braintree;
@@ -78,7 +77,7 @@ public class SubscriberService(
{ {
if (subscription.Metadata != null && subscription.Metadata.ContainsKey("organizationId")) if (subscription.Metadata != null && subscription.Metadata.ContainsKey("organizationId"))
{ {
await stripeAdapter.SubscriptionUpdateAsync(subscription.Id, new SubscriptionUpdateOptions await stripeAdapter.UpdateSubscriptionAsync(subscription.Id, new SubscriptionUpdateOptions
{ {
Metadata = metadata Metadata = metadata
}); });
@@ -97,7 +96,7 @@ public class SubscriberService(
options.CancellationDetails.Feedback = offboardingSurveyResponse.Reason; options.CancellationDetails.Feedback = offboardingSurveyResponse.Reason;
} }
await stripeAdapter.SubscriptionCancelAsync(subscription.Id, options); await stripeAdapter.CancelSubscriptionAsync(subscription.Id, options);
} }
else else
{ {
@@ -116,7 +115,7 @@ public class SubscriberService(
options.CancellationDetails.Feedback = offboardingSurveyResponse.Reason; options.CancellationDetails.Feedback = offboardingSurveyResponse.Reason;
} }
await stripeAdapter.SubscriptionUpdateAsync(subscription.Id, options); await stripeAdapter.UpdateSubscriptionAsync(subscription.Id, options);
} }
} }
@@ -227,7 +226,7 @@ public class SubscriberService(
_ => throw new ArgumentOutOfRangeException(nameof(subscriber)) _ => throw new ArgumentOutOfRangeException(nameof(subscriber))
}; };
var customer = await stripeAdapter.CustomerCreateAsync(options); var customer = await stripeAdapter.CreateCustomerAsync(options);
switch (subscriber) switch (subscriber)
{ {
@@ -270,7 +269,7 @@ public class SubscriberService(
try try
{ {
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions); var customer = await stripeAdapter.GetCustomerAsync(subscriber.GatewayCustomerId, customerGetOptions);
if (customer != null) if (customer != null)
{ {
@@ -306,7 +305,7 @@ public class SubscriberService(
try try
{ {
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions); var customer = await stripeAdapter.GetCustomerAsync(subscriber.GatewayCustomerId, customerGetOptions);
if (customer != null) if (customer != null)
{ {
@@ -357,7 +356,7 @@ public class SubscriberService(
try try
{ {
var subscription = await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions); var subscription = await stripeAdapter.GetSubscriptionAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
if (subscription != null) if (subscription != null)
{ {
@@ -393,7 +392,7 @@ public class SubscriberService(
try try
{ {
var subscription = await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions); var subscription = await stripeAdapter.GetSubscriptionAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
if (subscription != null) if (subscription != null)
{ {
@@ -487,23 +486,23 @@ public class SubscriberService(
switch (source) switch (source)
{ {
case BankAccount: case BankAccount:
await stripeAdapter.BankAccountDeleteAsync(stripeCustomer.Id, source.Id); await stripeAdapter.DeleteBankAccountAsync(stripeCustomer.Id, source.Id);
break; break;
case Card: case Card:
await stripeAdapter.CardDeleteAsync(stripeCustomer.Id, source.Id); await stripeAdapter.DeleteCardAsync(stripeCustomer.Id, source.Id);
break; break;
} }
} }
} }
var paymentMethods = stripeAdapter.PaymentMethodListAutoPagingAsync(new PaymentMethodListOptions var paymentMethods = stripeAdapter.ListPaymentMethodsAutoPagingAsync(new PaymentMethodListOptions
{ {
Customer = stripeCustomer.Id Customer = stripeCustomer.Id
}); });
await foreach (var paymentMethod in paymentMethods) await foreach (var paymentMethod in paymentMethods)
{ {
await stripeAdapter.PaymentMethodDetachAsync(paymentMethod.Id); await stripeAdapter.DetachPaymentMethodAsync(paymentMethod.Id);
} }
} }
} }
@@ -532,7 +531,7 @@ public class SubscriberService(
{ {
case PaymentMethodType.BankAccount: case PaymentMethodType.BankAccount:
{ {
var getSetupIntentsForUpdatedPaymentMethod = stripeAdapter.SetupIntentList(new SetupIntentListOptions var getSetupIntentsForUpdatedPaymentMethod = stripeAdapter.ListSetupIntentsAsync(new SetupIntentListOptions
{ {
PaymentMethod = token PaymentMethod = token
}); });
@@ -569,7 +568,7 @@ public class SubscriberService(
await RemoveStripePaymentMethodsAsync(customer); await RemoveStripePaymentMethodsAsync(customer);
// Attach the incoming payment method. // Attach the incoming payment method.
await stripeAdapter.PaymentMethodAttachAsync(token, await stripeAdapter.AttachPaymentMethodAsync(token,
new PaymentMethodAttachOptions { Customer = subscriber.GatewayCustomerId }); new PaymentMethodAttachOptions { Customer = subscriber.GatewayCustomerId });
var metadata = customer.Metadata; var metadata = customer.Metadata;
@@ -581,7 +580,7 @@ public class SubscriberService(
} }
// Set the customer's default payment method in Stripe and remove their Braintree customer ID. // Set the customer's default payment method in Stripe and remove their Braintree customer ID.
await stripeAdapter.CustomerUpdateAsync(subscriber.GatewayCustomerId, new CustomerUpdateOptions await stripeAdapter.UpdateCustomerAsync(subscriber.GatewayCustomerId, new CustomerUpdateOptions
{ {
InvoiceSettings = new CustomerInvoiceSettingsOptions InvoiceSettings = new CustomerInvoiceSettingsOptions
{ {
@@ -644,7 +643,7 @@ public class SubscriberService(
Expand = ["subscriptions", "tax", "tax_ids"] Expand = ["subscriptions", "tax", "tax_ids"]
}); });
customer = await stripeAdapter.CustomerUpdateAsync(customer.Id, new CustomerUpdateOptions customer = await stripeAdapter.UpdateCustomerAsync(customer.Id, new CustomerUpdateOptions
{ {
Address = new AddressOptions Address = new AddressOptions
{ {
@@ -662,7 +661,7 @@ public class SubscriberService(
if (taxId != null) if (taxId != null)
{ {
await stripeAdapter.TaxIdDeleteAsync(customer.Id, taxId.Id); await stripeAdapter.DeleteTaxIdAsync(customer.Id, taxId.Id);
} }
if (!string.IsNullOrWhiteSpace(taxInformation.TaxId)) if (!string.IsNullOrWhiteSpace(taxInformation.TaxId))
@@ -685,12 +684,12 @@ public class SubscriberService(
try try
{ {
await stripeAdapter.TaxIdCreateAsync(customer.Id, await stripeAdapter.CreateTaxIdAsync(customer.Id,
new TaxIdCreateOptions { Type = taxIdType, Value = taxInformation.TaxId }); new TaxIdCreateOptions { Type = taxIdType, Value = taxInformation.TaxId });
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF) if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
{ {
await stripeAdapter.TaxIdCreateAsync(customer.Id, await stripeAdapter.CreateTaxIdAsync(customer.Id,
new TaxIdCreateOptions { Type = StripeConstants.TaxIdType.EUVAT, Value = $"ES{taxInformation.TaxId}" }); new TaxIdCreateOptions { Type = StripeConstants.TaxIdType.EUVAT, Value = $"ES{taxInformation.TaxId}" });
} }
} }
@@ -736,7 +735,7 @@ public class SubscriberService(
Address.Country: not Core.Constants.CountryAbbreviations.UnitedStates, Address.Country: not Core.Constants.CountryAbbreviations.UnitedStates,
TaxExempt: not TaxExempt.Reverse TaxExempt: not TaxExempt.Reverse
}: }:
await stripeAdapter.CustomerUpdateAsync(customer.Id, await stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions { TaxExempt = TaxExempt.Reverse }); new CustomerUpdateOptions { TaxExempt = TaxExempt.Reverse });
break; break;
case case
@@ -744,14 +743,14 @@ public class SubscriberService(
Address.Country: Core.Constants.CountryAbbreviations.UnitedStates, Address.Country: Core.Constants.CountryAbbreviations.UnitedStates,
TaxExempt: TaxExempt.Reverse TaxExempt: TaxExempt.Reverse
}: }:
await stripeAdapter.CustomerUpdateAsync(customer.Id, await stripeAdapter.UpdateCustomerAsync(customer.Id,
new CustomerUpdateOptions { TaxExempt = TaxExempt.None }); new CustomerUpdateOptions { TaxExempt = TaxExempt.None });
break; break;
} }
if (!subscription.AutomaticTax.Enabled) if (!subscription.AutomaticTax.Enabled)
{ {
await stripeAdapter.SubscriptionUpdateAsync(subscription.Id, await stripeAdapter.UpdateSubscriptionAsync(subscription.Id,
new SubscriptionUpdateOptions new SubscriptionUpdateOptions
{ {
AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true } AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }
@@ -771,7 +770,7 @@ public class SubscriberService(
if (automaticTaxShouldBeEnabled && !subscription.AutomaticTax.Enabled) if (automaticTaxShouldBeEnabled && !subscription.AutomaticTax.Enabled)
{ {
await stripeAdapter.SubscriptionUpdateAsync(subscription.Id, await stripeAdapter.UpdateSubscriptionAsync(subscription.Id,
new SubscriptionUpdateOptions new SubscriptionUpdateOptions
{ {
AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true } AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }
@@ -790,7 +789,7 @@ public class SubscriberService(
} }
try try
{ {
await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId); await stripeAdapter.GetCustomerAsync(subscriber.GatewayCustomerId);
return true; return true;
} }
catch (StripeException e) when (e.StripeError.Code == "resource_missing") catch (StripeException e) when (e.StripeError.Code == "resource_missing")
@@ -809,7 +808,7 @@ public class SubscriberService(
} }
try try
{ {
await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId); await stripeAdapter.GetSubscriptionAsync(subscriber.GatewaySubscriptionId);
return true; return true;
} }
catch (StripeException e) when (e.StripeError.Code == "resource_missing") catch (StripeException e) when (e.StripeError.Code == "resource_missing")
@@ -828,7 +827,7 @@ public class SubscriberService(
metadata[BraintreeCustomerIdKey] = braintreeCustomerId; metadata[BraintreeCustomerIdKey] = braintreeCustomerId;
await stripeAdapter.CustomerUpdateAsync(customer.Id, new CustomerUpdateOptions await stripeAdapter.UpdateCustomerAsync(customer.Id, new CustomerUpdateOptions
{ {
Metadata = metadata Metadata = metadata
}); });
@@ -868,7 +867,7 @@ public class SubscriberService(
return null; return null;
} }
var setupIntent = await stripeAdapter.SetupIntentGet(setupIntentId, new SetupIntentGetOptions var setupIntent = await stripeAdapter.GetSetupIntentAsync(setupIntentId, new SetupIntentGetOptions
{ {
Expand = ["payment_method"] Expand = ["payment_method"]
}); });
@@ -886,7 +885,7 @@ public class SubscriberService(
metadata[BraintreeCustomerIdOldKey] = value; metadata[BraintreeCustomerIdOldKey] = value;
metadata[BraintreeCustomerIdKey] = null; metadata[BraintreeCustomerIdKey] = null;
await stripeAdapter.CustomerUpdateAsync(customer.Id, new CustomerUpdateOptions await stripeAdapter.UpdateCustomerAsync(customer.Id, new CustomerUpdateOptions
{ {
Metadata = metadata Metadata = metadata
}); });
@@ -903,18 +902,18 @@ public class SubscriberService(
switch (source) switch (source)
{ {
case BankAccount: case BankAccount:
await stripeAdapter.BankAccountDeleteAsync(customer.Id, source.Id); await stripeAdapter.DeleteBankAccountAsync(customer.Id, source.Id);
break; break;
case Card: case Card:
await stripeAdapter.CardDeleteAsync(customer.Id, source.Id); await stripeAdapter.DeleteCardAsync(customer.Id, source.Id);
break; break;
} }
} }
} }
var paymentMethods = await stripeAdapter.CustomerListPaymentMethods(customer.Id); var paymentMethods = await stripeAdapter.ListCustomerPaymentMethodsAsync(customer.Id);
await Task.WhenAll(paymentMethods.Select(pm => stripeAdapter.PaymentMethodDetachAsync(pm.Id))); await Task.WhenAll(paymentMethods.Select(pm => stripeAdapter.DetachPaymentMethodAsync(pm.Id)));
} }
private async Task ReplaceBraintreePaymentMethodAsync( private async Task ReplaceBraintreePaymentMethodAsync(

View File

@@ -7,7 +7,6 @@ using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using OneOf.Types; using OneOf.Types;
using Stripe; using Stripe;
@@ -53,7 +52,7 @@ public class RestartSubscriptionCommand(
TrialPeriodDays = 0 TrialPeriodDays = 0
}; };
var subscription = await stripeAdapter.SubscriptionCreateAsync(options); var subscription = await stripeAdapter.CreateSubscriptionAsync(options);
await EnableAsync(subscriber, subscription); await EnableAsync(subscriber, subscription);
return new None(); return new None();
} }

View File

@@ -2,8 +2,8 @@
#nullable disable #nullable disable
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Billing.Tax.Models; using Bit.Core.Billing.Tax.Models;
using Bit.Core.Services;
using Stripe; using Stripe;
namespace Bit.Core.Billing; namespace Bit.Core.Billing;
@@ -22,7 +22,7 @@ public static class Utilities
return null; return null;
} }
var openInvoices = await stripeAdapter.InvoiceSearchAsync(new InvoiceSearchOptions var openInvoices = await stripeAdapter.SearchInvoiceAsync(new InvoiceSearchOptions
{ {
Query = $"subscription:'{subscription.Id}' status:'open'" Query = $"subscription:'{subscription.Id}' status:'open'"
}); });

View File

@@ -1,11 +1,11 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Extensions; using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
namespace Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud; namespace Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
@@ -13,9 +13,9 @@ public class SetUpSponsorshipCommand : ISetUpSponsorshipCommand
{ {
private readonly IOrganizationSponsorshipRepository _organizationSponsorshipRepository; private readonly IOrganizationSponsorshipRepository _organizationSponsorshipRepository;
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
public SetUpSponsorshipCommand(IOrganizationSponsorshipRepository organizationSponsorshipRepository, IOrganizationRepository organizationRepository, IPaymentService paymentService) public SetUpSponsorshipCommand(IOrganizationSponsorshipRepository organizationSponsorshipRepository, IOrganizationRepository organizationRepository, IStripePaymentService paymentService)
{ {
_organizationSponsorshipRepository = organizationSponsorshipRepository; _organizationSponsorshipRepository = organizationSponsorshipRepository;
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;

View File

@@ -4,6 +4,7 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Extensions; using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@@ -14,14 +15,14 @@ namespace Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnte
public class ValidateSponsorshipCommand : CancelSponsorshipCommand, IValidateSponsorshipCommand public class ValidateSponsorshipCommand : CancelSponsorshipCommand, IValidateSponsorshipCommand
{ {
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IMailService _mailService; private readonly IMailService _mailService;
private readonly ILogger<ValidateSponsorshipCommand> _logger; private readonly ILogger<ValidateSponsorshipCommand> _logger;
public ValidateSponsorshipCommand( public ValidateSponsorshipCommand(
IOrganizationSponsorshipRepository organizationSponsorshipRepository, IOrganizationSponsorshipRepository organizationSponsorshipRepository,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
IMailService mailService, IMailService mailService,
ILogger<ValidateSponsorshipCommand> logger) : base(organizationSponsorshipRepository, organizationRepository) ILogger<ValidateSponsorshipCommand> logger) : base(organizationSponsorshipRepository, organizationRepository)
{ {

View File

@@ -3,6 +3,7 @@ using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
@@ -12,13 +13,13 @@ namespace Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
public class AddSecretsManagerSubscriptionCommand : IAddSecretsManagerSubscriptionCommand public class AddSecretsManagerSubscriptionCommand : IAddSecretsManagerSubscriptionCommand
{ {
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IOrganizationService _organizationService; private readonly IOrganizationService _organizationService;
private readonly IProviderRepository _providerRepository; private readonly IProviderRepository _providerRepository;
private readonly IPricingClient _pricingClient; private readonly IPricingClient _pricingClient;
public AddSecretsManagerSubscriptionCommand( public AddSecretsManagerSubscriptionCommand(
IPaymentService paymentService, IStripePaymentService paymentService,
IOrganizationService organizationService, IOrganizationService organizationService,
IProviderRepository providerRepository, IProviderRepository providerRepository,
IPricingClient pricingClient) IPricingClient pricingClient)

View File

@@ -3,6 +3,7 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
@@ -18,7 +19,7 @@ namespace Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubscriptionCommand public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubscriptionCommand
{ {
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IMailService _mailService; private readonly IMailService _mailService;
private readonly ILogger<UpdateSecretsManagerSubscriptionCommand> _logger; private readonly ILogger<UpdateSecretsManagerSubscriptionCommand> _logger;
private readonly IServiceAccountRepository _serviceAccountRepository; private readonly IServiceAccountRepository _serviceAccountRepository;
@@ -29,7 +30,7 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
public UpdateSecretsManagerSubscriptionCommand( public UpdateSecretsManagerSubscriptionCommand(
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
IMailService mailService, IMailService mailService,
ILogger<UpdateSecretsManagerSubscriptionCommand> logger, ILogger<UpdateSecretsManagerSubscriptionCommand> logger,
IServiceAccountRepository serviceAccountRepository, IServiceAccountRepository serviceAccountRepository,

View File

@@ -11,6 +11,7 @@ using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Organizations.Models; using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Organizations.Services; using Bit.Core.Billing.Organizations.Services;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
@@ -26,7 +27,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ICollectionRepository _collectionRepository; private readonly ICollectionRepository _collectionRepository;
private readonly IGroupRepository _groupRepository; private readonly IGroupRepository _groupRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IPolicyRepository _policyRepository; private readonly IPolicyRepository _policyRepository;
private readonly ISsoConfigRepository _ssoConfigRepository; private readonly ISsoConfigRepository _ssoConfigRepository;
private readonly IOrganizationConnectionRepository _organizationConnectionRepository; private readonly IOrganizationConnectionRepository _organizationConnectionRepository;
@@ -41,7 +42,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
ICollectionRepository collectionRepository, ICollectionRepository collectionRepository,
IGroupRepository groupRepository, IGroupRepository groupRepository,
IPaymentService paymentService, IStripePaymentService paymentService,
IPolicyRepository policyRepository, IPolicyRepository policyRepository,
ISsoConfigRepository ssoConfigRepository, ISsoConfigRepository ssoConfigRepository,
IOrganizationConnectionRepository organizationConnectionRepository, IOrganizationConnectionRepository organizationConnectionRepository,

View File

@@ -1,54 +0,0 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
using Bit.Core.Models.BitStripe;
using Stripe;
using Stripe.Tax;
namespace Bit.Core.Services;
public interface IStripeAdapter
{
Task<Customer> CustomerCreateAsync(CustomerCreateOptions customerCreateOptions);
Task CustomerDeleteDiscountAsync(string customerId, CustomerDeleteDiscountOptions options = null);
Task<Customer> CustomerGetAsync(string id, CustomerGetOptions options = null);
Task<Customer> CustomerUpdateAsync(string id, CustomerUpdateOptions options = null);
Task<Customer> CustomerDeleteAsync(string id);
Task<List<PaymentMethod>> CustomerListPaymentMethods(string id, CustomerPaymentMethodListOptions options = null);
Task<CustomerBalanceTransaction> CustomerBalanceTransactionCreate(string customerId,
CustomerBalanceTransactionCreateOptions options);
Task<Subscription> SubscriptionCreateAsync(SubscriptionCreateOptions subscriptionCreateOptions);
Task<Subscription> SubscriptionGetAsync(string id, SubscriptionGetOptions options = null);
Task<Subscription> SubscriptionUpdateAsync(string id, SubscriptionUpdateOptions options = null);
Task<Subscription> SubscriptionCancelAsync(string Id, SubscriptionCancelOptions options = null);
Task<Invoice> InvoiceGetAsync(string id, InvoiceGetOptions options);
Task<List<Invoice>> InvoiceListAsync(StripeInvoiceListOptions options);
Task<Invoice> InvoiceCreatePreviewAsync(InvoiceCreatePreviewOptions options);
Task<List<Invoice>> InvoiceSearchAsync(InvoiceSearchOptions options);
Task<Invoice> InvoiceUpdateAsync(string id, InvoiceUpdateOptions options);
Task<Invoice> InvoiceFinalizeInvoiceAsync(string id, InvoiceFinalizeOptions options);
Task<Invoice> InvoiceSendInvoiceAsync(string id, InvoiceSendOptions options);
Task<Invoice> InvoicePayAsync(string id, InvoicePayOptions options = null);
Task<Invoice> InvoiceDeleteAsync(string id, InvoiceDeleteOptions options = null);
Task<Invoice> InvoiceVoidInvoiceAsync(string id, InvoiceVoidOptions options = null);
IEnumerable<PaymentMethod> PaymentMethodListAutoPaging(PaymentMethodListOptions options);
IAsyncEnumerable<PaymentMethod> PaymentMethodListAutoPagingAsync(PaymentMethodListOptions options);
Task<PaymentMethod> PaymentMethodAttachAsync(string id, PaymentMethodAttachOptions options = null);
Task<PaymentMethod> PaymentMethodDetachAsync(string id, PaymentMethodDetachOptions options = null);
Task<TaxId> TaxIdCreateAsync(string id, TaxIdCreateOptions options);
Task<TaxId> TaxIdDeleteAsync(string customerId, string taxIdId, TaxIdDeleteOptions options = null);
Task<StripeList<Registration>> TaxRegistrationsListAsync(RegistrationListOptions options = null);
Task<StripeList<Charge>> ChargeListAsync(ChargeListOptions options);
Task<Refund> RefundCreateAsync(RefundCreateOptions options);
Task<Card> CardDeleteAsync(string customerId, string cardId, CardDeleteOptions options = null);
Task<BankAccount> BankAccountCreateAsync(string customerId, BankAccountCreateOptions options = null);
Task<BankAccount> BankAccountDeleteAsync(string customerId, string bankAccount, BankAccountDeleteOptions options = null);
Task<StripeList<Price>> PriceListAsync(PriceListOptions options = null);
Task<SetupIntent> SetupIntentCreate(SetupIntentCreateOptions options);
Task<List<SetupIntent>> SetupIntentList(SetupIntentListOptions options);
Task SetupIntentCancel(string id, SetupIntentCancelOptions options = null);
Task<SetupIntent> SetupIntentGet(string id, SetupIntentGetOptions options = null);
Task SetupIntentVerifyMicroDeposit(string id, SetupIntentVerifyMicrodepositsOptions options);
Task<List<Stripe.TestHelpers.TestClock>> TestClockListAsync();
Task<Price> PriceGetAsync(string id, PriceGetOptions options = null);
}

View File

@@ -1,6 +0,0 @@
namespace Bit.Core.Services;
public interface IStripeSyncService
{
Task UpdateCustomerEmailAddress(string gatewayCustomerId, string emailAddress);
}

View File

@@ -1,284 +0,0 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
using Bit.Core.Models.BitStripe;
using Stripe;
using Stripe.Tax;
namespace Bit.Core.Services;
public class StripeAdapter : IStripeAdapter
{
private readonly CustomerService _customerService;
private readonly SubscriptionService _subscriptionService;
private readonly InvoiceService _invoiceService;
private readonly PaymentMethodService _paymentMethodService;
private readonly TaxIdService _taxIdService;
private readonly ChargeService _chargeService;
private readonly RefundService _refundService;
private readonly CardService _cardService;
private readonly BankAccountService _bankAccountService;
private readonly PlanService _planService;
private readonly PriceService _priceService;
private readonly SetupIntentService _setupIntentService;
private readonly Stripe.TestHelpers.TestClockService _testClockService;
private readonly CustomerBalanceTransactionService _customerBalanceTransactionService;
private readonly Stripe.Tax.RegistrationService _taxRegistrationService;
private readonly CalculationService _calculationService;
public StripeAdapter()
{
_customerService = new CustomerService();
_subscriptionService = new SubscriptionService();
_invoiceService = new InvoiceService();
_paymentMethodService = new PaymentMethodService();
_taxIdService = new TaxIdService();
_chargeService = new ChargeService();
_refundService = new RefundService();
_cardService = new CardService();
_bankAccountService = new BankAccountService();
_priceService = new PriceService();
_planService = new PlanService();
_setupIntentService = new SetupIntentService();
_testClockService = new Stripe.TestHelpers.TestClockService();
_customerBalanceTransactionService = new CustomerBalanceTransactionService();
_taxRegistrationService = new Stripe.Tax.RegistrationService();
_calculationService = new CalculationService();
}
public Task<Customer> CustomerCreateAsync(CustomerCreateOptions options)
{
return _customerService.CreateAsync(options);
}
public Task CustomerDeleteDiscountAsync(string customerId, CustomerDeleteDiscountOptions options = null) =>
_customerService.DeleteDiscountAsync(customerId, options);
public Task<Customer> CustomerGetAsync(string id, CustomerGetOptions options = null)
{
return _customerService.GetAsync(id, options);
}
public Task<Customer> CustomerUpdateAsync(string id, CustomerUpdateOptions options = null)
{
return _customerService.UpdateAsync(id, options);
}
public Task<Customer> CustomerDeleteAsync(string id)
{
return _customerService.DeleteAsync(id);
}
public async Task<List<PaymentMethod>> CustomerListPaymentMethods(string id,
CustomerPaymentMethodListOptions options = null)
{
var paymentMethods = await _customerService.ListPaymentMethodsAsync(id, options);
return paymentMethods.Data;
}
public async Task<CustomerBalanceTransaction> CustomerBalanceTransactionCreate(string customerId,
CustomerBalanceTransactionCreateOptions options)
=> await _customerBalanceTransactionService.CreateAsync(customerId, options);
public Task<Subscription> SubscriptionCreateAsync(SubscriptionCreateOptions options)
{
return _subscriptionService.CreateAsync(options);
}
public Task<Subscription> SubscriptionGetAsync(string id, SubscriptionGetOptions options = null)
{
return _subscriptionService.GetAsync(id, options);
}
public async Task<Subscription> ProviderSubscriptionGetAsync(
string id,
Guid providerId,
SubscriptionGetOptions options = null)
{
var subscription = await _subscriptionService.GetAsync(id, options);
if (subscription.Metadata.TryGetValue("providerId", out var value) && value == providerId.ToString())
{
return subscription;
}
throw new InvalidOperationException("Subscription does not belong to the provider.");
}
public Task<Subscription> SubscriptionUpdateAsync(string id,
SubscriptionUpdateOptions options = null)
{
return _subscriptionService.UpdateAsync(id, options);
}
public Task<Subscription> SubscriptionCancelAsync(string Id, SubscriptionCancelOptions options = null)
{
return _subscriptionService.CancelAsync(Id, options);
}
public Task<Invoice> InvoiceGetAsync(string id, InvoiceGetOptions options)
{
return _invoiceService.GetAsync(id, options);
}
public async Task<List<Invoice>> InvoiceListAsync(StripeInvoiceListOptions options)
{
if (!options.SelectAll)
{
return (await _invoiceService.ListAsync(options.ToInvoiceListOptions())).Data;
}
options.Limit = 100;
var invoices = new List<Invoice>();
await foreach (var invoice in _invoiceService.ListAutoPagingAsync(options.ToInvoiceListOptions()))
{
invoices.Add(invoice);
}
return invoices;
}
public Task<Invoice> InvoiceCreatePreviewAsync(InvoiceCreatePreviewOptions options)
{
return _invoiceService.CreatePreviewAsync(options);
}
public async Task<List<Invoice>> InvoiceSearchAsync(InvoiceSearchOptions options)
=> (await _invoiceService.SearchAsync(options)).Data;
public Task<Invoice> InvoiceUpdateAsync(string id, InvoiceUpdateOptions options)
{
return _invoiceService.UpdateAsync(id, options);
}
public Task<Invoice> InvoiceFinalizeInvoiceAsync(string id, InvoiceFinalizeOptions options)
{
return _invoiceService.FinalizeInvoiceAsync(id, options);
}
public Task<Invoice> InvoiceSendInvoiceAsync(string id, InvoiceSendOptions options)
{
return _invoiceService.SendInvoiceAsync(id, options);
}
public Task<Invoice> InvoicePayAsync(string id, InvoicePayOptions options = null)
{
return _invoiceService.PayAsync(id, options);
}
public Task<Invoice> InvoiceDeleteAsync(string id, InvoiceDeleteOptions options = null)
{
return _invoiceService.DeleteAsync(id, options);
}
public Task<Invoice> InvoiceVoidInvoiceAsync(string id, InvoiceVoidOptions options = null)
{
return _invoiceService.VoidInvoiceAsync(id, options);
}
public IEnumerable<PaymentMethod> PaymentMethodListAutoPaging(PaymentMethodListOptions options)
{
return _paymentMethodService.ListAutoPaging(options);
}
public IAsyncEnumerable<PaymentMethod> PaymentMethodListAutoPagingAsync(PaymentMethodListOptions options)
=> _paymentMethodService.ListAutoPagingAsync(options);
public Task<PaymentMethod> PaymentMethodAttachAsync(string id, PaymentMethodAttachOptions options = null)
{
return _paymentMethodService.AttachAsync(id, options);
}
public Task<PaymentMethod> PaymentMethodDetachAsync(string id, PaymentMethodDetachOptions options = null)
{
return _paymentMethodService.DetachAsync(id, options);
}
public Task<Plan> PlanGetAsync(string id, PlanGetOptions options = null)
{
return _planService.GetAsync(id, options);
}
public Task<TaxId> TaxIdCreateAsync(string id, TaxIdCreateOptions options)
{
return _taxIdService.CreateAsync(id, options);
}
public Task<TaxId> TaxIdDeleteAsync(string customerId, string taxIdId,
TaxIdDeleteOptions options = null)
{
return _taxIdService.DeleteAsync(customerId, taxIdId);
}
public Task<StripeList<Registration>> TaxRegistrationsListAsync(RegistrationListOptions options = null)
{
return _taxRegistrationService.ListAsync(options);
}
public Task<StripeList<Charge>> ChargeListAsync(ChargeListOptions options)
{
return _chargeService.ListAsync(options);
}
public Task<Refund> RefundCreateAsync(RefundCreateOptions options)
{
return _refundService.CreateAsync(options);
}
public Task<Card> CardDeleteAsync(string customerId, string cardId, CardDeleteOptions options = null)
{
return _cardService.DeleteAsync(customerId, cardId, options);
}
public Task<BankAccount> BankAccountCreateAsync(string customerId, BankAccountCreateOptions options = null)
{
return _bankAccountService.CreateAsync(customerId, options);
}
public Task<BankAccount> BankAccountDeleteAsync(string customerId, string bankAccount, BankAccountDeleteOptions options = null)
{
return _bankAccountService.DeleteAsync(customerId, bankAccount, options);
}
public async Task<StripeList<Price>> PriceListAsync(PriceListOptions options = null)
{
return await _priceService.ListAsync(options);
}
public Task<SetupIntent> SetupIntentCreate(SetupIntentCreateOptions options)
=> _setupIntentService.CreateAsync(options);
public async Task<List<SetupIntent>> SetupIntentList(SetupIntentListOptions options)
{
var setupIntents = await _setupIntentService.ListAsync(options);
return setupIntents.Data;
}
public Task SetupIntentCancel(string id, SetupIntentCancelOptions options = null)
=> _setupIntentService.CancelAsync(id, options);
public Task<SetupIntent> SetupIntentGet(string id, SetupIntentGetOptions options = null)
=> _setupIntentService.GetAsync(id, options);
public Task SetupIntentVerifyMicroDeposit(string id, SetupIntentVerifyMicrodepositsOptions options)
=> _setupIntentService.VerifyMicrodepositsAsync(id, options);
public async Task<List<Stripe.TestHelpers.TestClock>> TestClockListAsync()
{
var items = new List<Stripe.TestHelpers.TestClock>();
var options = new Stripe.TestHelpers.TestClockListOptions()
{
Limit = 100
};
await foreach (var i in _testClockService.ListAutoPagingAsync(options))
{
items.Add(i);
}
return items;
}
public Task<Price> PriceGetAsync(string id, PriceGetOptions options = null)
=> _priceService.GetAsync(id, options);
}

View File

@@ -57,7 +57,7 @@ public class UserService : UserManager<User>, IUserService
private readonly ILicensingService _licenseService; private readonly ILicensingService _licenseService;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly IApplicationCacheService _applicationCacheService; private readonly IApplicationCacheService _applicationCacheService;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly IPolicyRepository _policyRepository; private readonly IPolicyRepository _policyRepository;
private readonly IPolicyService _policyService; private readonly IPolicyService _policyService;
private readonly IFido2 _fido2; private readonly IFido2 _fido2;
@@ -93,7 +93,7 @@ public class UserService : UserManager<User>, IUserService
ILicensingService licenseService, ILicensingService licenseService,
IEventService eventService, IEventService eventService,
IApplicationCacheService applicationCacheService, IApplicationCacheService applicationCacheService,
IPaymentService paymentService, IStripePaymentService paymentService,
IPolicyRepository policyRepository, IPolicyRepository policyRepository,
IPolicyService policyService, IPolicyService policyService,
IFido2 fido2, IFido2 fido2,
@@ -534,7 +534,7 @@ public class UserService : UserManager<User>, IUserService
try try
{ {
await _stripeSyncService.UpdateCustomerEmailAddress(user.GatewayCustomerId, await _stripeSyncService.UpdateCustomerEmailAddressAsync(user.GatewayCustomerId,
user.BillingEmailAddress()); user.BillingEmailAddress());
} }
catch (Exception ex) catch (Exception ex)
@@ -867,7 +867,7 @@ public class UserService : UserManager<User>, IUserService
} }
string paymentIntentClientSecret = null; string paymentIntentClientSecret = null;
IPaymentService paymentService = null; IStripePaymentService paymentService = null;
if (_globalSettings.SelfHosted) if (_globalSettings.SelfHosted)
{ {
if (license == null || !_licenseService.VerifyLicense(license)) if (license == null || !_licenseService.VerifyLicense(license))

View File

@@ -1,12 +1,12 @@
using Bit.Core.Entities; using Bit.Core.Billing.Services;
using Bit.Core.Entities;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Services;
namespace Bit.Core.Utilities; namespace Bit.Core.Utilities;
public static class BillingHelpers public static class BillingHelpers
{ {
internal static async Task<string> AdjustStorageAsync(IPaymentService paymentService, IStorableSubscriber storableSubscriber, internal static async Task<string> AdjustStorageAsync(IStripePaymentService paymentService, IStorableSubscriber storableSubscriber,
short storageAdjustmentGb, string storagePlanId, short baseStorageGb) short storageAdjustmentGb, string storagePlanId, short baseStorageGb)
{ {
if (storableSubscriber == null) if (storableSubscriber == null)

View File

@@ -238,7 +238,7 @@ public static class ServiceCollectionExtensions
PrivateKey = globalSettings.Braintree.PrivateKey PrivateKey = globalSettings.Braintree.PrivateKey
}; };
}); });
services.AddScoped<IPaymentService, StripePaymentService>(); services.AddScoped<IStripePaymentService, StripePaymentService>();
services.AddScoped<IPaymentHistoryService, PaymentHistoryService>(); services.AddScoped<IPaymentHistoryService, PaymentHistoryService>();
services.AddScoped<ITwoFactorEmailService, TwoFactorEmailService>(); services.AddScoped<ITwoFactorEmailService, TwoFactorEmailService>();
// Legacy mailer service // Legacy mailer service

View File

@@ -28,7 +28,7 @@ public class AccountsControllerTests : IDisposable
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly IFeatureService _featureService; private readonly IFeatureService _featureService;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery; private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
private readonly IUserAccountKeysQuery _userAccountKeysQuery; private readonly IUserAccountKeysQuery _userAccountKeysQuery;
private readonly ILicensingService _licensingService; private readonly ILicensingService _licensingService;
@@ -39,7 +39,7 @@ public class AccountsControllerTests : IDisposable
{ {
_userService = Substitute.For<IUserService>(); _userService = Substitute.For<IUserService>();
_featureService = Substitute.For<IFeatureService>(); _featureService = Substitute.For<IFeatureService>();
_paymentService = Substitute.For<IPaymentService>(); _paymentService = Substitute.For<IStripePaymentService>();
_twoFactorIsEnabledQuery = Substitute.For<ITwoFactorIsEnabledQuery>(); _twoFactorIsEnabledQuery = Substitute.For<ITwoFactorIsEnabledQuery>();
_userAccountKeysQuery = Substitute.For<IUserAccountKeysQuery>(); _userAccountKeysQuery = Substitute.For<IUserAccountKeysQuery>();
_licensingService = Substitute.For<ILicensingService>(); _licensingService = Substitute.For<ILicensingService>();

View File

@@ -3,9 +3,9 @@ using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Billing.Organizations.Models; using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Organizations.Services; using Bit.Core.Billing.Organizations.Services;
using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Http.HttpResults;
@@ -103,7 +103,7 @@ public class OrganizationBillingControllerTests
// Manually create a BillingHistoryInfo object to avoid requiring AutoFixture to create HttpResponseHeaders // Manually create a BillingHistoryInfo object to avoid requiring AutoFixture to create HttpResponseHeaders
var billingInfo = new BillingHistoryInfo(); var billingInfo = new BillingHistoryInfo();
sutProvider.GetDependency<IPaymentService>().GetBillingHistoryAsync(organization).Returns(billingInfo); sutProvider.GetDependency<IStripePaymentService>().GetBillingHistoryAsync(organization).Returns(billingInfo);
// Act // Act
var result = await sutProvider.Sut.GetHistoryAsync(organizationId); var result = await sutProvider.Sut.GetHistoryAsync(organizationId);

View File

@@ -37,7 +37,7 @@ public class OrganizationsControllerTests : IDisposable
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationService _organizationService; private readonly IOrganizationService _organizationService;
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IPaymentService _paymentService; private readonly IStripePaymentService _paymentService;
private readonly ISsoConfigRepository _ssoConfigRepository; private readonly ISsoConfigRepository _ssoConfigRepository;
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly IGetCloudOrganizationLicenseQuery _getCloudOrganizationLicenseQuery; private readonly IGetCloudOrganizationLicenseQuery _getCloudOrganizationLicenseQuery;
@@ -59,7 +59,7 @@ public class OrganizationsControllerTests : IDisposable
_organizationRepository = Substitute.For<IOrganizationRepository>(); _organizationRepository = Substitute.For<IOrganizationRepository>();
_organizationService = Substitute.For<IOrganizationService>(); _organizationService = Substitute.For<IOrganizationService>();
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>(); _organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
_paymentService = Substitute.For<IPaymentService>(); _paymentService = Substitute.For<IStripePaymentService>();
Substitute.For<IPolicyRepository>(); Substitute.For<IPolicyRepository>();
_ssoConfigRepository = Substitute.For<ISsoConfigRepository>(); _ssoConfigRepository = Substitute.For<ISsoConfigRepository>();
Substitute.For<ISsoConfigService>(); Substitute.For<ISsoConfigService>();

View File

@@ -10,10 +10,10 @@ using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Providers.Entities; using Bit.Core.Billing.Providers.Entities;
using Bit.Core.Billing.Providers.Repositories; using Bit.Core.Billing.Providers.Repositories;
using Bit.Core.Billing.Providers.Services; using Bit.Core.Billing.Providers.Services;
using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Bit.Core.Models.BitStripe; using Bit.Core.Models.BitStripe;
using Bit.Core.Services;
using Bit.Core.Test.Billing.Mocks; using Bit.Core.Test.Billing.Mocks;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
@@ -121,7 +121,7 @@ public class ProviderBillingControllerTests
} }
}; };
sutProvider.GetDependency<IStripeAdapter>().InvoiceListAsync(Arg.Is<StripeInvoiceListOptions>( sutProvider.GetDependency<IStripeAdapter>().ListInvoicesAsync(Arg.Is<StripeInvoiceListOptions>(
options => options =>
options.Customer == provider.GatewayCustomerId)).Returns(invoices); options.Customer == provider.GatewayCustomerId)).Returns(invoices);
@@ -301,7 +301,7 @@ public class ProviderBillingControllerTests
Status = "unpaid" Status = "unpaid"
}; };
stripeAdapter.SubscriptionGetAsync(provider.GatewaySubscriptionId, Arg.Is<SubscriptionGetOptions>( stripeAdapter.GetSubscriptionAsync(provider.GatewaySubscriptionId, Arg.Is<SubscriptionGetOptions>(
options => options =>
options.Expand.Contains("customer.tax_ids") && options.Expand.Contains("customer.tax_ids") &&
options.Expand.Contains("discounts") && options.Expand.Contains("discounts") &&
@@ -318,7 +318,7 @@ public class ProviderBillingControllerTests
Attempted = true Attempted = true
}; };
stripeAdapter.InvoiceSearchAsync(Arg.Is<InvoiceSearchOptions>( stripeAdapter.SearchInvoiceAsync(Arg.Is<InvoiceSearchOptions>(
options => options.Query == $"subscription:'{subscription.Id}' status:'open'")) options => options.Query == $"subscription:'{subscription.Id}' status:'open'"))
.Returns([overdueInvoice]); .Returns([overdueInvoice]);
@@ -351,7 +351,7 @@ public class ProviderBillingControllerTests
var plan = MockPlans.Get(providerPlan.PlanType); var plan = MockPlans.Get(providerPlan.PlanType);
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(providerPlan.PlanType).Returns(plan); sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(providerPlan.PlanType).Returns(plan);
var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, providerPlan.PlanType); var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, providerPlan.PlanType);
sutProvider.GetDependency<IStripeAdapter>().PriceGetAsync(priceId) sutProvider.GetDependency<IStripeAdapter>().GetPriceAsync(priceId)
.Returns(new Price .Returns(new Price
{ {
UnitAmountDecimal = plan.PasswordManager.ProviderPortalSeatPrice * 100 UnitAmountDecimal = plan.PasswordManager.ProviderPortalSeatPrice * 100
@@ -459,13 +459,13 @@ public class ProviderBillingControllerTests
Status = "active" Status = "active"
}; };
stripeAdapter.SubscriptionGetAsync(provider.GatewaySubscriptionId, Arg.Is<SubscriptionGetOptions>( stripeAdapter.GetSubscriptionAsync(provider.GatewaySubscriptionId, Arg.Is<SubscriptionGetOptions>(
options => options =>
options.Expand.Contains("customer.tax_ids") && options.Expand.Contains("customer.tax_ids") &&
options.Expand.Contains("discounts") && options.Expand.Contains("discounts") &&
options.Expand.Contains("test_clock"))).Returns(subscription); options.Expand.Contains("test_clock"))).Returns(subscription);
stripeAdapter.InvoiceSearchAsync(Arg.Is<InvoiceSearchOptions>( stripeAdapter.SearchInvoiceAsync(Arg.Is<InvoiceSearchOptions>(
options => options.Query == $"subscription:'{subscription.Id}' status:'open'")) options => options.Query == $"subscription:'{subscription.Id}' status:'open'"))
.Returns([]); .Returns([]);
@@ -498,7 +498,7 @@ public class ProviderBillingControllerTests
var plan = MockPlans.Get(providerPlan.PlanType); var plan = MockPlans.Get(providerPlan.PlanType);
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(providerPlan.PlanType).Returns(plan); sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(providerPlan.PlanType).Returns(plan);
var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, providerPlan.PlanType); var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, providerPlan.PlanType);
sutProvider.GetDependency<IStripeAdapter>().PriceGetAsync(priceId) sutProvider.GetDependency<IStripeAdapter>().GetPriceAsync(priceId)
.Returns(new Price .Returns(new Price
{ {
UnitAmountDecimal = plan.PasswordManager.ProviderPortalSeatPrice * 100 UnitAmountDecimal = plan.PasswordManager.ProviderPortalSeatPrice * 100

View File

@@ -31,7 +31,7 @@ public class BitPayControllerTests
private readonly IUserRepository _userRepository = Substitute.For<IUserRepository>(); private readonly IUserRepository _userRepository = Substitute.For<IUserRepository>();
private readonly IProviderRepository _providerRepository = Substitute.For<IProviderRepository>(); private readonly IProviderRepository _providerRepository = Substitute.For<IProviderRepository>();
private readonly IMailService _mailService = Substitute.For<IMailService>(); private readonly IMailService _mailService = Substitute.For<IMailService>();
private readonly IPaymentService _paymentService = Substitute.For<IPaymentService>(); private readonly IStripePaymentService _paymentService = Substitute.For<IStripePaymentService>();
private readonly IPremiumUserBillingService _premiumUserBillingService = private readonly IPremiumUserBillingService _premiumUserBillingService =
Substitute.For<IPremiumUserBillingService>(); Substitute.For<IPremiumUserBillingService>();

View File

@@ -28,7 +28,7 @@ public class PayPalControllerTests(ITestOutputHelper testOutputHelper)
private readonly IOptions<BillingSettings> _billingSettings = Substitute.For<IOptions<BillingSettings>>(); private readonly IOptions<BillingSettings> _billingSettings = Substitute.For<IOptions<BillingSettings>>();
private readonly IMailService _mailService = Substitute.For<IMailService>(); private readonly IMailService _mailService = Substitute.For<IMailService>();
private readonly IOrganizationRepository _organizationRepository = Substitute.For<IOrganizationRepository>(); private readonly IOrganizationRepository _organizationRepository = Substitute.For<IOrganizationRepository>();
private readonly IPaymentService _paymentService = Substitute.For<IPaymentService>(); private readonly IStripePaymentService _paymentService = Substitute.For<IStripePaymentService>();
private readonly ITransactionRepository _transactionRepository = Substitute.For<ITransactionRepository>(); private readonly ITransactionRepository _transactionRepository = Substitute.For<ITransactionRepository>();
private readonly IUserRepository _userRepository = Substitute.For<IUserRepository>(); private readonly IUserRepository _userRepository = Substitute.For<IUserRepository>();
private readonly IProviderRepository _providerRepository = Substitute.For<IProviderRepository>(); private readonly IProviderRepository _providerRepository = Substitute.For<IProviderRepository>();

View File

@@ -4,8 +4,8 @@ using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider; using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Caches; using Bit.Core.Billing.Caches;
using Bit.Core.Billing.Services;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using NSubstitute; using NSubstitute;
using Stripe; using Stripe;
using Xunit; using Xunit;
@@ -61,7 +61,7 @@ public class SetupIntentSucceededHandlerTests
// Assert // Assert
await _setupIntentCache.DidNotReceiveWithAnyArgs().GetSubscriberIdForSetupIntent(Arg.Any<string>()); await _setupIntentCache.DidNotReceiveWithAnyArgs().GetSubscriberIdForSetupIntent(Arg.Any<string>());
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync( await _stripeAdapter.DidNotReceiveWithAnyArgs().AttachPaymentMethodAsync(
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>()); Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
@@ -86,7 +86,7 @@ public class SetupIntentSucceededHandlerTests
await _handler.HandleAsync(_mockEvent); await _handler.HandleAsync(_mockEvent);
// Assert // Assert
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync( await _stripeAdapter.DidNotReceiveWithAnyArgs().AttachPaymentMethodAsync(
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>()); Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
@@ -116,7 +116,7 @@ public class SetupIntentSucceededHandlerTests
await _handler.HandleAsync(_mockEvent); await _handler.HandleAsync(_mockEvent);
// Assert // Assert
await _stripeAdapter.Received(1).PaymentMethodAttachAsync( await _stripeAdapter.Received(1).AttachPaymentMethodAsync(
"pm_test", "pm_test",
Arg.Is<PaymentMethodAttachOptions>(o => o.Customer == organization.GatewayCustomerId)); Arg.Is<PaymentMethodAttachOptions>(o => o.Customer == organization.GatewayCustomerId));
@@ -151,7 +151,7 @@ public class SetupIntentSucceededHandlerTests
await _handler.HandleAsync(_mockEvent); await _handler.HandleAsync(_mockEvent);
// Assert // Assert
await _stripeAdapter.Received(1).PaymentMethodAttachAsync( await _stripeAdapter.Received(1).AttachPaymentMethodAsync(
"pm_test", "pm_test",
Arg.Is<PaymentMethodAttachOptions>(o => o.Customer == provider.GatewayCustomerId)); Arg.Is<PaymentMethodAttachOptions>(o => o.Customer == provider.GatewayCustomerId));
@@ -183,7 +183,7 @@ public class SetupIntentSucceededHandlerTests
await _handler.HandleAsync(_mockEvent); await _handler.HandleAsync(_mockEvent);
// Assert // Assert
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync( await _stripeAdapter.DidNotReceiveWithAnyArgs().AttachPaymentMethodAsync(
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>()); Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
@@ -216,7 +216,7 @@ public class SetupIntentSucceededHandlerTests
await _handler.HandleAsync(_mockEvent); await _handler.HandleAsync(_mockEvent);
// Assert // Assert
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync( await _stripeAdapter.DidNotReceiveWithAnyArgs().AttachPaymentMethodAsync(
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>()); Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>()); await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());

View File

@@ -1,6 +1,7 @@
using Bit.Core.AdminConsole.Models.Business; using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.OrganizationFeatures.Import; using Bit.Core.AdminConsole.OrganizationFeatures.Import;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
@@ -57,7 +58,7 @@ public class ImportOrganizationUsersAndGroupsCommandTests
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>(); var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
SetupOrgUserRepositoryCreateManyAsyncMock(organizationUserRepository); SetupOrgUserRepositoryCreateManyAsyncMock(organizationUserRepository);
sutProvider.GetDependency<IPaymentService>().HasSecretsManagerStandalone(org).Returns(true); sutProvider.GetDependency<IStripePaymentService>().HasSecretsManagerStandalone(org).Returns(true);
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id).Returns(existingUsers); sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id).Returns(existingUsers);
sutProvider.GetDependency<IOrganizationRepository>().GetOccupiedSeatCountByOrganizationIdAsync(org.Id).Returns( sutProvider.GetDependency<IOrganizationRepository>().GetOccupiedSeatCountByOrganizationIdAsync(org.Id).Returns(
new OrganizationSeatCounts new OrganizationSeatCounts

View File

@@ -3,11 +3,11 @@ using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
using Bit.Core.AdminConsole.Utilities.Validation; using Bit.Core.AdminConsole.Utilities.Validation;
using Bit.Core.Billing.Services;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.Billing.Mocks.Plans; using Bit.Core.Test.Billing.Mocks.Plans;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
@@ -50,7 +50,7 @@ public class InviteOrganizationUsersValidatorTests
OccupiedSmSeats = 9 OccupiedSmSeats = 9
}; };
sutProvider.GetDependency<IPaymentService>() sutProvider.GetDependency<IStripePaymentService>()
.HasSecretsManagerStandalone(request.InviteOrganization) .HasSecretsManagerStandalone(request.InviteOrganization)
.Returns(true); .Returns(true);
@@ -96,7 +96,7 @@ public class InviteOrganizationUsersValidatorTests
OccupiedSmSeats = 9 OccupiedSmSeats = 9
}; };
sutProvider.GetDependency<IPaymentService>() sutProvider.GetDependency<IStripePaymentService>()
.HasSecretsManagerStandalone(request.InviteOrganization) .HasSecretsManagerStandalone(request.InviteOrganization)
.Returns(true); .Returns(true);
@@ -140,7 +140,7 @@ public class InviteOrganizationUsersValidatorTests
OccupiedSmSeats = 4 OccupiedSmSeats = 4
}; };
sutProvider.GetDependency<IPaymentService>() sutProvider.GetDependency<IStripePaymentService>()
.HasSecretsManagerStandalone(request.InviteOrganization) .HasSecretsManagerStandalone(request.InviteOrganization)
.Returns(true); .Returns(true);

View File

@@ -2,6 +2,7 @@
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations; using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@@ -172,7 +173,7 @@ public class ResellerClientOrganizationSignUpCommandTests
private static async Task AssertCleanupIsPerformed(SutProvider<ResellerClientOrganizationSignUpCommand> sutProvider) private static async Task AssertCleanupIsPerformed(SutProvider<ResellerClientOrganizationSignUpCommand> sutProvider)
{ {
await sutProvider.GetDependency<IPaymentService>() await sutProvider.GetDependency<IStripePaymentService>()
.Received(1) .Received(1)
.CancelAndRecoverChargesAsync(Arg.Any<Organization>()); .CancelAndRecoverChargesAsync(Arg.Any<Organization>());
await sutProvider.GetDependency<IOrganizationRepository>() await sutProvider.GetDependency<IOrganizationRepository>()

View File

@@ -2,9 +2,9 @@
using Bit.Core.AdminConsole.Models.Data.Organizations; using Bit.Core.AdminConsole.Models.Data.Organizations;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations; using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Services;
using Bit.Core.Models.StaticStore; using Bit.Core.Models.StaticStore;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.Billing.Mocks.Plans; using Bit.Core.Test.Billing.Mocks.Plans;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
@@ -28,7 +28,7 @@ public class UpdateOrganizationSubscriptionCommandTests
// Act // Act
await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate); await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate);
await sutProvider.GetDependency<IPaymentService>() await sutProvider.GetDependency<IStripePaymentService>()
.DidNotReceive() .DidNotReceive()
.AdjustSeatsAsync(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>()); .AdjustSeatsAsync(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>());
@@ -53,7 +53,7 @@ public class UpdateOrganizationSubscriptionCommandTests
// Act // Act
await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate); await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate);
await sutProvider.GetDependency<IPaymentService>() await sutProvider.GetDependency<IStripePaymentService>()
.Received(1) .Received(1)
.AdjustSeatsAsync( .AdjustSeatsAsync(
Arg.Is<Organization>(x => x.Id == organization.Id), Arg.Is<Organization>(x => x.Id == organization.Id),
@@ -81,7 +81,7 @@ public class UpdateOrganizationSubscriptionCommandTests
OrganizationSubscriptionUpdate[] subscriptionsToUpdate = OrganizationSubscriptionUpdate[] subscriptionsToUpdate =
[new() { Organization = organization, Plan = new Enterprise2023Plan(true) }]; [new() { Organization = organization, Plan = new Enterprise2023Plan(true) }];
sutProvider.GetDependency<IPaymentService>() sutProvider.GetDependency<IStripePaymentService>()
.AdjustSeatsAsync( .AdjustSeatsAsync(
Arg.Is<Organization>(x => x.Id == organization.Id), Arg.Is<Organization>(x => x.Id == organization.Id),
Arg.Is<Plan>(x => x.Type == organization.PlanType), Arg.Is<Plan>(x => x.Type == organization.PlanType),
@@ -115,7 +115,7 @@ public class UpdateOrganizationSubscriptionCommandTests
new() { Organization = failedOrganization, Plan = new Enterprise2023Plan(true) } new() { Organization = failedOrganization, Plan = new Enterprise2023Plan(true) }
]; ];
sutProvider.GetDependency<IPaymentService>() sutProvider.GetDependency<IStripePaymentService>()
.AdjustSeatsAsync( .AdjustSeatsAsync(
Arg.Is<Organization>(x => x.Id == failedOrganization.Id), Arg.Is<Organization>(x => x.Id == failedOrganization.Id),
Arg.Is<Plan>(x => x.Type == failedOrganization.PlanType), Arg.Is<Plan>(x => x.Type == failedOrganization.PlanType),
@@ -124,7 +124,7 @@ public class UpdateOrganizationSubscriptionCommandTests
// Act // Act
await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate); await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate);
await sutProvider.GetDependency<IPaymentService>() await sutProvider.GetDependency<IStripePaymentService>()
.Received(1) .Received(1)
.AdjustSeatsAsync( .AdjustSeatsAsync(
Arg.Is<Organization>(x => x.Id == successfulOrganization.Id), Arg.Is<Organization>(x => x.Id == successfulOrganization.Id),

View File

@@ -9,6 +9,7 @@ using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
@@ -1142,7 +1143,7 @@ public class OrganizationServiceTests
.GetByIdentifierAsync(Arg.Is<string>(id => id == organization.Identifier)); .GetByIdentifierAsync(Arg.Is<string>(id => id == organization.Identifier));
await stripeAdapter await stripeAdapter
.Received(1) .Received(1)
.CustomerUpdateAsync( .UpdateCustomerAsync(
Arg.Is<string>(id => id == organization.GatewayCustomerId), Arg.Is<string>(id => id == organization.GatewayCustomerId),
Arg.Is<CustomerUpdateOptions>(options => options.Email == requestOptionsReturned.Email Arg.Is<CustomerUpdateOptions>(options => options.Email == requestOptionsReturned.Email
&& options.Description == requestOptionsReturned.Description && options.Description == requestOptionsReturned.Description
@@ -1182,7 +1183,7 @@ public class OrganizationServiceTests
.GetByIdentifierAsync(Arg.Is<string>(id => id == organization.Identifier)); .GetByIdentifierAsync(Arg.Is<string>(id => id == organization.Identifier));
await stripeAdapter await stripeAdapter
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()); .UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>());
await organizationRepository await organizationRepository
.Received(1) .Received(1)
.ReplaceAsync(Arg.Is<Organization>(org => org == organization)); .ReplaceAsync(Arg.Is<Organization>(org => org == organization));

View File

@@ -4,7 +4,7 @@ using Bit.Core.Billing.Organizations.Commands;
using Bit.Core.Billing.Organizations.Models; using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Services; using Bit.Core.Billing.Services;
using Bit.Core.Test.Billing.Mocks.Plans; using Bit.Core.Test.Billing.Mocks.Plans;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
@@ -58,7 +58,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 5500 Total = 5500
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(purchase, billingAddress); var result = await _command.Run(purchase, billingAddress);
@@ -68,7 +68,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(55.00m, total); Assert.Equal(55.00m, total);
// Verify the correct Stripe API call for sponsored subscription // Verify the correct Stripe API call for sponsored subscription
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -116,7 +116,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 8250 Total = 8250
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(purchase, billingAddress); var result = await _command.Run(purchase, billingAddress);
@@ -126,7 +126,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(82.50m, total); Assert.Equal(82.50m, total);
// Verify the correct Stripe API call for standalone secrets manager // Verify the correct Stripe API call for standalone secrets manager
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "CA" && options.CustomerDetails.Address.Country == "CA" &&
@@ -179,7 +179,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 12200 Total = 12200
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(purchase, billingAddress); var result = await _command.Run(purchase, billingAddress);
@@ -189,7 +189,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(122.00m, total); Assert.Equal(122.00m, total);
// Verify the correct Stripe API call for comprehensive purchase with storage and service accounts // Verify the correct Stripe API call for comprehensive purchase with storage and service accounts
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "GB" && options.CustomerDetails.Address.Country == "GB" &&
@@ -240,7 +240,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 3300 Total = 3300
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(purchase, billingAddress); var result = await _command.Run(purchase, billingAddress);
@@ -250,7 +250,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(33.00m, total); Assert.Equal(33.00m, total);
// Verify the correct Stripe API call for Families tier (non-seat-based plan) // Verify the correct Stripe API call for Families tier (non-seat-based plan)
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -292,7 +292,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 2700 Total = 2700
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(purchase, billingAddress); var result = await _command.Run(purchase, billingAddress);
@@ -302,7 +302,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(27.00m, total); Assert.Equal(27.00m, total);
// Verify the correct Stripe API call for business use in non-US country (tax exempt reverse) // Verify the correct Stripe API call for business use in non-US country (tax exempt reverse)
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "DE" && options.CustomerDetails.Address.Country == "DE" &&
@@ -345,7 +345,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 12100 Total = 12100
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(purchase, billingAddress); var result = await _command.Run(purchase, billingAddress);
@@ -355,7 +355,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(121.00m, total); Assert.Equal(121.00m, total);
// Verify the correct Stripe API call for Spanish NIF that adds both Spanish NIF and EU VAT tax IDs // Verify the correct Stripe API call for Spanish NIF that adds both Spanish NIF and EU VAT tax IDs
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "ES" && options.CustomerDetails.Address.Country == "ES" &&
@@ -405,7 +405,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 1320 Total = 1320
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, planChange, billingAddress); var result = await _command.Run(organization, planChange, billingAddress);
@@ -415,7 +415,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(13.20m, total); Assert.Equal(13.20m, total);
// Verify the correct Stripe API call for free organization upgrade to Teams // Verify the correct Stripe API call for free organization upgrade to Teams
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -458,7 +458,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 4400 Total = 4400
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, planChange, billingAddress); var result = await _command.Run(organization, planChange, billingAddress);
@@ -468,7 +468,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(44.00m, total); Assert.Equal(44.00m, total);
// Verify the correct Stripe API call for free organization upgrade to Families (no SM for Families) // Verify the correct Stripe API call for free organization upgrade to Families (no SM for Families)
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "CA" && options.CustomerDetails.Address.Country == "CA" &&
@@ -522,7 +522,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = new Customer { Discount = null } Customer = new Customer { Discount = null }
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -534,7 +534,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 9900 Total = 9900
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, planChange, billingAddress); var result = await _command.Run(organization, planChange, billingAddress);
@@ -543,7 +543,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(9.00m, tax); Assert.Equal(9.00m, tax);
Assert.Equal(99.00m, total); Assert.Equal(99.00m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -597,7 +597,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = new Customer { Discount = null } Customer = new Customer { Discount = null }
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -609,7 +609,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 13200 Total = 13200
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, planChange, billingAddress); var result = await _command.Run(organization, planChange, billingAddress);
@@ -618,7 +618,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(12.00m, tax); Assert.Equal(12.00m, tax);
Assert.Equal(132.00m, total); Assert.Equal(132.00m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -661,7 +661,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 8800 Total = 8800
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, planChange, billingAddress); var result = await _command.Run(organization, planChange, billingAddress);
@@ -671,7 +671,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(88.00m, total); Assert.Equal(88.00m, total);
// Verify the correct Stripe API call for free organization with SM to Enterprise // Verify the correct Stripe API call for free organization with SM to Enterprise
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "GB" && options.CustomerDetails.Address.Country == "GB" &&
@@ -730,7 +730,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = new Customer { Discount = null } Customer = new Customer { Discount = null }
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -738,7 +738,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 16500 Total = 16500
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, planChange, billingAddress); var result = await _command.Run(organization, planChange, billingAddress);
@@ -748,7 +748,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(165.00m, total); Assert.Equal(165.00m, total);
// Verify the correct Stripe API call for existing subscription upgrade // Verify the correct Stripe API call for existing subscription upgrade
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "DE" && options.CustomerDetails.Address.Country == "DE" &&
@@ -814,7 +814,7 @@ public class PreviewOrganizationTaxCommandTests
} }
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -822,7 +822,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 6600 Total = 6600
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, planChange, billingAddress); var result = await _command.Run(organization, planChange, billingAddress);
@@ -832,7 +832,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(66.00m, total); Assert.Equal(66.00m, total);
// Verify the correct Stripe API call preserves existing discount // Verify the correct Stripe API call preserves existing discount
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -876,8 +876,8 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal("Organization does not have a subscription.", badRequest.Response); Assert.Equal("Organization does not have a subscription.", badRequest.Response);
// Verify no Stripe API calls were made // Verify no Stripe API calls were made
await _stripeAdapter.DidNotReceive().InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()); await _stripeAdapter.DidNotReceive().CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>());
await _stripeAdapter.DidNotReceive().SubscriptionGetAsync(Arg.Any<string>(), Arg.Any<SubscriptionGetOptions>()); await _stripeAdapter.DidNotReceive().GetSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionGetOptions>());
} }
#endregion #endregion
@@ -919,7 +919,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = customer Customer = customer
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -927,7 +927,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 6600 Total = 6600
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, update); var result = await _command.Run(organization, update);
@@ -937,7 +937,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(66.00m, total); Assert.Equal(66.00m, total);
// Verify the correct Stripe API call for PM seats only // Verify the correct Stripe API call for PM seats only
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -984,7 +984,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = customer Customer = customer
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -992,7 +992,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 13200 Total = 13200
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, update); var result = await _command.Run(organization, update);
@@ -1002,7 +1002,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(132.00m, total); Assert.Equal(132.00m, total);
// Verify the correct Stripe API call for PM seats + storage // Verify the correct Stripe API call for PM seats + storage
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "CA" && options.CustomerDetails.Address.Country == "CA" &&
@@ -1051,7 +1051,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = customer Customer = customer
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -1059,7 +1059,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 8800 Total = 8800
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, update); var result = await _command.Run(organization, update);
@@ -1069,7 +1069,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(88.00m, total); Assert.Equal(88.00m, total);
// Verify the correct Stripe API call for SM seats only // Verify the correct Stripe API call for SM seats only
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "DE" && options.CustomerDetails.Address.Country == "DE" &&
@@ -1119,7 +1119,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = customer Customer = customer
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -1127,7 +1127,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 16500 Total = 16500
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, update); var result = await _command.Run(organization, update);
@@ -1137,7 +1137,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(165.00m, total); Assert.Equal(165.00m, total);
// Verify the correct Stripe API call for SM seats + service accounts with tax ID // Verify the correct Stripe API call for SM seats + service accounts with tax ID
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "GB" && options.CustomerDetails.Address.Country == "GB" &&
@@ -1200,7 +1200,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = customer Customer = customer
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -1208,7 +1208,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 27500 Total = 27500
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, update); var result = await _command.Run(organization, update);
@@ -1218,7 +1218,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(275.00m, total); Assert.Equal(275.00m, total);
// Verify the correct Stripe API call for comprehensive update with discount and Spanish tax ID // Verify the correct Stripe API call for comprehensive update with discount and Spanish tax ID
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "ES" && options.CustomerDetails.Address.Country == "ES" &&
@@ -1276,7 +1276,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = customer Customer = customer
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -1284,7 +1284,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 5500 Total = 5500
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, update); var result = await _command.Run(organization, update);
@@ -1294,7 +1294,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(55.00m, total); Assert.Equal(55.00m, total);
// Verify the correct Stripe API call for Families tier (personal usage, no business tax exemption) // Verify the correct Stripe API call for Families tier (personal usage, no business tax exemption)
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "AU" && options.CustomerDetails.Address.Country == "AU" &&
@@ -1334,8 +1334,8 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal("Organization does not have a subscription.", badRequest.Response); Assert.Equal("Organization does not have a subscription.", badRequest.Response);
// Verify no Stripe API calls were made // Verify no Stripe API calls were made
await _stripeAdapter.DidNotReceive().InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()); await _stripeAdapter.DidNotReceive().CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>());
await _stripeAdapter.DidNotReceive().SubscriptionGetAsync(Arg.Any<string>(), Arg.Any<SubscriptionGetOptions>()); await _stripeAdapter.DidNotReceive().GetSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionGetOptions>());
} }
[Fact] [Fact]
@@ -1378,7 +1378,7 @@ public class PreviewOrganizationTaxCommandTests
Customer = customer Customer = customer
}; };
_stripeAdapter.SubscriptionGetAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription); _stripeAdapter.GetSubscriptionAsync("sub_test123", Arg.Any<SubscriptionGetOptions>()).Returns(subscription);
var invoice = new Invoice var invoice = new Invoice
{ {
@@ -1386,7 +1386,7 @@ public class PreviewOrganizationTaxCommandTests
Total = 3300 Total = 3300
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(organization, update); var result = await _command.Run(organization, update);
@@ -1396,7 +1396,7 @@ public class PreviewOrganizationTaxCommandTests
Assert.Equal(33.00m, total); Assert.Equal(33.00m, total);
// Verify only PM seats are included (storage=0 excluded, SM seats=0 so entire SM excluded) // Verify only PM seats are included (storage=0 excluded, SM seats=0 so entire SM excluded)
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&

View File

@@ -8,7 +8,6 @@ using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Platform.Installations; using Bit.Core.Platform.Installations;
using Bit.Core.Services;
using Bit.Core.Test.AutoFixture; using Bit.Core.Test.AutoFixture;
using Bit.Core.Test.Billing.AutoFixture; using Bit.Core.Test.Billing.AutoFixture;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
@@ -59,7 +58,7 @@ public class GetCloudOrganizationLicenseQueryTests
{ {
installation.Enabled = true; installation.Enabled = true;
sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation); sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation);
sutProvider.GetDependency<IPaymentService>().GetSubscriptionAsync(organization).Returns(subInfo); sutProvider.GetDependency<IStripePaymentService>().GetSubscriptionAsync(organization).Returns(subInfo);
sutProvider.GetDependency<ILicensingService>().SignLicense(Arg.Any<ILicense>()).Returns(licenseSignature); sutProvider.GetDependency<ILicensingService>().SignLicense(Arg.Any<ILicense>()).Returns(licenseSignature);
var result = await sutProvider.Sut.GetLicenseAsync(organization, installationId); var result = await sutProvider.Sut.GetLicenseAsync(organization, installationId);
@@ -80,7 +79,7 @@ public class GetCloudOrganizationLicenseQueryTests
{ {
installation.Enabled = true; installation.Enabled = true;
sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation); sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation);
sutProvider.GetDependency<IPaymentService>().GetSubscriptionAsync(organization).Returns(subInfo); sutProvider.GetDependency<IStripePaymentService>().GetSubscriptionAsync(organization).Returns(subInfo);
sutProvider.GetDependency<ILicensingService>().SignLicense(Arg.Any<ILicense>()).Returns(licenseSignature); sutProvider.GetDependency<ILicensingService>().SignLicense(Arg.Any<ILicense>()).Returns(licenseSignature);
sutProvider.GetDependency<ILicensingService>() sutProvider.GetDependency<ILicensingService>()
.CreateOrganizationTokenAsync(organization, installationId, subInfo) .CreateOrganizationTokenAsync(organization, installationId, subInfo)
@@ -119,7 +118,7 @@ public class GetCloudOrganizationLicenseQueryTests
installation.Enabled = true; installation.Enabled = true;
sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation); sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation);
sutProvider.GetDependency<IProviderRepository>().GetByOrganizationIdAsync(organization.Id).Returns(provider); sutProvider.GetDependency<IProviderRepository>().GetByOrganizationIdAsync(organization.Id).Returns(provider);
sutProvider.GetDependency<IPaymentService>().GetSubscriptionAsync(provider).Returns(subInfo); sutProvider.GetDependency<IStripePaymentService>().GetSubscriptionAsync(provider).Returns(subInfo);
sutProvider.GetDependency<ILicensingService>().SignLicense(Arg.Any<ILicense>()).Returns(licenseSignature); sutProvider.GetDependency<ILicensingService>().SignLicense(Arg.Any<ILicense>()).Returns(licenseSignature);
var result = await sutProvider.Sut.GetLicenseAsync(organization, installationId); var result = await sutProvider.Sut.GetLicenseAsync(organization, installationId);

View File

@@ -8,7 +8,6 @@ using Bit.Core.Billing.Organizations.Queries;
using Bit.Core.Billing.Payment.Queries; using Bit.Core.Billing.Payment.Queries;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
@@ -382,7 +381,7 @@ public class GetOrganizationWarningsQueryTests
var dueDate = now.AddDays(-10); var dueDate = now.AddDays(-10);
sutProvider.GetDependency<IStripeAdapter>().InvoiceSearchAsync(Arg.Is<InvoiceSearchOptions>(options => sutProvider.GetDependency<IStripeAdapter>().SearchInvoiceAsync(Arg.Is<InvoiceSearchOptions>(options =>
options.Query == $"subscription:'{subscriptionId}' status:'open'")).Returns([ options.Query == $"subscription:'{subscriptionId}' status:'open'")).Returns([
new Invoice { DueDate = dueDate, Created = dueDate.AddDays(-30) } new Invoice { DueDate = dueDate, Created = dueDate.AddDays(-30) }
]); ]);
@@ -542,7 +541,7 @@ public class GetOrganizationWarningsQueryTests
.Returns(true); .Returns(true);
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) .ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = new List<Registration> Data = new List<Registration>
@@ -583,7 +582,7 @@ public class GetOrganizationWarningsQueryTests
.Returns(true); .Returns(true);
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) .ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = new List<Registration> Data = new List<Registration>
@@ -635,7 +634,7 @@ public class GetOrganizationWarningsQueryTests
.Returns(true); .Returns(true);
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) .ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = new List<Registration> Data = new List<Registration>
@@ -687,7 +686,7 @@ public class GetOrganizationWarningsQueryTests
.Returns(true); .Returns(true);
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) .ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = new List<Registration> Data = new List<Registration>
@@ -739,7 +738,7 @@ public class GetOrganizationWarningsQueryTests
.Returns(true); .Returns(true);
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) .ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = new List<Registration> Data = new List<Registration>
@@ -785,7 +784,7 @@ public class GetOrganizationWarningsQueryTests
.Returns(true); .Returns(true);
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.TaxRegistrationsListAsync(Arg.Any<RegistrationListOptions>()) .ListTaxRegistrationsAsync(Arg.Any<RegistrationListOptions>())
.Returns(new StripeList<Registration> .Returns(new StripeList<Registration>
{ {
Data = new List<Registration> Data = new List<Registration>

View File

@@ -4,7 +4,6 @@ using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Payment.Commands; using Bit.Core.Billing.Payment.Commands;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Services;
using Bit.Core.Test.Billing.Extensions; using Bit.Core.Test.Billing.Extensions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
@@ -73,7 +72,7 @@ public class UpdateBillingAddressCommandTests
} }
}; };
_stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Matches(input) && options.Address.Matches(input) &&
options.HasExpansions("subscriptions") options.HasExpansions("subscriptions")
)).Returns(customer); )).Returns(customer);
@@ -84,7 +83,7 @@ public class UpdateBillingAddressCommandTests
var output = result.AsT0; var output = result.AsT0;
Assert.Equivalent(input, output); Assert.Equivalent(input, output);
await _stripeAdapter.Received(1).SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await _stripeAdapter.Received(1).UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
} }
@@ -131,7 +130,7 @@ public class UpdateBillingAddressCommandTests
} }
}; };
_stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Matches(input) && options.Address.Matches(input) &&
options.HasExpansions("subscriptions") options.HasExpansions("subscriptions")
)).Returns(customer); )).Returns(customer);
@@ -144,7 +143,7 @@ public class UpdateBillingAddressCommandTests
await _subscriberService.Received(1).CreateStripeCustomer(organization); await _subscriberService.Received(1).CreateStripeCustomer(organization);
await _stripeAdapter.Received(1).SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await _stripeAdapter.Received(1).UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
} }
@@ -192,7 +191,7 @@ public class UpdateBillingAddressCommandTests
} }
}; };
_stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Matches(input) && options.Address.Matches(input) &&
options.HasExpansions("subscriptions", "tax_ids") && options.HasExpansions("subscriptions", "tax_ids") &&
options.TaxExempt == TaxExempt.None options.TaxExempt == TaxExempt.None
@@ -204,7 +203,7 @@ public class UpdateBillingAddressCommandTests
var output = result.AsT0; var output = result.AsT0;
Assert.Equivalent(input, output); Assert.Equivalent(input, output);
await _stripeAdapter.Received(1).SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await _stripeAdapter.Received(1).UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
} }
@@ -260,7 +259,7 @@ public class UpdateBillingAddressCommandTests
} }
}; };
_stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Matches(input) && options.Address.Matches(input) &&
options.HasExpansions("subscriptions", "tax_ids") && options.HasExpansions("subscriptions", "tax_ids") &&
options.TaxExempt == TaxExempt.None options.TaxExempt == TaxExempt.None
@@ -272,10 +271,10 @@ public class UpdateBillingAddressCommandTests
var output = result.AsT0; var output = result.AsT0;
Assert.Equivalent(input, output); Assert.Equivalent(input, output);
await _stripeAdapter.Received(1).SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await _stripeAdapter.Received(1).UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
await _stripeAdapter.Received(1).TaxIdDeleteAsync(customer.Id, "tax_id_123"); await _stripeAdapter.Received(1).DeleteTaxIdAsync(customer.Id, "tax_id_123");
} }
[Fact] [Fact]
@@ -322,7 +321,7 @@ public class UpdateBillingAddressCommandTests
} }
}; };
_stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Matches(input) && options.Address.Matches(input) &&
options.HasExpansions("subscriptions", "tax_ids") && options.HasExpansions("subscriptions", "tax_ids") &&
options.TaxExempt == TaxExempt.Reverse options.TaxExempt == TaxExempt.Reverse
@@ -334,7 +333,7 @@ public class UpdateBillingAddressCommandTests
var output = result.AsT0; var output = result.AsT0;
Assert.Equivalent(input, output); Assert.Equivalent(input, output);
await _stripeAdapter.Received(1).SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await _stripeAdapter.Received(1).UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
} }
@@ -384,14 +383,14 @@ public class UpdateBillingAddressCommandTests
} }
}; };
_stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options => _stripeAdapter.UpdateCustomerAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Matches(input) && options.Address.Matches(input) &&
options.HasExpansions("subscriptions", "tax_ids") && options.HasExpansions("subscriptions", "tax_ids") &&
options.TaxExempt == TaxExempt.Reverse options.TaxExempt == TaxExempt.Reverse
)).Returns(customer); )).Returns(customer);
_stripeAdapter _stripeAdapter
.TaxIdCreateAsync(customer.Id, .CreateTaxIdAsync(customer.Id,
Arg.Is<TaxIdCreateOptions>(options => options.Type == TaxIdType.EUVAT)) Arg.Is<TaxIdCreateOptions>(options => options.Type == TaxIdType.EUVAT))
.Returns(new TaxId { Type = TaxIdType.EUVAT, Value = "ESA12345678" }); .Returns(new TaxId { Type = TaxIdType.EUVAT, Value = "ESA12345678" });
@@ -401,10 +400,10 @@ public class UpdateBillingAddressCommandTests
var output = result.AsT0; var output = result.AsT0;
Assert.Equivalent(input with { TaxId = new TaxID(TaxIdType.EUVAT, "ESA12345678") }, output); Assert.Equivalent(input with { TaxId = new TaxID(TaxIdType.EUVAT, "ESA12345678") }, output);
await _stripeAdapter.Received(1).SubscriptionUpdateAsync(organization.GatewaySubscriptionId, await _stripeAdapter.Received(1).UpdateSubscriptionAsync(organization.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
await _stripeAdapter.Received(1).TaxIdCreateAsync(organization.GatewayCustomerId, Arg.Is<TaxIdCreateOptions>( await _stripeAdapter.Received(1).CreateTaxIdAsync(organization.GatewayCustomerId, Arg.Is<TaxIdCreateOptions>(
options => options.Type == TaxIdType.SpanishNIF && options => options.Type == TaxIdType.SpanishNIF &&
options.Value == input.TaxId.Value)); options.Value == input.TaxId.Value));
} }

View File

@@ -4,7 +4,6 @@ using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Payment.Commands; using Bit.Core.Billing.Payment.Commands;
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Test.Billing.Extensions; using Bit.Core.Test.Billing.Extensions;
using Braintree; using Braintree;
@@ -82,7 +81,7 @@ public class UpdatePaymentMethodCommandTests
Status = "requires_action" Status = "requires_action"
}; };
_stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => _stripeAdapter.ListSetupIntentsAsync(Arg.Is<SetupIntentListOptions>(options =>
options.PaymentMethod == token && options.HasExpansions("data.payment_method"))).Returns([setupIntent]); options.PaymentMethod == token && options.HasExpansions("data.payment_method"))).Returns([setupIntent]);
var result = await _command.Run(organization, var result = await _command.Run(organization,
@@ -144,7 +143,7 @@ public class UpdatePaymentMethodCommandTests
Status = "requires_action" Status = "requires_action"
}; };
_stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => _stripeAdapter.ListSetupIntentsAsync(Arg.Is<SetupIntentListOptions>(options =>
options.PaymentMethod == token && options.HasExpansions("data.payment_method"))).Returns([setupIntent]); options.PaymentMethod == token && options.HasExpansions("data.payment_method"))).Returns([setupIntent]);
var result = await _command.Run(organization, var result = await _command.Run(organization,
@@ -213,7 +212,7 @@ public class UpdatePaymentMethodCommandTests
Status = "requires_action" Status = "requires_action"
}; };
_stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => _stripeAdapter.ListSetupIntentsAsync(Arg.Is<SetupIntentListOptions>(options =>
options.PaymentMethod == token && options.HasExpansions("data.payment_method"))).Returns([setupIntent]); options.PaymentMethod == token && options.HasExpansions("data.payment_method"))).Returns([setupIntent]);
var result = await _command.Run(organization, var result = await _command.Run(organization,
@@ -232,7 +231,7 @@ public class UpdatePaymentMethodCommandTests
Assert.Equal("https://example.com", maskedBankAccount.HostedVerificationUrl); Assert.Equal("https://example.com", maskedBankAccount.HostedVerificationUrl);
await _setupIntentCache.Received(1).Set(organization.Id, setupIntent.Id); await _setupIntentCache.Received(1).Set(organization.Id, setupIntent.Id);
await _stripeAdapter.Received(1).CustomerUpdateAsync(customer.Id, Arg.Is<CustomerUpdateOptions>(options => await _stripeAdapter.Received(1).UpdateCustomerAsync(customer.Id, Arg.Is<CustomerUpdateOptions>(options =>
options.Metadata[MetadataKeys.BraintreeCustomerId] == string.Empty && options.Metadata[MetadataKeys.BraintreeCustomerId] == string.Empty &&
options.Metadata[MetadataKeys.RetiredBraintreeCustomerId] == "braintree_customer_id")); options.Metadata[MetadataKeys.RetiredBraintreeCustomerId] == "braintree_customer_id"));
} }
@@ -262,7 +261,7 @@ public class UpdatePaymentMethodCommandTests
const string token = "TOKEN"; const string token = "TOKEN";
_stripeAdapter _stripeAdapter
.PaymentMethodAttachAsync(token, .AttachPaymentMethodAsync(token,
Arg.Is<PaymentMethodAttachOptions>(options => options.Customer == customer.Id)) Arg.Is<PaymentMethodAttachOptions>(options => options.Customer == customer.Id))
.Returns(new PaymentMethod .Returns(new PaymentMethod
{ {
@@ -291,7 +290,7 @@ public class UpdatePaymentMethodCommandTests
Assert.Equal("9999", maskedCard.Last4); Assert.Equal("9999", maskedCard.Last4);
Assert.Equal("01/2028", maskedCard.Expiration); Assert.Equal("01/2028", maskedCard.Expiration);
await _stripeAdapter.Received(1).CustomerUpdateAsync(customer.Id, await _stripeAdapter.Received(1).UpdateCustomerAsync(customer.Id,
Arg.Is<CustomerUpdateOptions>(options => options.InvoiceSettings.DefaultPaymentMethod == token)); Arg.Is<CustomerUpdateOptions>(options => options.InvoiceSettings.DefaultPaymentMethod == token));
} }
@@ -315,7 +314,7 @@ public class UpdatePaymentMethodCommandTests
const string token = "TOKEN"; const string token = "TOKEN";
_stripeAdapter _stripeAdapter
.PaymentMethodAttachAsync(token, .AttachPaymentMethodAsync(token,
Arg.Is<PaymentMethodAttachOptions>(options => options.Customer == customer.Id)) Arg.Is<PaymentMethodAttachOptions>(options => options.Customer == customer.Id))
.Returns(new PaymentMethod .Returns(new PaymentMethod
{ {
@@ -344,10 +343,10 @@ public class UpdatePaymentMethodCommandTests
Assert.Equal("9999", maskedCard.Last4); Assert.Equal("9999", maskedCard.Last4);
Assert.Equal("01/2028", maskedCard.Expiration); Assert.Equal("01/2028", maskedCard.Expiration);
await _stripeAdapter.Received(1).CustomerUpdateAsync(customer.Id, await _stripeAdapter.Received(1).UpdateCustomerAsync(customer.Id,
Arg.Is<CustomerUpdateOptions>(options => options.InvoiceSettings.DefaultPaymentMethod == token)); Arg.Is<CustomerUpdateOptions>(options => options.InvoiceSettings.DefaultPaymentMethod == token));
await _stripeAdapter.Received(1).CustomerUpdateAsync(customer.Id, await _stripeAdapter.Received(1).UpdateCustomerAsync(customer.Id,
Arg.Is<CustomerUpdateOptions>(options => options.Address.Country == "US" && options.Address.PostalCode == "12345")); Arg.Is<CustomerUpdateOptions>(options => options.Address.Country == "US" && options.Address.PostalCode == "12345"));
} }
@@ -468,7 +467,7 @@ public class UpdatePaymentMethodCommandTests
var maskedPayPalAccount = maskedPaymentMethod.AsT2; var maskedPayPalAccount = maskedPaymentMethod.AsT2;
Assert.Equal("user@gmail.com", maskedPayPalAccount.Email); Assert.Equal("user@gmail.com", maskedPayPalAccount.Email);
await _stripeAdapter.Received(1).CustomerUpdateAsync(customer.Id, await _stripeAdapter.Received(1).UpdateCustomerAsync(customer.Id,
Arg.Is<CustomerUpdateOptions>(options => Arg.Is<CustomerUpdateOptions>(options =>
options.Metadata[MetadataKeys.BraintreeCustomerId] == "braintree_customer_id")); options.Metadata[MetadataKeys.BraintreeCustomerId] == "braintree_customer_id"));
} }

View File

@@ -3,7 +3,6 @@ using Bit.Core.Billing.Caches;
using Bit.Core.Billing.Constants; using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Payment.Queries; using Bit.Core.Billing.Payment.Queries;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Services;
using Bit.Core.Test.Billing.Extensions; using Bit.Core.Test.Billing.Extensions;
using Braintree; using Braintree;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -166,7 +165,7 @@ public class GetPaymentMethodQueryTests
_setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123"); _setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123");
_stripeAdapter _stripeAdapter
.SetupIntentGet("seti_123", .GetSetupIntentAsync("seti_123",
Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method"))).Returns( Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method"))).Returns(
new SetupIntent new SetupIntent
{ {

View File

@@ -3,7 +3,6 @@ using Bit.Core.Billing.Caches;
using Bit.Core.Billing.Constants; using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Payment.Queries; using Bit.Core.Billing.Payment.Queries;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Services;
using Bit.Core.Test.Billing.Extensions; using Bit.Core.Test.Billing.Extensions;
using NSubstitute; using NSubstitute;
using NSubstitute.ReturnsExtensions; using NSubstitute.ReturnsExtensions;
@@ -57,7 +56,7 @@ public class HasPaymentMethodQueryTests
_setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123"); _setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123");
_stripeAdapter _stripeAdapter
.SetupIntentGet("seti_123", .GetSetupIntentAsync("seti_123",
Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method"))) Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method")))
.Returns(new SetupIntent .Returns(new SetupIntent
{ {
@@ -162,7 +161,7 @@ public class HasPaymentMethodQueryTests
_setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123"); _setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123");
_stripeAdapter _stripeAdapter
.SetupIntentGet("seti_123", .GetSetupIntentAsync("seti_123",
Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method"))) Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method")))
.Returns(new SetupIntent .Returns(new SetupIntent
{ {
@@ -246,7 +245,7 @@ public class HasPaymentMethodQueryTests
_setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123"); _setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123");
_stripeAdapter _stripeAdapter
.SetupIntentGet("seti_123", .GetSetupIntentAsync("seti_123",
Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method"))) Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method")))
.Returns(new SetupIntent .Returns(new SetupIntent
{ {

View File

@@ -146,11 +146,11 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockSetupIntent = Substitute.For<SetupIntent>(); var mockSetupIntent = Substitute.For<SetupIntent>();
mockSetupIntent.Id = "seti_123"; mockSetupIntent.Id = "seti_123";
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_stripeAdapter.SetupIntentList(Arg.Any<SetupIntentListOptions>()).Returns(Task.FromResult(new List<SetupIntent> { mockSetupIntent })); _stripeAdapter.ListSetupIntentsAsync(Arg.Any<SetupIntentListOptions>()).Returns(Task.FromResult(new List<SetupIntent> { mockSetupIntent }));
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
// Act // Act
@@ -158,8 +158,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
// Assert // Assert
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _stripeAdapter.Received(1).CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()); await _stripeAdapter.Received(1).CreateCustomerAsync(Arg.Any<CustomerCreateOptions>());
await _stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); await _stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
await _userService.Received(1).SaveUserAsync(user); await _userService.Received(1).SaveUserAsync(user);
await _pushNotificationService.Received(1).PushSyncVaultAsync(user.Id); await _pushNotificationService.Received(1).PushSyncVaultAsync(user.Id);
} }
@@ -200,10 +200,10 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
// Act // Act
@@ -211,8 +211,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
// Assert // Assert
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _stripeAdapter.Received(1).CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()); await _stripeAdapter.Received(1).CreateCustomerAsync(Arg.Any<CustomerCreateOptions>());
await _stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); await _stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
await _userService.Received(1).SaveUserAsync(user); await _userService.Received(1).SaveUserAsync(user);
await _pushNotificationService.Received(1).PushSyncVaultAsync(user.Id); await _pushNotificationService.Received(1).PushSyncVaultAsync(user.Id);
} }
@@ -243,10 +243,10 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
_subscriberService.CreateBraintreeCustomer(Arg.Any<User>(), Arg.Any<string>()).Returns("bt_customer_123"); _subscriberService.CreateBraintreeCustomer(Arg.Any<User>(), Arg.Any<string>()).Returns("bt_customer_123");
@@ -255,8 +255,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
// Assert // Assert
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _stripeAdapter.Received(1).CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()); await _stripeAdapter.Received(1).CreateCustomerAsync(Arg.Any<CustomerCreateOptions>());
await _stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); await _stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
await _subscriberService.Received(1).CreateBraintreeCustomer(user, paymentMethod.Token); await _subscriberService.Received(1).CreateBraintreeCustomer(user, paymentMethod.Token);
await _userService.Received(1).SaveUserAsync(user); await _userService.Received(1).SaveUserAsync(user);
await _pushNotificationService.Received(1).PushSyncVaultAsync(user.Id); await _pushNotificationService.Received(1).PushSyncVaultAsync(user.Id);
@@ -299,10 +299,10 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
// Act // Act
@@ -356,8 +356,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
// Mock that the user has a payment method (this is the key difference from the credit purchase case) // Mock that the user has a payment method (this is the key difference from the credit purchase case)
_hasPaymentMethodQuery.Run(Arg.Any<User>()).Returns(true); _hasPaymentMethodQuery.Run(Arg.Any<User>()).Returns(true);
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
// Act // Act
var result = await _command.Run(user, paymentMethod, billingAddress, 0); var result = await _command.Run(user, paymentMethod, billingAddress, 0);
@@ -365,7 +365,7 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
// Assert // Assert
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _subscriberService.Received(1).GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()); await _subscriberService.Received(1).GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>());
await _stripeAdapter.DidNotReceive().CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()); await _stripeAdapter.DidNotReceive().CreateCustomerAsync(Arg.Any<CustomerCreateOptions>());
await _updatePaymentMethodCommand.DidNotReceive().Run(Arg.Any<User>(), Arg.Any<TokenizedPaymentMethod>(), Arg.Any<BillingAddress>()); await _updatePaymentMethodCommand.DidNotReceive().Run(Arg.Any<User>(), Arg.Any<TokenizedPaymentMethod>(), Arg.Any<BillingAddress>());
} }
@@ -415,8 +415,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
_updatePaymentMethodCommand.Run(Arg.Any<User>(), Arg.Any<TokenizedPaymentMethod>(), Arg.Any<BillingAddress>()) _updatePaymentMethodCommand.Run(Arg.Any<User>(), Arg.Any<TokenizedPaymentMethod>(), Arg.Any<BillingAddress>())
.Returns(mockMaskedPaymentMethod); .Returns(mockMaskedPaymentMethod);
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
// Act // Act
var result = await _command.Run(user, paymentMethod, billingAddress, 0); var result = await _command.Run(user, paymentMethod, billingAddress, 0);
@@ -428,9 +428,9 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
// Verify GetCustomerOrThrow was called after updating payment method // Verify GetCustomerOrThrow was called after updating payment method
await _subscriberService.Received(1).GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()); await _subscriberService.Received(1).GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>());
// Verify no new customer was created // Verify no new customer was created
await _stripeAdapter.DidNotReceive().CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()); await _stripeAdapter.DidNotReceive().CreateCustomerAsync(Arg.Any<CustomerCreateOptions>());
// Verify subscription was created // Verify subscription was created
await _stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); await _stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
// Verify user was updated correctly // Verify user was updated correctly
Assert.True(user.Premium); Assert.True(user.Premium);
await _userService.Received(1).SaveUserAsync(user); await _userService.Received(1).SaveUserAsync(user);
@@ -474,10 +474,10 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_subscriberService.CreateBraintreeCustomer(Arg.Any<User>(), Arg.Any<string>()).Returns("bt_customer_123"); _subscriberService.CreateBraintreeCustomer(Arg.Any<User>(), Arg.Any<string>()).Returns("bt_customer_123");
// Act // Act
@@ -525,10 +525,10 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
// Act // Act
@@ -577,10 +577,10 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_subscriberService.CreateBraintreeCustomer(Arg.Any<User>(), Arg.Any<string>()).Returns("bt_customer_123"); _subscriberService.CreateBraintreeCustomer(Arg.Any<User>(), Arg.Any<string>()).Returns("bt_customer_123");
// Act // Act
@@ -628,13 +628,13 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer); _stripeAdapter.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
_stripeAdapter.SetupIntentList(Arg.Any<SetupIntentListOptions>()) _stripeAdapter.ListSetupIntentsAsync(Arg.Any<SetupIntentListOptions>())
.Returns(Task.FromResult(new List<SetupIntent>())); // Empty list - no setup intent found .Returns(Task.FromResult(new List<SetupIntent>())); // Empty list - no setup intent found
// Act // Act
@@ -681,8 +681,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
var mockInvoice = Substitute.For<Invoice>(); var mockInvoice = Substitute.For<Invoice>();
_subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer); _subscriberService.GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
_stripeAdapter.InvoiceUpdateAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice); _stripeAdapter.UpdateInvoiceAsync(Arg.Any<string>(), Arg.Any<InvoiceUpdateOptions>()).Returns(mockInvoice);
// Act // Act
var result = await _command.Run(user, paymentMethod, billingAddress, 0); var result = await _command.Run(user, paymentMethod, billingAddress, 0);
@@ -690,7 +690,7 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
// Assert // Assert
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _subscriberService.Received(1).GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>()); await _subscriberService.Received(1).GetCustomerOrThrow(Arg.Any<User>(), Arg.Any<CustomerGetOptions>());
await _stripeAdapter.DidNotReceive().CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()); await _stripeAdapter.DidNotReceive().CreateCustomerAsync(Arg.Any<CustomerCreateOptions>());
Assert.True(user.Premium); Assert.True(user.Premium);
Assert.Equal(mockSubscription.GetCurrentPeriodEnd(), user.PremiumExpirationDate); Assert.Equal(mockSubscription.GetCurrentPeriodEnd(), user.PremiumExpirationDate);
} }
@@ -716,8 +716,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
Assert.True(result.IsT3); // Assuming T3 is the Unhandled result Assert.True(result.IsT3); // Assuming T3 is the Unhandled result
Assert.IsType<BillingException>(result.AsT3.Exception); Assert.IsType<BillingException>(result.AsT3.Exception);
// Verify no customer was created or subscription attempted // Verify no customer was created or subscription attempted
await _stripeAdapter.DidNotReceive().CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()); await _stripeAdapter.DidNotReceive().CreateCustomerAsync(Arg.Any<CustomerCreateOptions>());
await _stripeAdapter.DidNotReceive().SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); await _stripeAdapter.DidNotReceive().CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
await _userService.DidNotReceive().SaveUserAsync(Arg.Any<User>()); await _userService.DidNotReceive().SaveUserAsync(Arg.Any<User>());
} }
@@ -767,8 +767,8 @@ public class CreatePremiumCloudHostedSubscriptionCommandTests
] ]
}; };
_stripeAdapter.CustomerCreateAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer); _stripeAdapter.CreateCustomerAsync(Arg.Any<CustomerCreateOptions>()).Returns(mockCustomer);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(mockSubscription);
// Act // Act
var result = await _command.Run(user, paymentMethod, billingAddress, additionalStorage); var result = await _command.Run(user, paymentMethod, billingAddress, additionalStorage);

View File

@@ -1,7 +1,7 @@
using Bit.Core.Billing.Payment.Models; using Bit.Core.Billing.Payment.Models;
using Bit.Core.Billing.Premium.Commands; using Bit.Core.Billing.Premium.Commands;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Services; using Bit.Core.Billing.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
using Stripe; using Stripe;
@@ -50,7 +50,7 @@ public class PreviewPremiumTaxCommandTests
Total = 3300 Total = 3300
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(0, billingAddress); var result = await _command.Run(0, billingAddress);
@@ -59,7 +59,7 @@ public class PreviewPremiumTaxCommandTests
Assert.Equal(3.00m, tax); Assert.Equal(3.00m, tax);
Assert.Equal(33.00m, total); Assert.Equal(33.00m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -84,7 +84,7 @@ public class PreviewPremiumTaxCommandTests
Total = 5500 Total = 5500
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(5, billingAddress); var result = await _command.Run(5, billingAddress);
@@ -93,7 +93,7 @@ public class PreviewPremiumTaxCommandTests
Assert.Equal(5.00m, tax); Assert.Equal(5.00m, tax);
Assert.Equal(55.00m, total); Assert.Equal(55.00m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "CA" && options.CustomerDetails.Address.Country == "CA" &&
@@ -120,7 +120,7 @@ public class PreviewPremiumTaxCommandTests
Total = 2750 Total = 2750
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(0, billingAddress); var result = await _command.Run(0, billingAddress);
@@ -129,7 +129,7 @@ public class PreviewPremiumTaxCommandTests
Assert.Equal(2.50m, tax); Assert.Equal(2.50m, tax);
Assert.Equal(27.50m, total); Assert.Equal(27.50m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "GB" && options.CustomerDetails.Address.Country == "GB" &&
@@ -154,7 +154,7 @@ public class PreviewPremiumTaxCommandTests
Total = 8800 Total = 8800
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(20, billingAddress); var result = await _command.Run(20, billingAddress);
@@ -163,7 +163,7 @@ public class PreviewPremiumTaxCommandTests
Assert.Equal(8.00m, tax); Assert.Equal(8.00m, tax);
Assert.Equal(88.00m, total); Assert.Equal(88.00m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "DE" && options.CustomerDetails.Address.Country == "DE" &&
@@ -190,7 +190,7 @@ public class PreviewPremiumTaxCommandTests
Total = 4950 Total = 4950
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(10, billingAddress); var result = await _command.Run(10, billingAddress);
@@ -199,7 +199,7 @@ public class PreviewPremiumTaxCommandTests
Assert.Equal(4.50m, tax); Assert.Equal(4.50m, tax);
Assert.Equal(49.50m, total); Assert.Equal(49.50m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "AU" && options.CustomerDetails.Address.Country == "AU" &&
@@ -226,7 +226,7 @@ public class PreviewPremiumTaxCommandTests
Total = 3000 Total = 3000
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(0, billingAddress); var result = await _command.Run(0, billingAddress);
@@ -235,7 +235,7 @@ public class PreviewPremiumTaxCommandTests
Assert.Equal(0.00m, tax); Assert.Equal(0.00m, tax);
Assert.Equal(30.00m, total); Assert.Equal(30.00m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "US" && options.CustomerDetails.Address.Country == "US" &&
@@ -260,7 +260,7 @@ public class PreviewPremiumTaxCommandTests
Total = 6600 Total = 6600
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(-5, billingAddress); var result = await _command.Run(-5, billingAddress);
@@ -269,7 +269,7 @@ public class PreviewPremiumTaxCommandTests
Assert.Equal(6.00m, tax); Assert.Equal(6.00m, tax);
Assert.Equal(66.00m, total); Assert.Equal(66.00m, total);
await _stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options => await _stripeAdapter.Received(1).CreateInvoicePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.Currency == "usd" && options.Currency == "usd" &&
options.CustomerDetails.Address.Country == "FR" && options.CustomerDetails.Address.Country == "FR" &&
@@ -295,7 +295,7 @@ public class PreviewPremiumTaxCommandTests
Total = 3123 // $31.23 Total = 3123 // $31.23
}; };
_stripeAdapter.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice); _stripeAdapter.CreateInvoicePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>()).Returns(invoice);
var result = await _command.Run(0, billingAddress); var result = await _command.Run(0, billingAddress);

View File

@@ -10,7 +10,6 @@ using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.Billing.Mocks; using Bit.Core.Test.Billing.Mocks;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
@@ -179,7 +178,7 @@ public class OrganizationBillingServiceTests
SubscriptionCreateOptions capturedOptions = null; SubscriptionCreateOptions capturedOptions = null;
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionCreateAsync(Arg.Do<SubscriptionCreateOptions>(options => capturedOptions = options)) .CreateSubscriptionAsync(Arg.Do<SubscriptionCreateOptions>(options => capturedOptions = options))
.Returns(new Subscription .Returns(new Subscription
{ {
Id = "sub_test123", Id = "sub_test123",
@@ -196,7 +195,7 @@ public class OrganizationBillingServiceTests
// Assert // Assert
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.Received(1) .Received(1)
.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); .CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
Assert.NotNull(capturedOptions); Assert.NotNull(capturedOptions);
Assert.Equal(7, capturedOptions.TrialPeriodDays); Assert.Equal(7, capturedOptions.TrialPeriodDays);
@@ -255,7 +254,7 @@ public class OrganizationBillingServiceTests
SubscriptionCreateOptions capturedOptions = null; SubscriptionCreateOptions capturedOptions = null;
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionCreateAsync(Arg.Do<SubscriptionCreateOptions>(options => capturedOptions = options)) .CreateSubscriptionAsync(Arg.Do<SubscriptionCreateOptions>(options => capturedOptions = options))
.Returns(new Subscription .Returns(new Subscription
{ {
Id = "sub_test123", Id = "sub_test123",
@@ -272,7 +271,7 @@ public class OrganizationBillingServiceTests
// Assert // Assert
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.Received(1) .Received(1)
.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); .CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
Assert.NotNull(capturedOptions); Assert.NotNull(capturedOptions);
Assert.Equal(0, capturedOptions.TrialPeriodDays); Assert.Equal(0, capturedOptions.TrialPeriodDays);
@@ -329,7 +328,7 @@ public class OrganizationBillingServiceTests
SubscriptionCreateOptions capturedOptions = null; SubscriptionCreateOptions capturedOptions = null;
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionCreateAsync(Arg.Do<SubscriptionCreateOptions>(options => capturedOptions = options)) .CreateSubscriptionAsync(Arg.Do<SubscriptionCreateOptions>(options => capturedOptions = options))
.Returns(new Subscription .Returns(new Subscription
{ {
Id = "sub_test123", Id = "sub_test123",
@@ -346,7 +345,7 @@ public class OrganizationBillingServiceTests
// Assert // Assert
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.Received(1) .Received(1)
.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); .CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
Assert.NotNull(capturedOptions); Assert.NotNull(capturedOptions);
Assert.Equal(7, capturedOptions.TrialPeriodDays); Assert.Equal(7, capturedOptions.TrialPeriodDays);
@@ -364,7 +363,7 @@ public class OrganizationBillingServiceTests
CustomerUpdateOptions capturedOptions = null; CustomerUpdateOptions capturedOptions = null;
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerUpdateAsync( .UpdateCustomerAsync(
Arg.Is<string>(id => id == organization.GatewayCustomerId), Arg.Is<string>(id => id == organization.GatewayCustomerId),
Arg.Do<CustomerUpdateOptions>(options => capturedOptions = options)) Arg.Do<CustomerUpdateOptions>(options => capturedOptions = options))
.Returns(new Customer()); .Returns(new Customer());
@@ -375,7 +374,7 @@ public class OrganizationBillingServiceTests
// Assert // Assert
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.Received(1) .Received(1)
.CustomerUpdateAsync( .UpdateCustomerAsync(
organization.GatewayCustomerId, organization.GatewayCustomerId,
Arg.Any<CustomerUpdateOptions>()); Arg.Any<CustomerUpdateOptions>());
@@ -401,7 +400,7 @@ public class OrganizationBillingServiceTests
CustomerUpdateOptions capturedOptions = null; CustomerUpdateOptions capturedOptions = null;
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerUpdateAsync( .UpdateCustomerAsync(
Arg.Is<string>(id => id == organization.GatewayCustomerId), Arg.Is<string>(id => id == organization.GatewayCustomerId),
Arg.Do<CustomerUpdateOptions>(options => capturedOptions = options)) Arg.Do<CustomerUpdateOptions>(options => capturedOptions = options))
.Returns(new Customer()); .Returns(new Customer());
@@ -412,7 +411,7 @@ public class OrganizationBillingServiceTests
// Assert // Assert
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.Received(1) .Received(1)
.CustomerUpdateAsync( .UpdateCustomerAsync(
organization.GatewayCustomerId, organization.GatewayCustomerId,
Arg.Any<CustomerUpdateOptions>()); Arg.Any<CustomerUpdateOptions>());
@@ -445,6 +444,6 @@ public class OrganizationBillingServiceTests
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()); .UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>());
} }
} }

View File

@@ -1,9 +1,9 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Services;
using Bit.Core.Billing.Services.Implementations; using Bit.Core.Billing.Services.Implementations;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Models.BitStripe; using Bit.Core.Models.BitStripe;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using NSubstitute; using NSubstitute;
using Stripe; using Stripe;
using Xunit; using Xunit;
@@ -19,7 +19,7 @@ public class PaymentHistoryServiceTests
var subscriber = new Organization { GatewayCustomerId = "cus_id", GatewaySubscriptionId = "sub_id" }; var subscriber = new Organization { GatewayCustomerId = "cus_id", GatewaySubscriptionId = "sub_id" };
var invoices = new List<Invoice> { new() { Id = "in_id" } }; var invoices = new List<Invoice> { new() { Id = "in_id" } };
var stripeAdapter = Substitute.For<IStripeAdapter>(); var stripeAdapter = Substitute.For<IStripeAdapter>();
stripeAdapter.InvoiceListAsync(Arg.Any<StripeInvoiceListOptions>()).Returns(invoices); stripeAdapter.ListInvoicesAsync(Arg.Any<StripeInvoiceListOptions>()).Returns(invoices);
var transactionRepository = Substitute.For<ITransactionRepository>(); var transactionRepository = Substitute.For<ITransactionRepository>();
var paymentHistoryService = new PaymentHistoryService(stripeAdapter, transactionRepository); var paymentHistoryService = new PaymentHistoryService(stripeAdapter, transactionRepository);
@@ -29,7 +29,7 @@ public class PaymentHistoryServiceTests
// Assert // Assert
Assert.NotEmpty(result); Assert.NotEmpty(result);
Assert.Single(result); Assert.Single(result);
await stripeAdapter.Received(1).InvoiceListAsync(Arg.Any<StripeInvoiceListOptions>()); await stripeAdapter.Received(1).ListInvoicesAsync(Arg.Any<StripeInvoiceListOptions>());
} }
[Fact] [Fact]

View File

@@ -1,7 +1,8 @@
using Bit.Core.Billing.Constants; using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Services;
using Bit.Core.Billing.Services.Implementations;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
@@ -49,7 +50,7 @@ public class StripePaymentServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync( .GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -100,7 +101,7 @@ public class StripePaymentServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync( .GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -159,7 +160,7 @@ public class StripePaymentServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync( .GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -198,7 +199,7 @@ public class StripePaymentServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync( .GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -256,7 +257,7 @@ public class StripePaymentServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync( .GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -295,7 +296,7 @@ public class StripePaymentServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync( .GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -332,7 +333,7 @@ public class StripePaymentServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync( .GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -367,7 +368,7 @@ public class StripePaymentServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter stripeAdapter
.SubscriptionGetAsync( .GetSubscriptionAsync(
Arg.Any<string>(), Arg.Any<string>(),
Arg.Any<SubscriptionGetOptions>()) Arg.Any<SubscriptionGetOptions>())
.Returns(subscription); .Returns(subscription);
@@ -376,7 +377,7 @@ public class StripePaymentServiceTests
await sutProvider.Sut.GetSubscriptionAsync(subscriber); await sutProvider.Sut.GetSubscriptionAsync(subscriber);
// Assert - Verify expand options are correct // Assert - Verify expand options are correct
await stripeAdapter.Received(1).SubscriptionGetAsync( await stripeAdapter.Received(1).GetSubscriptionAsync(
subscriber.GatewaySubscriptionId, subscriber.GatewaySubscriptionId,
Arg.Is<SubscriptionGetOptions>(o => Arg.Is<SubscriptionGetOptions>(o =>
o.Expand.Contains("customer.discount.coupon.applies_to") && o.Expand.Contains("customer.discount.coupon.applies_to") &&
@@ -405,6 +406,6 @@ public class StripePaymentServiceTests
// Verify no Stripe API calls were made // Verify no Stripe API calls were made
await sutProvider.GetDependency<IStripeAdapter>() await sutProvider.GetDependency<IStripeAdapter>()
.DidNotReceive() .DidNotReceive()
.SubscriptionGetAsync(Arg.Any<string>(), Arg.Any<SubscriptionGetOptions>()); .GetSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionGetOptions>());
} }
} }

View File

@@ -3,10 +3,10 @@ using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.Billing.Caches; using Bit.Core.Billing.Caches;
using Bit.Core.Billing.Constants; using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Billing.Services.Implementations; using Bit.Core.Billing.Services.Implementations;
using Bit.Core.Billing.Tax.Models; using Bit.Core.Billing.Tax.Models;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
@@ -44,7 +44,7 @@ public class SubscriberServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter stripeAdapter
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.Returns(subscription); .Returns(subscription);
await ThrowsBillingExceptionAsync(() => await ThrowsBillingExceptionAsync(() =>
@@ -52,11 +52,11 @@ public class SubscriberServiceTests
await stripeAdapter await stripeAdapter
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SubscriptionUpdateAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>()); .UpdateSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>());
await stripeAdapter await stripeAdapter
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SubscriptionCancelAsync(Arg.Any<string>(), Arg.Any<SubscriptionCancelOptions>()); .CancelSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionCancelOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -81,7 +81,7 @@ public class SubscriberServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter stripeAdapter
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.Returns(subscription); .Returns(subscription);
var offboardingSurveyResponse = new OffboardingSurveyResponse var offboardingSurveyResponse = new OffboardingSurveyResponse
@@ -95,12 +95,12 @@ public class SubscriberServiceTests
await stripeAdapter await stripeAdapter
.Received(1) .Received(1)
.SubscriptionUpdateAsync(subscriptionId, Arg.Is<SubscriptionUpdateOptions>( .UpdateSubscriptionAsync(subscriptionId, Arg.Is<SubscriptionUpdateOptions>(
options => options.Metadata["cancellingUserId"] == userId.ToString())); options => options.Metadata["cancellingUserId"] == userId.ToString()));
await stripeAdapter await stripeAdapter
.Received(1) .Received(1)
.SubscriptionCancelAsync(subscriptionId, Arg.Is<SubscriptionCancelOptions>(options => .CancelSubscriptionAsync(subscriptionId, Arg.Is<SubscriptionCancelOptions>(options =>
options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback && options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback &&
options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason)); options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason));
} }
@@ -127,7 +127,7 @@ public class SubscriberServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter stripeAdapter
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.Returns(subscription); .Returns(subscription);
var offboardingSurveyResponse = new OffboardingSurveyResponse var offboardingSurveyResponse = new OffboardingSurveyResponse
@@ -141,11 +141,11 @@ public class SubscriberServiceTests
await stripeAdapter await stripeAdapter
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SubscriptionUpdateAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>()); .UpdateSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>());
await stripeAdapter await stripeAdapter
.Received(1) .Received(1)
.SubscriptionCancelAsync(subscriptionId, Arg.Is<SubscriptionCancelOptions>(options => .CancelSubscriptionAsync(subscriptionId, Arg.Is<SubscriptionCancelOptions>(options =>
options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback && options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback &&
options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason)); options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason));
} }
@@ -170,7 +170,7 @@ public class SubscriberServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter stripeAdapter
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.Returns(subscription); .Returns(subscription);
var offboardingSurveyResponse = new OffboardingSurveyResponse var offboardingSurveyResponse = new OffboardingSurveyResponse
@@ -184,7 +184,7 @@ public class SubscriberServiceTests
await stripeAdapter await stripeAdapter
.Received(1) .Received(1)
.SubscriptionUpdateAsync(subscriptionId, Arg.Is<SubscriptionUpdateOptions>(options => .UpdateSubscriptionAsync(subscriptionId, Arg.Is<SubscriptionUpdateOptions>(options =>
options.CancelAtPeriodEnd == true && options.CancelAtPeriodEnd == true &&
options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback && options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback &&
options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason && options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason &&
@@ -192,7 +192,7 @@ public class SubscriberServiceTests
await stripeAdapter await stripeAdapter
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SubscriptionCancelAsync(Arg.Any<string>(), Arg.Any<SubscriptionCancelOptions>()); .CancelSubscriptionAsync(Arg.Any<string>(), Arg.Any<SubscriptionCancelOptions>());
} }
#endregion #endregion
@@ -223,7 +223,7 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId) .GetCustomerAsync(organization.GatewayCustomerId)
.ReturnsNull(); .ReturnsNull();
var customer = await sutProvider.Sut.GetCustomer(organization); var customer = await sutProvider.Sut.GetCustomer(organization);
@@ -237,7 +237,7 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId) .GetCustomerAsync(organization.GatewayCustomerId)
.ThrowsAsync<StripeException>(); .ThrowsAsync<StripeException>();
var customer = await sutProvider.Sut.GetCustomer(organization); var customer = await sutProvider.Sut.GetCustomer(organization);
@@ -253,7 +253,7 @@ public class SubscriberServiceTests
var customer = new Customer(); var customer = new Customer();
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId) .GetCustomerAsync(organization.GatewayCustomerId)
.Returns(customer); .Returns(customer);
var gotCustomer = await sutProvider.Sut.GetCustomer(organization); var gotCustomer = await sutProvider.Sut.GetCustomer(organization);
@@ -287,7 +287,7 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId) .GetCustomerAsync(organization.GatewayCustomerId)
.ReturnsNull(); .ReturnsNull();
await ThrowsBillingExceptionAsync(async () => await sutProvider.Sut.GetCustomerOrThrow(organization)); await ThrowsBillingExceptionAsync(async () => await sutProvider.Sut.GetCustomerOrThrow(organization));
@@ -301,7 +301,7 @@ public class SubscriberServiceTests
var stripeException = new StripeException(); var stripeException = new StripeException();
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId) .GetCustomerAsync(organization.GatewayCustomerId)
.ThrowsAsync(stripeException); .ThrowsAsync(stripeException);
await ThrowsBillingExceptionAsync( await ThrowsBillingExceptionAsync(
@@ -318,7 +318,7 @@ public class SubscriberServiceTests
var customer = new Customer(); var customer = new Customer();
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId) .GetCustomerAsync(organization.GatewayCustomerId)
.Returns(customer); .Returns(customer);
var gotCustomer = await sutProvider.Sut.GetCustomerOrThrow(organization); var gotCustomer = await sutProvider.Sut.GetCustomerOrThrow(organization);
@@ -351,7 +351,7 @@ public class SubscriberServiceTests
} }
}; };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>( Arg.Is<CustomerGetOptions>(
options => options.Expand.Contains("default_source") && options => options.Expand.Contains("default_source") &&
options.Expand.Contains("invoice_settings.default_payment_method"))) options.Expand.Contains("invoice_settings.default_payment_method")))
@@ -388,7 +388,7 @@ public class SubscriberServiceTests
} }
}; };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>( Arg.Is<CustomerGetOptions>(
options => options.Expand.Contains("default_source") && options => options.Expand.Contains("default_source") &&
options.Expand.Contains("invoice_settings.default_payment_method"))) options.Expand.Contains("invoice_settings.default_payment_method")))
@@ -442,7 +442,7 @@ public class SubscriberServiceTests
} }
}; };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>( Arg.Is<CustomerGetOptions>(
options => options.Expand.Contains("default_source") && options => options.Expand.Contains("default_source") &&
options.Expand.Contains("invoice_settings.default_payment_method"))) options.Expand.Contains("invoice_settings.default_payment_method")))
@@ -478,7 +478,7 @@ public class SubscriberServiceTests
} }
}; };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>( Arg.Is<CustomerGetOptions>(
options => options.Expand.Contains("default_source") && options => options.Expand.Contains("default_source") &&
options.Expand.Contains("invoice_settings.default_payment_method"))) options.Expand.Contains("invoice_settings.default_payment_method")))
@@ -498,7 +498,7 @@ public class SubscriberServiceTests
{ {
var customer = new Customer { Id = provider.GatewayCustomerId }; var customer = new Customer { Id = provider.GatewayCustomerId };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(options => options.Expand.Contains("default_source") && Arg.Is<CustomerGetOptions>(options => options.Expand.Contains("default_source") &&
options.Expand.Contains( options.Expand.Contains(
"invoice_settings.default_payment_method"))) "invoice_settings.default_payment_method")))
@@ -521,7 +521,7 @@ public class SubscriberServiceTests
sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(provider.Id).Returns(setupIntent.Id); sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(provider.Id).Returns(setupIntent.Id);
sutProvider.GetDependency<IStripeAdapter>().SetupIntentGet(setupIntent.Id, sutProvider.GetDependency<IStripeAdapter>().GetSetupIntentAsync(setupIntent.Id,
Arg.Is<SetupIntentGetOptions>(options => options.Expand.Contains("payment_method"))).Returns(setupIntent); Arg.Is<SetupIntentGetOptions>(options => options.Expand.Contains("payment_method"))).Returns(setupIntent);
var paymentMethod = await sutProvider.Sut.GetPaymentSource(provider); var paymentMethod = await sutProvider.Sut.GetPaymentSource(provider);
@@ -541,7 +541,7 @@ public class SubscriberServiceTests
DefaultSource = new BankAccount { Status = "verified", BankName = "Chase", Last4 = "9999" } DefaultSource = new BankAccount { Status = "verified", BankName = "Chase", Last4 = "9999" }
}; };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(options => options.Expand.Contains("default_source") && Arg.Is<CustomerGetOptions>(options => options.Expand.Contains("default_source") &&
options.Expand.Contains( options.Expand.Contains(
"invoice_settings.default_payment_method"))) "invoice_settings.default_payment_method")))
@@ -564,7 +564,7 @@ public class SubscriberServiceTests
DefaultSource = new Card { Brand = "Visa", Last4 = "9999", ExpMonth = 9, ExpYear = 2028 } DefaultSource = new Card { Brand = "Visa", Last4 = "9999", ExpMonth = 9, ExpYear = 2028 }
}; };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(options => options.Expand.Contains("default_source") && Arg.Is<CustomerGetOptions>(options => options.Expand.Contains("default_source") &&
options.Expand.Contains( options.Expand.Contains(
"invoice_settings.default_payment_method"))) "invoice_settings.default_payment_method")))
@@ -596,7 +596,7 @@ public class SubscriberServiceTests
} }
}; };
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId, sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>( Arg.Is<CustomerGetOptions>(
options => options.Expand.Contains("default_source") && options => options.Expand.Contains("default_source") &&
options.Expand.Contains("invoice_settings.default_payment_method"))) options.Expand.Contains("invoice_settings.default_payment_method")))
@@ -636,7 +636,7 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.ReturnsNull(); .ReturnsNull();
var subscription = await sutProvider.Sut.GetSubscription(organization); var subscription = await sutProvider.Sut.GetSubscription(organization);
@@ -650,7 +650,7 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.ThrowsAsync<StripeException>(); .ThrowsAsync<StripeException>();
var subscription = await sutProvider.Sut.GetSubscription(organization); var subscription = await sutProvider.Sut.GetSubscription(organization);
@@ -666,7 +666,7 @@ public class SubscriberServiceTests
var subscription = new Subscription(); var subscription = new Subscription();
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.Returns(subscription); .Returns(subscription);
var gotSubscription = await sutProvider.Sut.GetSubscription(organization); var gotSubscription = await sutProvider.Sut.GetSubscription(organization);
@@ -698,7 +698,7 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.ReturnsNull(); .ReturnsNull();
await ThrowsBillingExceptionAsync(async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization)); await ThrowsBillingExceptionAsync(async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization));
@@ -712,7 +712,7 @@ public class SubscriberServiceTests
var stripeException = new StripeException(); var stripeException = new StripeException();
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.ThrowsAsync(stripeException); .ThrowsAsync(stripeException);
await ThrowsBillingExceptionAsync( await ThrowsBillingExceptionAsync(
@@ -729,7 +729,7 @@ public class SubscriberServiceTests
var subscription = new Subscription(); var subscription = new Subscription();
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId) .GetSubscriptionAsync(organization.GatewaySubscriptionId)
.Returns(subscription); .Returns(subscription);
var gotSubscription = await sutProvider.Sut.GetSubscriptionOrThrow(organization); var gotSubscription = await sutProvider.Sut.GetSubscriptionOrThrow(organization);
@@ -760,7 +760,7 @@ public class SubscriberServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>()) .GetCustomerAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>())
.Returns(stripeCustomer); .Returns(stripeCustomer);
var (braintreeGateway, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>()); var (braintreeGateway, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>());
@@ -795,7 +795,7 @@ public class SubscriberServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>()) .GetCustomerAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>())
.Returns(stripeCustomer); .Returns(stripeCustomer);
var (_, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>()); var (_, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>());
@@ -832,7 +832,7 @@ public class SubscriberServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>()) .GetCustomerAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>())
.Returns(stripeCustomer); .Returns(stripeCustomer);
var (_, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>()); var (_, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>());
@@ -887,7 +887,7 @@ public class SubscriberServiceTests
}; };
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>()) .GetCustomerAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>())
.Returns(stripeCustomer); .Returns(stripeCustomer);
var (_, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>()); var (_, customerGateway, paymentMethodGateway) = SetupBraintree(sutProvider.GetDependency<IBraintreeGateway>());
@@ -946,21 +946,21 @@ public class SubscriberServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter stripeAdapter
.CustomerGetAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>()) .GetCustomerAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>())
.Returns(stripeCustomer); .Returns(stripeCustomer);
stripeAdapter stripeAdapter
.PaymentMethodListAutoPagingAsync(Arg.Any<PaymentMethodListOptions>()) .ListPaymentMethodsAutoPagingAsync(Arg.Any<PaymentMethodListOptions>())
.Returns(GetPaymentMethodsAsync(new List<PaymentMethod>())); .Returns(GetPaymentMethodsAsync(new List<PaymentMethod>()));
await sutProvider.Sut.RemovePaymentSource(organization); await sutProvider.Sut.RemovePaymentSource(organization);
await stripeAdapter.Received(1).BankAccountDeleteAsync(stripeCustomer.Id, bankAccountId); await stripeAdapter.Received(1).DeleteBankAccountAsync(stripeCustomer.Id, bankAccountId);
await stripeAdapter.Received(1).CardDeleteAsync(stripeCustomer.Id, cardId); await stripeAdapter.Received(1).DeleteCardAsync(stripeCustomer.Id, cardId);
await stripeAdapter.DidNotReceiveWithAnyArgs() await stripeAdapter.DidNotReceiveWithAnyArgs()
.PaymentMethodDetachAsync(Arg.Any<string>(), Arg.Any<PaymentMethodDetachOptions>()); .DetachPaymentMethodAsync(Arg.Any<string>(), Arg.Any<PaymentMethodDetachOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -978,11 +978,11 @@ public class SubscriberServiceTests
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter stripeAdapter
.CustomerGetAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>()) .GetCustomerAsync(organization.GatewayCustomerId, Arg.Any<CustomerGetOptions>())
.Returns(stripeCustomer); .Returns(stripeCustomer);
stripeAdapter stripeAdapter
.PaymentMethodListAutoPagingAsync(Arg.Any<PaymentMethodListOptions>()) .ListPaymentMethodsAutoPagingAsync(Arg.Any<PaymentMethodListOptions>())
.Returns(GetPaymentMethodsAsync(new List<PaymentMethod> .Returns(GetPaymentMethodsAsync(new List<PaymentMethod>
{ {
new () new ()
@@ -997,15 +997,15 @@ public class SubscriberServiceTests
await sutProvider.Sut.RemovePaymentSource(organization); await sutProvider.Sut.RemovePaymentSource(organization);
await stripeAdapter.DidNotReceiveWithAnyArgs().BankAccountDeleteAsync(Arg.Any<string>(), Arg.Any<string>()); await stripeAdapter.DidNotReceiveWithAnyArgs().DeleteBankAccountAsync(Arg.Any<string>(), Arg.Any<string>());
await stripeAdapter.DidNotReceiveWithAnyArgs().CardDeleteAsync(Arg.Any<string>(), Arg.Any<string>()); await stripeAdapter.DidNotReceiveWithAnyArgs().DeleteCardAsync(Arg.Any<string>(), Arg.Any<string>());
await stripeAdapter.Received(1) await stripeAdapter.Received(1)
.PaymentMethodDetachAsync(bankAccountId); .DetachPaymentMethodAsync(bankAccountId);
await stripeAdapter.Received(1) await stripeAdapter.Received(1)
.PaymentMethodDetachAsync(cardId); .DetachPaymentMethodAsync(cardId);
} }
private static async IAsyncEnumerable<PaymentMethod> GetPaymentMethodsAsync( private static async IAsyncEnumerable<PaymentMethod> GetPaymentMethodsAsync(
@@ -1050,7 +1050,7 @@ public class SubscriberServiceTests
Provider provider, Provider provider,
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId) sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId)
.Returns(new Customer()); .Returns(new Customer());
await ThrowsBillingExceptionAsync(() => await ThrowsBillingExceptionAsync(() =>
@@ -1062,7 +1062,7 @@ public class SubscriberServiceTests
Provider provider, Provider provider,
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId) sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId)
.Returns(new Customer()); .Returns(new Customer());
await ThrowsBillingExceptionAsync(() => await ThrowsBillingExceptionAsync(() =>
@@ -1076,10 +1076,10 @@ public class SubscriberServiceTests
{ {
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerGetAsync(provider.GatewayCustomerId) stripeAdapter.GetCustomerAsync(provider.GatewayCustomerId)
.Returns(new Customer()); .Returns(new Customer());
stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => options.PaymentMethod == "TOKEN")) stripeAdapter.ListSetupIntentsAsync(Arg.Is<SetupIntentListOptions>(options => options.PaymentMethod == "TOKEN"))
.Returns([new SetupIntent(), new SetupIntent()]); .Returns([new SetupIntent(), new SetupIntent()]);
await ThrowsBillingExceptionAsync(() => await ThrowsBillingExceptionAsync(() =>
@@ -1093,7 +1093,7 @@ public class SubscriberServiceTests
{ {
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerGetAsync( stripeAdapter.GetCustomerAsync(
provider.GatewayCustomerId, provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids"))) Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids")))
.Returns(new Customer .Returns(new Customer
@@ -1107,10 +1107,10 @@ public class SubscriberServiceTests
var matchingSetupIntent = new SetupIntent { Id = "setup_intent_1" }; var matchingSetupIntent = new SetupIntent { Id = "setup_intent_1" };
stripeAdapter.SetupIntentList(Arg.Is<SetupIntentListOptions>(options => options.PaymentMethod == "TOKEN")) stripeAdapter.ListSetupIntentsAsync(Arg.Is<SetupIntentListOptions>(options => options.PaymentMethod == "TOKEN"))
.Returns([matchingSetupIntent]); .Returns([matchingSetupIntent]);
stripeAdapter.CustomerListPaymentMethods(provider.GatewayCustomerId).Returns([ stripeAdapter.ListCustomerPaymentMethodsAsync(provider.GatewayCustomerId).Returns([
new PaymentMethod { Id = "payment_method_1" } new PaymentMethod { Id = "payment_method_1" }
]); ]);
@@ -1119,12 +1119,12 @@ public class SubscriberServiceTests
await sutProvider.GetDependency<ISetupIntentCache>().Received(1).Set(provider.Id, "setup_intent_1"); await sutProvider.GetDependency<ISetupIntentCache>().Received(1).Set(provider.Id, "setup_intent_1");
await stripeAdapter.DidNotReceive().SetupIntentCancel(Arg.Any<string>(), await stripeAdapter.DidNotReceive().CancelSetupIntentAsync(Arg.Any<string>(),
Arg.Any<SetupIntentCancelOptions>()); Arg.Any<SetupIntentCancelOptions>());
await stripeAdapter.Received(1).PaymentMethodDetachAsync("payment_method_1"); await stripeAdapter.Received(1).DetachPaymentMethodAsync("payment_method_1");
await stripeAdapter.Received(1).CustomerUpdateAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>( await stripeAdapter.Received(1).UpdateCustomerAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(
options => options.Metadata[Core.Billing.Utilities.BraintreeCustomerIdKey] == null)); options => options.Metadata[Core.Billing.Utilities.BraintreeCustomerIdKey] == null));
} }
@@ -1135,7 +1135,7 @@ public class SubscriberServiceTests
{ {
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerGetAsync( stripeAdapter.GetCustomerAsync(
provider.GatewayCustomerId, provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids")) Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids"))
) )
@@ -1148,22 +1148,22 @@ public class SubscriberServiceTests
} }
}); });
stripeAdapter.CustomerListPaymentMethods(provider.GatewayCustomerId).Returns([ stripeAdapter.ListCustomerPaymentMethodsAsync(provider.GatewayCustomerId).Returns([
new PaymentMethod { Id = "payment_method_1" } new PaymentMethod { Id = "payment_method_1" }
]); ]);
await sutProvider.Sut.UpdatePaymentSource(provider, await sutProvider.Sut.UpdatePaymentSource(provider,
new TokenizedPaymentSource(PaymentMethodType.Card, "TOKEN")); new TokenizedPaymentSource(PaymentMethodType.Card, "TOKEN"));
await stripeAdapter.DidNotReceive().SetupIntentCancel(Arg.Any<string>(), await stripeAdapter.DidNotReceive().CancelSetupIntentAsync(Arg.Any<string>(),
Arg.Any<SetupIntentCancelOptions>()); Arg.Any<SetupIntentCancelOptions>());
await stripeAdapter.Received(1).PaymentMethodDetachAsync("payment_method_1"); await stripeAdapter.Received(1).DetachPaymentMethodAsync("payment_method_1");
await stripeAdapter.Received(1).PaymentMethodAttachAsync("TOKEN", Arg.Is<PaymentMethodAttachOptions>( await stripeAdapter.Received(1).AttachPaymentMethodAsync("TOKEN", Arg.Is<PaymentMethodAttachOptions>(
options => options.Customer == provider.GatewayCustomerId)); options => options.Customer == provider.GatewayCustomerId));
await stripeAdapter.Received(1).CustomerUpdateAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>( await stripeAdapter.Received(1).UpdateCustomerAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(
options => options =>
options.InvoiceSettings.DefaultPaymentMethod == "TOKEN" && options.InvoiceSettings.DefaultPaymentMethod == "TOKEN" &&
options.Metadata[Core.Billing.Utilities.BraintreeCustomerIdKey] == null)); options.Metadata[Core.Billing.Utilities.BraintreeCustomerIdKey] == null));
@@ -1176,7 +1176,7 @@ public class SubscriberServiceTests
{ {
const string braintreeCustomerId = "braintree_customer_id"; const string braintreeCustomerId = "braintree_customer_id";
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId) sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId)
.Returns(new Customer .Returns(new Customer
{ {
Id = provider.GatewayCustomerId, Id = provider.GatewayCustomerId,
@@ -1202,7 +1202,7 @@ public class SubscriberServiceTests
{ {
const string braintreeCustomerId = "braintree_customer_id"; const string braintreeCustomerId = "braintree_customer_id";
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId) sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId)
.Returns(new Customer .Returns(new Customer
{ {
Id = provider.GatewayCustomerId, Id = provider.GatewayCustomerId,
@@ -1240,7 +1240,7 @@ public class SubscriberServiceTests
{ {
const string braintreeCustomerId = "braintree_customer_id"; const string braintreeCustomerId = "braintree_customer_id";
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync( sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(
provider.GatewayCustomerId, provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids"))) Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids")))
.Returns(new Customer .Returns(new Customer
@@ -1294,7 +1294,7 @@ public class SubscriberServiceTests
{ {
const string braintreeCustomerId = "braintree_customer_id"; const string braintreeCustomerId = "braintree_customer_id";
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync( sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(
provider.GatewayCustomerId, provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids"))) Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids")))
.Returns(new Customer .Returns(new Customer
@@ -1363,7 +1363,7 @@ public class SubscriberServiceTests
{ {
const string braintreeCustomerId = "braintree_customer_id"; const string braintreeCustomerId = "braintree_customer_id";
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(provider.GatewayCustomerId) sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(provider.GatewayCustomerId)
.Returns(new Customer .Returns(new Customer
{ {
Id = provider.GatewayCustomerId Id = provider.GatewayCustomerId
@@ -1395,7 +1395,7 @@ public class SubscriberServiceTests
new TokenizedPaymentSource(PaymentMethodType.PayPal, "TOKEN"))); new TokenizedPaymentSource(PaymentMethodType.PayPal, "TOKEN")));
await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs()
.CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>()); .UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1405,7 +1405,7 @@ public class SubscriberServiceTests
{ {
const string braintreeCustomerId = "braintree_customer_id"; const string braintreeCustomerId = "braintree_customer_id";
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync( sutProvider.GetDependency<IStripeAdapter>().GetCustomerAsync(
provider.GatewayCustomerId, provider.GatewayCustomerId,
Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids"))) Arg.Is<CustomerGetOptions>(p => p.Expand.Contains("tax") || p.Expand.Contains("tax_ids")))
.Returns(new Customer .Returns(new Customer
@@ -1442,7 +1442,7 @@ public class SubscriberServiceTests
await sutProvider.Sut.UpdatePaymentSource(provider, await sutProvider.Sut.UpdatePaymentSource(provider,
new TokenizedPaymentSource(PaymentMethodType.PayPal, "TOKEN")); new TokenizedPaymentSource(PaymentMethodType.PayPal, "TOKEN"));
await sutProvider.GetDependency<IStripeAdapter>().Received(1).CustomerUpdateAsync(provider.GatewayCustomerId, await sutProvider.GetDependency<IStripeAdapter>().Received(1).UpdateCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerUpdateOptions>( Arg.Is<CustomerUpdateOptions>(
options => options.Metadata[Core.Billing.Utilities.BraintreeCustomerIdKey] == braintreeCustomerId)); options => options.Metadata[Core.Billing.Utilities.BraintreeCustomerIdKey] == braintreeCustomerId));
} }
@@ -1473,7 +1473,7 @@ public class SubscriberServiceTests
var customer = new Customer { Id = provider.GatewayCustomerId, TaxIds = new StripeList<TaxId> { Data = [new TaxId { Id = "tax_id_1", Type = "us_ein" }] } }; var customer = new Customer { Id = provider.GatewayCustomerId, TaxIds = new StripeList<TaxId> { Data = [new TaxId { Id = "tax_id_1", Type = "us_ein" }] } };
stripeAdapter.CustomerGetAsync(provider.GatewayCustomerId, Arg.Is<CustomerGetOptions>( stripeAdapter.GetCustomerAsync(provider.GatewayCustomerId, Arg.Is<CustomerGetOptions>(
options => options.Expand.Contains("tax_ids"))).Returns(customer); options => options.Expand.Contains("tax_ids"))).Returns(customer);
var taxInformation = new TaxInformation( var taxInformation = new TaxInformation(
@@ -1487,7 +1487,7 @@ public class SubscriberServiceTests
"NY"); "NY");
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerUpdateAsync( .UpdateCustomerAsync(
Arg.Is<string>(p => p == provider.GatewayCustomerId), Arg.Is<string>(p => p == provider.GatewayCustomerId),
Arg.Is<CustomerUpdateOptions>(options => Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Country == "US" && options.Address.Country == "US" &&
@@ -1522,12 +1522,12 @@ public class SubscriberServiceTests
}); });
var subscription = new Subscription { Items = new StripeList<SubscriptionItem>() }; var subscription = new Subscription { Items = new StripeList<SubscriptionItem>() };
sutProvider.GetDependency<IStripeAdapter>().SubscriptionGetAsync(Arg.Any<string>()) sutProvider.GetDependency<IStripeAdapter>().GetSubscriptionAsync(Arg.Any<string>())
.Returns(subscription); .Returns(subscription);
await sutProvider.Sut.UpdateTaxInformation(provider, taxInformation); await sutProvider.Sut.UpdateTaxInformation(provider, taxInformation);
await stripeAdapter.Received(1).CustomerUpdateAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>( await stripeAdapter.Received(1).UpdateCustomerAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(
options => options =>
options.Address.Country == taxInformation.Country && options.Address.Country == taxInformation.Country &&
options.Address.PostalCode == taxInformation.PostalCode && options.Address.PostalCode == taxInformation.PostalCode &&
@@ -1536,13 +1536,13 @@ public class SubscriberServiceTests
options.Address.City == taxInformation.City && options.Address.City == taxInformation.City &&
options.Address.State == taxInformation.State)); options.Address.State == taxInformation.State));
await stripeAdapter.Received(1).TaxIdDeleteAsync(provider.GatewayCustomerId, "tax_id_1"); await stripeAdapter.Received(1).DeleteTaxIdAsync(provider.GatewayCustomerId, "tax_id_1");
await stripeAdapter.Received(1).TaxIdCreateAsync(provider.GatewayCustomerId, Arg.Is<TaxIdCreateOptions>( await stripeAdapter.Received(1).CreateTaxIdAsync(provider.GatewayCustomerId, Arg.Is<TaxIdCreateOptions>(
options => options.Type == "us_ein" && options => options.Type == "us_ein" &&
options.Value == taxInformation.TaxId)); options.Value == taxInformation.TaxId));
await stripeAdapter.Received(1).SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.Received(1).UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
} }
@@ -1555,7 +1555,7 @@ public class SubscriberServiceTests
var customer = new Customer { Id = provider.GatewayCustomerId, TaxIds = new StripeList<TaxId> { Data = [new TaxId { Id = "tax_id_1", Type = "us_ein" }] } }; var customer = new Customer { Id = provider.GatewayCustomerId, TaxIds = new StripeList<TaxId> { Data = [new TaxId { Id = "tax_id_1", Type = "us_ein" }] } };
stripeAdapter.CustomerGetAsync(provider.GatewayCustomerId, Arg.Is<CustomerGetOptions>( stripeAdapter.GetCustomerAsync(provider.GatewayCustomerId, Arg.Is<CustomerGetOptions>(
options => options.Expand.Contains("tax_ids"))).Returns(customer); options => options.Expand.Contains("tax_ids"))).Returns(customer);
var taxInformation = new TaxInformation( var taxInformation = new TaxInformation(
@@ -1569,7 +1569,7 @@ public class SubscriberServiceTests
"NY"); "NY");
sutProvider.GetDependency<IStripeAdapter>() sutProvider.GetDependency<IStripeAdapter>()
.CustomerUpdateAsync( .UpdateCustomerAsync(
Arg.Is<string>(p => p == provider.GatewayCustomerId), Arg.Is<string>(p => p == provider.GatewayCustomerId),
Arg.Is<CustomerUpdateOptions>(options => Arg.Is<CustomerUpdateOptions>(options =>
options.Address.Country == "CA" && options.Address.Country == "CA" &&
@@ -1605,12 +1605,12 @@ public class SubscriberServiceTests
}); });
var subscription = new Subscription { Items = new StripeList<SubscriptionItem>() }; var subscription = new Subscription { Items = new StripeList<SubscriptionItem>() };
sutProvider.GetDependency<IStripeAdapter>().SubscriptionGetAsync(Arg.Any<string>()) sutProvider.GetDependency<IStripeAdapter>().GetSubscriptionAsync(Arg.Any<string>())
.Returns(subscription); .Returns(subscription);
await sutProvider.Sut.UpdateTaxInformation(provider, taxInformation); await sutProvider.Sut.UpdateTaxInformation(provider, taxInformation);
await stripeAdapter.Received(1).CustomerUpdateAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>( await stripeAdapter.Received(1).UpdateCustomerAsync(provider.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(
options => options =>
options.Address.Country == taxInformation.Country && options.Address.Country == taxInformation.Country &&
options.Address.PostalCode == taxInformation.PostalCode && options.Address.PostalCode == taxInformation.PostalCode &&
@@ -1619,16 +1619,16 @@ public class SubscriberServiceTests
options.Address.City == taxInformation.City && options.Address.City == taxInformation.City &&
options.Address.State == taxInformation.State)); options.Address.State == taxInformation.State));
await stripeAdapter.Received(1).TaxIdDeleteAsync(provider.GatewayCustomerId, "tax_id_1"); await stripeAdapter.Received(1).DeleteTaxIdAsync(provider.GatewayCustomerId, "tax_id_1");
await stripeAdapter.Received(1).TaxIdCreateAsync(provider.GatewayCustomerId, Arg.Is<TaxIdCreateOptions>( await stripeAdapter.Received(1).CreateTaxIdAsync(provider.GatewayCustomerId, Arg.Is<TaxIdCreateOptions>(
options => options.Type == "us_ein" && options => options.Type == "us_ein" &&
options.Value == taxInformation.TaxId)); options.Value == taxInformation.TaxId));
await stripeAdapter.Received(1).CustomerUpdateAsync(provider.GatewayCustomerId, await stripeAdapter.Received(1).UpdateCustomerAsync(provider.GatewayCustomerId,
Arg.Is<CustomerUpdateOptions>(options => options.TaxExempt == StripeConstants.TaxExempt.Reverse)); Arg.Is<CustomerUpdateOptions>(options => options.TaxExempt == StripeConstants.TaxExempt.Reverse));
await stripeAdapter.Received(1).SubscriptionUpdateAsync(provider.GatewaySubscriptionId, await stripeAdapter.Received(1).UpdateSubscriptionAsync(provider.GatewaySubscriptionId,
Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true)); Arg.Is<SubscriptionUpdateOptions>(options => options.AutomaticTax.Enabled == true));
} }
@@ -1655,7 +1655,7 @@ public class SubscriberServiceTests
Assert.True(result); Assert.True(result);
await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs()
.CustomerGetAsync(Arg.Any<string>()); .GetCustomerAsync(Arg.Any<string>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1669,7 +1669,7 @@ public class SubscriberServiceTests
Assert.True(result); Assert.True(result);
await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs()
.CustomerGetAsync(Arg.Any<string>()); .GetCustomerAsync(Arg.Any<string>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1678,12 +1678,12 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerGetAsync(organization.GatewayCustomerId).Returns(new Customer()); stripeAdapter.GetCustomerAsync(organization.GatewayCustomerId).Returns(new Customer());
var result = await sutProvider.Sut.IsValidGatewayCustomerIdAsync(organization); var result = await sutProvider.Sut.IsValidGatewayCustomerIdAsync(organization);
Assert.True(result); Assert.True(result);
await stripeAdapter.Received(1).CustomerGetAsync(organization.GatewayCustomerId); await stripeAdapter.Received(1).GetCustomerAsync(organization.GatewayCustomerId);
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1693,12 +1693,12 @@ public class SubscriberServiceTests
{ {
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
var stripeException = new StripeException { StripeError = new StripeError { Code = "resource_missing" } }; var stripeException = new StripeException { StripeError = new StripeError { Code = "resource_missing" } };
stripeAdapter.CustomerGetAsync(organization.GatewayCustomerId).Throws(stripeException); stripeAdapter.GetCustomerAsync(organization.GatewayCustomerId).Throws(stripeException);
var result = await sutProvider.Sut.IsValidGatewayCustomerIdAsync(organization); var result = await sutProvider.Sut.IsValidGatewayCustomerIdAsync(organization);
Assert.False(result); Assert.False(result);
await stripeAdapter.Received(1).CustomerGetAsync(organization.GatewayCustomerId); await stripeAdapter.Received(1).GetCustomerAsync(organization.GatewayCustomerId);
} }
#endregion #endregion
@@ -1724,7 +1724,7 @@ public class SubscriberServiceTests
Assert.True(result); Assert.True(result);
await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs()
.SubscriptionGetAsync(Arg.Any<string>()); .GetSubscriptionAsync(Arg.Any<string>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1738,7 +1738,7 @@ public class SubscriberServiceTests
Assert.True(result); Assert.True(result);
await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IStripeAdapter>().DidNotReceiveWithAnyArgs()
.SubscriptionGetAsync(Arg.Any<string>()); .GetSubscriptionAsync(Arg.Any<string>());
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1747,12 +1747,12 @@ public class SubscriberServiceTests
SutProvider<SubscriberService> sutProvider) SutProvider<SubscriberService> sutProvider)
{ {
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.SubscriptionGetAsync(organization.GatewaySubscriptionId).Returns(new Subscription()); stripeAdapter.GetSubscriptionAsync(organization.GatewaySubscriptionId).Returns(new Subscription());
var result = await sutProvider.Sut.IsValidGatewaySubscriptionIdAsync(organization); var result = await sutProvider.Sut.IsValidGatewaySubscriptionIdAsync(organization);
Assert.True(result); Assert.True(result);
await stripeAdapter.Received(1).SubscriptionGetAsync(organization.GatewaySubscriptionId); await stripeAdapter.Received(1).GetSubscriptionAsync(organization.GatewaySubscriptionId);
} }
[Theory, BitAutoData] [Theory, BitAutoData]
@@ -1762,12 +1762,12 @@ public class SubscriberServiceTests
{ {
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>(); var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
var stripeException = new StripeException { StripeError = new StripeError { Code = "resource_missing" } }; var stripeException = new StripeException { StripeError = new StripeError { Code = "resource_missing" } };
stripeAdapter.SubscriptionGetAsync(organization.GatewaySubscriptionId).Throws(stripeException); stripeAdapter.GetSubscriptionAsync(organization.GatewaySubscriptionId).Throws(stripeException);
var result = await sutProvider.Sut.IsValidGatewaySubscriptionIdAsync(organization); var result = await sutProvider.Sut.IsValidGatewaySubscriptionIdAsync(organization);
Assert.False(result); Assert.False(result);
await stripeAdapter.Received(1).SubscriptionGetAsync(organization.GatewaySubscriptionId); await stripeAdapter.Received(1).GetSubscriptionAsync(organization.GatewaySubscriptionId);
} }
#endregion #endregion

View File

@@ -6,7 +6,6 @@ using Bit.Core.Billing.Services;
using Bit.Core.Billing.Subscriptions.Commands; using Bit.Core.Billing.Subscriptions.Commands;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using NSubstitute; using NSubstitute;
using Stripe; using Stripe;
using Xunit; using Xunit;
@@ -98,13 +97,13 @@ public class RestartSubscriptionCommandTests
}; };
_subscriberService.GetSubscription(organization).Returns(existingSubscription); _subscriberService.GetSubscription(organization).Returns(existingSubscription);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(newSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(newSubscription);
var result = await _command.Run(organization); var result = await _command.Run(organization);
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Is((SubscriptionCreateOptions options) => await _stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Is((SubscriptionCreateOptions options) =>
options.AutomaticTax.Enabled == true && options.AutomaticTax.Enabled == true &&
options.CollectionMethod == CollectionMethod.ChargeAutomatically && options.CollectionMethod == CollectionMethod.ChargeAutomatically &&
options.Customer == "cus_123" && options.Customer == "cus_123" &&
@@ -154,13 +153,13 @@ public class RestartSubscriptionCommandTests
}; };
_subscriberService.GetSubscription(provider).Returns(existingSubscription); _subscriberService.GetSubscription(provider).Returns(existingSubscription);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(newSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(newSubscription);
var result = await _command.Run(provider); var result = await _command.Run(provider);
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); await _stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
await _providerRepository.Received(1).ReplaceAsync(Arg.Is<Provider>(prov => await _providerRepository.Received(1).ReplaceAsync(Arg.Is<Provider>(prov =>
prov.Id == providerId && prov.Id == providerId &&
@@ -199,13 +198,13 @@ public class RestartSubscriptionCommandTests
}; };
_subscriberService.GetSubscription(user).Returns(existingSubscription); _subscriberService.GetSubscription(user).Returns(existingSubscription);
_stripeAdapter.SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(newSubscription); _stripeAdapter.CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>()).Returns(newSubscription);
var result = await _command.Run(user); var result = await _command.Run(user);
Assert.True(result.IsT0); Assert.True(result.IsT0);
await _stripeAdapter.Received(1).SubscriptionCreateAsync(Arg.Any<SubscriptionCreateOptions>()); await _stripeAdapter.Received(1).CreateSubscriptionAsync(Arg.Any<SubscriptionCreateOptions>());
await _userRepository.Received(1).ReplaceAsync(Arg.Is<User>(u => await _userRepository.Received(1).ReplaceAsync(Arg.Is<User>(u =>
u.Id == userId && u.Id == userId &&

View File

@@ -1,4 +1,5 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
@@ -12,7 +13,7 @@ public abstract class CancelSponsorshipCommandTestsBase : FamiliesForEnterpriseT
protected async Task AssertRemovedSponsoredPaymentAsync<T>(Organization sponsoredOrg, protected async Task AssertRemovedSponsoredPaymentAsync<T>(Organization sponsoredOrg,
OrganizationSponsorship sponsorship, SutProvider<T> sutProvider) OrganizationSponsorship sponsorship, SutProvider<T> sutProvider)
{ {
await sutProvider.GetDependency<IPaymentService>().Received(1) await sutProvider.GetDependency<IStripePaymentService>().Received(1)
.RemoveOrganizationSponsorshipAsync(sponsoredOrg, sponsorship); .RemoveOrganizationSponsorshipAsync(sponsoredOrg, sponsorship);
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).UpsertAsync(sponsoredOrg); await sutProvider.GetDependency<IOrganizationRepository>().Received(1).UpsertAsync(sponsoredOrg);
if (sponsorship != null) if (sponsorship != null)
@@ -46,7 +47,7 @@ OrganizationSponsorship sponsorship, SutProvider<T> sutProvider)
protected static async Task AssertDidNotRemoveSponsoredPaymentAsync<T>(SutProvider<T> sutProvider) protected static async Task AssertDidNotRemoveSponsoredPaymentAsync<T>(SutProvider<T> sutProvider)
{ {
await sutProvider.GetDependency<IPaymentService>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IStripePaymentService>().DidNotReceiveWithAnyArgs()
.RemoveOrganizationSponsorshipAsync(default, default); .RemoveOrganizationSponsorshipAsync(default, default);
await sutProvider.GetDependency<IOrganizationRepository>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IOrganizationRepository>().DidNotReceiveWithAnyArgs()
.UpsertAsync(default); .UpsertAsync(default);

View File

@@ -1,10 +1,10 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Services;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures; using Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
@@ -82,7 +82,7 @@ public class SetUpSponsorshipCommandTests : FamiliesForEnterpriseTestsBase
private static async Task AssertDidNotSetUpAsync(SutProvider<SetUpSponsorshipCommand> sutProvider) private static async Task AssertDidNotSetUpAsync(SutProvider<SetUpSponsorshipCommand> sutProvider)
{ {
await sutProvider.GetDependency<IPaymentService>() await sutProvider.GetDependency<IStripePaymentService>()
.DidNotReceiveWithAnyArgs() .DidNotReceiveWithAnyArgs()
.SponsorOrganizationAsync(default, default); .SponsorOrganizationAsync(default, default);
await sutProvider.GetDependency<IOrganizationRepository>() await sutProvider.GetDependency<IOrganizationRepository>()

View File

@@ -4,6 +4,7 @@ using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.StaticStore; using Bit.Core.Models.StaticStore;
@@ -54,7 +55,7 @@ public class AddSecretsManagerSubscriptionCommandTests
c.AdditionalServiceAccounts == additionalServiceAccounts && c.AdditionalServiceAccounts == additionalServiceAccounts &&
c.AdditionalSeats == organization.Seats.GetValueOrDefault())); c.AdditionalSeats == organization.Seats.GetValueOrDefault()));
await sutProvider.GetDependency<IPaymentService>().Received() await sutProvider.GetDependency<IStripePaymentService>().Received()
.AddSecretsManagerToSubscription(organization, plan, additionalSmSeats, additionalServiceAccounts); .AddSecretsManagerToSubscription(organization, plan, additionalSmSeats, additionalServiceAccounts);
// TODO: call ReferenceEventService - see AC-1481 // TODO: call ReferenceEventService - see AC-1481
@@ -150,7 +151,7 @@ public class AddSecretsManagerSubscriptionCommandTests
private static async Task VerifyDependencyNotCalledAsync(SutProvider<AddSecretsManagerSubscriptionCommand> sutProvider) private static async Task VerifyDependencyNotCalledAsync(SutProvider<AddSecretsManagerSubscriptionCommand> sutProvider)
{ {
await sutProvider.GetDependency<IPaymentService>().DidNotReceive() await sutProvider.GetDependency<IStripePaymentService>().DidNotReceive()
.AddSecretsManagerToSubscription(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>(), Arg.Any<int>()); .AddSecretsManagerToSubscription(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>(), Arg.Any<int>());
// TODO: call ReferenceEventService - see AC-1481 // TODO: call ReferenceEventService - see AC-1481

View File

@@ -1,5 +1,6 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Services;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
@@ -86,9 +87,9 @@ public class UpdateSecretsManagerSubscriptionCommandTests
await sutProvider.Sut.UpdateSubscriptionAsync(update); await sutProvider.Sut.UpdateSubscriptionAsync(update);
await sutProvider.GetDependency<IPaymentService>().Received(1) await sutProvider.GetDependency<IStripePaymentService>().Received(1)
.AdjustSmSeatsAsync(organization, plan, update.SmSeatsExcludingBase); .AdjustSmSeatsAsync(organization, plan, update.SmSeatsExcludingBase);
await sutProvider.GetDependency<IPaymentService>().Received(1) await sutProvider.GetDependency<IStripePaymentService>().Received(1)
.AdjustServiceAccountsAsync(organization, plan, update.SmServiceAccountsExcludingBase); .AdjustServiceAccountsAsync(organization, plan, update.SmServiceAccountsExcludingBase);
// TODO: call ReferenceEventService - see AC-1481 // TODO: call ReferenceEventService - see AC-1481
@@ -136,9 +137,9 @@ public class UpdateSecretsManagerSubscriptionCommandTests
await sutProvider.Sut.UpdateSubscriptionAsync(update); await sutProvider.Sut.UpdateSubscriptionAsync(update);
await sutProvider.GetDependency<IPaymentService>().Received(1) await sutProvider.GetDependency<IStripePaymentService>().Received(1)
.AdjustSmSeatsAsync(organization, plan, update.SmSeatsExcludingBase); .AdjustSmSeatsAsync(organization, plan, update.SmSeatsExcludingBase);
await sutProvider.GetDependency<IPaymentService>().Received(1) await sutProvider.GetDependency<IStripePaymentService>().Received(1)
.AdjustServiceAccountsAsync(organization, plan, update.SmServiceAccountsExcludingBase); .AdjustServiceAccountsAsync(organization, plan, update.SmServiceAccountsExcludingBase);
// TODO: call ReferenceEventService - see AC-1481 // TODO: call ReferenceEventService - see AC-1481
@@ -258,7 +259,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
await sutProvider.Sut.UpdateSubscriptionAsync(update); await sutProvider.Sut.UpdateSubscriptionAsync(update);
await sutProvider.GetDependency<IPaymentService>().Received(1).AdjustServiceAccountsAsync( await sutProvider.GetDependency<IStripePaymentService>().Received(1).AdjustServiceAccountsAsync(
Arg.Is<Organization>(o => o.Id == organizationId), Arg.Is<Organization>(o => o.Id == organizationId),
plan, plan,
expectedSmServiceAccountsExcludingBase); expectedSmServiceAccountsExcludingBase);
@@ -779,9 +780,9 @@ public class UpdateSecretsManagerSubscriptionCommandTests
private static async Task VerifyDependencyNotCalledAsync(SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider) private static async Task VerifyDependencyNotCalledAsync(SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
{ {
await sutProvider.GetDependency<IPaymentService>().DidNotReceive() await sutProvider.GetDependency<IStripePaymentService>().DidNotReceive()
.AdjustSmSeatsAsync(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>()); .AdjustSmSeatsAsync(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>());
await sutProvider.GetDependency<IPaymentService>().DidNotReceive() await sutProvider.GetDependency<IStripePaymentService>().DidNotReceive()
.AdjustServiceAccountsAsync(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>()); .AdjustServiceAccountsAsync(Arg.Any<Organization>(), Arg.Any<Plan>(), Arg.Any<int>());
// TODO: call ReferenceEventService - see AC-1481 // TODO: call ReferenceEventService - see AC-1481
await sutProvider.GetDependency<IMailService>().DidNotReceive() await sutProvider.GetDependency<IMailService>().DidNotReceive()

View File

@@ -1,5 +1,6 @@
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
@@ -121,7 +122,7 @@ public class UpgradeOrganizationPlanCommandTests
Users = 1 Users = 1
}); });
await sutProvider.Sut.UpgradePlanAsync(organization.Id, organizationUpgrade); await sutProvider.Sut.UpgradePlanAsync(organization.Id, organizationUpgrade);
await sutProvider.GetDependency<IPaymentService>().Received(1).AdjustSubscription( await sutProvider.GetDependency<IStripePaymentService>().Received(1).AdjustSubscription(
organization, organization,
MockPlans.Get(planType), MockPlans.Get(planType),
organizationUpgrade.AdditionalSeats, organizationUpgrade.AdditionalSeats,

View File

@@ -227,7 +227,7 @@ public abstract class WebApplicationFactoryBase<T> : WebApplicationFactory<T>
services.AddSingleton<ILoggerFactory, NullLoggerFactory>(); services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
// Noop StripePaymentService - this could be changed to integrate with our Stripe test account // Noop StripePaymentService - this could be changed to integrate with our Stripe test account
Replace(services, Substitute.For<IPaymentService>()); Replace(services, Substitute.For<IStripePaymentService>());
Replace(services, Substitute.For<IOrganizationBillingService>()); Replace(services, Substitute.For<IOrganizationBillingService>());
}); });