1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-21 12:05:42 +01:00

Removed automatic tax feature flag (#4487)

This commit is contained in:
Conner Turnbull 2024-07-10 07:32:41 -04:00 committed by GitHub
parent ff8a436cd4
commit 9e78236a72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 22 additions and 160 deletions

View File

@ -1,5 +1,4 @@
using Bit.Billing.Constants;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Constants;
@ -9,7 +8,6 @@ using Bit.Core.Services;
using Bit.Core.Utilities;
using Stripe;
using Event = Stripe.Event;
using TaxRate = Bit.Core.Entities.TaxRate;
namespace Bit.Billing.Services.Implementations;
@ -19,38 +17,32 @@ public class UpcomingInvoiceHandler : IUpcomingInvoiceHandler
private readonly IStripeEventService _stripeEventService;
private readonly IUserService _userService;
private readonly IStripeFacade _stripeFacade;
private readonly IFeatureService _featureService;
private readonly IMailService _mailService;
private readonly IProviderRepository _providerRepository;
private readonly IValidateSponsorshipCommand _validateSponsorshipCommand;
private readonly IOrganizationRepository _organizationRepository;
private readonly IStripeEventUtilityService _stripeEventUtilityService;
private readonly ITaxRateRepository _taxRateRepository;
public UpcomingInvoiceHandler(
ILogger<StripeEventProcessor> logger,
IStripeEventService stripeEventService,
IUserService userService,
IStripeFacade stripeFacade,
IFeatureService featureService,
IMailService mailService,
IProviderRepository providerRepository,
IValidateSponsorshipCommand validateSponsorshipCommand,
IOrganizationRepository organizationRepository,
IStripeEventUtilityService stripeEventUtilityService,
ITaxRateRepository taxRateRepository)
IStripeEventUtilityService stripeEventUtilityService)
{
_logger = logger;
_stripeEventService = stripeEventService;
_userService = userService;
_stripeFacade = stripeFacade;
_featureService = featureService;
_mailService = mailService;
_providerRepository = providerRepository;
_validateSponsorshipCommand = validateSponsorshipCommand;
_organizationRepository = organizationRepository;
_stripeEventUtilityService = stripeEventUtilityService;
_taxRateRepository = taxRateRepository;
}
/// <summary>
@ -75,27 +67,7 @@ public class UpcomingInvoiceHandler : IUpcomingInvoiceHandler
$"Received null Subscription from Stripe for ID '{invoice.SubscriptionId}' while processing Event with ID '{parsedEvent.Id}'");
}
var pm5766AutomaticTaxIsEnabled = _featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax);
if (pm5766AutomaticTaxIsEnabled)
{
var customerGetOptions = new CustomerGetOptions();
customerGetOptions.AddExpand("tax");
var customer = await _stripeFacade.GetCustomer(subscription.CustomerId, customerGetOptions);
if (!subscription.AutomaticTax.Enabled &&
customer.Tax?.AutomaticTax == StripeConstants.AutomaticTaxStatus.Supported)
{
subscription = await _stripeFacade.UpdateSubscription(subscription.Id,
new SubscriptionUpdateOptions
{
DefaultTaxRates = [],
AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }
});
}
}
var updatedSubscription = pm5766AutomaticTaxIsEnabled
? subscription
: await VerifyCorrectTaxRateForChargeAsync(invoice, subscription);
var updatedSubscription = await TryEnableAutomaticTaxAsync(subscription);
var (organizationId, userId, providerId) = _stripeEventUtilityService.GetIdsFromMetadata(updatedSubscription.Metadata);
@ -176,39 +148,24 @@ public class UpcomingInvoiceHandler : IUpcomingInvoiceHandler
}
}
private async Task<Stripe.Subscription> VerifyCorrectTaxRateForChargeAsync(Invoice invoice, Stripe.Subscription subscription)
private async Task<Subscription> TryEnableAutomaticTaxAsync(Subscription subscription)
{
if (string.IsNullOrWhiteSpace(invoice?.CustomerAddress?.Country) ||
string.IsNullOrWhiteSpace(invoice?.CustomerAddress?.PostalCode))
var customerGetOptions = new CustomerGetOptions { Expand = ["tax"] };
var customer = await _stripeFacade.GetCustomer(subscription.CustomerId, customerGetOptions);
if (subscription.AutomaticTax.Enabled ||
customer.Tax?.AutomaticTax != StripeConstants.AutomaticTaxStatus.Supported)
{
return subscription;
}
var localBitwardenTaxRates = await _taxRateRepository.GetByLocationAsync(
new TaxRate()
{
Country = invoice.CustomerAddress.Country,
PostalCode = invoice.CustomerAddress.PostalCode
}
);
if (!localBitwardenTaxRates.Any())
var subscriptionUpdateOptions = new SubscriptionUpdateOptions
{
return subscription;
}
DefaultTaxRates = [],
AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }
};
var stripeTaxRate = await _stripeFacade.GetTaxRate(localBitwardenTaxRates.First().Id);
if (stripeTaxRate == null || subscription.DefaultTaxRates.Any(x => x == stripeTaxRate))
{
return subscription;
}
subscription.DefaultTaxRates = [stripeTaxRate];
var subscriptionOptions = new SubscriptionUpdateOptions { DefaultTaxRates = [stripeTaxRate.Id] };
subscription = await _stripeFacade.UpdateSubscription(subscription.Id, subscriptionOptions);
return subscription;
return await _stripeFacade.UpdateSubscription(subscription.Id, subscriptionUpdateOptions);
}
private static bool OrgPlanForInvoiceNotifications(Organization org) => StaticStore.GetPlan(org.PlanType).IsAnnual;

