mirror of
https://github.com/bitwarden/browser
synced 2026-01-07 02:53:28 +00:00
[PM-8830] Billing Enums Rename (#9612)
* Renamed ProductType to ProductTierType * Renamed Product properties to ProductTier * Moved product-tier-type.enum.ts to billing folder * Added ProductType enum
This commit is contained in:
@@ -9,16 +9,15 @@ import {
|
||||
PaymentInformation,
|
||||
PlanInformation,
|
||||
} from "@bitwarden/common/billing/abstractions/organization-billing.service";
|
||||
import { PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { PaymentMethodType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { BillingSharedModule, PaymentComponent, TaxInfoComponent } from "../../shared";
|
||||
|
||||
export type TrialOrganizationType = Exclude<ProductType, ProductType.Free>;
|
||||
export type TrialOrganizationType = Exclude<ProductTierType, ProductTierType.Free>;
|
||||
|
||||
export interface OrganizationInfo {
|
||||
name: string;
|
||||
@@ -176,19 +175,19 @@ export class TrialBillingStepComponent implements OnInit {
|
||||
[cadence in SubscriptionCadence]?: PlanType;
|
||||
};
|
||||
} = {
|
||||
[ProductType.Enterprise]: {
|
||||
[ProductTierType.Enterprise]: {
|
||||
[SubscriptionCadence.Annual]: PlanType.EnterpriseAnnually,
|
||||
[SubscriptionCadence.Monthly]: PlanType.EnterpriseMonthly,
|
||||
},
|
||||
[ProductType.Families]: {
|
||||
[ProductTierType.Families]: {
|
||||
[SubscriptionCadence.Annual]: PlanType.FamiliesAnnually,
|
||||
// No monthly option for Families plan
|
||||
},
|
||||
[ProductType.Teams]: {
|
||||
[ProductTierType.Teams]: {
|
||||
[SubscriptionCadence.Annual]: PlanType.TeamsAnnually,
|
||||
[SubscriptionCadence.Monthly]: PlanType.TeamsMonthly,
|
||||
},
|
||||
[ProductType.TeamsStarter]: {
|
||||
[ProductTierType.TeamsStarter]: {
|
||||
// No annual option for Teams Starter plan
|
||||
[SubscriptionCadence.Monthly]: PlanType.TeamsStarter,
|
||||
},
|
||||
@@ -233,10 +232,10 @@ export class TrialBillingStepComponent implements OnInit {
|
||||
|
||||
private isApplicable(plan: PlanResponse): boolean {
|
||||
const hasCorrectProductType =
|
||||
plan.product === ProductType.Enterprise ||
|
||||
plan.product === ProductType.Families ||
|
||||
plan.product === ProductType.Teams ||
|
||||
plan.product === ProductType.TeamsStarter;
|
||||
plan.productTier === ProductTierType.Enterprise ||
|
||||
plan.productTier === ProductTierType.Families ||
|
||||
plan.productTier === ProductTierType.Teams ||
|
||||
plan.productTier === ProductTierType.TeamsStarter;
|
||||
const notDisabledOrLegacy = !plan.disabled && !plan.legacyYear;
|
||||
return hasCorrectProductType && notDisabledOrLegacy;
|
||||
}
|
||||
|
||||
@@ -51,14 +51,17 @@
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<h2 bitTypography="h2">{{ "chooseYourPlan" | i18n }}</h2>
|
||||
<bit-radio-group formControlName="product" [block]="true">
|
||||
<bit-radio-group formControlName="productTier" [block]="true">
|
||||
<div *ngFor="let selectableProduct of selectableProducts" class="tw-mb-3">
|
||||
<bit-radio-button [value]="selectableProduct.product" (change)="changedProduct()">
|
||||
<bit-radio-button [value]="selectableProduct.productTier" (change)="changedProduct()">
|
||||
<bit-label>{{ selectableProduct.nameLocalizationKey | i18n }}</bit-label>
|
||||
<bit-hint class="tw-text-sm"
|
||||
>{{ selectableProduct.descriptionLocalizationKey | i18n: "1" }}
|
||||
<ng-container
|
||||
*ngIf="selectableProduct.product === productTypes.Enterprise; else nonEnterprisePlans"
|
||||
*ngIf="
|
||||
selectableProduct.productTier === productTypes.Enterprise;
|
||||
else nonEnterprisePlans
|
||||
"
|
||||
>
|
||||
<ul class="tw-pl-0 tw-list-inside tw-mb-0">
|
||||
<li>{{ "includeAllTeamsFeatures" | i18n }}</li>
|
||||
@@ -75,7 +78,8 @@
|
||||
<ng-template #nonEnterprisePlans>
|
||||
<ng-container
|
||||
*ngIf="
|
||||
selectableProduct.product === productTypes.Teams && teamsStarterPlanIsAvailable;
|
||||
selectableProduct.productTier === productTypes.Teams &&
|
||||
teamsStarterPlanIsAvailable;
|
||||
else fullFeatureList
|
||||
"
|
||||
>
|
||||
@@ -90,13 +94,13 @@
|
||||
</ng-container>
|
||||
<ng-template #fullFeatureList>
|
||||
<ul class="tw-pl-0 tw-list-inside tw-mb-0">
|
||||
<li *ngIf="selectableProduct.product == productTypes.Free">
|
||||
<li *ngIf="selectableProduct.productTier == productTypes.Free">
|
||||
{{ "limitedUsers" | i18n: selectableProduct.PasswordManager.maxSeats }}
|
||||
</li>
|
||||
<li
|
||||
*ngIf="
|
||||
selectableProduct.product != productTypes.Free &&
|
||||
selectableProduct.product != productTypes.TeamsStarter &&
|
||||
selectableProduct.productTier != productTypes.Free &&
|
||||
selectableProduct.productTier != productTypes.TeamsStarter &&
|
||||
selectableProduct.PasswordManager.maxSeats
|
||||
"
|
||||
>
|
||||
@@ -136,7 +140,7 @@
|
||||
{{ "onPremHostingOptional" | i18n }}
|
||||
</li>
|
||||
<li *ngIf="selectableProduct.usersGetPremium">{{ "usersGetPremium" | i18n }}</li>
|
||||
<li *ngIf="selectableProduct.product != productTypes.Free">
|
||||
<li *ngIf="selectableProduct.productTier != productTypes.Free">
|
||||
{{ "priorityCustomerSupport" | i18n }}
|
||||
</li>
|
||||
<li *ngIf="selectableProduct.trialPeriodDays && createOrganization">
|
||||
@@ -147,7 +151,7 @@
|
||||
</ng-template>
|
||||
</bit-hint>
|
||||
</bit-radio-button>
|
||||
<span *ngIf="selectableProduct.product != productTypes.Free" class="tw-pl-4">
|
||||
<span *ngIf="selectableProduct.productTier != productTypes.Free" class="tw-pl-4">
|
||||
<ng-container
|
||||
*ngIf="selectableProduct.PasswordManager.basePrice && !acceptingSponsorship"
|
||||
>
|
||||
@@ -189,13 +193,13 @@
|
||||
}}
|
||||
/{{ "month" | i18n }}
|
||||
</span>
|
||||
<span *ngIf="selectableProduct.product == productTypes.Free" class="tw-pl-4">{{
|
||||
<span *ngIf="selectableProduct.productTier == productTypes.Free" class="tw-pl-4">{{
|
||||
"freeForever" | i18n
|
||||
}}</span>
|
||||
</div>
|
||||
</bit-radio-group>
|
||||
</bit-section>
|
||||
<bit-section *ngIf="formGroup.value.product !== productTypes.Free">
|
||||
<bit-section *ngIf="formGroup.value.productTier !== productTypes.Free">
|
||||
<bit-section
|
||||
*ngIf="
|
||||
selectedPlan.PasswordManager.hasAdditionalSeatsOption &&
|
||||
@@ -415,7 +419,7 @@
|
||||
</bit-section>
|
||||
|
||||
<!-- Payment info -->
|
||||
<bit-section *ngIf="formGroup.value.product !== productTypes.Free">
|
||||
<bit-section *ngIf="formGroup.value.productTier !== productTypes.Free">
|
||||
<h2 bitTypography="h2">
|
||||
{{ (createOrganization ? "paymentInformation" : "billingInformation") | i18n }}
|
||||
</h2>
|
||||
|
||||
@@ -23,12 +23,11 @@ import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/
|
||||
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
|
||||
import { ProviderOrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-organization-create.request";
|
||||
import { ProviderResponse } from "@bitwarden/common/admin-console/models/response/provider/provider.response";
|
||||
import { PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { PaymentMethodType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request";
|
||||
import { BillingResponse } from "@bitwarden/common/billing/models/response/billing.response";
|
||||
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -73,16 +72,16 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
selectedFile: File;
|
||||
|
||||
@Input()
|
||||
get product(): ProductType {
|
||||
return this._product;
|
||||
get productTier(): ProductTierType {
|
||||
return this._productTier;
|
||||
}
|
||||
|
||||
set product(product: ProductType) {
|
||||
this._product = product;
|
||||
this.formGroup?.controls?.product?.setValue(product);
|
||||
set productTier(product: ProductTierType) {
|
||||
this._productTier = product;
|
||||
this.formGroup?.controls?.productTier?.setValue(product);
|
||||
}
|
||||
|
||||
private _product = ProductType.Free;
|
||||
private _productTier = ProductTierType.Free;
|
||||
|
||||
@Input()
|
||||
get plan(): PlanType {
|
||||
@@ -102,7 +101,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
|
||||
loading = true;
|
||||
selfHosted = false;
|
||||
productTypes = ProductType;
|
||||
productTypes = ProductTierType;
|
||||
formPromise: Promise<string>;
|
||||
singleOrgPolicyAppliesToActiveUser = false;
|
||||
isInTrialFlow = false;
|
||||
@@ -123,7 +122,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
additionalSeats: [0, [Validators.min(0), Validators.max(100000)]],
|
||||
clientOwnerEmail: ["", [Validators.email]],
|
||||
plan: [this.plan],
|
||||
product: [this.product],
|
||||
productTier: [this.productTier],
|
||||
secretsManager: this.secretsManagerSubscription,
|
||||
});
|
||||
|
||||
@@ -166,20 +165,23 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
this.passwordManagerPlans = plans.data.filter((plan) => !!plan.PasswordManager);
|
||||
this.secretsManagerPlans = plans.data.filter((plan) => !!plan.SecretsManager);
|
||||
|
||||
if (this.product === ProductType.Enterprise || this.product === ProductType.Teams) {
|
||||
if (
|
||||
this.productTier === ProductTierType.Enterprise ||
|
||||
this.productTier === ProductTierType.Teams
|
||||
) {
|
||||
this.formGroup.controls.businessOwned.setValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.currentPlan && this.currentPlan.product !== ProductType.Enterprise) {
|
||||
if (this.currentPlan && this.currentPlan.productTier !== ProductTierType.Enterprise) {
|
||||
const upgradedPlan = this.passwordManagerPlans.find((plan) =>
|
||||
this.currentPlan.product === ProductType.Free
|
||||
this.currentPlan.productTier === ProductTierType.Free
|
||||
? plan.type === PlanType.FamiliesAnnually
|
||||
: plan.upgradeSortOrder == this.currentPlan.upgradeSortOrder + 1,
|
||||
);
|
||||
|
||||
this.plan = upgradedPlan.type;
|
||||
this.product = upgradedPlan.product;
|
||||
this.productTier = upgradedPlan.productTier;
|
||||
}
|
||||
|
||||
if (this.hasProvider) {
|
||||
@@ -190,7 +192,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
(plan) => plan.type === PlanType.TeamsAnnually,
|
||||
);
|
||||
this.plan = providerDefaultPlan.type;
|
||||
this.product = providerDefaultPlan.product;
|
||||
this.productTier = providerDefaultPlan.productTier;
|
||||
}
|
||||
|
||||
if (!this.createOrganization) {
|
||||
@@ -229,7 +231,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
|
||||
get upgradeRequiresPaymentMethod() {
|
||||
return (
|
||||
this.organization?.planProductType === ProductType.Free &&
|
||||
this.organization?.productTierType === ProductTierType.Free &&
|
||||
!this.showFree &&
|
||||
!this.billing?.paymentSource
|
||||
);
|
||||
@@ -277,12 +279,12 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
(plan) =>
|
||||
plan.type !== PlanType.Custom &&
|
||||
(!businessOwnedIsChecked || plan.canBeUsedByBusiness) &&
|
||||
(this.showFree || plan.product !== ProductType.Free) &&
|
||||
(this.showFree || plan.productTier !== ProductTierType.Free) &&
|
||||
(plan.isAnnual ||
|
||||
plan.product === ProductType.Free ||
|
||||
plan.product === ProductType.TeamsStarter) &&
|
||||
plan.productTier === ProductTierType.Free ||
|
||||
plan.productTier === ProductTierType.TeamsStarter) &&
|
||||
(!this.currentPlan || this.currentPlan.upgradeSortOrder < plan.upgradeSortOrder) &&
|
||||
(!this.hasProvider || plan.product !== ProductType.TeamsStarter) &&
|
||||
(!this.hasProvider || plan.productTier !== ProductTierType.TeamsStarter) &&
|
||||
((!this.isProviderQualifiedFor2020Plan() && this.planIsEnabled(plan)) ||
|
||||
(this.isProviderQualifiedFor2020Plan() &&
|
||||
Allowed2020PlansForLegacyProviders.includes(plan.type))),
|
||||
@@ -294,11 +296,11 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get selectablePlans() {
|
||||
const selectedProductType = this.formGroup.controls.product.value;
|
||||
const selectedProductTierType = this.formGroup.controls.productTier.value;
|
||||
const result =
|
||||
this.passwordManagerPlans?.filter(
|
||||
(plan) =>
|
||||
plan.product === selectedProductType &&
|
||||
plan.productTier === selectedProductTierType &&
|
||||
((!this.isProviderQualifiedFor2020Plan() && this.planIsEnabled(plan)) ||
|
||||
(this.isProviderQualifiedFor2020Plan() &&
|
||||
Allowed2020PlansForLegacyProviders.includes(plan.type))),
|
||||
@@ -516,10 +518,10 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
if (this.teamsStarterPlanIsAvailable) {
|
||||
this.formGroup.controls.product.setValue(ProductType.TeamsStarter);
|
||||
this.formGroup.controls.productTier.setValue(ProductTierType.TeamsStarter);
|
||||
this.formGroup.controls.plan.setValue(PlanType.TeamsStarter);
|
||||
} else {
|
||||
this.formGroup.controls.product.setValue(ProductType.Teams);
|
||||
this.formGroup.controls.productTier.setValue(ProductTierType.Teams);
|
||||
this.formGroup.controls.plan.setValue(PlanType.TeamsAnnually);
|
||||
}
|
||||
this.changedProduct();
|
||||
@@ -766,19 +768,19 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
|
||||
private upgradeFlowPrefillForm() {
|
||||
if (this.acceptingSponsorship) {
|
||||
this.formGroup.controls.product.setValue(ProductType.Families);
|
||||
this.formGroup.controls.productTier.setValue(ProductTierType.Families);
|
||||
this.changedProduct();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.currentPlan && this.currentPlan.product !== ProductType.Enterprise) {
|
||||
if (this.currentPlan && this.currentPlan.productTier !== ProductTierType.Enterprise) {
|
||||
const upgradedPlan = this.passwordManagerPlans.find((plan) => {
|
||||
if (this.currentPlan.product === ProductType.Free) {
|
||||
if (this.currentPlan.productTier === ProductTierType.Free) {
|
||||
return plan.type === PlanType.FamiliesAnnually;
|
||||
}
|
||||
|
||||
if (
|
||||
this.currentPlan.product === ProductType.Families &&
|
||||
this.currentPlan.productTier === ProductTierType.Families &&
|
||||
!this.teamsStarterPlanIsAvailable
|
||||
) {
|
||||
return plan.type === PlanType.TeamsAnnually;
|
||||
@@ -788,7 +790,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.plan = upgradedPlan.type;
|
||||
this.product = upgradedPlan.product;
|
||||
this.productTier = upgradedPlan.productTier;
|
||||
this.changedProduct();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { OrganizationApiKeyType, ProviderStatusType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||
import { BillingSubscriptionItemResponse } from "@bitwarden/common/billing/models/response/subscription.response";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -53,7 +52,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
manageBillingFromProviderPortal = ManageBilling;
|
||||
isProviderManaged = false;
|
||||
|
||||
protected readonly teamsStarter = ProductType.TeamsStarter;
|
||||
protected readonly teamsStarter = ProductTierType.TeamsStarter;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
@@ -286,7 +285,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
}
|
||||
} else if (this.sub.maxAutoscaleSeats === this.sub.seats && this.sub.seats != null) {
|
||||
return this.i18nService.t("subscriptionMaxReached", this.sub.seats.toString());
|
||||
} else if (this.userOrg.planProductType === ProductType.TeamsStarter) {
|
||||
} else if (this.userOrg.productTierType === ProductTierType.TeamsStarter) {
|
||||
return this.i18nService.t("subscriptionUserSeatsWithoutAdditionalSeatsOption", 10);
|
||||
} else if (this.sub.maxAutoscaleSeats == null) {
|
||||
return this.i18nService.t("subscriptionUserSeatsUnlimitedAutoscale");
|
||||
@@ -440,12 +439,12 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
};
|
||||
|
||||
get showChangePlanButton() {
|
||||
return this.sub.plan.product !== ProductType.Enterprise && !this.showChangePlan;
|
||||
return this.sub.plan.productTier !== ProductTierType.Enterprise && !this.showChangePlan;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to sort subscription items by product type and then by addon status
|
||||
* Helper to sort subscription items by productTier type and then by addon status
|
||||
*/
|
||||
function sortSubscriptionItems(
|
||||
a: BillingSubscriptionItemResponse,
|
||||
|
||||
@@ -3,9 +3,9 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { Subject, startWith, takeUntil } from "rxjs";
|
||||
|
||||
import { ControlsOf } from "@bitwarden/angular/types/controls-of";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { BillingCustomerDiscount } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { SecretsManagerLogo } from "../../layouts/secrets-manager-logo";
|
||||
@@ -40,7 +40,7 @@ export class SecretsManagerSubscribeComponent implements OnInit, OnDestroy {
|
||||
@Input() customerDiscount: BillingCustomerDiscount;
|
||||
|
||||
logo = SecretsManagerLogo;
|
||||
productTypes = ProductType;
|
||||
productTypes = ProductTierType;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
@@ -75,17 +75,17 @@ export class SecretsManagerSubscribeComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
get product() {
|
||||
return this.selectedPlan.product;
|
||||
return this.selectedPlan.productTier;
|
||||
}
|
||||
|
||||
get planName() {
|
||||
switch (this.product) {
|
||||
case ProductType.Free:
|
||||
case ProductTierType.Free:
|
||||
return this.i18nService.t("free2PersonOrganization");
|
||||
case ProductType.Teams:
|
||||
case ProductType.TeamsStarter:
|
||||
case ProductTierType.Teams:
|
||||
case ProductTierType.TeamsStarter:
|
||||
return this.i18nService.t("planNameTeams");
|
||||
case ProductType.Enterprise:
|
||||
case ProductTierType.Enterprise:
|
||||
return this.i18nService.t("planNameEnterprise");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user