mirror of
https://github.com/bitwarden/server
synced 2025-12-23 11:43:23 +00:00
[PM-16684] Integrate Pricing Service behind FF (#5276)
* Remove gRPC and convert PricingClient to HttpClient wrapper * Add PlanType.GetProductTier extension Many instances of StaticStore use are just to get the ProductTierType of a PlanType, but this can be derived from the PlanType itself without having to fetch the entire plan. * Remove invocations of the StaticStore in non-Test code * Deprecate StaticStore entry points * Run dotnet format * Matt's feedback * Run dotnet format * Rui's feedback * Run dotnet format * Replacements since approval * Run dotnet format
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing.Models;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
using Proto.Billing.Pricing;
|
||||
|
||||
#nullable enable
|
||||
|
||||
@@ -8,15 +8,15 @@ namespace Bit.Core.Billing.Pricing;
|
||||
|
||||
public record PlanAdapter : Plan
|
||||
{
|
||||
public PlanAdapter(PlanResponse planResponse)
|
||||
public PlanAdapter(PlanDTO plan)
|
||||
{
|
||||
Type = ToPlanType(planResponse.LookupKey);
|
||||
Type = ToPlanType(plan.LookupKey);
|
||||
ProductTier = ToProductTierType(Type);
|
||||
Name = planResponse.Name;
|
||||
IsAnnual = !string.IsNullOrEmpty(planResponse.Cadence) && planResponse.Cadence == "annually";
|
||||
NameLocalizationKey = planResponse.AdditionalData?["nameLocalizationKey"];
|
||||
DescriptionLocalizationKey = planResponse.AdditionalData?["descriptionLocalizationKey"];
|
||||
TrialPeriodDays = planResponse.TrialPeriodDays;
|
||||
Name = plan.Name;
|
||||
IsAnnual = plan.Cadence is "annually";
|
||||
NameLocalizationKey = plan.AdditionalData["nameLocalizationKey"];
|
||||
DescriptionLocalizationKey = plan.AdditionalData["descriptionLocalizationKey"];
|
||||
TrialPeriodDays = plan.TrialPeriodDays;
|
||||
HasSelfHost = HasFeature("selfHost");
|
||||
HasPolicies = HasFeature("policies");
|
||||
HasGroups = HasFeature("groups");
|
||||
@@ -30,20 +30,20 @@ public record PlanAdapter : Plan
|
||||
HasScim = HasFeature("scim");
|
||||
HasResetPassword = HasFeature("resetPassword");
|
||||
UsersGetPremium = HasFeature("usersGetPremium");
|
||||
UpgradeSortOrder = planResponse.AdditionalData != null
|
||||
? int.Parse(planResponse.AdditionalData["upgradeSortOrder"])
|
||||
UpgradeSortOrder = plan.AdditionalData.TryGetValue("upgradeSortOrder", out var upgradeSortOrder)
|
||||
? int.Parse(upgradeSortOrder)
|
||||
: 0;
|
||||
DisplaySortOrder = planResponse.AdditionalData != null
|
||||
? int.Parse(planResponse.AdditionalData["displaySortOrder"])
|
||||
DisplaySortOrder = plan.AdditionalData.TryGetValue("displaySortOrder", out var displaySortOrder)
|
||||
? int.Parse(displaySortOrder)
|
||||
: 0;
|
||||
HasCustomPermissions = HasFeature("customPermissions");
|
||||
Disabled = !planResponse.Available;
|
||||
PasswordManager = ToPasswordManagerPlanFeatures(planResponse);
|
||||
SecretsManager = planResponse.SecretsManager != null ? ToSecretsManagerPlanFeatures(planResponse) : null;
|
||||
Disabled = !plan.Available;
|
||||
LegacyYear = plan.LegacyYear;
|
||||
PasswordManager = ToPasswordManagerPlanFeatures(plan);
|
||||
SecretsManager = plan.SecretsManager != null ? ToSecretsManagerPlanFeatures(plan) : null;
|
||||
|
||||
return;
|
||||
|
||||
bool HasFeature(string lookupKey) => planResponse.Features.Any(feature => feature.LookupKey == lookupKey);
|
||||
bool HasFeature(string lookupKey) => plan.Features.Any(feature => feature.LookupKey == lookupKey);
|
||||
}
|
||||
|
||||
#region Mappings
|
||||
@@ -86,29 +86,25 @@ public record PlanAdapter : Plan
|
||||
_ => throw new BillingException() // TODO: Flesh out
|
||||
};
|
||||
|
||||
private static PasswordManagerPlanFeatures ToPasswordManagerPlanFeatures(PlanResponse planResponse)
|
||||
private static PasswordManagerPlanFeatures ToPasswordManagerPlanFeatures(PlanDTO plan)
|
||||
{
|
||||
var stripePlanId = GetStripePlanId(planResponse.Seats);
|
||||
var stripeSeatPlanId = GetStripeSeatPlanId(planResponse.Seats);
|
||||
var stripeProviderPortalSeatPlanId = planResponse.ManagedSeats?.StripePriceId;
|
||||
var basePrice = GetBasePrice(planResponse.Seats);
|
||||
var seatPrice = GetSeatPrice(planResponse.Seats);
|
||||
var providerPortalSeatPrice =
|
||||
planResponse.ManagedSeats != null ? decimal.Parse(planResponse.ManagedSeats.Price) : 0;
|
||||
var scales = planResponse.Seats.KindCase switch
|
||||
{
|
||||
PurchasableDTO.KindOneofCase.Scalable => true,
|
||||
PurchasableDTO.KindOneofCase.Packaged => planResponse.Seats.Packaged.Additional != null,
|
||||
_ => false
|
||||
};
|
||||
var baseSeats = GetBaseSeats(planResponse.Seats);
|
||||
var maxSeats = GetMaxSeats(planResponse.Seats);
|
||||
var baseStorageGb = (short?)planResponse.Storage?.Provided;
|
||||
var hasAdditionalStorageOption = planResponse.Storage != null;
|
||||
var stripeStoragePlanId = planResponse.Storage?.StripePriceId;
|
||||
short? maxCollections =
|
||||
planResponse.AdditionalData != null &&
|
||||
planResponse.AdditionalData.TryGetValue("passwordManager.maxCollections", out var value) ? short.Parse(value) : null;
|
||||
var stripePlanId = GetStripePlanId(plan.Seats);
|
||||
var stripeSeatPlanId = GetStripeSeatPlanId(plan.Seats);
|
||||
var stripeProviderPortalSeatPlanId = plan.ManagedSeats?.StripePriceId;
|
||||
var basePrice = GetBasePrice(plan.Seats);
|
||||
var seatPrice = GetSeatPrice(plan.Seats);
|
||||
var providerPortalSeatPrice = plan.ManagedSeats?.Price ?? 0;
|
||||
var scales = plan.Seats.Match(
|
||||
_ => false,
|
||||
packaged => packaged.Additional != null,
|
||||
_ => true);
|
||||
var baseSeats = GetBaseSeats(plan.Seats);
|
||||
var maxSeats = GetMaxSeats(plan.Seats);
|
||||
var baseStorageGb = (short?)plan.Storage?.Provided;
|
||||
var hasAdditionalStorageOption = plan.Storage != null;
|
||||
var additionalStoragePricePerGb = plan.Storage?.Price ?? 0;
|
||||
var stripeStoragePlanId = plan.Storage?.StripePriceId;
|
||||
short? maxCollections = plan.AdditionalData.TryGetValue("passwordManager.maxCollections", out var value) ? short.Parse(value) : null;
|
||||
|
||||
return new PasswordManagerPlanFeatures
|
||||
{
|
||||
@@ -124,30 +120,29 @@ public record PlanAdapter : Plan
|
||||
MaxSeats = maxSeats,
|
||||
BaseStorageGb = baseStorageGb,
|
||||
HasAdditionalStorageOption = hasAdditionalStorageOption,
|
||||
AdditionalStoragePricePerGb = additionalStoragePricePerGb,
|
||||
StripeStoragePlanId = stripeStoragePlanId,
|
||||
MaxCollections = maxCollections
|
||||
};
|
||||
}
|
||||
|
||||
private static SecretsManagerPlanFeatures ToSecretsManagerPlanFeatures(PlanResponse planResponse)
|
||||
private static SecretsManagerPlanFeatures ToSecretsManagerPlanFeatures(PlanDTO plan)
|
||||
{
|
||||
var seats = planResponse.SecretsManager.Seats;
|
||||
var serviceAccounts = planResponse.SecretsManager.ServiceAccounts;
|
||||
var seats = plan.SecretsManager!.Seats;
|
||||
var serviceAccounts = plan.SecretsManager.ServiceAccounts;
|
||||
|
||||
var maxServiceAccounts = GetMaxServiceAccounts(serviceAccounts);
|
||||
var allowServiceAccountsAutoscale = serviceAccounts.KindCase == FreeOrScalableDTO.KindOneofCase.Scalable;
|
||||
var allowServiceAccountsAutoscale = serviceAccounts.IsScalable;
|
||||
var stripeServiceAccountPlanId = GetStripeServiceAccountPlanId(serviceAccounts);
|
||||
var additionalPricePerServiceAccount = GetAdditionalPricePerServiceAccount(serviceAccounts);
|
||||
var baseServiceAccount = GetBaseServiceAccount(serviceAccounts);
|
||||
var hasAdditionalServiceAccountOption = serviceAccounts.KindCase == FreeOrScalableDTO.KindOneofCase.Scalable;
|
||||
var hasAdditionalServiceAccountOption = serviceAccounts.IsScalable;
|
||||
var stripeSeatPlanId = GetStripeSeatPlanId(seats);
|
||||
var hasAdditionalSeatsOption = seats.KindCase == FreeOrScalableDTO.KindOneofCase.Scalable;
|
||||
var hasAdditionalSeatsOption = seats.IsScalable;
|
||||
var seatPrice = GetSeatPrice(seats);
|
||||
var maxSeats = GetMaxSeats(seats);
|
||||
var allowSeatAutoscale = seats.KindCase == FreeOrScalableDTO.KindOneofCase.Scalable;
|
||||
var maxProjects =
|
||||
planResponse.AdditionalData != null &&
|
||||
planResponse.AdditionalData.TryGetValue("secretsManager.maxProjects", out var value) ? short.Parse(value) : 0;
|
||||
var allowSeatAutoscale = seats.IsScalable;
|
||||
var maxProjects = plan.AdditionalData.TryGetValue("secretsManager.maxProjects", out var value) ? short.Parse(value) : 0;
|
||||
|
||||
return new SecretsManagerPlanFeatures
|
||||
{
|
||||
@@ -167,66 +162,54 @@ public record PlanAdapter : Plan
|
||||
}
|
||||
|
||||
private static decimal? GetAdditionalPricePerServiceAccount(FreeOrScalableDTO freeOrScalable)
|
||||
=> freeOrScalable.KindCase != FreeOrScalableDTO.KindOneofCase.Scalable
|
||||
? null
|
||||
: decimal.Parse(freeOrScalable.Scalable.Price);
|
||||
=> freeOrScalable.FromScalable(x => x.Price);
|
||||
|
||||
private static decimal GetBasePrice(PurchasableDTO purchasable)
|
||||
=> purchasable.KindCase != PurchasableDTO.KindOneofCase.Packaged ? 0 : decimal.Parse(purchasable.Packaged.Price);
|
||||
=> purchasable.FromPackaged(x => x.Price);
|
||||
|
||||
private static int GetBaseSeats(PurchasableDTO purchasable)
|
||||
=> purchasable.KindCase != PurchasableDTO.KindOneofCase.Packaged ? 0 : purchasable.Packaged.Quantity;
|
||||
=> purchasable.FromPackaged(x => x.Quantity);
|
||||
|
||||
private static short GetBaseServiceAccount(FreeOrScalableDTO freeOrScalable)
|
||||
=> freeOrScalable.KindCase switch
|
||||
{
|
||||
FreeOrScalableDTO.KindOneofCase.Free => (short)freeOrScalable.Free.Quantity,
|
||||
FreeOrScalableDTO.KindOneofCase.Scalable => (short)freeOrScalable.Scalable.Provided,
|
||||
_ => 0
|
||||
};
|
||||
=> freeOrScalable.Match(
|
||||
free => (short)free.Quantity,
|
||||
scalable => (short)scalable.Provided);
|
||||
|
||||
private static short? GetMaxSeats(PurchasableDTO purchasable)
|
||||
=> purchasable.KindCase != PurchasableDTO.KindOneofCase.Free ? null : (short)purchasable.Free.Quantity;
|
||||
=> purchasable.Match<short?>(
|
||||
free => (short)free.Quantity,
|
||||
packaged => (short)packaged.Quantity,
|
||||
_ => null);
|
||||
|
||||
private static short? GetMaxSeats(FreeOrScalableDTO freeOrScalable)
|
||||
=> freeOrScalable.KindCase != FreeOrScalableDTO.KindOneofCase.Free ? null : (short)freeOrScalable.Free.Quantity;
|
||||
=> freeOrScalable.FromFree(x => (short)x.Quantity);
|
||||
|
||||
private static short? GetMaxServiceAccounts(FreeOrScalableDTO freeOrScalable)
|
||||
=> freeOrScalable.KindCase != FreeOrScalableDTO.KindOneofCase.Free ? null : (short)freeOrScalable.Free.Quantity;
|
||||
=> freeOrScalable.FromFree(x => (short)x.Quantity);
|
||||
|
||||
private static decimal GetSeatPrice(PurchasableDTO purchasable)
|
||||
=> purchasable.KindCase switch
|
||||
{
|
||||
PurchasableDTO.KindOneofCase.Packaged => purchasable.Packaged.Additional != null ? decimal.Parse(purchasable.Packaged.Additional.Price) : 0,
|
||||
PurchasableDTO.KindOneofCase.Scalable => decimal.Parse(purchasable.Scalable.Price),
|
||||
_ => 0
|
||||
};
|
||||
=> purchasable.Match(
|
||||
_ => 0,
|
||||
packaged => packaged.Additional?.Price ?? 0,
|
||||
scalable => scalable.Price);
|
||||
|
||||
private static decimal GetSeatPrice(FreeOrScalableDTO freeOrScalable)
|
||||
=> freeOrScalable.KindCase != FreeOrScalableDTO.KindOneofCase.Scalable
|
||||
? 0
|
||||
: decimal.Parse(freeOrScalable.Scalable.Price);
|
||||
=> freeOrScalable.FromScalable(x => x.Price);
|
||||
|
||||
private static string? GetStripePlanId(PurchasableDTO purchasable)
|
||||
=> purchasable.KindCase != PurchasableDTO.KindOneofCase.Packaged ? null : purchasable.Packaged.StripePriceId;
|
||||
=> purchasable.FromPackaged(x => x.StripePriceId);
|
||||
|
||||
private static string? GetStripeSeatPlanId(PurchasableDTO purchasable)
|
||||
=> purchasable.KindCase switch
|
||||
{
|
||||
PurchasableDTO.KindOneofCase.Packaged => purchasable.Packaged.Additional?.StripePriceId,
|
||||
PurchasableDTO.KindOneofCase.Scalable => purchasable.Scalable.StripePriceId,
|
||||
_ => null
|
||||
};
|
||||
=> purchasable.Match(
|
||||
_ => null,
|
||||
packaged => packaged.Additional?.StripePriceId,
|
||||
scalable => scalable.StripePriceId);
|
||||
|
||||
private static string? GetStripeSeatPlanId(FreeOrScalableDTO freeOrScalable)
|
||||
=> freeOrScalable.KindCase != FreeOrScalableDTO.KindOneofCase.Scalable
|
||||
? null
|
||||
: freeOrScalable.Scalable.StripePriceId;
|
||||
=> freeOrScalable.FromScalable(x => x.StripePriceId);
|
||||
|
||||
private static string? GetStripeServiceAccountPlanId(FreeOrScalableDTO freeOrScalable)
|
||||
=> freeOrScalable.KindCase != FreeOrScalableDTO.KindOneofCase.Scalable
|
||||
? null
|
||||
: freeOrScalable.Scalable.StripePriceId;
|
||||
=> freeOrScalable.FromScalable(x => x.StripePriceId);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user