From 8605fb451895be2f1c55deb63068196547fe6670 Mon Sep 17 00:00:00 2001
From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Date: Tue, 29 Oct 2024 14:03:35 -0400
Subject: [PATCH] feat: Salesforce change owner on booking [CAL-4641] (#17391)
* Let user set owner name to change
* Add backend logic
* Add message
* Type fixes
---
apps/web/public/static/locales/en/common.json | 1 +
.../components/EventTypeAppCardInterface.tsx | 22 ++++++++++
.../app-store/salesforce/lib/CrmService.ts | 40 +++++++++++++++++--
packages/app-store/salesforce/zod.ts | 2 +
4 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json
index 8bf40d22c0..6ae9da149c 100644
--- a/apps/web/public/static/locales/en/common.json
+++ b/apps/web/public/static/locales/en/common.json
@@ -2720,5 +2720,6 @@
"attendee_timezone_info": "Attendee Timezone",
"event_start_time_in_attendee_timezone_info": "Event Start Time In Attendee Timezone",
"event_end_time_in_attendee_timezone_info": "Event End Time In Attendee Timezone",
+ "salesforce_owner_name_to_change": "Owner name to change",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
diff --git a/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx b/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx
index a039260068..9fe63b17f2 100644
--- a/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx
+++ b/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx
@@ -27,6 +27,8 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
const createEventOn = getAppData("createEventOn") ?? SalesforceRecordEnum.CONTACT;
const onBookingWriteToEventObject = getAppData("onBookingWriteToEventObject") ?? false;
const onBookingWriteToEventObjectMap = getAppData("onBookingWriteToEventObjectMap") ?? {};
+ const onBookingChangeRecordOwner = getAppData("onBookingChangeRecordOwner") ?? false;
+ const onBookingChangeRecordOwnerName = getAppData("onBookingChangeRecordOwnerName") ?? [];
const { t } = useLocale();
const recordOptions = [
@@ -208,6 +210,26 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
) : null}
+
+ {
+ setAppData("onBookingChangeRecordOwner", checked);
+ }}
+ />
+
+ {onBookingChangeRecordOwner ? (
+
+
{t("salesforce_owner_name_to_change")}
+
setAppData("onBookingChangeRecordOwnerName", e.target.value)}
+ />
+
+ ) : null}
+
{eventType.schedulingType === SchedulingType.ROUND_ROBIN ? (
{
const conn = await this.conn;
- return await conn.query(`SELECT Id, Email FROM User WHERE Id = '${ownerId}'`);
+ return await conn.query(`SELECT Id, Email, Name FROM User WHERE Id = '${ownerId}'`);
};
private getSalesforceEventBody = (event: CalendarEvent): string => {
@@ -153,7 +153,6 @@ export default class SalesforceCRMService implements CRM {
options: { [key: string]: unknown }
) => {
const conn = await this.conn;
- const ownerId = await this.getSalesforceUserIdFromEmail(event.organizer.email);
return await conn.sobject("Event").create({
StartDateTime: new Date(event.startTime).toISOString(),
@@ -166,7 +165,6 @@ export default class SalesforceCRMService implements CRM {
IsRecurrence2: true,
Recurrence2PatternText: new RRule(event.recurringEvent).toString(),
}),
- ...(ownerId && { OwnerId: ownerId }),
});
};
@@ -188,9 +186,12 @@ export default class SalesforceCRMService implements CRM {
confirmedCustomFieldInputs[field] = appOptions.onBookingWriteToEventObjectMap[field];
}
+ const ownerId = await this.getSalesforceUserIdFromEmail(event.organizer.email);
+
const createdEvent = await this.salesforceCreateEventApiCall(event, {
EventWhoIds: contacts.map((contact) => contact.id),
...confirmedCustomFieldInputs,
+ ...(ownerId && { OwnerId: ownerId }),
}).catch(async (reason) => {
if (reason === sfApiErrors.INVALID_EVENTWHOIDS) {
this.calWarnings.push(
@@ -207,6 +208,10 @@ export default class SalesforceCRMService implements CRM {
return Promise.reject();
}
});
+ // Check to see if we also need to change the record owner
+ if (appOptions.onBookingChangeRecordOwner && appOptions.onBookingChangeRecordOwnerName && ownerId) {
+ await this.checkRecordOwnerNameFromRecordId(contacts[0].id, ownerId);
+ }
return createdEvent;
};
@@ -573,6 +578,35 @@ export default class SalesforceCRMService implements CRM {
}
}
+ private async checkRecordOwnerNameFromRecordId(id: string, newOwnerId: string) {
+ const conn = await this.conn;
+ const appOptions = this.getAppOptions();
+
+ // Get the associated record that the event was created on
+ const recordQuery = (await conn.query(
+ `SELECT OwnerId FROM ${appOptions?.createEventOn} WHERE Id = '${id}'`
+ )) as { records: { OwnerId: string }[] };
+
+ if (!recordQuery || !recordQuery.records.length) return;
+
+ const ownerId = recordQuery.records[0].OwnerId;
+
+ const ownerQuery = await this.getSalesforceUserFromOwnerId(ownerId);
+
+ if (!ownerQuery || !ownerQuery.records.length) return;
+
+ const owner = ownerQuery.records[0] as { Name: string };
+
+ // Check that the owner name matches the names where we need to change the organizer
+ if (appOptions?.onBookingChangeRecordOwnerName.includes(owner.Name)) {
+ await conn.sobject(appOptions?.createEventOn).update({
+ // First field is there WHERE statement
+ Id: id,
+ OwnerId: newOwnerId,
+ });
+ }
+ }
+
private async getAccountIdBasedOnEmailDomainOfContacts(email: string) {
const conn = await this.conn;
const emailDomain = email.split("@")[1];
diff --git a/packages/app-store/salesforce/zod.ts b/packages/app-store/salesforce/zod.ts
index 4fe37699e6..512d6614e9 100644
--- a/packages/app-store/salesforce/zod.ts
+++ b/packages/app-store/salesforce/zod.ts
@@ -15,6 +15,8 @@ export const appDataSchema = eventTypeAppCardZod.extend({
createLeadIfAccountNull: z.boolean().optional(),
onBookingWriteToEventObject: z.boolean().optional(),
onBookingWriteToEventObjectMap: z.record(z.any()).optional(),
+ onBookingChangeRecordOwner: z.boolean().optional(),
+ onBookingChangeRecordOwnerName: z.string().optional(),
});
export const appKeysSchema = z.object({