mirror of
https://github.com/bitwarden/browser
synced 2026-02-22 04:14:04 +00:00
fix(billing): Rename and update upgrade payment service
This commit is contained in:
@@ -3,7 +3,6 @@ import { mock, mockReset } from "jest-mock-extended";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationResponse } from "@bitwarden/common/admin-console/models/response/organization.response";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||
import { TaxServiceAbstraction } from "@bitwarden/common/billing/abstractions/tax.service.abstraction";
|
||||
import { PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
|
||||
@@ -12,16 +11,15 @@ import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { LogService } from "@bitwarden/logging";
|
||||
|
||||
import { SubscriberBillingClient } from "../../../../clients";
|
||||
import { AccountBillingClient } from "../../../../clients";
|
||||
import { TokenizedPaymentMethod } from "../../../../payment/types";
|
||||
import { BitwardenSubscriber } from "../../../../types";
|
||||
import { PersonalSubscriptionPricingTierIds } from "../../../../types/subscription-pricing-tier";
|
||||
|
||||
import { UpgradePaymentService, PlanDetails } from "./upgrade-payment.service";
|
||||
|
||||
describe("UpgradePaymentService", () => {
|
||||
const mockOrganizationBillingService = mock<OrganizationBillingServiceAbstraction>();
|
||||
const mockSubscriberBillingClient = mock<SubscriberBillingClient>();
|
||||
const mockAccountBillingClient = mock<AccountBillingClient>();
|
||||
const mockTaxService = mock<TaxServiceAbstraction>();
|
||||
const mockLogService = mock<LogService>();
|
||||
const mockApiService = mock<ApiService>();
|
||||
@@ -32,12 +30,11 @@ describe("UpgradePaymentService", () => {
|
||||
|
||||
let sut: UpgradePaymentService;
|
||||
|
||||
const mockSubscriber: BitwardenSubscriber = {
|
||||
type: "account",
|
||||
data: {
|
||||
id: "user-id" as UserId,
|
||||
email: "test@example.com",
|
||||
} as Account,
|
||||
const mockAccount = {
|
||||
id: "user-id" as UserId,
|
||||
email: "test@example.com",
|
||||
emailVerified: true,
|
||||
name: "Test User",
|
||||
};
|
||||
|
||||
const mockTokenizedPaymentMethod: TokenizedPaymentMethod = {
|
||||
@@ -91,7 +88,7 @@ describe("UpgradePaymentService", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
mockReset(mockOrganizationBillingService);
|
||||
mockReset(mockSubscriberBillingClient);
|
||||
mockReset(mockAccountBillingClient);
|
||||
mockReset(mockTaxService);
|
||||
mockReset(mockLogService);
|
||||
|
||||
@@ -103,7 +100,7 @@ describe("UpgradePaymentService", () => {
|
||||
provide: OrganizationBillingServiceAbstraction,
|
||||
useValue: mockOrganizationBillingService,
|
||||
},
|
||||
{ provide: SubscriberBillingClient, useValue: mockSubscriberBillingClient },
|
||||
{ provide: AccountBillingClient, useValue: mockAccountBillingClient },
|
||||
{ provide: TaxServiceAbstraction, useValue: mockTaxService },
|
||||
{ provide: LogService, useValue: mockLogService },
|
||||
{ provide: ApiService, useValue: mockApiService },
|
||||
@@ -187,16 +184,15 @@ describe("UpgradePaymentService", () => {
|
||||
});
|
||||
|
||||
describe("upgradeToPremium", () => {
|
||||
it("should call subscriberBillingClient to purchase premium subscription and refresh data", async () => {
|
||||
it("should call accountBillingClient to purchase premium subscription and refresh data", async () => {
|
||||
// Arrange
|
||||
mockSubscriberBillingClient.purchasePremiumSubscription.mockResolvedValue();
|
||||
mockAccountBillingClient.purchasePremiumSubscription.mockResolvedValue();
|
||||
|
||||
// Act
|
||||
await sut.upgradeToPremium(mockSubscriber, mockTokenizedPaymentMethod, mockBillingAddress);
|
||||
await sut.upgradeToPremium(mockTokenizedPaymentMethod, mockBillingAddress);
|
||||
|
||||
// Assert
|
||||
expect(mockSubscriberBillingClient.purchasePremiumSubscription).toHaveBeenCalledWith(
|
||||
mockSubscriber,
|
||||
expect(mockAccountBillingClient.purchasePremiumSubscription).toHaveBeenCalledWith(
|
||||
mockTokenizedPaymentMethod,
|
||||
mockBillingAddress,
|
||||
);
|
||||
@@ -210,7 +206,7 @@ describe("UpgradePaymentService", () => {
|
||||
|
||||
// Act & Assert
|
||||
await expect(
|
||||
sut.upgradeToPremium(mockSubscriber, incompletePaymentMethod, mockBillingAddress),
|
||||
sut.upgradeToPremium(incompletePaymentMethod, mockBillingAddress),
|
||||
).rejects.toThrow("Payment method type or token is missing");
|
||||
});
|
||||
|
||||
@@ -220,7 +216,7 @@ describe("UpgradePaymentService", () => {
|
||||
|
||||
// Act & Assert
|
||||
await expect(
|
||||
sut.upgradeToPremium(mockSubscriber, mockTokenizedPaymentMethod, incompleteBillingAddress),
|
||||
sut.upgradeToPremium(mockTokenizedPaymentMethod, incompleteBillingAddress),
|
||||
).rejects.toThrow("Billing address information is incomplete");
|
||||
});
|
||||
});
|
||||
@@ -236,7 +232,7 @@ describe("UpgradePaymentService", () => {
|
||||
|
||||
// Act
|
||||
await sut.upgradeToFamilies(
|
||||
mockSubscriber,
|
||||
mockAccount,
|
||||
mockFamiliesPlanDetails,
|
||||
mockTokenizedPaymentMethod,
|
||||
{
|
||||
@@ -295,7 +291,7 @@ describe("UpgradePaymentService", () => {
|
||||
|
||||
// Act & Assert
|
||||
await expect(
|
||||
sut.upgradeToFamilies(mockSubscriber, invalidPlanDetails, mockTokenizedPaymentMethod, {
|
||||
sut.upgradeToFamilies(mockAccount, invalidPlanDetails, mockTokenizedPaymentMethod, {
|
||||
organizationName: "Test Organization",
|
||||
billingAddress: mockBillingAddress,
|
||||
}),
|
||||
@@ -303,27 +299,11 @@ describe("UpgradePaymentService", () => {
|
||||
expect(mockOrganizationBillingService.purchaseSubscription).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should throw error if subscriber is not an account", async () => {
|
||||
const invalidSubscriber = { type: "organization" } as BitwardenSubscriber;
|
||||
|
||||
await expect(
|
||||
sut.upgradeToFamilies(
|
||||
invalidSubscriber,
|
||||
mockFamiliesPlanDetails,
|
||||
mockTokenizedPaymentMethod,
|
||||
{
|
||||
organizationName: "Test Organization",
|
||||
billingAddress: mockBillingAddress,
|
||||
},
|
||||
),
|
||||
).rejects.toThrow("Subscriber must be an account for families upgrade");
|
||||
});
|
||||
|
||||
it("should throw error if payment method is incomplete", async () => {
|
||||
const incompletePaymentMethod = { type: "card" } as TokenizedPaymentMethod;
|
||||
|
||||
await expect(
|
||||
sut.upgradeToFamilies(mockSubscriber, mockFamiliesPlanDetails, incompletePaymentMethod, {
|
||||
sut.upgradeToFamilies(mockAccount, mockFamiliesPlanDetails, incompletePaymentMethod, {
|
||||
organizationName: "Test Organization",
|
||||
billingAddress: mockBillingAddress,
|
||||
}),
|
||||
@@ -14,13 +14,12 @@ import { PreviewOrganizationInvoiceRequest } from "@bitwarden/common/billing/mod
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { LogService } from "@bitwarden/logging";
|
||||
|
||||
import { SubscriberBillingClient } from "../../../../clients";
|
||||
import { AccountBillingClient } from "../../../../clients";
|
||||
import {
|
||||
BillingAddress,
|
||||
TokenizablePaymentMethod,
|
||||
TokenizedPaymentMethod,
|
||||
} from "../../../../payment/types";
|
||||
import { BitwardenSubscriber } from "../../../../types";
|
||||
import {
|
||||
PersonalSubscriptionPricingTier,
|
||||
PersonalSubscriptionPricingTierId,
|
||||
@@ -53,7 +52,7 @@ export type PaymentFormValues = {
|
||||
export class UpgradePaymentService {
|
||||
constructor(
|
||||
private organizationBillingService: OrganizationBillingServiceAbstraction,
|
||||
private subscriberBillingClient: SubscriberBillingClient,
|
||||
private accountBillingClient: AccountBillingClient,
|
||||
private taxService: TaxServiceAbstraction,
|
||||
private logService: LogService,
|
||||
private apiService: ApiService,
|
||||
@@ -126,17 +125,12 @@ export class UpgradePaymentService {
|
||||
* Process premium upgrade
|
||||
*/
|
||||
async upgradeToPremium(
|
||||
subscriber: BitwardenSubscriber,
|
||||
paymentMethod: TokenizedPaymentMethod,
|
||||
billingAddress: Pick<BillingAddress, "country" | "postalCode">,
|
||||
): Promise<void> {
|
||||
this.validatePaymentAndBillingInfo(paymentMethod, billingAddress);
|
||||
|
||||
await this.subscriberBillingClient.purchasePremiumSubscription(
|
||||
subscriber,
|
||||
paymentMethod,
|
||||
billingAddress,
|
||||
);
|
||||
await this.accountBillingClient.purchasePremiumSubscription(paymentMethod, billingAddress);
|
||||
|
||||
await this.refreshAndSync();
|
||||
}
|
||||
@@ -145,15 +139,11 @@ export class UpgradePaymentService {
|
||||
* Process families upgrade
|
||||
*/
|
||||
async upgradeToFamilies(
|
||||
subscriber: BitwardenSubscriber,
|
||||
account: Account,
|
||||
planDetails: PlanDetails,
|
||||
paymentMethod: TokenizedPaymentMethod,
|
||||
formValues: PaymentFormValues,
|
||||
): Promise<OrganizationResponse> {
|
||||
if (subscriber.type !== "account") {
|
||||
throw new Error("Subscriber must be an account for families upgrade");
|
||||
}
|
||||
const user = subscriber.data as Account;
|
||||
const billingAddress = formValues.billingAddress;
|
||||
|
||||
if (!formValues.organizationName) {
|
||||
@@ -167,7 +157,7 @@ export class UpgradePaymentService {
|
||||
const subscriptionInformation: SubscriptionInformation = {
|
||||
organization: {
|
||||
name: formValues.organizationName,
|
||||
billingEmail: user.email, // Use account email as billing email
|
||||
billingEmail: account.email, // Use account email as billing email
|
||||
},
|
||||
plan: {
|
||||
type: PlanType.FamiliesAnnually,
|
||||
@@ -187,7 +177,7 @@ export class UpgradePaymentService {
|
||||
|
||||
const result = await this.organizationBillingService.purchaseSubscription(
|
||||
subscriptionInformation,
|
||||
user.id,
|
||||
account.id,
|
||||
);
|
||||
await this.refreshAndSync();
|
||||
return result;
|
||||
Reference in New Issue
Block a user