mirror of
https://github.com/bitwarden/server
synced 2026-01-04 17:43:53 +00:00
This reverts commit 3bef57259d.
This commit is contained in:
@@ -31,7 +31,6 @@ public static class ServiceCollectionExtensions
|
||||
services.AddPaymentOperations();
|
||||
services.AddOrganizationLicenseCommandsQueries();
|
||||
services.AddPremiumCommands();
|
||||
services.AddTransient<IGetOrganizationMetadataQuery, GetOrganizationMetadataQuery>();
|
||||
services.AddTransient<IGetOrganizationWarningsQuery, GetOrganizationWarningsQuery>();
|
||||
services.AddTransient<IRestartSubscriptionCommand, RestartSubscriptionCommand>();
|
||||
services.AddTransient<IPreviewOrganizationTaxCommand, PreviewOrganizationTaxCommand>();
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
namespace Bit.Core.Billing.Organizations.Models;
|
||||
|
||||
public record OrganizationMetadata(
|
||||
bool IsEligibleForSelfHost,
|
||||
bool IsManaged,
|
||||
bool IsOnSecretsManagerStandalone,
|
||||
bool IsSubscriptionUnpaid,
|
||||
bool HasSubscription,
|
||||
bool HasOpenInvoice,
|
||||
bool IsSubscriptionCanceled,
|
||||
DateTime? InvoiceDueDate,
|
||||
DateTime? InvoiceCreatedDate,
|
||||
DateTime? SubPeriodEndDate,
|
||||
int OrganizationOccupiedSeats)
|
||||
{
|
||||
public static OrganizationMetadata Default => new OrganizationMetadata(
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
0);
|
||||
}
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Organizations.Models;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Stripe;
|
||||
|
||||
namespace Bit.Core.Billing.Organizations.Queries;
|
||||
|
||||
public interface IGetOrganizationMetadataQuery
|
||||
{
|
||||
Task<OrganizationMetadata?> Run(Organization organization);
|
||||
}
|
||||
|
||||
public class GetOrganizationMetadataQuery(
|
||||
IGlobalSettings globalSettings,
|
||||
IOrganizationRepository organizationRepository,
|
||||
IPricingClient pricingClient,
|
||||
ISubscriberService subscriberService) : IGetOrganizationMetadataQuery
|
||||
{
|
||||
public async Task<OrganizationMetadata?> Run(Organization organization)
|
||||
{
|
||||
if (organization == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (globalSettings.SelfHosted)
|
||||
{
|
||||
return OrganizationMetadata.Default;
|
||||
}
|
||||
|
||||
var orgOccupiedSeats = await organizationRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
|
||||
{
|
||||
return OrganizationMetadata.Default with
|
||||
{
|
||||
OrganizationOccupiedSeats = orgOccupiedSeats.Total
|
||||
};
|
||||
}
|
||||
|
||||
var customer = await subscriberService.GetCustomer(organization,
|
||||
new CustomerGetOptions { Expand = ["discount.coupon.applies_to"] });
|
||||
|
||||
var subscription = await subscriberService.GetSubscription(organization);
|
||||
|
||||
if (customer == null || subscription == null)
|
||||
{
|
||||
return OrganizationMetadata.Default with
|
||||
{
|
||||
OrganizationOccupiedSeats = orgOccupiedSeats.Total
|
||||
};
|
||||
}
|
||||
|
||||
var isOnSecretsManagerStandalone = await IsOnSecretsManagerStandalone(organization, customer, subscription);
|
||||
|
||||
return new OrganizationMetadata(
|
||||
isOnSecretsManagerStandalone,
|
||||
orgOccupiedSeats.Total);
|
||||
}
|
||||
|
||||
private async Task<bool> IsOnSecretsManagerStandalone(
|
||||
Organization organization,
|
||||
Customer? customer,
|
||||
Subscription? subscription)
|
||||
{
|
||||
if (customer == null || subscription == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var plan = await pricingClient.GetPlanOrThrow(organization.PlanType);
|
||||
|
||||
if (!plan.SupportsSecretsManager)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var hasCoupon = customer.Discount?.Coupon?.Id == StripeConstants.CouponIDs.SecretsManagerStandalone;
|
||||
|
||||
if (!hasCoupon)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var subscriptionProductIds = subscription.Items.Data.Select(item => item.Plan.ProductId);
|
||||
|
||||
var couponAppliesTo = customer.Discount?.Coupon?.AppliesTo?.Products;
|
||||
|
||||
return subscriptionProductIds.Intersect(couponAppliesTo ?? []).Any();
|
||||
}
|
||||
}
|
||||
@@ -74,12 +74,16 @@ public class OrganizationBillingService(
|
||||
return OrganizationMetadata.Default;
|
||||
}
|
||||
|
||||
var orgOccupiedSeats = await organizationRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
|
||||
var isEligibleForSelfHost = await IsEligibleForSelfHostAsync(organization);
|
||||
|
||||
var isManaged = organization.Status == OrganizationStatusType.Managed;
|
||||
var orgOccupiedSeats = await organizationRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
|
||||
if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
|
||||
{
|
||||
return OrganizationMetadata.Default with
|
||||
{
|
||||
IsEligibleForSelfHost = isEligibleForSelfHost,
|
||||
IsManaged = isManaged,
|
||||
OrganizationOccupiedSeats = orgOccupiedSeats.Total
|
||||
};
|
||||
}
|
||||
@@ -93,14 +97,28 @@ public class OrganizationBillingService(
|
||||
{
|
||||
return OrganizationMetadata.Default with
|
||||
{
|
||||
OrganizationOccupiedSeats = orgOccupiedSeats.Total
|
||||
IsEligibleForSelfHost = isEligibleForSelfHost,
|
||||
IsManaged = isManaged
|
||||
};
|
||||
}
|
||||
|
||||
var isOnSecretsManagerStandalone = await IsOnSecretsManagerStandalone(organization, customer, subscription);
|
||||
|
||||
var invoice = !string.IsNullOrEmpty(subscription.LatestInvoiceId)
|
||||
? await stripeAdapter.InvoiceGetAsync(subscription.LatestInvoiceId, new InvoiceGetOptions())
|
||||
: null;
|
||||
|
||||
return new OrganizationMetadata(
|
||||
isEligibleForSelfHost,
|
||||
isManaged,
|
||||
isOnSecretsManagerStandalone,
|
||||
subscription.Status == StripeConstants.SubscriptionStatus.Unpaid,
|
||||
true,
|
||||
invoice?.Status == StripeConstants.InvoiceStatus.Open,
|
||||
subscription.Status == StripeConstants.SubscriptionStatus.Canceled,
|
||||
invoice?.DueDate,
|
||||
invoice?.Created,
|
||||
subscription.CurrentPeriodEnd,
|
||||
orgOccupiedSeats.Total);
|
||||
}
|
||||
|
||||
@@ -518,6 +536,16 @@ public class OrganizationBillingService(
|
||||
return customer;
|
||||
}
|
||||
|
||||
private async Task<bool> IsEligibleForSelfHostAsync(
|
||||
Organization organization)
|
||||
{
|
||||
var plans = await pricingClient.ListPlans();
|
||||
|
||||
var eligibleSelfHostPlans = plans.Where(plan => plan.HasSelfHost).Select(plan => plan.Type);
|
||||
|
||||
return eligibleSelfHostPlans.Contains(organization.PlanType);
|
||||
}
|
||||
|
||||
private async Task<bool> IsOnSecretsManagerStandalone(
|
||||
Organization organization,
|
||||
Customer? customer,
|
||||
|
||||
@@ -179,7 +179,6 @@ public static class FeatureFlagKeys
|
||||
public const string PM19422_AllowAutomaticTaxUpdates = "pm-19422-allow-automatic-tax-updates";
|
||||
public const string PM21821_ProviderPortalTakeover = "pm-21821-provider-portal-takeover";
|
||||
public const string PM22415_TaxIDWarnings = "pm-22415-tax-id-warnings";
|
||||
public const string PM25379_UseNewOrganizationMetadataStructure = "pm-25379-use-new-organization-metadata-structure";
|
||||
public const string PM24996ImplementUpgradeFromFreeDialog = "pm-24996-implement-upgrade-from-free-dialog";
|
||||
public const string PM24032_NewNavigationPremiumUpgradeButton = "pm-24032-new-navigation-premium-upgrade-button";
|
||||
public const string PM23713_PremiumBadgeOpensNewPremiumUpgradeDialog = "pm-23713-premium-badge-opens-new-premium-upgrade-dialog";
|
||||
|
||||
Reference in New Issue
Block a user