mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
[PM-22415] Tax ID notifications for Organizations and Providers (#15996)
* [NO LOGIC] Rename BillableEntity to BitwardenSubscriber This helps us maintain paraody with server where we call this choice type ISubscriber. I chose BitwardenSubscriber to avoid overlap with RxJS * [NO LOGIC] Move subscriber-billing.client to clients folder * [NO LOGIC] Move organization warnings under organization folder * Move getWarnings from OrganizationBillingApiService to new OrganizationBillingClient I'd like us to move away from stashing so much in libs and utilizing the JsLibServicesModule when it's not necessary to do so. These are invocations used exclusively by the Web Vault and, until that changes, they should be treated as such * Refactor OrganizationWarningsService There was a case added to the Inactive Subscription warning for a free trial, but free trials do not represent inactive subscriptions so this was semantically incorrect. This creates another method that pulls the free trial warning and shows a dialog asking the user to subscribe if they're on one. * Implement Tax ID Warnings throughout Admin Console and Provider Portal * Fix linting error * Jimmy's feedback
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { ChangePlanFrequencyRequest } from "@bitwarden/common/billing/models/request/change-plan-frequency.request";
|
||||
import { OrganizationWarningsResponse } from "@bitwarden/common/billing/models/response/organization-warnings.response";
|
||||
|
||||
import {
|
||||
BillingInvoiceResponse,
|
||||
@@ -18,8 +17,6 @@ export abstract class OrganizationBillingApiServiceAbstraction {
|
||||
startAfter?: string,
|
||||
) => Promise<BillingTransactionResponse[]>;
|
||||
|
||||
abstract getWarnings: (id: string) => Promise<OrganizationWarningsResponse>;
|
||||
|
||||
abstract setupBusinessUnit: (
|
||||
id: string,
|
||||
request: {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import { BaseResponse } from "../../../models/response/base.response";
|
||||
|
||||
export class OrganizationWarningsResponse extends BaseResponse {
|
||||
freeTrial?: FreeTrialWarningResponse;
|
||||
inactiveSubscription?: InactiveSubscriptionWarningResponse;
|
||||
resellerRenewal?: ResellerRenewalWarningResponse;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
const freeTrialWarning = this.getResponseProperty("FreeTrial");
|
||||
if (freeTrialWarning) {
|
||||
this.freeTrial = new FreeTrialWarningResponse(freeTrialWarning);
|
||||
}
|
||||
const inactiveSubscriptionWarning = this.getResponseProperty("InactiveSubscription");
|
||||
if (inactiveSubscriptionWarning) {
|
||||
this.inactiveSubscription = new InactiveSubscriptionWarningResponse(
|
||||
inactiveSubscriptionWarning,
|
||||
);
|
||||
}
|
||||
const resellerWarning = this.getResponseProperty("ResellerRenewal");
|
||||
if (resellerWarning) {
|
||||
this.resellerRenewal = new ResellerRenewalWarningResponse(resellerWarning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FreeTrialWarningResponse extends BaseResponse {
|
||||
remainingTrialDays: number;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.remainingTrialDays = this.getResponseProperty("RemainingTrialDays");
|
||||
}
|
||||
}
|
||||
|
||||
class InactiveSubscriptionWarningResponse extends BaseResponse {
|
||||
resolution: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.resolution = this.getResponseProperty("Resolution");
|
||||
}
|
||||
}
|
||||
|
||||
class ResellerRenewalWarningResponse extends BaseResponse {
|
||||
type: "upcoming" | "issued" | "past_due";
|
||||
upcoming?: UpcomingRenewal;
|
||||
issued?: IssuedRenewal;
|
||||
pastDue?: PastDueRenewal;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.type = this.getResponseProperty("Type");
|
||||
switch (this.type) {
|
||||
case "upcoming": {
|
||||
this.upcoming = new UpcomingRenewal(this.getResponseProperty("Upcoming"));
|
||||
break;
|
||||
}
|
||||
case "issued": {
|
||||
this.issued = new IssuedRenewal(this.getResponseProperty("Issued"));
|
||||
break;
|
||||
}
|
||||
case "past_due": {
|
||||
this.pastDue = new PastDueRenewal(this.getResponseProperty("PastDue"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UpcomingRenewal extends BaseResponse {
|
||||
renewalDate: Date;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.renewalDate = new Date(this.getResponseProperty("RenewalDate"));
|
||||
}
|
||||
}
|
||||
|
||||
class IssuedRenewal extends BaseResponse {
|
||||
issuedDate: Date;
|
||||
dueDate: Date;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.issuedDate = new Date(this.getResponseProperty("IssuedDate"));
|
||||
this.dueDate = new Date(this.getResponseProperty("DueDate"));
|
||||
}
|
||||
}
|
||||
|
||||
class PastDueRenewal extends BaseResponse {
|
||||
suspensionDate: Date;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.suspensionDate = new Date(this.getResponseProperty("SuspensionDate"));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ChangePlanFrequencyRequest } from "@bitwarden/common/billing/models/request/change-plan-frequency.request";
|
||||
import { OrganizationWarningsResponse } from "@bitwarden/common/billing/models/response/organization-warnings.response";
|
||||
|
||||
import { ApiService } from "../../../abstractions/api.service";
|
||||
import { OrganizationBillingApiServiceAbstraction } from "../../abstractions/organizations/organization-billing-api.service.abstraction";
|
||||
@@ -53,18 +52,6 @@ export class OrganizationBillingApiService implements OrganizationBillingApiServ
|
||||
return r?.map((i: any) => new BillingTransactionResponse(i)) || [];
|
||||
}
|
||||
|
||||
async getWarnings(id: string): Promise<OrganizationWarningsResponse> {
|
||||
const response = await this.apiService.send(
|
||||
"GET",
|
||||
`/organizations/${id}/billing/warnings`,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
|
||||
return new OrganizationWarningsResponse(response);
|
||||
}
|
||||
|
||||
async setupBusinessUnit(
|
||||
id: string,
|
||||
request: {
|
||||
|
||||
@@ -32,6 +32,7 @@ export enum FeatureFlag {
|
||||
AllowTrialLengthZero = "pm-20322-allow-trial-length-0",
|
||||
PM21881_ManagePaymentDetailsOutsideCheckout = "pm-21881-manage-payment-details-outside-checkout",
|
||||
PM21821_ProviderPortalTakeover = "pm-21821-provider-portal-takeover",
|
||||
PM22415_TaxIDWarnings = "pm-22415-tax-id-warnings",
|
||||
|
||||
/* Key Management */
|
||||
PrivateKeyRegeneration = "pm-12241-private-key-regeneration",
|
||||
@@ -108,6 +109,7 @@ export const DefaultFeatureFlagValue = {
|
||||
[FeatureFlag.AllowTrialLengthZero]: FALSE,
|
||||
[FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout]: FALSE,
|
||||
[FeatureFlag.PM21821_ProviderPortalTakeover]: FALSE,
|
||||
[FeatureFlag.PM22415_TaxIDWarnings]: FALSE,
|
||||
|
||||
/* Key Management */
|
||||
[FeatureFlag.PrivateKeyRegeneration]: FALSE,
|
||||
|
||||
Reference in New Issue
Block a user