diff --git a/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts b/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts index c35b169239..3d61e24746 100644 --- a/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts @@ -7,6 +7,15 @@ import { IDataObject, } from 'n8n-workflow'; + +export interface ICustomInterface { + name: string; + options?: Array<{ + id: number; + label: string; + }>; +} + /** * Make an API request to Pipedrive * @@ -108,3 +117,72 @@ export async function pipedriveApiRequestAllItems(this: IHookFunctions | IExecut data: returnData }; } + + + +/** + * Converts names and values of custom properties to their actual values + * + * @export + * @param {(IHookFunctions | IExecuteFunctions)} this + * @param {string} resource + * @param {IDataObject[]} items + * @returns {Promise} + */ +export async function pipedriveResolveCustomProperties(this: IHookFunctions | IExecuteFunctions, resource: string, items: IDataObject[]): Promise { + + const endpoints: { [key: string]: string } = { + 'activity': '/activityFields', + 'deal': '/dealFields', + 'organization': '/organizationFields', + 'person': '/personFields', + 'product': '/productFields', + }; + + if (endpoints[resource] === undefined) { + throw new Error(`The resource "${resource}" is not supported for resolving custom values!`); + } + + const requestMethod = 'GET'; + + const body = {}; + const qs = {}; + // Get the custom properties and their values + const responseData = await pipedriveApiRequest.call(this, requestMethod, endpoints[resource], body, qs); + + const customProperties: { + [key: string]: ICustomInterface; + } = {}; + + for (const customPropertyData of responseData.data) { + customProperties[customPropertyData.key] = customPropertyData; + } + + let customPropertyData; + + for (const item of items) { + // Itterate over all keys and replace the custom ones + for (const key of Object.keys(item)) { + if (customProperties[key] !== undefined) { + // Is a custom property + customPropertyData = customProperties[key]; + + // Check if also the value has to be resolved or just the key + if (item[key] !== null && item[key] !== undefined && customPropertyData.options !== undefined && Array.isArray(customPropertyData.options)) { + // Has an option key so get the actual option-value + const propertyOption = customPropertyData.options.find(option => option.id.toString() === item[key]!.toString()); + + if (propertyOption !== undefined) { + item[customPropertyData.name as string] = propertyOption.label; + delete item[key]; + } + } else { + // Does already represent the actual value or is null + item[customPropertyData.name as string] = item[key]; + delete item[key]; + } + } + } + } + +} diff --git a/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts b/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts index 50a2efcc67..6f949d693c 100644 --- a/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts +++ b/packages/nodes-base/nodes/Pipedrive/Pipedrive.node.ts @@ -11,6 +11,7 @@ import { import { pipedriveApiRequest, pipedriveApiRequestAllItems, + pipedriveResolveCustomProperties, } from './GenericFunctions'; interface CustomProperty { @@ -121,12 +122,11 @@ export class Pipedrive implements INodeType { value: 'get', description: 'Get data of an activity', }, - // TODO: Currently missing - // { - // name: 'Get All', - // value: 'getAll', - // description: 'Get data of all activities', - // }, + { + name: 'Get All', + value: 'getAll', + description: 'Get data of all activities', + }, { name: 'Update', value: 'update', @@ -164,12 +164,11 @@ export class Pipedrive implements INodeType { value: 'get', description: 'Get data of a deal', }, - // TODO: Currently missing - // { - // name: 'Get All', - // value: 'getAll', - // description: 'Get data of all deals', - // }, + { + name: 'Get All', + value: 'getAll', + description: 'Get data of all deals', + }, { name: 'Update', value: 'update', @@ -1186,51 +1185,6 @@ export class Pipedrive implements INodeType { description: 'ID of the organization to get.', }, - // ---------------------------------- - // organization:getAll - // ---------------------------------- - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'organization', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'organization', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', - }, - // ---------------------------------- @@ -1399,51 +1353,6 @@ export class Pipedrive implements INodeType { description: 'ID of the person to get.', }, - // ---------------------------------- - // person:getAll - // ---------------------------------- - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'person', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'person', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', - }, - // ---------------------------------- // person:update // ---------------------------------- @@ -1572,13 +1481,25 @@ export class Pipedrive implements INodeType { - // ---------------------------------- - // product - // ---------------------------------- // ---------------------------------- - // product:getAll + // activity / deal / organization / person / product // ---------------------------------- + { + displayName: 'Resolve Properties', + name: 'resolveProperties', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'get', + 'getAll', + ], + }, + }, + default: false, + description: 'By default do custom properties get returned only as ID instead of their actual name. Also option fields contain only the ID instead of their actual value. If this option gets set they get automatically resolved.', + }, { displayName: 'Return All', name: 'returnAll', @@ -1588,9 +1509,6 @@ export class Pipedrive implements INodeType { operation: [ 'getAll', ], - resource: [ - 'product', - ], }, }, default: false, @@ -1605,9 +1523,6 @@ export class Pipedrive implements INodeType { operation: [ 'getAll', ], - resource: [ - 'product', - ], returnAll: [ false, ], @@ -1629,9 +1544,6 @@ export class Pipedrive implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - let resource: string; - let operation: string; - // For Post let body: IDataObject; // For Query string @@ -1641,9 +1553,10 @@ export class Pipedrive implements INodeType { let endpoint: string; let returnAll = false; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + for (let i = 0; i < items.length; i++) { - resource = this.getNodeParameter('resource', 0) as string; - operation = this.getNodeParameter('operation', 0) as string; requestMethod = 'GET'; endpoint = ''; @@ -1683,8 +1596,23 @@ export class Pipedrive implements INodeType { requestMethod = 'GET'; const activityId = this.getNodeParameter('activityId', i) as number; + endpoint = `/activities/${activityId}`; + } else if (operation === 'getAll') { + // ---------------------------------- + // activity:getAll + // ---------------------------------- + + requestMethod = 'GET'; + + returnAll = this.getNodeParameter('returnAll', i) as boolean; + if (returnAll === false) { + qs.limit = this.getNodeParameter('limit', i) as number; + } + + endpoint = `/activities`; + } else if (operation === 'update') { // ---------------------------------- // activity:update @@ -1732,6 +1660,20 @@ export class Pipedrive implements INodeType { const dealId = this.getNodeParameter('dealId', i) as number; endpoint = `/deals/${dealId}`; + } else if (operation === 'getAll') { + // ---------------------------------- + // deal:getAll + // ---------------------------------- + + requestMethod = 'GET'; + + returnAll = this.getNodeParameter('returnAll', i) as boolean; + if (returnAll === false) { + qs.limit = this.getNodeParameter('limit', i) as number; + } + + endpoint = `/deals`; + } else if (operation === 'update') { // ---------------------------------- // deal:update @@ -1888,6 +1830,14 @@ export class Pipedrive implements INodeType { } } + if (['get', 'getAll'].includes(operation)) { + const resolveProperties = this.getNodeParameter('resolveProperties', 0) as boolean; + + if (resolveProperties === true) { + await pipedriveResolveCustomProperties.call(this, resource, returnData); + } + } + return [this.helpers.returnJsonArray(returnData)]; } }