Add Leads to Pipedrive node (#1986)

*  Add leads to Pipedrive node

*  Make org ID required for deal:create

* 🔨 Refactor linked entity for lead:create

* 🔨 Refactor linked entity for deal:create

* ✏️ Write breaking changes

*  Improvements

* 🐛 Fix issue with returning invalid data

*  Make lead-descriptions format consistent

Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
Iván Ovejero 2021-07-20 15:53:10 +02:00 committed by GitHub
parent a8098283af
commit ce43194e91
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 794 additions and 6 deletions

View file

@ -2,6 +2,16 @@
This list shows all the versions which include breaking changes and how to upgrade.
## 0.131.0
### What changed?
For the Pipedrive regular node, the `deal:create` operation now requires an organization ID or person ID, in line with upcoming changes to the Pipedrive API.
### When is action necessary?
If you are using the `deal:create` operation in the Pipedrive regular node, set an organization ID or a person ID.
## 0.130.0
### What changed?

View file

@ -21,6 +21,10 @@ import {
pipedriveResolveCustomProperties,
} from './GenericFunctions';
import {
currencies,
} from './utils';
interface CustomProperty {
name: string;
value: string;
@ -118,6 +122,10 @@ export class Pipedrive implements INodeType {
name: 'File',
value: 'file',
},
{
name: 'Lead',
value: 'lead',
},
{
name: 'Note',
value: 'note',
@ -285,6 +293,46 @@ export class Pipedrive implements INodeType {
description: 'The operation to perform.',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'lead',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a lead',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a lead',
},
{
name: 'Get',
value: 'get',
description: 'Get data of a lead',
},
{
name: 'Get All',
value: 'getAll',
description: 'Get data of all leads',
},
{
name: 'Update',
value: 'update',
description: 'Update a lead',
},
],
default: 'create',
},
{
displayName: 'Operation',
name: 'operation',
@ -846,6 +894,75 @@ export class Pipedrive implements INodeType {
},
description: 'The title of the deal to create',
},
{
displayName: 'Associate With',
name: 'associateWith',
type: 'options',
options: [
{
name: 'Organization',
value: 'organization',
},
{
name: 'Person',
value: 'person',
},
],
default: 'organization',
description: 'Type of entity to link to this deal',
required: true,
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Organization ID',
name: 'org_id',
type: 'number',
default: 0,
description: 'ID of the organization this deal will be associated with',
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'deal',
],
associateWith: [
'organization',
],
},
},
},
{
displayName: 'Person ID',
name: 'person_id',
type: 'number',
default: 0,
description: 'ID of the person this deal will be associated with.',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'deal',
],
associateWith: [
'person',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
@ -925,18 +1042,30 @@ export class Pipedrive implements INodeType {
{
displayName: 'Organization ID',
name: 'org_id',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getOrganizationIds',
type: 'number',
default: 0,
required: true,
displayOptions: {
show: {
'/associateWith': [
'person',
],
},
},
default: '',
description: 'ID of the organization this deal will be associated with.',
description: 'ID of the organization this deal will be associated with',
},
{
displayName: 'Person ID',
name: 'person_id',
type: 'number',
default: 0,
displayOptions: {
show: {
'/associateWith': [
'organization',
],
},
},
description: 'ID of the person this deal will be associated with.',
},
{
@ -1617,7 +1746,358 @@ export class Pipedrive implements INodeType {
},
default: 0,
required: true,
description: 'ID of the file to get.',
description: 'ID of the file to get',
},
// ----------------------------------------
// lead: create
// ----------------------------------------
{
displayName: 'Title',
name: 'title',
description: 'Name of the lead to create',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Associate With',
name: 'associateWith',
type: 'options',
options: [
{
name: 'Organization',
value: 'organization',
},
{
name: 'Person',
value: 'person',
},
],
default: 'organization',
description: 'Type of entity to link to this lead',
required: true,
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Organization ID',
name: 'organization_id',
type: 'number',
default: 0,
description: 'ID of the organization to link to this lead',
required: true,
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'create',
],
associateWith: [
'organization',
],
},
},
},
{
displayName: 'Person ID',
name: 'person_id',
type: 'number',
default: 0,
description: 'ID of the person to link to this lead',
required: true,
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'create',
],
associateWith: [
'person',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Expected Close Date',
name: 'expected_close_date',
type: 'dateTime',
default: '',
description: 'Date when the leads deal is expected to be closed, in ISO-8601 format',
},
{
displayName: 'Label IDs',
name: 'label_ids',
type: 'multiOptions',
typeOptions: {
loadOptionsMethod: 'getLeadLabels',
},
default: [],
description: 'ID of the labels to attach to the lead to create',
},
{
displayName: 'Organization ID',
name: 'organization_id',
type: 'number',
default: 0,
description: 'ID of the organization to link to this lead',
displayOptions: {
show: {
'/associateWith': [
'person',
],
},
},
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getUserIds',
},
default: '',
description: 'ID of the user who will own the lead to create',
},
{
displayName: 'Person ID',
name: 'person_id',
type: 'number',
default: 0,
description: 'ID of the person to link to this lead',
displayOptions: {
show: {
'/associateWith': [
'organization',
],
},
},
},
{
displayName: 'Value',
name: 'value',
type: 'fixedCollection',
description: 'Potential monetary value associated with the lead',
default: {},
options: [
{
displayName: 'Value Properties',
name: 'valueProperties',
values: [
{
displayName: 'Amount',
name: 'amount',
type: 'number',
default: '',
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
default: 'USD',
options: currencies.sort((a, b) => a.name.localeCompare(b.name)),
},
],
},
],
},
],
},
// ----------------------------------------
// lead: delete
// ----------------------------------------
{
displayName: 'Lead ID',
name: 'leadId',
description: 'ID of the lead to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------------
// lead: get
// ----------------------------------------
{
displayName: 'Lead ID',
name: 'leadId',
description: 'ID of the lead to retrieve',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'get',
],
},
},
},
// ----------------------------------------
// lead: update
// ----------------------------------------
{
displayName: 'Lead ID',
name: 'leadId',
description: 'ID of the lead to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Title',
name: 'title',
type: 'string',
default: '',
description: 'Name of the lead to update',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getUserIds',
},
default: '',
description: 'ID of the user who will own the lead to update',
},
{
displayName: 'Label IDs',
name: 'label_ids',
type: 'multiOptions',
typeOptions: {
loadOptionsMethod: 'getLeadLabels',
},
default: [],
description: 'ID of the labels to attach to the lead to update',
},
{
displayName: 'Person ID',
name: 'person_id',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getPersons',
},
default: '',
description: 'ID of the person to link to this lead',
},
{
displayName: 'Value',
name: 'value',
type: 'fixedCollection',
description: 'Potential monetary value associated with the lead',
default: {},
options: [
{
displayName: 'Value Properties',
name: 'valueProperties',
values: [
{
displayName: 'Amount',
name: 'amount',
type: 'number',
default: '',
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
default: 'USD',
options: currencies.sort((a, b) => a.name.localeCompare(b.name)),
},
],
},
],
},
{
displayName: 'Expected Close Date',
name: 'expected_close_date',
type: 'dateTime',
default: '',
description: 'Date when the leads deal is expected to be closed, in ISO-8601 format',
},
],
},
@ -2487,6 +2967,49 @@ export class Pipedrive implements INodeType {
description: 'How many results to return.',
},
// ----------------------------------------
// lead: getAll
// ----------------------------------------
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: [
'lead',
],
operation: [
'getAll',
],
},
},
options: [
{
displayName: 'Archived Status',
name: 'archived_status',
type: 'options',
default: 'all',
options: [
{
name: 'Archived',
value: 'archived',
},
{
name: 'All',
value: 'all',
},
{
name: 'Not Archived',
value: 'not_archived',
},
],
},
],
},
// ----------------------------------
// person:getAll
// ----------------------------------
@ -2981,6 +3504,27 @@ export class Pipedrive implements INodeType {
}
return returnData;
},
// Get all the persons to display them to user so that he can
// select them easily
async getPersons(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const { data } = await pipedriveApiRequest.call(this, 'GET', '/persons', {}) as {
data: Array<{ id: string; name: string; }>
};
return data.map(({ id, name }) => ({ value: id, name }));
},
// Get all the lead labels to display them to user so that he can
// select them easily
async getLeadLabels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const { data } = await pipedriveApiRequest.call(this, 'GET', '/leadLabels', {}) as {
data: Array<{ id: string; name: string; }>
};
return data.map(({ id, name }) => ({ value: id, name }));
},
// Get all the labels to display them to user so that he can
// select them easily
async getDealLabels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
@ -3147,6 +3691,15 @@ export class Pipedrive implements INodeType {
endpoint = '/deals';
body.title = this.getNodeParameter('title', i) as string;
const associateWith = this.getNodeParameter('associateWith', i) as 'organization' | 'person';
if (associateWith === 'organization') {
body.org_id = this.getNodeParameter('org_id', i) as string;
} else {
body.person_id = this.getNodeParameter('person_id', i) as string;
}
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
addAdditionalFields(body, additionalFields);
@ -3376,6 +3929,140 @@ export class Pipedrive implements INodeType {
addAdditionalFields(body, updateFields);
}
} else if (resource === 'lead') {
if (operation === 'create') {
// ----------------------------------------
// lead: create
// ----------------------------------------
// https://developers.pipedrive.com/docs/api/v1/Leads#addLead
body = {
title: this.getNodeParameter('title', i),
} as IDataObject;
const associateWith = this.getNodeParameter('associateWith', i) as 'organization' | 'person';
if (associateWith === 'organization') {
body.organization_id = this.getNodeParameter('organization_id', i) as number;
} else {
body.person_id = this.getNodeParameter('person_id', i) as number;
}
const { value, expected_close_date, ...rest } = this.getNodeParameter('additionalFields', i) as {
value: {
valueProperties: {
amount: number;
currency: string;
}
};
expected_close_date: string;
person_id: number,
organization_id: number,
};
if (Object.keys(rest).length) {
Object.assign(body, rest);
}
if (value) {
Object.assign(body, { value: value.valueProperties });
}
if (expected_close_date) {
body.expected_close_date = expected_close_date.split('T')[0];
}
requestMethod = 'POST';
endpoint = '/leads';
} else if (operation === 'delete') {
// ----------------------------------------
// lead: delete
// ----------------------------------------
// https://developers.pipedrive.com/docs/api/v1/Leads#deleteLead
const leadId = this.getNodeParameter('leadId', i);
requestMethod = 'DELETE';
endpoint = `/leads/${leadId}`;
} else if (operation === 'get') {
// ----------------------------------------
// lead: get
// ----------------------------------------
// https://developers.pipedrive.com/docs/api/v1/Leads#getLead
const leadId = this.getNodeParameter('leadId', i);
requestMethod = 'GET';
endpoint = `/leads/${leadId}`;
} else if (operation === 'getAll') {
// ----------------------------------------
// lead: getAll
// ----------------------------------------
// https://developers.pipedrive.com/docs/api/v1/Leads#getLeads
const filters = this.getNodeParameter('filters', i) as IDataObject;
if (Object.keys(filters).length) {
Object.assign(qs, filters);
}
requestMethod = 'GET';
endpoint = '/leads';
} else if (operation === 'update') {
// ----------------------------------------
// lead: update
// ----------------------------------------
// https://developers.pipedrive.com/docs/api/v1/Leads#updateLead
const { value, expected_close_date, ...rest } = this.getNodeParameter('updateFields', i) as {
value: {
valueProperties: {
amount: number;
currency: string;
}
};
expected_close_date: string;
};
if (Object.keys(rest).length) {
Object.assign(body, rest);
}
if (value) {
Object.assign(body, { value: value.valueProperties });
}
if (expected_close_date) {
body.expected_close_date = expected_close_date.split('T')[0];
}
if (Object.keys(rest).length) {
Object.assign(body, rest);
}
const leadId = this.getNodeParameter('leadId', i);
requestMethod = 'PATCH';
endpoint = `/leads/${leadId}`;
}
} else if (resource === 'organization') {
if (operation === 'create') {
// ----------------------------------
@ -3624,6 +4311,8 @@ export class Pipedrive implements INodeType {
if (Array.isArray(responseData.data)) {
returnData.push.apply(returnData, responseData.data as IDataObject[]);
} else if (responseData.data === true) {
returnData.push({ success: true });
} else {
returnData.push(responseData.data as IDataObject);
}

View file

@ -0,0 +1,89 @@
export const currencies = [
{ name: 'US Dollar', value: 'USD' },
{ name: 'Euro', value: 'EUR' },
{ name: 'UAE Dirham', value: 'AED' },
{ name: 'Afghani', value: 'AFN' },
{ name: 'Lek', value: 'ALL' },
{ name: 'Argentine Peso', value: 'ARS' },
{ name: 'Australian Dollar', value: 'AUD' },
{ name: 'Azerbaijan Manat', value: 'AZN' },
{ name: 'Barbados Dollar', value: 'BBD' },
{ name: 'Taka', value: 'BDT' },
{ name: 'Bulgarian Lev', value: 'BGN' },
{ name: 'Bermudian Dollar', value: 'BMD' },
{ name: 'Brunei Dollar', value: 'BND' },
{ name: 'Boliviano', value: 'BOB' },
{ name: 'Brazilian Real', value: 'BRL' },
{ name: 'Bahamian Dollar', value: 'BSD' },
{ name: 'Pula', value: 'BWP' },
{ name: 'Belize Dollar', value: 'BZD' },
{ name: 'Canadian Dollar', value: 'CAD' },
{ name: 'Swiss Franc', value: 'CHF' },
{ name: 'Chilean Peso', value: 'CLP' },
{ name: 'Yuan Renminbi', value: 'CNY' },
{ name: 'Colombian Peso', value: 'COP' },
{ name: 'Costa Rican Colon', value: 'CRC' },
{ name: 'Czech Koruna', value: 'CZK' },
{ name: 'Danish Krone', value: 'DKK' },
{ name: 'Dominican Peso', value: 'DOP' },
{ name: 'Algerian Dinar', value: 'DZD' },
{ name: 'Egyptian Pound', value: 'EGP' },
{ name: 'Fiji Dollar', value: 'FJD' },
{ name: 'Pound Sterling', value: 'GBP' },
{ name: 'Quetzal', value: 'GTQ' },
{ name: 'Hong Kong Dollar', value: 'HKD' },
{ name: 'Lempira', value: 'HNL' },
{ name: 'Kuna', value: 'HRK' },
{ name: 'Forint', value: 'HUF' },
{ name: 'Rupiah', value: 'IDR' },
{ name: 'New Israeli Sheqel', value: 'ILS' },
{ name: 'Indian Rupee', value: 'INR' },
{ name: 'Jamaican Dollar', value: 'JMD' },
{ name: 'Yen', value: 'JPY' },
{ name: 'Kenyan Shilling', value: 'KES' },
{ name: 'Won', value: 'KRW' },
{ name: 'Tenge', value: 'KZT' },
{ name: 'Lao Kip', value: 'LAK' },
{ name: 'Lebanese Pound', value: 'LBP' },
{ name: 'Sri Lanka Rupee', value: 'LKR' },
{ name: 'Liberian Dollar', value: 'LRD' },
{ name: 'Moroccan Dirham', value: 'MAD' },
{ name: 'Kyat', value: 'MMK' },
{ name: 'Pataca', value: 'MOP' },
{ name: 'Ouguiya', value: 'MRO' },
{ name: 'Mauritius Rupee', value: 'MUR' },
{ name: 'Rufiyaa', value: 'MVR' },
{ name: 'Mexican Peso', value: 'MXN' },
{ name: 'Malaysian Ringgit', value: 'MYR' },
{ name: 'Cordoba Oro', value: 'NIO' },
{ name: 'Norwegian Krone', value: 'NOK' },
{ name: 'Nepalese Rupee', value: 'NPR' },
{ name: 'New Zealand Dollar', value: 'NZD' },
{ name: 'Sol', value: 'PEN' },
{ name: 'Kina', value: 'PGK' },
{ name: 'Philippine Peso', value: 'PHP' },
{ name: 'Pakistan Rupee', value: 'PKR' },
{ name: 'Zloty', value: 'PLN' },
{ name: 'Qatari Rial', value: 'QAR' },
{ name: 'Romanian Leu', value: 'RON' },
{ name: 'Russian Ruble', value: 'RUB' },
{ name: 'Saudi Riyal', value: 'SAR' },
{ name: 'Solomon Islands Dollar ', value: 'SBD' },
{ name: 'Seychelles Rupee', value: 'SCR' },
{ name: 'Swedish Krona', value: 'SEK' },
{ name: 'Singapore Dollar', value: 'SGD' },
{ name: 'Syrian Pound', value: 'SYP' },
{ name: 'Baht', value: 'THB' },
{ name: 'Paanga', value: 'TOP' },
{ name: 'Turkish Lira', value: 'TRY' },
{ name: 'Trinidad and Tobago Dollar', value: 'TTD' },
{ name: 'New Taiwan Dollar', value: 'TWD' },
{ name: 'Hryvnia', value: 'UAH' },
{ name: 'Dong', value: 'VND' },
{ name: 'Vatu', value: 'VUV' },
{ name: 'Tala', value: 'WST' },
{ name: 'East Caribbean Dollar', value: 'XCD' },
{ name: 'West African CFA Franc', value: 'XOF' },
{ name: 'Yemeni Rial', value: 'YER' },
{ name: 'Rand', value: 'ZAR' },
];