Skip to content
This repository has been archived by the owner on Jan 23, 2024. It is now read-only.

Commit

Permalink
fix: Handle payment flow webhooks in case of event requiring confirma…
Browse files Browse the repository at this point in the history
…tion (calcom#11458)

Co-authored-by: alannnc <[email protected]>
  • Loading branch information
hariombalhara and alannnc authored Sep 30, 2023
1 parent 0bb99fc commit 20898e1
Show file tree
Hide file tree
Showing 29 changed files with 3,369 additions and 1,646 deletions.
1 change: 1 addition & 0 deletions apps/web/public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@
"booking_created": "Booking Created",
"booking_rejected": "Booking Rejected",
"booking_requested": "Booking Requested",
"booking_payment_initiated": "Booking Payment Initiated",
"meeting_ended": "Meeting Ended",
"form_submitted": "Form Submitted",
"booking_paid": "Booking Paid",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test/lib/checkBookingLimits.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import prismaMock from "../../../../tests/libs/__mocks__/prisma";
import prismaMock from "../../../../tests/libs/__mocks__/prismaMock";

import { describe, expect, it } from "vitest";

Expand Down
2 changes: 1 addition & 1 deletion apps/web/test/lib/checkDurationLimits.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import prismaMock from "../../../../tests/libs/__mocks__/prisma";
import prismaMock from "../../../../tests/libs/__mocks__/prismaMock";

import { describe, expect, it } from "vitest";

Expand Down
50 changes: 24 additions & 26 deletions apps/web/test/lib/getSchedule.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import CalendarManagerMock from "../../../../tests/libs/__mocks__/CalendarManager";
import prismaMock from "../../../../tests/libs/__mocks__/prisma";
import prismock from "../../../../tests/libs/__mocks__/prisma";

import { diff } from "jest-diff";
import { describe, expect, vi, beforeEach, afterEach, test } from "vitest";

import prisma from "@calcom/prisma";
import type { BookingStatus } from "@calcom/prisma/enums";
import type { Slot } from "@calcom/trpc/server/routers/viewer/slots/types";
import { getAvailableSlots as getSchedule } from "@calcom/trpc/server/routers/viewer/slots/util";

import { getDate, getGoogleCalendarCredential, createBookingScenario } from "../utils/bookingScenario";

// TODO: Mock properly
prismaMock.eventType.findUnique.mockResolvedValue(null);
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.user.findMany.mockResolvedValue([]);
import {
getDate,
getGoogleCalendarCredential,
createBookingScenario,
} from "../utils/bookingScenario/bookingScenario";

vi.mock("@calcom/lib/constants", () => ({
IS_PRODUCTION: true,
Expand Down Expand Up @@ -146,13 +144,13 @@ const TestData = {
};

const cleanup = async () => {
await prisma.eventType.deleteMany();
await prisma.user.deleteMany();
await prisma.schedule.deleteMany();
await prisma.selectedCalendar.deleteMany();
await prisma.credential.deleteMany();
await prisma.booking.deleteMany();
await prisma.app.deleteMany();
await prismock.eventType.deleteMany();
await prismock.user.deleteMany();
await prismock.schedule.deleteMany();
await prismock.selectedCalendar.deleteMany();
await prismock.credential.deleteMany();
await prismock.booking.deleteMany();
await prismock.app.deleteMany();
};

beforeEach(async () => {
Expand Down Expand Up @@ -201,7 +199,7 @@ describe("getSchedule", () => {
apps: [TestData.apps.googleCalendar],
};
// An event with one accepted booking
createBookingScenario(scenarioData);
await createBookingScenario(scenarioData);

const scheduleForDayWithAGoogleCalendarBooking = await getSchedule({
input: {
Expand All @@ -228,7 +226,7 @@ describe("getSchedule", () => {
const { dateString: plus3DateString } = getDate({ dateIncrement: 3 });

// An event with one accepted booking
createBookingScenario({
await createBookingScenario({
// An event with length 30 minutes, slotInterval 45 minutes, and minimumBookingNotice 1440 minutes (24 hours)
eventTypes: [
{
Expand Down Expand Up @@ -354,7 +352,7 @@ describe("getSchedule", () => {
});

test("slots are available as per `length`, `slotInterval` of the event", async () => {
createBookingScenario({
await createBookingScenario({
eventTypes: [
{
id: 1,
Expand Down Expand Up @@ -453,7 +451,7 @@ describe("getSchedule", () => {
})()
);

createBookingScenario({
await createBookingScenario({
eventTypes: [
{
id: 1,
Expand Down Expand Up @@ -569,7 +567,7 @@ describe("getSchedule", () => {
apps: [TestData.apps.googleCalendar],
};

createBookingScenario(scenarioData);
await createBookingScenario(scenarioData);

const scheduleForEventOnADayWithNonCalBooking = await getSchedule({
input: {
Expand Down Expand Up @@ -643,7 +641,7 @@ describe("getSchedule", () => {
apps: [TestData.apps.googleCalendar],
};

createBookingScenario(scenarioData);
await createBookingScenario(scenarioData);

const scheduleForEventOnADayWithCalBooking = await getSchedule({
input: {
Expand Down Expand Up @@ -701,7 +699,7 @@ describe("getSchedule", () => {
apps: [TestData.apps.googleCalendar],
};

createBookingScenario(scenarioData);
await createBookingScenario(scenarioData);

const schedule = await getSchedule({
input: {
Expand Down Expand Up @@ -765,7 +763,7 @@ describe("getSchedule", () => {
],
};

createBookingScenario(scenarioData);
await createBookingScenario(scenarioData);

const scheduleForEventOnADayWithDateOverride = await getSchedule({
input: {
Expand All @@ -790,7 +788,7 @@ describe("getSchedule", () => {
const { dateString: plus1DateString } = getDate({ dateIncrement: 1 });
const { dateString: plus2DateString } = getDate({ dateIncrement: 2 });

createBookingScenario({
await createBookingScenario({
eventTypes: [
// A Collective Event Type hosted by this user
{
Expand Down Expand Up @@ -885,7 +883,7 @@ describe("getSchedule", () => {
const { dateString: plus1DateString } = getDate({ dateIncrement: 1 });
const { dateString: plus2DateString } = getDate({ dateIncrement: 2 });

createBookingScenario({
await createBookingScenario({
eventTypes: [
// An event having two users with one accepted booking
{
Expand Down Expand Up @@ -1010,7 +1008,7 @@ describe("getSchedule", () => {
const { dateString: plus2DateString } = getDate({ dateIncrement: 2 });
const { dateString: plus3DateString } = getDate({ dateIncrement: 3 });

createBookingScenario({
await createBookingScenario({
eventTypes: [
// An event having two users with one accepted booking
{
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test/lib/handleChildrenEventTypes.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import prismaMock from "../../../../tests/libs/__mocks__/prisma";
import prismaMock from "../../../../tests/libs/__mocks__/prismaMock";

import type { EventType } from "@prisma/client";
import { describe, expect, it, vi } from "vitest";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/test/lib/team-event-types.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import prismaMock from "../../../../tests/libs/__mocks__/prisma";
import prismaMock from "../../../../tests/libs/__mocks__/prismaMock";

import { expect, it } from "vitest";

Expand Down
88 changes: 88 additions & 0 deletions apps/web/test/utils/bookingScenario/MockPaymentService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import prismaMock from "../../../../../tests/libs/__mocks__/prisma";

import type { Payment, Prisma, PaymentOption, Booking } from "@prisma/client";
import { v4 as uuidv4 } from "uuid";
import "vitest-fetch-mock";

import { sendAwaitingPaymentEmail } from "@calcom/emails";
import logger from "@calcom/lib/logger";
import type { CalendarEvent } from "@calcom/types/Calendar";
import type { IAbstractPaymentService } from "@calcom/types/PaymentService";

export function getMockPaymentService() {
function createPaymentLink(/*{ paymentUid, name, email, date }*/) {
return "http://mock-payment.example.com/";
}
const paymentUid = uuidv4();
const externalId = uuidv4();

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
class MockPaymentService implements IAbstractPaymentService {
// TODO: We shouldn't need to implement adding a row to Payment table but that's a requirement right now.
// We should actually delegate table creation to the core app. Here, only the payment app specific logic should come
async create(
payment: Pick<Prisma.PaymentUncheckedCreateInput, "amount" | "currency">,
bookingId: Booking["id"],
userId: Booking["userId"],
username: string | null,
bookerName: string | null,
bookerEmail: string,
paymentOption: PaymentOption
) {
const paymentCreateData = {
id: 1,
uid: paymentUid,
appId: null,
bookingId,
// booking Booking? @relation(fields: [bookingId], references: [id], onDelete: Cascade)
fee: 10,
success: true,
refunded: false,
data: {},
externalId,
paymentOption,
amount: payment.amount,
currency: payment.currency,
};

const paymentData = prismaMock.payment.create({
data: paymentCreateData,
});
logger.silly("Created mock payment", JSON.stringify({ paymentData }));

return paymentData;
}
async afterPayment(
event: CalendarEvent,
booking: {
user: { email: string | null; name: string | null; timeZone: string } | null;
id: number;
startTime: { toISOString: () => string };
uid: string;
},
paymentData: Payment
): Promise<void> {
// TODO: App implementing PaymentService is supposed to send email by itself at the moment.
await sendAwaitingPaymentEmail({
...event,
paymentInfo: {
link: createPaymentLink(/*{
paymentUid: paymentData.uid,
name: booking.user?.name,
email: booking.user?.email,
date: booking.startTime.toISOString(),
}*/),
paymentOption: paymentData.paymentOption || "ON_BOOKING",
amount: paymentData.amount,
currency: paymentData.currency,
},
});
}
}
return {
paymentUid,
externalId,
MockPaymentService,
};
}
Loading

0 comments on commit 20898e1

Please sign in to comment.