[PM-37084] Business Aware Schedule Recovery and Cancellation#7686
[PM-37084] Business Aware Schedule Recovery and Cancellation#7686sbrown-livefront wants to merge 20 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #7686 +/- ##
==========================================
- Coverage 60.43% 60.43% -0.01%
==========================================
Files 2140 2140
Lines 94628 94712 +84
Branches 8445 8456 +11
==========================================
+ Hits 57193 57239 +46
- Misses 35430 35462 +32
- Partials 2005 2011 +6 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed the unified Code Review DetailsNo additional findings beyond the three threads already resolved on this PR. |
|
amorask-bitwarden
left a comment
There was a problem hiding this comment.
Looks great - just left a question on a refactoring opp we have here. Let me know if you want to discuss further.
| var subscription = await stripeAdapter.GetSubscriptionAsync( | ||
| subscriber.GatewaySubscriptionId, | ||
| new SubscriptionGetOptions { Expand = ["discounts"] }); | ||
| new SubscriptionGetOptions { Expand = ["discounts", "customer", "customer.discount"] }); |
There was a problem hiding this comment.
⛏️ Expanding customer.discount necessarily expands customer.
| public async Task HandleAsync(Event parsedEvent) | ||
| { | ||
| var subscription = await _stripeEventService.GetSubscription(parsedEvent, true, ["customer", "discounts", "latest_invoice", "test_clock"]); | ||
| var subscription = await _stripeEventService.GetSubscription(parsedEvent, true, ["customer", "customer.discount", "discounts", "latest_invoice", "test_clock"]); |
There was a problem hiding this comment.
⛏ Same thing here.
| /// <param name="subscription"> The subscription to schedule a price increase for. </param> | ||
| /// <param name="organizationId"> The ID of the organization associated with the subscription. </param> | ||
| /// <returns> True if the schedule was dispatched successfully, false otherwise. </returns> | ||
| private async Task<bool> DispatchOrganizationScheduleAsync(Subscription subscription, Guid organizationId) |
There was a problem hiding this comment.
I think we have a refactoring opportunity here that I overlooked in the original implementation. This is almost the same exact logic that's in the UpcomingInvoiceHandler.ScheduleBusinessPlanPriceMigration. It seems like we're going to need the same logic in multiple areas, but I'm not positive they're supposed to behave exactly the same way between the original scheduling and a reinstatement. For example, some of the validation checks such as assignment.ScheduledAt is not null might not translate. Wanna give this a whirl or discuss further?



🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-37084
📔 Objective
Introduces a new unified scheduling path for price increases on subscriptions, enabling both personal and business (organization) subscription reinstatements to be handled by a single method. The main change is the addition of the
ScheduleForSubscriptionmethod inPriceIncreaseScheduler, which intelligently routes scheduling based on the subscription owner type. This supports new business plan price migration scenarios and improves maintainability by consolidating logic. The changes also include expanded test coverage to ensure correct routing and handling for various subscription and organization scenarios.Core functionality changes:
ScheduleForSubscriptiontoIPriceIncreaseSchedulerand implemented it inPriceIncreaseScheduler, which dispatches scheduling to the correct path (personal, business, or provider) based on the subscription owner. This method includes error handling and logging for unsupported or invalid cases.DispatchOrganizationScheduleAsyncto handle business plan migrations, including checks for organization existence, plan type, cohort assignment, cohort status, and migration path validity.PriceIncreaseSchedulerto include organization and cohort repositories, enabling the new scheduling logic.Integration and behavior updates:
SchedulePersonalPriceIncreasewithScheduleForSubscriptionin business logic (SubscriptionUpdatedHandler,ReinstateSubscriptionCommand) and associated tests, ensuring all scheduling now uses the unified path.Metadata and Stripe API Improvements
CancellingUserId, toMetadataKeysand updated all relevant code to use this constant, ensuring consistency and clarity.Test Clock and Testing Improvements
📸 Screenshots
Screen.Recording.2026-05-21.at.2.42.23.PM.mov