mirror of
https://github.com/bitwarden/server.git
synced 2024-11-21 12:05:42 +01: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:
parent
1c3bd4d252
commit
8177821e8b
@ -28,8 +28,8 @@ public class MaxProjectsQuery : IMaxProjectsQuery
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var plan = StaticStore.GetSecretsManagerPlan(org.PlanType);
|
||||
if (plan == null)
|
||||
var plan = StaticStore.GetPlan(org.PlanType);
|
||||
if (plan?.SecretsManager == null)
|
||||
{
|
||||
throw new BadRequestException("Existing plan not found.");
|
||||
}
|
||||
@ -37,7 +37,7 @@ public class MaxProjectsQuery : IMaxProjectsQuery
|
||||
if (plan.Type == PlanType.Free)
|
||||
{
|
||||
var projects = await _projectRepository.GetProjectCountByOrganizationIdAsync(organizationId);
|
||||
return projects + projectsToAdd > plan.MaxProjects ? (plan.MaxProjects, true) : (plan.MaxProjects, false);
|
||||
return ((short? max, bool? overMax))(projects + projectsToAdd > plan.SecretsManager.MaxProjects ? (plan.SecretsManager.MaxProjects, true) : (plan.SecretsManager.MaxProjects, false));
|
||||
}
|
||||
|
||||
return (null, null);
|
||||
|
@ -205,9 +205,8 @@ public class OrganizationsController : Controller
|
||||
var organization = await GetOrganization(id, model);
|
||||
|
||||
if (organization.UseSecretsManager &&
|
||||
!organization.SecretsManagerBeta
|
||||
&& StaticStore.GetSecretsManagerPlan(organization.PlanType) == null
|
||||
)
|
||||
!organization.SecretsManagerBeta &&
|
||||
!StaticStore.GetPlan(organization.PlanType).SupportsSecretsManager)
|
||||
{
|
||||
throw new BadRequestException("Plan does not support Secrets Manager");
|
||||
}
|
||||
|
@ -158,11 +158,12 @@ public class OrganizationEditModel : OrganizationViewModel
|
||||
* Add mappings for individual properties as you need them
|
||||
*/
|
||||
public IEnumerable<Dictionary<string, object>> GetPlansHelper() =>
|
||||
StaticStore.SecretManagerPlans.Select(p =>
|
||||
new Dictionary<string, object>
|
||||
StaticStore.Plans
|
||||
.Where(p => p.SupportsSecretsManager)
|
||||
.Select(p => new Dictionary<string, object>
|
||||
{
|
||||
{ "type", p.Type },
|
||||
{ "baseServiceAccount", p.BaseServiceAccount }
|
||||
{ "baseServiceAccount", p.SecretsManager.BaseServiceAccount }
|
||||
});
|
||||
|
||||
public Organization CreateOrganization(Provider provider)
|
||||
|
@ -540,7 +540,7 @@ public class OrganizationsController : Controller
|
||||
if (model.Type == OrganizationApiKeyType.BillingSync || model.Type == OrganizationApiKeyType.Scim)
|
||||
{
|
||||
// Non-enterprise orgs should not be able to create or view an apikey of billing sync/scim key types
|
||||
var plan = StaticStore.GetPasswordManagerPlan(organization.PlanType);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
if (plan.Product != ProductType.Enterprise)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
|
@ -19,30 +19,12 @@ public class PlansController : Controller
|
||||
[HttpGet("")]
|
||||
[AllowAnonymous]
|
||||
public ListResponseModel<PlanResponseModel> Get()
|
||||
{
|
||||
var data = StaticStore.PasswordManagerPlans;
|
||||
var responses = data.Select(plan => new PlanResponseModel(plan));
|
||||
return new ListResponseModel<PlanResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpGet("all")]
|
||||
[AllowAnonymous]
|
||||
public ListResponseModel<PlanResponseModel> GetAllPlans()
|
||||
{
|
||||
var data = StaticStore.Plans;
|
||||
var responses = data.Select(plan => new PlanResponseModel(plan));
|
||||
return new ListResponseModel<PlanResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpGet("sm-plans")]
|
||||
[AllowAnonymous]
|
||||
public ListResponseModel<PlanResponseModel> GetSecretsManagerPlans()
|
||||
{
|
||||
var data = StaticStore.SecretManagerPlans;
|
||||
var responses = data.Select(plan => new PlanResponseModel(plan));
|
||||
return new ListResponseModel<PlanResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpGet("sales-tax-rates")]
|
||||
public async Task<ListResponseModel<TaxRateResponseModel>> GetTaxRates()
|
||||
{
|
||||
|
@ -26,12 +26,7 @@ public class OrganizationResponseModel : ResponseModel
|
||||
BusinessCountry = organization.BusinessCountry;
|
||||
BusinessTaxNumber = organization.BusinessTaxNumber;
|
||||
BillingEmail = organization.BillingEmail;
|
||||
Plan = new PlanResponseModel(StaticStore.PasswordManagerPlans.FirstOrDefault(plan => plan.Type == organization.PlanType));
|
||||
var matchingPlan = StaticStore.GetSecretsManagerPlan(organization.PlanType);
|
||||
if (matchingPlan != null)
|
||||
{
|
||||
SecretsManagerPlan = new PlanResponseModel(matchingPlan);
|
||||
}
|
||||
Plan = new PlanResponseModel(StaticStore.GetPlan(organization.PlanType));
|
||||
PlanType = organization.PlanType;
|
||||
Seats = organization.Seats;
|
||||
MaxAutoscaleSeats = organization.MaxAutoscaleSeats;
|
||||
|
@ -21,15 +21,6 @@ public class PlanResponseModel : ResponseModel
|
||||
NameLocalizationKey = plan.NameLocalizationKey;
|
||||
DescriptionLocalizationKey = plan.DescriptionLocalizationKey;
|
||||
CanBeUsedByBusiness = plan.CanBeUsedByBusiness;
|
||||
BaseSeats = plan.BaseSeats;
|
||||
BaseStorageGb = plan.BaseStorageGb;
|
||||
MaxCollections = plan.MaxCollections;
|
||||
MaxUsers = plan.MaxUsers;
|
||||
HasAdditionalSeatsOption = plan.HasAdditionalSeatsOption;
|
||||
HasAdditionalStorageOption = plan.HasAdditionalStorageOption;
|
||||
MaxAdditionalSeats = plan.MaxAdditionalSeats;
|
||||
MaxAdditionalStorage = plan.MaxAdditionalStorage;
|
||||
HasPremiumAccessOption = plan.HasPremiumAccessOption;
|
||||
TrialPeriodDays = plan.TrialPeriodDays;
|
||||
HasSelfHost = plan.HasSelfHost;
|
||||
HasPolicies = plan.HasPolicies;
|
||||
@ -45,22 +36,12 @@ public class PlanResponseModel : ResponseModel
|
||||
DisplaySortOrder = plan.DisplaySortOrder;
|
||||
LegacyYear = plan.LegacyYear;
|
||||
Disabled = plan.Disabled;
|
||||
StripePlanId = plan.StripePlanId;
|
||||
StripeSeatPlanId = plan.StripeSeatPlanId;
|
||||
StripeStoragePlanId = plan.StripeStoragePlanId;
|
||||
BasePrice = plan.BasePrice;
|
||||
SeatPrice = plan.SeatPrice;
|
||||
AdditionalStoragePricePerGb = plan.AdditionalStoragePricePerGb;
|
||||
PremiumAccessOptionPrice = plan.PremiumAccessOptionPrice;
|
||||
if (plan.SecretsManager != null)
|
||||
{
|
||||
SecretsManager = new SecretsManagerPlanFeaturesResponseModel(plan.SecretsManager);
|
||||
}
|
||||
|
||||
AdditionalPricePerServiceAccount = plan.AdditionalPricePerServiceAccount;
|
||||
BaseServiceAccount = plan.BaseServiceAccount;
|
||||
MaxServiceAccounts = plan.MaxServiceAccounts;
|
||||
MaxAdditionalServiceAccounts = plan.MaxAdditionalServiceAccount;
|
||||
HasAdditionalServiceAccountOption = plan.HasAdditionalServiceAccountOption;
|
||||
MaxProjects = plan.MaxProjects;
|
||||
BitwardenProduct = plan.BitwardenProduct;
|
||||
StripeServiceAccountPlanId = plan.StripeServiceAccountPlanId;
|
||||
PasswordManager = new PasswordManagerPlanFeaturesResponseModel(plan.PasswordManager);
|
||||
}
|
||||
|
||||
public PlanType Type { get; set; }
|
||||
@ -70,16 +51,6 @@ public class PlanResponseModel : ResponseModel
|
||||
public string NameLocalizationKey { get; set; }
|
||||
public string DescriptionLocalizationKey { get; set; }
|
||||
public bool CanBeUsedByBusiness { get; set; }
|
||||
public int BaseSeats { get; set; }
|
||||
public short? BaseStorageGb { get; set; }
|
||||
public short? MaxCollections { get; set; }
|
||||
public short? MaxUsers { get; set; }
|
||||
|
||||
public bool HasAdditionalSeatsOption { get; set; }
|
||||
public int? MaxAdditionalSeats { get; set; }
|
||||
public bool HasAdditionalStorageOption { get; set; }
|
||||
public short? MaxAdditionalStorage { get; set; }
|
||||
public bool HasPremiumAccessOption { get; set; }
|
||||
public int? TrialPeriodDays { get; set; }
|
||||
|
||||
public bool HasSelfHost { get; set; }
|
||||
@ -98,21 +69,95 @@ public class PlanResponseModel : ResponseModel
|
||||
public int DisplaySortOrder { get; set; }
|
||||
public int? LegacyYear { get; set; }
|
||||
public bool Disabled { get; set; }
|
||||
public SecretsManagerPlanFeaturesResponseModel SecretsManager { get; protected init; }
|
||||
public PasswordManagerPlanFeaturesResponseModel PasswordManager { get; protected init; }
|
||||
|
||||
public string StripePlanId { get; set; }
|
||||
public string StripeSeatPlanId { get; set; }
|
||||
public string StripeStoragePlanId { get; set; }
|
||||
public string StripePremiumAccessPlanId { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public decimal SeatPrice { get; set; }
|
||||
public decimal AdditionalStoragePricePerGb { get; set; }
|
||||
public decimal PremiumAccessOptionPrice { get; set; }
|
||||
public string StripeServiceAccountPlanId { get; set; }
|
||||
public decimal? AdditionalPricePerServiceAccount { get; set; }
|
||||
public short? BaseServiceAccount { get; set; }
|
||||
public short? MaxServiceAccounts { get; set; }
|
||||
public short? MaxAdditionalServiceAccounts { get; set; }
|
||||
public bool HasAdditionalServiceAccountOption { get; set; }
|
||||
public short? MaxProjects { get; set; }
|
||||
public BitwardenProductType BitwardenProduct { get; set; }
|
||||
public class SecretsManagerPlanFeaturesResponseModel
|
||||
{
|
||||
public SecretsManagerPlanFeaturesResponseModel(Plan.SecretsManagerPlanFeatures plan)
|
||||
{
|
||||
MaxServiceAccounts = plan.MaxServiceAccounts;
|
||||
AllowServiceAccountsAutoscale = plan is { AllowServiceAccountsAutoscale: true };
|
||||
StripeServiceAccountPlanId = plan.StripeServiceAccountPlanId;
|
||||
AdditionalPricePerServiceAccount = plan.AdditionalPricePerServiceAccount;
|
||||
BaseServiceAccount = plan.BaseServiceAccount;
|
||||
MaxAdditionalServiceAccount = plan.MaxAdditionalServiceAccount;
|
||||
HasAdditionalServiceAccountOption = plan is { HasAdditionalServiceAccountOption: true };
|
||||
StripeSeatPlanId = plan.StripeSeatPlanId;
|
||||
HasAdditionalSeatsOption = plan is { HasAdditionalSeatsOption: true };
|
||||
BasePrice = plan.BasePrice;
|
||||
SeatPrice = plan.SeatPrice;
|
||||
BaseSeats = plan.BaseSeats;
|
||||
MaxSeats = plan.MaxSeats;
|
||||
MaxAdditionalSeats = plan.MaxAdditionalSeats;
|
||||
AllowSeatAutoscale = plan.AllowSeatAutoscale;
|
||||
MaxProjects = plan.MaxProjects;
|
||||
}
|
||||
// Service accounts
|
||||
public short? MaxServiceAccounts { get; init; }
|
||||
public bool AllowServiceAccountsAutoscale { get; init; }
|
||||
public string StripeServiceAccountPlanId { get; init; }
|
||||
public decimal? AdditionalPricePerServiceAccount { get; init; }
|
||||
public short? BaseServiceAccount { get; init; }
|
||||
public short? MaxAdditionalServiceAccount { get; init; }
|
||||
public bool HasAdditionalServiceAccountOption { get; init; }
|
||||
// Seats
|
||||
public string StripeSeatPlanId { get; init; }
|
||||
public bool HasAdditionalSeatsOption { get; init; }
|
||||
public decimal BasePrice { get; init; }
|
||||
public decimal SeatPrice { get; init; }
|
||||
public int BaseSeats { get; init; }
|
||||
public short? MaxSeats { get; init; }
|
||||
public int? MaxAdditionalSeats { get; init; }
|
||||
public bool AllowSeatAutoscale { get; init; }
|
||||
|
||||
// Features
|
||||
public int MaxProjects { get; init; }
|
||||
}
|
||||
|
||||
public record PasswordManagerPlanFeaturesResponseModel
|
||||
{
|
||||
public PasswordManagerPlanFeaturesResponseModel(Plan.PasswordManagerPlanFeatures plan)
|
||||
{
|
||||
StripePlanId = plan.StripePlanId;
|
||||
StripeSeatPlanId = plan.StripeSeatPlanId;
|
||||
BasePrice = plan.BasePrice;
|
||||
SeatPrice = plan.SeatPrice;
|
||||
AllowSeatAutoscale = plan.AllowSeatAutoscale;
|
||||
HasAdditionalSeatsOption = plan.HasAdditionalSeatsOption;
|
||||
MaxAdditionalSeats = plan.MaxAdditionalSeats;
|
||||
BaseSeats = plan.BaseSeats;
|
||||
HasPremiumAccessOption = plan.HasPremiumAccessOption;
|
||||
StripePremiumAccessPlanId = plan.StripePremiumAccessPlanId;
|
||||
PremiumAccessOptionPrice = plan.PremiumAccessOptionPrice;
|
||||
MaxSeats = plan.MaxSeats;
|
||||
BaseStorageGb = plan.BaseStorageGb;
|
||||
HasAdditionalStorageOption = plan.HasAdditionalStorageOption;
|
||||
AdditionalStoragePricePerGb = plan.AdditionalStoragePricePerGb;
|
||||
StripeStoragePlanId = plan.StripeStoragePlanId;
|
||||
MaxAdditionalStorage = plan.MaxAdditionalStorage;
|
||||
MaxCollections = plan.MaxCollections;
|
||||
}
|
||||
// Seats
|
||||
public string StripePlanId { get; init; }
|
||||
public string StripeSeatPlanId { get; init; }
|
||||
public decimal BasePrice { get; init; }
|
||||
public decimal SeatPrice { get; init; }
|
||||
public bool AllowSeatAutoscale { get; init; }
|
||||
public bool HasAdditionalSeatsOption { get; init; }
|
||||
public int? MaxAdditionalSeats { get; init; }
|
||||
public int BaseSeats { get; init; }
|
||||
public bool HasPremiumAccessOption { get; init; }
|
||||
public string StripePremiumAccessPlanId { get; init; }
|
||||
public decimal PremiumAccessOptionPrice { get; init; }
|
||||
public short? MaxSeats { get; init; }
|
||||
// Storage
|
||||
public short? BaseStorageGb { get; init; }
|
||||
public bool HasAdditionalStorageOption { get; init; }
|
||||
public decimal AdditionalStoragePricePerGb { get; init; }
|
||||
public string StripeStoragePlanId { get; init; }
|
||||
public short? MaxAdditionalStorage { get; init; }
|
||||
// Feature
|
||||
public short? MaxCollections { get; init; }
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class ProfileOrganizationResponseModel : ResponseModel
|
||||
FamilySponsorshipAvailable = FamilySponsorshipFriendlyName == null &&
|
||||
StaticStore.GetSponsoredPlan(PlanSponsorshipType.FamiliesForEnterprise)
|
||||
.UsersCanSponsor(organization);
|
||||
PlanProductType = StaticStore.GetPasswordManagerPlan(organization.PlanType).Product;
|
||||
PlanProductType = StaticStore.GetPlan(organization.PlanType).Product;
|
||||
FamilySponsorshipLastSyncDate = organization.FamilySponsorshipLastSyncDate;
|
||||
FamilySponsorshipToDelete = organization.FamilySponsorshipToDelete;
|
||||
FamilySponsorshipValidUntil = organization.FamilySponsorshipValidUntil;
|
||||
|
@ -42,6 +42,6 @@ public class ProfileProviderOrganizationResponseModel : ProfileOrganizationRespo
|
||||
UserId = organization.UserId;
|
||||
ProviderId = organization.ProviderId;
|
||||
ProviderName = organization.ProviderName;
|
||||
PlanProductType = StaticStore.GetPasswordManagerPlan(organization.PlanType).Product;
|
||||
PlanProductType = StaticStore.GetPlan(organization.PlanType).Product;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Utilities;
|
||||
@ -98,7 +97,6 @@ public class BillingSubscription
|
||||
Quantity = item.Quantity;
|
||||
SponsoredSubscriptionItem = item.SponsoredSubscriptionItem;
|
||||
AddonSubscriptionItem = item.AddonSubscriptionItem;
|
||||
BitwardenProduct = item.BitwardenProduct;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
@ -107,7 +105,6 @@ public class BillingSubscription
|
||||
public string Interval { get; set; }
|
||||
public bool SponsoredSubscriptionItem { get; set; }
|
||||
public bool AddonSubscriptionItem { get; set; }
|
||||
public BitwardenProductType BitwardenProduct { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,7 +447,7 @@ public class StripeController : Controller
|
||||
// org
|
||||
if (ids.Item1.HasValue)
|
||||
{
|
||||
if (subscription.Items.Any(i => StaticStore.PasswordManagerPlans.Any(p => p.StripePlanId == i.Plan.Id)))
|
||||
if (subscription.Items.Any(i => StaticStore.Plans.Any(p => p.PasswordManager.StripePlanId == i.Plan.Id)))
|
||||
{
|
||||
await _organizationService.EnableAsync(ids.Item1.Value, subscription.CurrentPeriodEnd);
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Core.Enums;
|
||||
|
||||
public enum BitwardenProductType : byte
|
||||
{
|
||||
[Display(Name = "Password Manager")]
|
||||
PasswordManager = 0,
|
||||
[Display(Name = "Secrets Manager")]
|
||||
SecretsManager = 1,
|
||||
}
|
@ -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.");
|
||||
}
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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; }
|
||||
|
@ -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,
|
||||
});
|
||||
|
@ -2,64 +2,84 @@
|
||||
|
||||
namespace Bit.Core.Models.StaticStore;
|
||||
|
||||
public class Plan
|
||||
public abstract record Plan
|
||||
{
|
||||
public PlanType Type { get; set; }
|
||||
public ProductType Product { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool IsAnnual { get; set; }
|
||||
public string NameLocalizationKey { get; set; }
|
||||
public string DescriptionLocalizationKey { get; set; }
|
||||
public bool CanBeUsedByBusiness { get; set; }
|
||||
public int BaseSeats { get; set; }
|
||||
public short? BaseStorageGb { get; set; }
|
||||
public short? MaxCollections { get; set; }
|
||||
public short? MaxUsers { get; set; }
|
||||
public short? MaxServiceAccounts { get; set; }
|
||||
public bool AllowSeatAutoscale { get; set; }
|
||||
public PlanType Type { get; protected init; }
|
||||
public ProductType Product { get; protected init; }
|
||||
public string Name { get; protected init; }
|
||||
public bool IsAnnual { get; protected init; }
|
||||
public string NameLocalizationKey { get; protected init; }
|
||||
public string DescriptionLocalizationKey { get; protected init; }
|
||||
public bool CanBeUsedByBusiness { get; protected init; }
|
||||
public int? TrialPeriodDays { get; protected init; }
|
||||
public bool HasSelfHost { get; protected init; }
|
||||
public bool HasPolicies { get; protected init; }
|
||||
public bool HasGroups { get; protected init; }
|
||||
public bool HasDirectory { get; protected init; }
|
||||
public bool HasEvents { get; protected init; }
|
||||
public bool HasTotp { get; protected init; }
|
||||
public bool Has2fa { get; protected init; }
|
||||
public bool HasApi { get; protected init; }
|
||||
public bool HasSso { get; protected init; }
|
||||
public bool HasKeyConnector { get; protected init; }
|
||||
public bool HasScim { get; protected init; }
|
||||
public bool HasResetPassword { get; protected init; }
|
||||
public bool UsersGetPremium { get; protected init; }
|
||||
public bool HasCustomPermissions { get; protected init; }
|
||||
public int UpgradeSortOrder { get; protected init; }
|
||||
public int DisplaySortOrder { get; protected init; }
|
||||
public int? LegacyYear { get; protected init; }
|
||||
public bool Disabled { get; protected init; }
|
||||
public PasswordManagerPlanFeatures PasswordManager { get; protected init; }
|
||||
public SecretsManagerPlanFeatures SecretsManager { get; protected init; }
|
||||
public bool SupportsSecretsManager => SecretsManager != null;
|
||||
|
||||
public bool AllowServiceAccountsAutoscale { get; set; }
|
||||
public record SecretsManagerPlanFeatures
|
||||
{
|
||||
// Service accounts
|
||||
public short? MaxServiceAccounts { get; init; }
|
||||
public bool AllowServiceAccountsAutoscale { get; init; }
|
||||
public string StripeServiceAccountPlanId { get; init; }
|
||||
public decimal? AdditionalPricePerServiceAccount { get; init; }
|
||||
public short BaseServiceAccount { get; init; }
|
||||
public short? MaxAdditionalServiceAccount { get; init; }
|
||||
public bool HasAdditionalServiceAccountOption { get; init; }
|
||||
// Seats
|
||||
public string StripeSeatPlanId { get; init; }
|
||||
public bool HasAdditionalSeatsOption { get; init; }
|
||||
public decimal BasePrice { get; init; }
|
||||
public decimal SeatPrice { get; init; }
|
||||
public int BaseSeats { get; init; }
|
||||
public short? MaxSeats { get; init; }
|
||||
public int? MaxAdditionalSeats { get; init; }
|
||||
public bool AllowSeatAutoscale { get; init; }
|
||||
|
||||
public bool HasAdditionalSeatsOption { get; set; }
|
||||
public int? MaxAdditionalSeats { get; set; }
|
||||
public bool HasAdditionalStorageOption { get; set; }
|
||||
public short? MaxAdditionalStorage { get; set; }
|
||||
public bool HasPremiumAccessOption { get; set; }
|
||||
public int? TrialPeriodDays { get; set; }
|
||||
// Features
|
||||
public int MaxProjects { get; init; }
|
||||
}
|
||||
|
||||
public bool HasSelfHost { get; set; }
|
||||
public bool HasPolicies { get; set; }
|
||||
public bool HasGroups { get; set; }
|
||||
public bool HasDirectory { get; set; }
|
||||
public bool HasEvents { get; set; }
|
||||
public bool HasTotp { get; set; }
|
||||
public bool Has2fa { get; set; }
|
||||
public bool HasApi { get; set; }
|
||||
public bool HasSso { get; set; }
|
||||
public bool HasKeyConnector { get; set; }
|
||||
public bool HasScim { get; set; }
|
||||
public bool HasResetPassword { get; set; }
|
||||
public bool UsersGetPremium { get; set; }
|
||||
public bool HasCustomPermissions { get; set; }
|
||||
|
||||
public int UpgradeSortOrder { get; set; }
|
||||
public int DisplaySortOrder { get; set; }
|
||||
public int? LegacyYear { get; set; }
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
public string StripePlanId { get; set; }
|
||||
public string StripeSeatPlanId { get; set; }
|
||||
public string StripeStoragePlanId { get; set; }
|
||||
public string StripeServiceAccountPlanId { get; set; }
|
||||
public string StripePremiumAccessPlanId { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public decimal SeatPrice { get; set; }
|
||||
public decimal AdditionalStoragePricePerGb { get; set; }
|
||||
public decimal PremiumAccessOptionPrice { get; set; }
|
||||
public decimal? AdditionalPricePerServiceAccount { get; set; }
|
||||
public short? BaseServiceAccount { get; set; }
|
||||
public short? MaxAdditionalServiceAccount { get; set; }
|
||||
public bool HasAdditionalServiceAccountOption { get; set; }
|
||||
public short? MaxProjects { get; set; }
|
||||
public BitwardenProductType BitwardenProduct { get; set; }
|
||||
public record PasswordManagerPlanFeatures
|
||||
{
|
||||
// Seats
|
||||
public string StripePlanId { get; init; }
|
||||
public string StripeSeatPlanId { get; init; }
|
||||
public decimal BasePrice { get; init; }
|
||||
public decimal SeatPrice { get; init; }
|
||||
public bool AllowSeatAutoscale { get; init; }
|
||||
public bool HasAdditionalSeatsOption { get; init; }
|
||||
public int? MaxAdditionalSeats { get; init; }
|
||||
public int BaseSeats { get; init; }
|
||||
public bool HasPremiumAccessOption { get; init; }
|
||||
public string StripePremiumAccessPlanId { get; init; }
|
||||
public decimal PremiumAccessOptionPrice { get; init; }
|
||||
public short? MaxSeats { get; init; }
|
||||
// Storage
|
||||
public short? BaseStorageGb { get; init; }
|
||||
public bool HasAdditionalStorageOption { get; init; }
|
||||
public decimal AdditionalStoragePricePerGb { get; init; }
|
||||
public string StripeStoragePlanId { get; init; }
|
||||
public short? MaxAdditionalStorage { get; init; }
|
||||
// Feature
|
||||
public short? MaxCollections { get; init; }
|
||||
}
|
||||
}
|
||||
|
20
src/Core/Models/StaticStore/Plans/CustomPlan.cs
Normal file
20
src/Core/Models/StaticStore/Plans/CustomPlan.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record CustomPlan : Models.StaticStore.Plan
|
||||
{
|
||||
public CustomPlan()
|
||||
{
|
||||
Type = PlanType.Custom;
|
||||
PasswordManager = new CustomPasswordManagerFeatures();
|
||||
}
|
||||
|
||||
private record CustomPasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public CustomPasswordManagerFeatures()
|
||||
{
|
||||
AllowSeatAutoscale = true;
|
||||
}
|
||||
}
|
||||
}
|
65
src/Core/Models/StaticStore/Plans/Enterprise2019Plan.cs
Normal file
65
src/Core/Models/StaticStore/Plans/Enterprise2019Plan.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record Enterprise2019Plan : Models.StaticStore.Plan
|
||||
{
|
||||
public Enterprise2019Plan(bool isAnnual)
|
||||
{
|
||||
Type = isAnnual ? PlanType.EnterpriseAnnually2019 : PlanType.EnterpriseMonthly2019;
|
||||
Product = ProductType.Enterprise;
|
||||
Name = isAnnual ? "Enterprise (Annually) 2019" : "Enterprise (Monthly) 2019";
|
||||
IsAnnual = isAnnual;
|
||||
NameLocalizationKey = "planNameEnterprise";
|
||||
DescriptionLocalizationKey = "planDescEnterprise";
|
||||
CanBeUsedByBusiness = true;
|
||||
|
||||
TrialPeriodDays = 7;
|
||||
|
||||
HasPolicies = true;
|
||||
HasSelfHost = true;
|
||||
HasGroups = true;
|
||||
HasDirectory = true;
|
||||
HasEvents = true;
|
||||
HasTotp = true;
|
||||
Has2fa = true;
|
||||
HasApi = true;
|
||||
UsersGetPremium = true;
|
||||
HasCustomPermissions = true;
|
||||
|
||||
UpgradeSortOrder = 3;
|
||||
DisplaySortOrder = 3;
|
||||
LegacyYear = 2020;
|
||||
|
||||
PasswordManager = new Enterprise2019PasswordManagerFeatures(isAnnual);
|
||||
}
|
||||
|
||||
private record Enterprise2019PasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public Enterprise2019PasswordManagerFeatures(bool isAnnual)
|
||||
{
|
||||
BaseSeats = 0;
|
||||
BaseStorageGb = 1;
|
||||
|
||||
HasAdditionalStorageOption = true;
|
||||
HasAdditionalSeatsOption = true;
|
||||
|
||||
AllowSeatAutoscale = true;
|
||||
|
||||
if (isAnnual)
|
||||
{
|
||||
StripeStoragePlanId = "storage-gb-annually";
|
||||
StripeSeatPlanId = "enterprise-org-seat-annually";
|
||||
SeatPrice = 36;
|
||||
AdditionalStoragePricePerGb = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
StripeSeatPlanId = "enterprise-org-seat-monthly";
|
||||
StripeStoragePlanId = "storage-gb-monthly";
|
||||
SeatPrice = 4M;
|
||||
AdditionalStoragePricePerGb = 0.5M;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
100
src/Core/Models/StaticStore/Plans/EnterprisePlan.cs
Normal file
100
src/Core/Models/StaticStore/Plans/EnterprisePlan.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record EnterprisePlan : Models.StaticStore.Plan
|
||||
{
|
||||
public EnterprisePlan(bool isAnnual)
|
||||
{
|
||||
Type = isAnnual ? PlanType.EnterpriseAnnually : PlanType.EnterpriseMonthly;
|
||||
Product = ProductType.Enterprise;
|
||||
Name = isAnnual ? "Enterprise (Annually)" : "Enterprise (Monthly)";
|
||||
IsAnnual = isAnnual;
|
||||
NameLocalizationKey = "planNameEnterprise";
|
||||
DescriptionLocalizationKey = "planDescEnterprise";
|
||||
CanBeUsedByBusiness = true;
|
||||
|
||||
TrialPeriodDays = 7;
|
||||
|
||||
HasPolicies = true;
|
||||
HasSelfHost = true;
|
||||
HasGroups = true;
|
||||
HasDirectory = true;
|
||||
HasEvents = true;
|
||||
HasTotp = true;
|
||||
Has2fa = true;
|
||||
HasApi = true;
|
||||
HasSso = true;
|
||||
HasKeyConnector = true;
|
||||
HasScim = true;
|
||||
HasResetPassword = true;
|
||||
UsersGetPremium = true;
|
||||
HasCustomPermissions = true;
|
||||
|
||||
UpgradeSortOrder = 3;
|
||||
DisplaySortOrder = 3;
|
||||
|
||||
PasswordManager = new EnterprisePasswordManagerFeatures(isAnnual);
|
||||
SecretsManager = new EnterpriseSecretsManagerFeatures(isAnnual);
|
||||
}
|
||||
|
||||
private record EnterpriseSecretsManagerFeatures : SecretsManagerPlanFeatures
|
||||
{
|
||||
public EnterpriseSecretsManagerFeatures(bool isAnnual)
|
||||
{
|
||||
BaseSeats = 0;
|
||||
BasePrice = 0;
|
||||
BaseServiceAccount = 200;
|
||||
|
||||
HasAdditionalSeatsOption = true;
|
||||
HasAdditionalServiceAccountOption = true;
|
||||
|
||||
AllowSeatAutoscale = true;
|
||||
AllowServiceAccountsAutoscale = true;
|
||||
|
||||
if (isAnnual)
|
||||
{
|
||||
StripeSeatPlanId = "secrets-manager-enterprise-seat-annually";
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-annually";
|
||||
SeatPrice = 144;
|
||||
AdditionalPricePerServiceAccount = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
StripeSeatPlanId = "secrets-manager-enterprise-seat-monthly";
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-monthly";
|
||||
SeatPrice = 13;
|
||||
AdditionalPricePerServiceAccount = 0.5M;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record EnterprisePasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public EnterprisePasswordManagerFeatures(bool isAnnual)
|
||||
{
|
||||
BaseSeats = 0;
|
||||
BaseStorageGb = 1;
|
||||
|
||||
HasAdditionalStorageOption = true;
|
||||
HasAdditionalSeatsOption = true;
|
||||
|
||||
AllowSeatAutoscale = true;
|
||||
|
||||
if (isAnnual)
|
||||
{
|
||||
AdditionalStoragePricePerGb = 4;
|
||||
StripeStoragePlanId = "storage-gb-annually";
|
||||
StripeSeatPlanId = "2020-enterprise-org-seat-annually";
|
||||
SeatPrice = 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
StripeSeatPlanId = "2020-enterprise-seat-monthly";
|
||||
StripeStoragePlanId = "storage-gb-monthly";
|
||||
SeatPrice = 6;
|
||||
AdditionalStoragePricePerGb = 0.5M;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
src/Core/Models/StaticStore/Plans/Families2019Plan.cs
Normal file
49
src/Core/Models/StaticStore/Plans/Families2019Plan.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record Families2019Plan : Models.StaticStore.Plan
|
||||
{
|
||||
public Families2019Plan()
|
||||
{
|
||||
Type = PlanType.FamiliesAnnually2019;
|
||||
Product = ProductType.Families;
|
||||
Name = "Families 2019";
|
||||
IsAnnual = true;
|
||||
NameLocalizationKey = "planNameFamilies";
|
||||
DescriptionLocalizationKey = "planDescFamilies";
|
||||
|
||||
TrialPeriodDays = 7;
|
||||
|
||||
HasSelfHost = true;
|
||||
HasTotp = true;
|
||||
|
||||
UpgradeSortOrder = 1;
|
||||
DisplaySortOrder = 1;
|
||||
LegacyYear = 2020;
|
||||
|
||||
PasswordManager = new Families2019PasswordManagerFeatures();
|
||||
}
|
||||
|
||||
private record Families2019PasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public Families2019PasswordManagerFeatures()
|
||||
{
|
||||
BaseSeats = 5;
|
||||
BaseStorageGb = 1;
|
||||
MaxSeats = 5;
|
||||
|
||||
HasAdditionalStorageOption = true;
|
||||
HasPremiumAccessOption = true;
|
||||
|
||||
StripePlanId = "personal-org-annually";
|
||||
StripeStoragePlanId = "storage-gb-annually";
|
||||
StripePremiumAccessPlanId = "personal-org-premium-access-annually";
|
||||
BasePrice = 12;
|
||||
AdditionalStoragePricePerGb = 4;
|
||||
PremiumAccessOptionPrice = 40;
|
||||
|
||||
AllowSeatAutoscale = false;
|
||||
}
|
||||
}
|
||||
}
|
46
src/Core/Models/StaticStore/Plans/FamiliesPlan.cs
Normal file
46
src/Core/Models/StaticStore/Plans/FamiliesPlan.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record FamiliesPlan : Models.StaticStore.Plan
|
||||
{
|
||||
public FamiliesPlan()
|
||||
{
|
||||
Type = PlanType.FamiliesAnnually;
|
||||
Product = ProductType.Families;
|
||||
Name = "Families";
|
||||
IsAnnual = true;
|
||||
NameLocalizationKey = "planNameFamilies";
|
||||
DescriptionLocalizationKey = "planDescFamilies";
|
||||
|
||||
TrialPeriodDays = 7;
|
||||
|
||||
HasSelfHost = true;
|
||||
HasTotp = true;
|
||||
UsersGetPremium = true;
|
||||
|
||||
UpgradeSortOrder = 1;
|
||||
DisplaySortOrder = 1;
|
||||
|
||||
PasswordManager = new TeamsPasswordManagerFeatures();
|
||||
}
|
||||
|
||||
private record TeamsPasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public TeamsPasswordManagerFeatures()
|
||||
{
|
||||
BaseSeats = 6;
|
||||
BaseStorageGb = 1;
|
||||
MaxSeats = 6;
|
||||
|
||||
HasAdditionalStorageOption = true;
|
||||
|
||||
StripePlanId = "2020-families-org-annually";
|
||||
StripeStoragePlanId = "storage-gb-annually";
|
||||
BasePrice = 40;
|
||||
AdditionalStoragePricePerGb = 4;
|
||||
|
||||
AllowSeatAutoscale = false;
|
||||
}
|
||||
}
|
||||
}
|
47
src/Core/Models/StaticStore/Plans/FreePlan.cs
Normal file
47
src/Core/Models/StaticStore/Plans/FreePlan.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record FreePlan : Models.StaticStore.Plan
|
||||
{
|
||||
public FreePlan()
|
||||
{
|
||||
Type = PlanType.Free;
|
||||
Product = ProductType.Free;
|
||||
Name = "Free";
|
||||
NameLocalizationKey = "planNameFree";
|
||||
DescriptionLocalizationKey = "planDescFree";
|
||||
|
||||
UpgradeSortOrder = -1; // Always the lowest plan, cannot be upgraded to
|
||||
DisplaySortOrder = -1;
|
||||
|
||||
PasswordManager = new FreePasswordManagerFeatures();
|
||||
SecretsManager = new FreeSecretsManagerFeatures();
|
||||
}
|
||||
|
||||
private record FreeSecretsManagerFeatures : SecretsManagerPlanFeatures
|
||||
{
|
||||
public FreeSecretsManagerFeatures()
|
||||
{
|
||||
BaseSeats = 2;
|
||||
BaseServiceAccount = 3;
|
||||
MaxProjects = 3;
|
||||
MaxSeats = 2;
|
||||
MaxServiceAccounts = 3;
|
||||
|
||||
AllowSeatAutoscale = false;
|
||||
}
|
||||
}
|
||||
|
||||
private record FreePasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public FreePasswordManagerFeatures()
|
||||
{
|
||||
BaseSeats = 2;
|
||||
MaxCollections = 2;
|
||||
MaxSeats = 2;
|
||||
|
||||
AllowSeatAutoscale = false;
|
||||
}
|
||||
}
|
||||
}
|
60
src/Core/Models/StaticStore/Plans/Teams2019Plan.cs
Normal file
60
src/Core/Models/StaticStore/Plans/Teams2019Plan.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record Teams2019Plan : Models.StaticStore.Plan
|
||||
{
|
||||
public Teams2019Plan(bool isAnnual)
|
||||
{
|
||||
Type = isAnnual ? PlanType.TeamsAnnually2019 : PlanType.TeamsMonthly2019;
|
||||
Product = ProductType.Teams;
|
||||
Name = isAnnual ? "Teams (Annually) 2019" : "Teams (Monthly) 2019";
|
||||
IsAnnual = isAnnual;
|
||||
NameLocalizationKey = "planNameTeams";
|
||||
DescriptionLocalizationKey = "planDescTeams";
|
||||
CanBeUsedByBusiness = true;
|
||||
|
||||
TrialPeriodDays = 7;
|
||||
|
||||
HasTotp = true;
|
||||
|
||||
UpgradeSortOrder = 2;
|
||||
DisplaySortOrder = 2;
|
||||
LegacyYear = 2020;
|
||||
|
||||
PasswordManager = new Teams2019PasswordManagerFeatures(isAnnual);
|
||||
}
|
||||
|
||||
private record Teams2019PasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public Teams2019PasswordManagerFeatures(bool isAnnual)
|
||||
{
|
||||
BaseSeats = 5;
|
||||
BaseStorageGb = 1;
|
||||
|
||||
HasAdditionalStorageOption = true;
|
||||
HasAdditionalSeatsOption = true;
|
||||
|
||||
AllowSeatAutoscale = true;
|
||||
|
||||
if (isAnnual)
|
||||
{
|
||||
StripePlanId = "teams-org-annually";
|
||||
StripeStoragePlanId = "storage-gb-annually";
|
||||
StripeSeatPlanId = "teams-org-seat-annually";
|
||||
SeatPrice = 24;
|
||||
BasePrice = 60;
|
||||
AdditionalStoragePricePerGb = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
StripePlanId = "teams-org-monthly";
|
||||
StripeSeatPlanId = "teams-org-seat-monthly";
|
||||
StripeStoragePlanId = "storage-gb-monthly";
|
||||
BasePrice = 8;
|
||||
SeatPrice = 2.5M;
|
||||
AdditionalStoragePricePerGb = 0.5M;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
94
src/Core/Models/StaticStore/Plans/TeamsPlan.cs
Normal file
94
src/Core/Models/StaticStore/Plans/TeamsPlan.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
public record TeamsPlan : Models.StaticStore.Plan
|
||||
{
|
||||
public TeamsPlan(bool isAnnual)
|
||||
{
|
||||
Type = isAnnual ? PlanType.TeamsAnnually : PlanType.TeamsMonthly;
|
||||
Product = ProductType.Teams;
|
||||
Name = isAnnual ? "Teams (Annually)" : "Teams (Monthly)";
|
||||
IsAnnual = isAnnual;
|
||||
NameLocalizationKey = "planNameTeams";
|
||||
DescriptionLocalizationKey = "planDescTeams";
|
||||
CanBeUsedByBusiness = true;
|
||||
|
||||
TrialPeriodDays = 7;
|
||||
|
||||
HasGroups = true;
|
||||
HasDirectory = true;
|
||||
HasEvents = true;
|
||||
HasTotp = true;
|
||||
Has2fa = true;
|
||||
HasApi = true;
|
||||
UsersGetPremium = true;
|
||||
|
||||
UpgradeSortOrder = 2;
|
||||
DisplaySortOrder = 2;
|
||||
|
||||
PasswordManager = new TeamsPasswordManagerFeatures(isAnnual);
|
||||
SecretsManager = new TeamsSecretsManagerFeatures(isAnnual);
|
||||
}
|
||||
|
||||
private record TeamsSecretsManagerFeatures : SecretsManagerPlanFeatures
|
||||
{
|
||||
public TeamsSecretsManagerFeatures(bool isAnnual)
|
||||
{
|
||||
BaseSeats = 0;
|
||||
BasePrice = 0;
|
||||
BaseServiceAccount = 50;
|
||||
|
||||
HasAdditionalSeatsOption = true;
|
||||
HasAdditionalServiceAccountOption = true;
|
||||
|
||||
AllowSeatAutoscale = true;
|
||||
AllowServiceAccountsAutoscale = true;
|
||||
|
||||
if (isAnnual)
|
||||
{
|
||||
StripeSeatPlanId = "secrets-manager-teams-seat-annually";
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-annually";
|
||||
SeatPrice = 72;
|
||||
AdditionalPricePerServiceAccount = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
StripeSeatPlanId = "secrets-manager-teams-seat-monthly";
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-monthly";
|
||||
SeatPrice = 7;
|
||||
AdditionalPricePerServiceAccount = 0.5M;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record TeamsPasswordManagerFeatures : PasswordManagerPlanFeatures
|
||||
{
|
||||
public TeamsPasswordManagerFeatures(bool isAnnual)
|
||||
{
|
||||
BaseSeats = 0;
|
||||
BaseStorageGb = 1;
|
||||
BasePrice = 0;
|
||||
|
||||
HasAdditionalStorageOption = true;
|
||||
HasAdditionalSeatsOption = true;
|
||||
|
||||
AllowSeatAutoscale = true;
|
||||
|
||||
if (isAnnual)
|
||||
{
|
||||
StripeStoragePlanId = "storage-gb-annually";
|
||||
StripeSeatPlanId = "2020-teams-org-seat-annually";
|
||||
SeatPrice = 36;
|
||||
AdditionalStoragePricePerGb = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
StripeSeatPlanId = "2020-teams-org-seat-monthly";
|
||||
StripeStoragePlanId = "storage-gb-monthly";
|
||||
SeatPrice = 4;
|
||||
AdditionalStoragePricePerGb = 0.5M;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -54,7 +54,7 @@ public class CloudSyncSponsorshipsCommand : ICloudSyncSponsorshipsCommand
|
||||
{
|
||||
var requiredSponsoringProductType = StaticStore.GetSponsoredPlan(selfHostedSponsorship.PlanSponsorshipType)?.SponsoringProductType;
|
||||
if (requiredSponsoringProductType == null
|
||||
|| StaticStore.GetPasswordManagerPlan(sponsoringOrg.PlanType).Product != requiredSponsoringProductType.Value)
|
||||
|| StaticStore.GetPlan(sponsoringOrg.PlanType).Product != requiredSponsoringProductType.Value)
|
||||
{
|
||||
continue; // prevent unsupported sponsorships
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class SetUpSponsorshipCommand : ISetUpSponsorshipCommand
|
||||
var requiredSponsoredProductType = StaticStore.GetSponsoredPlan(sponsorship.PlanSponsorshipType.Value)?.SponsoredProductType;
|
||||
if (requiredSponsoredProductType == null ||
|
||||
sponsoredOrganization == null ||
|
||||
StaticStore.GetPasswordManagerPlan(sponsoredOrganization.PlanType).Product != requiredSponsoredProductType.Value)
|
||||
StaticStore.GetPlan(sponsoredOrganization.PlanType).Product != requiredSponsoredProductType.Value)
|
||||
{
|
||||
throw new BadRequestException("Can only redeem sponsorship offer on families organizations.");
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class ValidateSponsorshipCommand : CancelSponsorshipCommand, IValidateSpo
|
||||
return false;
|
||||
}
|
||||
|
||||
var sponsoringOrgPlan = Utilities.StaticStore.GetPasswordManagerPlan(sponsoringOrganization.PlanType);
|
||||
var sponsoringOrgPlan = Utilities.StaticStore.GetPlan(sponsoringOrganization.PlanType);
|
||||
if (OrgDisabledForMoreThanGracePeriod(sponsoringOrganization) ||
|
||||
sponsoredPlan.SponsoringProductType != sponsoringOrgPlan.Product ||
|
||||
existingSponsorship.ToDelete ||
|
||||
|
@ -32,7 +32,7 @@ public class CreateSponsorshipCommand : ICreateSponsorshipCommand
|
||||
var requiredSponsoringProductType = StaticStore.GetSponsoredPlan(sponsorshipType)?.SponsoringProductType;
|
||||
if (requiredSponsoringProductType == null ||
|
||||
sponsoringOrg == null ||
|
||||
StaticStore.GetPasswordManagerPlan(sponsoringOrg.PlanType).Product != requiredSponsoringProductType.Value)
|
||||
StaticStore.GetPlan(sponsoringOrg.PlanType).Product != requiredSponsoringProductType.Value)
|
||||
{
|
||||
throw new BadRequestException("Specified Organization cannot sponsor other organizations.");
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class AddSecretsManagerSubscriptionCommand : IAddSecretsManagerSubscripti
|
||||
{
|
||||
await ValidateOrganization(organization);
|
||||
|
||||
var plan = StaticStore.GetSecretsManagerPlan(organization.PlanType);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var signup = SetOrganizationUpgrade(organization, additionalSmSeats, additionalServiceAccounts);
|
||||
_organizationService.ValidateSecretsManagerPlan(plan, signup);
|
||||
|
||||
@ -39,8 +39,8 @@ public class AddSecretsManagerSubscriptionCommand : IAddSecretsManagerSubscripti
|
||||
await _paymentService.AddSecretsManagerToSubscription(organization, plan, additionalSmSeats, additionalServiceAccounts);
|
||||
}
|
||||
|
||||
organization.SmSeats = plan.BaseSeats + additionalSmSeats;
|
||||
organization.SmServiceAccounts = plan.BaseServiceAccount.GetValueOrDefault() + additionalServiceAccounts;
|
||||
organization.SmSeats = plan.SecretsManager.BaseSeats + additionalSmSeats;
|
||||
organization.SmServiceAccounts = plan.SecretsManager.BaseServiceAccount + additionalServiceAccounts;
|
||||
organization.UseSecretsManager = true;
|
||||
|
||||
await _organizationService.ReplaceAndUpdateCacheAsync(organization);
|
||||
@ -79,7 +79,7 @@ public class AddSecretsManagerSubscriptionCommand : IAddSecretsManagerSubscripti
|
||||
throw new BadRequestException("Organization already uses Secrets Manager.");
|
||||
}
|
||||
|
||||
var plan = StaticStore.GetSecretsManagerPlan(organization.PlanType);
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == organization.PlanType && p.SupportsSecretsManager);
|
||||
if (string.IsNullOrWhiteSpace(organization.GatewayCustomerId) && plan.Product != ProductType.Free)
|
||||
{
|
||||
throw new BadRequestException("No payment method found.");
|
||||
|
@ -205,10 +205,10 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
|
||||
}
|
||||
|
||||
// Check plan maximum seats
|
||||
if (!plan.HasAdditionalSeatsOption ||
|
||||
(plan.MaxAdditionalSeats.HasValue && update.SmSeatsExcludingBase > plan.MaxAdditionalSeats.Value))
|
||||
if (!plan.SecretsManager.HasAdditionalSeatsOption ||
|
||||
(plan.SecretsManager.MaxAdditionalSeats.HasValue && update.SmSeatsExcludingBase > plan.SecretsManager.MaxAdditionalSeats.Value))
|
||||
{
|
||||
var planMaxSeats = plan.BaseSeats + plan.MaxAdditionalSeats.GetValueOrDefault();
|
||||
var planMaxSeats = plan.SecretsManager.BaseSeats + plan.SecretsManager.MaxAdditionalSeats.GetValueOrDefault();
|
||||
throw new BadRequestException($"You have reached the maximum number of Secrets Manager seats ({planMaxSeats}) for this plan.");
|
||||
}
|
||||
|
||||
@ -222,9 +222,9 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
|
||||
}
|
||||
|
||||
// Check minimum seats included with plan
|
||||
if (plan.BaseSeats > update.SmSeats.Value)
|
||||
if (plan.SecretsManager.BaseSeats > update.SmSeats.Value)
|
||||
{
|
||||
throw new BadRequestException($"Plan has a minimum of {plan.BaseSeats} Secrets Manager seats.");
|
||||
throw new BadRequestException($"Plan has a minimum of {plan.SecretsManager.BaseSeats} Secrets Manager seats.");
|
||||
}
|
||||
|
||||
// Check minimum seats required by business logic
|
||||
@ -262,11 +262,11 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
|
||||
}
|
||||
|
||||
// Check plan maximum service accounts
|
||||
if (!plan.HasAdditionalServiceAccountOption ||
|
||||
(plan.MaxAdditionalServiceAccount.HasValue && update.SmServiceAccountsExcludingBase > plan.MaxAdditionalServiceAccount.Value))
|
||||
if (!plan.SecretsManager.HasAdditionalServiceAccountOption ||
|
||||
(plan.SecretsManager.MaxAdditionalServiceAccount.HasValue && update.SmServiceAccountsExcludingBase > plan.SecretsManager.MaxAdditionalServiceAccount.Value))
|
||||
{
|
||||
var planMaxServiceAccounts = plan.BaseServiceAccount.GetValueOrDefault() +
|
||||
plan.MaxAdditionalServiceAccount.GetValueOrDefault();
|
||||
var planMaxServiceAccounts = plan.SecretsManager.BaseServiceAccount +
|
||||
plan.SecretsManager.MaxAdditionalServiceAccount.GetValueOrDefault();
|
||||
throw new BadRequestException($"You have reached the maximum number of service accounts ({planMaxServiceAccounts}) for this plan.");
|
||||
}
|
||||
|
||||
@ -281,9 +281,9 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
|
||||
}
|
||||
|
||||
// Check minimum service accounts included with plan
|
||||
if (plan.BaseServiceAccount.HasValue && plan.BaseServiceAccount.Value > update.SmServiceAccounts.Value)
|
||||
if (plan.SecretsManager.BaseServiceAccount > update.SmServiceAccounts.Value)
|
||||
{
|
||||
throw new BadRequestException($"Plan has a minimum of {plan.BaseServiceAccount} service accounts.");
|
||||
throw new BadRequestException($"Plan has a minimum of {plan.SecretsManager.BaseServiceAccount} service accounts.");
|
||||
}
|
||||
|
||||
// Check minimum service accounts required by business logic
|
||||
@ -319,15 +319,15 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
|
||||
throw new BadRequestException($"Cannot set max Secrets Manager seat autoscaling below current Secrets Manager seat count.");
|
||||
}
|
||||
|
||||
if (plan.MaxUsers.HasValue && update.MaxAutoscaleSmSeats.Value > plan.MaxUsers)
|
||||
if (plan.SecretsManager.MaxSeats.HasValue && update.MaxAutoscaleSmSeats.Value > plan.SecretsManager.MaxSeats)
|
||||
{
|
||||
throw new BadRequestException(string.Concat(
|
||||
$"Your plan has a Secrets Manager seat limit of {plan.MaxUsers}, ",
|
||||
$"Your plan has a Secrets Manager seat limit of {plan.SecretsManager.MaxSeats}, ",
|
||||
$"but you have specified a max autoscale count of {update.MaxAutoscaleSmSeats}.",
|
||||
"Reduce your max autoscale count."));
|
||||
}
|
||||
|
||||
if (!plan.AllowSeatAutoscale)
|
||||
if (!plan.SecretsManager.AllowSeatAutoscale)
|
||||
{
|
||||
throw new BadRequestException("Your plan does not allow Secrets Manager seat autoscaling.");
|
||||
}
|
||||
@ -349,15 +349,15 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
|
||||
$"Cannot set max service accounts autoscaling below current service accounts count.");
|
||||
}
|
||||
|
||||
if (!plan.AllowServiceAccountsAutoscale)
|
||||
if (!plan.SecretsManager.AllowServiceAccountsAutoscale)
|
||||
{
|
||||
throw new BadRequestException("Your plan does not allow service accounts autoscaling.");
|
||||
}
|
||||
|
||||
if (plan.MaxServiceAccounts.HasValue && update.MaxAutoscaleSmServiceAccounts.Value > plan.MaxServiceAccounts)
|
||||
if (plan.SecretsManager.MaxServiceAccounts.HasValue && update.MaxAutoscaleSmServiceAccounts.Value > plan.SecretsManager.MaxServiceAccounts)
|
||||
{
|
||||
throw new BadRequestException(string.Concat(
|
||||
$"Your plan has a service account limit of {plan.MaxServiceAccounts}, ",
|
||||
$"Your plan has a service account limit of {plan.SecretsManager.MaxServiceAccounts}, ",
|
||||
$"but you have specified a max autoscale count of {update.MaxAutoscaleSmServiceAccounts}.",
|
||||
"Reduce your max autoscale count."));
|
||||
}
|
||||
|
@ -73,69 +73,67 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
throw new BadRequestException("Your account has no payment method available.");
|
||||
}
|
||||
|
||||
var existingPasswordManagerPlan = StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
if (existingPasswordManagerPlan == null)
|
||||
var existingPlan = StaticStore.GetPlan(organization.PlanType);
|
||||
if (existingPlan == null)
|
||||
{
|
||||
throw new BadRequestException("Existing plan not found.");
|
||||
}
|
||||
|
||||
var newPasswordManagerPlan =
|
||||
StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == upgrade.Plan && !p.Disabled);
|
||||
if (newPasswordManagerPlan == null)
|
||||
var newPlan = StaticStore.Plans.FirstOrDefault(p => p.Type == upgrade.Plan && !p.Disabled);
|
||||
if (newPlan == null)
|
||||
{
|
||||
throw new BadRequestException("Plan not found.");
|
||||
}
|
||||
|
||||
if (existingPasswordManagerPlan.Type == newPasswordManagerPlan.Type)
|
||||
if (existingPlan.Type == newPlan.Type)
|
||||
{
|
||||
throw new BadRequestException("Organization is already on this plan.");
|
||||
}
|
||||
|
||||
if (existingPasswordManagerPlan.UpgradeSortOrder >= newPasswordManagerPlan.UpgradeSortOrder)
|
||||
if (existingPlan.UpgradeSortOrder >= newPlan.UpgradeSortOrder)
|
||||
{
|
||||
throw new BadRequestException("You cannot upgrade to this plan.");
|
||||
}
|
||||
|
||||
if (existingPasswordManagerPlan.Type != PlanType.Free)
|
||||
if (existingPlan.Type != PlanType.Free)
|
||||
{
|
||||
throw new BadRequestException("You can only upgrade from the free plan. Contact support.");
|
||||
}
|
||||
|
||||
_organizationService.ValidatePasswordManagerPlan(newPasswordManagerPlan, upgrade);
|
||||
var newSecretsManagerPlan =
|
||||
StaticStore.SecretManagerPlans.FirstOrDefault(p => p.Type == upgrade.Plan && !p.Disabled);
|
||||
_organizationService.ValidatePasswordManagerPlan(newPlan, upgrade);
|
||||
|
||||
if (upgrade.UseSecretsManager)
|
||||
{
|
||||
_organizationService.ValidateSecretsManagerPlan(newSecretsManagerPlan, upgrade);
|
||||
_organizationService.ValidateSecretsManagerPlan(newPlan, upgrade);
|
||||
}
|
||||
|
||||
var newPasswordManagerPlanSeats = (short)(newPasswordManagerPlan.BaseSeats +
|
||||
(newPasswordManagerPlan.HasAdditionalSeatsOption ? upgrade.AdditionalSeats : 0));
|
||||
if (!organization.Seats.HasValue || organization.Seats.Value > newPasswordManagerPlanSeats)
|
||||
var updatedPasswordManagerSeats = (short)(newPlan.PasswordManager.BaseSeats +
|
||||
(newPlan.PasswordManager.HasAdditionalSeatsOption ? upgrade.AdditionalSeats : 0));
|
||||
if (!organization.Seats.HasValue || organization.Seats.Value > updatedPasswordManagerSeats)
|
||||
{
|
||||
var occupiedSeats =
|
||||
await _organizationUserRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
|
||||
if (occupiedSeats > newPasswordManagerPlanSeats)
|
||||
if (occupiedSeats > updatedPasswordManagerSeats)
|
||||
{
|
||||
throw new BadRequestException($"Your organization currently has {occupiedSeats} seats filled. " +
|
||||
$"Your new plan only has ({newPasswordManagerPlanSeats}) seats. Remove some users.");
|
||||
$"Your new plan only has ({updatedPasswordManagerSeats}) seats. Remove some users.");
|
||||
}
|
||||
}
|
||||
|
||||
if (newPasswordManagerPlan.MaxCollections.HasValue && (!organization.MaxCollections.HasValue ||
|
||||
if (newPlan.PasswordManager.MaxCollections.HasValue && (!organization.MaxCollections.HasValue ||
|
||||
organization.MaxCollections.Value >
|
||||
newPasswordManagerPlan.MaxCollections.Value))
|
||||
newPlan.PasswordManager.MaxCollections.Value))
|
||||
{
|
||||
var collectionCount = await _collectionRepository.GetCountByOrganizationIdAsync(organization.Id);
|
||||
if (collectionCount > newPasswordManagerPlan.MaxCollections.Value)
|
||||
if (collectionCount > newPlan.PasswordManager.MaxCollections.Value)
|
||||
{
|
||||
throw new BadRequestException($"Your organization currently has {collectionCount} collections. " +
|
||||
$"Your new plan allows for a maximum of ({newPasswordManagerPlan.MaxCollections.Value}) collections. " +
|
||||
$"Your new plan allows for a maximum of ({newPlan.PasswordManager.MaxCollections.Value}) collections. " +
|
||||
"Remove some collections.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPasswordManagerPlan.HasGroups && organization.UseGroups)
|
||||
if (!newPlan.HasGroups && organization.UseGroups)
|
||||
{
|
||||
var groups = await _groupRepository.GetManyByOrganizationIdAsync(organization.Id);
|
||||
if (groups.Any())
|
||||
@ -145,7 +143,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPasswordManagerPlan.HasPolicies && organization.UsePolicies)
|
||||
if (!newPlan.HasPolicies && organization.UsePolicies)
|
||||
{
|
||||
var policies = await _policyRepository.GetManyByOrganizationIdAsync(organization.Id);
|
||||
if (policies.Any(p => p.Enabled))
|
||||
@ -155,7 +153,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPasswordManagerPlan.HasSso && organization.UseSso)
|
||||
if (!newPlan.HasSso && organization.UseSso)
|
||||
{
|
||||
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organization.Id);
|
||||
if (ssoConfig != null && ssoConfig.Enabled)
|
||||
@ -165,7 +163,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPasswordManagerPlan.HasKeyConnector && organization.UseKeyConnector)
|
||||
if (!newPlan.HasKeyConnector && organization.UseKeyConnector)
|
||||
{
|
||||
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organization.Id);
|
||||
if (ssoConfig != null && ssoConfig.GetData().MemberDecryptionType == MemberDecryptionType.KeyConnector)
|
||||
@ -175,7 +173,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPasswordManagerPlan.HasResetPassword && organization.UseResetPassword)
|
||||
if (!newPlan.HasResetPassword && organization.UseResetPassword)
|
||||
{
|
||||
var resetPasswordPolicy =
|
||||
await _policyRepository.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.ResetPassword);
|
||||
@ -186,7 +184,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPasswordManagerPlan.HasScim && organization.UseScim)
|
||||
if (!newPlan.HasScim && organization.UseScim)
|
||||
{
|
||||
var scimConnections = await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(organization.Id,
|
||||
OrganizationConnectionType.Scim);
|
||||
@ -197,7 +195,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPasswordManagerPlan.HasCustomPermissions && organization.UseCustomPermissions)
|
||||
if (!newPlan.HasCustomPermissions && organization.UseCustomPermissions)
|
||||
{
|
||||
var organizationCustomUsers =
|
||||
await _organizationUserRepository.GetManyByOrganizationAsync(organization.Id,
|
||||
@ -209,9 +207,9 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
if (upgrade.UseSecretsManager && newSecretsManagerPlan != null)
|
||||
if (upgrade.UseSecretsManager)
|
||||
{
|
||||
await ValidateSecretsManagerSeatsAndServiceAccountAsync(upgrade, organization, newSecretsManagerPlan);
|
||||
await ValidateSecretsManagerSeatsAndServiceAccountAsync(upgrade, organization, newPlan);
|
||||
}
|
||||
|
||||
// TODO: Check storage?
|
||||
@ -220,12 +218,8 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
|
||||
if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
|
||||
{
|
||||
var organizationUpgradePlan = upgrade.UseSecretsManager
|
||||
? StaticStore.Plans.Where(p => p.Type == upgrade.Plan).ToList()
|
||||
: StaticStore.Plans.Where(p => p.Type == upgrade.Plan && p.BitwardenProduct == BitwardenProductType.PasswordManager).ToList();
|
||||
|
||||
paymentIntentClientSecret = await _paymentService.UpgradeFreeOrganizationAsync(organization,
|
||||
organizationUpgradePlan, upgrade);
|
||||
newPlan, upgrade);
|
||||
success = string.IsNullOrWhiteSpace(paymentIntentClientSecret);
|
||||
}
|
||||
else
|
||||
@ -235,34 +229,34 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
|
||||
organization.BusinessName = upgrade.BusinessName;
|
||||
organization.PlanType = newPasswordManagerPlan.Type;
|
||||
organization.Seats = (short)(newPasswordManagerPlan.BaseSeats + upgrade.AdditionalSeats);
|
||||
organization.MaxCollections = newPasswordManagerPlan.MaxCollections;
|
||||
organization.UseGroups = newPasswordManagerPlan.HasGroups;
|
||||
organization.UseDirectory = newPasswordManagerPlan.HasDirectory;
|
||||
organization.UseEvents = newPasswordManagerPlan.HasEvents;
|
||||
organization.UseTotp = newPasswordManagerPlan.HasTotp;
|
||||
organization.Use2fa = newPasswordManagerPlan.Has2fa;
|
||||
organization.UseApi = newPasswordManagerPlan.HasApi;
|
||||
organization.SelfHost = newPasswordManagerPlan.HasSelfHost;
|
||||
organization.UsePolicies = newPasswordManagerPlan.HasPolicies;
|
||||
organization.MaxStorageGb = !newPasswordManagerPlan.BaseStorageGb.HasValue
|
||||
organization.PlanType = newPlan.Type;
|
||||
organization.Seats = (short)(newPlan.PasswordManager.BaseSeats + upgrade.AdditionalSeats);
|
||||
organization.MaxCollections = newPlan.PasswordManager.MaxCollections;
|
||||
organization.UseGroups = newPlan.HasGroups;
|
||||
organization.UseDirectory = newPlan.HasDirectory;
|
||||
organization.UseEvents = newPlan.HasEvents;
|
||||
organization.UseTotp = newPlan.HasTotp;
|
||||
organization.Use2fa = newPlan.Has2fa;
|
||||
organization.UseApi = newPlan.HasApi;
|
||||
organization.SelfHost = newPlan.HasSelfHost;
|
||||
organization.UsePolicies = newPlan.HasPolicies;
|
||||
organization.MaxStorageGb = !newPlan.PasswordManager.BaseStorageGb.HasValue
|
||||
? (short?)null
|
||||
: (short)(newPasswordManagerPlan.BaseStorageGb.Value + upgrade.AdditionalStorageGb);
|
||||
organization.UseGroups = newPasswordManagerPlan.HasGroups;
|
||||
organization.UseDirectory = newPasswordManagerPlan.HasDirectory;
|
||||
organization.UseEvents = newPasswordManagerPlan.HasEvents;
|
||||
organization.UseTotp = newPasswordManagerPlan.HasTotp;
|
||||
organization.Use2fa = newPasswordManagerPlan.Has2fa;
|
||||
organization.UseApi = newPasswordManagerPlan.HasApi;
|
||||
organization.UseSso = newPasswordManagerPlan.HasSso;
|
||||
organization.UseKeyConnector = newPasswordManagerPlan.HasKeyConnector;
|
||||
organization.UseScim = newPasswordManagerPlan.HasScim;
|
||||
organization.UseResetPassword = newPasswordManagerPlan.HasResetPassword;
|
||||
organization.SelfHost = newPasswordManagerPlan.HasSelfHost;
|
||||
organization.UsersGetPremium = newPasswordManagerPlan.UsersGetPremium || upgrade.PremiumAccessAddon;
|
||||
organization.UseCustomPermissions = newPasswordManagerPlan.HasCustomPermissions;
|
||||
organization.Plan = newPasswordManagerPlan.Name;
|
||||
: (short)(newPlan.PasswordManager.BaseStorageGb.Value + upgrade.AdditionalStorageGb);
|
||||
organization.UseGroups = newPlan.HasGroups;
|
||||
organization.UseDirectory = newPlan.HasDirectory;
|
||||
organization.UseEvents = newPlan.HasEvents;
|
||||
organization.UseTotp = newPlan.HasTotp;
|
||||
organization.Use2fa = newPlan.Has2fa;
|
||||
organization.UseApi = newPlan.HasApi;
|
||||
organization.UseSso = newPlan.HasSso;
|
||||
organization.UseKeyConnector = newPlan.HasKeyConnector;
|
||||
organization.UseScim = newPlan.HasScim;
|
||||
organization.UseResetPassword = newPlan.HasResetPassword;
|
||||
organization.SelfHost = newPlan.HasSelfHost;
|
||||
organization.UsersGetPremium = newPlan.UsersGetPremium || upgrade.PremiumAccessAddon;
|
||||
organization.UseCustomPermissions = newPlan.HasCustomPermissions;
|
||||
organization.Plan = newPlan.Name;
|
||||
organization.Enabled = success;
|
||||
organization.PublicKey = upgrade.PublicKey;
|
||||
organization.PrivateKey = upgrade.PrivateKey;
|
||||
@ -271,8 +265,8 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
|
||||
if (upgrade.UseSecretsManager)
|
||||
{
|
||||
organization.SmSeats = newSecretsManagerPlan.BaseSeats + upgrade.AdditionalSmSeats.GetValueOrDefault();
|
||||
organization.SmServiceAccounts = newSecretsManagerPlan.BaseServiceAccount.GetValueOrDefault() +
|
||||
organization.SmSeats = newPlan.SecretsManager.BaseSeats + upgrade.AdditionalSmSeats.GetValueOrDefault();
|
||||
organization.SmServiceAccounts = newPlan.SecretsManager.BaseServiceAccount +
|
||||
upgrade.AdditionalServiceAccounts.GetValueOrDefault();
|
||||
}
|
||||
|
||||
@ -283,10 +277,10 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.UpgradePlan, organization, _currentContext)
|
||||
{
|
||||
PlanName = newPasswordManagerPlan.Name,
|
||||
PlanType = newPasswordManagerPlan.Type,
|
||||
OldPlanName = existingPasswordManagerPlan.Name,
|
||||
OldPlanType = existingPasswordManagerPlan.Type,
|
||||
PlanName = newPlan.Name,
|
||||
PlanType = newPlan.Type,
|
||||
OldPlanName = existingPlan.Name,
|
||||
OldPlanType = existingPlan.Type,
|
||||
Seats = organization.Seats,
|
||||
Storage = organization.MaxStorageGb,
|
||||
// TODO: add reference events for SmSeats and Service Accounts - see AC-1481
|
||||
@ -299,8 +293,8 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
private async Task ValidateSecretsManagerSeatsAndServiceAccountAsync(OrganizationUpgrade upgrade, Organization organization,
|
||||
Models.StaticStore.Plan newSecretsManagerPlan)
|
||||
{
|
||||
var newPlanSmSeats = (short)(newSecretsManagerPlan.BaseSeats +
|
||||
(newSecretsManagerPlan.HasAdditionalSeatsOption
|
||||
var newPlanSmSeats = (short)(newSecretsManagerPlan.SecretsManager.BaseSeats +
|
||||
(newSecretsManagerPlan.SecretsManager.HasAdditionalSeatsOption
|
||||
? upgrade.AdditionalSmSeats
|
||||
: 0));
|
||||
var occupiedSmSeats =
|
||||
@ -316,10 +310,10 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
}
|
||||
}
|
||||
|
||||
var additionalServiceAccounts = newSecretsManagerPlan.HasAdditionalServiceAccountOption
|
||||
var additionalServiceAccounts = newSecretsManagerPlan.SecretsManager.HasAdditionalServiceAccountOption
|
||||
? upgrade.AdditionalServiceAccounts
|
||||
: 0;
|
||||
var newPlanServiceAccounts = newSecretsManagerPlan.BaseServiceAccount + additionalServiceAccounts;
|
||||
var newPlanServiceAccounts = newSecretsManagerPlan.SecretsManager.BaseServiceAccount + additionalServiceAccounts;
|
||||
|
||||
if (!organization.SmServiceAccounts.HasValue || organization.SmServiceAccounts.Value > newPlanServiceAccounts)
|
||||
{
|
||||
@ -329,7 +323,7 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand
|
||||
{
|
||||
throw new BadRequestException(
|
||||
$"Your organization currently has {currentServiceAccounts} service accounts. " +
|
||||
$"Your new plan only allows {newSecretsManagerPlan.MaxServiceAccounts} service accounts. " +
|
||||
$"Your new plan only allows {newSecretsManagerPlan.SecretsManager.MaxServiceAccounts} service accounts. " +
|
||||
"Remove some service accounts or increase your subscription.");
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,12 @@ public interface IPaymentService
|
||||
{
|
||||
Task CancelAndRecoverChargesAsync(ISubscriber subscriber);
|
||||
Task<string> PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType,
|
||||
string paymentToken, List<Plan> plans, short additionalStorageGb, int additionalSeats,
|
||||
string paymentToken, Plan plan, short additionalStorageGb, int additionalSeats,
|
||||
bool premiumAccessAddon, TaxInfo taxInfo, bool provider = false, int additionalSmSeats = 0,
|
||||
int additionalServiceAccount = 0);
|
||||
Task SponsorOrganizationAsync(Organization org, OrganizationSponsorship sponsorship);
|
||||
Task RemoveOrganizationSponsorshipAsync(Organization org, OrganizationSponsorship sponsorship);
|
||||
Task<string> UpgradeFreeOrganizationAsync(Organization org, List<Plan> plans, OrganizationUpgrade upgrade);
|
||||
Task<string> UpgradeFreeOrganizationAsync(Organization org, Plan plan, OrganizationUpgrade upgrade);
|
||||
Task<string> PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken,
|
||||
short additionalStorageGb, TaxInfo taxInfo);
|
||||
Task<string> AdjustSeatsAsync(Organization organization, Plan plan, int additionalSeats, DateTime? prorationDate = null);
|
||||
|
@ -175,19 +175,19 @@ public class OrganizationService : IOrganizationService
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var plan = StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
if (plan == null)
|
||||
{
|
||||
throw new BadRequestException("Existing plan not found.");
|
||||
}
|
||||
|
||||
if (!plan.HasAdditionalStorageOption)
|
||||
if (!plan.PasswordManager.HasAdditionalStorageOption)
|
||||
{
|
||||
throw new BadRequestException("Plan does not allow additional storage.");
|
||||
}
|
||||
|
||||
var secret = await BillingHelpers.AdjustStorageAsync(_paymentService, organization, storageAdjustmentGb,
|
||||
plan.StripeStoragePlanId);
|
||||
plan.PasswordManager.StripeStoragePlanId);
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.AdjustStorage, organization, _currentContext)
|
||||
{
|
||||
@ -233,21 +233,21 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException($"Cannot set max seat autoscaling below current seat count.");
|
||||
}
|
||||
|
||||
var plan = StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
if (plan == null)
|
||||
{
|
||||
throw new BadRequestException("Existing plan not found.");
|
||||
}
|
||||
|
||||
if (!plan.AllowSeatAutoscale)
|
||||
if (!plan.PasswordManager.AllowSeatAutoscale)
|
||||
{
|
||||
throw new BadRequestException("Your plan does not allow seat autoscaling.");
|
||||
}
|
||||
|
||||
if (plan.MaxUsers.HasValue && maxAutoscaleSeats.HasValue &&
|
||||
maxAutoscaleSeats > plan.MaxUsers)
|
||||
if (plan.PasswordManager.MaxSeats.HasValue && maxAutoscaleSeats.HasValue &&
|
||||
maxAutoscaleSeats > plan.PasswordManager.MaxSeats)
|
||||
{
|
||||
throw new BadRequestException(string.Concat($"Your plan has a seat limit of {plan.MaxUsers}, ",
|
||||
throw new BadRequestException(string.Concat($"Your plan has a seat limit of {plan.PasswordManager.MaxSeats}, ",
|
||||
$"but you have specified a max autoscale count of {maxAutoscaleSeats}.",
|
||||
"Reduce your max autoscale seat count."));
|
||||
}
|
||||
@ -285,21 +285,21 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException("No subscription found.");
|
||||
}
|
||||
|
||||
var plan = StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
if (plan == null)
|
||||
{
|
||||
throw new BadRequestException("Existing plan not found.");
|
||||
}
|
||||
|
||||
if (!plan.HasAdditionalSeatsOption)
|
||||
if (!plan.PasswordManager.HasAdditionalSeatsOption)
|
||||
{
|
||||
throw new BadRequestException("Plan does not allow additional seats.");
|
||||
}
|
||||
|
||||
var newSeatTotal = organization.Seats.Value + seatAdjustment;
|
||||
if (plan.BaseSeats > newSeatTotal)
|
||||
if (plan.PasswordManager.BaseSeats > newSeatTotal)
|
||||
{
|
||||
throw new BadRequestException($"Plan has a minimum of {plan.BaseSeats} seats.");
|
||||
throw new BadRequestException($"Plan has a minimum of {plan.PasswordManager.BaseSeats} seats.");
|
||||
}
|
||||
|
||||
if (newSeatTotal <= 0)
|
||||
@ -307,11 +307,11 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException("You must have at least 1 seat.");
|
||||
}
|
||||
|
||||
var additionalSeats = newSeatTotal - plan.BaseSeats;
|
||||
if (plan.MaxAdditionalSeats.HasValue && additionalSeats > plan.MaxAdditionalSeats.Value)
|
||||
var additionalSeats = newSeatTotal - plan.PasswordManager.BaseSeats;
|
||||
if (plan.PasswordManager.MaxAdditionalSeats.HasValue && additionalSeats > plan.PasswordManager.MaxAdditionalSeats.Value)
|
||||
{
|
||||
throw new BadRequestException($"Organization plan allows a maximum of " +
|
||||
$"{plan.MaxAdditionalSeats.Value} additional seats.");
|
||||
$"{plan.PasswordManager.MaxAdditionalSeats.Value} additional seats.");
|
||||
}
|
||||
|
||||
if (!organization.Seats.HasValue || organization.Seats.Value > newSeatTotal)
|
||||
@ -403,11 +403,10 @@ public class OrganizationService : IOrganizationService
|
||||
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup signup,
|
||||
bool provider = false)
|
||||
{
|
||||
var passwordManagerPlan = StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == signup.Plan);
|
||||
var plan = StaticStore.GetPlan(signup.Plan);
|
||||
|
||||
ValidatePasswordManagerPlan(passwordManagerPlan, signup);
|
||||
ValidatePasswordManagerPlan(plan, signup);
|
||||
|
||||
var secretsManagerPlan = StaticStore.SecretManagerPlans.FirstOrDefault(p => p.Type == signup.Plan);
|
||||
if (signup.UseSecretsManager)
|
||||
{
|
||||
if (provider)
|
||||
@ -415,7 +414,7 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException(
|
||||
"Organizations with a Managed Service Provider do not support Secrets Manager.");
|
||||
}
|
||||
ValidateSecretsManagerPlan(secretsManagerPlan, signup);
|
||||
ValidateSecretsManagerPlan(plan, signup);
|
||||
}
|
||||
|
||||
if (!provider)
|
||||
@ -430,25 +429,25 @@ public class OrganizationService : IOrganizationService
|
||||
Name = signup.Name,
|
||||
BillingEmail = signup.BillingEmail,
|
||||
BusinessName = signup.BusinessName,
|
||||
PlanType = passwordManagerPlan.Type,
|
||||
Seats = (short)(passwordManagerPlan.BaseSeats + signup.AdditionalSeats),
|
||||
MaxCollections = passwordManagerPlan.MaxCollections,
|
||||
MaxStorageGb = !passwordManagerPlan.BaseStorageGb.HasValue ?
|
||||
(short?)null : (short)(passwordManagerPlan.BaseStorageGb.Value + signup.AdditionalStorageGb),
|
||||
UsePolicies = passwordManagerPlan.HasPolicies,
|
||||
UseSso = passwordManagerPlan.HasSso,
|
||||
UseGroups = passwordManagerPlan.HasGroups,
|
||||
UseEvents = passwordManagerPlan.HasEvents,
|
||||
UseDirectory = passwordManagerPlan.HasDirectory,
|
||||
UseTotp = passwordManagerPlan.HasTotp,
|
||||
Use2fa = passwordManagerPlan.Has2fa,
|
||||
UseApi = passwordManagerPlan.HasApi,
|
||||
UseResetPassword = passwordManagerPlan.HasResetPassword,
|
||||
SelfHost = passwordManagerPlan.HasSelfHost,
|
||||
UsersGetPremium = passwordManagerPlan.UsersGetPremium || signup.PremiumAccessAddon,
|
||||
UseCustomPermissions = passwordManagerPlan.HasCustomPermissions,
|
||||
UseScim = passwordManagerPlan.HasScim,
|
||||
Plan = passwordManagerPlan.Name,
|
||||
PlanType = plan!.Type,
|
||||
Seats = (short)(plan.PasswordManager.BaseSeats + signup.AdditionalSeats),
|
||||
MaxCollections = plan.PasswordManager.MaxCollections,
|
||||
MaxStorageGb = !plan.PasswordManager.BaseStorageGb.HasValue ?
|
||||
(short?)null : (short)(plan.PasswordManager.BaseStorageGb.Value + signup.AdditionalStorageGb),
|
||||
UsePolicies = plan.HasPolicies,
|
||||
UseSso = plan.HasSso,
|
||||
UseGroups = plan.HasGroups,
|
||||
UseEvents = plan.HasEvents,
|
||||
UseDirectory = plan.HasDirectory,
|
||||
UseTotp = plan.HasTotp,
|
||||
Use2fa = plan.Has2fa,
|
||||
UseApi = plan.HasApi,
|
||||
UseResetPassword = plan.HasResetPassword,
|
||||
SelfHost = plan.HasSelfHost,
|
||||
UsersGetPremium = plan.UsersGetPremium || signup.PremiumAccessAddon,
|
||||
UseCustomPermissions = plan.HasCustomPermissions,
|
||||
UseScim = plan.HasScim,
|
||||
Plan = plan.Name,
|
||||
Gateway = null,
|
||||
ReferenceData = signup.Owner.ReferenceData,
|
||||
Enabled = true,
|
||||
@ -464,12 +463,12 @@ public class OrganizationService : IOrganizationService
|
||||
|
||||
if (signup.UseSecretsManager)
|
||||
{
|
||||
organization.SmSeats = secretsManagerPlan.BaseSeats + signup.AdditionalSmSeats.GetValueOrDefault();
|
||||
organization.SmServiceAccounts = secretsManagerPlan.BaseServiceAccount.GetValueOrDefault() +
|
||||
organization.SmSeats = plan.SecretsManager.BaseSeats + signup.AdditionalSmSeats.GetValueOrDefault();
|
||||
organization.SmServiceAccounts = plan.SecretsManager.BaseServiceAccount +
|
||||
signup.AdditionalServiceAccounts.GetValueOrDefault();
|
||||
}
|
||||
|
||||
if (passwordManagerPlan.Type == PlanType.Free && !provider)
|
||||
if (plan.Type == PlanType.Free && !provider)
|
||||
{
|
||||
var adminCount =
|
||||
await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(signup.Owner.Id);
|
||||
@ -478,14 +477,10 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException("You can only be an admin of one free organization.");
|
||||
}
|
||||
}
|
||||
else if (passwordManagerPlan.Type != PlanType.Free)
|
||||
else if (plan.Type != PlanType.Free)
|
||||
{
|
||||
var purchaseOrganizationPlan = signup.UseSecretsManager
|
||||
? StaticStore.Plans.Where(p => p.Type == signup.Plan).ToList()
|
||||
: StaticStore.PasswordManagerPlans.Where(p => p.Type == signup.Plan).Take(1).ToList();
|
||||
|
||||
await _paymentService.PurchaseOrganizationAsync(organization, signup.PaymentMethodType.Value,
|
||||
signup.PaymentToken, purchaseOrganizationPlan, signup.AdditionalStorageGb, signup.AdditionalSeats,
|
||||
signup.PaymentToken, plan, signup.AdditionalStorageGb, signup.AdditionalSeats,
|
||||
signup.PremiumAccessAddon, signup.TaxInfo, provider, signup.AdditionalSmSeats.GetValueOrDefault(),
|
||||
signup.AdditionalServiceAccounts.GetValueOrDefault());
|
||||
}
|
||||
@ -495,8 +490,8 @@ public class OrganizationService : IOrganizationService
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.Signup, organization, _currentContext)
|
||||
{
|
||||
PlanName = passwordManagerPlan.Name,
|
||||
PlanType = passwordManagerPlan.Type,
|
||||
PlanName = plan.Name,
|
||||
PlanType = plan.Type,
|
||||
Seats = returnValue.Item1.Seats,
|
||||
Storage = returnValue.Item1.MaxStorageGb,
|
||||
// TODO: add reference events for SmSeats and Service Accounts - see AC-1481
|
||||
@ -525,7 +520,7 @@ public class OrganizationService : IOrganizationService
|
||||
}
|
||||
|
||||
if (license.PlanType != PlanType.Custom &&
|
||||
StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == license.PlanType && !p.Disabled) == null)
|
||||
StaticStore.Plans.FirstOrDefault(p => p.Type == license.PlanType && !p.Disabled) == null)
|
||||
{
|
||||
throw new BadRequestException("Plan not found.");
|
||||
}
|
||||
@ -1955,11 +1950,6 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException($"{productType} Plan not found.");
|
||||
}
|
||||
|
||||
if (plan.BaseSeats + additionalSeats <= 0)
|
||||
{
|
||||
throw new BadRequestException($"You do not have any {productType} seats!");
|
||||
}
|
||||
|
||||
if (additionalSeats < 0)
|
||||
{
|
||||
throw new BadRequestException($"You can't subtract {productType} seats!");
|
||||
@ -1970,7 +1960,7 @@ public class OrganizationService : IOrganizationService
|
||||
{
|
||||
ValidatePlan(plan, upgrade.AdditionalSeats, "Password Manager");
|
||||
|
||||
if (plan.BaseSeats + upgrade.AdditionalSeats <= 0)
|
||||
if (plan.PasswordManager.BaseSeats + upgrade.AdditionalSeats <= 0)
|
||||
{
|
||||
throw new BadRequestException($"You do not have any Password Manager seats!");
|
||||
}
|
||||
@ -1980,7 +1970,7 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException($"You can't subtract Password Manager seats!");
|
||||
}
|
||||
|
||||
if (!plan.HasAdditionalStorageOption && upgrade.AdditionalStorageGb > 0)
|
||||
if (!plan.PasswordManager.HasAdditionalStorageOption && upgrade.AdditionalStorageGb > 0)
|
||||
{
|
||||
throw new BadRequestException("Plan does not allow additional storage.");
|
||||
}
|
||||
@ -1990,29 +1980,39 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException("You can't subtract storage!");
|
||||
}
|
||||
|
||||
if (!plan.HasPremiumAccessOption && upgrade.PremiumAccessAddon)
|
||||
if (!plan.PasswordManager.HasPremiumAccessOption && upgrade.PremiumAccessAddon)
|
||||
{
|
||||
throw new BadRequestException("This plan does not allow you to buy the premium access addon.");
|
||||
}
|
||||
|
||||
if (!plan.HasAdditionalSeatsOption && upgrade.AdditionalSeats > 0)
|
||||
if (!plan.PasswordManager.HasAdditionalSeatsOption && upgrade.AdditionalSeats > 0)
|
||||
{
|
||||
throw new BadRequestException("Plan does not allow additional users.");
|
||||
}
|
||||
|
||||
if (plan.HasAdditionalSeatsOption && plan.MaxAdditionalSeats.HasValue &&
|
||||
upgrade.AdditionalSeats > plan.MaxAdditionalSeats.Value)
|
||||
if (plan.PasswordManager.HasAdditionalSeatsOption && plan.PasswordManager.MaxAdditionalSeats.HasValue &&
|
||||
upgrade.AdditionalSeats > plan.PasswordManager.MaxAdditionalSeats.Value)
|
||||
{
|
||||
throw new BadRequestException($"Selected plan allows a maximum of " +
|
||||
$"{plan.MaxAdditionalSeats.GetValueOrDefault(0)} additional users.");
|
||||
$"{plan.PasswordManager.MaxAdditionalSeats.GetValueOrDefault(0)} additional users.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ValidateSecretsManagerPlan(Models.StaticStore.Plan plan, OrganizationUpgrade upgrade)
|
||||
{
|
||||
if (plan.SupportsSecretsManager == false)
|
||||
{
|
||||
throw new BadRequestException("Invalid Secrets Manager plan selected.");
|
||||
}
|
||||
|
||||
ValidatePlan(plan, upgrade.AdditionalSmSeats.GetValueOrDefault(), "Secrets Manager");
|
||||
|
||||
if (!plan.HasAdditionalServiceAccountOption && upgrade.AdditionalServiceAccounts > 0)
|
||||
if (plan.SecretsManager.BaseSeats + upgrade.AdditionalSmSeats <= 0)
|
||||
{
|
||||
throw new BadRequestException($"You do not have any Secrets Manager seats!");
|
||||
}
|
||||
|
||||
if (!plan.SecretsManager.HasAdditionalServiceAccountOption && upgrade.AdditionalServiceAccounts > 0)
|
||||
{
|
||||
throw new BadRequestException("Plan does not allow additional Service Accounts.");
|
||||
}
|
||||
@ -2027,14 +2027,14 @@ public class OrganizationService : IOrganizationService
|
||||
throw new BadRequestException("You can't subtract Service Accounts!");
|
||||
}
|
||||
|
||||
switch (plan.HasAdditionalSeatsOption)
|
||||
switch (plan.SecretsManager.HasAdditionalSeatsOption)
|
||||
{
|
||||
case false when upgrade.AdditionalSmSeats > 0:
|
||||
throw new BadRequestException("Plan does not allow additional users.");
|
||||
case true when plan.MaxAdditionalSeats.HasValue &&
|
||||
upgrade.AdditionalSmSeats > plan.MaxAdditionalSeats.Value:
|
||||
case true when plan.SecretsManager.MaxAdditionalSeats.HasValue &&
|
||||
upgrade.AdditionalSmSeats > plan.SecretsManager.MaxAdditionalSeats.Value:
|
||||
throw new BadRequestException($"Selected plan allows a maximum of " +
|
||||
$"{plan.MaxAdditionalSeats.GetValueOrDefault(0)} additional users.");
|
||||
$"{plan.SecretsManager.MaxAdditionalSeats.GetValueOrDefault(0)} additional users.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2457,7 +2457,7 @@ public class OrganizationService : IOrganizationService
|
||||
|
||||
public async Task CreatePendingOrganization(Organization organization, string ownerEmail, ClaimsPrincipal user, IUserService userService, bool salesAssistedTrialStarted)
|
||||
{
|
||||
var plan = StaticStore.PasswordManagerPlans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
if (plan is not { LegacyYear: null })
|
||||
{
|
||||
throw new BadRequestException("Invalid plan selected.");
|
||||
|
@ -49,7 +49,7 @@ public class StripePaymentService : IPaymentService
|
||||
}
|
||||
|
||||
public async Task<string> PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType,
|
||||
string paymentToken, List<StaticStore.Plan> plans, short additionalStorageGb,
|
||||
string paymentToken, StaticStore.Plan plan, short additionalStorageGb,
|
||||
int additionalSeats, bool premiumAccessAddon, TaxInfo taxInfo, bool provider = false,
|
||||
int additionalSmSeats = 0, int additionalServiceAccount = 0)
|
||||
{
|
||||
@ -119,7 +119,7 @@ public class StripePaymentService : IPaymentService
|
||||
}
|
||||
}
|
||||
|
||||
var subCreateOptions = new OrganizationPurchaseSubscriptionOptions(org, plans, taxInfo, additionalSeats, additionalStorageGb, premiumAccessAddon
|
||||
var subCreateOptions = new OrganizationPurchaseSubscriptionOptions(org, plan, taxInfo, additionalSeats, additionalStorageGb, premiumAccessAddon
|
||||
, additionalSmSeats, additionalServiceAccount);
|
||||
|
||||
Stripe.Customer customer = null;
|
||||
@ -211,7 +211,7 @@ public class StripePaymentService : IPaymentService
|
||||
|
||||
private async Task ChangeOrganizationSponsorship(Organization org, OrganizationSponsorship sponsorship, bool applySponsorship)
|
||||
{
|
||||
var existingPlan = Utilities.StaticStore.GetPasswordManagerPlan(org.PlanType);
|
||||
var existingPlan = Utilities.StaticStore.GetPlan(org.PlanType);
|
||||
var sponsoredPlan = sponsorship != null ?
|
||||
Utilities.StaticStore.GetSponsoredPlan(sponsorship.PlanSponsorshipType.Value) :
|
||||
null;
|
||||
@ -231,7 +231,7 @@ public class StripePaymentService : IPaymentService
|
||||
public Task RemoveOrganizationSponsorshipAsync(Organization org, OrganizationSponsorship sponsorship) =>
|
||||
ChangeOrganizationSponsorship(org, sponsorship, false);
|
||||
|
||||
public async Task<string> UpgradeFreeOrganizationAsync(Organization org, List<StaticStore.Plan> plans,
|
||||
public async Task<string> UpgradeFreeOrganizationAsync(Organization org, StaticStore.Plan plan,
|
||||
OrganizationUpgrade upgrade)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(org.GatewaySubscriptionId))
|
||||
@ -266,7 +266,7 @@ public class StripePaymentService : IPaymentService
|
||||
}
|
||||
}
|
||||
|
||||
var subCreateOptions = new OrganizationUpgradeSubscriptionOptions(customer.Id, org, plans, upgrade);
|
||||
var subCreateOptions = new OrganizationUpgradeSubscriptionOptions(customer.Id, org, plan, upgrade);
|
||||
var (stripePaymentMethod, paymentMethodType) = IdentifyPaymentMethod(customer, subCreateOptions);
|
||||
|
||||
var subscription = await ChargeForNewSubscriptionAsync(org, customer, false,
|
||||
|
@ -1,398 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
|
||||
namespace Bit.Core.Utilities;
|
||||
|
||||
public static class PasswordManagerPlanStore
|
||||
{
|
||||
public static IEnumerable<Plan> CreatePlan()
|
||||
{
|
||||
return new List<Plan>
|
||||
{
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.Free,
|
||||
Product = ProductType.Free,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Free",
|
||||
NameLocalizationKey = "planNameFree",
|
||||
DescriptionLocalizationKey = "planDescFree",
|
||||
BaseSeats = 2,
|
||||
MaxCollections = 2,
|
||||
MaxUsers = 2,
|
||||
|
||||
UpgradeSortOrder = -1, // Always the lowest plan, cannot be upgraded to
|
||||
DisplaySortOrder = -1,
|
||||
|
||||
AllowSeatAutoscale = false,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.FamiliesAnnually2019,
|
||||
Product = ProductType.Families,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Families 2019",
|
||||
IsAnnual = true,
|
||||
NameLocalizationKey = "planNameFamilies",
|
||||
DescriptionLocalizationKey = "planDescFamilies",
|
||||
BaseSeats = 5,
|
||||
BaseStorageGb = 1,
|
||||
MaxUsers = 5,
|
||||
|
||||
HasAdditionalStorageOption = true,
|
||||
HasPremiumAccessOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasSelfHost = true,
|
||||
HasTotp = true,
|
||||
|
||||
UpgradeSortOrder = 1,
|
||||
DisplaySortOrder = 1,
|
||||
LegacyYear = 2020,
|
||||
|
||||
StripePlanId = "personal-org-annually",
|
||||
StripeStoragePlanId = "storage-gb-annually",
|
||||
StripePremiumAccessPlanId = "personal-org-premium-access-annually",
|
||||
BasePrice = 12,
|
||||
AdditionalStoragePricePerGb = 4,
|
||||
PremiumAccessOptionPrice = 40,
|
||||
|
||||
AllowSeatAutoscale = false,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.TeamsAnnually2019,
|
||||
Product = ProductType.Teams,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Teams (Annually) 2019",
|
||||
IsAnnual = true,
|
||||
NameLocalizationKey = "planNameTeams",
|
||||
DescriptionLocalizationKey = "planDescTeams",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 5,
|
||||
BaseStorageGb = 1,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasTotp = true,
|
||||
|
||||
UpgradeSortOrder = 2,
|
||||
DisplaySortOrder = 2,
|
||||
LegacyYear = 2020,
|
||||
|
||||
StripePlanId = "teams-org-annually",
|
||||
StripeSeatPlanId = "teams-org-seat-annually",
|
||||
StripeStoragePlanId = "storage-gb-annually",
|
||||
BasePrice = 60,
|
||||
SeatPrice = 24,
|
||||
AdditionalStoragePricePerGb = 4,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.TeamsMonthly2019,
|
||||
Product = ProductType.Teams,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Teams (Monthly) 2019",
|
||||
NameLocalizationKey = "planNameTeams",
|
||||
DescriptionLocalizationKey = "planDescTeams",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 5,
|
||||
BaseStorageGb = 1,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasTotp = true,
|
||||
|
||||
UpgradeSortOrder = 2,
|
||||
DisplaySortOrder = 2,
|
||||
LegacyYear = 2020,
|
||||
|
||||
StripePlanId = "teams-org-monthly",
|
||||
StripeSeatPlanId = "teams-org-seat-monthly",
|
||||
StripeStoragePlanId = "storage-gb-monthly",
|
||||
BasePrice = 8,
|
||||
SeatPrice = 2.5M,
|
||||
AdditionalStoragePricePerGb = 0.5M,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.EnterpriseAnnually2019,
|
||||
Name = "Enterprise (Annually) 2019",
|
||||
IsAnnual = true,
|
||||
Product = ProductType.Enterprise,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
NameLocalizationKey = "planNameEnterprise",
|
||||
DescriptionLocalizationKey = "planDescEnterprise",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseStorageGb = 1,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasPolicies = true,
|
||||
HasSelfHost = true,
|
||||
HasGroups = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasTotp = true,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
UsersGetPremium = true,
|
||||
HasCustomPermissions = true,
|
||||
|
||||
UpgradeSortOrder = 3,
|
||||
DisplaySortOrder = 3,
|
||||
LegacyYear = 2020,
|
||||
|
||||
StripePlanId = null,
|
||||
StripeSeatPlanId = "enterprise-org-seat-annually",
|
||||
StripeStoragePlanId = "storage-gb-annually",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 36,
|
||||
AdditionalStoragePricePerGb = 4,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.EnterpriseMonthly2019,
|
||||
Product = ProductType.Enterprise,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Enterprise (Monthly) 2019",
|
||||
NameLocalizationKey = "planNameEnterprise",
|
||||
DescriptionLocalizationKey = "planDescEnterprise",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseStorageGb = 1,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasPolicies = true,
|
||||
HasGroups = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasTotp = true,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasSelfHost = true,
|
||||
UsersGetPremium = true,
|
||||
HasCustomPermissions = true,
|
||||
|
||||
UpgradeSortOrder = 3,
|
||||
DisplaySortOrder = 3,
|
||||
LegacyYear = 2020,
|
||||
|
||||
StripePlanId = null,
|
||||
StripeSeatPlanId = "enterprise-org-seat-monthly",
|
||||
StripeStoragePlanId = "storage-gb-monthly",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 4M,
|
||||
AdditionalStoragePricePerGb = 0.5M,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.FamiliesAnnually,
|
||||
Product = ProductType.Families,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Families",
|
||||
IsAnnual = true,
|
||||
NameLocalizationKey = "planNameFamilies",
|
||||
DescriptionLocalizationKey = "planDescFamilies",
|
||||
BaseSeats = 6,
|
||||
BaseStorageGb = 1,
|
||||
MaxUsers = 6,
|
||||
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasSelfHost = true,
|
||||
HasTotp = true,
|
||||
UsersGetPremium = true,
|
||||
|
||||
UpgradeSortOrder = 1,
|
||||
DisplaySortOrder = 1,
|
||||
|
||||
StripePlanId = "2020-families-org-annually",
|
||||
StripeStoragePlanId = "storage-gb-annually",
|
||||
BasePrice = 40,
|
||||
AdditionalStoragePricePerGb = 4,
|
||||
|
||||
AllowSeatAutoscale = false,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.TeamsAnnually,
|
||||
Product = ProductType.Teams,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Teams (Annually)",
|
||||
IsAnnual = true,
|
||||
NameLocalizationKey = "planNameTeams",
|
||||
DescriptionLocalizationKey = "planDescTeams",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseStorageGb = 1,
|
||||
BaseSeats = 0,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasGroups = true,
|
||||
HasTotp = true,
|
||||
UsersGetPremium = true,
|
||||
|
||||
UpgradeSortOrder = 2,
|
||||
DisplaySortOrder = 2,
|
||||
|
||||
StripeSeatPlanId = "2020-teams-org-seat-annually",
|
||||
StripeStoragePlanId = "storage-gb-annually",
|
||||
SeatPrice = 36,
|
||||
AdditionalStoragePricePerGb = 4,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.TeamsMonthly,
|
||||
Product = ProductType.Teams,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Teams (Monthly)",
|
||||
NameLocalizationKey = "planNameTeams",
|
||||
DescriptionLocalizationKey = "planDescTeams",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseStorageGb = 1,
|
||||
BaseSeats = 0,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasGroups = true,
|
||||
HasTotp = true,
|
||||
UsersGetPremium = true,
|
||||
|
||||
UpgradeSortOrder = 2,
|
||||
DisplaySortOrder = 2,
|
||||
|
||||
StripeSeatPlanId = "2020-teams-org-seat-monthly",
|
||||
StripeStoragePlanId = "storage-gb-monthly",
|
||||
SeatPrice = 4,
|
||||
AdditionalStoragePricePerGb = 0.5M,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.EnterpriseAnnually,
|
||||
Name = "Enterprise (Annually)",
|
||||
Product = ProductType.Enterprise,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
IsAnnual = true,
|
||||
NameLocalizationKey = "planNameEnterprise",
|
||||
DescriptionLocalizationKey = "planDescEnterprise",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseStorageGb = 1,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasPolicies = true,
|
||||
HasSelfHost = true,
|
||||
HasGroups = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasTotp = true,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasSso = true,
|
||||
HasKeyConnector = true,
|
||||
HasScim = true,
|
||||
HasResetPassword = true,
|
||||
UsersGetPremium = true,
|
||||
HasCustomPermissions = true,
|
||||
|
||||
UpgradeSortOrder = 3,
|
||||
DisplaySortOrder = 3,
|
||||
|
||||
StripeSeatPlanId = "2020-enterprise-org-seat-annually",
|
||||
StripeStoragePlanId = "storage-gb-annually",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 60,
|
||||
AdditionalStoragePricePerGb = 4,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.EnterpriseMonthly,
|
||||
Product = ProductType.Enterprise,
|
||||
BitwardenProduct = BitwardenProductType.PasswordManager,
|
||||
Name = "Enterprise (Monthly)",
|
||||
NameLocalizationKey = "planNameEnterprise",
|
||||
DescriptionLocalizationKey = "planDescEnterprise",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseStorageGb = 1,
|
||||
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalStorageOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
|
||||
HasPolicies = true,
|
||||
HasGroups = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasTotp = true,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasSelfHost = true,
|
||||
HasSso = true,
|
||||
HasKeyConnector = true,
|
||||
HasScim = true,
|
||||
HasResetPassword = true,
|
||||
UsersGetPremium = true,
|
||||
HasCustomPermissions = true,
|
||||
|
||||
UpgradeSortOrder = 3,
|
||||
DisplaySortOrder = 3,
|
||||
|
||||
StripeSeatPlanId = "2020-enterprise-seat-monthly",
|
||||
StripeStoragePlanId = "storage-gb-monthly",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 6,
|
||||
AdditionalStoragePricePerGb = 0.5M,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.Custom,
|
||||
|
||||
AllowSeatAutoscale = true,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
|
||||
namespace Bit.Core.Utilities;
|
||||
|
||||
public static class SecretsManagerPlanStore
|
||||
{
|
||||
public static IEnumerable<Plan> CreatePlan()
|
||||
{
|
||||
return new List<Plan>
|
||||
{
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.EnterpriseMonthly,
|
||||
Product = ProductType.Enterprise,
|
||||
BitwardenProduct = BitwardenProductType.SecretsManager,
|
||||
Name = "Enterprise (Monthly)",
|
||||
NameLocalizationKey = "planNameEnterprise",
|
||||
DescriptionLocalizationKey = "planDescEnterprise",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseServiceAccount = 200,
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalServiceAccountOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
HasPolicies = true,
|
||||
HasGroups = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasTotp = true,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasSelfHost = true,
|
||||
HasSso = true,
|
||||
HasKeyConnector = true,
|
||||
HasScim = true,
|
||||
HasResetPassword = true,
|
||||
UsersGetPremium = true,
|
||||
HasCustomPermissions = true,
|
||||
UpgradeSortOrder = 3,
|
||||
DisplaySortOrder = 3,
|
||||
StripeSeatPlanId = "secrets-manager-enterprise-seat-monthly",
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-monthly",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 13,
|
||||
AdditionalPricePerServiceAccount = 0.5M,
|
||||
AllowSeatAutoscale = true,
|
||||
AllowServiceAccountsAutoscale = true
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.EnterpriseAnnually,
|
||||
Name = "Enterprise (Annually)",
|
||||
Product = ProductType.Enterprise,
|
||||
BitwardenProduct = BitwardenProductType.SecretsManager,
|
||||
IsAnnual = true,
|
||||
NameLocalizationKey = "planNameEnterprise",
|
||||
DescriptionLocalizationKey = "planDescEnterprise",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseServiceAccount = 200,
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalServiceAccountOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
HasPolicies = true,
|
||||
HasSelfHost = true,
|
||||
HasGroups = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasTotp = true,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasSso = true,
|
||||
HasKeyConnector = true,
|
||||
HasScim = true,
|
||||
HasResetPassword = true,
|
||||
UsersGetPremium = true,
|
||||
HasCustomPermissions = true,
|
||||
UpgradeSortOrder = 3,
|
||||
DisplaySortOrder = 3,
|
||||
StripeSeatPlanId = "secrets-manager-enterprise-seat-annually",
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-annually",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 144,
|
||||
AdditionalPricePerServiceAccount = 6,
|
||||
AllowSeatAutoscale = true,
|
||||
AllowServiceAccountsAutoscale = true
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.TeamsMonthly,
|
||||
Name = "Teams (Monthly)",
|
||||
Product = ProductType.Teams,
|
||||
BitwardenProduct = BitwardenProductType.SecretsManager,
|
||||
NameLocalizationKey = "planNameTeams",
|
||||
DescriptionLocalizationKey = "planDescTeams",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseServiceAccount = 50,
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalServiceAccountOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasGroups = true,
|
||||
HasTotp = true,
|
||||
UsersGetPremium = true,
|
||||
UpgradeSortOrder = 2,
|
||||
DisplaySortOrder = 2,
|
||||
StripeSeatPlanId = "secrets-manager-teams-seat-monthly",
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-monthly",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 7,
|
||||
AdditionalPricePerServiceAccount = 0.5M,
|
||||
AllowSeatAutoscale = true,
|
||||
AllowServiceAccountsAutoscale = true
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.TeamsAnnually,
|
||||
Name = "Teams (Annually)",
|
||||
Product = ProductType.Teams,
|
||||
BitwardenProduct = BitwardenProductType.SecretsManager,
|
||||
IsAnnual = true,
|
||||
NameLocalizationKey = "planNameTeams",
|
||||
DescriptionLocalizationKey = "planDescTeams",
|
||||
CanBeUsedByBusiness = true,
|
||||
BaseSeats = 0,
|
||||
BaseServiceAccount = 50,
|
||||
HasAdditionalSeatsOption = true,
|
||||
HasAdditionalServiceAccountOption = true,
|
||||
TrialPeriodDays = 7,
|
||||
Has2fa = true,
|
||||
HasApi = true,
|
||||
HasDirectory = true,
|
||||
HasEvents = true,
|
||||
HasGroups = true,
|
||||
HasTotp = true,
|
||||
UsersGetPremium = true,
|
||||
|
||||
UpgradeSortOrder = 2,
|
||||
DisplaySortOrder = 2,
|
||||
StripeSeatPlanId = "secrets-manager-teams-seat-annually",
|
||||
StripeServiceAccountPlanId = "secrets-manager-service-account-annually",
|
||||
BasePrice = 0,
|
||||
SeatPrice = 72,
|
||||
AdditionalPricePerServiceAccount = 6,
|
||||
AllowSeatAutoscale = true,
|
||||
AllowServiceAccountsAutoscale = true
|
||||
},
|
||||
new Plan
|
||||
{
|
||||
Type = PlanType.Free,
|
||||
Product = ProductType.Free,
|
||||
BitwardenProduct = BitwardenProductType.SecretsManager,
|
||||
Name = "Free",
|
||||
NameLocalizationKey = "planNameFree",
|
||||
DescriptionLocalizationKey = "planDescFree",
|
||||
BaseSeats = 2,
|
||||
BaseServiceAccount = 3,
|
||||
MaxProjects = 3,
|
||||
MaxUsers = 2,
|
||||
MaxServiceAccounts = 3,
|
||||
UpgradeSortOrder = -1, // Always the lowest plan, cannot be upgraded to
|
||||
DisplaySortOrder = -1,
|
||||
AllowSeatAutoscale = false,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
using Bit.Core.Enums;
|
||||
using System.Collections.Immutable;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
using Bit.Core.Models.StaticStore.Plans;
|
||||
|
||||
namespace Bit.Core.Utilities;
|
||||
|
||||
@ -104,21 +106,26 @@ public class StaticStore
|
||||
GlobalDomains.Add(GlobalEquivalentDomainsType.Pinterest, new List<string> { "pinterest.com", "pinterest.com.au", "pinterest.cl", "pinterest.de", "pinterest.dk", "pinterest.es", "pinterest.fr", "pinterest.co.uk", "pinterest.jp", "pinterest.co.kr", "pinterest.nz", "pinterest.pt", "pinterest.se" });
|
||||
#endregion
|
||||
|
||||
#region Plans
|
||||
Plans = new List<Models.StaticStore.Plan>
|
||||
{
|
||||
new EnterprisePlan(true),
|
||||
new EnterprisePlan(false),
|
||||
new TeamsPlan(true),
|
||||
new TeamsPlan(false),
|
||||
new FamiliesPlan(),
|
||||
new FreePlan(),
|
||||
new CustomPlan(),
|
||||
|
||||
PasswordManagerPlans = PasswordManagerPlanStore.CreatePlan();
|
||||
SecretManagerPlans = SecretsManagerPlanStore.CreatePlan();
|
||||
|
||||
Plans = PasswordManagerPlans.Concat(SecretManagerPlans);
|
||||
|
||||
|
||||
#endregion
|
||||
new Enterprise2019Plan(true),
|
||||
new Enterprise2019Plan(false),
|
||||
new Teams2019Plan(true),
|
||||
new Teams2019Plan(false),
|
||||
new Families2019Plan(),
|
||||
}.ToImmutableList();
|
||||
}
|
||||
|
||||
public static IDictionary<GlobalEquivalentDomainsType, IEnumerable<string>> GlobalDomains { get; set; }
|
||||
public static IEnumerable<Plan> Plans { get; set; }
|
||||
public static IEnumerable<Plan> SecretManagerPlans { get; set; }
|
||||
public static IEnumerable<Plan> PasswordManagerPlans { get; set; }
|
||||
public static IEnumerable<Models.StaticStore.Plan> Plans { get; }
|
||||
public static IEnumerable<SponsoredPlan> SponsoredPlans { get; set; } = new[]
|
||||
{
|
||||
new SponsoredPlan
|
||||
@ -128,21 +135,20 @@ public class StaticStore
|
||||
SponsoringProductType = ProductType.Enterprise,
|
||||
StripePlanId = "2021-family-for-enterprise-annually",
|
||||
UsersCanSponsor = (OrganizationUserOrganizationDetails org) =>
|
||||
GetPasswordManagerPlan(org.PlanType).Product == ProductType.Enterprise,
|
||||
GetPlan(org.PlanType).Product == ProductType.Enterprise,
|
||||
}
|
||||
};
|
||||
public static Plan GetPasswordManagerPlan(PlanType planType) =>
|
||||
PasswordManagerPlans.SingleOrDefault(p => p.Type == planType);
|
||||
|
||||
public static Plan GetSecretsManagerPlan(PlanType planType) =>
|
||||
SecretManagerPlans.SingleOrDefault(p => p.Type == planType);
|
||||
public static Models.StaticStore.Plan GetPlan(PlanType planType) =>
|
||||
Plans.SingleOrDefault(p => p.Type == planType);
|
||||
|
||||
|
||||
public static SponsoredPlan GetSponsoredPlan(PlanSponsorshipType planSponsorshipType) =>
|
||||
SponsoredPlans.FirstOrDefault(p => p.PlanSponsorshipType == planSponsorshipType);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the stripe plan id is an addon item by checking if the provided stripe plan id
|
||||
/// matches either the <see cref="Plan.StripeStoragePlanId"/> or <see cref="Plan.StripeServiceAccountPlanId"/>
|
||||
/// matches either the <see cref="Plan.PasswordManagerPlanFeatures.StripeStoragePlanId"/> or <see cref="Plan.SecretsManagerPlanFeatures.StripeServiceAccountPlanId"/>
|
||||
/// in any <see cref="Plans"/>.
|
||||
/// </summary>
|
||||
/// <param name="stripePlanId"></param>
|
||||
@ -151,41 +157,8 @@ public class StaticStore
|
||||
/// </returns>
|
||||
public static bool IsAddonSubscriptionItem(string stripePlanId)
|
||||
{
|
||||
if (PasswordManagerPlans.Select(p => p.StripeStoragePlanId).Contains(stripePlanId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SecretManagerPlans.Select(p => p.StripeServiceAccountPlanId).Contains(stripePlanId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="Plan"/> by comparing the provided stripeId to the various
|
||||
/// Stripe plan ids within a <see cref="Plan"/>.
|
||||
/// The following <see cref="Plan"/> properties are checked:
|
||||
/// <list type="bullet">
|
||||
/// <item><see cref="Plan.StripePlanId"/></item>
|
||||
/// <item><see cref="Plan.StripeSeatPlanId"/></item>
|
||||
/// <item><see cref="Plan.StripeStoragePlanId"/></item>
|
||||
/// <item><see cref="Plan.StripeServiceAccountPlanId"/></item>
|
||||
/// <item><see cref="Plan.StripePremiumAccessPlanId"/></item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <param name="stripeId"></param>
|
||||
/// <returns>The plan if a matching stripeId was found, null otherwise</returns>
|
||||
public static Plan GetPlanByStripeId(string stripeId)
|
||||
{
|
||||
return Plans.FirstOrDefault(p =>
|
||||
p.StripePlanId == stripeId ||
|
||||
p.StripeSeatPlanId == stripeId ||
|
||||
p.StripeStoragePlanId == stripeId ||
|
||||
p.StripeServiceAccountPlanId == stripeId ||
|
||||
p.StripePremiumAccessPlanId == stripeId
|
||||
);
|
||||
return Plans.Any(p =>
|
||||
p.PasswordManager.StripeStoragePlanId == stripePlanId ||
|
||||
(p.SecretsManager?.StripeServiceAccountPlanId == stripePlanId));
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,11 @@ namespace Bit.Api.Test.Controllers;
|
||||
public class OrganizationSponsorshipsControllerTests
|
||||
{
|
||||
public static IEnumerable<object[]> EnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPasswordManagerPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonEnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPasswordManagerPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonFamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPasswordManagerPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
|
||||
Enum.GetValues<OrganizationUserStatusType>()
|
||||
|
@ -73,7 +73,7 @@ public class SyncControllerTests
|
||||
user.EquivalentDomains = JsonSerializer.Serialize(userEquivalentDomains);
|
||||
user.ExcludedGlobalEquivalentDomains = JsonSerializer.Serialize(userExcludedGlobalEquivalentDomains);
|
||||
|
||||
// At least 1 org needs to be enabled to fully test
|
||||
// At least 1 org needs to be enabled to fully test
|
||||
if (!organizationUserDetails.Any(o => o.Enabled))
|
||||
{
|
||||
// We need at least 1 enabled org
|
||||
@ -165,7 +165,7 @@ public class SyncControllerTests
|
||||
user.EquivalentDomains = JsonSerializer.Serialize(userEquivalentDomains);
|
||||
user.ExcludedGlobalEquivalentDomains = JsonSerializer.Serialize(userExcludedGlobalEquivalentDomains);
|
||||
|
||||
// All orgs disabled
|
||||
// All orgs disabled
|
||||
if (organizationUserDetails.Count > 0)
|
||||
{
|
||||
foreach (var orgUserDetails in organizationUserDetails)
|
||||
@ -218,7 +218,7 @@ public class SyncControllerTests
|
||||
|
||||
Assert.IsType<SyncResponseModel>(result);
|
||||
|
||||
// Collections should be empty when all standard orgs are disabled.
|
||||
// Collections should be empty when all standard orgs are disabled.
|
||||
Assert.Empty(result.Collections);
|
||||
}
|
||||
|
||||
@ -297,7 +297,7 @@ public class SyncControllerTests
|
||||
Assert.IsType<SyncResponseModel>(result);
|
||||
|
||||
// Look up ProviderOrg output and compare to ProviderOrg method inputs to ensure
|
||||
// product type is set correctly.
|
||||
// product type is set correctly.
|
||||
foreach (var profProviderOrg in result.Profile.ProviderOrganizations)
|
||||
{
|
||||
var matchedProviderUserOrgDetails =
|
||||
@ -305,7 +305,7 @@ public class SyncControllerTests
|
||||
|
||||
if (matchedProviderUserOrgDetails != null)
|
||||
{
|
||||
var providerOrgProductType = StaticStore.GetPasswordManagerPlan(matchedProviderUserOrgDetails.PlanType).Product;
|
||||
var providerOrgProductType = StaticStore.GetPlan(matchedProviderUserOrgDetails.PlanType).Product;
|
||||
Assert.Equal(providerOrgProductType, profProviderOrg.PlanProductType);
|
||||
}
|
||||
}
|
||||
@ -337,7 +337,7 @@ public class SyncControllerTests
|
||||
await sendRepository.ReceivedWithAnyArgs(1)
|
||||
.GetManyByUserIdAsync(default);
|
||||
|
||||
// These two are only called when at least 1 enabled org.
|
||||
// These two are only called when at least 1 enabled org.
|
||||
if (hasEnabledOrgs)
|
||||
{
|
||||
await collectionRepository.ReceivedWithAnyArgs(1)
|
||||
@ -347,7 +347,7 @@ public class SyncControllerTests
|
||||
}
|
||||
else
|
||||
{
|
||||
// all disabled orgs
|
||||
// all disabled orgs
|
||||
await collectionRepository.ReceivedWithAnyArgs(0)
|
||||
.GetManyByUserIdAsync(default);
|
||||
await collectionCipherRepository.ReceivedWithAnyArgs(0)
|
||||
|
@ -66,7 +66,7 @@ internal class PaidOrganization : ICustomization
|
||||
public PlanType CheckedPlanType { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
var validUpgradePlans = StaticStore.PasswordManagerPlans.Where(p => p.Type != PlanType.Free && p.LegacyYear == null).OrderBy(p => p.UpgradeSortOrder).Select(p => p.Type).ToList();
|
||||
var validUpgradePlans = StaticStore.Plans.Where(p => p.Type != PlanType.Free && p.LegacyYear == null).OrderBy(p => p.UpgradeSortOrder).Select(p => p.Type).ToList();
|
||||
var lowestActivePaidPlan = validUpgradePlans.First();
|
||||
CheckedPlanType = CheckedPlanType.Equals(PlanType.Free) ? lowestActivePaidPlan : CheckedPlanType;
|
||||
validUpgradePlans.Remove(lowestActivePaidPlan);
|
||||
@ -94,11 +94,11 @@ internal class FreeOrganizationUpgrade : ICustomization
|
||||
.With(o => o.PlanType, PlanType.Free));
|
||||
|
||||
var plansToIgnore = new List<PlanType> { PlanType.Free, PlanType.Custom };
|
||||
var selectedPlan = StaticStore.PasswordManagerPlans.Last(p => !plansToIgnore.Contains(p.Type) && !p.Disabled);
|
||||
var selectedPlan = StaticStore.Plans.Last(p => !plansToIgnore.Contains(p.Type) && !p.Disabled);
|
||||
|
||||
fixture.Customize<OrganizationUpgrade>(composer => composer
|
||||
.With(ou => ou.Plan, selectedPlan.Type)
|
||||
.With(ou => ou.PremiumAccessAddon, selectedPlan.HasPremiumAccessOption));
|
||||
.With(ou => ou.PremiumAccessAddon, selectedPlan.PasswordManager.HasPremiumAccessOption));
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.Without(o => o.GatewaySubscriptionId));
|
||||
}
|
||||
@ -140,7 +140,7 @@ public class SecretsManagerOrganizationCustomization : ICustomization
|
||||
.With(o => o.UseSecretsManager, true)
|
||||
.With(o => o.SecretsManagerBeta, false)
|
||||
.With(o => o.PlanType, planType)
|
||||
.With(o => o.Plan, StaticStore.GetPasswordManagerPlan(planType).Name)
|
||||
.With(o => o.Plan, StaticStore.GetPlan(planType).Name)
|
||||
.With(o => o.MaxAutoscaleSmSeats, (int?)null)
|
||||
.With(o => o.MaxAutoscaleSmServiceAccounts, (int?)null)
|
||||
);
|
||||
|
@ -6,16 +6,16 @@ namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesFo
|
||||
public abstract class FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
public static IEnumerable<object[]> EnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPasswordManagerPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonEnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPasswordManagerPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> FamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPasswordManagerPlan(p).Product == ProductType.Families).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Families).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonFamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPasswordManagerPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
|
||||
Enum.GetValues<OrganizationUserStatusType>()
|
||||
|
@ -32,7 +32,7 @@ public class AddSecretsManagerSubscriptionCommandTests
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
|
||||
await sutProvider.Sut.SignUpAsync(organization, additionalSmSeats, additionalServiceAccounts);
|
||||
|
||||
@ -49,8 +49,8 @@ public class AddSecretsManagerSubscriptionCommandTests
|
||||
// TODO: call ReferenceEventService - see AC-1481
|
||||
|
||||
sutProvider.GetDependency<IOrganizationService>().Received(1).ReplaceAndUpdateCacheAsync(Arg.Is<Organization>(c =>
|
||||
c.SmSeats == plan.BaseSeats + additionalSmSeats &&
|
||||
c.SmServiceAccounts == plan.BaseServiceAccount.GetValueOrDefault() + additionalServiceAccounts &&
|
||||
c.SmSeats == plan.SecretsManager.BaseSeats + additionalSmSeats &&
|
||||
c.SmServiceAccounts == plan.SecretsManager.BaseServiceAccount + additionalServiceAccounts &&
|
||||
c.UseSecretsManager == true));
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
|
||||
await sutProvider.Sut.UpdateSubscriptionAsync(update);
|
||||
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == organization.PlanType);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
.AdjustSeatsAsync(organization, plan, update.SmSeatsExcludingBase);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
@ -96,7 +96,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
|
||||
await sutProvider.Sut.UpdateSubscriptionAsync(update);
|
||||
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == organization.PlanType);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
.AdjustSeatsAsync(organization, plan, update.SmSeatsExcludingBase);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
@ -213,11 +213,11 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
public async Task AdjustServiceAccountsAsync_WithEnterpriseOrTeamsPlans_Success(PlanType planType, Guid organizationId,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(p => p.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
|
||||
var organizationSeats = plan.BaseSeats + 10;
|
||||
var organizationSeats = plan.SecretsManager.BaseSeats + 10;
|
||||
var organizationMaxAutoscaleSeats = 20;
|
||||
var organizationServiceAccounts = plan.BaseServiceAccount.GetValueOrDefault() + 10;
|
||||
var organizationServiceAccounts = plan.SecretsManager.BaseServiceAccount + 10;
|
||||
var organizationMaxAutoscaleServiceAccounts = 300;
|
||||
|
||||
var organization = new Organization
|
||||
@ -235,7 +235,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
|
||||
var smServiceAccountsAdjustment = 10;
|
||||
var expectedSmServiceAccounts = organizationServiceAccounts + smServiceAccountsAdjustment;
|
||||
var expectedSmServiceAccountsExcludingBase = expectedSmServiceAccounts - plan.BaseServiceAccount.GetValueOrDefault();
|
||||
var expectedSmServiceAccountsExcludingBase = expectedSmServiceAccounts - plan.SecretsManager.BaseServiceAccount;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustServiceAccounts(10);
|
||||
|
||||
|
@ -94,6 +94,7 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
upgrade.AdditionalSmSeats = 10;
|
||||
upgrade.AdditionalSeats = 10;
|
||||
upgrade.Plan = PlanType.TeamsAnnually;
|
||||
await sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade);
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1).ReplaceAndUpdateCacheAsync(organization);
|
||||
}
|
||||
@ -108,8 +109,7 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
{
|
||||
upgrade.Plan = planType;
|
||||
|
||||
var passwordManagerPlan = StaticStore.GetPasswordManagerPlan(upgrade.Plan);
|
||||
var secretsManagerPlan = StaticStore.GetSecretsManagerPlan(upgrade.Plan);
|
||||
var plan = StaticStore.GetPlan(upgrade.Plan);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
|
||||
@ -121,9 +121,9 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1).ReplaceAndUpdateCacheAsync(
|
||||
Arg.Is<Organization>(o =>
|
||||
o.Seats == passwordManagerPlan.BaseSeats + upgrade.AdditionalSeats
|
||||
&& o.SmSeats == secretsManagerPlan.BaseSeats + upgrade.AdditionalSmSeats
|
||||
&& o.SmServiceAccounts == secretsManagerPlan.BaseServiceAccount + upgrade.AdditionalServiceAccounts));
|
||||
o.Seats == plan.PasswordManager.BaseSeats + upgrade.AdditionalSeats
|
||||
&& o.SmSeats == plan.SecretsManager.BaseSeats + upgrade.AdditionalSmSeats
|
||||
&& o.SmServiceAccounts == plan.SecretsManager.BaseServiceAccount + upgrade.AdditionalServiceAccounts));
|
||||
|
||||
Assert.True(result.Item1);
|
||||
Assert.NotNull(result.Item2);
|
||||
|
@ -155,20 +155,20 @@ public class OrganizationServiceTests
|
||||
{
|
||||
signup.Plan = planType;
|
||||
|
||||
var passwordManagerPlan = StaticStore.GetPasswordManagerPlan(signup.Plan);
|
||||
var plan = StaticStore.GetPlan(signup.Plan);
|
||||
|
||||
signup.AdditionalSeats = 0;
|
||||
signup.PaymentMethodType = PaymentMethodType.Card;
|
||||
signup.PremiumAccessAddon = false;
|
||||
signup.UseSecretsManager = false;
|
||||
|
||||
var purchaseOrganizationPlan = StaticStore.Plans.Where(x => x.Type == signup.Plan).ToList();
|
||||
var purchaseOrganizationPlan = StaticStore.GetPlan(signup.Plan);
|
||||
|
||||
var result = await sutProvider.Sut.SignUpAsync(signup);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).CreateAsync(
|
||||
Arg.Is<Organization>(o =>
|
||||
o.Seats == passwordManagerPlan.BaseSeats + signup.AdditionalSeats
|
||||
o.Seats == plan.PasswordManager.BaseSeats + signup.AdditionalSeats
|
||||
&& o.SmSeats == null
|
||||
&& o.SmServiceAccounts == null));
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).CreateAsync(
|
||||
@ -177,8 +177,8 @@ public class OrganizationServiceTests
|
||||
await sutProvider.GetDependency<IReferenceEventService>().Received(1)
|
||||
.RaiseEventAsync(Arg.Is<ReferenceEvent>(referenceEvent =>
|
||||
referenceEvent.Type == ReferenceEventType.Signup &&
|
||||
referenceEvent.PlanName == passwordManagerPlan.Name &&
|
||||
referenceEvent.PlanType == passwordManagerPlan.Type &&
|
||||
referenceEvent.PlanName == plan.Name &&
|
||||
referenceEvent.PlanType == plan.Type &&
|
||||
referenceEvent.Seats == result.Item1.Seats &&
|
||||
referenceEvent.Storage == result.Item1.MaxStorageGb));
|
||||
// TODO: add reference events for SmSeats and Service Accounts - see AC-1481
|
||||
@ -192,7 +192,7 @@ public class OrganizationServiceTests
|
||||
Arg.Any<Organization>(),
|
||||
signup.PaymentMethodType.Value,
|
||||
signup.PaymentToken,
|
||||
Arg.Is<List<Plan>>(plan => plan.Single() == passwordManagerPlan),
|
||||
plan,
|
||||
signup.AdditionalStorageGb,
|
||||
signup.AdditionalSeats,
|
||||
signup.PremiumAccessAddon,
|
||||
@ -212,8 +212,7 @@ public class OrganizationServiceTests
|
||||
{
|
||||
signup.Plan = planType;
|
||||
|
||||
var passwordManagerPlan = StaticStore.GetPasswordManagerPlan(signup.Plan);
|
||||
var secretsManagerPlan = StaticStore.GetSecretsManagerPlan(signup.Plan);
|
||||
var plan = StaticStore.GetPlan(signup.Plan);
|
||||
|
||||
signup.UseSecretsManager = true;
|
||||
signup.AdditionalSeats = 15;
|
||||
@ -222,23 +221,21 @@ public class OrganizationServiceTests
|
||||
signup.PaymentMethodType = PaymentMethodType.Card;
|
||||
signup.PremiumAccessAddon = false;
|
||||
|
||||
var purchaseOrganizationPlan = StaticStore.Plans.Where(x => x.Type == signup.Plan).ToList();
|
||||
|
||||
var result = await sutProvider.Sut.SignUpAsync(signup);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).CreateAsync(
|
||||
Arg.Is<Organization>(o =>
|
||||
o.Seats == passwordManagerPlan.BaseSeats + signup.AdditionalSeats
|
||||
&& o.SmSeats == secretsManagerPlan.BaseSeats + signup.AdditionalSmSeats
|
||||
&& o.SmServiceAccounts == secretsManagerPlan.BaseServiceAccount + signup.AdditionalServiceAccounts));
|
||||
o.Seats == plan.PasswordManager.BaseSeats + signup.AdditionalSeats
|
||||
&& o.SmSeats == plan.SecretsManager.BaseSeats + signup.AdditionalSmSeats
|
||||
&& o.SmServiceAccounts == plan.SecretsManager.BaseServiceAccount + signup.AdditionalServiceAccounts));
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).CreateAsync(
|
||||
Arg.Is<OrganizationUser>(o => o.AccessSecretsManager == signup.UseSecretsManager));
|
||||
|
||||
await sutProvider.GetDependency<IReferenceEventService>().Received(1)
|
||||
.RaiseEventAsync(Arg.Is<ReferenceEvent>(referenceEvent =>
|
||||
referenceEvent.Type == ReferenceEventType.Signup &&
|
||||
referenceEvent.PlanName == purchaseOrganizationPlan[0].Name &&
|
||||
referenceEvent.PlanType == purchaseOrganizationPlan[0].Type &&
|
||||
referenceEvent.PlanName == plan.Name &&
|
||||
referenceEvent.PlanType == plan.Type &&
|
||||
referenceEvent.Seats == result.Item1.Seats &&
|
||||
referenceEvent.Storage == result.Item1.MaxStorageGb));
|
||||
// TODO: add reference events for SmSeats and Service Accounts - see AC-1481
|
||||
@ -252,7 +249,7 @@ public class OrganizationServiceTests
|
||||
Arg.Any<Organization>(),
|
||||
signup.PaymentMethodType.Value,
|
||||
signup.PaymentToken,
|
||||
Arg.Is<List<Plan>>(plan => plan.All(p => purchaseOrganizationPlan.Contains(p))),
|
||||
Arg.Is<Plan>(plan),
|
||||
signup.AdditionalStorageGb,
|
||||
signup.AdditionalSeats,
|
||||
signup.PremiumAccessAddon,
|
||||
@ -1706,7 +1703,7 @@ public class OrganizationServiceTests
|
||||
public void ValidateSecretsManagerPlan_ThrowsException_WhenInvalidPlanSelected(
|
||||
PlanType planType, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.Plans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
@ -1727,7 +1724,7 @@ public class OrganizationServiceTests
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
public void ValidateSecretsManagerPlan_ThrowsException_WhenNoSecretsManagerSeats(PlanType planType, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
UseSecretsManager = true,
|
||||
@ -1744,7 +1741,7 @@ public class OrganizationServiceTests
|
||||
[BitAutoData(PlanType.Free)]
|
||||
public void ValidateSecretsManagerPlan_ThrowsException_WhenSubtractingSeats(PlanType planType, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
UseSecretsManager = true,
|
||||
@ -1761,7 +1758,7 @@ public class OrganizationServiceTests
|
||||
PlanType planType,
|
||||
SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
UseSecretsManager = true,
|
||||
@ -1780,7 +1777,7 @@ public class OrganizationServiceTests
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
public void ValidateSecretsManagerPlan_ThrowsException_WhenMoreSeatsThanPasswordManagerSeats(PlanType planType, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
UseSecretsManager = true,
|
||||
@ -1801,7 +1798,7 @@ public class OrganizationServiceTests
|
||||
PlanType planType,
|
||||
SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
UseSecretsManager = true,
|
||||
@ -1819,7 +1816,7 @@ public class OrganizationServiceTests
|
||||
PlanType planType,
|
||||
SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
UseSecretsManager = true,
|
||||
@ -1840,7 +1837,7 @@ public class OrganizationServiceTests
|
||||
PlanType planType,
|
||||
SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.SecretManagerPlans.FirstOrDefault(x => x.Type == planType);
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
var signup = new OrganizationUpgrade
|
||||
{
|
||||
UseSecretsManager = true,
|
||||
|
@ -40,7 +40,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Stripe_ProviderOrg_Coupon_Add(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo, bool provider = true)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
@ -56,7 +56,7 @@ public class StripePaymentServiceTests
|
||||
.BaseServiceUri.CloudRegion
|
||||
.Returns("US");
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans, 0, 0, false, taxInfo, provider);
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo, provider);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
@ -95,8 +95,8 @@ public class StripePaymentServiceTests
|
||||
public async void PurchaseOrganizationAsync_SM_Stripe_ProviderOrg_Coupon_Add(SutProvider<StripePaymentService> sutProvider, Organization organization,
|
||||
string paymentToken, TaxInfo taxInfo, bool provider = true)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
organization.UseSecretsManager = true;
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
@ -112,7 +112,7 @@ public class StripePaymentServiceTests
|
||||
.BaseServiceUri.CloudRegion
|
||||
.Returns("US");
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans, 1, 1,
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 1, 1,
|
||||
false, taxInfo, provider, 1, 1);
|
||||
|
||||
Assert.Null(result);
|
||||
@ -151,8 +151,8 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Stripe(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
organization.UseSecretsManager = true;
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
@ -167,7 +167,7 @@ public class StripePaymentServiceTests
|
||||
.BaseServiceUri.CloudRegion
|
||||
.Returns("US");
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans, 0, 0
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0
|
||||
, false, taxInfo, false, 8, 10);
|
||||
|
||||
Assert.Null(result);
|
||||
@ -207,7 +207,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Stripe_PM(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.PasswordManagerPlans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
@ -224,7 +224,7 @@ public class StripePaymentServiceTests
|
||||
.BaseServiceUri.CloudRegion
|
||||
.Returns("US");
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans, 0, 0, false, taxInfo);
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
@ -264,7 +264,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Stripe_TaxRate(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
@ -280,7 +280,7 @@ public class StripePaymentServiceTests
|
||||
t.Country == taxInfo.BillingAddressCountry && t.PostalCode == taxInfo.BillingAddressPostalCode))
|
||||
.Returns(new List<TaxRate> { new() { Id = "T-1" } });
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans, 0, 0, false, taxInfo);
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
|
||||
@ -293,7 +293,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Stripe_TaxRate_SM(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
@ -309,7 +309,7 @@ public class StripePaymentServiceTests
|
||||
t.Country == taxInfo.BillingAddressCountry && t.PostalCode == taxInfo.BillingAddressPostalCode))
|
||||
.Returns(new List<TaxRate> { new() { Id = "T-1" } });
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans, 2, 2,
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 2, 2,
|
||||
false, taxInfo, false, 2, 2);
|
||||
|
||||
Assert.Null(result);
|
||||
@ -323,7 +323,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Stripe_Declined(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
@ -356,7 +356,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_SM_Stripe_Declined(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
@ -390,7 +390,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Stripe_RequiresAction(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
@ -412,7 +412,7 @@ public class StripePaymentServiceTests
|
||||
},
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans, 0, 0, false, taxInfo);
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Equal("clientSecret", result);
|
||||
Assert.False(organization.Enabled);
|
||||
@ -421,7 +421,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_SM_Stripe_RequiresAction(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
@ -443,7 +443,7 @@ public class StripePaymentServiceTests
|
||||
},
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plans,
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan,
|
||||
10, 10, false, taxInfo, false, 10, 10);
|
||||
|
||||
Assert.Equal("clientSecret", result);
|
||||
@ -453,7 +453,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Paypal(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
@ -480,7 +480,7 @@ public class StripePaymentServiceTests
|
||||
var braintreeGateway = sutProvider.GetDependency<IBraintreeGateway>();
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plans, 0, 0, false, taxInfo);
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
@ -517,10 +517,8 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_SM_Paypal(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var passwordManagerPlan = plans.Single(p => p.BitwardenProduct == BitwardenProductType.PasswordManager);
|
||||
var secretsManagerPlan = plans.Single(p => p.BitwardenProduct == BitwardenProductType.SecretsManager);
|
||||
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
organization.UseSecretsManager = true;
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
@ -550,7 +548,7 @@ public class StripePaymentServiceTests
|
||||
var additionalSeats = 10;
|
||||
var additionalSmSeats = 5;
|
||||
var additionalServiceAccounts = 20;
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plans,
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan,
|
||||
additionalStorage, additionalSeats, false, taxInfo, false, additionalSmSeats, additionalServiceAccounts);
|
||||
|
||||
Assert.Null(result);
|
||||
@ -582,17 +580,17 @@ public class StripePaymentServiceTests
|
||||
s.Expand[0] == "latest_invoice.payment_intent" &&
|
||||
s.Metadata[organization.GatewayIdField()] == organization.Id.ToString() &&
|
||||
s.Items.Count == 4 &&
|
||||
s.Items.Count(i => i.Plan == passwordManagerPlan.StripeSeatPlanId && i.Quantity == additionalSeats) == 1 &&
|
||||
s.Items.Count(i => i.Plan == passwordManagerPlan.StripeStoragePlanId && i.Quantity == additionalStorage) == 1 &&
|
||||
s.Items.Count(i => i.Plan == secretsManagerPlan.StripeSeatPlanId && i.Quantity == additionalSmSeats) == 1 &&
|
||||
s.Items.Count(i => i.Plan == secretsManagerPlan.StripeServiceAccountPlanId && i.Quantity == additionalServiceAccounts) == 1
|
||||
s.Items.Count(i => i.Plan == plan.PasswordManager.StripeSeatPlanId && i.Quantity == additionalSeats) == 1 &&
|
||||
s.Items.Count(i => i.Plan == plan.PasswordManager.StripeStoragePlanId && i.Quantity == additionalStorage) == 1 &&
|
||||
s.Items.Count(i => i.Plan == plan.SecretsManager.StripeSeatPlanId && i.Quantity == additionalSmSeats) == 1 &&
|
||||
s.Items.Count(i => i.Plan == plan.SecretsManager.StripeServiceAccountPlanId && i.Quantity == additionalServiceAccounts) == 1
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_Paypal_FailedCreate(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(false);
|
||||
@ -601,7 +599,7 @@ public class StripePaymentServiceTests
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plans, 0, 0, false, taxInfo));
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo));
|
||||
|
||||
Assert.Equal("Failed to create PayPal customer record.", exception.Message);
|
||||
}
|
||||
@ -609,7 +607,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_SM_Paypal_FailedCreate(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(false);
|
||||
@ -618,7 +616,7 @@ public class StripePaymentServiceTests
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plans,
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan,
|
||||
1, 1, false, taxInfo, false, 8, 8));
|
||||
|
||||
Assert.Equal("Failed to create PayPal customer record.", exception.Message);
|
||||
@ -627,7 +625,7 @@ public class StripePaymentServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async void PurchaseOrganizationAsync_PayPal_Declined(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plans = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
@ -689,7 +687,7 @@ public class StripePaymentServiceTests
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription { });
|
||||
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
|
||||
var upgrade = new OrganizationUpgrade()
|
||||
{
|
||||
@ -700,7 +698,7 @@ public class StripePaymentServiceTests
|
||||
AdditionalSmSeats = 0,
|
||||
AdditionalServiceAccounts = 0
|
||||
};
|
||||
var result = await sutProvider.Sut.UpgradeFreeOrganizationAsync(organization, plans, upgrade);
|
||||
var result = await sutProvider.Sut.UpgradeFreeOrganizationAsync(organization, plan, upgrade);
|
||||
|
||||
Assert.Null(result);
|
||||
}
|
||||
@ -736,8 +734,8 @@ public class StripePaymentServiceTests
|
||||
AdditionalServiceAccounts = 50
|
||||
};
|
||||
|
||||
var plans = StaticStore.Plans.Where(p => p.Type == PlanType.EnterpriseAnnually).ToList();
|
||||
var result = await sutProvider.Sut.UpgradeFreeOrganizationAsync(organization, plans, upgrade);
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
var result = await sutProvider.Sut.UpgradeFreeOrganizationAsync(organization, plan, upgrade);
|
||||
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
@ -14,57 +13,18 @@ public class StaticStoreTests
|
||||
var plans = StaticStore.Plans;
|
||||
Assert.NotNull(plans);
|
||||
Assert.NotEmpty(plans);
|
||||
Assert.Equal(17, plans.Count());
|
||||
Assert.Equal(12, plans.Count());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PlanType.EnterpriseAnnually)]
|
||||
public void StaticStore_GetPasswordManagerPlanByPlanType_Success(PlanType planType)
|
||||
[InlineData(PlanType.EnterpriseMonthly)]
|
||||
[InlineData(PlanType.TeamsMonthly)]
|
||||
[InlineData(PlanType.TeamsAnnually)]
|
||||
public void StaticStore_GetPlan_Success(PlanType planType)
|
||||
{
|
||||
var plan = StaticStore.GetPasswordManagerPlan(planType);
|
||||
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
Assert.NotNull(plan);
|
||||
Assert.Equal(planType, plan.Type);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PlanType.EnterpriseAnnually)]
|
||||
public void StaticStore_GetSecretsManagerPlanByPlanType_Success(PlanType planType)
|
||||
{
|
||||
var plan = StaticStore.GetSecretsManagerPlan(planType);
|
||||
|
||||
Assert.NotNull(plan);
|
||||
Assert.Equal(planType, plan.Type);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PlanType.EnterpriseAnnually)]
|
||||
public void StaticStore_GetPasswordManagerPlan_ReturnsPasswordManagerPlans(PlanType planType)
|
||||
{
|
||||
var plan = StaticStore.GetPasswordManagerPlan(planType);
|
||||
Assert.NotNull(plan);
|
||||
Assert.Equal(BitwardenProductType.PasswordManager, plan.BitwardenProduct);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PlanType.EnterpriseAnnually)]
|
||||
public void StaticStore_GetSecretsManagerPlan_ReturnsSecretManagerPlans(PlanType planType)
|
||||
{
|
||||
var plan = StaticStore.GetSecretsManagerPlan(planType);
|
||||
Assert.NotNull(plan);
|
||||
Assert.Equal(BitwardenProductType.SecretsManager, plan.BitwardenProduct);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PlanType.EnterpriseAnnually, BitwardenProductType.PasswordManager)]
|
||||
public void StaticStore_AddDuplicatePlans_SingleOrDefaultThrowsException(PlanType planType, BitwardenProductType bitwardenProductType)
|
||||
{
|
||||
var plansStore = new List<Plan>
|
||||
{
|
||||
new Plan { Type = PlanType.EnterpriseAnnually, BitwardenProduct = BitwardenProductType.PasswordManager },
|
||||
new Plan { Type = PlanType.EnterpriseAnnually, BitwardenProduct = BitwardenProductType.PasswordManager }
|
||||
};
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => plansStore.SingleOrDefault(p => p.Type == planType && p.BitwardenProduct == bitwardenProductType));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user