Skip to content

Commit 5cc6b44

Browse files
refactor(billing): use plan migration extensions in PriceIncreaseScheduler
1 parent be085ee commit 5cc6b44

1 file changed

Lines changed: 5 additions & 17 deletions

File tree

src/Core/Billing/Pricing/PriceIncreaseScheduler.cs

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,7 @@ await stripeAdapter.UpdateSubscriptionScheduleAsync(schedule.Id,
556556
// Teams Starter and Teams 2019 are Packaged sources whose base line (and, for Teams 2019, the
557557
// seat-overage line) collapse onto the Scalable target's single seat price at a usage-resolved
558558
// quantity. Scalable sources preserve their line-item quantities.
559-
var isPackagedSourcePlan = sourcePlan.HasNonSeatBasedPasswordManagerPlan() ||
560-
migrationPath.SeatCountPolicy == SeatCountPolicy.ActualUsage;
559+
var isPackagedSourcePlan = sourcePlan.IsPackagedMigrationSource(migrationPath.SeatCountPolicy);
561560

562561
var items = new List<SubscriptionSchedulePhaseItemOptions>();
563562
foreach (var item in subscription.Items.Data)
@@ -619,27 +618,16 @@ await stripeAdapter.UpdateSubscriptionScheduleAsync(schedule.Id,
619618
}
620619

621620
/// <summary>
622-
/// Resolves the billed Phase 2 seat count for a Packaged source. Teams Starter (flat bundle)
623-
/// bills occupied seats, floored at 1; Teams 2019 (seat overage) bills occupied seats below the
624-
/// base and the purchased count at or above it.
621+
/// Resolves the billed Phase 2 seat count for a Packaged source from the organization's actual usage.
625622
/// </summary>
626623
private async Task<int> CalculateTargetPlanSeatCountAsync(OrganizationPlan sourcePlan, Guid organizationId)
627624
{
625+
// Packaged line items don't reflect the true total, so bill by actual usage. organization.Seats
626+
// supplies the purchased count ResolveMigratedSeatCount uses for the seat-overage case.
628627
var occupiedSeatCount = (await organizationRepository
629628
.GetOccupiedSeatCountByOrganizationIdAsync(organizationId)).Total;
630-
631-
// Teams Starter: flat bundle, no overage — bill occupied seats (no base/purchased comparison),
632-
// floored at 1.
633-
if (sourcePlan.HasNonSeatBasedPasswordManagerPlan())
634-
{
635-
return Math.Max(1, occupiedSeatCount);
636-
}
637-
638-
// Teams 2019: occupied below the packaged base, otherwise the purchased seat count.
639629
var organization = await organizationRepository.GetByIdAsync(organizationId);
640-
return occupiedSeatCount < sourcePlan.PasswordManager.BaseSeats
641-
? occupiedSeatCount
642-
: organization?.Seats ?? occupiedSeatCount;
630+
return sourcePlan.ResolveMigratedSeatCount(occupiedSeatCount, organization?.Seats);
643631
}
644632

645633
/// <summary>

0 commit comments

Comments
 (0)