-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[PM-37084] Business Aware Schedule Recovery and Cancellation #7686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
23b2951
af04330
18f84c7
67eede5
2fdfacb
ff70af0
33910be
7d424f9
12c7b8b
b1bb099
c4d5f30
18ecb4d
365f579
599a5d7
36bd4d2
2cbbac1
1582b86
157ead7
36b3453
97a2fb4
68ffb1d
59ec480
cb962e2
bcf9fe8
3baa358
66a3e8e
59d3c27
8cdee4c
c9eba37
53cacd7
64bc9ee
4840b16
a0f1caa
eb5f904
3babcfe
5f8e86c
1274c66
c6e40b8
a54e3ef
78a678a
30a0ead
ca8e254
6e8b785
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |
| using Bit.Core.Repositories; | ||
| using Bit.Core.Services; | ||
| using Stripe; | ||
| using Stripe.TestHelpers; | ||
| using Event = Stripe.Event; | ||
| using Plan = Bit.Core.Models.StaticStore.Plan; | ||
| using PremiumPlan = Bit.Core.Billing.Pricing.Premium.Plan; | ||
|
|
@@ -356,45 +357,38 @@ private async Task<bool> ScheduleBusinessPlanPriceMigrationAsync( | |
| } | ||
|
|
||
| var assignment = await assignmentRepository.GetByOrganizationIdAsync(organization.Id); | ||
|
|
||
| if (assignment is null || assignment.ScheduledDate is not null) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| var cohort = await cohortRepository.GetByIdAsync(assignment.CohortId); | ||
|
|
||
| if (cohort is null || !cohort.IsActive) | ||
| if (subscription.TestClock != null) | ||
| { | ||
| return false; | ||
| await WaitForTestClockToAdvanceAsync(subscription.TestClock); | ||
| } | ||
|
|
||
| if (cohort.MigrationPathId is null) | ||
| { | ||
| // Churn-only cohort β no migration to schedule. | ||
| return false; | ||
| } | ||
| var migrationScheduled = await priceIncreaseScheduler.ScheduleForSubscription(subscription); | ||
|
|
||
| var migrationPath = MigrationPaths.FromId(cohort.MigrationPathId.Value); | ||
| if (migrationPath is null) | ||
| if (!migrationScheduled) | ||
|
sbrown-livefront marked this conversation as resolved.
|
||
| { | ||
| logger.LogError( | ||
| "Unknown MigrationPathId ({MigrationPathId}) on cohort ({CohortId}) for Organization ({OrganizationId})", | ||
| cohort.MigrationPathId, cohort.Id, organization.Id); | ||
| return false; | ||
| } | ||
|
|
||
| if (organization.PlanType != migrationPath.FromPlan) | ||
| var cohort = await cohortRepository.GetByIdAsync(assignment.CohortId); | ||
| if (cohort?.MigrationPathId is null) | ||
| { | ||
| logger.LogWarning( | ||
| "Skipping business price migration for Organization ({OrganizationId}); PlanType {ActualPlan} does not match cohort {CohortName} source {ExpectedPlan}", | ||
| organization.Id, organization.PlanType, cohort.Name, migrationPath.FromPlan); | ||
| return false; | ||
| "Cohort ({CohortId}) missing or has no MigrationPathId; skipping renewal email for Organization ({OrganizationId})", | ||
| assignment.CohortId, organization.Id); | ||
| return true; | ||
| } | ||
|
|
||
| var scheduled = await priceIncreaseScheduler.ScheduleBusinessPriceIncrease(subscription, cohort); | ||
| if (!scheduled) | ||
| var migrationPath = MigrationPaths.FromId(cohort.MigrationPathId.Value); | ||
| if (migrationPath is null) | ||
| { | ||
| logger.LogWarning( | ||
| "Unknown MigrationPathId ({MigrationPathId}) on cohort ({CohortId}); skipping renewal email for Organization ({OrganizationId})", | ||
| cohort.MigrationPathId, cohort.Id, organization.Id); | ||
| return true; | ||
| } | ||
|
|
||
|
Comment on lines
+377
to
394
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. β Seems like some logging would be useful for these
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in 30a0ead |
||
|
|
@@ -428,6 +422,19 @@ private Task SendBusinessRenewalEmailAsync( | |
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| private async Task WaitForTestClockToAdvanceAsync(TestClock testClock) | ||
| { | ||
| while (testClock.Status != "ready") | ||
| { | ||
| await Task.Delay(TimeSpan.FromSeconds(2)); | ||
| testClock = await stripeAdapter.GetTestClockAsync(testClock.Id); | ||
| if (testClock.Status == "internal_failure") | ||
| { | ||
| throw new Exception("Stripe Test Clock encountered an internal failure"); | ||
| } | ||
| } | ||
| } | ||
|
sbrown-livefront marked this conversation as resolved.
|
||
|
|
||
| #endregion | ||
|
|
||
| #region Premium Users | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| ο»Ώnamespace Bit.Core.Billing.Pricing; | ||
|
|
||
| /// <summary> | ||
| /// Controls optional guard behavior when scheduling an organization price increase via | ||
| /// <see cref="IPriceIncreaseScheduler.ScheduleForSubscription"/>. Guards are applied | ||
| /// during cohort validation before any Stripe calls are made. | ||
| /// </summary> | ||
| public record OrganizationPriceIncreaseOptions | ||
| { | ||
| /// <summary> | ||
| /// Skip scheduling if a price increase has already been scheduled for this | ||
| /// organization (i.e. <c>assignment.ScheduledDate</c> is set). | ||
| /// </summary> | ||
| public bool SkipIfAlreadyScheduled { get; init; } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.