mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
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:
parent
b1a18bc4a5
commit
2af2c41572
6 changed files with 89 additions and 83 deletions
|
|
@ -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...)
|
||||
|
||||
|
|
|
|||
|
|
@ -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...)
|
||||
|
||||
|
|
|
|||
5
website/api/controllers/entrance/signup.js
vendored
5
website/api/controllers/entrance/signup.js
vendored
|
|
@ -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...)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
31
website/api/helpers/salesforce/create-lead.js
vendored
31
website/api/helpers/salesforce/create-lead.js
vendored
|
|
@ -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}`);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue