diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.html b/apps/web/src/app/billing/organizations/organization-plans.component.html index 6e587ebc2d..0a925dc228 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.html +++ b/apps/web/src/app/billing/organizations/organization-plans.component.html @@ -392,7 +392,10 @@ {{ paymentDesc }} - +
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 c6b7b4c977..f79b33f5b8 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.ts +++ b/apps/web/src/app/billing/organizations/organization-plans.component.ts @@ -16,11 +16,14 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { OrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/organization-create.request"; 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 { 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"; 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"; @@ -114,6 +117,8 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { passwordManagerPlans: PlanResponse[]; secretsManagerPlans: PlanResponse[]; + organization: Organization; + billing: BillingResponse; private destroy$ = new Subject(); @@ -164,6 +169,11 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { this.singleOrgPolicyAppliesToActiveUser = policyAppliesToActiveUser; }); + if (this.organizationId) { + this.organization = this.organizationService.get(this.organizationId); + this.billing = await this.organizationApiService.getBilling(this.organizationId); + } + this.loading = false; } @@ -180,6 +190,14 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { return this.organizationId == null; } + get upgradeRequiresPaymentMethod() { + return ( + this.organization?.planProductType === ProductType.Free && + !this.showFree && + !this.billing?.paymentSource + ); + } + get selectedPlan() { return this.passwordManagerPlans.find( (plan) => plan.type === this.formGroup.controls.plan.value @@ -508,9 +526,18 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { // Secrets Manager this.buildSecretsManagerRequest(request); - // Retrieve org info to backfill pub/priv key if necessary - const org = await this.organizationService.get(this.organizationId); - if (!org.hasPublicAndPrivateKeys) { + if (this.upgradeRequiresPaymentMethod) { + const tokenResult = await this.paymentComponent.createPaymentToken(); + const paymentRequest = new PaymentRequest(); + paymentRequest.paymentToken = tokenResult[0]; + paymentRequest.paymentMethodType = tokenResult[1]; + paymentRequest.country = this.taxComponent.taxInfo.country; + paymentRequest.postalCode = this.taxComponent.taxInfo.postalCode; + await this.organizationApiService.updatePayment(this.organizationId, paymentRequest); + } + + // Backfill pub/priv key if necessary + if (!this.organization.hasPublicAndPrivateKeys) { const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId); const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey); request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);