From 695d2c0f398751e7663ee35ce3b161e261efe308 Mon Sep 17 00:00:00 2001 From: Lauris Skraucis Date: Thu, 6 Feb 2025 11:45:13 +0100 Subject: [PATCH] feat: v2 bookings return cancelledBy and rescheduledBy (#19110) --- .../controllers/e2e/user-bookings.e2e-spec.ts | 102 ++++++++++++++++++ .../2024-08-13/services/output.service.ts | 4 + .../2024-08-13/outputs/booking.output.ts | 12 +++ 3 files changed, 118 insertions(+) diff --git a/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts b/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts index 0eaa6eb14b..e1c517c849 100644 --- a/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts +++ b/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts @@ -1308,6 +1308,108 @@ describe("Bookings Endpoints 2024-08-13", () => { }); }); + describe("who cancelled and rescheduled a booking", () => { + it("should return who cancelled a booking", async () => { + const cancelledByEmail = `user-bookings-canceller-${randomString()}@canceller.com`; + const cancelledBooking = await bookingsRepositoryFixture.create({ + uid: `booking-uid-${eventTypeId}`, + title: "booking title", + startTime: "2050-09-05T11:00:00.000Z", + endTime: "2050-09-05T12:00:00.000Z", + eventType: { + connect: { + id: eventTypeId, + }, + }, + status: "CANCELLED", + cancelledBy: cancelledByEmail, + metadata: {}, + responses: { + name: "tester", + email: "tester@example.com", + guests: [], + }, + user: { + connect: { + id: user.id, + }, + }, + }); + + return request(app.getHttpServer()) + .get(`/v2/bookings/${cancelledBooking.uid}`) + .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13) + .expect(200) + .then(async (response) => { + await bookingsRepositoryFixture.deleteById(cancelledBooking.id); + const responseBody: GetBookingOutput_2024_08_13 = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + expect(responseBody.data).toBeDefined(); + expect(responseDataIsBooking(responseBody.data)).toBe(true); + + if (responseDataIsBooking(responseBody.data)) { + const data: BookingOutput_2024_08_13 = responseBody.data; + expect(data.uid).toEqual(cancelledBooking.uid); + expect(data.cancelledByEmail).toEqual(cancelledByEmail); + } else { + throw new Error( + "Invalid response data - expected booking but received array of possibily recurring bookings" + ); + } + }); + }); + + it("should return who rescheduled a booking", async () => { + const rescheduledByEmail = `user-bookings-rescheduler-${randomString()}@rescheduler.com`; + const rescheduledBooking = await bookingsRepositoryFixture.create({ + uid: `booking-uid-${eventTypeId}`, + title: "booking title", + startTime: "2050-09-05T11:00:00.000Z", + endTime: "2050-09-05T12:00:00.000Z", + eventType: { + connect: { + id: eventTypeId, + }, + }, + status: "CANCELLED", + rescheduledBy: rescheduledByEmail, + metadata: {}, + responses: { + name: "tester", + email: "tester@example.com", + guests: [], + }, + user: { + connect: { + id: user.id, + }, + }, + }); + + return request(app.getHttpServer()) + .get(`/v2/bookings/${rescheduledBooking.uid}`) + .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13) + .expect(200) + .then(async (response) => { + await bookingsRepositoryFixture.deleteById(rescheduledBooking.id); + const responseBody: GetBookingOutput_2024_08_13 = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + expect(responseBody.data).toBeDefined(); + expect(responseDataIsBooking(responseBody.data)).toBe(true); + + if (responseDataIsBooking(responseBody.data)) { + const data: BookingOutput_2024_08_13 = responseBody.data; + expect(data.uid).toEqual(rescheduledBooking.uid); + expect(data.rescheduledByEmail).toEqual(rescheduledByEmail); + } else { + throw new Error( + "Invalid response data - expected booking but received array of possibily recurring bookings" + ); + } + }); + }); + }); + function responseDataIsRecurranceBooking(data: any): data is RecurringBookingOutput_2024_08_13 { return ( !Array.isArray(data) && diff --git a/apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts b/apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts index a18abfbe81..85cecde75f 100644 --- a/apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts +++ b/apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts @@ -108,7 +108,9 @@ export class OutputBookingsService_2024_08_13 { hosts: [this.getHost(databaseBooking.user)], status: databaseBooking.status.toLowerCase(), cancellationReason: databaseBooking.cancellationReason || undefined, + cancelledByEmail: databaseBooking.cancelledBy || undefined, reschedulingReason: bookingResponses?.rescheduledReason, + rescheduledByEmail: databaseBooking.rescheduledBy || undefined, rescheduledFromUid: databaseBooking.fromReschedule || undefined, start: databaseBooking.startTime, end: databaseBooking.endTime, @@ -198,7 +200,9 @@ export class OutputBookingsService_2024_08_13 { hosts: [this.getHost(databaseBooking.user)], status: databaseBooking.status.toLowerCase(), cancellationReason: databaseBooking.cancellationReason || undefined, + cancelledByEmail: databaseBooking.cancelledBy || undefined, reschedulingReason: bookingResponses?.rescheduledReason, + rescheduledByEmail: databaseBooking.rescheduledBy || undefined, rescheduledFromUid: databaseBooking.fromReschedule || undefined, start: databaseBooking.startTime, end: databaseBooking.endTime, diff --git a/packages/platform/types/bookings/2024-08-13/outputs/booking.output.ts b/packages/platform/types/bookings/2024-08-13/outputs/booking.output.ts index 451bf2a769..fc44efce6a 100644 --- a/packages/platform/types/bookings/2024-08-13/outputs/booking.output.ts +++ b/packages/platform/types/bookings/2024-08-13/outputs/booking.output.ts @@ -156,12 +156,24 @@ class BaseBookingOutput_2024_08_13 { @Expose() cancellationReason?: string; + @ApiPropertyOptional({ type: String, example: "canceller@example.com" }) + @IsEmail() + @IsOptional() + @Expose() + cancelledByEmail?: string; + @ApiPropertyOptional({ type: String, example: "User rescheduled the event" }) @IsString() @IsOptional() @Expose() reschedulingReason?: string; + @ApiPropertyOptional({ type: String, example: "rescheduler@example.com" }) + @IsEmail() + @IsOptional() + @Expose() + rescheduledByEmail?: string; + @ApiPropertyOptional({ type: String, example: "previous_uid_123" }) @IsString() @IsOptional()