1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-08 03:15:07 -05:00

[AC 1451] Refactor staticstore plans and consuming logic (#3164)

* refactor the plan and create new objects

* initial commit

* Add new plan types

* continue the refactoring by adding new plantypes

* changes for plans

* Refactoring continues

* making changes for plan

* Fixing the failing test

* Fixing  whitespace

* Fix some in correct values

* Resolve the plan data

* rearranging the plan

* Make the plan more immutable

* Resolve the lint errors

* Fix the failing test

* Add custom plan

* Fix the failing test

* Fix the failing test

* resolve the failing addons after refactoring

* Refactoring

* Merge branch 'master' into ac-1451/refactor-staticstore-plans-and-consuming-logic

* merge from master

* Merge branch 'master' into ac-1451/refactor-staticstore-plans-and-consuming-logic

* format whitespace

* resolve the conflict

* Fix some pr comments

* Fixing some of the pr comments

* fixing some of the pr comments

* Resolve some pr comments

* Resolve pr comments

* Resolves some pr comments

* Resolving some or comments

* Resolve a failing test

* fix the failing test

* Resolving some pr comments

* Fix the failing test

* resolve pr comment

* add a using statement fir a failing test

---------

Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
This commit is contained in:
cyprain-okeke
2023-10-17 15:56:35 +01:00
committed by GitHub
parent 1c3bd4d252
commit 8177821e8b
48 changed files with 1041 additions and 1173 deletions

View File

@ -43,18 +43,18 @@ public class SecretsManagerSubscriptionUpdate
/// The seats the organization will have after the update, excluding the base seats included in the plan
/// Usually this is what the organization is billed for
/// </summary>
public int SmSeatsExcludingBase => SmSeats.HasValue ? SmSeats.Value - Plan.BaseSeats : 0;
public int SmSeatsExcludingBase => SmSeats.HasValue ? SmSeats.Value - Plan.SecretsManager.BaseSeats : 0;
/// <summary>
/// The seats the organization will have after the update, excluding the base seats included in the plan
/// Usually this is what the organization is billed for
/// </summary>
public int SmServiceAccountsExcludingBase => SmServiceAccounts.HasValue ? SmServiceAccounts.Value - Plan.BaseServiceAccount.GetValueOrDefault() : 0;
public int SmServiceAccountsExcludingBase => SmServiceAccounts.HasValue ? SmServiceAccounts.Value - Plan.SecretsManager!.BaseServiceAccount : 0;
public bool SmSeatsChanged => SmSeats != Organization.SmSeats;
public bool SmServiceAccountsChanged => SmServiceAccounts != Organization.SmServiceAccounts;
public bool MaxAutoscaleSmSeatsChanged => MaxAutoscaleSmSeats != Organization.MaxAutoscaleSmSeats;
public bool MaxAutoscaleSmServiceAccountsChanged =>
MaxAutoscaleSmServiceAccounts != Organization.MaxAutoscaleSmServiceAccounts;
public Plan Plan => Utilities.StaticStore.GetSecretsManagerPlan(Organization.PlanType);
public Plan Plan => Utilities.StaticStore.GetPlan(Organization.PlanType);
public bool SmSeatAutoscaleLimitReached => SmSeats.HasValue && MaxAutoscaleSmSeats.HasValue && SmSeats == MaxAutoscaleSmSeats;
public bool SmServiceAccountAutoscaleLimitReached => SmServiceAccounts.HasValue &&
@ -70,7 +70,7 @@ public class SecretsManagerSubscriptionUpdate
Organization = organization;
if (Plan == null)
if (!Plan.SupportsSecretsManager)
{
throw new NotFoundException("Invalid Secrets Manager plan.");
}

View File

@ -1,12 +1,12 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Stripe;
using Plan = Bit.Core.Models.StaticStore.Plan;
namespace Bit.Core.Models.Business;
public class OrganizationSubscriptionOptionsBase : Stripe.SubscriptionCreateOptions
{
public OrganizationSubscriptionOptionsBase(Organization org, List<StaticStore.Plan> plans, TaxInfo taxInfo, int additionalSeats,
public OrganizationSubscriptionOptionsBase(Organization org, StaticStore.Plan plan, TaxInfo taxInfo, int additionalSeats,
int additionalStorageGb, bool premiumAccessAddon, int additionalSmSeats, int additionalServiceAccounts)
{
Items = new List<SubscriptionItemOptions>();
@ -14,79 +14,80 @@ public class OrganizationSubscriptionOptionsBase : Stripe.SubscriptionCreateOpti
{
[org.GatewayIdField()] = org.Id.ToString()
};
foreach (var plan in plans)
{
AddPlanIdToSubscription(plan);
switch (plan.BitwardenProduct)
{
case BitwardenProductType.PasswordManager:
{
AddPremiumAccessAddon(premiumAccessAddon, plan);
AddAdditionalSeatToSubscription(additionalSeats, plan);
AddAdditionalStorage(additionalStorageGb, plan);
break;
}
case BitwardenProductType.SecretsManager:
{
AddAdditionalSeatToSubscription(additionalSmSeats, plan);
AddServiceAccount(additionalServiceAccounts, plan);
break;
}
}
AddPlanIdToSubscription(plan);
if (org.UseSecretsManager)
{
AddSecretsManagerSeat(plan, additionalSmSeats);
AddServiceAccount(plan, additionalServiceAccounts);
}
AddPremiumAccessAddon(plan, premiumAccessAddon);
AddPasswordManagerSeat(plan, additionalSeats);
AddAdditionalStorage(plan, additionalStorageGb);
if (!string.IsNullOrWhiteSpace(taxInfo?.StripeTaxRateId))
{
DefaultTaxRates = new List<string> { taxInfo.StripeTaxRateId };
}
}
private void AddServiceAccount(int additionalServiceAccounts, StaticStore.Plan plan)
private void AddSecretsManagerSeat(Plan plan, int additionalSmSeats)
{
if (additionalServiceAccounts > 0 && plan.StripeServiceAccountPlanId != null)
if (additionalSmSeats > 0 && plan.SecretsManager.StripeSeatPlanId != null)
{
Items.Add(new SubscriptionItemOptions
{ Plan = plan.SecretsManager.StripeSeatPlanId, Quantity = additionalSmSeats });
}
}
private void AddPasswordManagerSeat(Plan plan, int additionalSeats)
{
if (additionalSeats > 0 && plan.PasswordManager.StripeSeatPlanId != null)
{
Items.Add(new SubscriptionItemOptions
{ Plan = plan.PasswordManager.StripeSeatPlanId, Quantity = additionalSeats });
}
}
private void AddServiceAccount(StaticStore.Plan plan, int additionalServiceAccounts)
{
if (additionalServiceAccounts > 0 && plan.SecretsManager.StripeServiceAccountPlanId != null)
{
Items.Add(new SubscriptionItemOptions
{
Plan = plan.StripeServiceAccountPlanId,
Plan = plan.SecretsManager.StripeServiceAccountPlanId,
Quantity = additionalServiceAccounts
});
}
}
private void AddAdditionalStorage(int additionalStorageGb, StaticStore.Plan plan)
private void AddAdditionalStorage(StaticStore.Plan plan, int additionalStorageGb)
{
if (additionalStorageGb > 0)
{
Items.Add(new SubscriptionItemOptions
{
Plan = plan.StripeStoragePlanId,
Plan = plan.PasswordManager.StripeStoragePlanId,
Quantity = additionalStorageGb
});
}
}
private void AddPremiumAccessAddon(bool premiumAccessAddon, StaticStore.Plan plan)
private void AddPremiumAccessAddon(StaticStore.Plan plan, bool premiumAccessAddon)
{
if (premiumAccessAddon && plan.StripePremiumAccessPlanId != null)
if (premiumAccessAddon && plan.PasswordManager.StripePremiumAccessPlanId != null)
{
Items.Add(new SubscriptionItemOptions { Plan = plan.StripePremiumAccessPlanId, Quantity = 1 });
}
}
private void AddAdditionalSeatToSubscription(int additionalSeats, StaticStore.Plan plan)
{
if (additionalSeats > 0 && plan.StripeSeatPlanId != null)
{
Items.Add(new SubscriptionItemOptions { Plan = plan.StripeSeatPlanId, Quantity = additionalSeats });
Items.Add(new SubscriptionItemOptions { Plan = plan.PasswordManager.StripePremiumAccessPlanId, Quantity = 1 });
}
}
private void AddPlanIdToSubscription(StaticStore.Plan plan)
{
if (plan.StripePlanId != null)
if (plan.PasswordManager.StripePlanId != null)
{
Items.Add(new SubscriptionItemOptions { Plan = plan.StripePlanId, Quantity = 1 });
Items.Add(new SubscriptionItemOptions { Plan = plan.PasswordManager.StripePlanId, Quantity = 1 });
}
}
}
@ -94,14 +95,14 @@ public class OrganizationSubscriptionOptionsBase : Stripe.SubscriptionCreateOpti
public class OrganizationPurchaseSubscriptionOptions : OrganizationSubscriptionOptionsBase
{
public OrganizationPurchaseSubscriptionOptions(
Organization org, List<StaticStore.Plan> plans,
Organization org, StaticStore.Plan plan,
TaxInfo taxInfo, int additionalSeats,
int additionalStorageGb, bool premiumAccessAddon,
int additionalSmSeats, int additionalServiceAccounts) :
base(org, plans, taxInfo, additionalSeats, additionalStorageGb, premiumAccessAddon, additionalSmSeats, additionalServiceAccounts)
base(org, plan, taxInfo, additionalSeats, additionalStorageGb, premiumAccessAddon, additionalSmSeats, additionalServiceAccounts)
{
OffSession = true;
TrialPeriodDays = plans.FirstOrDefault(x => x.BitwardenProduct == BitwardenProductType.PasswordManager)!.TrialPeriodDays;
TrialPeriodDays = plan.TrialPeriodDays;
}
}
@ -109,8 +110,8 @@ public class OrganizationUpgradeSubscriptionOptions : OrganizationSubscriptionOp
{
public OrganizationUpgradeSubscriptionOptions(
string customerId, Organization org,
List<StaticStore.Plan> plans, OrganizationUpgrade upgrade) :
base(org, plans, upgrade.TaxInfo, upgrade.AdditionalSeats, upgrade.AdditionalStorageGb,
StaticStore.Plan plan, OrganizationUpgrade upgrade) :
base(org, plan, upgrade.TaxInfo, upgrade.AdditionalSeats, upgrade.AdditionalStorageGb,
upgrade.PremiumAccessAddon, upgrade.AdditionalSmSeats.GetValueOrDefault(),
upgrade.AdditionalServiceAccounts.GetValueOrDefault())
{

View File

@ -1,5 +1,4 @@
using Bit.Core.Enums;
using Stripe;
using Stripe;
namespace Bit.Core.Models.Business;
@ -64,16 +63,12 @@ public class SubscriptionInfo
Interval = item.Plan.Interval;
AddonSubscriptionItem =
Utilities.StaticStore.IsAddonSubscriptionItem(item.Plan.Id);
BitwardenProduct =
Utilities.StaticStore.GetPlanByStripeId(item.Plan.Id)?.BitwardenProduct ?? BitwardenProductType.PasswordManager;
}
Quantity = (int)item.Quantity;
SponsoredSubscriptionItem = Utilities.StaticStore.SponsoredPlans.Any(p => p.StripePlanId == item.Plan.Id);
}
public BitwardenProductType BitwardenProduct { get; set; }
public bool AddonSubscriptionItem { get; set; }
public string Name { get; set; }

View File

@ -1,5 +1,4 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Stripe;
namespace Bit.Core.Models.Business;
@ -30,29 +29,23 @@ public abstract class SubscriptionUpdate
planId == null ? null : subscription.Items?.Data?.FirstOrDefault(i => i.Plan.Id == planId);
}
public class SeatSubscriptionUpdate : SubscriptionUpdate
public abstract class BaseSeatSubscriptionUpdate : SubscriptionUpdate
{
private readonly int _previousSeats;
private readonly StaticStore.Plan _plan;
protected readonly StaticStore.Plan Plan;
private readonly long? _additionalSeats;
protected override List<string> PlanIds => new() { _plan.StripeSeatPlanId };
public SeatSubscriptionUpdate(Organization organization, StaticStore.Plan plan, long? additionalSeats)
protected BaseSeatSubscriptionUpdate(Organization organization, StaticStore.Plan plan, long? additionalSeats, int previousSeats)
{
_plan = plan;
Plan = plan;
_additionalSeats = additionalSeats;
switch (plan.BitwardenProduct)
{
case BitwardenProductType.PasswordManager:
_previousSeats = organization.Seats.GetValueOrDefault();
break;
case BitwardenProductType.SecretsManager:
_previousSeats = organization.SmSeats.GetValueOrDefault();
break;
}
_previousSeats = previousSeats;
}
protected abstract string GetPlanId();
protected override List<string> PlanIds => new() { GetPlanId() };
public override List<SubscriptionItemOptions> UpgradeItemsOptions(Subscription subscription)
{
var item = SubscriptionItem(subscription, PlanIds.Single());
@ -85,12 +78,30 @@ public class SeatSubscriptionUpdate : SubscriptionUpdate
}
}
public class SeatSubscriptionUpdate : BaseSeatSubscriptionUpdate
{
public SeatSubscriptionUpdate(Organization organization, StaticStore.Plan plan, long? additionalSeats)
: base(organization, plan, additionalSeats, organization.Seats.GetValueOrDefault())
{ }
protected override string GetPlanId() => Plan.PasswordManager.StripeSeatPlanId;
}
public class SmSeatSubscriptionUpdate : BaseSeatSubscriptionUpdate
{
public SmSeatSubscriptionUpdate(Organization organization, StaticStore.Plan plan, long? additionalSeats)
: base(organization, plan, additionalSeats, organization.SmSeats.GetValueOrDefault())
{ }
protected override string GetPlanId() => Plan.SecretsManager.StripeSeatPlanId;
}
public class ServiceAccountSubscriptionUpdate : SubscriptionUpdate
{
private long? _prevServiceAccounts;
private readonly StaticStore.Plan _plan;
private readonly long? _additionalServiceAccounts;
protected override List<string> PlanIds => new() { _plan.StripeServiceAccountPlanId };
protected override List<string> PlanIds => new() { _plan.SecretsManager.StripeServiceAccountPlanId };
public ServiceAccountSubscriptionUpdate(Organization organization, StaticStore.Plan plan, long? additionalServiceAccounts)
{
@ -190,7 +201,7 @@ public class SponsorOrganizationSubscriptionUpdate : SubscriptionUpdate
public SponsorOrganizationSubscriptionUpdate(StaticStore.Plan existingPlan, StaticStore.SponsoredPlan sponsoredPlan, bool applySponsorship)
{
_existingPlanStripeId = existingPlan.StripePlanId;
_existingPlanStripeId = existingPlan.PasswordManager.StripePlanId;
_sponsoredPlanStripeId = sponsoredPlan?.StripePlanId;
_applySponsorship = applySponsorship;
}
@ -269,7 +280,7 @@ public class SecretsManagerSubscribeUpdate : SubscriptionUpdate
private readonly long? _additionalServiceAccounts;
private readonly int _previousSeats;
private readonly int _previousServiceAccounts;
protected override List<string> PlanIds => new() { _plan.StripeSeatPlanId, _plan.StripeServiceAccountPlanId };
protected override List<string> PlanIds => new() { _plan.SecretsManager.StripeSeatPlanId, _plan.SecretsManager.StripeServiceAccountPlanId };
public SecretsManagerSubscribeUpdate(Organization organization, StaticStore.Plan plan, long? additionalSeats, long? additionalServiceAccounts)
{
_plan = plan;
@ -303,7 +314,7 @@ public class SecretsManagerSubscribeUpdate : SubscriptionUpdate
{
updatedItems.Add(new SubscriptionItemOptions
{
Price = _plan.StripeSeatPlanId,
Price = _plan.SecretsManager.StripeSeatPlanId,
Quantity = _additionalSeats
});
}
@ -312,7 +323,7 @@ public class SecretsManagerSubscribeUpdate : SubscriptionUpdate
{
updatedItems.Add(new SubscriptionItemOptions
{
Price = _plan.StripeServiceAccountPlanId,
Price = _plan.SecretsManager.StripeServiceAccountPlanId,
Quantity = _additionalServiceAccounts
});
}
@ -322,14 +333,14 @@ public class SecretsManagerSubscribeUpdate : SubscriptionUpdate
{
updatedItems.Add(new SubscriptionItemOptions
{
Price = _plan.StripeSeatPlanId,
Price = _plan.SecretsManager.StripeSeatPlanId,
Quantity = _previousSeats,
Deleted = _previousSeats == 0 ? true : (bool?)null,
});
updatedItems.Add(new SubscriptionItemOptions
{
Price = _plan.StripeServiceAccountPlanId,
Price = _plan.SecretsManager.StripeServiceAccountPlanId,
Quantity = _previousServiceAccounts,
Deleted = _previousServiceAccounts == 0 ? true : (bool?)null,
});