diff --git a/packages/nodes-base/credentials/SalesmateApi.credentials.ts b/packages/nodes-base/credentials/SalesmateApi.credentials.ts new file mode 100644 index 0000000000..a041f9e41c --- /dev/null +++ b/packages/nodes-base/credentials/SalesmateApi.credentials.ts @@ -0,0 +1,24 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class SalesmateApi implements ICredentialType { + name = 'salesmateApi'; + displayName = 'Salesmate API'; + properties = [ + { + displayName: 'Session Token', + name: 'sessionToken', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'URL', + name: 'url', + type: 'string' as NodePropertyTypes, + default: '', + placeholder: 'n8n.salesmate.io', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Salesmate/ActivityDescription.ts b/packages/nodes-base/nodes/Salesmate/ActivityDescription.ts new file mode 100644 index 0000000000..fe737729a7 --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/ActivityDescription.ts @@ -0,0 +1,627 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const activityOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'activity', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a activity', + }, + { + name: 'Update', + value: 'update', + description: 'Update a activity', + }, + { + name: 'Get', + value: 'get', + description: 'Get a activity', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all companies', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a activity', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const activityFields = [ + +/* -------------------------------------------------------------------------- */ +/* activity:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Owner', + name: 'owner', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Type', + name: 'type', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'create', + ], + }, + }, + description: 'This field displays activity type such as call, meeting etc.', + required: true, + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'create', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + typeOptions: { + alwaysOpenEditWindow: true, + }, + type: 'string', + default: '', + description: 'This field contains details related to the activity.', + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + default: '', + description: 'This field contains tags associated with an activity', + }, + { + displayName: 'Due Date', + name: 'dueDate', + type: 'dateTime', + default: '', + description: 'Expiry date of an activity.', + }, + { + displayName: 'Duration', + name: 'duration', + type: 'number', + default: '', + description: 'Time duration of an activity.', + }, + { + displayName: 'Is Calendar Invite', + name: 'isCalendarInvite', + type: 'boolean', + default: false, + description: 'This field is used to send calendar invite.', + }, + { + displayName: 'Is Completed', + name: 'isCompleted', + type: 'boolean', + default: false, + description: 'This field indicates whether the activity is completed or not.', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* activity:update */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Activity ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'update', + ], + }, + }, + description: 'activity ID', + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'update', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + }, + { + displayName: 'Type', + name: 'type', + type: 'string', + default: '', + }, + { + displayName: 'Owner', + name: 'owner', + type: 'string', + default: '', + }, + { + displayName: 'Description', + name: 'description', + typeOptions: { + alwaysOpenEditWindow: true, + }, + type: 'string', + default: '', + description: 'This field contains details related to the activity.', + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + default: '', + description: 'This field contains tags associated with an activity', + }, + { + displayName: 'Due Date', + name: 'dueDate', + type: 'dateTime', + default: '', + description: 'Expiry date of an activity.', + }, + { + displayName: 'Duration', + name: 'duration', + type: 'number', + default: '', + description: 'Time duration of an activity.', + }, + { + displayName: 'Is Calendar Invite', + name: 'isCalendarInvite', + type: 'boolean', + default: false, + description: 'This field is used to send calendar invite.', + }, + { + displayName: 'Is Completed', + name: 'isCompleted', + type: 'boolean', + default: false, + description: 'This field indicates whether the activity is completed or not.', + }, + ], + + }, +/* -------------------------------------------------------------------------- */ +/* activity:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Activity ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'get', + ], + }, + }, + description: 'activity ID', + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'get', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, +/* -------------------------------------------------------------------------- */ +/* activity:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 25, + }, + default: 10, + description: 'How many results to return.', + }, + { + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'activity', + ], + }, + }, + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Fields', + name: 'fields', + type: 'string', + default: '', + }, + { + displayName: 'Sort By', + name: 'sortBy', + type: 'string', + default: '', + }, + { + displayName: 'Sort Order', + name: 'sortOrder', + type: 'options', + options: [ + { + name: 'Asc', + value: 'asc', + }, + { + name: 'Desc', + value: 'desc', + }, + ], + default: 'desc', + description: 'Sort order', + } + ], + }, + { + displayName: 'Filters', + name: 'filtersJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'activity', + ], + jsonParameters: [ + true, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + placeholder: 'Add filter', + type: 'fixedCollection', + typeOptions: { + multipleValues: false, + }, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'getAll', + ], + jsonParameters: [ + false, + ], + }, + }, + default: {}, + options: [ + { + name: 'filtersUi', + displayName: 'Filters', + values: [ + { + displayName: 'Operator', + name: 'operator', + type: 'options', + options: [ + { + name: 'And', + value: 'AND', + }, + { + name: 'Or', + value: 'OR', + }, + ], + default: 'AND', + }, + { + displayName: 'Conditions', + name: 'conditions', + placeholder: 'Add Condition', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'conditionsUi', + displayName: 'Conditions', + values: [ + { + displayName: 'Field', + name: 'field', + type: 'options', + options: [ + { + name: 'Title', + value: 'title', + }, + { + name: 'Tags', + value: 'tags', + }, + ], + default: 'title', + }, + { + displayName: 'Condition', + name: 'condition', + type: 'options', + options: [ + { + name: 'Equals', + value: 'EQUALS', + }, + { + name: 'Not Equals', + value: 'NOT_EQUALS', + }, + { + name: 'Empty', + value: 'EMPTY', + }, + { + name: 'Not Empty', + value: 'NOT_EMPTY', + }, + { + name: 'CONTAINS', + value: 'Contains', + }, + { + name: 'Does Not Contains', + value: 'DOES_NOT_CONTAINS', + }, + { + name: 'Starts With', + value: 'STARTS_WITH', + }, + { + name: 'Ends With', + value: 'ENDS_WITH', + }, + ], + default: 'EQUALS', + description: 'Value of the property to set.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + } + ] + }, + ], + }, + ] + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* activity:delete */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Activity ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'activity', + ], + operation: [ + 'delete', + ], + }, + }, + description: 'If more than one activity add them separated by ,', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Salesmate/ActivityInterface.ts b/packages/nodes-base/nodes/Salesmate/ActivityInterface.ts new file mode 100644 index 0000000000..ab671d0b73 --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/ActivityInterface.ts @@ -0,0 +1,11 @@ +export interface IActivity { + title?: string; + owner?: number; + type?: string; + description?: string; + tags?: string; + dueDate?: number; + duration?: number; + isCalendarInvite?: boolean; + isCompleted?: boolean; +} diff --git a/packages/nodes-base/nodes/Salesmate/CompanyDescription.ts b/packages/nodes-base/nodes/Salesmate/CompanyDescription.ts new file mode 100644 index 0000000000..a2dbc2e762 --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/CompanyDescription.ts @@ -0,0 +1,724 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const companyOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'company', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a company', + }, + { + name: 'Update', + value: 'update', + description: 'Update a company', + }, + { + name: 'Get', + value: 'get', + description: 'Get a company', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all companies', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a company', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const companyFields = [ + +/* -------------------------------------------------------------------------- */ +/* company:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Owner', + name: 'owner', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Website', + name: 'website', + type: 'string', + default: '', + }, + { + displayName: 'Phone', + name: 'phone', + type: 'string', + default: '', + }, + { + displayName: 'Other Phone', + name: 'otherPhone', + type: 'string', + default: '', + }, + { + displayName: 'Facebook Handle', + name: 'facebookHandle', + type: 'string', + default: '', + }, + { + displayName: 'Google Plus Handle', + name: 'googlePlusHandle', + type: 'string', + default: '', + }, + { + displayName: 'LinkedIn Handle', + name: 'linkedInHandle', + type: 'string', + default: '', + }, + { + displayName: 'Skype ID', + name: 'skypeId', + type: 'string', + default: '', + }, + { + displayName: 'Twitter Handle', + name: 'twitterHandle', + type: 'string', + default: '', + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + }, + { + displayName: 'Billing Address Line 1', + name: 'billingAddressLine1', + type: 'string', + default: '', + }, + { + displayName: 'Billing Address Line 2', + name: 'billingAddressLine2', + type: 'string', + default: '', + }, + { + displayName: 'Billing City', + name: 'billingCity', + type: 'string', + default: '', + }, + { + displayName: 'Billing Zip Code', + name: 'billingZipCode', + type: 'string', + default: '', + }, + { + displayName: 'Billing State', + name: 'billingState', + type: 'string', + default: '', + }, + { + displayName: 'Billing Country', + name: 'billingState', + type: 'string', + default: '', + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + default: '', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* company:update */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Company ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + description: 'company ID', + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'name', + name: 'name', + type: 'string', + default: '', + }, + { + displayName: 'Owner', + name: 'owner', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + }, + { + displayName: 'Website', + name: 'website', + type: 'string', + default: '', + }, + { + displayName: 'Phone', + name: 'phone', + type: 'string', + default: '', + }, + { + displayName: 'Other Phone', + name: 'otherPhone', + type: 'string', + default: '', + }, + { + displayName: 'Facebook Handle', + name: 'facebookHandle', + type: 'string', + default: '', + }, + { + displayName: 'Google Plus Handle', + name: 'googlePlusHandle', + type: 'string', + default: '', + }, + { + displayName: 'LinkedIn Handle', + name: 'linkedInHandle', + type: 'string', + default: '', + }, + { + displayName: 'Skype ID', + name: 'skypeId', + type: 'string', + default: '', + }, + { + displayName: 'Twitter Handle', + name: 'twitterHandle', + type: 'string', + default: '', + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + }, + { + displayName: 'Billing Address Line 1', + name: 'billingAddressLine1', + type: 'string', + default: '', + }, + { + displayName: 'Billing Address Line 2', + name: 'billingAddressLine2', + type: 'string', + default: '', + }, + { + displayName: 'Billing City', + name: 'billingCity', + type: 'string', + default: '', + }, + { + displayName: 'Billing Zip Code', + name: 'billingZipCode', + type: 'string', + default: '', + }, + { + displayName: 'Billing State', + name: 'billingState', + type: 'string', + default: '', + }, + { + displayName: 'Billing Country', + name: 'billingState', + type: 'string', + default: '', + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + default: '', + }, + ], + + }, +/* -------------------------------------------------------------------------- */ +/* company:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Company ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'get', + ], + }, + }, + description: 'company ID', + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'get', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, +/* -------------------------------------------------------------------------- */ +/* company:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 25, + }, + default: 10, + description: 'How many results to return.', + }, + { + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'company', + ], + }, + }, + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Fields', + name: 'fields', + type: 'string', + default: '', + }, + { + displayName: 'Sort By', + name: 'sortBy', + type: 'string', + default: '', + }, + { + displayName: 'Sort Order', + name: 'sortOrder', + type: 'options', + options: [ + { + name: 'Asc', + value: 'asc', + }, + { + name: 'Desc', + value: 'desc', + }, + ], + default: 'desc', + description: 'Sort order', + } + ], + }, + { + displayName: 'Filters', + name: 'filtersJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'company', + ], + jsonParameters: [ + true, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + placeholder: 'Add filter', + type: 'fixedCollection', + typeOptions: { + multipleValues: false, + }, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + jsonParameters: [ + false, + ], + }, + }, + default: {}, + options: [ + { + name: 'filtersUi', + displayName: 'Filters', + values: [ + { + displayName: 'Operator', + name: 'operator', + type: 'options', + options: [ + { + name: 'And', + value: 'AND', + }, + { + name: 'Or', + value: 'OR', + }, + ], + default: 'AND', + }, + { + displayName: 'Conditions', + name: 'conditions', + placeholder: 'Add Condition', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'conditionsUi', + displayName: 'Conditions', + values: [ + { + displayName: 'Field', + name: 'field', + type: 'options', + options: [ + { + name: 'Name', + value: 'name', + }, + { + name: 'Email', + value: 'email', + }, + { + name: 'Phone', + value: 'phone', + }, + ], + default: 'name', + }, + { + displayName: 'Condition', + name: 'condition', + type: 'options', + options: [ + { + name: 'Equals', + value: 'EQUALS', + }, + { + name: 'Not Equals', + value: 'NOT_EQUALS', + }, + { + name: 'Empty', + value: 'EMPTY', + }, + { + name: 'Not Empty', + value: 'NOT_EMPTY', + }, + { + name: 'CONTAINS', + value: 'Contains', + }, + { + name: 'Does Not Contains', + value: 'DOES_NOT_CONTAINS', + }, + { + name: 'Starts With', + value: 'STARTS_WITH', + }, + { + name: 'Ends With', + value: 'ENDS_WITH', + }, + ], + default: 'EQUALS', + description: 'Value of the property to set.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + } + ] + }, + ], + }, + ] + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* company:delete */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Company ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'delete', + ], + }, + }, + description: 'If more than one company add them separated by ,', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Salesmate/CompanyInterface.ts b/packages/nodes-base/nodes/Salesmate/CompanyInterface.ts new file mode 100644 index 0000000000..52368cb116 --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/CompanyInterface.ts @@ -0,0 +1,22 @@ +export interface ICompany { + name?: string; + owner?: number; + website?: string; + phone?: string; + otherPhone?: string; + googlePlusHandle?: string; + linkedInHandle?: string; + facebookHandle?: string; + linkedinHandle?: string; + skypeId?: string; + twitterHandle?: string; + currency?: string; + billingAddressLine1?: string; + billingAddressLine2?: string; + billingCity?: string; + billingZipCode?: string; + billingCountry?: string; + billingState?: string; + description?: string; + tags?: string; +} diff --git a/packages/nodes-base/nodes/Salesmate/DealDescription.ts b/packages/nodes-base/nodes/Salesmate/DealDescription.ts new file mode 100644 index 0000000000..343c02b55a --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/DealDescription.ts @@ -0,0 +1,895 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const dealOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'deal', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a deal', + }, + { + name: 'Update', + value: 'update', + description: 'Update a deal', + }, + { + name: 'Get', + value: 'get', + description: 'Get a deal', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all companies', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a deal', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const dealFields = [ + +/* -------------------------------------------------------------------------- */ +/* deal:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Owner', + name: 'owner', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Primary Contact', + name: 'primaryContact', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getContacts', + }, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + description: 'Primary contact for the deal.', + required: true, + }, + { + displayName: 'Pipeline', + name: 'pipeline', + type: 'options', + options: [ + { + name: 'Sales', + value: 'Sales', + }, + ], + default: '', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'Open', + options: [ + { + name: 'Open', + value: 'Open', + }, + { + name: 'Close', + value: 'Close', + }, + { + name: 'Lost', + value: 'Lost', + }, + ], + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Stage', + name: 'stage', + type: 'options', + default: '', + options: [ + { + name: 'New (Untouched)', + value: 'New (Untouched)', + }, + { + name: 'Contacted', + value: 'Contacted', + }, + { + name: 'Qualified', + value: 'Qualified', + }, + { + name: 'Proposal Presented', + value: 'Proposal Presented', + }, + { + name: 'In Negotiation', + value: 'In Negotiation', + }, + ], + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + typeOptions: { + alwaysOpenEditWindow: true, + }, + type: 'string', + default: '', + description: 'This field contains details related to the deal.', + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + default: '', + description: 'This field contains tags associated with an deal', + }, + { + displayName: 'Primary Company', + name: 'primaryCompany', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCompanies', + }, + default: '', + }, + { + displayName: 'Source', + name: 'source', + type: 'options', + options: [ + { + name: 'Ads', + value: 'Ads', + }, + { + name: 'Referrals', + value: 'Referrals', + }, + { + name: 'Website', + value: 'Website', + }, + { + name: 'Word of mouth', + value: 'Word of mouth', + }, + ], + default: 'Ads', + }, + { + displayName: 'Estimated Close Date', + name: 'estimatedCloseDate', + type: 'dateTime', + default: '', + }, + { + displayName: 'Deal Value', + name: 'dealValue', + type: 'number', + typeOptions: { + numberPrecision: 2, + }, + default: 0, + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 'Medium', + options: [ + { + name: 'High', + value: 'High', + }, + { + name: 'Medium', + value: 'Medium', + }, + { + name: 'Low', + value: 'Low', + }, + ], + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* deal:update */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Deal ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'update', + ], + }, + }, + description: 'deal ID', + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'update', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + }, + { + displayName: 'Owner', + name: 'owner', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + }, + { + displayName: 'Primary Contact', + name: 'primaryContact', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getContacts', + }, + }, + { + displayName: 'Pipeline', + name: 'pipeline', + type: 'options', + options: [ + { + name: 'Sales', + value: 'Sales', + }, + ], + default: '', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'Open', + options: [ + { + name: 'Open', + value: 'Open', + }, + { + name: 'Close', + value: 'Close', + }, + { + name: 'Lost', + value: 'Lost', + }, + ], + }, + { + displayName: 'Stage', + name: 'stage', + type: 'options', + default: '', + options: [ + { + name: 'New (Untouched)', + value: 'New (Untouched)', + }, + { + name: 'Contacted', + value: 'Contacted', + }, + { + name: 'Qualified', + value: 'Qualified', + }, + { + name: 'Proposal Presented', + value: 'Proposal Presented', + }, + { + name: 'In Negotiation', + value: 'In Negotiation', + }, + ], + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + }, + { + displayName: 'Description', + name: 'description', + typeOptions: { + alwaysOpenEditWindow: true, + }, + type: 'string', + default: '', + description: 'This field contains details related to the deal.', + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + default: '', + description: 'This field contains tags associated with an deal', + }, + { + displayName: 'Primary Company', + name: 'primaryCompany', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCompanies', + }, + default: '', + }, + { + displayName: 'Source', + name: 'source', + type: 'options', + options: [ + { + name: 'Ads', + value: 'Ads', + }, + { + name: 'Referrals', + value: 'Referrals', + }, + { + name: 'Website', + value: 'Website', + }, + { + name: 'Word of mouth', + value: 'Word of mouth', + }, + ], + default: 'Ads', + }, + { + displayName: 'Estimated Close Date', + name: 'estimatedCloseDate', + type: 'dateTime', + default: '', + }, + { + displayName: 'Deal Value', + name: 'dealValue', + type: 'number', + typeOptions: { + numberPrecision: 2, + }, + default: 0, + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 'Medium', + options: [ + { + name: 'High', + value: 'High', + }, + { + name: 'Medium', + value: 'Medium', + }, + { + name: 'Low', + value: 'Low', + }, + ], + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* deal:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Deal ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'get', + ], + }, + }, + description: 'deal ID', + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'get', + ], + }, + }, + default: false, + description: `If the data should include the fields details`, + }, +/* -------------------------------------------------------------------------- */ +/* deal:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 25, + }, + default: 10, + description: 'How many results to return.', + }, + { + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'deal', + ], + }, + }, + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Fields', + name: 'fields', + type: 'string', + default: '', + }, + { + displayName: 'Sort By', + name: 'sortBy', + type: 'string', + default: '', + }, + { + displayName: 'Sort Order', + name: 'sortOrder', + type: 'options', + options: [ + { + name: 'Asc', + value: 'asc', + }, + { + name: 'Desc', + value: 'desc', + }, + ], + default: 'desc', + description: 'Sort order', + } + ], + }, + { + displayName: 'Filters', + name: 'filtersJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'deal', + ], + jsonParameters: [ + true, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + placeholder: 'Add filter', + type: 'fixedCollection', + typeOptions: { + multipleValues: false, + }, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'getAll', + ], + jsonParameters: [ + false, + ], + }, + }, + default: {}, + options: [ + { + name: 'filtersUi', + displayName: 'Filters', + values: [ + { + displayName: 'Operator', + name: 'operator', + type: 'options', + options: [ + { + name: 'And', + value: 'AND', + }, + { + name: 'Or', + value: 'OR', + }, + ], + default: 'AND', + }, + { + displayName: 'Conditions', + name: 'conditions', + placeholder: 'Add Condition', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'conditionsUi', + displayName: 'Conditions', + values: [ + { + displayName: 'Field', + name: 'field', + type: 'options', + options: [ + { + name: 'Title', + value: 'title', + }, + { + name: 'Tags', + value: 'tags', + }, + { + name: 'Last Communication Mode', + value: 'lastCommunicationMode', + }, + ], + default: 'title', + }, + { + displayName: 'Condition', + name: 'condition', + type: 'options', + options: [ + { + name: 'Equals', + value: 'EQUALS', + }, + { + name: 'Not Equals', + value: 'NOT_EQUALS', + }, + { + name: 'Empty', + value: 'EMPTY', + }, + { + name: 'Not Empty', + value: 'NOT_EMPTY', + }, + { + name: 'CONTAINS', + value: 'Contains', + }, + { + name: 'Does Not Contains', + value: 'DOES_NOT_CONTAINS', + }, + { + name: 'Starts With', + value: 'STARTS_WITH', + }, + { + name: 'Ends With', + value: 'ENDS_WITH', + }, + ], + default: 'EQUALS', + description: 'Value of the property to set.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + } + ] + }, + ], + }, + ] + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* deal:delete */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Deal ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'delete', + ], + }, + }, + description: 'If more than one deal add them separated by ,', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Salesmate/DealInterface.ts b/packages/nodes-base/nodes/Salesmate/DealInterface.ts new file mode 100644 index 0000000000..7e4e1df106 --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/DealInterface.ts @@ -0,0 +1,16 @@ +export interface IDeal { + title?: string; + owner?: number; + pipeline?: string; + primaryContact?: number; + primaryCompany?: number; + status?: string; + stage?: string; + source?: string; + estimatedCloseDate?: string; + dealValue?: number; + currency?: string; + priority?: string; + description?: string; + tags?: string; +} diff --git a/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts b/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts new file mode 100644 index 0000000000..a84dbc95e2 --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts @@ -0,0 +1,67 @@ +import { OptionsWithUri } from 'request'; +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IWebhookFunctions, +} from 'n8n-core'; +import { IDataObject } from 'n8n-workflow'; + +export async function salesmateApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('salesmateApi'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const options: OptionsWithUri = { + headers: { + 'sessionToken': credentials.sessionToken, + 'x-linkname': credentials.url, + 'Content-Type': 'application/json', + }, + method, + qs, + body, + uri: uri ||`https://apis.salesmate.io${resource}`, + json: true + }; + if (!Object.keys(body).length) { + delete options.body; + } + try { + return await this.helpers.request!(options); + } catch (error) { + throw new Error('Salesmate Error: ' + error); + } +} + +export async function salesmateApiRequestAllItems(this: IHookFunctions | IExecuteFunctions| ILoadOptionsFunctions, propertyName: string, method: string, resource: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any + + const returnData: IDataObject[] = []; + + let responseData; + query.pageNo = 1; + query.rows = 25; + do { + responseData = await salesmateApiRequest.call(this, method, resource, body, query); + returnData.push.apply(returnData, responseData[propertyName].data); + query.pageNo++; + } while ( + responseData[propertyName].totalPages !== undefined && + query.pageNo <= responseData[propertyName].totalPages + ); + + return returnData; +} + + +export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any + let result; + try { + result = JSON.parse(json!); + } catch (exception) { + result = undefined; + } + return result; +} diff --git a/packages/nodes-base/nodes/Salesmate/Salesmate.node.ts b/packages/nodes-base/nodes/Salesmate/Salesmate.node.ts new file mode 100644 index 0000000000..a57b8b7410 --- /dev/null +++ b/packages/nodes-base/nodes/Salesmate/Salesmate.node.ts @@ -0,0 +1,700 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; +import { + IDataObject, + ILoadOptionsFunctions, + INodeExecutionData, + INodePropertyOptions, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; +import { + salesmateApiRequest, + salesmateApiRequestAllItems, + validateJSON, +} from './GenericFunctions'; +import { + companyFields, + companyOperations, +} from './CompanyDescription'; +import { + activityFields, + activityOperations, +} from './ActivityDescription'; +import { + ICompany, + } from './CompanyInterface'; + import { + IActivity, + } from './ActivityInterface'; + import { + IDeal, + } from './DealInterface'; +import { + dealFields, + dealOperations, + } from './DealDescription'; + +export class Salesmate implements INodeType { + description: INodeTypeDescription = { + displayName: 'Salesmate', + name: 'salesmate', + icon: 'file:salesmate.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ":" + $parameter["resource"]}}', + description: 'Consume Salesmate API', + defaults: { + name: 'Salesmate', + color: '#004ef6', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'salesmateApi', + required: true, + } + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Activity', + value: 'activity', + }, + { + name: 'Company', + value: 'company', + }, + { + name: 'Deal', + value: 'deal', + }, + ], + default: 'activity', + description: 'Resource to consume.', + }, + ...companyOperations, + ...activityOperations, + ...dealOperations, + ...companyFields, + ...activityFields, + ...dealFields, + ], + }; + + methods = { + loadOptions: { + // Get all the available users to display them to user so that he can + // select them easily + async getUsers(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const users = await salesmateApiRequest.call(this, 'GET', '/v1/users/active'); + for (const user of users.Data) { + const userName = user.nickname; + const userId = user.id; + returnData.push({ + name: userName, + value: userId, + }); + } + return returnData; + }, + // Get all the available contacs to display them to user so that he can + // select them easily + async getContacts(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const qs: IDataObject = { + fields: ['name', 'id'], + query: {} + }; + const contacts = await salesmateApiRequest.call(this, 'POST', '/v2/contacts/search', qs); + for (const contact of contacts.Data.data) { + const contactName = contact.name; + const contactId = contact.id; + returnData.push({ + name: contactName, + value: contactId, + }); + } + return returnData; + }, + // Get all the available companies to display them to user so that he can + // select them easily + async getCompanies(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const qs: IDataObject = { + fields: ['name', 'id'], + query: {} + }; + const companies = await salesmateApiRequest.call(this, 'POST', '/v2/companies/search', qs); + for (const company of companies.Data.data) { + const companyName = company.name; + const companyId = company.id; + returnData.push({ + name: companyName, + value: companyId, + }); + } + return returnData; + }, + }, + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length as unknown as number; + const qs: IDataObject = {}; + let responseData; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + for (let i = 0; i < length; i++) { + if (resource === 'company') { + if (operation === 'create') { + const owner = this.getNodeParameter('owner', i) as number; + const name = this.getNodeParameter('name', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + const body: ICompany = { + name, + owner, + }; + if (additionalFields.website) { + body.website = additionalFields.website as string; + } + if (additionalFields.phone) { + body.phone = additionalFields.phone as string; + } + if (additionalFields.otherPhone) { + body.otherPhone = additionalFields.otherPhone as string; + } + if (additionalFields.facebookHandle) { + body.facebookHandle = additionalFields.facebookHandle as string; + } + if (additionalFields.googlePlusHandle) { + body.googlePlusHandle = additionalFields.googlePlusHandle as string; + } + if (additionalFields.linkedInHandle) { + body.linkedInHandle = additionalFields.linkedInHandle as string; + } + if (additionalFields.skypeId) { + body.skypeId = additionalFields.skypeId as string; + } + if (additionalFields.twitterHandle) { + body.twitterHandle = additionalFields.twitterHandle as string; + } + if (additionalFields.currency) { + body.currency = additionalFields.currency as string; + } + if (additionalFields.billingAddressLine1) { + body.billingAddressLine1 = additionalFields.billingAddressLine1 as string; + } + if (additionalFields.billingAddressLine2) { + body.billingAddressLine2 = additionalFields.billingAddressLine2 as string; + } + if (additionalFields.billingCity) { + body.billingCity = additionalFields.billingCity as string; + } + if (additionalFields.billingZipCode) { + body.billingZipCode = additionalFields.billingZipCode as string; + } + if (additionalFields.billingState) { + body.billingState = additionalFields.billingState as string; + } + if (additionalFields.description) { + body.description = additionalFields.description as string; + } + if (additionalFields.tags) { + body.tags = additionalFields.tags as string; + } + responseData = await salesmateApiRequest.call(this, 'POST', '/v1/companies', body); + responseData = responseData.Data; + if (!rawData) { + delete responseData.detail; + } + } + if (operation === 'update') { + const companyId = this.getNodeParameter('id', i) as string; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + const rawData = this.getNodeParameter('rawData', i) as boolean; + const body: ICompany = {}; + if (updateFields.owner) { + body.owner = updateFields.owner as number; + } + if (updateFields.name) { + body.name = updateFields.name as string; + } + if (updateFields.website) { + body.website = updateFields.website as string; + } + if (updateFields.phone) { + body.phone = updateFields.phone as string; + } + if (updateFields.otherPhone) { + body.otherPhone = updateFields.otherPhone as string; + } + if (updateFields.facebookHandle) { + body.facebookHandle = updateFields.facebookHandle as string; + } + if (updateFields.googlePlusHandle) { + body.googlePlusHandle = updateFields.googlePlusHandle as string; + } + if (updateFields.linkedInHandle) { + body.linkedInHandle = updateFields.linkedInHandle as string; + } + if (updateFields.skypeId) { + body.skypeId = updateFields.skypeId as string; + } + if (updateFields.twitterHandle) { + body.twitterHandle = updateFields.twitterHandle as string; + } + if (updateFields.currency) { + body.currency = updateFields.currency as string; + } + if (updateFields.billingAddressLine1) { + body.billingAddressLine1 = updateFields.billingAddressLine1 as string; + } + if (updateFields.billingAddressLine2) { + body.billingAddressLine2 = updateFields.billingAddressLine2 as string; + } + if (updateFields.billingCity) { + body.billingCity = updateFields.billingCity as string; + } + if (updateFields.billingZipCode) { + body.billingZipCode = updateFields.billingZipCode as string; + } + if (updateFields.billingState) { + body.billingState = updateFields.billingState as string; + } + if (updateFields.description) { + body.description = updateFields.description as string; + } + if (updateFields.tags) { + body.tags = updateFields.tags as string; + } + responseData = await salesmateApiRequest.call(this, 'PUT', `/v1/companies/${companyId}`, body); + responseData = responseData.Data; + if (!rawData) { + delete responseData.detail; + } + } + if (operation === 'get') { + const companyId = this.getNodeParameter('id', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + responseData = await salesmateApiRequest.call(this, 'GET', `/v1/companies/${companyId}`); + responseData = responseData.Data; + if (!rawData) { + responseData = responseData.map((company: IDataObject) => { + const aux: IDataObject = {}; + aux[company.fieldName as string] = company.value; + return aux; + }); + } + } + if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + const options = this.getNodeParameter('options', i) as IDataObject; + const jsonActive = this.getNodeParameter('jsonParameters', i) as boolean; + let body: IDataObject = { + query: { + group: { + }, + }, + }; + if (options.sortBy) { + qs.sortBy = options.sortBy as string; + } + if (options.sortOrder) { + qs.sortOrder = options.sortOrder as string; + } + if (options.fields) { + body.fields = (options.fields as string).split(',') as string[]; + } else { + throw new Error('You have to add at least one field'); + } + if (!jsonActive) { + const filters: IDataObject[] = []; + const filtersUi = (this.getNodeParameter('filters', i) as IDataObject).filtersUi as IDataObject; + if (filtersUi && filtersUi.conditions) { + const conditions = filtersUi.conditions as IDataObject; + if (conditions.conditionsUi) { + for (const condition of conditions.conditionsUi as IDataObject[]) { + const filter: IDataObject = {}; + filter.moduleName = 'Company'; + filter.field = { + fieldName: condition.field, + }; + filter.condition = condition.condition; + filter.data = condition.value; + filters.push(filter) + } + } + } + if (filtersUi && filtersUi.operator) { + //@ts-ignore + body.query.group = { + operator: filtersUi.operator, + rules: filters, + }; + } + } else { + const json = validateJSON(this.getNodeParameter('filtersJson', i) as string); + body = json; + } + if (returnAll) { + responseData = await salesmateApiRequestAllItems.call(this, 'Data', 'POST', '/v2/companies/search', body, qs); + } else { + const limit = this.getNodeParameter('limit', i) as number; + qs.rows = limit; + responseData = await salesmateApiRequest.call(this, 'POST', '/v2/companies/search', body, qs); + responseData = responseData.Data.data; + } + } + if (operation === 'delete') { + const companyId = parseInt(this.getNodeParameter('id', i) as string, 10); + responseData = await salesmateApiRequest.call(this, 'DELETE', `/v1/companies/${companyId}`); + } + } + if (resource === 'activity') { + if (operation === 'create') { + const owner = this.getNodeParameter('owner', i) as number; + const title = this.getNodeParameter('title', i) as string; + const type = this.getNodeParameter('type', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + const body: IActivity = { + title, + owner, + type, + }; + if (additionalFields.dueDate) { + body.dueDate = new Date(additionalFields.dueDate as string).getTime(); + } + if (additionalFields.duration) { + body.duration = additionalFields.duration as number; + } + if (additionalFields.isCalendarInvite) { + body.isCalendarInvite = additionalFields.isCalendarInvite as boolean; + } + if (additionalFields.isCompleted) { + body.isCompleted = additionalFields.isCompleted as boolean; + } + if (additionalFields.description) { + body.description = additionalFields.description as string; + } + if (additionalFields.tags) { + body.tags = additionalFields.tags as string; + } + responseData = await salesmateApiRequest.call(this, 'POST', '/v1/activities', body); + responseData = responseData.Data; + if (!rawData) { + delete responseData.detail; + } + } + if (operation === 'update') { + const activityId = this.getNodeParameter('id', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + const body: IActivity = {}; + if (updateFields.title) { + body.title = updateFields.title as string; + } + if (updateFields.type) { + body.type = updateFields.type as string; + } + if (updateFields.owner) { + body.owner = updateFields.owner as number; + } + if (updateFields.dueDate) { + body.dueDate = new Date(updateFields.dueDate as string).getTime(); + } + if (updateFields.duration) { + body.duration = updateFields.duration as number; + } + if (updateFields.isCalendarInvite) { + body.isCalendarInvite = updateFields.isCalendarInvite as boolean; + } + if (updateFields.isCompleted) { + body.isCompleted = updateFields.isCompleted as boolean; + } + if (updateFields.description) { + body.description = updateFields.description as string; + } + if (updateFields.tags) { + body.tags = updateFields.tags as string; + } + responseData = await salesmateApiRequest.call(this, 'PUT', `/v1/activities/${activityId}`, body); + responseData = responseData.Data; + if (!rawData) { + delete responseData.detail; + } + } + if (operation === 'get') { + const activityId = this.getNodeParameter('id', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + responseData = await salesmateApiRequest.call(this, 'GET', `/v1/activities/${activityId}`); + responseData = responseData.Data; + if (!rawData) { + responseData = responseData.map((activity: IDataObject) => { + const aux: IDataObject = {}; + aux[activity.fieldName as string] = activity.value; + return aux; + }); + } + } + if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + const options = this.getNodeParameter('options', i) as IDataObject; + const jsonActive = this.getNodeParameter('jsonParameters', i) as boolean; + let body: IDataObject = { + query: { + group: { + }, + }, + }; + if (options.sortBy) { + qs.sortBy = options.sortBy as string; + } + if (options.sortOrder) { + qs.sortOrder = options.sortOrder as string; + } + if (options.fields) { + body.fields = (options.fields as string).split(',') as string[]; + } else { + throw new Error('You have to add at least one field'); + } + if (!jsonActive) { + const filters: IDataObject[] = []; + const filtersUi = (this.getNodeParameter('filters', i) as IDataObject).filtersUi as IDataObject; + if (filtersUi && filtersUi.conditions) { + const conditions = filtersUi.conditions as IDataObject; + if (conditions.conditionsUi) { + for (const condition of conditions.conditionsUi as IDataObject[]) { + const filter: IDataObject = {}; + filter.moduleName = 'Task'; + filter.field = { + fieldName: condition.field, + }; + filter.condition = condition.condition; + filter.data = condition.value; + filters.push(filter) + } + } + } + if (filtersUi && filtersUi.operator) { + //@ts-ignore + body.query.group = { + operator: filtersUi.operator, + rules: filters, + }; + } + } else { + const json = validateJSON(this.getNodeParameter('filtersJson', i) as string); + body = json; + } + if (returnAll) { + responseData = await salesmateApiRequestAllItems.call(this, 'Data', 'POST', '/v2/activities/search', body, qs); + } else { + const limit = this.getNodeParameter('limit', i) as number; + qs.rows = limit; + responseData = await salesmateApiRequest.call(this, 'POST', '/v2/activities/search', body, qs); + responseData = responseData.Data.data; + } + } + if (operation === 'delete') { + const activityId = this.getNodeParameter('id', i) as string; + responseData = await salesmateApiRequest.call(this, 'DELETE', `/v1/activities/${activityId}`); + } + } + if (resource === 'deal') { + if (operation === 'create') { + const title = this.getNodeParameter('title', i) as string; + const owner = this.getNodeParameter('owner', i) as number; + const primaryContact = this.getNodeParameter('primaryContact', i) as number; + const pipeline = this.getNodeParameter('pipeline', i) as string; + const status = this.getNodeParameter('status', i) as string; + const stage = this.getNodeParameter('stage', i) as string; + const currency = this.getNodeParameter('currency', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + const body: IDeal = { + title, + owner, + primaryContact, + pipeline, + status, + stage, + currency, + }; + if (additionalFields.description) { + body.description = additionalFields.description as string; + } + if (additionalFields.tags) { + body.tags = additionalFields.tags as string; + } + if (additionalFields.primaryCompany) { + body.primaryCompany = additionalFields.primaryCompany as number; + } + if (additionalFields.source) { + body.source = additionalFields.source as string; + } + if (additionalFields.estimatedCloseDate) { + body.estimatedCloseDate = additionalFields.estimatedCloseDate as string; + } + if (additionalFields.dealValue) { + body.dealValue = additionalFields.dealValue as number; + } + if (additionalFields.priority) { + body.priority = additionalFields.priority as string; + } + responseData = await salesmateApiRequest.call(this, 'POST', '/v1/deals', body); + responseData = responseData.Data; + if (!rawData) { + delete responseData.detail; + } + } + if (operation === 'update') { + const dealId = this.getNodeParameter('id', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + const body: IDeal = {}; + if (updateFields.title) { + body.title = updateFields.title as string; + } + if (updateFields.owner) { + body.owner = updateFields.owner as number; + } + if (updateFields.primaryContact) { + body.primaryContact = updateFields.primaryContact as number; + } + if (updateFields.status) { + body.status = updateFields.status as string; + } + if (updateFields.currency) { + body.currency = updateFields.currency as string; + } + if (updateFields.stage) { + body.stage = updateFields.stage as string; + } + if (updateFields.pipeline) { + body.pipeline = updateFields.pipeline as string; + } + if (updateFields.description) { + body.description = updateFields.description as string; + } + if (updateFields.tags) { + body.tags = updateFields.tags as string; + } + if (updateFields.primaryCompany) { + body.primaryCompany = updateFields.primaryCompany as number; + } + if (updateFields.source) { + body.source = updateFields.source as string; + } + if (updateFields.estimatedCloseDate) { + body.estimatedCloseDate = updateFields.estimatedCloseDate as string; + } + if (updateFields.dealValue) { + body.dealValue = updateFields.dealValue as number; + } + if (updateFields.priority) { + body.priority = updateFields.priority as string; + } + responseData = await salesmateApiRequest.call(this, 'PUT', `/v1/deals/${dealId}`, body); + responseData = responseData.Data; + if (!rawData) { + delete responseData.detail; + } + } + if (operation === 'get') { + const dealId = this.getNodeParameter('id', i) as string; + const rawData = this.getNodeParameter('rawData', i) as boolean; + responseData = await salesmateApiRequest.call(this, 'GET', `/v1/deals/${dealId}`); + responseData = responseData.Data; + if (!rawData) { + responseData = responseData.map((deal: IDataObject) => { + const aux: IDataObject = {}; + aux[deal.fieldName as string] = deal.value; + return aux; + }); + } + } + if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + const options = this.getNodeParameter('options', i) as IDataObject; + const jsonActive = this.getNodeParameter('jsonParameters', i) as boolean; + let body: IDataObject = { + query: { + group: { + }, + }, + }; + if (options.sortBy) { + qs.sortBy = options.sortBy as string; + } + if (options.sortOrder) { + qs.sortOrder = options.sortOrder as string; + } + if (options.fields) { + body.fields = (options.fields as string).split(',') as string[]; + } else { + throw new Error('You have to add at least one field'); + } + if (!jsonActive) { + const filters: IDataObject[] = []; + const filtersUi = (this.getNodeParameter('filters', i) as IDataObject).filtersUi as IDataObject; + if (filtersUi && filtersUi.conditions) { + const conditions = filtersUi.conditions as IDataObject; + if (conditions.conditionsUi) { + for (const condition of conditions.conditionsUi as IDataObject[]) { + const filter: IDataObject = {}; + filter.moduleName = 'Task'; + filter.field = { + fieldName: condition.field, + }; + filter.condition = condition.condition; + filter.data = condition.value; + filters.push(filter) + } + } + } + if (filtersUi && filtersUi.operator) { + //@ts-ignore + body.query.group = { + operator: filtersUi.operator, + rules: filters, + }; + } + } else { + const json = validateJSON(this.getNodeParameter('filtersJson', i) as string); + body = json; + } + if (returnAll) { + responseData = await salesmateApiRequestAllItems.call(this, 'Data', 'POST', '/v2/deals/search', body, qs); + } else { + const limit = this.getNodeParameter('limit', i) as number; + qs.rows = limit; + responseData = await salesmateApiRequest.call(this, 'POST', '/v2/deals/search', body, qs); + responseData = responseData.Data.data; + } + } + if (operation === 'delete') { + const dealId = this.getNodeParameter('id', i) as string; + responseData = await salesmateApiRequest.call(this, 'DELETE', `/v1/deals/${dealId}`); + } + } + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } + } + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Salesmate/salesmate.png b/packages/nodes-base/nodes/Salesmate/salesmate.png new file mode 100644 index 0000000000..3307335968 Binary files /dev/null and b/packages/nodes-base/nodes/Salesmate/salesmate.png differ diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index df87d196ce..9cd7f397c5 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -73,6 +73,7 @@ "dist/credentials/SlackApi.credentials.js", "dist/credentials/Smtp.credentials.js", "dist/credentials/StripeApi.credentials.js", + "dist/credentials/SalesmateApi.credentials.js", "dist/credentials/TelegramApi.credentials.js", "dist/credentials/TodoistApi.credentials.js", "dist/credentials/TrelloApi.credentials.js", @@ -170,6 +171,7 @@ "dist/nodes/Start.node.js", "dist/nodes/Stripe/StripeTrigger.node.js", "dist/nodes/Switch.node.js", + "dist/nodes/Salesmate/Salesmate.node.js", "dist/nodes/Telegram/Telegram.node.js", "dist/nodes/Telegram/TelegramTrigger.node.js", "dist/nodes/Todoist/Todoist.node.js",