Files
calendar/packages/features/ee/billing/teams/internal-team-billing.test.ts
T
+13 a4a3eb5ea9 refactor: Billing service (#15366)
* WIP: Billing service

* WIP

* Update __handler.ts

* Update index.ts

* WIP

* WIP

Signed-off-by: zomars <zomars@me.com>

* WIP

Signed-off-by: zomars <zomars@me.com>

* Update delete.handler.ts

* Update delete.handler.ts

* Update internal-team-billing.ts

* WIP

* Type fixes

Signed-off-by: zomars <zomars@me.com>

* WIP

Signed-off-by: zomars <zomars@me.com>

* Discard changes to apps/api/v2/src/ee/event-types/event-types_2024_04_15/controllers/event-types.controller.ts

* Discard changes to packages/app-store/skype/config.json

* style: update text area (#15934)

* chore: update text-editor input

* chore: update text-editor input

* final update

* Update Editor.tsx

---------

Co-authored-by: unknown <adhabal2002@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>

* fix: #15697 Assignment warning modal poping up ,even when hosts are added . (#15699)

* removed reduntand check on assignedusers

* update for managed eventtype

* formatted

* comments

* Updated comments

* extracted checkForEmptyAssignment and added tests

* updated comments

* updated to show dialog also when not yet saved

* update translations

* updated comments

* updated translation

* updated types

* chore: update naming and comments

* Delete apps/web/lib/checkForEmptyAssignment.ts

deleted since file was renamed

* Delete apps/web/test/lib/checkForEmptyAssignment.test.ts

deleted as the file is renamed to be more descriptive

* update to do teamcheck before

* chore: revert name to CheckForEmptyAssignment

* updated check conditions

* updated useEffect dependencies

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>

* fix: getting an error when a team member tries to leave (#15925)

a team

Co-authored-by: Somay Chauhan <somaychauhan98@gmail.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>

* feat: add transitions to more components (#15916)

* add transitions to more components

* chore: Remove duplicate class

* fix: Change minimum number of teams required for org self-serve (#15955)

* fix: Change minimum number of teams required for org self-serve

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* refactor: Use a new constant for displaying org helper text dialogue

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* Update packages/lib/constants.ts

* Update turbo.json

---------

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>

* feat: pwa ready and add shortcut for quick access (#15957)

* chore: Update site.webmanifest with additional display properties

* chore: Update site.webmanifest with additional display properties

* Update apps/web/public/site.webmanifest

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>

* i18n: update translations for "by proceeding, ..." (#15921)

* feat: Add title attribute to iframe in embed.ts (#15944)

* feat: Add title attribute to iframe in embed.ts

* Update packages/embeds/embed-core/src/embed.ts

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* fix: Assignment reminder modal appears when deleting a team event type (#15544)

* fix: Assignment reminder modal appears when deleting a team event type

* update

* Update EventTypeSingleLayout.tsx

* Update event-types-single-view.tsx

* update

* Early return https://handbook.cal.com/engineering/best-practices/prefer-early-returns

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Hariom <hariombalhara@gmail.com>

* fix: Add CORP and COEP headers to embedded pages (#15275)

* Add CORP headers

* Improve test

* Add unit tests as well

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>

* feat: No-show bookings - do not count towards a member's round robin assignment (#15323)

* feat: No-show bookings - do not count towards a member's round robin assignment

* filter no show organizer

* remove logs

* fix: filter bookings where host attendee is no show

* fix: use not condition for noShow

* chore: test

* add default false for noShowHost

* Revert "chore: test"

This reverts commit c914a8fc4a14ca9c7d8c4a08ff8b0f463789171c.

* chore: integration test

* fix: noShowHost not working for null

* Update packages/lib/server/getLuckyUser.ts

* chore: update test description

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: gh0st91848 <gh0st91848@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* refactor: v1 orgs unlimited teams (#15908)

* refactor: v1 orgs unlimited teams

* fix: response message ownerId

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>

* fix: refresh connect atoms on token change (#15933)

* added dropdown

* change comment

* fix: added types

---------

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>

* fix: Next.js bundle analysis (#15903)

* fix: Next.js bundle analysis

* Added the main checkout back

* fix: type in webhook payload (#15912)

Co-authored-by: CarinaWolli <wollencarina@gmail.com>

* fix: auto accept (#15975)

* fix: auto accept

* Update packages/lib/server/repository/organization.ts

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* fix: Broken GitHub workflows (#15979)

* test: Delete credential endpoint (#15322)

* Init

* Add mock trpc context

* Intro mockDatabaseClient

* Introduce mockDatabaseClient class

* Add delete video app test

* Add calendar test

* Remove unused func from bookingScenario

* Remove console.log

* Add app repository

* Add createMany method to event type repository

* Remove instance of MockDatabaseClient from video test

* Add destination calendar repository

* Remove instances of MockDatabaseClient

* abstract logic to own handler

* Remove dev dependency

* Clean up

* Type fix

* Pull yarn.lock from main

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>

* fix: #15967 Show better error when wrong variable is used in custom event name (#15974)

* update to show exact err msg with custom event name

* updated tests for validateCustomEventName

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>

* WIP

Signed-off-by: zomars <zomars@me.com>

* Update yarn.lock

* Update publish.handler.ts

* Update internal-team-billing.test.ts

* rename create to init

* remove sync services

* wip tests for delete team

* wip tets

* wip tests

* tests/internal-test

* remove return that is inaccessable

* remove team calls to use repository

* remove redudant file

* update team repo

* add stripe mocks and test

* fix constants

* tests to main stripe handler

* remove logs

* fix constants

* Update packages/features/ee/billing/api/webhook/_customer.subscription.deleted.team-plan.ts

Co-authored-by: Omar López <zomars@me.com>

* move workflow logic to a service

* use static method > creating new class

* fix: remove http code deep in repo + tests

* Feedback

* Update index.ts

* Type fix

* Lazy load fixes

---------

Signed-off-by: zomars <zomars@me.com>
Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>
Co-authored-by: Rohan Advani <122167726+RNAdvani@users.noreply.github.com>
Co-authored-by: unknown <adhabal2002@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Vijay <vijayraghav22@gmail.com>
Co-authored-by: Somay Chauhan <somaychauhan98@gmail.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Co-authored-by: Hichem Fantar <hichemfantar2049@gmail.com>
Co-authored-by: Souptik Datta <souptikdatta2001@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Johannes Maendle <141119154+jomaendle2@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: gh0st91848 <gh0st91848@gmail.com>
Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: sean-brydon <sean@cal.com>
Co-authored-by: sean <sean@brydon.io>
2024-10-04 13:44:50 -07:00

177 lines
6.0 KiB
TypeScript

import prismaMock from "../../../../../tests/libs/__mocks__/prismaMock";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { purchaseTeamOrOrgSubscription } from "@calcom/features/ee/teams/lib/payments";
import { WEBAPP_URL } from "@calcom/lib/constants";
import * as billingModule from "..";
import { InternalTeamBilling } from "./internal-team-billing";
import { TeamBillingPublishResponseStatus } from "./team-billing";
vi.mock("@calcom/lib/constants", async () => {
const actual = await vi.importActual("@calcom/lib/constants");
return {
...actual,
WEBAPP_URL: "http://localhost:3000",
};
});
vi.mock("..", () => ({
default: {
handleSubscriptionCancel: vi.fn(),
handleSubscriptionUpdate: vi.fn(),
checkoutSessionIsPaid: vi.fn(),
},
}));
vi.mock("@calcom/features/ee/teams/lib/payments", () => ({
purchaseTeamOrOrgSubscription: vi.fn(),
}));
const mockTeam = {
id: 1,
metadata: {
subscriptionId: "sub_123",
subscriptionItemId: "si_456",
paymentId: "cs_789",
},
isOrganization: true,
parentId: null,
};
describe("InternalTeamBilling", () => {
beforeEach(() => {
vi.resetAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
describe("cancel", () => {
const internalTeamBilling = new InternalTeamBilling(mockTeam);
it("should cancel the subscription and downgrade the team", async () => {
await internalTeamBilling.cancel();
expect(billingModule.default.handleSubscriptionCancel).toHaveBeenCalledWith("sub_123");
expect(prismaMock.team.update).toHaveBeenCalledWith({
where: { id: 1 },
data: {
metadata: {},
},
});
});
});
describe("publish", () => {
const internalTeamBilling = new InternalTeamBilling(mockTeam);
it("should create a checkout session and update the team", async () => {
vi.spyOn(billingModule.default, "checkoutSessionIsPaid").mockResolvedValue(false);
vi.mocked(purchaseTeamOrOrgSubscription).mockResolvedValue({
url: "http://checkout.url",
});
prismaMock.membership.count.mockResolvedValue(5);
prismaMock.membership.findFirstOrThrow.mockResolvedValue({ userId: 123 });
const result = await internalTeamBilling.publish();
expect(result).toEqual({
redirectUrl: "http://checkout.url",
status: TeamBillingPublishResponseStatus.REQUIRES_PAYMENT,
});
expect(prismaMock.membership.count).toHaveBeenCalledWith({ where: { teamId: 1 } });
expect(prismaMock.membership.findFirstOrThrow).toHaveBeenCalledWith({
where: { teamId: 1, role: "OWNER" },
select: { userId: true },
});
});
it("should return upgrade url if upgrade is required", async () => {
const internalTeamBilling = new InternalTeamBilling(mockTeam);
const mockUrl = `${WEBAPP_URL}/api/teams/${mockTeam.id}/upgrade?session_id=cs_789`;
vi.spyOn(internalTeamBilling, "checkIfTeamPaymentRequired").mockResolvedValue({
url: mockUrl,
paymentId: "cs_789",
paymentRequired: false,
});
const result = await internalTeamBilling.publish();
expect(result).toEqual({
redirectUrl: mockUrl,
status: TeamBillingPublishResponseStatus.REQUIRES_UPGRADE,
});
expect(internalTeamBilling.checkIfTeamPaymentRequired).toHaveBeenCalled();
});
});
describe("updateQuantity", () => {
it("should update the subscription quantity", async () => {
const mockTeamNotOrg = {
...mockTeam,
isOrganization: false,
};
const internalTeamBilling = new InternalTeamBilling(mockTeamNotOrg);
prismaMock.membership.count.mockResolvedValue(10);
vi.spyOn(internalTeamBilling, "checkIfTeamPaymentRequired").mockResolvedValue({
url: "http://checkout.url",
paymentId: "cs_789",
paymentRequired: false,
});
await internalTeamBilling.updateQuantity();
expect(billingModule.default.handleSubscriptionUpdate).toHaveBeenCalledWith({
subscriptionId: "sub_123",
subscriptionItemId: "si_456",
membershipCount: 10,
});
});
it("should not update if membership count is less than minimum for organizations", async () => {
const internalTeamBilling = new InternalTeamBilling(mockTeam);
prismaMock.membership.count.mockResolvedValue(2);
vi.spyOn(internalTeamBilling, "checkIfTeamPaymentRequired").mockResolvedValue({
url: "http://checkout.url",
paymentId: "cs_789",
paymentRequired: false,
});
await internalTeamBilling.updateQuantity();
expect(billingModule.default.handleSubscriptionUpdate).not.toHaveBeenCalled();
});
});
describe("checkIfTeamPaymentRequired", () => {
const internalTeamBilling = new InternalTeamBilling(mockTeam);
it("should return payment required if no paymentId", async () => {
internalTeamBilling.team.metadata.paymentId = undefined;
const result = await internalTeamBilling.checkIfTeamPaymentRequired();
expect(result).toEqual({ url: null, paymentId: null, paymentRequired: true });
});
it("should return payment required if checkout session is not paid", async () => {
vi.spyOn(billingModule.default, "checkoutSessionIsPaid").mockResolvedValue(false);
const internalTeamBilling = new InternalTeamBilling(mockTeam);
const result = await internalTeamBilling.checkIfTeamPaymentRequired();
expect(result).toEqual({ url: null, paymentId: "cs_789", paymentRequired: true });
});
it("should return upgrade URL if checkout session is paid", async () => {
vi.spyOn(billingModule.default, "checkoutSessionIsPaid").mockResolvedValue(true);
const internalTeamBilling = new InternalTeamBilling(mockTeam);
const result = await internalTeamBilling.checkIfTeamPaymentRequired();
expect(result).toEqual({
url: `${WEBAPP_URL}/api/teams/1/upgrade?session_id=cs_789`,
paymentId: "cs_789",
paymentRequired: false,
});
});
});
});