From de04bc44106cddce1df9702c033ca51b70104fc1 Mon Sep 17 00:00:00 2001 From: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com> Date: Wed, 20 Dec 2023 22:55:30 +0100 Subject: [PATCH] [AC-1753] Automatically assign provider's pricing to new organizations (#7228) * changes for the msp task * fix an issues * resolve pr comment --- .../organization-plans.component.ts | 39 ++++++++++++++++--- .../response/provider/provider.response.ts | 2 + 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.ts b/apps/web/src/app/billing/organizations/organization-plans.component.ts index b8dd447100..f1e9743afb 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.ts +++ b/apps/web/src/app/billing/organizations/organization-plans.component.ts @@ -21,6 +21,7 @@ import { OrganizationCreateRequest } from "@bitwarden/common/admin-console/model import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request"; 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 { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request"; import { BillingResponse } from "@bitwarden/common/billing/models/response/billing.response"; @@ -47,6 +48,13 @@ interface OnSuccessArgs { organizationId: string; } +const Allowed2020PlanTypes = [ + PlanType.TeamsMonthly2020, + PlanType.TeamsAnnually2020, + PlanType.EnterpriseAnnually2020, + PlanType.EnterpriseMonthly2020, +]; + @Component({ selector: "app-organization-plans", templateUrl: "organization-plans.component.html", @@ -119,6 +127,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { secretsManagerPlans: PlanResponse[]; organization: Organization; billing: BillingResponse; + provider: ProviderResponse; private destroy$ = new Subject(); @@ -153,6 +162,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { if (this.hasProvider) { this.formGroup.controls.businessOwned.setValue(true); this.changedOwnedBusiness(); + this.provider = await this.apiService.getProvider(this.providerId); } if (!this.createOrganization) { @@ -214,6 +224,17 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { return this.selectedPlan.isAnnual ? "year" : "month"; } + isProviderQualifiedFor2020Plan() { + const targetDate = new Date("2023-11-06"); + + if (!this.provider || !this.provider.creationDate) { + return false; + } + + const creationDate = new Date(this.provider.creationDate); + return creationDate < targetDate; + } + get selectableProducts() { if (this.acceptingSponsorship) { const familyPlan = this.passwordManagerPlans.find( @@ -230,14 +251,15 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { plan.type !== PlanType.Custom && (!businessOwnedIsChecked || plan.canBeUsedByBusiness) && (this.showFree || plan.product !== ProductType.Free) && - this.planIsEnabled(plan) && (plan.isAnnual || plan.product === ProductType.Free || plan.product === ProductType.TeamsStarter) && (this.currentProductType !== ProductType.TeamsStarter || plan.product === ProductType.Teams || plan.product === ProductType.Enterprise) && - (!this.providerId || plan.product !== ProductType.TeamsStarter), + (!this.providerId || plan.product !== ProductType.TeamsStarter) && + ((!this.isProviderQualifiedFor2020Plan() && this.planIsEnabled(plan)) || + (this.isProviderQualifiedFor2020Plan() && Allowed2020PlanTypes.includes(plan.type))), ); result.sort((planA, planB) => planA.displaySortOrder - planB.displaySortOrder); @@ -247,9 +269,16 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { get selectablePlans() { const selectedProductType = this.formGroup.controls.product.value; - const result = this.passwordManagerPlans?.filter( - (plan) => this.planIsEnabled(plan) && plan.product === selectedProductType, - ); + const result = this.passwordManagerPlans?.filter((plan) => { + const productMatch = plan.product === selectedProductType; + + return ( + (!this.isProviderQualifiedFor2020Plan() && this.planIsEnabled(plan) && productMatch) || + (this.isProviderQualifiedFor2020Plan() && + Allowed2020PlanTypes.includes(plan.type) && + productMatch) + ); + }); result.sort((planA, planB) => planA.displaySortOrder - planB.displaySortOrder); return result; diff --git a/libs/common/src/admin-console/models/response/provider/provider.response.ts b/libs/common/src/admin-console/models/response/provider/provider.response.ts index de53f5e7be..0ea925cd33 100644 --- a/libs/common/src/admin-console/models/response/provider/provider.response.ts +++ b/libs/common/src/admin-console/models/response/provider/provider.response.ts @@ -5,6 +5,7 @@ export class ProviderResponse extends BaseResponse { name: string; businessName: string; billingEmail: string; + creationDate: Date; constructor(response: any) { super(response); @@ -12,5 +13,6 @@ export class ProviderResponse extends BaseResponse { this.name = this.getResponseProperty("Name"); this.businessName = this.getResponseProperty("BusinessName"); this.billingEmail = this.getResponseProperty("BillingEmail"); + this.creationDate = this.getResponseProperty("CreationDate"); } }