From 5709ea36f4d174049704ac83669158fa5a073b68 Mon Sep 17 00:00:00 2001
From: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com>
Date: Fri, 14 Feb 2025 12:03:09 -0500
Subject: [PATCH] [PM-15485] Add provider plan details to provider Admin pages
(#5326)
* Add Provider Plan details to Provider Admin pages
* Run dotnet format
* Thomas' feedback
* Updated code ownership
* Robert's feedback
* Thomas' feedback
---
src/Admin/Admin.csproj | 1 -
.../Controllers/ProvidersController.cs | 3 +-
.../AdminConsole/Models/ProviderEditModel.cs | 2 +-
.../AdminConsole/Models/ProviderViewModel.cs | 49 +++++++++++++++++--
.../AdminConsole/Views/Providers/Edit.cshtml | 4 ++
.../AdminConsole/Views/Providers/View.cshtml | 4 ++
.../Billing/Models/ProviderPlanViewModel.cs | 26 ++++++++++
.../Views/Providers/ProviderPlans.cshtml | 18 +++++++
...ProviderOrganizationOrganizationDetails.cs | 2 +
...rganizationDetailsReadByProviderIdQuery.cs | 1 +
...derOrganizationOrganizationDetailsView.sql | 1 +
...derOrganizationOrganizationDetailsView.sql | 23 +++++++++
12 files changed, 128 insertions(+), 6 deletions(-)
create mode 100644 src/Admin/Billing/Models/ProviderPlanViewModel.cs
create mode 100644 src/Admin/Billing/Views/Providers/ProviderPlans.cshtml
create mode 100644 util/Migrator/DbScripts/2025-01-29_00_AddPlanTypeToProviderOrganizationOrganizationDetailsView.sql
diff --git a/src/Admin/Admin.csproj b/src/Admin/Admin.csproj
index 5493e65afd..4a255eefb2 100644
--- a/src/Admin/Admin.csproj
+++ b/src/Admin/Admin.csproj
@@ -16,7 +16,6 @@
-
diff --git a/src/Admin/AdminConsole/Controllers/ProvidersController.cs b/src/Admin/AdminConsole/Controllers/ProvidersController.cs
index 8a56483a60..6229a4deab 100644
--- a/src/Admin/AdminConsole/Controllers/ProvidersController.cs
+++ b/src/Admin/AdminConsole/Controllers/ProvidersController.cs
@@ -235,7 +235,8 @@ public class ProvidersController : Controller
var users = await _providerUserRepository.GetManyDetailsByProviderAsync(id);
var providerOrganizations = await _providerOrganizationRepository.GetManyDetailsByProviderAsync(id);
- return View(new ProviderViewModel(provider, users, providerOrganizations));
+ var providerPlans = await _providerPlanRepository.GetByProviderId(id);
+ return View(new ProviderViewModel(provider, users, providerOrganizations, providerPlans.ToList()));
}
[SelfHosted(NotSelfHostedOnly = true)]
diff --git a/src/Admin/AdminConsole/Models/ProviderEditModel.cs b/src/Admin/AdminConsole/Models/ProviderEditModel.cs
index 7fd5c765c8..bcdf602c07 100644
--- a/src/Admin/AdminConsole/Models/ProviderEditModel.cs
+++ b/src/Admin/AdminConsole/Models/ProviderEditModel.cs
@@ -19,7 +19,7 @@ public class ProviderEditModel : ProviderViewModel, IValidatableObject
IEnumerable organizations,
IReadOnlyCollection providerPlans,
string gatewayCustomerUrl = null,
- string gatewaySubscriptionUrl = null) : base(provider, providerUsers, organizations)
+ string gatewaySubscriptionUrl = null) : base(provider, providerUsers, organizations, providerPlans)
{
Name = provider.DisplayName();
BusinessName = provider.DisplayBusinessName();
diff --git a/src/Admin/AdminConsole/Models/ProviderViewModel.cs b/src/Admin/AdminConsole/Models/ProviderViewModel.cs
index 9c4d07e8bf..724e6220b3 100644
--- a/src/Admin/AdminConsole/Models/ProviderViewModel.cs
+++ b/src/Admin/AdminConsole/Models/ProviderViewModel.cs
@@ -1,6 +1,9 @@
-using Bit.Core.AdminConsole.Entities.Provider;
+using Bit.Admin.Billing.Models;
+using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Models.Data.Provider;
+using Bit.Core.Billing.Entities;
+using Bit.Core.Billing.Enums;
namespace Bit.Admin.AdminConsole.Models;
@@ -8,17 +11,57 @@ public class ProviderViewModel
{
public ProviderViewModel() { }
- public ProviderViewModel(Provider provider, IEnumerable providerUsers, IEnumerable organizations)
+ public ProviderViewModel(
+ Provider provider,
+ IEnumerable providerUsers,
+ IEnumerable organizations,
+ IReadOnlyCollection providerPlans)
{
Provider = provider;
UserCount = providerUsers.Count();
ProviderAdmins = providerUsers.Where(u => u.Type == ProviderUserType.ProviderAdmin);
-
ProviderOrganizations = organizations.Where(o => o.ProviderId == provider.Id);
+
+ if (Provider.Type == ProviderType.Msp)
+ {
+ var usedTeamsSeats = ProviderOrganizations.Where(po => po.PlanType == PlanType.TeamsMonthly)
+ .Sum(po => po.OccupiedSeats) ?? 0;
+ var teamsProviderPlan = providerPlans.FirstOrDefault(plan => plan.PlanType == PlanType.TeamsMonthly);
+ if (teamsProviderPlan != null && teamsProviderPlan.IsConfigured())
+ {
+ ProviderPlanViewModels.Add(new ProviderPlanViewModel("Teams (Monthly) Subscription", teamsProviderPlan, usedTeamsSeats));
+ }
+
+ var usedEnterpriseSeats = ProviderOrganizations.Where(po => po.PlanType == PlanType.EnterpriseMonthly)
+ .Sum(po => po.OccupiedSeats) ?? 0;
+ var enterpriseProviderPlan = providerPlans.FirstOrDefault(plan => plan.PlanType == PlanType.EnterpriseMonthly);
+ if (enterpriseProviderPlan != null && enterpriseProviderPlan.IsConfigured())
+ {
+ ProviderPlanViewModels.Add(new ProviderPlanViewModel("Enterprise (Monthly) Subscription", enterpriseProviderPlan, usedEnterpriseSeats));
+ }
+ }
+ else if (Provider.Type == ProviderType.MultiOrganizationEnterprise)
+ {
+ var usedEnterpriseSeats = ProviderOrganizations.Where(po => po.PlanType == PlanType.EnterpriseMonthly)
+ .Sum(po => po.OccupiedSeats).GetValueOrDefault(0);
+ var enterpriseProviderPlan = providerPlans.FirstOrDefault();
+ if (enterpriseProviderPlan != null && enterpriseProviderPlan.IsConfigured())
+ {
+ var planLabel = enterpriseProviderPlan.PlanType switch
+ {
+ PlanType.EnterpriseMonthly => "Enterprise (Monthly) Subscription",
+ PlanType.EnterpriseAnnually => "Enterprise (Annually) Subscription",
+ _ => string.Empty
+ };
+
+ ProviderPlanViewModels.Add(new ProviderPlanViewModel(planLabel, enterpriseProviderPlan, usedEnterpriseSeats));
+ }
+ }
}
public int UserCount { get; set; }
public Provider Provider { get; set; }
public IEnumerable ProviderAdmins { get; set; }
public IEnumerable ProviderOrganizations { get; set; }
+ public List ProviderPlanViewModels { get; set; } = [];
}
diff --git a/src/Admin/AdminConsole/Views/Providers/Edit.cshtml b/src/Admin/AdminConsole/Views/Providers/Edit.cshtml
index 43d72338be..be13a7c740 100644
--- a/src/Admin/AdminConsole/Views/Providers/Edit.cshtml
+++ b/src/Admin/AdminConsole/Views/Providers/Edit.cshtml
@@ -17,6 +17,10 @@
Provider Information
@await Html.PartialAsync("_ViewInformation", Model)
+@if (Model.ProviderPlanViewModels.Any())
+{
+ @await Html.PartialAsync("~/Billing/Views/Providers/ProviderPlans.cshtml", Model.ProviderPlanViewModels)
+}
@await Html.PartialAsync("Admins", Model)