Website: Update round robin in salesforce helpers & move lead creation to save-questionnaire-progress. (#19209)

Closes: #18932

Changes:
- Updated `update-or-create-contact-and-account.js` to not round robin
new account records created.
- Updated create-lead to reassign accounts owned by the integrations
admin user when a new lead is created.
- Updated logged warnings in signup, deliver-contact-form-message and
deliver-talk-to-us-form-submission.
- Updated signup.js to not create salesforce leads (only account and
contact records)
- Updated save-questionnaire-progress to create Salesforce leads when we
know the user has a use case for Fleet.
This commit is contained in:
Eric 2024-05-27 16:43:40 -05:00 committed by GitHub
parent b1a18bc4a5
commit 2af2c41572
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 89 additions and 83 deletions

View file

@ -80,7 +80,7 @@ module.exports = {
leadSource: 'Website - Contact forms',
leadDescription: `Sent a contact form message: ${message}`,
}).tolerate((err)=>{
sails.log.warn(`Background task failed: When a user submitted a contact form message, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}. Error:`, err.raw);
sails.log.warn(`Background task failed: When a user submitted a contact form message, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}.`, err);
});
});//_∏_ (Meanwhile...)

View file

@ -86,7 +86,7 @@ module.exports = {
leadSource: 'Website - Contact forms',
leadDescription: `Submitted the "Talk to us" form.`,
}).tolerate((err)=>{
sails.log.warn(`Background task failed: When a user submitted the "Talk to us" form, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}. Error:`, err.raw);
sails.log.warn(`Background task failed: When a user submitted the "Talk to us" form, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}.`, err);
});
});//_∏_ (Meanwhile...)

View file

