fix: fixes for round robin reassignment (#17233)
* fixes scheduled email for new host * fixes emails and calendar event * type fixes * add test to check if caneclation email is called --------- Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: sean <sean@brydon.io>
This commit is contained in:
co-authored by
CarinaWolli
sean
parent
1fc376c51a
commit
1ee4fa0906
@@ -247,4 +247,78 @@ describe("roundRobinManualReassignment test", () => {
|
||||
expect(attendees.some((attendee) => attendee.email === currentRRHost.email)).toBe(false);
|
||||
expect(attendees.some((attendee) => attendee.email === newHost.email)).toBe(true);
|
||||
});
|
||||
|
||||
test("sends cancellation email to previous RR host when reassigning", async ({ emails }) => {
|
||||
const roundRobinManualReassignment = (await import("./roundRobinManualReassignment")).default;
|
||||
const EventManager = (await import("@calcom/core/EventManager")).default;
|
||||
|
||||
const eventManagerSpy = vi.spyOn(EventManager.prototype as any, "reschedule");
|
||||
eventManagerSpy.mockResolvedValue({ referencesToCreate: [] });
|
||||
|
||||
const sendRoundRobinCancelledEmailsAndSMSSpy = vi.spyOn(
|
||||
await import("@calcom/emails"),
|
||||
"sendRoundRobinCancelledEmailsAndSMS"
|
||||
);
|
||||
|
||||
const users = testUsers;
|
||||
const originalHost = users[0];
|
||||
const previousRRHost = users[1];
|
||||
const newHost = users[2];
|
||||
|
||||
const { dateString: dateStringPlusOne } = getDate({ dateIncrement: 1 });
|
||||
|
||||
const bookingToReassignUid = "booking-to-reassign-with-previous-rr-host";
|
||||
|
||||
await createBookingScenario(
|
||||
getScenarioData({
|
||||
eventTypes: [
|
||||
{
|
||||
id: 1,
|
||||
slug: "round-robin-event",
|
||||
schedulingType: SchedulingType.ROUND_ROBIN,
|
||||
length: 45,
|
||||
users: users.map((user) => ({ id: user.id })),
|
||||
hosts: users.map((user) => ({ userId: user.id, isFixed: false })),
|
||||
},
|
||||
],
|
||||
bookings: [
|
||||
{
|
||||
id: 124,
|
||||
eventTypeId: 1,
|
||||
userId: originalHost.id,
|
||||
uid: bookingToReassignUid,
|
||||
status: BookingStatus.ACCEPTED,
|
||||
startTime: `${dateStringPlusOne}T05:00:00.000Z`,
|
||||
endTime: `${dateStringPlusOne}T05:15:00.000Z`,
|
||||
attendees: [
|
||||
getMockBookingAttendee({
|
||||
id: 2,
|
||||
name: "attendee",
|
||||
email: "attendee@test.com",
|
||||
locale: "en",
|
||||
timeZone: "Asia/Kolkata",
|
||||
}),
|
||||
getMockBookingAttendee({
|
||||
id: previousRRHost.id,
|
||||
name: previousRRHost.name,
|
||||
email: previousRRHost.email,
|
||||
locale: "en",
|
||||
timeZone: previousRRHost.timeZone,
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
organizer: originalHost,
|
||||
usersApartFromOrganizer: users.slice(1),
|
||||
})
|
||||
);
|
||||
|
||||
await roundRobinManualReassignment({
|
||||
bookingId: 124,
|
||||
newUserId: newHost.id,
|
||||
orgId: null,
|
||||
});
|
||||
|
||||
expect(sendRoundRobinCancelledEmailsAndSMSSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,6 +104,24 @@ export const roundRobinManualReassignment = async ({
|
||||
const newUserT = await getTranslation(newUser.locale || "en", "common");
|
||||
const originalOrganizerT = await getTranslation(originalOrganizer.locale || "en", "common");
|
||||
|
||||
const roundRobinHosts = eventType.hosts.filter((host) => !host.isFixed);
|
||||
|
||||
const attendeeEmailsSet = new Set(booking.attendees.map((attendee) => attendee.email));
|
||||
|
||||
// Find the current round robin host assigned
|
||||
const previousRRHost = (() => {
|
||||
for (const host of roundRobinHosts) {
|
||||
if (host.user.id === booking.userId) {
|
||||
return host.user;
|
||||
}
|
||||
if (attendeeEmailsSet.has(host.user.email)) {
|
||||
return host.user;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
const previousRRHostT = await getTranslation(previousRRHost?.locale || "en", "common");
|
||||
|
||||
if (hasOrganizerChanged) {
|
||||
const bookingResponses = booking.responses;
|
||||
const responseSchema = getBookingResponsesSchema({
|
||||
@@ -166,24 +184,38 @@ export const roundRobinManualReassignment = async ({
|
||||
hasOrganizerChanged,
|
||||
});
|
||||
|
||||
const organizer = hasOrganizerChanged ? newUser : booking.user ?? newUser;
|
||||
|
||||
const organizerT = await getTranslation(organizer?.locale || "en", "common");
|
||||
|
||||
const teamMembers = await getTeamMembers({
|
||||
eventTypeHosts,
|
||||
attendees: booking.attendees,
|
||||
organizer: newUser,
|
||||
previousHost: originalOrganizer,
|
||||
organizer,
|
||||
previousHost: previousRRHost || null,
|
||||
reassignedHost: newUser,
|
||||
});
|
||||
|
||||
const attendeePromises = booking.attendees.map(async (attendee) => ({
|
||||
email: attendee.email,
|
||||
name: attendee.name,
|
||||
timeZone: attendee.timeZone,
|
||||
language: {
|
||||
translate: await getTranslation(attendee.locale ?? "en", "common"),
|
||||
locale: attendee.locale ?? "en",
|
||||
},
|
||||
phoneNumber: attendee.phoneNumber || undefined,
|
||||
}));
|
||||
const attendeePromises = [];
|
||||
for (const attendee of booking.attendees) {
|
||||
if (
|
||||
attendee.email === newUser.email ||
|
||||
attendee.email === previousRRHost?.email ||
|
||||
teamMembers.some((member) => member.email === attendee.email)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
attendeePromises.push(
|
||||
getTranslation(attendee.locale ?? "en", "common").then((tAttendee) => ({
|
||||
email: attendee.email,
|
||||
name: attendee.name,
|
||||
timeZone: attendee.timeZone,
|
||||
language: { translate: tAttendee, locale: attendee.locale ?? "en" },
|
||||
phoneNumber: attendee.phoneNumber || undefined,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
const attendeeList = await Promise.all(attendeePromises);
|
||||
|
||||
@@ -194,10 +226,10 @@ export const roundRobinManualReassignment = async ({
|
||||
startTime: dayjs(booking.startTime).utc().format(),
|
||||
endTime: dayjs(booking.endTime).utc().format(),
|
||||
organizer: {
|
||||
email: newUser.email,
|
||||
name: newUser.name || "",
|
||||
timeZone: newUser.timeZone,
|
||||
language: { translate: newUserT, locale: newUser.locale || "en" },
|
||||
email: organizer.email,
|
||||
name: organizer.name || "",
|
||||
timeZone: organizer.timeZone,
|
||||
language: { translate: organizerT, locale: organizer.locale || "en" },
|
||||
},
|
||||
attendees: attendeeList,
|
||||
uid: booking.uid,
|
||||
@@ -242,8 +274,10 @@ export const roundRobinManualReassignment = async ({
|
||||
newReferencesToCreate,
|
||||
});
|
||||
|
||||
const { cancellationReason, ...evtWithoutCancellationReason } = evt;
|
||||
|
||||
// Send emails
|
||||
await sendRoundRobinScheduledEmailsAndSMS(evt, [
|
||||
await sendRoundRobinScheduledEmailsAndSMS(evtWithoutCancellationReason, [
|
||||
{
|
||||
...newUser,
|
||||
name: newUser.name || "",
|
||||
@@ -262,19 +296,21 @@ export const roundRobinManualReassignment = async ({
|
||||
language: { translate: originalOrganizerT, locale: originalOrganizer.locale || "en" },
|
||||
};
|
||||
|
||||
await sendRoundRobinCancelledEmailsAndSMS(
|
||||
cancelledEvt,
|
||||
[
|
||||
{
|
||||
...originalOrganizer,
|
||||
name: originalOrganizer.name || "",
|
||||
username: originalOrganizer.username || "",
|
||||
timeFormat: getTimeFormatStringFromUserTimeFormat(originalOrganizer.timeFormat),
|
||||
language: { translate: originalOrganizerT, locale: originalOrganizer.locale || "en" },
|
||||
},
|
||||
],
|
||||
eventType?.metadata as EventTypeMetadata
|
||||
);
|
||||
if (previousRRHost) {
|
||||
await sendRoundRobinCancelledEmailsAndSMS(
|
||||
cancelledEvt,
|
||||
[
|
||||
{
|
||||
...previousRRHost,
|
||||
name: previousRRHost.name || "",
|
||||
username: previousRRHost.username || "",
|
||||
timeFormat: getTimeFormatStringFromUserTimeFormat(previousRRHost.timeFormat),
|
||||
language: { translate: previousRRHostT, locale: previousRRHost.locale || "en" },
|
||||
},
|
||||
],
|
||||
eventType?.metadata as EventTypeMetadata
|
||||
);
|
||||
}
|
||||
|
||||
if (hasOrganizerChanged) {
|
||||
// Handle changing workflows with organizer
|
||||
|
||||
@@ -151,17 +151,6 @@ export const roundRobinReassignment = async ({
|
||||
reassignedHost: reassignedRRHost,
|
||||
});
|
||||
|
||||
// Assume the RR host was labelled as a team member
|
||||
if (reassignedRRHost.email !== organizer.email) {
|
||||
teamMembers.push({
|
||||
id: reassignedRRHost.id,
|
||||
email: reassignedRRHost.email,
|
||||
name: reassignedRRHost.name || "",
|
||||
timeZone: reassignedRRHost.timeZone,
|
||||
language: { translate: reassignedRRHostT, locale: reassignedRRHost.locale ?? "en" },
|
||||
});
|
||||
}
|
||||
|
||||
const attendeePromises = [];
|
||||
for (const attendee of booking.attendees) {
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user