chore: Salesforce add more logging (#19106)

* Add more logs

* Remove unused method

* Fallback when creating an event

* Type fix

* Type fix

* Type fix

* Add more logging

* More logging
This commit is contained in:
Joe Au-Yeung authored and GitHub committed 2025-02-06 10:25:38 -03:00
1 parent 3972972d57
commit 89033c0e9c
1 file changed
+83 -33
+83 -33
View File
@@ -180,11 +180,14 @@ export default class SalesforceCRMService implements CRM {
};
private salesforceCreateEvent = async (event: CalendarEvent, contacts: Contact[]) => {
const log = logger.getSubLogger({ prefix: [`[salesforceCreateEvent]:${event.uid}`] });
const appOptions = this.getAppOptions();
const writeToEventRecord = await this.generateWriteToEventBody(event);
log.info(`Writing to event fields: ${Object.keys(writeToEventRecord)} `);
let ownerId = null;
let ownerId: string | undefined = undefined;
if (event?.organizer?.email) {
ownerId = await this.getSalesforceUserIdFromEmail(event.organizer.email);
} else {
@@ -201,8 +204,20 @@ export default class SalesforceCRMService implements CRM {
this.log.warn("salesforceCreateEvent: No contacts found for event", event.uid, contacts);
}
const eventWhoIds = contacts.reduce((contactIds, contact) => {
if (contact?.id) {
contactIds.push(contact.id);
}
return contactIds;
}, [] as string[]);
if (eventWhoIds.length !== contacts.length) {
log.warn(`Not all contacts contain ids ${contacts}`);
}
const createdEvent = await this.salesforceCreateEventApiCall(event, {
EventWhoIds: contacts.map((contact) => contact.id),
EventWhoIds: eventWhoIds,
...writeToEventRecord,
...(ownerId && { OwnerId: ownerId }),
}).catch(async (reason) => {
@@ -218,12 +233,27 @@ export default class SalesforceCRMService implements CRM {
WhoId: firstContact,
}).catch((reason) => Promise.reject(reason));
}
return Promise.reject(reason);
log.error(`Error creating event: ${JSON.stringify(reason)}`);
// Try creating a simple object without additional records
return await this.salesforceCreateEventApiCall(event, {
EventWhoIds: eventWhoIds,
...(ownerId && { OwnerId: ownerId }),
}).catch((reason) => {
log.error(`Error creating simple event: ${JSON.stringify(reason)}`);
return Promise.reject(reason);
});
});
// Check to see if we also need to change the record owner
if (appOptions.onBookingChangeRecordOwner && appOptions.onBookingChangeRecordOwnerName && ownerId) {
// TODO: firstContact id is assumed to not be undefined. But current code doesn't check for it.
await this.checkRecordOwnerNameFromRecordId(firstContact.id, ownerId);
if (appOptions.onBookingChangeRecordOwner && appOptions.onBookingChangeRecordOwnerName) {
if (ownerId) {
// TODO: firstContact id is assumed to not be undefined. But current code doesn't check for it.
await this.checkRecordOwnerNameFromRecordId(firstContact.id, ownerId);
} else {
this.log.warn(
`Could not find owner with email ${event.organizer.email} to change record ${firstContact.id} ownership to`
);
}
}
if (appOptions.onBookingWriteToRecord && appOptions.onBookingWriteToRecordFields) {
await this.writeToPersonRecord(
@@ -472,6 +502,7 @@ export default class SalesforceCRMService implements CRM {
if (!contactsToCreate[0]?.email) {
this.log.warn(`createContact: no attendee email found `, contactsToCreate);
return [];
}
if (createEventOn === SalesforceRecordEnum.LEAD) {
@@ -787,36 +818,44 @@ export default class SalesforceCRMService implements CRM {
const conn = await this.conn;
const appOptions = this.getAppOptions();
if (!appOptions?.createEventOn) {
this.log.info(`Changing owner for record ${id}`);
const recordType = this.determineRecordTypeById(id);
if (!appOptions?.onBookingChangeRecordOwnerName) {
this.log.warn(
`No appOptions.createEventOn found for ${this.integrationName} on checkRecordOwnerNameFromRecordId`
`No appOptions.onBookingChangeRecordOwnerName found for ${this.integrationName} on checkRecordOwnerNameFromRecordId`
);
return;
}
// 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 }[] };
`SELECT OwnerId, Owner.Name FROM ${recordType} WHERE Id = '${id}'`
)) as { records: { OwnerId: string; Owner: { Name: string } }[] };
if (!recordQuery || !recordQuery.records.length) return;
if (!recordQuery || !recordQuery.records.length) {
this.log.warn(`Could not find record for id ${id} and type ${recordType}`);
}
const ownerId = recordQuery.records[0].OwnerId;
const owner = recordQuery.records[0].Owner;
const ownerQuery = await this.getSalesforceUserFromUserId(ownerId);
if (!appOptions.onBookingChangeRecordOwnerName.includes(owner?.Name)) {
this.log.warn(
`Current owner name ${owner?.Name} for record ${id} does not match the option ${appOptions.onBookingChangeRecordOwnerName}`
);
}
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({
await conn
.sobject(appOptions?.createEventOn)
.update({
// First field is there WHERE statement
Id: id,
OwnerId: newOwnerId,
})
.catch((error) => {
this.log.warn(`Error changing owner name with error ${JSON.stringify(error)}`);
});
}
}
private async getAccountIdBasedOnEmailDomainOfContacts(email: string) {
@@ -901,9 +940,9 @@ export default class SalesforceCRMService implements CRM {
bookingUid?: string | null
) {
const conn = await this.conn;
const { createEventOn, onBookingWriteToRecordFields = {} } = this.getAppOptions();
const { onBookingWriteToRecordFields = {} } = this.getAppOptions();
// Determine record type (Contact or Lead)
const personRecordType = this.determinePersonRecordType(createEventOn);
const personRecordType = this.determineRecordTypeById(contactId);
// Search the fields and ensure 1. they exist 2. they're the right type
const fieldsToWriteOn = Object.keys(onBookingWriteToRecordFields);
const existingFields = await this.ensureFieldsExistOnObject(fieldsToWriteOn, personRecordType);
@@ -931,7 +970,9 @@ export default class SalesforceCRMService implements CRM {
calEventResponses,
});
this.log.info(`Final writeOnRecordBody contains fields ${Object.keys(writeOnRecordBody)}`);
this.log.info(
`Final writeOnRecordBody contains fields ${Object.keys(writeOnRecordBody)} for record ${contactId}`
);
// Update the person record
await conn
@@ -970,7 +1011,7 @@ export default class SalesforceCRMService implements CRM {
// Skip if field should only be written when empty and already has a value
if (fieldConfig.whenToWrite === WhenToWriteToRecord.FIELD_EMPTY && personRecord[field.name]) {
this.log.info(
`Writing to field ${field.name} on contactId ${personRecord?.id} with value ${
`Field ${field.name} on contactId ${personRecord?.Id} already exists with value ${
personRecord[field.name]
}`
);
@@ -1149,14 +1190,6 @@ export default class SalesforceCRMService implements CRM {
return null;
}
private determinePersonRecordType(createEventOn: string): SalesforceRecordEnum {
return createEventOn === SalesforceRecordEnum.LEAD &&
this.appOptions.createEventOnLeadCheckForContact &&
this.getFallbackToContact()
? SalesforceRecordEnum.CONTACT
: this.appOptions.createEventOn;
}
private async fetchPersonRecord(
contactId: string,
existingFields: Field[],
@@ -1342,4 +1375,21 @@ export default class SalesforceCRMService implements CRM {
throw new Error(errorMessage);
});
}
/** All salesforce ids have a 3 character prefix associated with the record type
* https://help.salesforce.com/s/articleView?id=000385203&type=1
*/
private determineRecordTypeById(id: string) {
switch (id.substring(0, 3)) {
case "003":
return SalesforceRecordEnum.CONTACT;
case "001":
return SalesforceRecordEnum.ACCOUNT;
case "00Q":
return SalesforceRecordEnum.LEAD;
default:
this.log.warn(`Unhandled record id type ${id}`);
return SalesforceRecordEnum.CONTACT;
}
}
}