Enrich Data from Deals
The contact properties are enriched by the deals. We do two runs to setup the base enrichment. The first gives the product category and the colors and the second run gives as the Hydrosonic products.
Basic Enrichment
To get all the IDs from deals we run an export of the current Deal pipeline what results in a CSV file with the ID and Associated Contact IDs.
The following filter will be helpful to get you only the deals you need:
– Number of associated contacts: is greater than 0
– Amount: is greater than 0
– Order ID: is know
By the Update of the integration there should only be valid deals in the Pipelines. But it's better to double check as there might be deals slipping trough.

As we only need the Associated Contact IDs we can filter them and leave everything else behind. If the column amount has the value 0 there where no purchases and also can be ignored.

The IDs can be placed into the Constant "deal_ids" and the script run in the console. Every deal gets checked and the values added to the properties. That may take some time to finish. The terminal shows the progress.
const axios = require('axios');
const token_hubspot = {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer XXX',
},
};
const deal_ids = [];
async function processEvent(deal_id) {
try {
const lineItemsResponse = await axios.get('https://api.hubapi.com/crm/v4/objects/deals/' + deal_id + '/associations/line_items?limit=500', token_hubspot);
const lineitem_id = lineItemsResponse.data.results;
const data_sku = {
properties: ['hs_sku'],
inputs: lineitem_id.map(item => ({
id: item.toObjectId
})),
};
const skuResponse = await axios.post('https://api.hubapi.com/crm/v3/objects/line_items/batch/read', data_sku, token_hubspot);
const sku_id = skuResponse.data.results;
const product = sku_id.map(sku => {
const code = sku.properties.hs_sku;
if (!code) return '';
const parts = code.split('-');
return parts.length > 1 ? `${parts[0]}-${parts[1].substring(0, 2)}` : '';
});
const primary = sku_id.map(sku => {
const code = sku.properties.hs_sku;
if (!code) return '';
return code.includes('-') ? code.split('-', 3)[2].substring(0, 1) : '';
});
const secondary = sku_id.map(sku => {
const code = sku.properties.hs_sku;
if (!code) return '';
return code.includes('-') ? code.split('-', 3)[2].substring(1, 2) : '';
});
const contactResponse = await axios.get('https://api.hubapi.com/crm/v4/objects/deals/' + deal_id + '/associations/contacts', token_hubspot);
const contact_id = contactResponse.data.results;
const contact = contact_id.length > 0 ? contact_id[0].toObjectId : '';
const joinedProduct = product.join(';');
const joinedPrimary = primary.join(';');
const joinedSecondary = secondary.join(';');
console.log(contact);
console.log(joinedProduct);
console.log(joinedPrimary);
console.log(joinedSecondary);
var config_get_contact = {
method: 'get',
url: 'https://api.hubapi.com/crm/v3/objects/contacts/' + contact + '?properties=persona_shop_product,persona_shop_color_primary,persona_shop_color_secondary',
headers: token_hubspot.headers,
};
const response_get_contact = await axios(config_get_contact);
console.log(JSON.stringify(response_get_contact.data));
let product_string, primary_string, secondary_string;
if (response_get_contact.data.properties.persona_shop_product == null) {
console.log("EMPTY / New: " + joinedProduct)
product_string = joinedProduct;
} else {
var product_new = joinedProduct;
console.log("New: " + product_new);
var product_comma = response_get_contact.data.properties.persona_shop_product;
var product_current = product_comma.split(';');
console.log("Current: " + product_current);
product_current.push(product_new);
product_string = product_current.join(';');
console.log(product_string);
}
if (response_get_contact.data.properties.persona_shop_color_primary == null) {
console.log("EMPTY / New: " + joinedPrimary)
primary_string = joinedPrimary;
} else {
var primary_new = joinedPrimary;
console.log("New: " + primary_new);
var primary_comma = response_get_contact.data.properties.persona_shop_color_primary;
var primary_current = primary_comma.split(';');
console.log("Current: " + primary_current);
primary_current.push(primary_new);
primary_string = primary_current.join(';');
console.log(primary_string);
}
if (response_get_contact.data.properties.persona_shop_color_secondary == null) {
console.log("EMPTY / New: " + joinedSecondary)
secondary_string = joinedSecondary;
} else {
var secondary_new = joinedSecondary;
console.log("New: " + secondary_new);
var secondary_comma = response_get_contact.data.properties.persona_shop_color_secondary;
var secondary_current = secondary_comma.split(';');
console.log("Current: " + secondary_current);
secondary_current.push(secondary_new);
secondary_string = secondary_current.join(';');
console.log(secondary_string);
}
// Patch Contact by ID
var data_patch = JSON.stringify({
"properties": {
"persona_shop_product": product_string,
"persona_shop_color_primary": primary_string,
"persona_shop_color_secondary": secondary_string
}
});
console.log(data_patch);
var config_patch_contact = {
method: 'patch',
url: 'https://api.hubapi.com/crm/v3/objects/contacts/' + contact,
headers: token_hubspot.headers,
data: data_patch
};
const response_patch = await axios(config_patch_contact);
console.log(JSON.stringify(response_patch.data));
} catch (error) {
console.error(error);
return {
outputFields: {
error: error.message
}
};
}
}
(async function () {
for (const deal_id of deal_ids) {
await processEvent(deal_id);
}
})();

As the deals have no owner yet we have to give them the "Country Owner". The Owner ID has to be added to the script.
After the first run we do a second run for the Hydrosonic products.
const axios = require('axios');
const token_hubspot = {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer XXX',
},
};
const deal_ids = [];
async function processEvent(deal_id) {
try {
const [lineitems_get, contact_get] = await Promise.all([
axios.get('https://api.hubapi.com/crm/v4/objects/deals/' + deal_id + '/associations/line_items?limit=50',token_hubspot),
axios.get('https://api.hubapi.com/crm/v4/objects/deals/' + deal_id + '/associations/contacts?limit=10',token_hubspot),
]);
const lineitems_result = lineitems_get.data.results;
const contact_id = contact_get.data.results[0].toObjectId;
const [date_get] = await Promise.all([
axios.get('https://api.hubapi.com/crm/v4/objects/deal/' + deal_id + '/',token_hubspot),
]);
const purchase_date = date_get.data.properties.createdate;
console.log(purchase_date);
const [owner_get] = await Promise.all([
axios.get('https://api.hubapi.com/crm/v4/objects/contact/'+contact_id+'/?properties=hubspot_owner_id',token_hubspot),
]);
const owner_id = owner_get.data.properties.hubspot_owner_id;
console.log(owner_id);
const formatDate = (dateString) => {
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
for (const lineitem of lineitems_result) {
const lineitem_id = lineitem.toObjectId;
const product_get = await axios.get(`https://api.hubapi.com/crm/v3/objects/line_items/${lineitem_id}?properties=name,hs_sku`,token_hubspot);
const { properties } = product_get.data;
const product_id = properties.hs_object_id;
const product_name = properties.name;
const product_date = formatDate(purchase_date);
const product_sku = properties.hs_sku;
const product_type =
product_sku === '30-11015-050' ||
product_sku === '30-12015-050' ||
product_sku === '30-12015-051' ||
product_sku === '30-13015-990'
? 'toothbrush'
: 'brushhead';
console.log(product_id, product_name, product_sku, product_date);
if (
[
'30-13015-990', // Black Is White Hydrosonic
'30-11015-050', // Hydrosonic Pro
'30-12015-050', // Hydrosonic Easy
'30-12025-051', // Hydrosonic Easy
'30-21022-000', // Power Duo
'30-21032-000', // Sensitive Duo
'30-21042-000', // Single Duo
'30-22022-000', // CHS 200 Sensitive Duo
'30-22032-000', // CHS 300 Power Duo
'30-23022-990', // BIW Carbon Duo
'30-23012-990', // BIW 259 Smart Duo
].includes(product_sku)
) {
const customcard_data = JSON.stringify({
properties: {
name: product_name,
sku: product_sku,
date: product_date,
type: product_type,
lineitem_id: product_id,
hubspot_owner_id: "1002208226"
},
associations: [
{
to: {
id: contact_id
},
types: [
{
associationCategory: 'USER_DEFINED',
associationTypeId: 17,
},
],
},
{
to: {
id: deal_id
},
types: [
{
associationCategory: 'USER_DEFINED',
associationTypeId: 19,
},
],
},
],
});
try {
const customcard_response = await axios.post('https://api.hubapi.com/crm/v3/objects/hydrosonic/',customcard_data,token_hubspot);
const customcard_total = customcard_response.data;
console.log(customcard_total);
} catch (error) {
console.log(error);
}
}
}
} catch (error) {
console.log(error);
}
}
(async function () {
for (const deal_id of deal_ids) {
await processEvent(deal_id);
}
})();
As the enrichment takes a few days a delta enrichment has to be done to capture all of them.
Continues Enrichment
For the continues enrichment we're using the HubSpot workflows together with Pipedream. Copy a current Workflow "Deal New // Line Items + Owner // XX" and do the necessary changes. The Pipedream URL can be found if you clone a current Workflow in Pipedream. HubSpot and Pipedream go hand in hand, you can not finish one before you did the other.


If you activate the Workflow make sure you choose the option: "No, only enroll..." as we did already enroll all the other deals manually beforehand.
The Pipedream Username is: webmaster@curaden.com. Make sure after you copy the workflows in Pipedream to add the Contact Owner.


Don't forget to do a delta migration since you started until the moment you're done and the continues integration starts.
The last step is to align all the Contacts and Deals to the necessary owner. The easiest way to do so is by the List view with a filter.

