chore: Add skeleton for BookingCancelService (#24038)
This commit is contained in:
1 parent
4cee53b07c
commit
5e5e77236a
10 files changed
+158
-14
No files matched your search
@@ -0,0 +1,10 @@
|
||||
import { BookingCancelService } from "@/lib/services/booking-cancel.service";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
providers: [BookingCancelService],
|
||||
exports: [BookingCancelService],
|
||||
})
|
||||
export class BookingCancelModule {}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { BookingCancelService as BaseBookingCancelService } from "@calcom/features/bookings/lib/handleCancelBooking";
|
||||
|
||||
@Injectable()
|
||||
export class BookingCancelService extends BaseBookingCancelService {
|
||||
constructor(
|
||||
prismaWriteService: PrismaWriteService,
|
||||
) {
|
||||
super({
|
||||
prismaClient: prismaWriteService.prisma,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,20 @@ async function handler(req: NextRequest) {
|
||||
cookieStore.delete("calcom.csrf_token");
|
||||
|
||||
const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
|
||||
|
||||
const result = await handleCancelBooking({
|
||||
bookingData,
|
||||
userId: session?.user?.id || -1,
|
||||
});
|
||||
|
||||
// const bookingCancelService = getBookingCancelService();
|
||||
// const result = await bookingCancelService.cancelBooking({
|
||||
// bookingData: bookingData,
|
||||
// bookingMeta: {
|
||||
// userId: session?.user?.id || -1,
|
||||
// },
|
||||
// });
|
||||
|
||||
const statusCode = result.success ? 200 : 400;
|
||||
|
||||
return NextResponse.json(result, { status: statusCode });
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { createContainer } from "@calcom/lib/di/di";
|
||||
|
||||
import {
|
||||
type BookingCancelService,
|
||||
moduleLoader as bookingCancelServiceModule,
|
||||
} from "../modules/BookingCancelService.module";
|
||||
|
||||
const bookingCancelServiceContainer = createContainer();
|
||||
|
||||
export function getBookingCancelService(): BookingCancelService {
|
||||
bookingCancelServiceModule.loadModule(bookingCancelServiceContainer);
|
||||
|
||||
return bookingCancelServiceContainer.get<BookingCancelService>(bookingCancelServiceModule.token);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { BookingCancelService } from "@calcom/features/bookings/lib/handleCancelBooking";
|
||||
import { bindModuleToClassOnToken, createModule } from "@calcom/lib/di/di";
|
||||
import { DI_TOKENS } from "@calcom/lib/di/tokens";
|
||||
import { moduleLoader as prismaModuleLoader } from "@calcom/prisma/prisma.module";
|
||||
|
||||
const thisModule = createModule();
|
||||
const token = DI_TOKENS.BOOKING_CANCEL_SERVICE;
|
||||
const moduleToken = DI_TOKENS.BOOKING_CANCEL_SERVICE_MODULE;
|
||||
const loadModule = bindModuleToClassOnToken({
|
||||
module: thisModule,
|
||||
moduleToken,
|
||||
token,
|
||||
classs: BookingCancelService,
|
||||
depsMap: {
|
||||
prismaClient: prismaModuleLoader,
|
||||
},
|
||||
});
|
||||
|
||||
export const moduleLoader = {
|
||||
token,
|
||||
loadModule,
|
||||
};
|
||||
|
||||
export type { BookingCancelService };
|
||||
@@ -5,4 +5,6 @@ export const BOOKING_DI_TOKENS = {
|
||||
RECURRING_BOOKING_SERVICE_MODULE: Symbol("RecurringBookingServiceModule"),
|
||||
INSTANT_BOOKING_CREATE_SERVICE: Symbol("InstantBookingCreateService"),
|
||||
INSTANT_BOOKING_CREATE_SERVICE_MODULE: Symbol("InstantBookingCreateServiceModule"),
|
||||
BOOKING_CANCEL_SERVICE: Symbol("BookingCancelService"),
|
||||
BOOKING_CANCEL_SERVICE_MODULE: Symbol("BookingCancelServiceModule"),
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Domain types for Booking Cancellation Service
|
||||
* These types are framework-agnostic and contain only the data required for booking cancellation operations
|
||||
*/
|
||||
import type { z } from "zod";
|
||||
|
||||
import type { bookingCancelInput } from "@calcom/prisma/zod-utils";
|
||||
|
||||
/**
|
||||
* The booking data required for cancellation
|
||||
*/
|
||||
export type CancelRegularBookingData = z.infer<typeof bookingCancelInput>;
|
||||
|
||||
/**
|
||||
* Additional metadata for booking cancellation, typically used for platform integrations
|
||||
*/
|
||||
export type CancelBookingMeta = {
|
||||
userId?: number;
|
||||
platformClientId?: string;
|
||||
platformRescheduleUrl?: string;
|
||||
platformCancelUrl?: string;
|
||||
platformBookingUrl?: string;
|
||||
arePlatformEmailsEnabled?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* The response returned after attempting to cancel a booking
|
||||
*/
|
||||
export type HandleCancelBookingResponse = {
|
||||
success: boolean;
|
||||
message: string;
|
||||
onlyRemovedAttendee: boolean;
|
||||
bookingId: number;
|
||||
bookingUid: string;
|
||||
};
|
||||
@@ -5,10 +5,13 @@ import { FAKE_DAILY_CREDENTIAL } from "@calcom/app-store/dailyvideo/lib/VideoApi
|
||||
import { eventTypeMetaDataSchemaWithTypedApps } from "@calcom/app-store/zod-utils";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { sendCancelledEmailsAndSMS } from "@calcom/emails";
|
||||
import EventManager from "@calcom/features/bookings/lib/EventManager";
|
||||
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
|
||||
import { processNoShowFeeOnCancellation } from "@calcom/features/bookings/lib/payment/processNoShowFeeOnCancellation";
|
||||
import { processPaymentRefund } from "@calcom/features/bookings/lib/payment/processPaymentRefund";
|
||||
import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer";
|
||||
import { sendCancelledReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler";
|
||||
import { WorkflowRepository } from "@calcom/features/ee/workflows/repositories/WorkflowRepository";
|
||||
import type { GetSubscriberOptions } from "@calcom/features/webhooks/lib/getWebhooks";
|
||||
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
|
||||
import {
|
||||
@@ -17,8 +20,6 @@ import {
|
||||
} from "@calcom/features/webhooks/lib/scheduleTrigger";
|
||||
import sendPayload from "@calcom/features/webhooks/lib/sendOrSchedulePayload";
|
||||
import type { EventTypeInfo } from "@calcom/features/webhooks/lib/sendPayload";
|
||||
import EventManager from "@calcom/features/bookings/lib/EventManager";
|
||||
import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer";
|
||||
import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId";
|
||||
import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
@@ -27,10 +28,10 @@ import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import { WorkflowRepository } from "@calcom/features/ee/workflows/repositories/WorkflowRepository";
|
||||
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
// TODO: Prisma import would be used from DI in a followup PR when we remove `handler` export
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { Prisma, WorkflowReminder } from "@calcom/prisma/client";
|
||||
import type { Prisma, PrismaClient, WorkflowReminder } from "@calcom/prisma/client";
|
||||
import type { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import { bookingMetadataSchema, bookingCancelInput } from "@calcom/prisma/zod-utils";
|
||||
@@ -38,10 +39,16 @@ import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
|
||||
import { getAllWorkflowsFromEventType } from "@calcom/trpc/server/routers/viewer/workflows/util";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
import type {
|
||||
CancelRegularBookingData,
|
||||
CancelBookingMeta,
|
||||
HandleCancelBookingResponse,
|
||||
} from "./dto/BookingCancel";
|
||||
import { getAllCredentialsIncludeServiceAccountKey } from "./getAllCredentialsForUsersOnEvent/getAllCredentials";
|
||||
import { getBookingToDelete } from "./getBookingToDelete";
|
||||
import { handleInternalNote } from "./handleInternalNote";
|
||||
import cancelAttendeeSeat from "./handleSeats/cancel/cancelAttendeeSeat";
|
||||
import type { IBookingCancelService } from "./interfaces/IBookingCancelService";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: ["handleCancelBooking"] });
|
||||
|
||||
@@ -60,14 +67,6 @@ export type CancelBookingInput = {
|
||||
bookingData: z.infer<typeof bookingCancelInput>;
|
||||
} & PlatformParams;
|
||||
|
||||
export type HandleCancelBookingResponse = {
|
||||
success: boolean;
|
||||
message: string;
|
||||
onlyRemovedAttendee: boolean;
|
||||
bookingId: number;
|
||||
bookingUid: string;
|
||||
};
|
||||
|
||||
async function handler(input: CancelBookingInput) {
|
||||
const body = input.bookingData;
|
||||
const {
|
||||
@@ -118,7 +117,12 @@ async function handler(input: CancelBookingInput) {
|
||||
const isCancellationUserHost =
|
||||
bookingToDelete.userId == userId || bookingToDelete.user.email === cancelledBy;
|
||||
|
||||
if (!platformClientId && !cancellationReason?.trim() && isCancellationUserHost && !skipCancellationReasonValidation) {
|
||||
if (
|
||||
!platformClientId &&
|
||||
!cancellationReason?.trim() &&
|
||||
isCancellationUserHost &&
|
||||
!skipCancellationReasonValidation
|
||||
) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Cancellation reason is required when you are the host",
|
||||
@@ -588,4 +592,24 @@ async function handler(input: CancelBookingInput) {
|
||||
} satisfies HandleCancelBookingResponse;
|
||||
}
|
||||
|
||||
type BookingCancelServiceDependencies = {
|
||||
prismaClient: PrismaClient;
|
||||
};
|
||||
/**
|
||||
* Takes care of cancelling bookings. This includes regular bookings, recurring bookings, seated bookings, etc.
|
||||
* Handles both individual booking cancellations and bulk cancellations for recurring events.
|
||||
*/
|
||||
export class BookingCancelService implements IBookingCancelService {
|
||||
constructor(private readonly deps: BookingCancelServiceDependencies) {}
|
||||
|
||||
async cancelBooking(input: { bookingData: CancelRegularBookingData; bookingMeta?: CancelBookingMeta }) {
|
||||
const cancelBookingInput: CancelBookingInput = {
|
||||
bookingData: input.bookingData,
|
||||
...(input.bookingMeta || {}),
|
||||
};
|
||||
// TODO: Deps to be passed to it later when we stop exporting handler
|
||||
return handler(cancelBookingInput);
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,12 @@
|
||||
import type {
|
||||
CancelRegularBookingData,
|
||||
CancelBookingMeta,
|
||||
HandleCancelBookingResponse,
|
||||
} from "../dto/BookingCancel";
|
||||
|
||||
export interface IBookingCancelService {
|
||||
cancelBooking(input: {
|
||||
bookingData: CancelRegularBookingData;
|
||||
bookingMeta?: CancelBookingMeta;
|
||||
}): Promise<HandleCancelBookingResponse>;
|
||||
}
|
||||
@@ -55,7 +55,6 @@ export const DI_TOKENS = {
|
||||
HOST_REPOSITORY_MODULE: Symbol("HostRepositoryModule"),
|
||||
ATTRIBUTE_REPOSITORY: Symbol("AttributeRepository"),
|
||||
ATTRIBUTE_REPOSITORY_MODULE: Symbol("AttributeRepositoryModule"),
|
||||
// Booking service tokens
|
||||
...BOOKING_DI_TOKENS,
|
||||
// Watchlist service tokens
|
||||
...WATCHLIST_DI_TOKENS,
|
||||
|
||||
Reference in new issue
Block a user