1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-24 12:35:25 +01:00

[AC-2678] Enterprise to Families Sponsorship Bugs (#4118)

* Removed prorationDate as it wasn't used, and wasn't needed

* Fixed logic to detect if a subscription was sponsored

* Moved OrganizationSponsorshipsController.cs to Billing folder
This commit is contained in:
Conner Turnbull 2024-06-03 13:18:46 -04:00 committed by GitHub
parent 9eec986c1c
commit 395d6e845c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 75 additions and 77 deletions

View File

@ -497,7 +497,6 @@ public class AccountController : Controller
var occupiedSeats = await _organizationUserRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id); var occupiedSeats = await _organizationUserRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
var initialSeatCount = organization.Seats.Value; var initialSeatCount = organization.Seats.Value;
var availableSeats = initialSeatCount - occupiedSeats; var availableSeats = initialSeatCount - occupiedSeats;
var prorationDate = DateTime.UtcNow;
if (availableSeats < 1) if (availableSeats < 1)
{ {
try try
@ -507,13 +506,13 @@ public class AccountController : Controller
throw new Exception("Cannot autoscale on self-hosted instance."); throw new Exception("Cannot autoscale on self-hosted instance.");
} }
await _organizationService.AutoAddSeatsAsync(organization, 1, prorationDate); await _organizationService.AutoAddSeatsAsync(organization, 1);
} }
catch (Exception e) catch (Exception e)
{ {
if (organization.Seats.Value != initialSeatCount) if (organization.Seats.Value != initialSeatCount)
{ {
await _organizationService.AdjustSeatsAsync(orgId, initialSeatCount - organization.Seats.Value, prorationDate); await _organizationService.AdjustSeatsAsync(orgId, initialSeatCount - organization.Seats.Value);
} }
_logger.LogInformation(e, "SSO auto provisioning failed"); _logger.LogInformation(e, "SSO auto provisioning failed");
throw new Exception(_i18nService.T("NoSeatsAvailable", organization.DisplayName())); throw new Exception(_i18nService.T("NoSeatsAvailable", organization.DisplayName()));

View File

@ -13,7 +13,7 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Bit.Api.Controllers; namespace Bit.Api.Billing.Controllers;
[Route("organization/sponsorship")] [Route("organization/sponsorship")]
public class OrganizationSponsorshipsController : Controller public class OrganizationSponsorshipsController : Controller

View File

@ -1199,7 +1199,9 @@ public class StripeController : Controller
} }
private static bool IsSponsoredSubscription(Subscription subscription) => private static bool IsSponsoredSubscription(Subscription subscription) =>
StaticStore.SponsoredPlans.Any(p => p.StripePlanId == subscription.Id); StaticStore.SponsoredPlans
.Any(p => subscription.Items
.Any(i => i.Plan.Id == p.StripePlanId));
/// <summary> /// <summary>
/// Handles the <see cref="HandledStripeWebhook.PaymentFailed"/> event type from Stripe. /// Handles the <see cref="HandledStripeWebhook.PaymentFailed"/> event type from Stripe.

View File

@ -17,8 +17,8 @@ public interface IOrganizationService
Task ReinstateSubscriptionAsync(Guid organizationId); Task ReinstateSubscriptionAsync(Guid organizationId);
Task<string> AdjustStorageAsync(Guid organizationId, short storageAdjustmentGb); Task<string> AdjustStorageAsync(Guid organizationId, short storageAdjustmentGb);
Task UpdateSubscription(Guid organizationId, int seatAdjustment, int? maxAutoscaleSeats); Task UpdateSubscription(Guid organizationId, int seatAdjustment, int? maxAutoscaleSeats);
Task AutoAddSeatsAsync(Organization organization, int seatsToAdd, DateTime? prorationDate = null); Task AutoAddSeatsAsync(Organization organization, int seatsToAdd);
Task<string> AdjustSeatsAsync(Guid organizationId, int seatAdjustment, DateTime? prorationDate = null); Task<string> AdjustSeatsAsync(Guid organizationId, int seatAdjustment);
Task VerifyBankAsync(Guid organizationId, int amount1, int amount2); Task VerifyBankAsync(Guid organizationId, int amount1, int amount2);
/// <summary> /// <summary>
/// Create a new organization in a cloud environment /// Create a new organization in a cloud environment

View File

