-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[PM-15814]Alert owners of reseller-managed orgs to renewal events #12607
[PM-15814]Alert owners of reseller-managed orgs to renewal events #12607
Conversation
Fixed Issues
|
Codecov ReportAttention: Patch coverage is
✅ All tests successful. No failed tests found. Additional details and impacted files@@ Coverage Diff @@
## main #12607 +/- ##
==========================================
- Coverage 33.79% 33.76% -0.04%
==========================================
Files 2911 2912 +1
Lines 90718 90781 +63
Branches 17155 17173 +18
==========================================
- Hits 30655 30649 -6
- Misses 57674 57743 +69
Partials 2389 2389 ☔ View full report in Codecov by Sentry. |
@cyprain-okeke are the date formats localized? MM/DD/YYYY is not used in most places. |
…gs-to-renewal-events
…rs-of-reseller-managed-orgs-to-renewal-events' into pm-15814-alert-owners-of-reseller-managed-orgs-to-renewal-events
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. just a small nit
@@ -592,6 +599,7 @@ export class VaultComponent implements OnInit, OnDestroy { | |||
.subscribe(); | |||
|
|||
this.unpaidSubscriptionDialog$.pipe(takeUntil(this.destroy$)).subscribe(); | |||
//this.resellerWarning1$.pipe(takeUntil(this.destroy$)).subscribe(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like leftover commented out code, okay to remove?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some small changes needed
@@ -187,6 +191,8 @@ export class VaultComponent implements OnInit, OnDestroy { | |||
private hasSubscription$ = new BehaviorSubject<boolean>(false); | |||
protected currentSearchText$: Observable<string>; | |||
protected freeTrial$: Observable<FreeTrial>; | |||
protected resellerWarning$: Observable<ResellerWarning | null>; | |||
protected resellerWarning: ResellerWarning; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this variable is used anywhere
@@ -592,6 +599,7 @@ export class VaultComponent implements OnInit, OnDestroy { | |||
.subscribe(); | |||
|
|||
this.unpaidSubscriptionDialog$.pipe(takeUntil(this.destroy$)).subscribe(); | |||
//this.resellerWarning1$.pipe(takeUntil(this.destroy$)).subscribe(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed if it's not needed anymore
@@ -612,6 +619,16 @@ export class VaultComponent implements OnInit, OnDestroy { | |||
}), | |||
); | |||
|
|||
this.resellerWarning$ = combineLatest([organization$]).pipe( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we only need combineLatest
when we have multiple independent streams. This can be simplified a bit
this.resellerWarning$ = combineLatest([organization$]).pipe( | |
this.resellerWarning$ = organization$.pipe( | |
filter(org => org.isOwner), | |
switchMap(org => this.billingApiService | |
.getOrganizationBillingMetadata(org.id) | |
.pipe(map(metadata => ({org, metadata}))) | |
), | |
map() |
05e0d3b
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-15814
📔 Objective
Organizations that are managed by a reseller have a higher probability of churning. This happens because of a breakdown in communication around renewal dates.
the managed org does not have visibility into when their renewal date is, because their billing is managed by the reseller. Without knowing their renewal date, the managed org cannot issue a purchase order to their reseller.
the reseller does not respond to invoices from Bitwarden because they do not include a purchase order number matching one from a customer of theirs (the managed org).
the first indication the managed org has that something has gone wrong is when the organization is suspended. This happens 30 days after the automatic invoice we send to the reseller is marked as unpaid, which is usually 45 days after it was issued (resellers get net-45 by default).
To help prevent this issue, we will show in-product messaging to owners of reseller-managed organizations, alerting them that their renewal date is upcoming, and to reach out to their reseller to insure uninterrupted service.
📸 Screenshots
⏰ Reminders before review
🦮 Reviewer guidelines
:+1:
) or similar for great changes:memo:
) or ℹ️ (:information_source:
) for notes or general info:question:
) for questions:thinking:
) or 💭 (:thought_balloon:
) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:
) for suggestions / improvements:x:
) or:warning:
) for more significant problems or concerns needing attention:seedling:
) or ♻️ (:recycle:
) for future improvements or indications of technical debt:pick:
) for minor or nitpick changes