@ -140,14 +140,13 @@ the account verification message.)`,
// Use timers.setImmediate() to update/create CRM records in the background.
require('timers').setImmediate(async ()=>{
await sails.helpers.salesforce.updateOrCreateContactAndAccountAndCreateLead.with({
await sails.helpers.salesforce.updateOrCreateContactAndAccount.with({
emailAddress: newEmailAddress,
firstName: firstName,
lastName: lastName,
organization: organization,
leadSource: 'Website - Sign up',
}).tolerate((err)=>{
sails.log.warn(`Background task failed: When a user (email: ${newEmailAddress} sign up for a fleetdm.com account, a Contact, Account, and Lead record could not be created/updated in the CRM. Error:`, err.raw);
sails.log.warn(`Background task failed: When a user (email: ${newEmailAddress} signed up for a fleetdm.com account, a Contact and Account record could not be created/updated in the CRM.`, err);
});
});//_∏_ (Meanwhile...)

View file

@ -114,7 +114,8 @@ module.exports = {
// - procurement-wants-some-stuff » No change (Stage ??)
// - nothing » No change (Stage ??)
// Set a variable to track whether we should create a Lead record in Salesforce.
let createLeadRecord = false;
let psychologicalStage = userRecord.psychologicalStage;
// Get the value of the submitted formData, we do this so we only need to check one variable, instead of (formData.attribute === 'foo');
let valueFromFormData = _.values(formData)[0];
@ -125,8 +126,10 @@ module.exports = {
} else if(currentStep === 'have-you-ever-used-fleet') {
if(['yes-deployed'].includes(valueFromFormData)) {
// If the user has Fleet deployed, set their stage to 6.
createLeadRecord = true;
psychologicalStage = '6 - Has team buy-in';
} else if(valueFromFormData === 'yes-recently-deployed'){
createLeadRecord = true;
psychologicalStage = '5 - Personally confident';
} else if(valueFromFormData === 'yes-deployed-local'){
// If they've tried Fleet locally, set their stage to 3.
@ -151,6 +154,7 @@ module.exports = {
psychologicalStage = '2 - Aware';
}
} else {// Otherwise, they have a use case and will be set to stage 4.
createLeadRecord = true;
psychologicalStage = '4 - Has use case';
}
} else if(currentStep === 'is-it-any-good') {
@ -166,9 +170,11 @@ module.exports = {
psychologicalStage = '2 - Aware';
}
} else {
createLeadRecord = true;
psychologicalStage = '4 - Has use case';
}
} else {// For any other selected primary buying situation, since a use case will have been selected, set their psyStage to 4
createLeadRecord = true;
psychologicalStage = '4 - Has use case';
// FUTURE: check previous answers for other selected buying situations.
}
@ -177,6 +183,7 @@ module.exports = {
if(valueFromFormData === 'let-me-think-about-it') {
psychologicalStage = '2 - Aware';
} else if (['deploy-fleet-in-environment','host-fleet-for-me'].includes(valueFromFormData)) {
createLeadRecord = true;
psychologicalStage = '4 - Has use case';
} else { require('assert')(false,'This should never happen.'); }
} else if(currentStep === 'how-was-your-deployment') {
@ -209,42 +216,40 @@ module.exports = {
// Only update CRM records if the user's psychological stage changes.
if(psychologicalStage !== userRecord.psychologicalStage) {
// If the createLeadRecord flag was set to true, create a lead record.
if(createLeadRecord){
// Use setImmediate to queue CRM updates.
// [?]: https://nodejs.org/api/timers.html#setimmediatecallback-args
require('timers').setImmediate(async ()=>{
await sails.helpers.salesforce.updateOrCreateContactAndAccount.with({
emailAddress: this.req.me.emailAddress,
firstName: this.req.me.firstName,
lastName: this.req.me.lastName,
primaryBuyingSituation: primaryBuyingSituation === 'eo-security' ? 'Endpoint operations - Security' : primaryBuyingSituation === 'eo-it' ? 'Endpoint operations - IT' : primaryBuyingSituation === 'mdm' ? 'Device management (MDM)' : primaryBuyingSituation === 'vm' ? 'Vulnerability management' : undefined,
organization: this.req.me.organization,
psychologicalStage,
}).tolerate((err)=>{
sails.log.warn(`Background task failed: When a user (email: ${this.req.me.emailAddress} submitted a step of the get started questionnaire, a Contact and Account record could not be created/updated in the CRM. Full error:`, err);
});
});//_∏_ (Meanwhile...)
require('timers').setImmediate(async ()=>{
await sails.helpers.salesforce.updateOrCreateContactAndAccountAndCreateLead.with({
emailAddress: this.req.me.emailAddress,
firstName: this.req.me.firstName,
lastName: this.req.me.lastName,
primaryBuyingSituation: primaryBuyingSituation === 'eo-security' ? 'Endpoint operations - Security' : primaryBuyingSituation === 'eo-it' ? 'Endpoint operations - IT' : primaryBuyingSituation === 'mdm' ? 'Device management (MDM)' : primaryBuyingSituation === 'vm' ? 'Vulnerability management' : undefined,
organization: this.req.me.organization,
psychologicalStage,
leadSource: 'Website - Sign up',
}).tolerate((err)=>{
sails.log.warn(`Background task failed: When a user (email: ${this.req.me.emailAddress} submitted a step of the get started questionnaire, a Contact and Account record could not be created/updated in the CRM.`, err);
});
});//_∏_ (Meanwhile...)
} else {
// Otherwise, update or create a contact and account record.
require('timers').setImmediate(async ()=>{
await sails.helpers.salesforce.updateOrCreateContactAndAccount.with({
emailAddress: this.req.me.emailAddress,
firstName: this.req.me.firstName,
lastName: this.req.me.lastName,
primaryBuyingSituation: primaryBuyingSituation === 'eo-security' ? 'Endpoint operations - Security' : primaryBuyingSituation === 'eo-it' ? 'Endpoint operations - IT' : primaryBuyingSituation === 'mdm' ? 'Device management (MDM)' : primaryBuyingSituation === 'vm' ? 'Vulnerability management' : undefined,
organization: this.req.me.organization,
psychologicalStage,
}).tolerate((err)=>{
sails.log.warn(`Background task failed: When a user (email: ${this.req.me.emailAddress} submitted a step of the get started questionnaire, a Contact and Account record could not be created/updated in the CRM.`, err);
});
});//_∏_ (Meanwhile...)
}
}//fi
// TODO: send all other answers to Salesforce (when there are fields for them)
// await sails.helpers.http.post.with({
// url: 'https://hooks.zapier.com/hooks/catch/3627242/3nltwbg/',
// data: {
// emailAddress: this.req.me.emailAddress,
// firstName: this.req.me.firstName,
// lastName: this.req.me.lastName,
// primaryBuyingSituation: primaryBuyingSituation,
// organization: this.req.me.organization,
// psychologicalStage,
// currentStep,
// webhookSecret: sails.config.custom.zapierSandboxWebhookSecret,
// }
// })
// .timeout(5000)
// .tolerate(['non200Response', 'requestFailed'], (err)=>{
// // Note that Zapier responds with a 2xx status code even if something goes wrong, so just because this message is not logged doesn't mean everything is hunky dory. More info: https://github.com/fleetdm/fleet/pull/6380#issuecomment-1204395762
// sails.log.warn(`When a user completed a questionnaire step, a lead/contact could not be updated in the CRM for this email address: ${this.req.me.emailAddress}. Raw error: ${err}`);
// return;
// });
// Set the user's answer to the current step.
questionnaireProgress[currentStep] = formData;
// Clone the questionnaireProgress to prevent any mutations from sending it through the updateOne Waterline method.

View file

@ -72,6 +72,35 @@ module.exports = {
}).intercept((err)=>{
return new Error(`When attempting to create a Lead record using an exisitng Account record (ID: ${salesforceAccountId}), An error occured when retreiving the specified record. Error: ${err}`);
});
let salesforceAccountOwnerId = accountRecord.OwnerId;
// If the account record is owned by the integrations admin user and is not the account where unenriched contacts go, we'll round robin it and reassign it to an AE.
if(salesforceAccountOwnerId === '0054x00000735wDAAQ' && salesforceAccountId !== '0014x000025JC8DAAW') {
// Get all round robin users.
let roundRobinUsers = await salesforceConnection.sobject('User')
.find({
AE_Round_robin__c: true,// eslint-disable-line camelcase
});
// Get the user with the earliest round robin timestamp.
let userWithEarliestAssignTimeStamp = _.sortBy(roundRobinUsers, 'AE_Account_Assignment_round_robin__c')[0];
let today = new Date();
let nowOn = today.toISOString().replace('Z', '+0000');
// Update the salesforceAccountOwnerId value to be the ID of the next user in the round robin.
salesforceAccountOwnerId = userWithEarliestAssignTimeStamp.Id;
// Update this user to put them at the bottom of the round robin list.
await salesforceConnection.sobject('User')
.update({
Id: salesforceAccountOwnerId,
// eslint-disable-next-line camelcase
AE_Account_Assignment_round_robin__c: nowOn
});
// Reassign the account to the new owner.
await salesforceConnection.sobject('Account')
.update({
Id: salesforceAccountId,
OwnerId: salesforceAccountOwnerId
});
}
let primaryBuyingSituationValuesByCodename = {
'vm': 'Vulnerability management',
@ -103,7 +132,7 @@ module.exports = {
Primary_buying_scenario__c: primaryBuyingSituationToSet,// eslint-disable-line camelcase
LinkedIn_profile__c: contactRecord.LinkedIn_profile__c,// eslint-disable-line camelcase
// Information from the account record:
OwnerId: accountRecord.OwnerId
OwnerId: salesforceAccountOwnerId
});
}).intercept((err)=>{
return new Error(`Could not create new Lead record. Error: ${err}`);

View file

@ -94,60 +94,33 @@ module.exports = {
// '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 and it is not owned by the integrations admin or a disabled user, we'll use assign the new contact to the account owner.
if(existingAccountRecord && !['0054x00000735wDAAQ', '0054x0000086wsQAAQ'].includes(existingAccountRecord.OwnerId)) {
// 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 we didn't find an existing record, or found one onwned by the integrations admin or a disabled user, we'll round robin it between the AE's Salesforce users.
let roundRobinUsers = await salesforceConnection.sobject('User')
.find({
AE_Round_robin__c: true,// eslint-disable-line camelcase
});
let userWithEarliestAssignTimeStamp = _.sortBy(roundRobinUsers, 'AE_Account_Assignment_round_robin__c')[0];
// If no existing account record was found, create a new one.
// Create a timestamp to use for the new account's assigned date.
let today = new Date();
let nowOn = today.toISOString().replace('Z', '+0000');
// Update the accountOwnerId value to be the ID of the next user in the round robin.
salesforceAccountOwnerId = userWithEarliestAssignTimeStamp.Id;
// Update this user to put them at the bottom of the round robin list.
await salesforceConnection.sobject('User')
.update({
Id: salesforceAccountOwnerId,
let newAccountRecord = await salesforceConnection.sobject('Account')
.create({
Account_Assigned_date__c: nowOn,// eslint-disable-line camelcase
// eslint-disable-next-line camelcase
AE_Account_Assignment_round_robin__c: nowOn
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,
});
if(existingAccountRecord){
// If we found an existing Account record owned by the integrations admin user account, reassign it to the new owner.
salesforceAccountId = existingAccountRecord.Id;
await salesforceConnection.sobject('Account')
.update({
Id: salesforceAccountId,
OwnerId: salesforceAccountOwnerId
});
} else {
// If no existing account record was found, create a new one.
let newAccountRecord = await salesforceConnection.sobject('Account')
.create({
OwnerId: salesforceAccountOwnerId,
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,
});
salesforceAccountId = newAccountRecord.id;
}//fi
// console.log('New account created!', salesforceAccountId);
salesforceAccountId = newAccountRecord.id;
}//fi
// console.log('New account created!', salesforceAccountId);
}//fi