UNPKG

n8n-nodes-close-crm

Version:

N8N community node for Close CRM integration with comprehensive lead, opportunity, task, note, call management, and enhanced triggers for workflow automation

848 lines (847 loc) 154 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Close = void 0; const n8n_workflow_1 = require("n8n-workflow"); const GenericFunctions_1 = require("./GenericFunctions"); const LeadDescription_1 = require("./descriptions/LeadDescription"); const LeadStatusDescription_1 = require("./descriptions/LeadStatusDescription"); const OpportunityDescription_1 = require("./descriptions/OpportunityDescription"); const OpportunityStatusDescription_1 = require("./descriptions/OpportunityStatusDescription"); const TaskDescription_1 = require("./descriptions/TaskDescription"); const NoteDescription_1 = require("./descriptions/NoteDescription"); const CallDescription_1 = require("./descriptions/CallDescription"); const EmailDescription_1 = require("./descriptions/EmailDescription"); const MeetingDescription_1 = require("./descriptions/MeetingDescription"); const SmsDescription_1 = require("./descriptions/SmsDescription"); const CustomActivityDescription_1 = require("./descriptions/CustomActivityDescription"); const ContactDescription_1 = require("./descriptions/ContactDescription"); const SequenceDescription_1 = require("./descriptions/SequenceDescription"); const BulkActionDescription_1 = require("./descriptions/BulkActionDescription"); const ExportDescription_1 = require("./descriptions/ExportDescription"); const FieldEnrichmentDescription_1 = require("./descriptions/FieldEnrichmentDescription"); const CustomFieldsDescription_1 = require("./descriptions/CustomFieldsDescription"); function removeNullishValues(payload) { return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== null && value !== undefined)); } function hasValue(value) { return value !== null && value !== undefined; } function parseJsonParam(value, fieldName) { if (value === undefined || value === null || value === '') { return undefined; } if (typeof value === 'object') { return value; } if (typeof value === 'string') { const trimmed = value.trim(); if (!trimmed) { return undefined; } try { return JSON.parse(trimmed); } catch (error) { throw new Error(`Invalid JSON in field "${fieldName}": ${error.message}`); } } return value; } class Close { constructor() { this.description = { displayName: 'Close CRM', name: 'close', icon: 'file:close.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Consume Close CRM API', defaults: { name: 'Close CRM', }, inputs: [{ type: 'main' }], outputs: [{ type: 'main' }], credentials: [ { name: 'closeApi', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Lead', value: 'lead', }, { name: 'Lead Status', value: 'leadStatus', }, { name: 'Contact', value: 'contact', }, { name: 'Opportunity', value: 'opportunity', }, { name: 'Opportunity Status', value: 'opportunityStatus', }, { name: 'Task', value: 'task', }, { name: 'Note', value: 'note', }, { name: 'Call', value: 'call', }, { name: 'Email', value: 'email', }, { name: 'Meeting', value: 'meeting', }, { name: 'SMS', value: 'sms', }, { name: 'Custom Activity', value: 'customActivity', }, { name: 'Sequence (Automation & Bulk Actions)', value: 'sequence', }, { name: 'Bulk Action (Automation & Bulk Actions)', value: 'bulkAction', }, { name: 'Export (Automation & Bulk Actions)', value: 'export', }, { name: 'Field Enrichment (Automation & Bulk Actions)', value: 'fieldEnrichment', }, ], default: 'lead', }, ...LeadDescription_1.leadOperations, ...LeadDescription_1.leadFields, ...LeadStatusDescription_1.leadStatusOperations, ...LeadStatusDescription_1.leadStatusFields, ...ContactDescription_1.contactOperations, ...ContactDescription_1.contactFields, ...OpportunityDescription_1.opportunityOperations, ...OpportunityDescription_1.opportunityFields, ...OpportunityStatusDescription_1.opportunityStatusOperations, ...OpportunityStatusDescription_1.opportunityStatusFields, ...TaskDescription_1.taskOperations, ...TaskDescription_1.taskFields, ...NoteDescription_1.noteOperations, ...NoteDescription_1.noteFields, ...CallDescription_1.callOperations, ...CallDescription_1.callFields, ...EmailDescription_1.emailOperations, ...EmailDescription_1.emailFields, ...MeetingDescription_1.meetingOperations, ...MeetingDescription_1.meetingFields, ...SmsDescription_1.smsOperations, ...SmsDescription_1.smsFields, ...CustomActivityDescription_1.customActivityOperations, ...CustomActivityDescription_1.customActivityFields, ...SequenceDescription_1.sequenceOperations, ...SequenceDescription_1.sequenceFields, ...BulkActionDescription_1.bulkActionOperations, ...BulkActionDescription_1.bulkActionFields, ...ExportDescription_1.exportOperations, ...ExportDescription_1.exportFields, ...FieldEnrichmentDescription_1.fieldEnrichmentOperations, ...FieldEnrichmentDescription_1.fieldEnrichmentFields, ...CustomFieldsDescription_1.customFieldsCreateSections, ...CustomFieldsDescription_1.customFieldsUpdateSections, ...CustomFieldsDescription_1.customActivityCustomFieldsCreateSections, ...CustomFieldsDescription_1.customActivityCustomFieldsUpdateSections, ], }; this.methods = { loadOptions: { async getLeadStatuses() { const returnData = []; const statuses = await GenericFunctions_1.closeApiRequest.call(this, 'GET', '/status/lead/'); for (const status of statuses.data) { returnData.push({ name: status.label, value: status.id, }); } return returnData; }, async getOpportunityStatuses() { const returnData = []; const statuses = await GenericFunctions_1.closeApiRequest.call(this, 'GET', '/status/opportunity/'); for (const status of statuses.data) { returnData.push({ name: status.label, value: status.id, }); } return returnData; }, async getSmartViews() { const returnData = []; const views = await GenericFunctions_1.closeApiRequest.call(this, 'GET', '/saved_search/'); for (const view of views.data) { returnData.push({ name: view.name, value: view.id, }); } return returnData; }, async getUsers() { const returnData = []; const users = await GenericFunctions_1.closeApiRequest.call(this, 'GET', '/user/'); for (const user of users.data) { returnData.push({ name: `${user.first_name} ${user.last_name} (${user.email})`, value: user.id, }); } return returnData; }, // New Custom Fields Load Methods async getSingleChoiceFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getChoiceSingleFields(this); }, async getMultipleChoiceFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getChoiceMultipleFields(this); }, async getTextFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getTextFields(this); }, async getNumberFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getNumberFields(this); }, async getDateFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getDateFields(this); }, async getDateTimeFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getDateFields(this); }, async getSingleUserFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getUserSingleFields(this); }, async getMultipleUserFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getUserMultipleFields(this); }, async getSingleContactFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactSingleFields(this); }, async getMultipleContactFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactMultipleFields(this); }, // New dynamic method for field type filtering async getFieldsByType() { return CustomFieldsDescription_1.customFieldsLoadMethods.getFieldsByType(this); }, async getFieldChoices() { return CustomFieldsDescription_1.customFieldsLoadMethods.getFieldChoices(this); }, async getAllChoiceValues() { return CustomFieldsDescription_1.customFieldsLoadMethods.getAllChoiceValues(this); }, async getCachedUsers() { return CustomFieldsDescription_1.customFieldsLoadMethods.getCachedUsers(this); }, // Contact Custom Fields Load Methods async getContactTextFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactTextFields(this); }, async getContactNumberFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactNumberFields(this); }, async getContactDateFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactDateFields(this); }, async getContactSingleChoiceFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactSingleChoiceFields(this); }, async getContactMultipleChoiceFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactMultipleChoiceFields(this); }, async getContactAllChoiceValues() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactAllChoiceValues(this); }, async getContactSingleUserFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactSingleUserFields(this); }, async getContactMultipleUserFields() { return CustomFieldsDescription_1.customFieldsLoadMethods.getContactMultipleUserFields(this); }, async getCustomActivityTypes() { const returnData = []; const types = await GenericFunctions_1.closeApiRequest.call(this, 'GET', '/custom_activity/'); for (const type of types.data) { returnData.push({ name: type.name, value: type.id, }); } return returnData; }, // Custom Activity Custom Fields Load Methods async getCustomActivityTextFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivityTextFields(this); }, async getCustomActivityRichTextFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivityRichTextFields(this); }, async getCustomActivityNumberFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivityNumberFields(this); }, async getCustomActivityDateFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivityDateFields(this); }, async getCustomActivitySingleChoiceFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivitySingleChoiceFields(this); }, async getCustomActivityMultipleChoiceFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivityMultipleChoiceFields(this); }, async getCustomActivityAllChoiceValues() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivityAllChoiceValues(this); }, async getCustomActivitySingleUserFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivitySingleUserFields(this); }, async getCustomActivityMultipleUserFields() { return CustomFieldsDescription_1.customActivityCustomFieldsLoadMethods.getCustomActivityMultipleUserFields(this); }, }, }; } async execute() { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; const items = this.getInputData(); const returnData = []; const length = items.length; const qs = {}; let responseData; const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); for (let i = 0; i < length; i++) { try { // Input validation if (!resource) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Resource is required'); } if (!operation) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Operation is required'); } if (resource === 'lead') { if (operation === 'create') { const name = this.getNodeParameter('name', i); if (!name) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Lead name is required for create operation'); } const body = { name, }; // Add additional fields if provided const additionalFields = this.getNodeParameter('additionalFields', i); if (hasValue(additionalFields.description) && additionalFields.description !== '') { body.description = additionalFields.description; } if (hasValue(additionalFields.statusId) && additionalFields.statusId !== '') { body.status_id = additionalFields.statusId; } if (hasValue(additionalFields.userId) && additionalFields.userId !== '') { body.user_id = additionalFields.userId; } if (hasValue(additionalFields.url) && additionalFields.url !== '') { body.url = additionalFields.url; } // Add contacts if provided const contacts = this.getNodeParameter('contactsUi', i, {}); if ((_a = contacts.contactsValues) === null || _a === void 0 ? void 0 : _a.length) { body.contacts = await Promise.all(contacts.contactsValues.map(async (contact) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; const contactObj = {}; if (contact.name) contactObj.name = contact.name; if (contact.email) contactObj.emails = [{ type: 'office', email: contact.email }]; // Handle phones array with both office and mobile numbers const phones = []; if (contact.phone) { phones.push({ type: 'office', phone: contact.phone }); } if (contact.mobilePhone) { phones.push({ type: 'mobile', phone: contact.mobilePhone }); } if (phones.length > 0) { contactObj.phones = phones; } if (contact.title) contactObj.title = contact.title; // Add custom fields for contact if provided const hasCustomFields = ((_b = (_a = contact.contactCustomTextFields) === null || _a === void 0 ? void 0 : _a.textFields) === null || _b === void 0 ? void 0 : _b.length) || ((_d = (_c = contact.contactCustomNumberFields) === null || _c === void 0 ? void 0 : _c.numberFields) === null || _d === void 0 ? void 0 : _d.length) || ((_f = (_e = contact.contactCustomDateFields) === null || _e === void 0 ? void 0 : _e.dateFields) === null || _f === void 0 ? void 0 : _f.length) || ((_h = (_g = contact.contactCustomChoiceSingleFields) === null || _g === void 0 ? void 0 : _g.choiceSingleFields) === null || _h === void 0 ? void 0 : _h.length) || ((_k = (_j = contact.contactCustomChoiceMultipleFields) === null || _j === void 0 ? void 0 : _j.choiceMultipleFields) === null || _k === void 0 ? void 0 : _k.length) || ((_m = (_l = contact.contactCustomUserSingleFields) === null || _l === void 0 ? void 0 : _l.userSingleFields) === null || _m === void 0 ? void 0 : _m.length) || ((_p = (_o = contact.contactCustomUserMultipleFields) === null || _o === void 0 ? void 0 : _o.userMultipleFields) === null || _p === void 0 ? void 0 : _p.length); if (hasCustomFields) { try { const contactFields = await CustomFieldsDescription_1.customFieldsLoadMethods.getCachedContactCustomFields(this); const contactCustomFieldsPayload = (0, CustomFieldsDescription_1.constructContactCustomFieldsPayload)(contact, contactFields); Object.assign(contactObj, contactCustomFieldsPayload); } catch (error) { console.error('Error processing contact custom fields:', error); } } return removeNullishValues(contactObj); })); } // Add address if provided const address = this.getNodeParameter('addressUi', i, {}); if (address && (address.street || address.city || address.state || address.zipcode || address.country)) { const addressesArray = []; const addressObj = { type: 'office' }; if (address.street) addressObj.address_1 = address.street; if (address.city) addressObj.city = address.city; if (address.state) addressObj.state = address.state; if (address.zipcode) addressObj.zipcode = address.zipcode; if (address.country) addressObj.country = address.country; addressesArray.push(removeNullishValues(addressObj)); body.addresses = addressesArray; } // Add custom fields if provided (backwards compatibility) const customFields = this.getNodeParameter('customFieldsUi', i, {}); if ((_b = customFields.customFieldsValues) === null || _b === void 0 ? void 0 : _b.length) { for (const field of customFields.customFieldsValues) { // Parse the encoded field ID and type const [actualFieldId, fieldType] = field.fieldId.split('|'); // Use the appropriate value based on field type const value = fieldType === 'choices' ? field.fieldValueChoice : field.fieldValue; if (value) { body[`custom.${actualFieldId}`] = value; } } } // Add custom fields from the new structure try { // Collect custom fields data from the new dynamic structure const customFieldsData = this.getNodeParameter('customFields', i, {}); // If we have custom fields, process them if (customFieldsData && Object.keys(customFieldsData).length > 0) { const fields = await CustomFieldsDescription_1.customFieldsLoadMethods.getCachedCustomFields(this); const customFieldsPayload = (0, CustomFieldsDescription_1.constructCustomFieldsPayload)({ customFields: customFieldsData }, fields); // Merge the custom fields payload into the body Object.assign(body, customFieldsPayload); } } catch (error) { console.error('Error processing custom fields:', error); // Continue with execution - don't fail the entire operation } responseData = await GenericFunctions_1.closeApiRequest.call(this, 'POST', '/lead/', body); } if (operation === 'delete') { const leadId = this.getNodeParameter('leadId', i); if (!leadId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Lead ID is required for delete operation'); } responseData = await GenericFunctions_1.closeApiRequest.call(this, 'DELETE', `/lead/${leadId}/`); } if (operation === 'find') { const leadId = this.getNodeParameter('leadId', i); const companyName = this.getNodeParameter('companyName', i); const companyUrl = this.getNodeParameter('companyUrl', i); const email = this.getNodeParameter('email', i); const phone = this.getNodeParameter('phone', i); const statusId = this.getNodeParameter('statusId', i); const returnAll = this.getNodeParameter('returnAll', i); // If Lead ID is provided, get specific lead if (leadId) { responseData = await GenericFunctions_1.closeApiRequest.call(this, 'GET', `/lead/${leadId}/`); } else { // Build advanced filter query for precise field matching const filterQueries = []; // Always specify we're looking for leads filterQueries.push({ type: 'object_type', object_type: 'lead', }); // Filter by status_id (Status Name) if (statusId) { filterQueries.push({ type: 'field_condition', field: { type: 'regular_field', object_type: 'lead', field_name: 'status_id', }, condition: { type: 'term', values: [statusId], }, }); } // Filter by display_name (Company Name) if (companyName) { filterQueries.push({ type: 'field_condition', field: { type: 'regular_field', object_type: 'lead', field_name: 'display_name', }, condition: { type: 'text', mode: 'full_words', value: companyName, }, }); } // Filter by url (Company URL) if (companyUrl) { filterQueries.push({ type: 'field_condition', field: { type: 'regular_field', object_type: 'lead', field_name: 'url', }, condition: { type: 'text', mode: 'full_words', value: companyUrl, }, }); } // Filter by email (Contact Email) - nested relation: Lead -> Contact -> Email if (email) { filterQueries.push({ type: 'has_related', this_object_type: 'lead', related_object_type: 'contact', related_query: { type: 'has_related', this_object_type: 'contact', related_object_type: 'contact_email', related_query: { type: 'field_condition', field: { type: 'regular_field', object_type: 'contact_email', field_name: 'email', }, condition: { type: 'text', value: email, mode: 'phrase', }, }, }, }); } // Filter by phone (Contact Phone) - nested relation: Lead -> Contact -> Phone if (phone) { filterQueries.push({ type: 'has_related', this_object_type: 'lead', related_object_type: 'contact', related_query: { type: 'has_related', this_object_type: 'contact', related_object_type: 'contact_phone', related_query: { type: 'field_condition', field: { type: 'regular_field', object_type: 'contact_phone', field_name: 'phone', }, condition: { type: 'text', value: phone, mode: 'phrase', }, }, }, }); } // If no filters provided, use standard API to get all leads if (filterQueries.length === 1) { const searchQs = {}; if (returnAll) { responseData = await GenericFunctions_1.closeApiRequestAllItems.call(this, 'data', 'GET', '/lead/', {}, searchQs); } else { searchQs._limit = this.getNodeParameter('limit', i); responseData = await GenericFunctions_1.closeApiRequest.call(this, 'GET', '/lead/', {}, searchQs); responseData = responseData.data; } } else { // Build the final query for Advanced Filtering API const searchBody = { query: { type: 'and', queries: filterQueries, }, // Request all fields to get complete lead data _fields: { lead: [ 'id', 'display_name', 'name', 'description', 'url', 'status_id', 'status_label', 'contacts', 'addresses', 'created_by', 'date_created', 'date_updated', 'organization_id', 'tasks', 'opportunities', ], }, }; // Add pagination - Advanced Filtering API uses results_limit if (!returnAll) { searchBody.results_limit = this.getNodeParameter('limit', i); } // Use Advanced Filtering API if (returnAll) { responseData = await GenericFunctions_1.closeApiRequestAllItems.call(this, 'data', 'POST', '/data/search/', searchBody, {}); } else { responseData = await GenericFunctions_1.closeApiRequest.call(this, 'POST', '/data/search/', searchBody); responseData = responseData.data; } } } } if (operation === 'merge') { const sourceLeadId = this.getNodeParameter('sourceLeadId', i); const destinationLeadId = this.getNodeParameter('destinationLeadId', i); if (!sourceLeadId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Source Lead ID is required for merge operation'); } if (!destinationLeadId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Destination Lead ID is required for merge operation'); } const body = { source: sourceLeadId, destination: destinationLeadId, }; responseData = await GenericFunctions_1.closeApiRequest.call(this, 'POST', '/lead/merge/', body); } if (operation === 'update') { const leadId = this.getNodeParameter('leadId', i); if (!leadId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Lead ID is required for update operation'); } const updateFields = this.getNodeParameter('updateFields', i); const body = {}; if (hasValue(updateFields.name) && updateFields.name !== '') { body.name = updateFields.name; } if (hasValue(updateFields.description) && updateFields.description !== '') { body.description = updateFields.description; } if (hasValue(updateFields.statusId) && updateFields.statusId !== '') { body.status_id = updateFields.statusId; } if (hasValue(updateFields.userId) && updateFields.userId !== '') { body.user_id = updateFields.userId; } if (hasValue(updateFields.url) && updateFields.url !== '') { body.url = updateFields.url; } // Add contacts if provided const contacts = this.getNodeParameter('contactsUi', i, {}); if ((_c = contacts.contactsValues) === null || _c === void 0 ? void 0 : _c.length) { // Fetch the existing lead to get current contacts const existingLead = await GenericFunctions_1.closeApiRequest.call(this, 'GET', `/lead/${leadId}/`); const existingContacts = existingLead.contacts || []; // Map contacts by position: first contact updates first existing contact, etc. body.contacts = await Promise.all(contacts.contactsValues.map(async (contact, index) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _r; const contactObj = {}; // If there's an existing contact at this position, include its ID for update if ((_a = existingContacts[index]) === null || _a === void 0 ? void 0 : _a.id) { contactObj.id = existingContacts[index].id; } if (contact.name) contactObj.name = contact.name; if (contact.email) contactObj.emails = [{ type: 'office', email: contact.email }]; // Handle phones array with both office and mobile numbers const phones = []; if (contact.phone) { phones.push({ type: 'office', phone: contact.phone }); } if (contact.mobilePhone) { phones.push({ type: 'mobile', phone: contact.mobilePhone }); } if (phones.length > 0) { contactObj.phones = phones; } if (contact.title) contactObj.title = contact.title; // Add custom fields for contact if provided const hasCustomFields = ((_c = (_b = contact.contactCustomTextFields) === null || _b === void 0 ? void 0 : _b.textFields) === null || _c === void 0 ? void 0 : _c.length) || ((_e = (_d = contact.contactCustomNumberFields) === null || _d === void 0 ? void 0 : _d.numberFields) === null || _e === void 0 ? void 0 : _e.length) || ((_g = (_f = contact.contactCustomDateFields) === null || _f === void 0 ? void 0 : _f.dateFields) === null || _g === void 0 ? void 0 : _g.length) || ((_j = (_h = contact.contactCustomChoiceSingleFields) === null || _h === void 0 ? void 0 : _h.choiceSingleFields) === null || _j === void 0 ? void 0 : _j.length) || ((_l = (_k = contact.contactCustomChoiceMultipleFields) === null || _k === void 0 ? void 0 : _k.choiceMultipleFields) === null || _l === void 0 ? void 0 : _l.length) || ((_o = (_m = contact.contactCustomUserSingleFields) === null || _m === void 0 ? void 0 : _m.userSingleFields) === null || _o === void 0 ? void 0 : _o.length) || ((_r = (_p = contact.contactCustomUserMultipleFields) === null || _p === void 0 ? void 0 : _p.userMultipleFields) === null || _r === void 0 ? void 0 : _r.length); if (hasCustomFields) { try { const contactFields = await CustomFieldsDescription_1.customFieldsLoadMethods.getCachedContactCustomFields(this); const contactCustomFieldsPayload = (0, CustomFieldsDescription_1.constructContactCustomFieldsPayload)(contact, contactFields); Object.assign(contactObj, contactCustomFieldsPayload); } catch (error) { console.error('Error processing contact custom fields:', error); } } return removeNullishValues(contactObj); })); } // Add address if provided const address = this.getNodeParameter('addressUi', i, {}); if (address && (address.street || address.city || address.state || address.zipcode || address.country)) { const addressesArray = []; const addressObj = { type: 'office' }; if (address.street) addressObj.address_1 = address.street; if (address.city) addressObj.city = address.city; if (address.state) addressObj.state = address.state; if (address.zipcode) addressObj.zipcode = address.zipcode; if (address.country) addressObj.country = address.country; addressesArray.push(removeNullishValues(addressObj)); body.addresses = addressesArray; } // Add custom fields if provided (backwards compatibility) const customFields = this.getNodeParameter('customFieldsUi', i, {}); if ((_d = customFields.customFieldsValues) === null || _d === void 0 ? void 0 : _d.length) { for (const field of customFields.customFieldsValues) { // Parse the encoded field ID and type const [actualFieldId, fieldType] = field.fieldId.split('|'); // Use the appropriate value based on field type const value = fieldType === 'choices' ? field.fieldValueChoice : field.fieldValue; if (value) { body[`custom.${actualFieldId}`] = value; } } } // Add custom fields from the new structure try { // Collect custom fields data from the new dynamic structure const customFieldsData = this.getNodeParameter('customFields', i, {}); // If we have custom fields, process them if (customFieldsData && Object.keys(customFieldsData).length > 0) { const fields = await CustomFieldsDescription_1.customFieldsLoadMethods.getCachedCustomFields(this); const customFieldsPayload = (0, CustomFieldsDescription_1.constructCustomFieldsPayload)({ customFields: customFieldsData }, fields); // Merge the custom fields payload into the body Object.assign(body, customFieldsPayload); } } catch (error) { console.error('Error processing custom fields:', error); // Continue with execution - don't fail the entire operation } responseData = await GenericFunctions_1.closeApiRequest.call(this, 'PUT', `/lead/${leadId}/`, body); } } if (resource === 'leadStatus') { if (operation === 'list') { responseData = await GenericFunctions_1.closeApiRequest.call(this, 'GET', '/status/lead/'); responseData = responseData.data || responseData; } if (operation === 'create') { const label = this.getNodeParameter('label', i); if (!label) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Label is required for lead status creation'); } const body = { label, }; // Add additional fields if provided const additionalFields = this.getNodeParameter('additionalFields', i); if (additionalFields.type) { body.type = additionalFields.type; } responseData = await GenericFunctions_1.closeApiRequest.call(this, 'POST', '/status/lead/', body); } if (operation === 'update') { const statusId = this.getNodeParameter('statusId', i); const label = this.getNodeParameter('label', i); if (!statusId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Status ID is required for update operation'); } if (!label) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Label is required for update operation'); } const body = { label, }; // Add additional fields if provided const additionalFields = this.getNodeParameter('additionalFields', i); if (additionalFields.type) { body.type = additionalFields.type; } responseData = await GenericFunctions_1.closeApiRequest.call(this, 'PUT', `/status/lead/${statusId}/`, body); } if (operation === 'delete') { const statusId = this.getNodeParameter('statusId', i); if (!statusId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Status ID is required for delete operation'); }