Hey guys. I'm looking for some help with this. I'm trying to unlock the potential of the custom code element present in workflows, the one granted by Operations Hub.
I'm basically trying to adapt the following sample code to work with Companies, and use their names as the deduplication property:
But I get the following, basic-looking error pointing at line 20, which is the first time the code tries to search by ID. For some reason, it fails.
ERROR Invoke Error {"errorType":"TypeError","errorMessage":"Cannot read properties of undefined (reading 'getById')","stack":["TypeError: Cannot read properties of undefined (reading 'getById')"," at Object.exports.main (/var/task/file.js:20:6)"," at Runtime.exports.hubspot_handler [as handler] (/var/task/hubspotHandler.js:6:21)"," at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)"]}
Here's the full code. I tried both referencing the ID using the sample's "event.object.objectId" and also feeding it as an input field on the workflow. The error remains the same.
/**
* Searches for another company with the same value of DEDUPE_PROPERTY.
* - If no matches are found, nothing happens
* - If one match is found, the enrolled company is merged into the matching company
* - If more than one match is found, the action fails
*/
const DEDUPE_PROPERTY = 'name';
const hubspot = require('@hubspot/api-client');
exports.main = (event, callback) => {
// Make sure to add your API key under "Secrets" above.
const hubspotClient = new hubspot.Client({
accessToken: process.env.CompanyAssocCreateToken
});
hubspotClient.crm.companies.defaultApi
.getById(event.object.objectId, [DEDUPE_PROPERTY])
.then(companyResult => {
let dedupePropValue = companyResult.body.properties[DEDUPE_PROPERTY];
console.log(`Looking for duplicates based on ${DEDUPE_PROPERTY} = ${dedupePropValue}`);
hubspotClient.crm.companies.defaultApi
.doSearch({
filterGroups: [{
filters: [{
propertyName: DEDUPE_PROPERTY,
operator: 'EQ',
value: dedupePropValue
}]
}]
})
.then(searchResults => {
let idsToMerge = searchResults.body.results
.map(object => object.id)
.filter(vid => Number(vid) !== Number(event.object.objectId));
if (idsToMerge.length == 0) {
console.log('No matching company, nothing to merge');
return;
} else if (idsToMerge.length > 1) {
console.log(`Found multiple potential company IDs ${idsToMerge.join(', ')} to merge`);
throw new Error("Ambiguous merge; more than one matching company");
}
let idToMerge = idsToMerge[0];
console.log(`Merging enrolled company id=${event.object.objectId} into company id=${idToMerge}`);
hubspotClient
.apiRequest({
method: 'POST',
path: `/crm/v3/objects/companies/merge`,
body: {
objectIdToMerge: idToMerge,
primaryObjectId: event.object.objectId
}
})
.then(mergeResult => {
console.log('Companies merged!');
});
});
});
callback({
outputFields: {
company_id: event.object.objectId
}
});
};
After a bunch of troubleshooting, I found the two issues which were breaking the code:
I was calling the wrong APIs, which should be basicApi and searchApi instead of DefaultApi. The Company Endpoints documentation was misleading in this regard.
The sample code refers to "body.properties" when trying to look into the properties clause of a response, and "body" throws it off, so that's inaccurate too. The reference should only be "properties", as in companyResult.properties[DEDUPE_PROPERTY].
Hi, @GJakobTriad... thanks so much for posting your solution - it was enormously helpful!
I also used the contact dedupe snippet from GitHub and combined that with your revisions. The code executed successfully but wasn't doing anything (the companies weren't merging).
I found that I had a discrepancy further down in my combined code, so I'm reposting the full, working code block here for other folks who may be runing into the same issue.
/**
* Searches for another company with the same value of DEDUPE_PROPERTY.
* - If no matches are found, nothing happens
* - If one match is found, the enrolled company is merged into the matching company
* - If more than one match is found, the action fails
*/
const DEDUPE_PROPERTY = 'domain';
const hubspot = require('@hubspot/api-client');
exports.main = (event, callback) => {
// Make sure to add your API key under "Secrets" above.
const hubspotClient = new hubspot.Client({
accessToken: process.env.[INSERT ACCESS TOKEN]
});
hubspotClient.crm.companies.basicApi
.getById(event.object.objectId, [DEDUPE_PROPERTY])
.then(companyResult => {
let dedupePropValue = companyResult.properties[DEDUPE_PROPERTY];
console.log(`Looking for duplicates based on ${DEDUPE_PROPERTY} = ${dedupePropValue}`);
hubspotClient.crm.companies.searchApi
.doSearch({
filterGroups: [{
filters: [{
propertyName: DEDUPE_PROPERTY,
operator: 'EQ',
value: dedupePropValue
}]
}]
})
.then(searchResults => {
let idsToMerge = searchResults.results
.map(object => object.id)
.filter(vid => Number(vid) !== Number(event.object.objectId));
if (idsToMerge.length == 0) {
console.log('No matching company, nothing to merge');
return;
} else if (idsToMerge.length > 1) {
console.log(`Found multiple potential company IDs ${idsToMerge.join(', ')} to merge`);
throw new Error("Ambiguous merge; more than one matching company");
}
let idToMerge = idsToMerge[0];
console.log(`Merging enrolled company id=${event.object.objectId} into company id=${idToMerge}`);
hubspotClient
.apiRequest({
method: 'POST',
path: `/crm/v3/objects/companies/merge`,
body: {
objectIdToMerge: idToMerge,
primaryObjectId: event.object.objectId
}
})
.then(mergeResult => {
console.log('Companies merged!');
});
});
});
callback({
outputFields: {
company_id: event.object.objectId
}
});
};
After a bunch of troubleshooting, I found the two issues which were breaking the code:
I was calling the wrong APIs, which should be basicApi and searchApi instead of DefaultApi. The Company Endpoints documentation was misleading in this regard.
The sample code refers to "body.properties" when trying to look into the properties clause of a response, and "body" throws it off, so that's inaccurate too. The reference should only be "properties", as in companyResult.properties[DEDUPE_PROPERTY].