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:
parent
9eec986c1c
commit
395d6e845c
@ -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()));
|
||||||
|
@ -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
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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]
|
Loading…
Reference in New Issue
Block a user