Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-16684] Integrate Pricing Service behind FF #5276

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
aa3e9fe
Remove gRPC and convert PricingClient to HttpClient wrapper
amorask-bitwarden Jan 14, 2025
c752582
Add PlanType.GetProductTier extension
amorask-bitwarden Jan 14, 2025
3435e75
Remove invocations of the StaticStore in non-Test code
amorask-bitwarden Jan 15, 2025
8538693
Deprecate StaticStore entry points
amorask-bitwarden Jan 15, 2025
2dddebf
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 15, 2025
b2593b6
Run dotnet format
amorask-bitwarden Jan 15, 2025
39eb028
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 16, 2025
679c158
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 16, 2025
250ac13
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 17, 2025
90ad0bb
Matt's feedback
amorask-bitwarden Jan 17, 2025
c5ce133
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 21, 2025
cfce0cf
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 23, 2025
f9ab39f
Run dotnet format
amorask-bitwarden Jan 23, 2025
8d60635
Rui's feedback
amorask-bitwarden Jan 23, 2025
88c0b8e
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 27, 2025
a8df63c
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 27, 2025
6dd97f0
Run dotnet format
amorask-bitwarden Jan 27, 2025
e85b501
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 28, 2025
ceadae5
Merge branch 'main' into billing/PM-16684/integrate-pricing-service
amorask-bitwarden Jan 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Extensions;
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Stripe;

namespace Bit.Commercial.Core.AdminConsole.Providers;
Expand All @@ -27,6 +27,7 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
private readonly IProviderBillingService _providerBillingService;
private readonly ISubscriberService _subscriberService;
private readonly IHasConfirmedOwnersExceptQuery _hasConfirmedOwnersExceptQuery;
private readonly IPricingClient _pricingClient;

public RemoveOrganizationFromProviderCommand(
IEventService eventService,
Expand All @@ -38,7 +39,8 @@ public RemoveOrganizationFromProviderCommand(
IFeatureService featureService,
IProviderBillingService providerBillingService,
ISubscriberService subscriberService,
IHasConfirmedOwnersExceptQuery hasConfirmedOwnersExceptQuery)
IHasConfirmedOwnersExceptQuery hasConfirmedOwnersExceptQuery,
IPricingClient pricingClient)
{
_eventService = eventService;
_mailService = mailService;
Expand All @@ -50,6 +52,7 @@ public RemoveOrganizationFromProviderCommand(
_providerBillingService = providerBillingService;
_subscriberService = subscriberService;
_hasConfirmedOwnersExceptQuery = hasConfirmedOwnersExceptQuery;
_pricingClient = pricingClient;
}

public async Task RemoveOrganizationFromProvider(
Expand Down Expand Up @@ -110,7 +113,7 @@ private async Task ResetOrganizationBillingAsync(
Email = organization.BillingEmail
});

var plan = StaticStore.GetPlan(organization.PlanType).PasswordManager;
var plan = await _pricingClient.GetPlanOrThrow(organization.PlanType);

var subscriptionCreateOptions = new SubscriptionCreateOptions
{
Expand All @@ -124,7 +127,7 @@ private async Task ResetOrganizationBillingAsync(
},
OffSession = true,
ProrationBehavior = StripeConstants.ProrationBehavior.CreateProrations,
Items = [new SubscriptionItemOptions { Price = plan.StripeSeatPlanId, Quantity = organization.Seats }]
Items = [new SubscriptionItemOptions { Price = plan.PasswordManager.StripeSeatPlanId, Quantity = organization.Seats }]
};

var subscription = await _stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Context;
using Bit.Core.Entities;
Expand Down Expand Up @@ -50,6 +51,7 @@
private readonly IDataProtectorTokenFactory<ProviderDeleteTokenable> _providerDeleteTokenDataFactory;
private readonly IApplicationCacheService _applicationCacheService;
private readonly IProviderBillingService _providerBillingService;
private readonly IPricingClient _pricingClient;

public ProviderService(IProviderRepository providerRepository, IProviderUserRepository providerUserRepository,
IProviderOrganizationRepository providerOrganizationRepository, IUserRepository userRepository,
Expand All @@ -58,7 +60,7 @@
IOrganizationRepository organizationRepository, GlobalSettings globalSettings,
ICurrentContext currentContext, IStripeAdapter stripeAdapter, IFeatureService featureService,
IDataProtectorTokenFactory<ProviderDeleteTokenable> providerDeleteTokenDataFactory,
IApplicationCacheService applicationCacheService, IProviderBillingService providerBillingService)
IApplicationCacheService applicationCacheService, IProviderBillingService providerBillingService, IPricingClient pricingClient)
{
_providerRepository = providerRepository;
_providerUserRepository = providerUserRepository;
Expand All @@ -77,6 +79,7 @@
_providerDeleteTokenDataFactory = providerDeleteTokenDataFactory;
_applicationCacheService = applicationCacheService;
_providerBillingService = providerBillingService;
_pricingClient = pricingClient;
}

