mirror of
https://github.com/bitwarden/server
synced 2025-12-25 20:53:16 +00:00
Use upgrade path to change sponsorship
Sponsorships need to be annual to match the GB add-on charge rate
This commit is contained in:
@@ -1,39 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Bit.Core.Models.Table;
|
||||
|
||||
namespace Bit.Core.Models.Business
|
||||
{
|
||||
public class SponsoredOrganizationSubscription
|
||||
{
|
||||
public const string OrganizationSponsorhipIdMetadataKey = "OrganizationSponsorshipId";
|
||||
private readonly string _customerId;
|
||||
private readonly Organization _org;
|
||||
private readonly StaticStore.Plan _plan;
|
||||
private readonly List<Stripe.TaxRate> _taxRates;
|
||||
|
||||
public SponsoredOrganizationSubscription(Organization org, Stripe.Subscription existingSubscription)
|
||||
{
|
||||
_org = org;
|
||||
_customerId = org.GatewayCustomerId;
|
||||
_plan = Utilities.StaticStore.GetPlan(org.PlanType);
|
||||
_taxRates = existingSubscription.DefaultTaxRates;
|
||||
}
|
||||
|
||||
public SponsorOrganizationSubscriptionOptions GetSponsorSubscriptionOptions(OrganizationSponsorship sponsorship,
|
||||
int additionalSeats = 0, int additionalStorageGb = 0, bool premiumAccessAddon = false)
|
||||
{
|
||||
var sponsoredPlan = Utilities.StaticStore.GetSponsoredPlan(sponsorship.PlanSponsorshipType.Value);
|
||||
|
||||
var subCreateOptions = new SponsorOrganizationSubscriptionOptions(_customerId, _org, _plan,
|
||||
sponsoredPlan, _taxRates, additionalSeats, additionalStorageGb, premiumAccessAddon);
|
||||
|
||||
subCreateOptions.Metadata.Add(OrganizationSponsorhipIdMetadataKey, sponsorship.Id.ToString());
|
||||
return subCreateOptions;
|
||||
}
|
||||
|
||||
public OrganizationUpgradeSubscriptionOptions RemoveOrganizationSubscriptionOptions(int additionalSeats = 0,
|
||||
int additionalStorageGb = 0, bool premiumAccessAddon = false) =>
|
||||
new OrganizationUpgradeSubscriptionOptions(_customerId, _org, _plan, _taxRates,
|
||||
additionalSeats, additionalStorageGb, premiumAccessAddon);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using Bit.Core.Models.Table;
|
||||
using Stripe;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bit.Core.Models.Business
|
||||
{
|
||||
public class OrganizationSubscriptionOptionsBase : Stripe.SubscriptionCreateOptions
|
||||
{
|
||||
public OrganizationSubscriptionOptionsBase(Organization org, StaticStore.Plan plan,
|
||||
int additionalSeats, int additionalStorageGb, bool premiumAccessAddon)
|
||||
public OrganizationSubscriptionOptionsBase(Organization org, StaticStore.Plan plan, TaxInfo taxInfo, int additionalSeats, int additionalStorageGb, bool premiumAccessAddon)
|
||||
{
|
||||
Items = new List<SubscriptionItemOptions>();
|
||||
Metadata = new Dictionary<string, string>
|
||||
@@ -16,6 +14,15 @@ namespace Bit.Core.Models.Business
|
||||
[org.GatewayIdField()] = org.Id.ToString()
|
||||
};
|
||||
|
||||
if (plan.StripePlanId != null)
|
||||
{
|
||||
Items.Add(new SubscriptionItemOptions
|
||||
{
|
||||
Plan = plan.StripePlanId,
|
||||
Quantity = 1
|
||||
});
|
||||
}
|
||||
|
||||
if (additionalSeats > 0 && plan.StripeSeatPlanId != null)
|
||||
{
|
||||
Items.Add(new SubscriptionItemOptions
|
||||
@@ -42,53 +49,15 @@ namespace Bit.Core.Models.Business
|
||||
Quantity = 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void AddPlanItem(StaticStore.Plan plan) => AddPlanItem(plan.StripePlanId);
|
||||
protected void AddPlanItem(StaticStore.SponsoredPlan sponsoredPlan) => AddPlanItem(sponsoredPlan.StripePlanId);
|
||||
protected void AddPlanItem(string stripePlanId)
|
||||
{
|
||||
if (stripePlanId != null)
|
||||
if (!string.IsNullOrWhiteSpace(taxInfo?.StripeTaxRateId))
|
||||
{
|
||||
Items.Add(new SubscriptionItemOptions
|
||||
{
|
||||
Plan = stripePlanId,
|
||||
Quantity = 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void AddTaxRateItem(TaxInfo taxInfo) => AddTaxRateItem(new List<string> { taxInfo.StripeTaxRateId });
|
||||
protected void AddTaxRateItem(List<Stripe.TaxRate> taxRates) => AddTaxRateItem(taxRates?.Select(t => t.Id).ToList());
|
||||
protected void AddTaxRateItem(List<string> taxRateIds)
|
||||
{
|
||||
if (taxRateIds != null && taxRateIds.Any(tax => !string.IsNullOrWhiteSpace(tax)))
|
||||
{
|
||||
DefaultTaxRates = taxRateIds;
|
||||
DefaultTaxRates = new List<string> { taxInfo.StripeTaxRateId };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class UnsponsoredOrganizationSubscriptionOptionsBase : OrganizationSubscriptionOptionsBase
|
||||
{
|
||||
public UnsponsoredOrganizationSubscriptionOptionsBase(Organization org, StaticStore.Plan plan, TaxInfo taxInfo,
|
||||
int additionalSeats, int additionalStorage, bool premiumAccessAddon) :
|
||||
base(org, plan, additionalSeats, additionalStorage, premiumAccessAddon)
|
||||
{
|
||||
AddPlanItem(plan);
|
||||
AddTaxRateItem(taxInfo);
|
||||
}
|
||||
public UnsponsoredOrganizationSubscriptionOptionsBase(Organization org, StaticStore.Plan plan, List<Stripe.TaxRate> taxInfo,
|
||||
int additionalSeats, int additionalStorage, bool premiumAccessAddon) :
|
||||
base(org, plan, additionalSeats, additionalStorage, premiumAccessAddon)
|
||||
{
|
||||
AddPlanItem(plan);
|
||||
AddTaxRateItem(taxInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class OrganizationPurchaseSubscriptionOptions : UnsponsoredOrganizationSubscriptionOptionsBase
|
||||
public class OrganizationPurchaseSubscriptionOptions : OrganizationSubscriptionOptionsBase
|
||||
{
|
||||
public OrganizationPurchaseSubscriptionOptions(
|
||||
Organization org, StaticStore.Plan plan,
|
||||
@@ -101,54 +70,16 @@ namespace Bit.Core.Models.Business
|
||||
}
|
||||
}
|
||||
|
||||
public class OrganizationUpgradeSubscriptionOptions : UnsponsoredOrganizationSubscriptionOptionsBase
|
||||
public class OrganizationUpgradeSubscriptionOptions : OrganizationSubscriptionOptionsBase
|
||||
{
|
||||
public OrganizationUpgradeSubscriptionOptions(
|
||||
string customerId, Organization org,
|
||||
StaticStore.Plan plan, TaxInfo taxInfo,
|
||||
int additionalSeats = 0, int additionalStorageGb = 0,
|
||||
bool premiumAccessAddon = false) :
|
||||
base(org, plan, taxInfo, additionalSeats, additionalStorageGb, premiumAccessAddon)
|
||||
{
|
||||
Customer = customerId;
|
||||
}
|
||||
public OrganizationUpgradeSubscriptionOptions(
|
||||
string customerId, Organization org,
|
||||
StaticStore.Plan plan, List<Stripe.TaxRate> taxInfo,
|
||||
int additionalSeats = 0, int additionalStorageGb = 0,
|
||||
bool premiumAccessAddon = false) :
|
||||
base(org, plan, taxInfo, additionalSeats, additionalStorageGb, premiumAccessAddon)
|
||||
{
|
||||
Customer = customerId;
|
||||
}
|
||||
}
|
||||
|
||||
public class RemoveOrganizationSubscriptionOptions : OrganizationSubscriptionOptionsBase
|
||||
{
|
||||
public RemoveOrganizationSubscriptionOptions(string customerId, Organization org,
|
||||
StaticStore.Plan plan, List<string> existingTaxRateStripeIds,
|
||||
int additionalSeats = 0, int additionalStorageGb = 0,
|
||||
bool premiumAccessAddon = false) :
|
||||
base(org, plan, additionalSeats, additionalStorageGb, premiumAccessAddon)
|
||||
{
|
||||
Customer = customerId;
|
||||
AddPlanItem(plan);
|
||||
AddTaxRateItem(existingTaxRateStripeIds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SponsorOrganizationSubscriptionOptions : OrganizationSubscriptionOptionsBase
|
||||
{
|
||||
public SponsorOrganizationSubscriptionOptions(
|
||||
string customerId, Organization org, StaticStore.Plan existingPlan,
|
||||
StaticStore.SponsoredPlan sponsorshipPlan, List<Stripe.TaxRate> existingTaxRates, int additionalSeats = 0,
|
||||
int additionalStorageGb = 0, bool premiumAccessAddon = false) :
|
||||
base(org, existingPlan, additionalSeats, additionalStorageGb, premiumAccessAddon)
|
||||
{
|
||||
Customer = customerId;
|
||||
AddPlanItem(sponsorshipPlan);
|
||||
AddTaxRateItem(existingTaxRates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Bit.Core.Models.Table;
|
||||
using Stripe;
|
||||
@@ -6,16 +7,28 @@ namespace Bit.Core.Models.Business
|
||||
{
|
||||
public abstract class SubscriptionUpdate
|
||||
{
|
||||
protected abstract string PlanId { get; }
|
||||
protected abstract List<string> PlanIds { get; }
|
||||
|
||||
public abstract SubscriptionItemOptions RevertItemOptions(Subscription subscription);
|
||||
public abstract SubscriptionItemOptions UpgradeItemOptions(Subscription subscription);
|
||||
public abstract List<SubscriptionItemOptions> RevertItemsOptions(Subscription subscription);
|
||||
public abstract List<SubscriptionItemOptions> UpgradeItemsOptions(Subscription subscription);
|
||||
|
||||
public bool UpdateNeeded(Subscription subscription) =>
|
||||
(SubscriptionItem(subscription)?.Quantity ?? 0) != (UpgradeItemOptions(subscription).Quantity ?? 0);
|
||||
public bool UpdateNeeded(Subscription subscription)
|
||||
{
|
||||
var upgradeItemsOptions = UpgradeItemsOptions(subscription);
|
||||
foreach (var upgradeItemOptions in upgradeItemsOptions)
|
||||
{
|
||||
var upgradeQuantity = upgradeItemOptions.Quantity ?? 0;
|
||||
var existingQuantity = SubscriptionItem(subscription, upgradeItemOptions.Plan)?.Quantity ?? 0;
|
||||
if (upgradeQuantity != existingQuantity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected SubscriptionItem SubscriptionItem(Subscription subscription) =>
|
||||
subscription.Items?.Data?.FirstOrDefault(i => i.Plan.Id == PlanId);
|
||||
protected static SubscriptionItem SubscriptionItem(Subscription subscription, string planId) =>
|
||||
subscription.Items?.Data?.FirstOrDefault(i => i.Plan.Id == planId);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +37,7 @@ namespace Bit.Core.Models.Business
|
||||
private readonly Organization _organization;
|
||||
private readonly StaticStore.Plan _plan;
|
||||
private readonly long? _additionalSeats;
|
||||
protected override string PlanId => _plan.StripeSeatPlanId;
|
||||
protected override List<string> PlanIds => new() { _plan.StripeSeatPlanId };
|
||||
|
||||
public SeatSubscriptionUpdate(Organization organization, StaticStore.Plan plan, long? additionalSeats)
|
||||
{
|
||||
@@ -33,27 +46,33 @@ namespace Bit.Core.Models.Business
|
||||
_additionalSeats = additionalSeats;
|
||||
}
|
||||
|
||||
public override SubscriptionItemOptions UpgradeItemOptions(Subscription subscription)
|
||||
public override List<SubscriptionItemOptions> UpgradeItemsOptions(Subscription subscription)
|
||||
{
|
||||
var item = SubscriptionItem(subscription);
|
||||
return new SubscriptionItemOptions
|
||||
var item = SubscriptionItem(subscription, PlanIds.Single());
|
||||
return new()
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = PlanId,
|
||||
Quantity = _additionalSeats,
|
||||
Deleted = (item?.Id != null && _additionalSeats == 0) ? true : (bool?)null,
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = PlanIds.Single(),
|
||||
Quantity = _additionalSeats,
|
||||
Deleted = (item?.Id != null && _additionalSeats == 0) ? true : (bool?)null,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override SubscriptionItemOptions RevertItemOptions(Subscription subscription)
|
||||
public override List<SubscriptionItemOptions> RevertItemsOptions(Subscription subscription)
|
||||
{
|
||||
var item = SubscriptionItem(subscription);
|
||||
return new SubscriptionItemOptions
|
||||
var item = SubscriptionItem(subscription, PlanIds.Single());
|
||||
return new()
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = PlanId,
|
||||
Quantity = _organization.Seats,
|
||||
Deleted = item?.Id != null ? true : (bool?)null,
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = PlanIds.Single(),
|
||||
Quantity = _organization.Seats,
|
||||
Deleted = item?.Id != null ? true : (bool?)null,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -62,7 +81,7 @@ namespace Bit.Core.Models.Business
|
||||
{
|
||||
private readonly string _plan;
|
||||
private readonly long? _additionalStorage;
|
||||
protected override string PlanId => _plan;
|
||||
protected override List<string> PlanIds => new() { _plan };
|
||||
|
||||
public StorageSubscriptionUpdate(string plan, long? additionalStorage)
|
||||
{
|
||||
@@ -70,28 +89,102 @@ namespace Bit.Core.Models.Business
|
||||
_additionalStorage = additionalStorage;
|
||||
}
|
||||
|
||||
public override SubscriptionItemOptions UpgradeItemOptions(Subscription subscription)
|
||||
public override List<SubscriptionItemOptions> UpgradeItemsOptions(Subscription subscription)
|
||||
{
|
||||
var item = SubscriptionItem(subscription);
|
||||
return new SubscriptionItemOptions
|
||||
var item = SubscriptionItem(subscription, PlanIds.Single());
|
||||
return new()
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = _plan,
|
||||
Quantity = _additionalStorage,
|
||||
Deleted = (item?.Id != null && _additionalStorage == 0) ? true : (bool?)null,
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = _plan,
|
||||
Quantity = _additionalStorage,
|
||||
Deleted = (item?.Id != null && _additionalStorage == 0) ? true : (bool?)null,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override SubscriptionItemOptions RevertItemOptions(Subscription subscription)
|
||||
public override List<SubscriptionItemOptions> RevertItemsOptions(Subscription subscription)
|
||||
{
|
||||
var item = SubscriptionItem(subscription);
|
||||
return new SubscriptionItemOptions
|
||||
var item = SubscriptionItem(subscription, PlanIds.Single());
|
||||
return new()
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = _plan,
|
||||
Quantity = item?.Quantity ?? 0,
|
||||
Deleted = item?.Id != null ? true : (bool?)null,
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = item?.Id,
|
||||
Plan = _plan,
|
||||
Quantity = item?.Quantity ?? 0,
|
||||
Deleted = item?.Id != null ? true : (bool?)null,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class SponsorOrganizationSubscriptionUpdate : SubscriptionUpdate
|
||||
{
|
||||
private string _existingPlanStripeId;
|
||||
private string _sponsoredPlanStripeId;
|
||||
private bool _applySponsorship;
|
||||
protected override List<string> PlanIds => new() { _existingPlanStripeId, _sponsoredPlanStripeId };
|
||||
|
||||
public SponsorOrganizationSubscriptionUpdate(StaticStore.Plan existingPlan, StaticStore.SponsoredPlan sponsoredPlan, bool applySponsorship)
|
||||
{
|
||||
_existingPlanStripeId = existingPlan.StripePlanId;
|
||||
_sponsoredPlanStripeId = sponsoredPlan.StripePlanId;
|
||||
}
|
||||
|
||||
public override List<SubscriptionItemOptions> RevertItemsOptions(Subscription subscription)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = AddStripeItem(subscription)?.Id,
|
||||
Plan = AddStripePlanId,
|
||||
Quantity = 0,
|
||||
Deleted = true,
|
||||
},
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = RemoveStripeItem(subscription)?.Id,
|
||||
Plan = RemoveStripePlanId,
|
||||
Quantity = 1,
|
||||
Deleted = false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public override List<SubscriptionItemOptions> UpgradeItemsOptions(Subscription subscription)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = RemoveStripeItem(subscription)?.Id,
|
||||
Plan = RemoveStripePlanId,
|
||||
Quantity = 0,
|
||||
Deleted = true,
|
||||
},
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Id = AddStripeItem(subscription)?.Id,
|
||||
Plan = AddStripePlanId,
|
||||
Quantity = 1,
|
||||
Deleted = false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private string RemoveStripePlanId => _applySponsorship ? _existingPlanStripeId : _sponsoredPlanStripeId;
|
||||
private string AddStripePlanId => _applySponsorship ? _sponsoredPlanStripeId : _existingPlanStripeId;
|
||||
private Stripe.SubscriptionItem RemoveStripeItem(Subscription subscription) =>
|
||||
_applySponsorship ?
|
||||
SubscriptionItem(subscription, _existingPlanStripeId) :
|
||||
SubscriptionItem(subscription, _sponsoredPlanStripeId);
|
||||
private Stripe.SubscriptionItem AddStripeItem(Subscription subscription) =>
|
||||
_applySponsorship ?
|
||||
SubscriptionItem(subscription, _sponsoredPlanStripeId) :
|
||||
SubscriptionItem(subscription, _existingPlanStripeId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user