diff --git a/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs b/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs index c9fb75dc37..ee0d0bbc2a 100644 --- a/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationSubscriptions/UpgradeOrganizationPlanCommand.cs @@ -307,23 +307,25 @@ public class UpgradeOrganizationPlanCommand : IUpgradeOrganizationPlanCommand { throw new BadRequestException( $"Your organization currently has {occupiedSmSeats} Secrets Manager seats filled. " + - $"Your new plan only has ({newPlanSmSeats}) seats. Remove some users."); + $"Your new plan only has {newPlanSmSeats} seats. Remove some users or increase your subscription."); } } - if (newSecretsManagerPlan.BaseServiceAccount != null) + var additionalServiceAccounts = newSecretsManagerPlan.HasAdditionalServiceAccountOption + ? upgrade.AdditionalServiceAccounts + : 0; + var newPlanServiceAccounts = newSecretsManagerPlan.BaseServiceAccount + additionalServiceAccounts; + + if (!organization.SmServiceAccounts.HasValue || organization.SmServiceAccounts.Value > newPlanServiceAccounts) { - if (!organization.SmServiceAccounts.HasValue || - organization.SmServiceAccounts.Value > newSecretsManagerPlan.MaxServiceAccounts) + var currentServiceAccounts = + await _serviceAccountRepository.GetServiceAccountCountByOrganizationIdAsync(organization.Id); + if (currentServiceAccounts > newPlanServiceAccounts) { - var currentServiceAccounts = - await _serviceAccountRepository.GetServiceAccountCountByOrganizationIdAsync(organization.Id); - if (currentServiceAccounts > newSecretsManagerPlan.MaxServiceAccounts) - { - throw new BadRequestException( - $"Your organization currently has {currentServiceAccounts} service account seats filled. " + - $"Your new plan only has ({newSecretsManagerPlan.MaxServiceAccounts}) service accounts. Remove some service accounts."); - } + throw new BadRequestException( + $"Your organization currently has {currentServiceAccounts} service accounts. " + + $"Your new plan only allows {newSecretsManagerPlan.MaxServiceAccounts} service accounts. " + + "Remove some service accounts or increase your subscription."); } } } diff --git a/test/Core.Test/OrganizationFeatures/OrganizationSubscriptionUpdate/UpgradeOrganizationPlanCommandTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationSubscriptionUpdate/UpgradeOrganizationPlanCommandTests.cs index f9524b2d6b..f18a8b5de9 100644 --- a/test/Core.Test/OrganizationFeatures/OrganizationSubscriptionUpdate/UpgradeOrganizationPlanCommandTests.cs +++ b/test/Core.Test/OrganizationFeatures/OrganizationSubscriptionUpdate/UpgradeOrganizationPlanCommandTests.cs @@ -3,6 +3,7 @@ using Bit.Core.Exceptions; using Bit.Core.Models.Business; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions; using Bit.Core.Repositories; +using Bit.Core.SecretsManager.Repositories; using Bit.Core.Services; using Bit.Core.Test.AutoFixture.OrganizationFixtures; using Bit.Core.Utilities; @@ -128,4 +129,57 @@ public class UpgradeOrganizationPlanCommandTests Assert.NotNull(result.Item2); } + + [Theory, FreeOrganizationUpgradeCustomize] + [BitAutoData(PlanType.EnterpriseMonthly)] + [BitAutoData(PlanType.EnterpriseAnnually)] + [BitAutoData(PlanType.TeamsMonthly)] + [BitAutoData(PlanType.TeamsAnnually)] + public async Task UpgradePlan_SM_NotEnoughSmSeats_Throws(PlanType planType, Organization organization, OrganizationUpgrade upgrade, + SutProvider sutProvider) + { + upgrade.Plan = planType; + upgrade.AdditionalSeats = 15; + upgrade.AdditionalSmSeats = 1; + upgrade.AdditionalServiceAccounts = 0; + + organization.SmSeats = 2; + + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency() + .GetOccupiedSmSeatCountByOrganizationIdAsync(organization.Id).Returns(2); + + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade)); + Assert.Contains("Your organization currently has 2 Secrets Manager seats filled. Your new plan only has", exception.Message); + + sutProvider.GetDependency().DidNotReceiveWithAnyArgs().ReplaceAndUpdateCacheAsync(default); + } + + [Theory, FreeOrganizationUpgradeCustomize] + [BitAutoData(PlanType.EnterpriseMonthly, 201)] + [BitAutoData(PlanType.EnterpriseAnnually, 201)] + [BitAutoData(PlanType.TeamsMonthly, 51)] + [BitAutoData(PlanType.TeamsAnnually, 51)] + public async Task UpgradePlan_SM_NotEnoughServiceAccounts_Throws(PlanType planType, int currentServiceAccounts, + Organization organization, OrganizationUpgrade upgrade, SutProvider sutProvider) + { + upgrade.Plan = planType; + upgrade.AdditionalSeats = 15; + upgrade.AdditionalSmSeats = 1; + upgrade.AdditionalServiceAccounts = 0; + + organization.SmSeats = 1; + organization.SmServiceAccounts = currentServiceAccounts; + + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency() + .GetOccupiedSmSeatCountByOrganizationIdAsync(organization.Id).Returns(1); + sutProvider.GetDependency() + .GetServiceAccountCountByOrganizationIdAsync(organization.Id).Returns(currentServiceAccounts); + + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade)); + Assert.Contains($"Your organization currently has {currentServiceAccounts} service accounts. Your new plan only allows", exception.Message); + + sutProvider.GetDependency().DidNotReceiveWithAnyArgs().ReplaceAndUpdateCacheAsync(default); + } }