public async Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key, TaxInfo taxInfo = null)
Expand Down Expand Up @@ -452,30 +455,31 @@

if (!string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
{
var subscriptionItem = await GetSubscriptionItemAsync(organization.GatewaySubscriptionId,
GetStripeSeatPlanId(organization.PlanType));
var plan = await _pricingClient.GetPlanOrThrow(organization.PlanType);

var subscriptionItem = await GetSubscriptionItemAsync(
organization.GatewaySubscriptionId,
plan.PasswordManager.StripeSeatPlanId);

var extractedPlanType = PlanTypeMappings(organization);
var extractedPlan = await _pricingClient.GetPlanOrThrow(extractedPlanType);

if (subscriptionItem != null)
{
await UpdateSubscriptionAsync(subscriptionItem, GetStripeSeatPlanId(extractedPlanType), organization);
await UpdateSubscriptionAsync(subscriptionItem, extractedPlan.PasswordManager.StripeSeatPlanId, organization);

Check warning on line 469 in bitwarden_license/src/Commercial.Core/AdminConsole/Services/ProviderService.cs

View check run for this annotation

Codecov / codecov/patch

bitwarden_license/src/Commercial.Core/AdminConsole/Services/ProviderService.cs#L469

Added line #L469 was not covered by tests
}
}

await _organizationRepository.UpsertAsync(organization);
}

private async Task<Stripe.SubscriptionItem> GetSubscriptionItemAsync(string subscriptionId, string oldPlanId)
private async Task<SubscriptionItem> GetSubscriptionItemAsync(string subscriptionId, string oldPlanId)
{
var subscriptionDetails = await _stripeAdapter.SubscriptionGetAsync(subscriptionId);
return subscriptionDetails.Items.Data.FirstOrDefault(item => item.Price.Id == oldPlanId);
}

private static string GetStripeSeatPlanId(PlanType planType)
{
return StaticStore.GetPlan(planType).PasswordManager.StripeSeatPlanId;
}

private async Task UpdateSubscriptionAsync(Stripe.SubscriptionItem subscriptionItem, string extractedPlanType, Organization organization)
private async Task UpdateSubscriptionAsync(SubscriptionItem subscriptionItem, string extractedPlanType, Organization organization)
{
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Entities;
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Repositories;
using Bit.Core.Billing.Services;
using Bit.Core.Billing.Services.Contracts;
Expand All @@ -16,7 +17,6 @@
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using CsvHelper;
using Microsoft.Extensions.Logging;
using Stripe;
Expand All @@ -28,6 +28,7 @@
ILogger<ProviderBillingService> logger,
IOrganizationRepository organizationRepository,
IPaymentService paymentService,
IPricingClient pricingClient,
IProviderInvoiceItemRepository providerInvoiceItemRepository,
IProviderOrganizationRepository providerOrganizationRepository,
IProviderPlanRepository providerPlanRepository,
Expand All @@ -49,7 +50,8 @@
return;
}

var oldPlanConfiguration = StaticStore.GetPlan(plan.PlanType);
var oldPlanConfiguration = await pricingClient.GetPlanOrThrow(plan.PlanType);
var newPlanConfiguration = await pricingClient.GetPlanOrThrow(command.NewPlan);