View File

@ -148,9 +148,7 @@ public class OrganizationService : IOrganizationService
organization,
paymentMethodType,
paymentToken,
_featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax)
? taxInfo
: null);
taxInfo);
if (updated)
{
await ReplaceAndUpdateCacheAsync(organization);

View File

@ -115,7 +115,6 @@ public static class FeatureFlagKeys
public const string ItemShare = "item-share";
public const string KeyRotationImprovements = "key-rotation-improvements";
public const string DuoRedirect = "duo-redirect";
public const string PM5766AutomaticTax = "PM-5766-automatic-tax";
public const string PM5864DollarThreshold = "PM-5864-dollar-threshold";
public const string ShowPaymentMethodWarningBanners = "show-payment-method-warning-banners";
public const string AC2101UpdateTrialInitiationEmail = "AC-2101-update-trial-initiation-email";

View File

@ -103,28 +103,6 @@ public class StripePaymentService : IPaymentService
throw new GatewayException("Payment method is not supported at this time.");
}
var pm5766AutomaticTaxIsEnabled = _featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax);
if (!pm5766AutomaticTaxIsEnabled &&
taxInfo != null &&
!string.IsNullOrWhiteSpace(taxInfo.BillingAddressCountry) &&
!string.IsNullOrWhiteSpace(taxInfo.BillingAddressPostalCode))
{
var taxRateSearch = new TaxRate
{
Country = taxInfo.BillingAddressCountry,
PostalCode = taxInfo.BillingAddressPostalCode
};
var taxRates = await _taxRateRepository.GetByLocationAsync(taxRateSearch);
// should only be one tax rate per country/zip combo
var taxRate = taxRates.FirstOrDefault();
if (taxRate != null)
{
taxInfo.StripeTaxRateId = taxRate.Id;
}
}
var subCreateOptions = new OrganizationPurchaseSubscriptionOptions(org, plan, taxInfo, additionalSeats, additionalStorageGb, premiumAccessAddon
, additionalSmSeats, additionalServiceAccount);
@ -180,7 +158,7 @@ public class StripePaymentService : IPaymentService
subCreateOptions.AddExpand("latest_invoice.payment_intent");
subCreateOptions.Customer = customer.Id;
if (pm5766AutomaticTaxIsEnabled && CustomerHasTaxLocationVerified(customer))
if (CustomerHasTaxLocationVerified(customer))
{
subCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
}
@ -273,31 +251,7 @@ public class StripePaymentService : IPaymentService
throw new GatewayException("Could not find customer payment profile.");
}
var pm5766AutomaticTaxIsEnabled = _featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax);
var taxInfo = upgrade.TaxInfo;
if (!pm5766AutomaticTaxIsEnabled &&
taxInfo != null &&
!string.IsNullOrWhiteSpace(taxInfo.BillingAddressCountry) &&
!string.IsNullOrWhiteSpace(taxInfo.BillingAddressPostalCode))
{
var taxRateSearch = new TaxRate
{
Country = taxInfo.BillingAddressCountry,
PostalCode = taxInfo.BillingAddressPostalCode
};
var taxRates = await _taxRateRepository.GetByLocationAsync(taxRateSearch);
// should only be one tax rate per country/zip combo
var taxRate = taxRates.FirstOrDefault();
if (taxRate != null)
{
taxInfo.StripeTaxRateId = taxRate.Id;
}
}
if (pm5766AutomaticTaxIsEnabled &&
!string.IsNullOrEmpty(upgrade.TaxInfo?.BillingAddressCountry) &&
if (!string.IsNullOrEmpty(upgrade.TaxInfo?.BillingAddressCountry) &&
!string.IsNullOrEmpty(upgrade.TaxInfo?.BillingAddressPostalCode))
{
var addressOptions = new AddressOptions
@ -319,7 +273,7 @@ public class StripePaymentService : IPaymentService
var subCreateOptions = new OrganizationUpgradeSubscriptionOptions(customer.Id, org, plan, upgrade);
if (pm5766AutomaticTaxIsEnabled && CustomerHasTaxLocationVerified(customer))
if (CustomerHasTaxLocationVerified(customer))
{
subCreateOptions.DefaultTaxRates = [];
subCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
@ -533,26 +487,6 @@ public class StripePaymentService : IPaymentService
Quantity = 1
});
var pm5766AutomaticTaxIsEnabled = _featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax);
if (!pm5766AutomaticTaxIsEnabled &&
!string.IsNullOrWhiteSpace(taxInfo?.BillingAddressCountry) &&
!string.IsNullOrWhiteSpace(taxInfo?.BillingAddressPostalCode))
{
var taxRates = await _taxRateRepository.GetByLocationAsync(
new TaxRate
{
Country = taxInfo.BillingAddressCountry,
PostalCode = taxInfo.BillingAddressPostalCode
}
);
var taxRate = taxRates.FirstOrDefault();
if (taxRate != null)
{
subCreateOptions.DefaultTaxRates = [taxRate.Id];
}
}
if (additionalStorageGb > 0)
{
subCreateOptions.Items.Add(new SubscriptionItemOptions
@ -562,7 +496,7 @@ public class StripePaymentService : IPaymentService
});
}
if (pm5766AutomaticTaxIsEnabled && CustomerHasTaxLocationVerified(customer))
if (CustomerHasTaxLocationVerified(customer))
{
subCreateOptions.DefaultTaxRates = [];
subCreateOptions.AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true };
@ -605,8 +539,7 @@ public class StripePaymentService : IPaymentService
SubscriptionItems = ToInvoiceSubscriptionItemOptions(subCreateOptions.Items)
});
if (_featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax) &&
CustomerHasTaxLocationVerified(customer))
if (CustomerHasTaxLocationVerified(customer))
{
previewInvoice.AutomaticTax = new InvoiceAutomaticTax { Enabled = true };
}
@ -669,8 +602,7 @@ public class StripePaymentService : IPaymentService
SubscriptionDefaultTaxRates = subCreateOptions.DefaultTaxRates,
};
var pm5766AutomaticTaxIsEnabled = _featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax);
if (pm5766AutomaticTaxIsEnabled && CustomerHasTaxLocationVerified(customer))
if (CustomerHasTaxLocationVerified(customer))
{
upcomingInvoiceOptions.AutomaticTax = new InvoiceAutomaticTaxOptions { Enabled = true };
upcomingInvoiceOptions.SubscriptionDefaultTaxRates = [];
@ -800,9 +732,7 @@ public class StripePaymentService : IPaymentService
new SubscriptionPendingInvoiceItemIntervalOptions { Interval = "month" };
}
var pm5766AutomaticTaxIsEnabled = _featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax);
if (pm5766AutomaticTaxIsEnabled &&
sub.AutomaticTax.Enabled != true &&
if (sub.AutomaticTax.Enabled != true &&
CustomerHasTaxLocationVerified(sub.Customer))
{
subUpdateOptions.DefaultTaxRates = [];
@ -815,26 +745,6 @@ public class StripePaymentService : IPaymentService
return null;
}
if (!pm5766AutomaticTaxIsEnabled)
{
var customer = await _stripeAdapter.CustomerGetAsync(sub.CustomerId);
if (!string.IsNullOrWhiteSpace(customer?.Address?.Country)
&& !string.IsNullOrWhiteSpace(customer?.Address?.PostalCode))
{
var taxRates = await _taxRateRepository.GetByLocationAsync(new TaxRate
{
Country = customer.Address.Country,
PostalCode = customer.Address.PostalCode
});
var taxRate = taxRates.FirstOrDefault();
if (taxRate != null && !sub.DefaultTaxRates.Any(x => x.Equals(taxRate.Id)))
{
subUpdateOptions.DefaultTaxRates = [taxRate.Id];
}
}
}
string paymentIntentClientSecret = null;
try
{
@ -1502,8 +1412,7 @@ public class StripePaymentService : IPaymentService
});
}
if (_featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax) &&
!string.IsNullOrEmpty(subscriber.GatewaySubscriptionId) &&
if (!string.IsNullOrEmpty(subscriber.GatewaySubscriptionId) &&
customer.Subscriptions.Any(sub =>
sub.Id == subscriber.GatewaySubscriptionId &&
!sub.AutomaticTax.Enabled) &&

View File

@ -725,7 +725,6 @@ public class StripePaymentServiceTests
AmountDue = 0
});
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription { });
featureService.IsEnabled(FeatureFlagKeys.PM5766AutomaticTax).Returns(true);
var upgrade = new OrganizationUpgrade()
{