1
0
mirror of https://github.com/bitwarden/server synced 2025-12-22 11:13:27 +00:00

[PM-24298] milestone3 families 2025 (#6586)

* [PM-24298] milestone3 families2025

# Conflicts:
#	src/Billing/Services/Implementations/UpcomingInvoiceHandler.cs
#	test/Billing.Test/Services/UpcomingInvoiceHandlerTests.cs

* update test name
This commit is contained in:
Kyle Denney
2025-11-17 16:03:35 -06:00
committed by GitHub
parent f52a630197
commit 75d8250f3a
2 changed files with 217 additions and 44 deletions

View File

@@ -195,41 +195,48 @@ public class UpcomingInvoiceHandler(
Plan plan,
bool milestone3)
{
if (milestone3 && plan.Type == PlanType.FamiliesAnnually2019)
// currently these are the only plans that need aligned and both require the same flag and share most of the logic
if (!milestone3 || plan.Type is not (PlanType.FamiliesAnnually2019 or PlanType.FamiliesAnnually2025))
{
var passwordManagerItem =
subscription.Items.FirstOrDefault(item => item.Price.Id == plan.PasswordManager.StripePlanId);
return;
}
if (passwordManagerItem == null)
{
logger.LogWarning("Could not find Organization's ({OrganizationId}) password manager item while processing '{EventType}' event ({EventID})",
organization.Id, @event.Type, @event.Id);
return;
}
var passwordManagerItem =
subscription.Items.FirstOrDefault(item => item.Price.Id == plan.PasswordManager.StripePlanId);
var families = await pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually);
if (passwordManagerItem == null)
{
logger.LogWarning("Could not find Organization's ({OrganizationId}) password manager item while processing '{EventType}' event ({EventID})",
organization.Id, @event.Type, @event.Id);
return;
}
organization.PlanType = families.Type;
organization.Plan = families.Name;
organization.UsersGetPremium = families.UsersGetPremium;
organization.Seats = families.PasswordManager.BaseSeats;
var families = await pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually);
var options = new SubscriptionUpdateOptions
{
Items =
[
new SubscriptionItemOptions
{
Id = passwordManagerItem.Id,
organization.PlanType = families.Type;
organization.Plan = families.Name;
organization.UsersGetPremium = families.UsersGetPremium;
organization.Seats = families.PasswordManager.BaseSeats;
var options = new SubscriptionUpdateOptions
{
Items =
[
new SubscriptionItemOptions
{
Id = passwordManagerItem.Id,
Price = families.PasswordManager.StripePlanId
}
],
Discounts =
[
new SubscriptionDiscountOptions { Coupon = CouponIDs.Milestone3SubscriptionDiscount }
],
ProrationBehavior = ProrationBehavior.None
};
}
],
ProrationBehavior = ProrationBehavior.None
};
if (plan.Type == PlanType.FamiliesAnnually2019)
{
options.Discounts =
[
new SubscriptionDiscountOptions { Coupon = CouponIDs.Milestone3SubscriptionDiscount }
];
var premiumAccessAddOnItem = subscription.Items.FirstOrDefault(item =>
item.Price.Id == plan.PasswordManager.StripePremiumAccessPlanId);
@@ -253,21 +260,21 @@ public class UpcomingInvoiceHandler(
Deleted = true
});
}
}
try
{
await organizationRepository.ReplaceAsync(organization);
await stripeFacade.UpdateSubscription(subscription.Id, options);
}
catch (Exception exception)
{
logger.LogError(
exception,
"Failed to align subscription concerns for Organization ({OrganizationID}) while processing '{EventType}' event ({EventID})",
organization.Id,
@event.Type,
@event.Id);
}
try
{
await organizationRepository.ReplaceAsync(organization);
await stripeFacade.UpdateSubscription(subscription.Id, options);
}
catch (Exception exception)
{
logger.LogError(
exception,
"Failed to align subscription concerns for Organization ({OrganizationID}) while processing '{EventType}' event ({EventID})",
organization.Id,
@event.Type,
@event.Id);
}
}