mirror of
https://github.com/bitwarden/server.git
synced 2025-07-04 01:22:50 -05:00
[PM-19147] Automatic Tax Improvements (#5545)
* Pm 19147 2 (#5544) * Pm 19147 2 (#5544) * Unit tests for tax strategies `GetUpdateOptions` * Only allow automatic tax flag to be updated for complete subscription updates such as plan changes, not when upgrading additional storage, seats, etc * unit tests for factory * Fix build * Automatic tax for tax estimation * Fix stub * Fix stub * "customer.tax_ids" isn't expanded in some flows. * Fix SubscriberServiceTests.cs * BusinessUseAutomaticTaxStrategy > SetUpdateOptions tests * Fix ProviderBillingServiceTests.cs
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.Providers.Interfaces;
|
||||
@ -7,10 +8,12 @@ using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Services.Implementations.AutomaticTax;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Stripe;
|
||||
|
||||
namespace Bit.Commercial.Core.AdminConsole.Providers;
|
||||
@ -28,6 +31,7 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
|
||||
private readonly ISubscriberService _subscriberService;
|
||||
private readonly IHasConfirmedOwnersExceptQuery _hasConfirmedOwnersExceptQuery;
|
||||
private readonly IPricingClient _pricingClient;
|
||||
private readonly IAutomaticTaxStrategy _automaticTaxStrategy;
|
||||
|
||||
public RemoveOrganizationFromProviderCommand(
|
||||
IEventService eventService,
|
||||
@ -40,7 +44,8 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
|
||||
IProviderBillingService providerBillingService,
|
||||
ISubscriberService subscriberService,
|
||||
IHasConfirmedOwnersExceptQuery hasConfirmedOwnersExceptQuery,
|
||||
IPricingClient pricingClient)
|
||||
IPricingClient pricingClient,
|
||||
[FromKeyedServices(AutomaticTaxFactory.BusinessUse)] IAutomaticTaxStrategy automaticTaxStrategy)
|
||||
{
|
||||
_eventService = eventService;
|
||||
_mailService = mailService;
|
||||
@ -53,6 +58,7 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
|
||||
_subscriberService = subscriberService;
|
||||
_hasConfirmedOwnersExceptQuery = hasConfirmedOwnersExceptQuery;
|
||||
_pricingClient = pricingClient;
|
||||
_automaticTaxStrategy = automaticTaxStrategy;
|
||||
}
|
||||
|
||||
public async Task RemoveOrganizationFromProvider(
|
||||
@ -107,10 +113,11 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
|
||||
organization.IsValidClient() &&
|
||||
!string.IsNullOrEmpty(organization.GatewayCustomerId))
|
||||
{
|
||||
await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, new CustomerUpdateOptions
|
||||
var customer = await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, new CustomerUpdateOptions
|
||||
{
|
||||
Description = string.Empty,
|
||||
Email = organization.BillingEmail
|
||||
Email = organization.BillingEmail,
|
||||
Expand = ["tax", "tax_ids"]
|
||||
});
|
||||
|
||||
var plan = await _pricingClient.GetPlanOrThrow(organization.PlanType);
|
||||
@ -120,7 +127,6 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
|
||||
Customer = organization.GatewayCustomerId,
|
||||
CollectionMethod = StripeConstants.CollectionMethod.SendInvoice,
|
||||
DaysUntilDue = 30,
|
||||
AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true },
|
||||
Metadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "organizationId", organization.Id.ToString() }
|
||||
@ -130,6 +136,18 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
|
||||
Items = [new SubscriptionItemOptions { Price = plan.PasswordManager.StripeSeatPlanId, Quantity = organization.Seats }]
|
||||
};
|
||||
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.PM19147_AutomaticTaxImprovements))
|
||||
{
|
||||
_automaticTaxStrategy.SetCreateOptions(subscriptionCreateOptions, customer);
|
||||
}
|
||||
else
|
||||
{
|
||||
subscriptionCreateOptions.AutomaticTax ??= new SubscriptionAutomaticTaxOptions
|
||||
{
|
||||
Enabled = true
|
||||
};
|
||||
}
|
||||
|
||||
var subscription = await _stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions);
|
||||
|
||||
organization.GatewaySubscriptionId = subscription.Id;
|
||||
|
@ -14,6 +14,7 @@ using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Services.Contracts;
|
||||
using Bit.Core.Billing.Services.Implementations.AutomaticTax;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
@ -22,6 +23,7 @@ using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using CsvHelper;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Stripe;
|
||||
|
||||
@ -29,6 +31,7 @@ namespace Bit.Commercial.Core.Billing;
|
||||
|
||||
public class ProviderBillingService(
|
||||
IEventService eventService,
|
||||
IFeatureService featureService,
|
||||
IGlobalSettings globalSettings,
|
||||
ILogger<ProviderBillingService> logger,
|
||||
IOrganizationRepository organizationRepository,
|
||||
@ -40,7 +43,9 @@ public class ProviderBillingService(
|
||||
IProviderUserRepository providerUserRepository,
|
||||
IStripeAdapter stripeAdapter,
|
||||
ISubscriberService subscriberService,
|
||||
ITaxService taxService) : IProviderBillingService
|
||||
ITaxService taxService,
|
||||
[FromKeyedServices(AutomaticTaxFactory.BusinessUse)] IAutomaticTaxStrategy automaticTaxStrategy)
|
||||
: IProviderBillingService
|
||||
{
|
||||
[RequireFeature(FeatureFlagKeys.P15179_AddExistingOrgsFromProviderPortal)]
|
||||
public async Task AddExistingOrganization(
|
||||
@ -557,7 +562,8 @@ public class ProviderBillingService(
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(provider);
|
||||
|
||||
var customer = await subscriberService.GetCustomerOrThrow(provider);
|
||||
var customerGetOptions = new CustomerGetOptions { Expand = ["tax", "tax_ids"] };
|
||||
var customer = await subscriberService.GetCustomerOrThrow(provider, customerGetOptions);
|
||||
|
||||
var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id);
|
||||
|
||||
@ -589,10 +595,6 @@ public class ProviderBillingService(
|
||||
|
||||
var subscriptionCreateOptions = new SubscriptionCreateOptions
|
||||
{
|
||||
AutomaticTax = new SubscriptionAutomaticTaxOptions
|
||||
{
|
||||
Enabled = true
|
||||
},
|
||||
CollectionMethod = StripeConstants.CollectionMethod.SendInvoice,
|
||||
Customer = customer.Id,
|
||||
DaysUntilDue = 30,
|
||||
@ -605,6 +607,15 @@ public class ProviderBillingService(
|
||||
ProrationBehavior = StripeConstants.ProrationBehavior.CreateProrations
|
||||
};
|
||||
|
||||
if (featureService.IsEnabled(FeatureFlagKeys.PM19147_AutomaticTaxImprovements))
|
||||
{
|
||||
automaticTaxStrategy.SetCreateOptions(subscriptionCreateOptions, customer);
|
||||
}
|
||||
else
|
||||
{
|
||||
subscriptionCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var subscription = await stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions);
|
||||
|
Reference in New Issue
Block a user