plan.PlanType = command.NewPlan;
await providerPlanRepository.ReplaceAsync(plan);
Expand All @@ -73,7 +75,7 @@
[
new SubscriptionItemOptions
{
Price = StaticStore.GetPlan(command.NewPlan).PasswordManager.StripeProviderPortalSeatPlanId,
Price = newPlanConfiguration.PasswordManager.StripeProviderPortalSeatPlanId,
Quantity = oldSubscriptionItem!.Quantity
},
new SubscriptionItemOptions
Expand All @@ -99,7 +101,7 @@
throw new ConflictException($"Organization '{providerOrganization.Id}' not found.");
}
organization.PlanType = command.NewPlan;
organization.Plan = StaticStore.GetPlan(command.NewPlan).Name;
organization.Plan = newPlanConfiguration.Name;

Check warning on line 104 in bitwarden_license/src/Commercial.Core/Billing/ProviderBillingService.cs

View check run for this annotation

Codecov / codecov/patch

bitwarden_license/src/Commercial.Core/Billing/ProviderBillingService.cs#L104

Added line #L104 was not covered by tests
await organizationRepository.ReplaceAsync(organization);
}
}
Expand Down Expand Up @@ -388,7 +390,7 @@

foreach (var providerPlan in providerPlans)
{
var plan = StaticStore.GetPlan(providerPlan.PlanType);
var plan = await pricingClient.GetPlanOrThrow(providerPlan.PlanType);

if (!providerPlan.IsConfigured())
{
Expand Down Expand Up @@ -472,8 +474,10 @@

if (providerPlan.SeatMinimum != newPlanConfiguration.SeatsMinimum)
{
var priceId = StaticStore.GetPlan(newPlanConfiguration.Plan).PasswordManager
.StripeProviderPortalSeatPlanId;
var newPlan = await pricingClient.GetPlanOrThrow(newPlanConfiguration.Plan);

var priceId = newPlan.PasswordManager.StripeProviderPortalSeatPlanId;

var subscriptionItem = subscription.Items.First(item => item.Price.Id == priceId);

if (providerPlan.PurchasedSeats == 0)
Expand Down Expand Up @@ -537,7 +541,7 @@
ProviderPlan providerPlan,
int newlyAssignedSeats) => async (currentlySubscribedSeats, newlySubscribedSeats) =>
{
var plan = StaticStore.GetPlan(providerPlan.PlanType);
var plan = await pricingClient.GetPlanOrThrow(providerPlan.PlanType);

await paymentService.AdjustSeats(
provider,
Expand All @@ -561,7 +565,7 @@
var providerOrganizations =
await providerOrganizationRepository.GetManyDetailsByProviderAsync(provider.Id);

var plan = StaticStore.GetPlan(planType);
var plan = await pricingClient.GetPlanOrThrow(planType);

return providerOrganizations
.Where(providerOrganization => providerOrganization.Plan == plan.Name && providerOrganization.Status == OrganizationStatusType.Managed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public MaxProjectsQuery(
throw new NotFoundException();
}

// TODO: PRICING -> https://bitwarden.atlassian.net/browse/PM-17122
var plan = StaticStore.GetPlan(org.PlanType);
if (plan?.SecretsManager == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
Expand Down Expand Up @@ -205,6 +206,8 @@ public async Task RemoveOrganizationFromProvider_OrganizationStripeEnabled_Conso

var teamsMonthlyPlan = StaticStore.GetPlan(PlanType.TeamsMonthly);

sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(PlanType.TeamsMonthly).Returns(teamsMonthlyPlan);

sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>().HasConfirmedOwnersExceptAsync(
providerOrganization.OrganizationId,
[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Bit.Core.AdminConsole.Models.Business.Tokenables;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Context;
using Bit.Core.Entities;
Expand Down Expand Up @@ -550,8 +551,14 @@ public async Task AddOrganization_CreateBeforeNov62023_PlanTypeUpdated(Provider
organization.PlanType = PlanType.EnterpriseMonthly;
organization.Plan = "Enterprise (Monthly)";

sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
.Returns(StaticStore.GetPlan(organization.PlanType));

var expectedPlanType = PlanType.EnterpriseMonthly2020;

sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(expectedPlanType)
.Returns(StaticStore.GetPlan(expectedPlanType));

var expectedPlanId = "2020-enterprise-org-seat-monthly";

sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
Expand Down
Loading
Loading