fix: preserve metadata fields during partial event type updates (#25621)

* fix: preserve metadata fields during partial event type updates

- Fix multipleDuration (lengthInMinutesOptions) being reset to undefined on partial updates
- Fix bookerLayouts being reset to undefined on partial updates
- Fix requiresConfirmationThreshold being reset to undefined on partial updates
- Add e2e test for lengthInMinutesOptions preservation

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* test: expand metadata preservation test to include bookerLayouts and confirmationPolicy

Co-Authored-By: morgan@cal.com <morgan@cal.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2025-12-10 10:33:01 +00:00
1 parent 5ac374374c
commit 300b9c916d
2 files changed
+84 -4

No files matched your search

@@ -229,10 +229,16 @@ export class InputEventTypesService_2024_06_14 {
const metadata: EventTypeMetadata = {
...metadataTransformed,
bookerLayouts: this.transformInputBookerLayouts(bookerLayouts),
requiresConfirmationThreshold:
confirmationPolicyTransformed?.requiresConfirmationThreshold ?? undefined,
multipleDuration: lengthInMinutesOptions,
...(bookerLayouts !== undefined
? { bookerLayouts: this.transformInputBookerLayouts(bookerLayouts) }
: {}),
...(confirmationPolicy !== undefined
? {
requiresConfirmationThreshold:
confirmationPolicyTransformed?.requiresConfirmationThreshold ?? undefined,
}
: {}),
...(lengthInMinutesOptions !== undefined ? { multipleDuration: lengthInMinutesOptions } : {}),
};
const eventType = {
@@ -1294,6 +1294,80 @@ describe("Organizations Event Types Endpoints", () => {
expect(updatedEventType.bookingRequiresAuthentication).toEqual(false);
});
it("should preserve metadata fields when doing partial update", async () => {
const createBody: CreateTeamEventTypeInput_2024_06_14 = {
title: "Coding consultation with metadata",
slug: `organizations-event-types-metadata-${randomString()}`,
description: "Our team will review your codebase.",
lengthInMinutes: 30,
lengthInMinutesOptions: [15, 30, 60],
locations: [
{
type: "integration",
integration: "cal-video",
},
],
schedulingType: "COLLECTIVE",
hosts: [
{
userId: teammate1.id,
},
],
bookerLayouts: {
enabledLayouts: [
BookerLayoutsInputEnum_2024_06_14.column,
BookerLayoutsInputEnum_2024_06_14.month,
BookerLayoutsInputEnum_2024_06_14.week,
],
defaultLayout: BookerLayoutsInputEnum_2024_06_14.month,
},
confirmationPolicy: {
type: ConfirmationPolicyEnum.TIME,
noticeThreshold: {
count: 60,
unit: NoticeThresholdUnitEnum.MINUTES,
},
blockUnconfirmedBookingsInBooker: true,
},
};
const createResponse = await request(app.getHttpServer())
.post(`/v2/organizations/${org.id}/teams/${team.id}/event-types`)
.send(createBody)
.expect(201);
const createdEventType: TeamEventTypeOutput_2024_06_14 = createResponse.body.data;
// Verify all metadata fields are set correctly on creation
expect(createdEventType.lengthInMinutesOptions).toBeDefined();
expect(createdEventType.lengthInMinutesOptions).toEqual([15, 30, 60]);
expect(createdEventType.bookerLayouts).toBeDefined();
expect(createdEventType.bookerLayouts).toEqual(createBody.bookerLayouts);
expect(createdEventType.confirmationPolicy).toBeDefined();
expect(createdEventType.confirmationPolicy).toEqual(createBody.confirmationPolicy);
// Now do a partial update that only changes a different field (not metadata fields)
const updateBody: UpdateTeamEventTypeInput_2024_06_14 = {
bookingRequiresAuthentication: false,
};
const updateResponse = await request(app.getHttpServer())
.patch(`/v2/organizations/${org.id}/teams/${team.id}/event-types/${createdEventType.id}`)
.send(updateBody)
.expect(200);
const updatedEventType: TeamEventTypeOutput_2024_06_14 = updateResponse.body.data;
// Verify that all metadata fields are preserved and not reset to undefined
expect(updatedEventType.lengthInMinutesOptions).toBeDefined();
expect(updatedEventType.lengthInMinutesOptions).toEqual([15, 30, 60]);
expect(updatedEventType.bookerLayouts).toBeDefined();
expect(updatedEventType.bookerLayouts).toEqual(createBody.bookerLayouts);
expect(updatedEventType.confirmationPolicy).toBeDefined();
expect(updatedEventType.confirmationPolicy).toEqual(createBody.confirmationPolicy);
expect(updatedEventType.bookingRequiresAuthentication).toEqual(false);
});
function evaluateHost(expected: Host, received: Host | undefined) {
expect(expected.userId).toEqual(received?.userId);
expect(expected.mandatory).toEqual(received?.mandatory);