From 223e1f23620df9f12bc523ed0ce0ab6cb0d29ae2 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 21 Jun 2024 17:12:01 -0500 Subject: [PATCH] Website: Update contact record creation (#19922) Closes: https://github.com/fleetdm/confidential/issues/6929 Changes: - Updated the update-or-create-contact-and-account helper to search for an existing contact by email address before searching for an account with the information provided by the get-enriched helper. This change will allow us to change the account that a contact is associated with in the CRM without duplicate records getting (re)created. --- .../update-or-create-contact-and-account.js | 194 +++++++++--------- 1 file changed, 95 insertions(+), 99 deletions(-) diff --git a/website/api/helpers/salesforce/update-or-create-contact-and-account.js b/website/api/helpers/salesforce/update-or-create-contact-and-account.js index 407a7026a9..0fd40147dd 100644 --- a/website/api/helpers/salesforce/update-or-create-contact-and-account.js +++ b/website/api/helpers/salesforce/update-or-create-contact-and-account.js @@ -45,6 +45,7 @@ module.exports = { fn: async function ({emailAddress, linkedinUrl, firstName, lastName, organization, primaryBuyingSituation, psychologicalStage}) { + // Return undefined if we're not running in a production environment. if(sails.config.environment !== 'production') { sails.log.verbose('Skipping Salesforce integration...'); return { @@ -63,110 +64,23 @@ module.exports = { throw new Error('UsageError: when updating or creating a contact and account in salesforce, either an email or linkedInUrl is required.'); } - if(linkedinUrl){ - // If linkedinUrl was provided, strip the protocol and subdomain from the URL. - linkedinUrl = linkedinUrl.replace(sails.config.custom.RX_PROTOCOL_AND_COMMON_SUBDOMAINS, ''); - } - // Send the information we have to the enrichment helper. - let enrichmentData = await sails.helpers.iq.getEnriched(emailAddress, linkedinUrl, firstName, lastName, organization); - // console.log(enrichmentData); - // Log in to Salesforce. let jsforce = require('jsforce'); let salesforceConnection = new jsforce.Connection({ loginUrl : 'https://fleetdm.my.salesforce.com' }); - - let salesforceAccountOwnerId; - await salesforceConnection.login(sails.config.custom.salesforceIntegrationUsername, sails.config.custom.salesforceIntegrationPasskey); - let salesforceAccountId; - if(!enrichmentData.employer || !enrichmentData.employer.emailDomain || !enrichmentData.employer.organization) { - // Special sacraficial meat cave where the contacts with no organization go. - // https://fleetdm.lightning.force.com/lightning/r/Account/0014x000025JC8DAAW/view - salesforceAccountId = '0014x000025JC8DAAW'; - salesforceAccountOwnerId = '0054x00000735wDAAQ';// « "Integrations admin" user. - } else { - // Search for an existing Account record by the organization returned from the getEnriched helper. - let existingAccountRecord = await salesforceConnection.sobject('Account') - .findOne({ - 'Name': enrichmentData.employer.organization, - // 'LinkedIn_company_URL__c': enrichmentData.employer.linkedinCompanyPageUrl // TODO: if this information is not present on an existing account, nothing will be returned. - }); - // If we didn't find an account that's name exaclty matches, we'll do another search using the provided email domain. - if(!existingAccountRecord){ - existingAccountRecord = await salesforceConnection.sobject('Account') - .findOne({ - 'Website': enrichmentData.employer.emailDomain, - // 'LinkedIn_company_URL__c': enrichmentData.employer.linkedinCompanyPageUrl // TODO: if this information is not present on an existing account, nothing will be returned. - }); - } - // console.log(existingAccountRecord); - // If we found an exisitng account, we'll use assign the new contact to the account owner. - if(existingAccountRecord) { - // Store the ID of the Account record we found. - salesforceAccountId = existingAccountRecord.Id; - salesforceAccountOwnerId = existingAccountRecord.OwnerId; - // console.log('exising account found!', salesforceAccountId); - } else { - // If no existing account record was found, create a new one. - // Create a timestamp to use for the new account's assigned date. - salesforceAccountOwnerId = '0054x00000735wDAAQ';// « "Integrations admin" user. - let today = new Date(); - let nowOn = today.toISOString().replace('Z', '+0000'); - - let newAccountRecord = await salesforceConnection.sobject('Account') - .create({ - Account_Assigned_date__c: nowOn,// eslint-disable-line camelcase - // eslint-disable-next-line camelcase - Current_Assignment_Reason__c: 'Inbound Lead',// TODO verify that this matters. if not, do not set it. - Prospect_Status__c: 'Assigned',// eslint-disable-line camelcase - - Name: enrichmentData.employer.organization,// IFWMIH: We know organization exists - Website: enrichmentData.employer.emailDomain, - LinkedIn_company_URL__c: enrichmentData.employer.linkedinCompanyPageUrl,// eslint-disable-line camelcase - NumberOfEmployees: enrichmentData.employer.numberOfEmployees, - OwnerId: salesforceAccountOwnerId - }); - salesforceAccountId = newAccountRecord.id; - }//fi - // console.log('New account created!', salesforceAccountId); - }//fi - - - - // Now search for an existing Contact. - // FUTURE: expand this section to improve the searches. - let existingContactRecord; - if(emailAddress){ - // console.log('searching for existing contact by emailAddress'); - existingContactRecord = await salesforceConnection.sobject('Contact') - .findOne({ - AccountId: salesforceAccountId, - Email: emailAddress, - }); - } else if(linkedinUrl) { - // console.log('searching for existing contact by linkedInUrl'); - existingContactRecord = await salesforceConnection.sobject('Contact') - .findOne({ - AccountId: salesforceAccountId, - LinkedIn_profile__c: linkedinUrl // eslint-disable-line camelcase - }); - } else { - existingContactRecord = undefined; - }//fi - let salesforceContactId; + let salesforceAccountId; + + // Build a dictionary of values we'll update/create a contact record with. let valuesToSet = {}; if(emailAddress){ valuesToSet.Email = emailAddress; } - if(linkedinUrl || (enrichmentData.person && enrichmentData.person.linkedinUrl)){ - valuesToSet.LinkedIn_profile__c = linkedinUrl || enrichmentData.person.linkedinUrl;// eslint-disable-line camelcase - } - if(enrichmentData.person && enrichmentData.person.title){ - valuesToSet.Title = enrichmentData.person.title; + if(linkedinUrl){ + valuesToSet.LinkedIn_profile__c = linkedinUrl;// eslint-disable-line camelcase } if(primaryBuyingSituation) { valuesToSet.Primary_buying_situation__c = primaryBuyingSituation;// eslint-disable-line camelcase @@ -176,18 +90,102 @@ module.exports = { } - if(existingContactRecord){ + let existingContactRecord; + // Search for an existing Contact record using the provided email address or linkedIn profile URL. + if(emailAddress) { + existingContactRecord = await salesforceConnection.sobject('Contact') + .findOne({ + Email: emailAddress, + }); + } else if(linkedinUrl) { + existingContactRecord = await salesforceConnection.sobject('Contact') + .findOne({ + LinkedIn_profile__c: linkedinUrl // eslint-disable-line camelcase + }); + } + + if(existingContactRecord) { + // console.log(`Exisitng contact found! ${existingContactRecord.Id}`); + // If we found an existing contact, we'll update it with the information provided. salesforceContactId = existingContactRecord.Id; - // console.log(`existing contact record found! ${salesforceContactId}`); - // Update the existing contact with the information provided. await salesforceConnection.sobject('Contact') .update({ Id: salesforceContactId, ...valuesToSet, }); + salesforceAccountId = existingContactRecord.AccountId; // console.log(`${salesforceContactId} updated!`); } else { - // Otherwise create a new Contact record. + // Otherwise, we'll enrich the information we have, and check for an existing account. + if(linkedinUrl){ + // If linkedinUrl was provided, strip the protocol and subdomain from the URL. + linkedinUrl = linkedinUrl.replace(sails.config.custom.RX_PROTOCOL_AND_COMMON_SUBDOMAINS, ''); + } + // Send the information we have to the enrichment helper. + let enrichmentData = await sails.helpers.iq.getEnriched(emailAddress, linkedinUrl, firstName, lastName, organization); + // console.log(enrichmentData); + // Add information from the enrichmentData to the values to set on the new Contact record. + if(enrichmentData.person && enrichmentData.person.linkedinUrl){ + valuesToSet.LinkedIn_profile__c = enrichmentData.person.linkedinUrl;// eslint-disable-line camelcase + } + if(enrichmentData.person && enrichmentData.person.title){ + valuesToSet.Title = enrichmentData.person.title; + } + let salesforceAccountOwnerId; + if(!enrichmentData.employer || !enrichmentData.employer.emailDomain || !enrichmentData.employer.organization) { + // Special sacrificial meat cave where the contacts with no organization go. + // https://fleetdm.lightning.force.com/lightning/r/Account/0014x000025JC8DAAW/view + salesforceAccountId = '0014x000025JC8DAAW'; + salesforceAccountOwnerId = '0054x00000735wDAAQ';// « "Integrations admin" user. + } else { + // Search for an existing Account record by the organization returned from the getEnriched helper. + let existingAccountRecord = await salesforceConnection.sobject('Account') + .findOne({ + 'Name': enrichmentData.employer.organization, + // 'LinkedIn_company_URL__c': enrichmentData.employer.linkedinCompanyPageUrl // TODO: if this information is not present on an existing account, nothing will be returned. + }); + // If we didn't find an account that's name exaclty matches, we'll do another search using the provided email domain. + if(!existingAccountRecord){ + existingAccountRecord = await salesforceConnection.sobject('Account') + .findOne({ + 'Website': enrichmentData.employer.emailDomain, + // 'LinkedIn_company_URL__c': enrichmentData.employer.linkedinCompanyPageUrl // TODO: if this information is not present on an existing account, nothing will be returned. + }); + } + // console.log(existingAccountRecord); + // If we found an exisitng account, we'll assign the new contact to the account owner. + if(existingAccountRecord) { + // Store the ID of the Account record we found. + salesforceAccountId = existingAccountRecord.Id; + salesforceAccountOwnerId = existingAccountRecord.OwnerId; + // console.log('exising account found!', salesforceAccountId); + } else { + // If no existing account record was found, create a new one, and assign it to the "Integrations Admin" user. + salesforceAccountOwnerId = '0054x00000735wDAAQ';// « "Integrations admin" user. + // Create a timestamp to use for the new account's assigned date. + let today = new Date(); + let nowOn = today.toISOString().replace('Z', '+0000'); + + let newAccountRecord = await salesforceConnection.sobject('Account') + .create({ + Account_Assigned_date__c: nowOn,// eslint-disable-line camelcase + // eslint-disable-next-line camelcase + Current_Assignment_Reason__c: 'Inbound Lead',// TODO verify that this matters. if not, do not set it. + Prospect_Status__c: 'Assigned',// eslint-disable-line camelcase + + Name: enrichmentData.employer.organization,// IFWMIH: We know organization exists + Website: enrichmentData.employer.emailDomain, + LinkedIn_company_URL__c: enrichmentData.employer.linkedinCompanyPageUrl,// eslint-disable-line camelcase + NumberOfEmployees: enrichmentData.employer.numberOfEmployees, + OwnerId: salesforceAccountOwnerId + }); + salesforceAccountId = newAccountRecord.id; + }//fi + // console.log('New account created!', salesforceAccountId); + }//fi + + // console.log(`creating new Contact record.`) + // Create a new Contact record for this person. let newContactRecord = await salesforceConnection.sobject('Contact') .create({ AccountId: salesforceAccountId, @@ -196,12 +194,10 @@ module.exports = { LastName: lastName, ...valuesToSet, }); - // console.log(newContactRecord); + // console.log(`Created ${newContactRecord.id}`); salesforceContactId = newContactRecord.id; - // console.log(`New contact record created! ${salesforceContactId}`); }//fi - return { salesforceAccountId, salesforceContactId