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);