@ -282,7 +282,7 @@ public class OrganizationService : IOrganizationService
await ReplaceAndUpdateCacheAsync(organization); await ReplaceAndUpdateCacheAsync(organization);
} }
public async Task<string> AdjustSeatsAsync(Guid organizationId, int seatAdjustment, DateTime? prorationDate = null) public async Task<string> AdjustSeatsAsync(Guid organizationId, int seatAdjustment)
{ {
var organization = await GetOrgById(organizationId); var organization = await GetOrgById(organizationId);
if (organization == null) if (organization == null)
@ -290,10 +290,10 @@ public class OrganizationService : IOrganizationService
throw new NotFoundException(); throw new NotFoundException();
} }
return await AdjustSeatsAsync(organization, seatAdjustment, prorationDate); return await AdjustSeatsAsync(organization, seatAdjustment);
} }
private async Task<string> AdjustSeatsAsync(Organization organization, int seatAdjustment, DateTime? prorationDate = null, IEnumerable<string> ownerEmails = null) private async Task<string> AdjustSeatsAsync(Organization organization, int seatAdjustment, IEnumerable<string> ownerEmails = null)
{ {
if (organization.Seats == null) if (organization.Seats == null)
{ {
@ -349,7 +349,7 @@ public class OrganizationService : IOrganizationService
} }
} }
var paymentIntentClientSecret = await _paymentService.AdjustSeatsAsync(organization, plan, additionalSeats, prorationDate); var paymentIntentClientSecret = await _paymentService.AdjustSeatsAsync(organization, plan, additionalSeats);
await _referenceEventService.RaiseEventAsync( await _referenceEventService.RaiseEventAsync(
new ReferenceEvent(ReferenceEventType.AdjustSeats, organization, _currentContext) new ReferenceEvent(ReferenceEventType.AdjustSeats, organization, _currentContext)
{ {
@ -1161,7 +1161,6 @@ public class OrganizationService : IOrganizationService
throw new AggregateException("One or more errors occurred while inviting users.", exceptions); throw new AggregateException("One or more errors occurred while inviting users.", exceptions);
} }
var prorationDate = DateTime.UtcNow;
try try
{ {
await _organizationUserRepository.CreateManyAsync(orgUsers); await _organizationUserRepository.CreateManyAsync(orgUsers);
@ -1180,11 +1179,10 @@ public class OrganizationService : IOrganizationService
throw new BadRequestException("Cannot add seats. Cannot manage organization users."); throw new BadRequestException("Cannot add seats. Cannot manage organization users.");
} }
await AutoAddSeatsAsync(organization, newSeatsRequired, prorationDate); await AutoAddSeatsAsync(organization, newSeatsRequired);
if (additionalSmSeatsRequired > 0) if (additionalSmSeatsRequired > 0)
{ {
smSubscriptionUpdate.ProrationDate = prorationDate;
await _updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(smSubscriptionUpdate); await _updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(smSubscriptionUpdate);
} }
@ -1206,7 +1204,7 @@ public class OrganizationService : IOrganizationService
// Revert autoscaling // Revert autoscaling
if (initialSeatCount.HasValue && currentOrganization.Seats.HasValue && currentOrganization.Seats.Value != initialSeatCount.Value) if (initialSeatCount.HasValue && currentOrganization.Seats.HasValue && currentOrganization.Seats.Value != initialSeatCount.Value)
{ {
await AdjustSeatsAsync(organization, initialSeatCount.Value - currentOrganization.Seats.Value, prorationDate); await AdjustSeatsAsync(organization, initialSeatCount.Value - currentOrganization.Seats.Value);
} }
// Revert SmSeat autoscaling // Revert SmSeat autoscaling
@ -1215,8 +1213,7 @@ public class OrganizationService : IOrganizationService
{ {
var smSubscriptionUpdateRevert = new SecretsManagerSubscriptionUpdate(currentOrganization, false) var smSubscriptionUpdateRevert = new SecretsManagerSubscriptionUpdate(currentOrganization, false)
{ {
SmSeats = initialSmSeatCount.Value, SmSeats = initialSmSeatCount.Value
ProrationDate = prorationDate
}; };
await _updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(smSubscriptionUpdateRevert); await _updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(smSubscriptionUpdateRevert);
} }
@ -1457,7 +1454,7 @@ public class OrganizationService : IOrganizationService
return (true, failureReason); return (true, failureReason);
} }
public async Task AutoAddSeatsAsync(Organization organization, int seatsToAdd, DateTime? prorationDate = null) public async Task AutoAddSeatsAsync(Organization organization, int seatsToAdd)
{ {
if (seatsToAdd < 1 || !organization.Seats.HasValue) if (seatsToAdd < 1 || !organization.Seats.HasValue)
{ {
@ -1485,7 +1482,7 @@ public class OrganizationService : IOrganizationService
} }
var initialSeatCount = organization.Seats.Value; var initialSeatCount = organization.Seats.Value;
await AdjustSeatsAsync(organization, seatsToAdd, prorationDate, ownerEmails); await AdjustSeatsAsync(organization, seatsToAdd, ownerEmails);
if (!organization.OwnersNotifiedOfAutoscaling.HasValue) if (!organization.OwnersNotifiedOfAutoscaling.HasValue)
{ {
@ -2364,7 +2361,7 @@ public class OrganizationService : IOrganizationService
var availableSeats = organization.Seats.GetValueOrDefault(0) - occupiedSeats; var availableSeats = organization.Seats.GetValueOrDefault(0) - occupiedSeats;
if (availableSeats < 1) if (availableSeats < 1)
{ {
await AutoAddSeatsAsync(organization, 1, DateTime.UtcNow); await AutoAddSeatsAsync(organization, 1);
} }
await CheckPoliciesBeforeRestoreAsync(organizationUser, userService); await CheckPoliciesBeforeRestoreAsync(organizationUser, userService);
@ -2391,7 +2388,7 @@ public class OrganizationService : IOrganizationService
var occupiedSeats = await _organizationUserRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id); var occupiedSeats = await _organizationUserRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
var availableSeats = organization.Seats.GetValueOrDefault(0) - occupiedSeats; var availableSeats = organization.Seats.GetValueOrDefault(0) - occupiedSeats;
var newSeatsRequired = organizationUserIds.Count() - availableSeats; var newSeatsRequired = organizationUserIds.Count() - availableSeats;
await AutoAddSeatsAsync(organization, newSeatsRequired, DateTime.UtcNow); await AutoAddSeatsAsync(organization, newSeatsRequired);
var deletingUserIsOwner = false; var deletingUserIsOwner = false;
if (restoringUserId.HasValue) if (restoringUserId.HasValue)

View File

@ -29,11 +29,6 @@ public class SecretsManagerSubscriptionUpdate
/// </summary> /// </summary>
public int? MaxAutoscaleSmServiceAccounts { get; set; } public int? MaxAutoscaleSmServiceAccounts { get; set; }
/// <summary>
/// The proration date for the subscription update (optional)
/// </summary>
public DateTime? ProrationDate { get; set; }
/// <summary> /// <summary>
/// Whether the subscription update is a result of autoscaling /// Whether the subscription update is a result of autoscaling
/// </summary> /// </summary>

View File

@ -66,7 +66,7 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
{ {
if (update.SmSeatsChanged) if (update.SmSeatsChanged)
{ {
await _paymentService.AdjustSmSeatsAsync(update.Organization, update.Plan, update.SmSeatsExcludingBase, update.ProrationDate); await _paymentService.AdjustSmSeatsAsync(update.Organization, update.Plan, update.SmSeatsExcludingBase);
// TODO: call ReferenceEventService - see AC-1481 // TODO: call ReferenceEventService - see AC-1481
} }
@ -74,7 +74,7 @@ public class UpdateSecretsManagerSubscriptionCommand : IUpdateSecretsManagerSubs
if (update.SmServiceAccountsChanged) if (update.SmServiceAccountsChanged)
{ {
await _paymentService.AdjustServiceAccountsAsync(update.Organization, update.Plan, await _paymentService.AdjustServiceAccountsAsync(update.Organization, update.Plan,
update.SmServiceAccountsExcludingBase, update.ProrationDate); update.SmServiceAccountsExcludingBase);
// TODO: call ReferenceEventService - see AC-1481 // TODO: call ReferenceEventService - see AC-1481
} }

View File

@ -26,20 +26,17 @@ public interface IPaymentService
bool subscribedToSecretsManager, bool subscribedToSecretsManager,
int? newlyPurchasedSecretsManagerSeats, int? newlyPurchasedSecretsManagerSeats,
int? newlyPurchasedAdditionalSecretsManagerServiceAccounts, int? newlyPurchasedAdditionalSecretsManagerServiceAccounts,
int newlyPurchasedAdditionalStorage, int newlyPurchasedAdditionalStorage);
DateTime? prorationDate = null); Task<string> AdjustSeatsAsync(Organization organization, Plan plan, int additionalSeats);
Task<string> AdjustSeatsAsync(Organization organization, Plan plan, int additionalSeats, DateTime? prorationDate = null);
Task<string> AdjustSeats( Task<string> AdjustSeats(
Provider provider, Provider provider,
Plan plan, Plan plan,
int currentlySubscribedSeats, int currentlySubscribedSeats,
int newlySubscribedSeats, int newlySubscribedSeats);
DateTime? prorationDate = null); Task<string> AdjustSmSeatsAsync(Organization organization, Plan plan, int additionalSeats);
Task<string> AdjustSmSeatsAsync(Organization organization, Plan plan, int additionalSeats, DateTime? prorationDate = null); Task<string> AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage, string storagePlanId);
Task<string> AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage, string storagePlanId, DateTime? prorationDate = null);
Task<string> AdjustServiceAccountsAsync(Organization organization, Plan plan, int additionalServiceAccounts, Task<string> AdjustServiceAccountsAsync(Organization organization, Plan plan, int additionalServiceAccounts);
DateTime? prorationDate = null);
Task CancelSubscriptionAsync(ISubscriber subscriber, bool endOfPeriod = false); Task CancelSubscriptionAsync(ISubscriber subscriber, bool endOfPeriod = false);
Task ReinstateSubscriptionAsync(ISubscriber subscriber); Task ReinstateSubscriptionAsync(ISubscriber subscriber);
Task<bool> UpdatePaymentMethodAsync(ISubscriber subscriber, PaymentMethodType paymentMethodType, Task<bool> UpdatePaymentMethodAsync(ISubscriber subscriber, PaymentMethodType paymentMethodType,
@ -55,7 +52,7 @@ public interface IPaymentService
Task UpdateTaxRateAsync(TaxRate taxRate); Task UpdateTaxRateAsync(TaxRate taxRate);
Task ArchiveTaxRateAsync(TaxRate taxRate); Task ArchiveTaxRateAsync(TaxRate taxRate);
Task<string> AddSecretsManagerToSubscription(Organization org, Plan plan, int additionalSmSeats, Task<string> AddSecretsManagerToSubscription(Organization org, Plan plan, int additionalSmSeats,
int additionalServiceAccount, DateTime? prorationDate = null); int additionalServiceAccount);
Task<bool> RisksSubscriptionFailure(Organization organization); Task<bool> RisksSubscriptionFailure(Organization organization);
Task<bool> HasSecretsManagerStandalone(Organization organization); Task<bool> HasSecretsManagerStandalone(Organization organization);
} }

View File

@ -226,7 +226,10 @@ public class StripePaymentService : IPaymentService
} }
} }
private async Task ChangeOrganizationSponsorship(Organization org, OrganizationSponsorship sponsorship, bool applySponsorship) private async Task ChangeOrganizationSponsorship(
Organization org,
OrganizationSponsorship sponsorship,
bool applySponsorship)
{ {
var existingPlan = Utilities.StaticStore.GetPlan(org.PlanType); var existingPlan = Utilities.StaticStore.GetPlan(org.PlanType);
var sponsoredPlan = sponsorship != null ? var sponsoredPlan = sponsorship != null ?
@ -234,7 +237,7 @@ public class StripePaymentService : IPaymentService
null; null;
var subscriptionUpdate = new SponsorOrganizationSubscriptionUpdate(existingPlan, sponsoredPlan, applySponsorship); var subscriptionUpdate = new SponsorOrganizationSubscriptionUpdate(existingPlan, sponsoredPlan, applySponsorship);
await FinalizeSubscriptionChangeAsync(org, subscriptionUpdate, DateTime.UtcNow, true); await FinalizeSubscriptionChangeAsync(org, subscriptionUpdate, true);
var sub = await _stripeAdapter.SubscriptionGetAsync(org.GatewaySubscriptionId); var sub = await _stripeAdapter.SubscriptionGetAsync(org.GatewaySubscriptionId);
org.ExpirationDate = sub.CurrentPeriodEnd; org.ExpirationDate = sub.CurrentPeriodEnd;
@ -759,7 +762,7 @@ public class StripePaymentService : IPaymentService
} }
private async Task<string> FinalizeSubscriptionChangeAsync(ISubscriber subscriber, private async Task<string> FinalizeSubscriptionChangeAsync(ISubscriber subscriber,
SubscriptionUpdate subscriptionUpdate, DateTime? prorationDate, bool invoiceNow = false) SubscriptionUpdate subscriptionUpdate, bool invoiceNow = false)
{ {
// remember, when in doubt, throw // remember, when in doubt, throw
var subGetOptions = new SubscriptionGetOptions(); var subGetOptions = new SubscriptionGetOptions();
@ -771,7 +774,6 @@ public class StripePaymentService : IPaymentService
throw new GatewayException("Subscription not found."); throw new GatewayException("Subscription not found.");
} }
prorationDate ??= DateTime.UtcNow;
var collectionMethod = sub.CollectionMethod; var collectionMethod = sub.CollectionMethod;
var daysUntilDue = sub.DaysUntilDue; var daysUntilDue = sub.DaysUntilDue;
var chargeNow = collectionMethod == "charge_automatically"; var chargeNow = collectionMethod == "charge_automatically";
@ -786,8 +788,7 @@ public class StripePaymentService : IPaymentService
? Constants.AlwaysInvoice ? Constants.AlwaysInvoice
: Constants.CreateProrations, : Constants.CreateProrations,
DaysUntilDue = daysUntilDue ?? 1, DaysUntilDue = daysUntilDue ?? 1,
CollectionMethod = "send_invoice", CollectionMethod = "send_invoice"
ProrationDate = prorationDate,
}; };
if (!invoiceNow && isAnnualPlan && isPm5864DollarThresholdEnabled && sub.Status.Trim() != "trialing") if (!invoiceNow && isAnnualPlan && isPm5864DollarThresholdEnabled && sub.Status.Trim() != "trialing")
{ {
@ -907,9 +908,8 @@ public class StripePaymentService : IPaymentService
bool subscribedToSecretsManager, bool subscribedToSecretsManager,
int? newlyPurchasedSecretsManagerSeats, int? newlyPurchasedSecretsManagerSeats,
int? newlyPurchasedAdditionalSecretsManagerServiceAccounts, int? newlyPurchasedAdditionalSecretsManagerServiceAccounts,
int newlyPurchasedAdditionalStorage, int newlyPurchasedAdditionalStorage) =>
DateTime? prorationDate = null) FinalizeSubscriptionChangeAsync(
=> FinalizeSubscriptionChangeAsync(
organization, organization,
new CompleteSubscriptionUpdate( new CompleteSubscriptionUpdate(
organization, organization,
@ -919,41 +919,47 @@ public class StripePaymentService : IPaymentService
PurchasedPasswordManagerSeats = newlyPurchasedPasswordManagerSeats, PurchasedPasswordManagerSeats = newlyPurchasedPasswordManagerSeats,
SubscribedToSecretsManager = subscribedToSecretsManager, SubscribedToSecretsManager = subscribedToSecretsManager,
PurchasedSecretsManagerSeats = newlyPurchasedSecretsManagerSeats, PurchasedSecretsManagerSeats = newlyPurchasedSecretsManagerSeats,
PurchasedAdditionalSecretsManagerServiceAccounts = newlyPurchasedAdditionalSecretsManagerServiceAccounts, PurchasedAdditionalSecretsManagerServiceAccounts =
newlyPurchasedAdditionalSecretsManagerServiceAccounts,
PurchasedAdditionalStorage = newlyPurchasedAdditionalStorage PurchasedAdditionalStorage = newlyPurchasedAdditionalStorage
}), }), true);
prorationDate, true);
public Task<string> AdjustSeatsAsync(Organization organization, StaticStore.Plan plan, int additionalSeats, DateTime? prorationDate = null) public Task<string> AdjustSeatsAsync(Organization organization, StaticStore.Plan plan, int additionalSeats) =>
{ FinalizeSubscriptionChangeAsync(organization, new SeatSubscriptionUpdate(organization, plan, additionalSeats));
return FinalizeSubscriptionChangeAsync(organization, new SeatSubscriptionUpdate(organization, plan, additionalSeats), prorationDate);
}
public Task<string> AdjustSeats( public Task<string> AdjustSeats(
Provider provider, Provider provider,
StaticStore.Plan plan, StaticStore.Plan plan,
int currentlySubscribedSeats, int currentlySubscribedSeats,
int newlySubscribedSeats, int newlySubscribedSeats)
DateTime? prorationDate = null)
=> FinalizeSubscriptionChangeAsync( => FinalizeSubscriptionChangeAsync(
provider, provider,
new ProviderSubscriptionUpdate(plan.Type, currentlySubscribedSeats, newlySubscribedSeats), new ProviderSubscriptionUpdate(
prorationDate); plan.Type,
currentlySubscribedSeats,
newlySubscribedSeats));
public Task<string> AdjustSmSeatsAsync(Organization organization, StaticStore.Plan plan, int additionalSeats, DateTime? prorationDate = null) public Task<string> AdjustSmSeatsAsync(Organization organization, StaticStore.Plan plan, int additionalSeats) =>
{ FinalizeSubscriptionChangeAsync(
return FinalizeSubscriptionChangeAsync(organization, new SmSeatSubscriptionUpdate(organization, plan, additionalSeats), prorationDate); organization,
} new SmSeatSubscriptionUpdate(organization, plan, additionalSeats));
public Task<string> AdjustServiceAccountsAsync(Organization organization, StaticStore.Plan plan, int additionalServiceAccounts, DateTime? prorationDate = null) public Task<string> AdjustServiceAccountsAsync(
{ Organization organization,
return FinalizeSubscriptionChangeAsync(organization, new ServiceAccountSubscriptionUpdate(organization, plan, additionalServiceAccounts), prorationDate); StaticStore.Plan plan,
} int additionalServiceAccounts) =>
FinalizeSubscriptionChangeAsync(
organization,
new ServiceAccountSubscriptionUpdate(organization, plan, additionalServiceAccounts));
public Task<string> AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage, public Task<string> AdjustStorageAsync(
string storagePlanId, DateTime? prorationDate = null) IStorableSubscriber storableSubscriber,
int additionalStorage,
string storagePlanId)
{ {
return FinalizeSubscriptionChangeAsync(storableSubscriber, new StorageSubscriptionUpdate(storagePlanId, additionalStorage), prorationDate); return FinalizeSubscriptionChangeAsync(
storableSubscriber,
new StorageSubscriptionUpdate(storagePlanId, additionalStorage));
} }
public async Task CancelAndRecoverChargesAsync(ISubscriber subscriber) public async Task CancelAndRecoverChargesAsync(ISubscriber subscriber)
@ -1771,13 +1777,15 @@ public class StripePaymentService : IPaymentService
} }
} }
public async Task<string> AddSecretsManagerToSubscription(Organization org, StaticStore.Plan plan, int additionalSmSeats, public async Task<string> AddSecretsManagerToSubscription(
int additionalServiceAccount, DateTime? prorationDate = null) Organization org,
{ StaticStore.Plan plan,
return await FinalizeSubscriptionChangeAsync(org, int additionalSmSeats,
new SecretsManagerSubscribeUpdate(org, plan, additionalSmSeats, additionalServiceAccount), prorationDate, int additionalServiceAccount) =>
await FinalizeSubscriptionChangeAsync(
org,
new SecretsManagerSubscribeUpdate(org, plan, additionalSmSeats, additionalServiceAccount),
true); true);
}
public async Task<bool> RisksSubscriptionFailure(Organization organization) public async Task<bool> RisksSubscriptionFailure(Organization organization)
{ {

View File

@ -1,4 +1,4 @@
using Bit.Api.Controllers; using Bit.Api.Billing.Controllers;
using Bit.Api.Models.Request.Organizations; using Bit.Api.Models.Request.Organizations;
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Context; using Bit.Core.Context;
@ -14,7 +14,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
namespace Bit.Api.Test.AdminConsole.Controllers; namespace Bit.Api.Test.Billing.Controllers;
[ControllerCustomize(typeof(OrganizationSponsorshipsController))] [ControllerCustomize(typeof(OrganizationSponsorshipsController))]
[SutProviderCustomize] [SutProviderCustomize]