@traien/n8n-nodes-espocrm
Version:
n8n integration with EspoCRM
536 lines • 24.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EspoCRM = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const account_operations_1 = require("./operations/account/account.operations");
const contact_operations_1 = require("./operations/contact/contact.operations");
const lead_operations_1 = require("./operations/lead/lead.operations");
const dynamic_operations_1 = require("./operations/dynamic/dynamic.operations");
const meeting_operations_1 = require("./operations/meeting/meeting.operations");
const task_operations_1 = require("./operations/task/task.operations");
const call_operations_1 = require("./operations/call/call.operations");
const opportunity_operations_1 = require("./operations/opportunity/opportunity.operations");
const attachment_operations_1 = require("./operations/attachment/attachment.operations");
const document_operations_1 = require("./operations/document/document.operations");
const case_operations_1 = require("./operations/case/case.operations");
const HandlerFactory_1 = require("./handlers/HandlerFactory");
const MetadataService_1 = require("./services/MetadataService");
const GenericFunctions_1 = require("./GenericFunctions");
class EspoCRM {
constructor() {
this.description = {
displayName: 'EspoCRM',
name: 'espoCrm',
icon: 'file:espocrm.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Interact with EspoCRM API',
defaults: {
name: 'EspoCRM',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'espoCRMApi',
required: true,
},
],
documentationUrl: 'https://docs.espocrm.com/development/api/',
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Account',
value: 'account',
},
{
name: 'Contact',
value: 'contact',
},
{
name: 'Custom Entity',
value: 'customEntity',
},
{
name: 'Dynamic',
value: 'dynamic',
},
{
name: 'Lead',
value: 'lead',
},
{
name: 'Meeting',
value: 'meeting',
},
{
name: 'Task',
value: 'task',
},
{
name: 'Call',
value: 'call',
},
{
name: 'Opportunity',
value: 'opportunity',
},
{
name: 'Case',
value: 'case',
},
{
name: 'Attachment',
value: 'attachment',
},
{
name: 'Document',
value: 'document',
},
],
default: 'contact',
},
{
displayName: 'Entity Type Name or ID',
name: 'entityType',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getEntityTypes',
},
default: '',
required: true,
displayOptions: {
show: {
resource: ['customEntity'],
},
},
description: 'Type of entity to interact with (e.g., Opportunity, Case, Product). Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
...account_operations_1.accountOperations,
...account_operations_1.accountFields,
...contact_operations_1.contactOperations,
...contact_operations_1.contactFields,
...lead_operations_1.leadOperations,
...lead_operations_1.leadFields,
...meeting_operations_1.meetingOperations,
...meeting_operations_1.meetingFields,
...task_operations_1.taskOperations,
...task_operations_1.taskFields,
...call_operations_1.callOperations,
...call_operations_1.callFields,
...opportunity_operations_1.opportunityOperations,
...opportunity_operations_1.opportunityFields,
...case_operations_1.caseOperations,
...case_operations_1.caseFields,
...attachment_operations_1.attachmentOperations,
...attachment_operations_1.attachmentFields,
...document_operations_1.documentOperations,
...document_operations_1.documentFields,
...dynamic_operations_1.dynamicOperations,
...dynamic_operations_1.dynamicFields,
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['customEntity'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new record',
action: 'Create a record',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a record',
action: 'Delete a record',
},
{
name: 'Get',
value: 'get',
description: 'Get a single record',
action: 'Get a record',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get many records',
action: 'Get many records',
},
{
name: 'Update',
value: 'update',
description: 'Update a record',
action: 'Update a record',
},
],
default: 'create',
},
{
displayName: 'Data',
name: 'data',
type: 'json',
default: '',
required: true,
displayOptions: {
show: {
resource: ['customEntity'],
operation: ['create'],
},
},
description: 'Data of the record to create',
},
{
displayName: 'Record ID',
name: 'id',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['customEntity'],
operation: ['get', 'update', 'delete'],
},
},
description: 'ID of the record',
},
{
displayName: 'Data',
name: 'data',
type: 'json',
default: '',
required: true,
displayOptions: {
show: {
resource: ['customEntity'],
operation: ['update'],
},
},
description: 'Data to update the record with',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['customEntity'],
operation: ['getAll'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['customEntity'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Filter Options',
name: 'filterOptions',
type: 'collection',
placeholder: 'Add Filter Option',
default: {},
displayOptions: {
show: {
resource: ['customEntity'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Boolean Filter List',
name: 'boolFilterList',
type: 'string',
default: '',
placeholder: 'onlyMy,followed',
description: 'Comma-separated list of predefined boolean filters',
},
{
displayName: 'Offset',
name: 'offset',
type: 'number',
default: 0,
description: 'Number of results to skip (for pagination)',
},
{
displayName: 'Order By',
name: 'orderBy',
type: 'string',
default: '',
placeholder: 'createdAt',
description: 'Field to sort results by',
},
{
displayName: 'Order Direction',
name: 'order',
type: 'options',
options: [
{
name: 'Ascending',
value: 'asc',
},
{
name: 'Descending',
value: 'desc',
},
],
default: 'asc',
description: 'Direction to sort results by',
},
{
displayName: 'Primary Filter',
name: 'primaryFilter',
type: 'string',
default: '',
description: 'Context-specific base filter to apply',
},
{
displayName: 'Select Fields',
name: 'select',
type: 'string',
default: '',
placeholder: 'id,name',
description: 'Comma-separated list of fields to return',
},
{
displayName: 'Where (Filter Conditions)',
name: 'where',
type: 'json',
default: '[]',
typeOptions: {
alwaysParseJson: true,
},
description: 'Filter conditions for the query as defined in the EspoCRM API',
},
{
displayName: 'Skip Total Count',
name: 'skipTotalCount',
type: 'boolean',
default: false,
description: 'Whether to skip calculating total count for large datasets to improve performance',
},
],
},
],
};
this.methods = {
loadOptions: {
async getEntityTypes() {
try {
const entityTypes = await MetadataService_1.MetadataService.getEntityList.call(this, this);
return entityTypes.map(entityType => ({
name: entityType,
value: entityType,
})).sort((a, b) => a.name.localeCompare(b.name));
}
catch (error) {
console.error('Error loading entity types:', error);
return [{ name: 'Error Loading Entity Types', value: '' }];
}
},
async getEntityFields() {
const entityType = this.getCurrentNodeParameter('entityType');
if (!entityType) {
return [{ name: 'Please Select an Entity Type First', value: '' }];
}
try {
const fieldDefs = await MetadataService_1.MetadataService.getFieldDefs.call(this, this, entityType);
return Object.keys(fieldDefs).map(fieldName => {
const fieldDef = fieldDefs[fieldName];
const label = fieldDef.label ? `${fieldDef.label} (${fieldName})` : fieldName;
return {
name: label,
value: fieldName,
};
}).sort((a, b) => a.name.localeCompare(b.name));
}
catch (error) {
console.error(`Error loading fields for entity type ${entityType}:`, error);
return [{ name: `Error loading fields for ${entityType}`, value: '' }];
}
},
async getEnumOptions() {
const entityType = this.getCurrentNodeParameter('entityType');
const fieldName = this.getCurrentNodeParameter('field');
if (!entityType || !fieldName) {
return [{ name: 'Please Select an Entity Type and Field First', value: '' }];
}
try {
const fieldDefs = await MetadataService_1.MetadataService.getFieldDefs.call(this, this, entityType);
const fieldDef = fieldDefs[fieldName];
if (fieldDef && fieldDef.type === 'enum' && fieldDef.options) {
const options = fieldDef.options;
return options.map((option) => ({
name: option,
value: option,
}));
}
return [{ name: 'Not an Enum Field or No Options Available', value: '' }];
}
catch (error) {
console.error(`Error loading enum options for ${entityType}.${fieldName}:`, error);
return [{ name: `Error loading options for ${fieldName}`, value: '' }];
}
},
},
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
for (let i = 0; i < items.length; i++) {
try {
const resource = this.getNodeParameter('resource', i);
const operation = this.getNodeParameter('operation', i);
if (resource === 'dynamic') {
const operation = this.getNodeParameter('operation', i);
const entityType = this.getNodeParameter('entityType', i);
if (operation === 'create') {
const dataToSend = {};
const fields = this.getNodeParameter('fieldsUi.fieldValues', i, []);
for (const field of fields) {
dataToSend[field.fieldName] = field.fieldValue;
}
const endpoint = `/${entityType}`;
const responseData = await GenericFunctions_1.espoApiRequest.call(this, 'POST', endpoint, dataToSend);
returnData.push(responseData);
}
else if (operation === 'get') {
const recordId = this.getNodeParameter('recordId', i);
const endpoint = `/${entityType}/${recordId}`;
const responseData = await GenericFunctions_1.espoApiRequest.call(this, 'GET', endpoint, {});
returnData.push(responseData);
}
else if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', i);
const filters = this.getNodeParameter('filters', i, {});
const endpoint = `/${entityType}`;
const qs = {};
if (filters.where) {
if (typeof filters.where === 'string') {
try {
qs.where = JSON.parse(filters.where);
}
catch (e) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid JSON in 'where' parameter: ${e.message}`);
}
}
else {
qs.where = filters.where;
}
}
if (filters.orderBy) {
qs.orderBy = filters.orderBy;
}
if (filters.order) {
qs.order = filters.order;
}
if (filters.select) {
qs.select = filters.select;
}
if (returnAll === true) {
const responseData = await GenericFunctions_1.espoApiRequestAllItems.call(this, 'GET', endpoint, {}, qs);
returnData.push(...responseData);
}
else {
const limit = this.getNodeParameter('limit', i);
qs.maxSize = limit;
const responseData = await GenericFunctions_1.espoApiRequest.call(this, 'GET', endpoint, {}, qs);
returnData.push(...responseData.list);
}
}
else if (operation === 'update') {
const recordId = this.getNodeParameter('recordId', i);
const dataToSend = {};
const fields = this.getNodeParameter('fieldsUi.fieldValues', i, []);
for (const field of fields) {
dataToSend[field.fieldName] = field.fieldValue;
}
const endpoint = `/${entityType}/${recordId}`;
const responseData = await GenericFunctions_1.espoApiRequest.call(this, 'PATCH', endpoint, dataToSend);
returnData.push(responseData);
}
else if (operation === 'delete') {
const recordId = this.getNodeParameter('recordId', i);
const endpoint = `/${entityType}/${recordId}`;
await GenericFunctions_1.espoApiRequest.call(this, 'DELETE', endpoint, {});
returnData.push({
success: true,
id: recordId,
entityType,
});
}
}
else {
const handler = HandlerFactory_1.HandlerFactory.getHandler(resource);
let responseData;
if (resource === 'attachment' && operation === 'upload') {
responseData = await handler.create.call(this, i);
returnData.push(responseData);
break;
}
switch (operation) {
case 'create':
responseData = await handler.create.call(this, i);
returnData.push(responseData);
break;
case 'get':
responseData = await handler.get.call(this, i);
returnData.push(responseData);
break;
case 'update':
responseData = await handler.update.call(this, i);
returnData.push(responseData);
break;
case 'delete':
responseData = await handler.delete.call(this, i);
returnData.push(responseData);
break;
case 'getAll':
responseData = await handler.getAll.call(this, i);
returnData.push(...responseData);
break;
default:
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The operation "${operation}" is not supported for resource type "${resource}"`);
}
}
}
catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });
continue;
}
throw error;
}
}
return [this.helpers.returnJsonArray(returnData)];
}
}
exports.EspoCRM = EspoCRM;
//# sourceMappingURL=EspoCRM.node.js.map