diff --git a/packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts b/packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts
new file mode 100644
index 0000000000..23739bf118
--- /dev/null
+++ b/packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts
@@ -0,0 +1,40 @@
+import {
+ ICredentialType,
+ NodePropertyTypes,
+} from 'n8n-workflow';
+
+export class SalesforceOAuth2Api implements ICredentialType {
+ name = 'salesforceOAuth2Api';
+ extends = [
+ 'oAuth2Api',
+ ];
+ displayName = 'Salesforce OAuth2 API';
+ properties = [
+ {
+ displayName: 'Authorization URL',
+ name: 'authUrl',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'https://login.salesforce.com/services/oauth2/authorize',
+ required: true,
+ },
+ {
+ displayName: 'Access Token URL',
+ name: 'accessTokenUrl',
+ type: 'string' as NodePropertyTypes,
+ default: 'https://yourcompany.salesforce.com/services/oauth2/token',
+ required: true,
+ },
+ {
+ displayName: 'Scope',
+ name: 'scope',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'full',
+ },
+ {
+ displayName: 'Auth URI Query Parameters',
+ name: 'authQueryParameters',
+ type: 'hidden' as NodePropertyTypes,
+ default: '',
+ },
+ ];
+}
diff --git a/packages/nodes-base/nodes/Salesforce/AccountDescription.ts b/packages/nodes-base/nodes/Salesforce/AccountDescription.ts
new file mode 100644
index 0000000000..0c9d336065
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/AccountDescription.ts
@@ -0,0 +1,700 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const accountOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create an account',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update an account',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get an account',
+ },
+ {
+ name: 'Get Summary',
+ value: 'getSummary',
+ description: `Returns an overview of account's metadata.`,
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all accounts',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete an account',
+ },
+ {
+ name: 'Add Note',
+ value: 'addNote',
+ description: 'Add note to an account',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const accountFields = [
+
+/* -------------------------------------------------------------------------- */
+/* account:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Name',
+ name: 'name',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'create',
+ ]
+ },
+ },
+ description: 'Name of the account. Maximum size is 255 characters.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fax',
+ name: 'fax',
+ type: 'string',
+ default: '',
+ description: 'Fax number for the account.',
+ },
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getAccountTypes',
+ },
+ description: 'Type of account',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the account.',
+ },
+ {
+ displayName: 'Jigsaw',
+ name: 'jigsaw',
+ type: 'string',
+ default: '',
+ description: 'references the ID of a company in Data.com',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the account.',
+ },
+ {
+ displayName: 'SicDesc',
+ name: 'sicDesc',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'A brief description of an organization’s line of business, based on its SIC code.',
+ },
+ {
+ displayName: 'Website',
+ name: 'website',
+ type: 'string',
+ default: '',
+ description: 'The website of this account. Maximum of 255 characters.',
+ },
+ {
+ displayName: 'Industry',
+ name: 'industry',
+ type: 'string',
+ default: '',
+ description: 'The website of this account. Maximum of 255 characters.',
+ },
+ {
+ displayName: 'Parent Id',
+ name: 'parentId',
+ type: 'string',
+ default: '',
+ description: 'ID of the parent object, if any.',
+ },
+ {
+ displayName: 'Billing City',
+ name: 'billingCity',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 40 characters.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Text description of the account. Limited to 32,000 KB.',
+ },
+ {
+ displayName: 'Billing State',
+ name: 'billingState',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Shipping City',
+ name: 'shippingCity',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. City maximum size is 40 characters',
+ },
+ {
+ displayName: 'Account Source',
+ name: 'accountSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getAccountSources',
+ },
+ default: '',
+ description: 'The source of the account record',
+ },
+ {
+ displayName: 'Annual Revenue',
+ name: 'annualRevenue',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 2,
+ },
+ default: '',
+ description: 'Estimated annual revenue of the account.',
+ },
+ {
+ displayName: 'Billing Street',
+ name: 'billingStreet',
+ type: 'string',
+ default: '',
+ description: 'Street address for the billing address of this account.',
+ },
+ {
+ displayName: 'Shipping State',
+ name: 'shippingState',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. State maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Billing Country',
+ name: 'billingCountry',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Shipping Street',
+ name: 'shippingStreet',
+ type: 'string',
+ default: '',
+ description: 'The street address of the shipping address for this account. Maximum of 255 characters.',
+ },
+ {
+ displayName: 'Shipping Country',
+ name: 'shippingCountry',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. Country maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Billing Postal Code',
+ name: 'billingPostalCode',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 20 characters.',
+ },
+ {
+ displayName: 'Number Of Employees',
+ name: 'numberOfEmployees',
+ type: 'integer',
+ default: '',
+ description: 'Number of employees',
+ },
+ {
+ displayName: 'Shipping Postal Code',
+ name: 'shippingPostalCode',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. Postal code maximum size is 20 characters.',
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* account:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Account ID',
+ name: 'accountId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'update',
+ ]
+ },
+ },
+ description: 'Id of account that needs to be fetched',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'update',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Name',
+ name: 'name',
+ type: 'string',
+ default: '',
+ description: 'Name of the account. Maximum size is 255 characters.',
+ },
+ {
+ displayName: 'Fax',
+ name: 'fax',
+ type: 'string',
+ default: '',
+ description: 'Fax number for the account.',
+ },
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getAccountTypes',
+ },
+ description: 'Type of account',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the account.',
+ },
+ {
+ displayName: 'Jigsaw',
+ name: 'jigsaw',
+ type: 'string',
+ default: '',
+ description: 'references the ID of a company in Data.com',
+ },
+ {
+ displayName: 'Owner',
+ name: 'ownerId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the account.',
+ },
+ {
+ displayName: 'SicDesc',
+ name: 'sicDesc',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'A brief description of an organization’s line of business, based on its SIC code.',
+ },
+ {
+ displayName: 'Website',
+ name: 'website',
+ type: 'string',
+ default: '',
+ description: 'The website of this account. Maximum of 255 characters.',
+ },
+ {
+ displayName: 'Industry',
+ name: 'industry',
+ type: 'string',
+ default: '',
+ description: 'The website of this account. Maximum of 255 characters.',
+ },
+ {
+ displayName: 'Parent Id',
+ name: 'parentId',
+ type: 'string',
+ default: '',
+ description: 'ID of the parent object, if any.',
+ },
+ {
+ displayName: 'Billing City',
+ name: 'billingCity',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 40 characters.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Text description of the account. Limited to 32,000 KB.',
+ },
+ {
+ displayName: 'Billing State',
+ name: 'billingState',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Shipping City',
+ name: 'shippingCity',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. City maximum size is 40 characters',
+ },
+ {
+ displayName: 'Account Source',
+ name: 'accountSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getAccountSources',
+ },
+ default: '',
+ description: 'The source of the account record',
+ },
+ {
+ displayName: 'Annual Revenue',
+ name: 'annualRevenue',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 2,
+ },
+ default: '',
+ description: 'Estimated annual revenue of the account.',
+ },
+ {
+ displayName: 'Billing Street',
+ name: 'billingStreet',
+ type: 'string',
+ default: '',
+ description: 'Street address for the billing address of this account.',
+ },
+ {
+ displayName: 'Shipping State',
+ name: 'shippingState',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. State maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Billing Country',
+ name: 'billingCountry',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Shipping Street',
+ name: 'shippingStreet',
+ type: 'string',
+ default: '',
+ description: 'The street address of the shipping address for this account. Maximum of 255 characters.',
+ },
+ {
+ displayName: 'Shipping Country',
+ name: 'shippingCountry',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. Country maximum size is 80 characters.',
+ },
+ {
+ displayName: 'Billing Postal Code',
+ name: 'billingPostalCode',
+ type: 'string',
+ default: '',
+ description: 'Details for the billing address of this account. Maximum size is 20 characters.',
+ },
+ {
+ displayName: 'Number Of Employees',
+ name: 'numberOfEmployees',
+ type: 'integer',
+ default: '',
+ description: 'Number of employees',
+ },
+ {
+ displayName: 'Shipping Postal Code',
+ name: 'shippingPostalCode',
+ type: 'string',
+ default: '',
+ description: 'Details of the shipping address for this account. Postal code maximum size is 20 characters.',
+ },
+ ],
+ },
+
+/* -------------------------------------------------------------------------- */
+/* account:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Account ID',
+ name: 'accountId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'get',
+ ]
+ },
+ },
+ description: 'Id of account that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* account:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Account ID',
+ name: 'accountId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'delete',
+ ]
+ },
+ },
+ description: 'Id of account that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* account:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ 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: [
+ 'account',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 50,
+ description: 'How many results to return.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fields',
+ name: 'fields',
+ type: 'string',
+ default: '',
+ description: 'Fields to include separated by ,',
+ },
+ ]
+ },
+/* -------------------------------------------------------------------------- */
+/* account:addNote */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Account ID',
+ name: 'accountId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Id of account that needs to be fetched',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Title of the note.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'account',
+ ],
+ operation: [
+ 'addNote',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Body',
+ name: 'body',
+ type: 'string',
+ default: '',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'Body of the note. Limited to 32 KB.',
+ },
+ {
+ displayName: 'Owner',
+ name: 'ownerId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the user who owns the note.',
+ },
+ {
+ displayName: 'Is Private',
+ name: 'isPrivate',
+ type: 'boolean',
+ default: false,
+ description: 'If true, only the note owner or a user with the “Modify All Data” permission can view the note or query it via the API',
+ },
+ ]
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Salesforce/AccountInterface.ts b/packages/nodes-base/nodes/Salesforce/AccountInterface.ts
new file mode 100644
index 0000000000..c42b485105
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/AccountInterface.ts
@@ -0,0 +1,26 @@
+export interface IAccount {
+ Name?: string;
+ Fax?: string;
+ Type?: string;
+ Phone?: string;
+ Jigsaw?: string;
+ OwnerId?: string;
+ SicDesc?: string;
+ Website?: string;
+ Industry?: string;
+ ParentId?: string;
+ BillingCity?: string;
+ Description?: string;
+ BillingState?: string;
+ ShippingStreet?: string;
+ ShippingCity?:string;
+ AccountSource?: string;
+ AnnualRevenue?: number;
+ BillingStreet?: string;
+ ShippingState?: string;
+ BillingCountry?: string;
+ ShippingCountry?: string;
+ BillingPostalCode?: string;
+ NumberOfEmployees?: string;
+ ShippingPostalCode?: string;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/AttachmentDescription.ts b/packages/nodes-base/nodes/Salesforce/AttachmentDescription.ts
new file mode 100644
index 0000000000..60158a7e52
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/AttachmentDescription.ts
@@ -0,0 +1,347 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const attachmentOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a attachment',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update a attachment',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a attachment',
+ },
+ {
+ name: 'Get Summary',
+ value: 'getSummary',
+ description: `Returns an overview of attachment's metadata.`,
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all attachments',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete a attachment',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const attachmentFields = [
+
+/* -------------------------------------------------------------------------- */
+/* attachment:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Parent ID',
+ name: 'parentId',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'create'
+ ],
+ },
+ },
+ description: '',
+ },
+ {
+ displayName: 'Name',
+ name: 'name',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'create'
+ ],
+ },
+ },
+ description: 'Required. Name of the attached file. Maximum size is 255 characters. Label is File Name.',
+ },
+ {
+ displayName: 'Binary Property',
+ name: 'binaryPropertyName',
+ type: 'string',
+ default: 'data',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'create'
+ ],
+ },
+ },
+ placeholder: '',
+ description: 'Name of the binary property which contains
the data for the file to be uploaded.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the User who owns the attachment.',
+ },
+ {
+ displayName: 'Is Private',
+ name: 'isPrivate',
+ type: 'boolean',
+ default: false,
+ description: 'Indicates whether this record is viewable only by the owner and administrators (true) or viewable by all otherwise-allowed users (false). ',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: `Text description of the Document. Limit: 255 characters.`,
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* attachment:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Attachment ID',
+ name: 'attachmentId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'update',
+ ]
+ },
+ },
+ description: 'Id of attachment that needs to be fetched',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'update',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Name',
+ name: 'name',
+ type: 'string',
+ default: '',
+ description: 'Required. Name of the attached file. Maximum size is 255 characters. Label is File Name.',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the User who owns the attachment.',
+ },
+ {
+ displayName: 'Is Private',
+ name: 'isPrivate',
+ type: 'boolean',
+ default: false,
+ description: 'Indicates whether this record is viewable only by the owner and administrators (true) or viewable by all otherwise-allowed users (false). ',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: `Text description of the Document. Limit: 255 characters.`,
+ },
+ {
+ displayName: 'Binary Property',
+ name: 'binaryPropertyName',
+ type: 'string',
+ default: 'data',
+ placeholder: '',
+ description: 'Name of the binary property which contains
the data for the file to be uploaded.',
+ },
+ ],
+ },
+
+/* -------------------------------------------------------------------------- */
+/* attachment:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Attachment ID',
+ name: 'attachmentId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'get',
+ ]
+ },
+ },
+ description: 'Id of attachment that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* attachment:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Attachment ID',
+ name: 'attachmentId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'delete',
+ ]
+ },
+ },
+ description: 'Id of attachment that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* attachment:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ 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: [
+ 'attachment',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 50,
+ description: 'How many results to return.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'attachment',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fields',
+ name: 'fields',
+ type: 'string',
+ default: '',
+ description: 'Fields to include separated by ,',
+ },
+ ]
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Salesforce/AttachmentInterface.ts b/packages/nodes-base/nodes/Salesforce/AttachmentInterface.ts
new file mode 100644
index 0000000000..e63558a496
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/AttachmentInterface.ts
@@ -0,0 +1,10 @@
+
+export interface IAttachment {
+ ParentId?: string;
+ Name?: string;
+ Body?: string;
+ OwnerId?: string;
+ IsPrivate?: boolean;
+ ContentType?: string;
+ Description?: string;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/CampaignMemberInterface.ts b/packages/nodes-base/nodes/Salesforce/CampaignMemberInterface.ts
new file mode 100644
index 0000000000..3b025c0ce9
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/CampaignMemberInterface.ts
@@ -0,0 +1,7 @@
+
+export interface ICampaignMember {
+ CampaignId?: string;
+ ContactId?: string;
+ LeadId?: string;
+ Status?: string;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/CaseDescription.ts b/packages/nodes-base/nodes/Salesforce/CaseDescription.ts
new file mode 100644
index 0000000000..9b9c458bac
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/CaseDescription.ts
@@ -0,0 +1,563 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const caseOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a case',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update a case',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a case',
+ },
+ {
+ name: 'Get Summary',
+ value: 'getSummary',
+ description: `Returns an overview of case's metadata.`,
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all cases',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete a case',
+ },
+ {
+ name: 'Add Comment',
+ value: 'addComment',
+ description: 'Add a comment to a case',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const caseFields = [
+
+/* -------------------------------------------------------------------------- */
+/* case:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ required: true,
+ typeOptions: {
+ loadOptionsMethod: 'getCaseTypes',
+ },
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ default: '',
+ description: 'The type of case',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Origin',
+ name: 'origin',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCaseOrigins',
+ },
+ default: '',
+ description: 'The source of the case, such as Email, Phone, or Web. Label is Case Origin.',
+ },
+ {
+ displayName: 'Reason',
+ name: 'reason',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCaseReasons',
+ },
+ default: '',
+ description: 'The reason why the case was created, such as Instructions not clear, or User didn’t attend training.',
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCaseStatuses',
+ },
+ default: '',
+ description: 'The status of the case, such as “New,” “Closed,” or “Escalated.” This field directly controls the IsClosed flag',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the case.',
+ },
+ {
+ displayName: 'Subject',
+ name: 'subject',
+ type: 'string',
+ default: '',
+ description: 'The subject of the case. Limit: 255 characters.',
+ },
+ {
+ displayName: 'Parent Id',
+ name: 'ParentId',
+ type: 'string',
+ default: '',
+ description: 'The ID of the parent case in the hierarchy. The label is Parent Case.',
+ },
+ {
+ displayName: 'Priority',
+ name: 'priority',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCasePriorities',
+ },
+ default: '',
+ description: 'The importance or urgency of the case, such as High, Medium, or Low.',
+ },
+ {
+ displayName: 'Account Id',
+ name: 'accountId',
+ type: 'string',
+ default: '',
+ description: 'ID of the account associated with this case.',
+ },
+ {
+ displayName: 'Contact Id',
+ name: 'contactId',
+ type: 'string',
+ default: '',
+ description: 'IID of the associated Contact.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: 'A text description of the case. Limit: 32 KB.',
+ },
+ {
+ displayName: 'Is Escalated',
+ name: 'isEscalated',
+ type: 'boolean',
+ default: false,
+ description: 'Indicates whether the case has been escalated (true) or not.',
+ },
+ {
+ displayName: 'Supplied Name',
+ name: 'suppliedName',
+ type: 'string',
+ default: '',
+ description: `The name that was entered when the case was created. This field can't be updated after the case has been created`,
+ },
+ {
+ displayName: 'Supplied Email',
+ name: 'suppliedEmail',
+ type: 'string',
+ default: '',
+ description: `The email address that was entered when the case was created. This field can't be updated after the case has been created.`,
+ },
+ {
+ displayName: 'Supplied Phone',
+ name: 'suppliedPhone',
+ type: 'string',
+ default: '',
+ description: `The phone number that was entered when the case was created. This field can't be updated after the case has been created.`,
+ },
+ {
+ displayName: 'Supplied Company',
+ name: 'suppliedCompany',
+ type: 'string',
+ default: '',
+ description: `The company name that was entered when the case was created. This field can't be updated after the case has been created..`,
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* case:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Case ID',
+ name: 'caseId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'update',
+ ]
+ },
+ },
+ description: 'Id of case that needs to be fetched',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'update',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCaseTypes',
+ },
+ default: '',
+ description: 'The type of case',
+ },
+ {
+ displayName: 'Origin',
+ name: 'origin',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCaseOrigins',
+ },
+ default: '',
+ description: 'The source of the case, such as Email, Phone, or Web. Label is Case Origin.',
+ },
+ {
+ displayName: 'Reason',
+ name: 'reason',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCaseReasons',
+ },
+ default: '',
+ description: 'The reason why the case was created, such as Instructions not clear, or User didn’t attend training.',
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCaseStatuses',
+ },
+ default: '',
+ description: 'The status of the case, such as “New,” “Closed,” or “Escalated.” This field directly controls the IsClosed flag',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the case.',
+ },
+ {
+ displayName: 'Subject',
+ name: 'subject',
+ type: 'string',
+ default: '',
+ description: 'The subject of the case. Limit: 255 characters.',
+ },
+ {
+ displayName: 'Parent Id',
+ name: 'ParentId',
+ type: 'string',
+ default: '',
+ description: 'The ID of the parent case in the hierarchy. The label is Parent Case.',
+ },
+ {
+ displayName: 'Priority',
+ name: 'priority',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCasePriorities',
+ },
+ default: '',
+ description: 'The importance or urgency of the case, such as High, Medium, or Low.',
+ },
+ {
+ displayName: 'Account Id',
+ name: 'accountId',
+ type: 'string',
+ default: '',
+ description: 'ID of the account associated with this case.',
+ },
+ {
+ displayName: 'Contact Id',
+ name: 'contactId',
+ type: 'string',
+ default: '',
+ description: 'IID of the associated Contact.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: 'A text description of the case. Limit: 32 KB.',
+ },
+ {
+ displayName: 'Is Escalated',
+ name: 'isEscalated',
+ type: 'boolean',
+ default: false,
+ description: 'Indicates whether the case has been escalated (true) or not.',
+ },
+ {
+ displayName: 'Supplied Name',
+ name: 'suppliedName',
+ type: 'string',
+ default: '',
+ description: `The name that was entered when the case was created. This field can't be updated after the case has been created`,
+ },
+ {
+ displayName: 'Supplied Email',
+ name: 'suppliedEmail',
+ type: 'string',
+ default: '',
+ description: `The email address that was entered when the case was created. This field can't be updated after the case has been created.`,
+ },
+ {
+ displayName: 'Supplied Phone',
+ name: 'suppliedPhone',
+ type: 'string',
+ default: '',
+ description: `The phone number that was entered when the case was created. This field can't be updated after the case has been created.`,
+ },
+ {
+ displayName: 'Supplied Company',
+ name: 'suppliedCompany',
+ type: 'string',
+ default: '',
+ description: `The company name that was entered when the case was created. This field can't be updated after the case has been created..`,
+ },
+ ],
+ },
+
+/* -------------------------------------------------------------------------- */
+/* case:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Case ID',
+ name: 'caseId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'get',
+ ]
+ },
+ },
+ description: 'Id of case that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* case:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Case ID',
+ name: 'caseId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'delete',
+ ]
+ },
+ },
+ description: 'Id of case that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* case:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ 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: [
+ 'case',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 50,
+ description: 'How many results to return.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fields',
+ name: 'fields',
+ type: 'string',
+ default: '',
+ description: 'Fields to include separated by ,',
+ },
+ ]
+ },
+
+/* -------------------------------------------------------------------------- */
+/* case:addComment */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Case ID',
+ name: 'caseId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'addComment',
+ ]
+ },
+ },
+ description: 'Id of case that needs to be fetched',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'case',
+ ],
+ operation: [
+ 'addComment',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Comment Body',
+ name: 'commentBody',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Text of the CaseComment. The maximum size of the comment body is 4,000 bytes. Label is Body.',
+ },
+ {
+ displayName: 'Is Published',
+ name: 'isPublished',
+ type: 'boolean',
+ default: false,
+ description: 'Indicates whether the CaseComment is visible to customers in the Self-Service portal (true) or not (false). ',
+ },
+ ]
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Salesforce/CaseInterface.ts b/packages/nodes-base/nodes/Salesforce/CaseInterface.ts
new file mode 100644
index 0000000000..169d47c14d
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/CaseInterface.ts
@@ -0,0 +1,25 @@
+
+export interface ICase {
+ Type?: string;
+ Origin?: string;
+ Reason?: string;
+ Status?: string;
+ OwnerId?: string;
+ Subject?: string;
+ ParentId?: string;
+ Priority?: string;
+ AccountId?: string;
+ ContactId?: string;
+ Description?: string;
+ IsEscalated?: boolean;
+ SuppliedName?: string;
+ SuppliedEmail?: string;
+ SuppliedPhone?: string;
+ SuppliedCompany?: string;
+}
+
+export interface ICaseComment {
+ CommentBody?: string;
+ ParentId?: string;
+ IsPublished?: boolean;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/ContactDescription.ts b/packages/nodes-base/nodes/Salesforce/ContactDescription.ts
new file mode 100644
index 0000000000..bda804e6d6
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/ContactDescription.ts
@@ -0,0 +1,835 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const contactOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a contact',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update a contact',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a contact',
+ },
+ {
+ name: 'Get Summary',
+ value: 'getSummary',
+ description: `Returns an overview of contact's metadata.`,
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all contacts',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete a contact',
+ },
+ {
+ name: 'Add Lead To Campaign',
+ value: 'addToCampaign',
+ description: 'Add lead to a campaign',
+ },
+ {
+ name: 'Add Note',
+ value: 'addNote',
+ description: 'Add note to a contact',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const contactFields = [
+
+/* -------------------------------------------------------------------------- */
+/* contact:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Last Name',
+ name: 'lastname',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'create',
+ ]
+ },
+ },
+ description: 'Required. Last name of the contact. Limited to 80 characters.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fax',
+ name: 'fax',
+ type: 'string',
+ default: '',
+ description: 'Fax number for the contact. Label is Business Fax.',
+ },
+ {
+ displayName: 'Email',
+ name: 'email',
+ type: 'string',
+ default: '',
+ description: 'Email address for the contact.',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the contact.',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ default: '',
+ description: 'Title of the contact such as CEO or Vice President.',
+ },
+ {
+ displayName: 'Jigsaw',
+ name: 'jigsaw',
+ type: 'string',
+ default: '',
+ description: `references the ID of a contact in Data.com.
+ If a contact has a value in this field, it means that a contact was imported as a contact from Data.com.`,
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the contact.',
+ },
+ {
+ displayName: 'Account',
+ name: 'acconuntId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getAccounts',
+ },
+ default: '',
+ description: 'ID of the account that is the parent of this contact.',
+ },
+ {
+ displayName: 'Birthdate',
+ name: 'birthdate',
+ type: 'string',
+ default: '',
+ description: 'The birthdate of the contact.',
+ },
+ {
+ displayName: 'First Name',
+ name: 'firstName',
+ type: 'string',
+ default: '',
+ description: 'First name of the contact. Maximum size is 40 characters.',
+ },
+ {
+ displayName: 'Home Phone',
+ name: 'homePhone',
+ type: 'string',
+ default: '',
+ description: 'Home telephone number for the contact',
+ },
+ {
+ displayName: 'Other City',
+ name: 'otherCity',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Department',
+ name: 'department',
+ type: 'string',
+ default: '',
+ description: 'The department of the contact.',
+ },
+ {
+ displayName: 'Lead Source',
+ name: 'leadSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadSources',
+ },
+ default: '',
+ description: 'Source from which the lead was obtained.',
+ },
+ {
+ displayName: 'Other Phone',
+ name: 'otherPhone',
+ type: 'string',
+ default: '',
+ description: 'Telephone for alternate address.',
+ },
+ {
+ displayName: 'Other State',
+ name: 'otherState',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Salutation',
+ name: 'salutation',
+ type: 'string',
+ default: '',
+ description: 'Honorific abbreviation, word, or phrase to be used in front of name in greetings, such as Dr. or Mrs.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: 'A description of the contact. Label is Contact Description. Limit: 32 KB.',
+ },
+ {
+ displayName: 'Mailing City',
+ name: 'mailingCity',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Mobile Phone',
+ name: 'mobilePhone',
+ type: 'string',
+ default: '',
+ description: `Contact’s mobile phone number.`,
+ },
+ {
+ displayName: 'Other Street',
+ name: 'otherStreet',
+ type: 'string',
+ default: '',
+ description: 'Street for alternate address.',
+ },
+ {
+ displayName: 'Mailing State',
+ name: 'mailingState',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Other Country',
+ name: 'otherCountry',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Assistant Name',
+ name: 'assistantName',
+ type: 'string',
+ default: '',
+ description: 'The name of the assistant.',
+ },
+ {
+ displayName: 'Mailing Street',
+ name: 'mailingStreet',
+ type: 'string',
+ default: '',
+ description: 'Street address for mailing address.',
+ },
+ {
+ displayName: 'Assistant Phone',
+ name: 'Assistant Phone',
+ type: 'string',
+ default: '',
+ description: 'The telephone number of the assistant.',
+ },
+ {
+ displayName: 'Mailing Country',
+ name: 'mailingCountry',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Other Postal Code',
+ name: 'otherPostalCode',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Email Bounced Date',
+ name: 'otherPostalCode',
+ type: 'dateTime',
+ default: '',
+ description: 'If bounce management is activated and an email sent to the contact bounces, the date and time the bounce occurred.',
+ },
+ {
+ displayName: 'Mailing Postal Code',
+ name: 'mailingPostalCode',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Email Bounced Reason',
+ name: 'emailBouncedReason',
+ type: 'string',
+ default: '',
+ description: 'If bounce management is activated and an email sent to the contact bounces, the reason the bounce occurred.',
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* contact:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Contact ID',
+ name: 'contactId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'update',
+ ]
+ },
+ },
+ description: 'Id of contact that needs to be fetched',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'update',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fax',
+ name: 'fax',
+ type: 'string',
+ default: '',
+ description: 'Fax number for the contact. Label is Business Fax.',
+ },
+ {
+ displayName: 'Email',
+ name: 'email',
+ type: 'string',
+ default: '',
+ description: 'Email address for the contact.',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the contact.',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ default: '',
+ description: 'Title of the contact such as CEO or Vice President.',
+ },
+ {
+ displayName: 'Jigsaw',
+ name: 'jigsaw',
+ type: 'string',
+ default: '',
+ description: `references the ID of a contact in Data.com.
+ If a contact has a value in this field, it means that a contact was imported as a contact from Data.com.`,
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the contact.',
+ },
+ {
+ displayName: 'Account',
+ name: 'acconuntId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getAccounts',
+ },
+ default: '',
+ description: 'ID of the account that is the parent of this contact.',
+ },
+ {
+ displayName: 'Birthdate',
+ name: 'birthdate',
+ type: 'string',
+ default: '',
+ description: 'The birthdate of the contact.',
+ },
+ {
+ displayName: 'First Name',
+ name: 'firstName',
+ type: 'string',
+ default: '',
+ description: 'First name of the contact. Maximum size is 40 characters.',
+ },
+ {
+ displayName: 'Home Phone',
+ name: 'homePhone',
+ type: 'string',
+ default: '',
+ description: 'Home telephone number for the contact.',
+ },
+ {
+ displayName: 'Other City',
+ name: 'otherCity',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Department',
+ name: 'department',
+ type: 'string',
+ default: '',
+ description: 'The department of the contact.',
+ },
+ {
+ displayName: 'Lead Source',
+ name: 'leadSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadSources',
+ },
+ default: '',
+ description: 'Source from which the lead was obtained.',
+ },
+ {
+ displayName: 'Other Phone',
+ name: 'otherPhone',
+ type: 'string',
+ default: '',
+ description: 'Telephone for alternate address.',
+ },
+ {
+ displayName: 'Other State',
+ name: 'otherState',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Salutation',
+ name: 'salutation',
+ type: 'string',
+ default: '',
+ description: 'Honorific abbreviation, word, or phrase to be used in front of name in greetings, such as Dr. or Mrs.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: 'A description of the contact. Label is Contact Description. Limit: 32 KB.',
+ },
+ {
+ displayName: 'Mailing City',
+ name: 'mailingCity',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Mobile Phone',
+ name: 'mobilePhone',
+ type: 'string',
+ default: '',
+ description: `Contact’s mobile phone number.`,
+ },
+ {
+ displayName: 'Other Street',
+ name: 'otherStreet',
+ type: 'string',
+ default: '',
+ description: 'Street for alternate address.',
+ },
+ {
+ displayName: 'Mailing State',
+ name: 'mailingState',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Other Country',
+ name: 'otherCountry',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Assistant Name',
+ name: 'assistantName',
+ type: 'string',
+ default: '',
+ description: 'The name of the assistant.',
+ },
+ {
+ displayName: 'Mailing Street',
+ name: 'mailingStreet',
+ type: 'string',
+ default: '',
+ description: 'Street address for mailing address.',
+ },
+ {
+ displayName: 'Assistant Phone',
+ name: 'Assistant Phone',
+ type: 'string',
+ default: '',
+ description: 'The telephone number of the assistant.',
+ },
+ {
+ displayName: 'Mailing Country',
+ name: 'mailingCountry',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Other Postal Code',
+ name: 'otherPostalCode',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Email Bounced Date',
+ name: 'emailBouncedDate',
+ type: 'dateTime',
+ default: '',
+ description: 'If bounce management is activated and an email sent to the contact bounces, the date and time the bounce occurred.',
+ },
+ {
+ displayName: 'Mailing Postal Code',
+ name: 'mailingPostalCode',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Email Bounced Reason',
+ name: 'emailBouncedReason',
+ type: 'string',
+ default: '',
+ description: 'If bounce management is activated and an email sent to the contact bounces, the reason the bounce occurred.',
+ },
+ ],
+ },
+
+/* -------------------------------------------------------------------------- */
+/* contact:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Contact ID',
+ name: 'contactId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'get',
+ ]
+ },
+ },
+ description: 'Id of contact that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* contact:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Contact ID',
+ name: 'contactId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'delete',
+ ]
+ },
+ },
+ description: 'Id of contact that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* contact:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ 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: [
+ 'contact',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 50,
+ description: 'How many results to return.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fields',
+ name: 'fields',
+ type: 'string',
+ default: '',
+ description: 'Fields to include separated by ,',
+ },
+ ]
+ },
+
+/* -------------------------------------------------------------------------- */
+/* contact:addToCampaign */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Contact ID',
+ name: 'contactId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'addToCampaign',
+ ]
+ },
+ },
+ description: 'Id of contact that needs to be fetched',
+ },
+ {
+ displayName: 'Campaign',
+ name: 'campaignId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCampaigns',
+ },
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'addToCampaign',
+ ]
+ },
+ },
+ description: 'Id of the campaign that needs to be fetched',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'addToCampaign',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'string',
+ default: '',
+ description: 'Controls the HasResponded flag on this object',
+ },
+ ]
+ },
+/* -------------------------------------------------------------------------- */
+/* contact:addNote */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Contact ID',
+ name: 'contactId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Id of contact that needs to be fetched',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Title of the note.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'contact',
+ ],
+ operation: [
+ 'addNote',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Body',
+ name: 'body',
+ type: 'string',
+ default: '',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'Body of the note. Limited to 32 KB.',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the user who owns the note.',
+ },
+ {
+ displayName: 'Is Private',
+ name: 'isPrivate',
+ type: 'boolean',
+ default: false,
+ description: 'If true, only the note owner or a user with the “Modify All Data” permission can view the note or query it via the API',
+ },
+ ]
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Salesforce/ContactInterface.ts b/packages/nodes-base/nodes/Salesforce/ContactInterface.ts
new file mode 100644
index 0000000000..e51090b88f
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/ContactInterface.ts
@@ -0,0 +1,34 @@
+
+export interface IContact {
+ LastName?: string;
+ Fax?: string;
+ Email?: string;
+ Phone?: string;
+ Title?: string;
+ Jigsaw?: string;
+ OwnerId?: string;
+ AccountId?: string;
+ Birthdate?:string;
+ FirstName?: string;
+ HomePhone?: string;
+ OtherCity?: string;
+ Department?: string;
+ LeadSource?: string;
+ OtherPhone?: string;
+ OtherState?: string;
+ Salutation?: string;
+ Description?: string;
+ MailingCity?: string;
+ MobilePhone?: string;
+ OtherStreet?: string;
+ MailingState?: string;
+ OtherCountry?: string;
+ AssistantName?: string;
+ MailingStreet?: string;
+ AssistantPhone?: string;
+ MailingCountry?: string;
+ OtherPostalCode?: string;
+ MailingPostalCode?: string;
+ EmailBouncedDate?: string;
+ EmailBouncedReason?: string;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts b/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts
new file mode 100644
index 0000000000..33fec16bf3
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts
@@ -0,0 +1,50 @@
+import { OptionsWithUri } from 'request';
+import {
+ IExecuteFunctions,
+ IExecuteSingleFunctions,
+ ILoadOptionsFunctions,
+} from 'n8n-core';
+import {
+ IDataObject
+} from 'n8n-workflow';
+
+export async function salesforceApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any
+ const credentials = this.getCredentials('salesforceOAuth2Api');
+ const subdomain = (credentials!.accessTokenUrl as string).split('.')[0].split('/')[2];
+ const options: OptionsWithUri = {
+ method,
+ body,
+ qs,
+ uri: uri || `https://${subdomain}.salesforce.com/services/data/v39.0${resource}`,
+ json: true
+ };
+ try {
+ //@ts-ignore
+ return await this.helpers.requestOAuth.call(this, 'salesforceOAuth2Api', options);
+ } catch (error) {
+ if (error.response && error.response.body && error.response.body[0].message) {
+ // Try to return the error prettier
+ throw new Error(`Salesforce error response [${error.statusCode}]: ${error.response.body[0].message}`);
+ }
+ throw error;
+ }
+}
+
+export async function salesforceApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any
+
+ const returnData: IDataObject[] = [];
+
+ let responseData;
+ let uri: string | undefined;
+
+ do {
+ responseData = await salesforceApiRequest.call(this, method, endpoint, body, query, uri);
+ uri = responseData.nextRecordsUrl;
+ returnData.push.apply(returnData, responseData[propertyName]);
+ } while (
+ responseData.nextRecordsUrl !== undefined &&
+ responseData.nextRecordsUrl !== null
+ );
+
+ return returnData;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/LeadDescription.ts b/packages/nodes-base/nodes/Salesforce/LeadDescription.ts
new file mode 100644
index 0000000000..ba9134741d
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/LeadDescription.ts
@@ -0,0 +1,762 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const leadOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a lead',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update a lead',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a lead',
+ },
+ {
+ name: 'Get Summary',
+ value: 'getSummary',
+ description: `Returns an overview of Lead's metadata.`,
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all leads',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete a lead',
+ },
+ {
+ name: 'Add Lead To Campaign',
+ value: 'addToCampaign',
+ description: 'Add lead to a campaign',
+ },
+ {
+ name: 'Add Note',
+ value: 'addNote',
+ description: 'Add note to a lead',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const leadFields = [
+
+/* -------------------------------------------------------------------------- */
+/* lead:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Company',
+ name: 'company',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'create',
+ ]
+ },
+ },
+ description: 'Company of the lead. If person account record types have been enabled, and if the value of Company is null, the lead converts to a person account.',
+ },
+ {
+ displayName: 'Last Name',
+ name: 'lastname',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'create',
+ ]
+ },
+ },
+ description: 'Required. Last name of the lead. Limited to 80 characters.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'City',
+ name: 'city',
+ type: 'string',
+ default: '',
+ description: 'City for the address of the lead.',
+ },
+ {
+ displayName: 'Email',
+ name: 'email',
+ type: 'string',
+ default: '',
+ description: 'Email address for the lead.',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the lead.',
+ },
+ {
+ displayName: 'State',
+ name: 'state',
+ type: 'string',
+ default: '',
+ description: 'State for the address of the lead.',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ default: '',
+ description: 'Title for the lead, for example CFO or CEO.',
+ },
+ {
+ displayName: 'Jigsaw',
+ name: 'jigsaw',
+ type: 'string',
+ default: '',
+ description: `references the ID of a contact in Data.com.
+ If a lead has a value in this field, it means that a contact was imported as a lead from Data.com.`,
+ },
+ {
+ displayName: 'Rating',
+ name: 'rating',
+ type: 'string',
+ default: '',
+ description: 'Rating of the lead.',
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadStatuses',
+ },
+ default: '',
+ description: 'Status code for this converted lead.',
+ },
+ {
+ displayName: 'Street',
+ name: 'street',
+ type: 'string',
+ default: '',
+ description: 'Street number and name for the address of the lead',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the lead.',
+ },
+ {
+ displayName: 'Website',
+ name: 'website',
+ type: 'string',
+ default: '',
+ description: 'Website for the lead.',
+ },
+ {
+ displayName: 'Industry',
+ name: 'industry',
+ type: 'string',
+ default: '',
+ description: 'Website for the lead.',
+ },
+ {
+ displayName: 'Fist Name',
+ name: 'firstname',
+ type: 'string',
+ default: '',
+ description: 'First name of the lead. Limited to 40 characters.',
+ },
+ {
+ displayName: 'Lead Source',
+ name: 'leadSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadSources',
+ },
+ default: '',
+ description: 'Source from which the lead was obtained.',
+ },
+ {
+ displayName: 'Postal Code',
+ name: 'postalCode',
+ type: 'string',
+ default: '',
+ description: 'Postal code for the address of the lead. Label is Zip/Postal Code.',
+ },
+ {
+ displayName: 'Salutation',
+ name: 'salutation',
+ type: 'string',
+ default: '',
+ description: 'Salutation for the lead.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Description of the lead.',
+ },
+ {
+ displayName: 'Annual Revenue',
+ name: 'annualRevenue',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 2,
+ numberStepSize: 1,
+ },
+ default: '',
+ description: 'Annual revenue for the company of the lead.',
+ },
+ {
+ displayName: 'Number Of Employees',
+ name: 'numberOfEmployees',
+ type: 'number',
+ typeOptions: {
+ numberStepSize: 1,
+ },
+ default: '',
+ description: 'Number of employees at the lead’s company. Label is Employees.',
+ },
+ {
+ displayName: 'Is Unread By Owner',
+ name: 'IsUnreadByOwner',
+ type: 'Boolean',
+ default: false,
+ description: 'If true, lead has been assigned, but not yet viewed. See Unread Leads for more information. Label is Unread By Owner.',
+ },
+ ]
+ },
+/* -------------------------------------------------------------------------- */
+/* lead:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Lead ID',
+ name: 'leadId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'update',
+ ]
+ },
+ },
+ description: 'Id of Lead that needs to be fetched',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'update',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Company',
+ name: 'company',
+ type: 'string',
+ default: '',
+ description: 'Company of the lead. If person account record types have been enabled, and if the value of Company is null, the lead converts to a person account.',
+ },
+ {
+ displayName: 'Last Name',
+ name: 'lastname',
+ type: 'string',
+ default: '',
+ description: 'Required. Last name of the lead. Limited to 80 characters.',
+ },
+ {
+ displayName: 'City',
+ name: 'city',
+ type: 'string',
+ default: '',
+ description: 'City for the address of the lead.',
+ },
+ {
+ displayName: 'Email',
+ name: 'email',
+ type: 'string',
+ default: '',
+ description: 'Email address for the lead.',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the lead.',
+ },
+ {
+ displayName: 'State',
+ name: 'state',
+ type: 'string',
+ default: '',
+ description: 'State for the address of the lead.',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ default: '',
+ description: 'Title for the lead, for example CFO or CEO.',
+ },
+ {
+ displayName: 'Jigsaw',
+ name: 'jigsaw',
+ type: 'string',
+ default: '',
+ description: `references the ID of a contact in Data.com.
+ If a lead has a value in this field, it means that a contact was imported as a lead from Data.com.`,
+ },
+ {
+ displayName: 'Rating',
+ name: 'rating',
+ type: 'string',
+ default: '',
+ description: 'Rating of the lead.',
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadStatuses',
+ },
+ default: '',
+ description: 'Status code for this converted lead.',
+ },
+ {
+ displayName: 'Street',
+ name: 'street',
+ type: 'string',
+ default: '',
+ description: 'Street number and name for the address of the lead',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the lead.',
+ },
+ {
+ displayName: 'Website',
+ name: 'website',
+ type: 'string',
+ default: '',
+ description: 'Website for the lead.',
+ },
+ {
+ displayName: 'Industry',
+ name: 'industry',
+ type: 'string',
+ default: '',
+ description: 'Website for the lead.',
+ },
+ {
+ displayName: 'Fist Name',
+ name: 'firstname',
+ type: 'string',
+ default: '',
+ description: 'First name of the lead. Limited to 40 characters.',
+ },
+ {
+ displayName: 'Lead Source',
+ name: 'leadSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadSources',
+ },
+ default: '',
+ description: 'Source from which the lead was obtained.',
+ },
+ {
+ displayName: 'Postal Code',
+ name: 'postalCode',
+ type: 'string',
+ default: '',
+ description: 'Postal code for the address of the lead. Label is Zip/Postal Code.',
+ },
+ {
+ displayName: 'Salutation',
+ name: 'salutation',
+ type: 'string',
+ default: '',
+ description: 'Salutation for the lead.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Description of the lead.',
+ },
+ {
+ displayName: 'Annual Revenue',
+ name: 'annualRevenue',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 2,
+ numberStepSize: 1,
+ },
+ default: '',
+ description: 'Annual revenue for the company of the lead.',
+ },
+ {
+ displayName: 'Number Of Employees',
+ name: 'numberOfEmployees',
+ type: 'number',
+ typeOptions: {
+ numberStepSize: 1,
+ },
+ default: '',
+ description: 'Number of employees at the lead’s company. Label is Employees.',
+ },
+ {
+ displayName: 'Is Unread By Owner',
+ name: 'IsUnreadByOwner',
+ type: 'Boolean',
+ default: false,
+ description: 'If true, lead has been assigned, but not yet viewed. See Unread Leads for more information. Label is Unread By Owner.',
+ },
+ ]
+ },
+
+/* -------------------------------------------------------------------------- */
+/* lead:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Lead ID',
+ name: 'leadId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'get',
+ ]
+ },
+ },
+ description: 'Id of Lead that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* lead:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Lead ID',
+ name: 'leadId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'delete',
+ ]
+ },
+ },
+ description: 'Id of Lead that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* lead:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ 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: [
+ 'lead',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 50,
+ description: 'How many results to return.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fields',
+ name: 'fields',
+ type: 'string',
+ default: '',
+ description: 'Fields to include separated by ,',
+ },
+ ]
+ },
+/* -------------------------------------------------------------------------- */
+/* contact:addToCampaign */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Lead ID',
+ name: 'leadId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'addToCampaign',
+ ]
+ },
+ },
+ description: 'Id of contact that needs to be fetched',
+ },
+ {
+ displayName: 'Campaign',
+ name: 'campaignId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCampaigns',
+ },
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'addToCampaign',
+ ]
+ },
+ },
+ description: 'Id of the campaign that needs to be fetched',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'addToCampaign',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'string',
+ default: '',
+ description: 'Controls the HasResponded flag on this object',
+ },
+ ]
+ },
+/* -------------------------------------------------------------------------- */
+/* lead:addNote */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Lead ID',
+ name: 'leadId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Id of lead that needs to be fetched',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Title of the note.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'lead',
+ ],
+ operation: [
+ 'addNote',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Body',
+ name: 'body',
+ type: 'string',
+ default: '',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'Body of the note. Limited to 32 KB.',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the user who owns the note.',
+ },
+ {
+ displayName: 'Is Private',
+ name: 'isPrivate',
+ type: 'boolean',
+ default: false,
+ description: 'If true, only the note owner or a user with the “Modify All Data” permission can view the note or query it via the API',
+ },
+ ]
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Salesforce/LeadInterface.ts b/packages/nodes-base/nodes/Salesforce/LeadInterface.ts
new file mode 100644
index 0000000000..c6cd047394
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/LeadInterface.ts
@@ -0,0 +1,26 @@
+
+export interface ILead {
+ Company?: string;
+ LastName?: string;
+ Email?: string;
+ City?: string;
+ Phone?: string;
+ State?: string;
+ Title?: string;
+ Jigsaw?: string;
+ Rating?: string;
+ Status?: string;
+ Street?: string;
+ Country?: string;
+ OwnerId?: string;
+ Website?: string;
+ Industry?: string;
+ FirstName?: string;
+ LeadSource?: string;
+ PostalCode?: string;
+ Salutation?: string;
+ Description?: string;
+ AnnualRevenue?: number;
+ IsUnreadByOwner?: boolean;
+ NumberOfEmployees?: number;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/NoteInterface.ts b/packages/nodes-base/nodes/Salesforce/NoteInterface.ts
new file mode 100644
index 0000000000..2036cfea21
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/NoteInterface.ts
@@ -0,0 +1,8 @@
+
+export interface INote {
+ Title?: string;
+ ParentId?: string;
+ Body?: string;
+ OwnerId?: string;
+ IsPrivate?: boolean;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/OpportunityDescription.ts b/packages/nodes-base/nodes/Salesforce/OpportunityDescription.ts
new file mode 100644
index 0000000000..89efd96478
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/OpportunityDescription.ts
@@ -0,0 +1,625 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const opportunityOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create an opportunity',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update an opportunity',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get an opportunity',
+ },
+ {
+ name: 'Get Summary',
+ value: 'getSummary',
+ description: `Returns an overview of opportunity's metadata.`,
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all opportunitys',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete an opportunity',
+ },
+ {
+ name: 'Add Note',
+ value: 'addNote',
+ description: 'Add note to an opportunity',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const opportunityFields = [
+
+/* -------------------------------------------------------------------------- */
+/* opportunity:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Name',
+ name: 'name',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'create',
+ ]
+ },
+ },
+ description: 'Required. Last name of the opportunity. Limited to 80 characters.',
+ },
+ {
+ displayName: 'Close Date',
+ name: 'closeDate',
+ type: 'dateTime',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'create',
+ ]
+ },
+ },
+ description: 'Required. Date when the opportunity is expected to close.',
+ },
+ {
+ displayName: 'Stage Name',
+ name: 'stageName',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getStages'
+ },
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'create',
+ ]
+ },
+ },
+ description: 'Required. Date when the opportunity is expected to close.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ default: '',
+ options: [
+ {
+ name: 'Business',
+ valie: 'Business',
+ },
+ {
+ name: 'New Business',
+ valie: 'New Business',
+ },
+ ],
+ description: 'Type of opportunity. For example, Existing Business or New Business. Label is Opportunity Type.',
+ },
+ {
+ displayName: 'Amount',
+ name: 'amount',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 2,
+ },
+ default: '',
+ description: 'Estimated total sale amount',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the opportunity.',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the opportunity.',
+ },
+ {
+ displayName: 'Next Step',
+ name: 'nextStep',
+ type: 'string',
+ default: '',
+ description: 'Description of next task in closing opportunity. Limit: 255 characters.',
+ },
+ {
+ displayName: 'Account',
+ name: 'accountId',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getAccounts',
+ },
+ description: 'ID of the account associated with this opportunity.',
+ },
+ {
+ displayName: 'Campaign',
+ name: 'campaignId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCampaigns',
+ },
+ default: '',
+ description: 'Id of the campaign that needs to be fetched',
+ },
+ {
+ displayName: 'Lead Source',
+ name: 'leadSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadSources',
+ },
+ default: '',
+ description: 'Source from which the lead was obtained.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: 'A description of the opportunity. Label is Contact Description. Limit: 32 KB.',
+ },
+ {
+ displayName: 'Probability',
+ name: 'probability',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 1,
+ },
+ default: '',
+ description: 'Percentage of estimated confidence in closing the opportunity',
+ },
+ {
+ displayName: 'Pricebook2 Id',
+ name: 'pricebook2Id',
+ type: 'string',
+ default: '',
+ description: 'ID of a related Pricebook2 object',
+ },
+ {
+ displayName: 'Forecast Category Name',
+ name: 'forecastCategoryName',
+ type: 'string',
+ default: '',
+ description: 'It is implied, but not directly controlled, by the StageName field',
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* opportunity:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Opportunity ID',
+ name: 'opportunityId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'update',
+ ]
+ },
+ },
+ description: 'Id of opportunity that needs to be fetched',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'update',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Name',
+ name: 'name',
+ type: 'string',
+ default: '',
+ description: 'Required. Last name of the opportunity. Limited to 80 characters.',
+ },
+ {
+ displayName: 'Close Date',
+ name: 'closeDate',
+ type: 'dateTime',
+ default: '',
+ description: 'Required. Date when the opportunity is expected to close.',
+ },
+ {
+ displayName: 'Stage Name',
+ name: 'stageName',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getStages'
+ },
+ default: '',
+ description: 'Required. Date when the opportunity is expected to close.',
+ },
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ default: '',
+ options: [
+ {
+ name: 'Business',
+ valie: 'Business',
+ },
+ {
+ name: 'New Business',
+ valie: 'New Business',
+ },
+ ],
+ description: 'Type of opportunity. For example, Existing Business or New Business. Label is Opportunity Type.',
+ },
+ {
+ displayName: 'Amount',
+ name: 'amount',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 2,
+ },
+ default: '',
+ description: 'Estimated total sale amount',
+ },
+ {
+ displayName: 'Phone',
+ name: 'phone',
+ type: 'string',
+ default: '',
+ description: 'Phone number for the opportunity.',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'The owner of the opportunity.',
+ },
+ {
+ displayName: 'Next Step',
+ name: 'nextStep',
+ type: 'string',
+ default: '',
+ description: 'Description of next task in closing opportunity. Limit: 255 characters.',
+ },
+ {
+ displayName: 'Account',
+ name: 'accountId',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getAccounts',
+ },
+ description: 'ID of the account associated with this opportunity.',
+ },
+ {
+ displayName: 'Campaign',
+ name: 'campaignId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCampaigns',
+ },
+ default: '',
+ description: 'Id of the campaign that needs to be fetched',
+ },
+ {
+ displayName: 'Lead Source',
+ name: 'leadSource',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getLeadSources',
+ },
+ default: '',
+ description: 'Source from which the lead was obtained.',
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ description: 'A description of the opportunity. Label is Contact Description. Limit: 32 KB.',
+ },
+ {
+ displayName: 'Probability',
+ name: 'probability',
+ type: 'number',
+ typeOptions: {
+ numberPrecision: 1,
+ },
+ default: '',
+ description: 'Percentage of estimated confidence in closing the opportunity',
+ },
+ {
+ displayName: 'Pricebook2 Id',
+ name: 'pricebook2Id',
+ type: 'string',
+ default: '',
+ description: 'ID of a related Pricebook2 object',
+ },
+ {
+ displayName: 'Forecast Category Name',
+ name: 'forecastCategoryName',
+ type: 'string',
+ default: '',
+ description: 'It is implied, but not directly controlled, by the StageName field',
+ },
+ ],
+ },
+
+/* -------------------------------------------------------------------------- */
+/* opportunity:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Opportunity ID',
+ name: 'opportunityId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'get',
+ ]
+ },
+ },
+ description: 'Id of opportunity that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* opportunity:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Opportunity ID',
+ name: 'opportunityId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'delete',
+ ]
+ },
+ },
+ description: 'Id of opportunity that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* opportunity:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ 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: [
+ 'opportunity',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 50,
+ description: 'How many results to return.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fields',
+ name: 'fields',
+ type: 'string',
+ default: '',
+ description: 'Fields to include separated by ,',
+ },
+ ]
+ },
+
+/* -------------------------------------------------------------------------- */
+/* opportunity:addNote */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Opportunity ID',
+ name: 'opportunityId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Id of opportunity that needs to be fetched',
+ },
+ {
+ displayName: 'Title',
+ name: 'title',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'addNote',
+ ]
+ },
+ },
+ description: 'Title of the note.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'opportunity',
+ ],
+ operation: [
+ 'addNote',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Body',
+ name: 'body',
+ type: 'string',
+ default: '',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'Body of the note. Limited to 32 KB.',
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the user who owns the note.',
+ },
+ {
+ displayName: 'Is Private',
+ name: 'isPrivate',
+ type: 'boolean',
+ default: false,
+ description: 'If true, only the note owner or a user with the “Modify All Data” permission can view the note or query it via the API',
+ },
+ ]
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Salesforce/OpportunityInterface.ts b/packages/nodes-base/nodes/Salesforce/OpportunityInterface.ts
new file mode 100644
index 0000000000..bad4852648
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/OpportunityInterface.ts
@@ -0,0 +1,17 @@
+
+export interface IOpportunity {
+ Name?: string;
+ StageName?: string;
+ CloseDate?: string;
+ Type?: string;
+ Amount?: number;
+ OwnerId?: string;
+ NextStep?: string;
+ AccountId?: string;
+ CampaignId?: string;
+ LeadSource?: string;
+ Description?: string;
+ Probability?: number;
+ Pricebook2Id?:string;
+ ForecastCategoryName?: string;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/Salesforce.node.ts b/packages/nodes-base/nodes/Salesforce/Salesforce.node.ts
new file mode 100644
index 0000000000..0c07520d61
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/Salesforce.node.ts
@@ -0,0 +1,1893 @@
+import {
+ IExecuteFunctions,
+} from 'n8n-core';
+import {
+ IDataObject,
+ ILoadOptionsFunctions,
+ INodeTypeDescription,
+ INodeExecutionData,
+ INodeType,
+ INodePropertyOptions,
+} from 'n8n-workflow';
+import {
+ salesforceApiRequest,
+ salesforceApiRequestAllItems,
+} from './GenericFunctions';
+import {
+ leadFields,
+ leadOperations,
+} from './LeadDescription';
+import {
+ contactFields,
+ contactOperations,
+} from './ContactDescription';
+import {
+ opportunityOperations,
+ opportunityFields,
+ } from './OpportunityDescription';
+ import {
+ accountOperations,
+ accountFields,
+ } from './AccountDescription';
+ import {
+ caseOperations,
+ caseFields,
+ } from './CaseDescription';
+ import {
+ taskOperations,
+ taskFields,
+ } from './TaskDescription';
+ import {
+ attachmentOperations,
+ attachmentFields,
+ } from './AttachmentDescription';
+ import {
+ IOpportunity,
+} from './OpportunityInterface';
+import {
+ ICampaignMember,
+} from './CampaignMemberInterface';
+import {
+ ILead,
+} from './LeadInterface';
+import {
+ IContact,
+ } from './ContactInterface';
+ import {
+ IAccount,
+ } from './AccountInterface';
+ import {
+ INote,
+} from './NoteInterface';
+import {
+ ICase,
+ ICaseComment,
+} from './CaseInterface';
+import {
+ ITask,
+} from './TaskInterface';
+import {
+ IAttachment,
+} from './AttachmentInterface';
+
+export class Salesforce implements INodeType {
+ description: INodeTypeDescription = {
+ displayName: 'Salesforce',
+ name: 'salesforce',
+ icon: 'file:salesforce.png',
+ group: ['output'],
+ version: 1,
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
+ description: 'Consume Salesforce API',
+ defaults: {
+ name: 'Salesforce',
+ color: '#429fd9',
+ },
+ inputs: ['main'],
+ outputs: ['main'],
+ credentials: [
+ {
+ name: 'salesforceOAuth2Api',
+ required: true,
+ },
+ ],
+ properties: [
+ {
+ displayName: 'Resource',
+ name: 'resource',
+ type: 'options',
+ options: [
+ {
+ name: 'Lead',
+ value: 'lead',
+ description: 'Represents a prospect or potential .',
+ },
+ {
+ name: 'Contact',
+ value: 'contact',
+ description: 'Represents a contact, which is an individual associated with an account.',
+ },
+ {
+ name: 'Opportunity',
+ value: 'opportunity',
+ description: 'Represents an opportunity, which is a sale or pending deal.',
+ },
+ {
+ name: 'Account',
+ value: 'account',
+ description: 'Represents an individual account, which is an organization or person involved with your business (such as customers, competitors, and partners).',
+ },
+ {
+ name: 'Case',
+ value: 'case',
+ description: 'Represents a case, which is a customer issue or problem.',
+ },
+ {
+ name: 'Task',
+ value: 'task',
+ description: 'Represents a business activity such as making a phone call or other to-do items. In the user interface, and records are collectively referred to as activities.',
+ },
+ {
+ name: 'Attachment',
+ value: 'attachment',
+ description: 'Represents a file that a has uploaded and attached to a parent object.',
+ },
+ ],
+ default: 'lead',
+ description: 'Resource to consume.',
+ },
+ ...leadOperations,
+ ...leadFields,
+ ...contactOperations,
+ ...contactFields,
+ ...opportunityOperations,
+ ...opportunityFields,
+ ...accountOperations,
+ ...accountFields,
+ ...caseOperations,
+ ...caseFields,
+ ...taskOperations,
+ ...taskFields,
+ ...attachmentOperations,
+ ...attachmentFields,
+ ],
+ };
+
+ methods = {
+ loadOptions: {
+ // Get all the lead statuses to display them to user so that he can
+ // select them easily
+ async getLeadStatuses(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ const qs = {
+ q: 'SELECT id, MasterLabel FROM LeadStatus',
+ };
+ const statuses = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ for (const status of statuses) {
+ const statusName = status.MasterLabel;
+ const statusId = status.Id;
+ returnData.push({
+ name: statusName,
+ value: statusId,
+ });
+ }
+ return returnData;
+ },
+ // Get all the users to display them to user so that he can
+ // select them easily
+ async getUsers(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ const qs = {
+ q: 'SELECT id, Name FROM User',
+ };
+ const users = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ for (const user of users) {
+ const userName = user.Name;
+ const userId = user.Id;
+ returnData.push({
+ name: userName,
+ value: userId,
+ });
+ }
+ return returnData;
+ },
+ // Get all the lead sources to display them to user so that he can
+ // select them easily
+ async getLeadSources(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/lead/describe');
+ for (const field of fields) {
+ if (field.name === 'LeadSource') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the accounts to display them to user so that he can
+ // select them easily
+ async getAccounts(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ const qs = {
+ q: 'SELECT id, Name FROM Account',
+ };
+ const accounts = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ for (const account of accounts) {
+ const accountName = account.Name;
+ const accountId = account.Id;
+ returnData.push({
+ name: accountName,
+ value: accountId,
+ });
+ }
+ return returnData;
+ },
+ // Get all the campaigns to display them to user so that he can
+ // select them easily
+ async getCampaigns(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ const qs = {
+ q: 'SELECT id, Name FROM Campaign',
+ };
+ const campaigns = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ for (const campaign of campaigns) {
+ const campaignName = campaign.Name;
+ const campaignId = campaign.Id;
+ returnData.push({
+ name: campaignName,
+ value: campaignId,
+ });
+ }
+ return returnData;
+ },
+ // Get all the stages to display them to user so that he can
+ // select them easily
+ async getStages(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/opportunity/describe');
+ for (const field of fields) {
+ if (field.name === 'StageName') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the stages to display them to user so that he can
+ // select them easily
+ async getAccountTypes(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/account/describe');
+ for (const field of fields) {
+ if (field.name === 'Type') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the account sources to display them to user so that he can
+ // select them easily
+ async getAccountSources(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/account/describe');
+ for (const field of fields) {
+ if (field.name === 'AccountSource') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the case types to display them to user so that he can
+ // select them easily
+ async getCaseTypes(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/case/describe');
+ for (const field of fields) {
+ if (field.name === 'Type') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the case statuses to display them to user so that he can
+ // select them easily
+ async getCaseStatuses(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/case/describe');
+ for (const field of fields) {
+ if (field.name === 'Status') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the case reasons to display them to user so that he can
+ // select them easily
+ async getCaseReasons(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/case/describe');
+ for (const field of fields) {
+ if (field.name === 'Reason') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the case origins to display them to user so that he can
+ // select them easily
+ async getCaseOrigins(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/case/describe');
+ for (const field of fields) {
+ if (field.name === 'Origin') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the case priorities to display them to user so that he can
+ // select them easily
+ async getCasePriorities(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/case/describe');
+ for (const field of fields) {
+ if (field.name === 'Priority') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the task statuses to display them to user so that he can
+ // select them easily
+ async getTaskStatuses(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/task/describe');
+ for (const field of fields) {
+ if (field.name === 'Status') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the task subjects to display them to user so that he can
+ // select them easily
+ async getTaskSubjects(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/task/describe');
+ for (const field of fields) {
+ if (field.name === 'Subject') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the task call types to display them to user so that he can
+ // select them easily
+ async getTaskCallTypes(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/task/describe');
+ for (const field of fields) {
+ if (field.name === 'CallType') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the task call priorities to display them to user so that he can
+ // select them easily
+ async getTaskPriorities(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/task/describe');
+ for (const field of fields) {
+ if (field.name === 'Priority') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the task recurrence types to display them to user so that he can
+ // select them easily
+ async getTaskRecurrenceTypes(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/task/describe');
+ for (const field of fields) {
+ if (field.name === 'RecurrenceType') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ // Get all the task recurrence instances to display them to user so that he can
+ // select them easily
+ async getTaskRecurrenceInstances(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ //find a way to filter this object to get just the lead sources instead of the whole object
+ const { fields } = await salesforceApiRequest.call(this, 'GET', '/sobjects/task/describe');
+ for (const field of fields) {
+ if (field.name === 'RecurrenceInstance') {
+ for (const pickValue of field.picklistValues) {
+ const pickValueName = pickValue.label;
+ const pickValueId = pickValue.value;
+ returnData.push({
+ name: pickValueName,
+ value: pickValueId,
+ });
+ }
+ }
+ }
+ return returnData;
+ },
+ },
+ };
+
+ async execute(this: IExecuteFunctions): Promise {
+ const items = this.getInputData();
+ const returnData: IDataObject[] = [];
+ const length = items.length as unknown as number;
+ let responseData;
+ const qs: IDataObject = {};
+ 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 === 'lead') {
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Lead/post-lead
+ if (operation === 'create') {
+ const company = this.getNodeParameter('company', i) as string;
+ const lastname = this.getNodeParameter('lastname', i) as string;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const body: ILead = {
+ Company: company,
+ LastName: lastname,
+ };
+ if (additionalFields.email) {
+ body.Email = additionalFields.email as string;
+ }
+ if (additionalFields.city) {
+ body.City = additionalFields.city as string;
+ }
+ if (additionalFields.phone) {
+ body.Phone = additionalFields.phone as string;
+ }
+ if (additionalFields.state) {
+ body.State = additionalFields.state as string;
+ }
+ if (additionalFields.title) {
+ body.Title = additionalFields.title as string;
+ }
+ if (additionalFields.jigsaw) {
+ body.Jigsaw = additionalFields.jigsaw as string;
+ }
+ if (additionalFields.rating) {
+ body.Rating = additionalFields.rating as string;
+ }
+ if (additionalFields.status) {
+ body.Status = additionalFields.status as string;
+ }
+ if (additionalFields.street) {
+ body.Street = additionalFields.street as string;
+ }
+ if (additionalFields.country) {
+ body.Country = additionalFields.country as string;
+ }
+ if (additionalFields.owner) {
+ body.OwnerId = additionalFields.owner as string;
+ }
+ if (additionalFields.website) {
+ body.Website = additionalFields.website as string;
+ }
+ if (additionalFields.industry) {
+ body.Industry = additionalFields.industry as string;
+ }
+ if (additionalFields.firstName) {
+ body.FirstName = additionalFields.firstName as string;
+ }
+ if (additionalFields.leadSource) {
+ body.LeadSource = additionalFields.leadSource as string;
+ }
+ if (additionalFields.postalCode) {
+ body.PostalCode = additionalFields.postalCode as string;
+ }
+ if (additionalFields.salutation) {
+ body.Salutation = additionalFields.salutation as string;
+ }
+ if (additionalFields.description) {
+ body.Description = additionalFields.description as string;
+ }
+ if (additionalFields.annualRevenue) {
+ body.AnnualRevenue = additionalFields.annualRevenue as number;
+ }
+ if (additionalFields.isUnreadByOwner) {
+ body.IsUnreadByOwner = additionalFields.isUnreadByOwner as boolean;
+ }
+ if (additionalFields.numberOfEmployees) {
+ body.NumberOfEmployees = additionalFields.numberOfEmployees as number;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/lead', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Lead/patch-lead-id
+ if (operation === 'update') {
+ const leadId = this.getNodeParameter('leadId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ const body: ILead = {};
+ if (!Object.keys(updateFields).length) {
+ throw new Error('You must add at least one update field');
+ }
+ if (updateFields.lastname) {
+ body.LastName = updateFields.lastname as string;
+ }
+ if (updateFields.company) {
+ body.Company = updateFields.company as string;
+ }
+ if (updateFields.email) {
+ body.Email = updateFields.email as string;
+ }
+ if (updateFields.city) {
+ body.City = updateFields.city as string;
+ }
+ if (updateFields.phone) {
+ body.Phone = updateFields.phone as string;
+ }
+ if (updateFields.state) {
+ body.State = updateFields.state as string;
+ }
+ if (updateFields.title) {
+ body.Title = updateFields.title as string;
+ }
+ if (updateFields.jigsaw) {
+ body.Jigsaw = updateFields.jigsaw as string;
+ }
+ if (updateFields.rating) {
+ body.Rating = updateFields.rating as string;
+ }
+ if (updateFields.status) {
+ body.Status = updateFields.status as string;
+ }
+ if (updateFields.street) {
+ body.Street = updateFields.street as string;
+ }
+ if (updateFields.country) {
+ body.Country = updateFields.country as string;
+ }
+ if (updateFields.owner) {
+ body.OwnerId = updateFields.owner as string;
+ }
+ if (updateFields.website) {
+ body.Website = updateFields.website as string;
+ }
+ if (updateFields.industry) {
+ body.Industry = updateFields.industry as string;
+ }
+ if (updateFields.firstName) {
+ body.FirstName = updateFields.firstName as string;
+ }
+ if (updateFields.leadSource) {
+ body.LeadSource = updateFields.leadSource as string;
+ }
+ if (updateFields.postalCode) {
+ body.PostalCode = updateFields.postalCode as string;
+ }
+ if (updateFields.salutation) {
+ body.Salutation = updateFields.salutation as string;
+ }
+ if (updateFields.description) {
+ body.Description = updateFields.description as string;
+ }
+ if (updateFields.annualRevenue) {
+ body.AnnualRevenue = updateFields.annualRevenue as number;
+ }
+ if (updateFields.isUnreadByOwner) {
+ body.IsUnreadByOwner = updateFields.isUnreadByOwner as boolean;
+ }
+ if (updateFields.numberOfEmployees) {
+ body.NumberOfEmployees = updateFields.numberOfEmployees as number;
+ }
+ responseData = await salesforceApiRequest.call(this, 'PATCH', `/sobjects/lead/${leadId}`, body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Lead/get-lead-id
+ if (operation === 'get') {
+ const leadId = this.getNodeParameter('leadId', i) as string;
+ responseData = await salesforceApiRequest.call(this, 'GET', `/sobjects/lead/${leadId}`);
+ }
+ //https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_query.htm
+ if (operation === 'getAll') {
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const fields = ['id'];
+ if (options.fields) {
+ // @ts-ignore
+ fields.push(...options.fields.split(','))
+ }
+ try {
+ if (returnAll) {
+ qs.q = `SELECT ${fields.join(',')} FROM Lead`,
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.q = `SELECT ${fields.join(',')} FROM Lead Limit ${limit}`;
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ }
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Lead/delete-lead-id
+ if (operation === 'delete') {
+ const leadId = this.getNodeParameter('leadId', i) as string;
+ try {
+ responseData = await salesforceApiRequest.call(this, 'DELETE', `/sobjects/lead/${leadId}`);
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Lead/get-lead
+ if (operation === 'getSummary') {
+ responseData = await salesforceApiRequest.call(this, 'GET', '/sobjects/lead');
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/CampaignMember
+ if (operation === 'addToCampaign') {
+ const leadId = this.getNodeParameter('leadId', i) as string;
+ const campaignId = this.getNodeParameter('campaignId', i) as string;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const body: ICampaignMember = {
+ LeadId: leadId,
+ CampaignId: campaignId,
+ };
+ if (options.status) {
+ body.Status = options.status as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/CampaignMember', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Note/post-note
+ if (operation === 'addNote') {
+ const leadId = this.getNodeParameter('leadId', i) as string;
+ const title = this.getNodeParameter('title', i) as string;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const body: INote = {
+ Title: title,
+ ParentId: leadId,
+ };
+ if (options.body) {
+ body.Body = options.body as string;
+ }
+ if (options.owner) {
+ body.OwnerId = options.owner as string;
+ }
+ if (options.isPrivate) {
+ body.IsPrivate = options.isPrivate as boolean;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/note', body);
+ }
+ }
+ if (resource === 'contact') {
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Contact/post-contact
+ if (operation === 'create') {
+ const lastname = this.getNodeParameter('lastname', i) as string;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const body: IContact = {
+ LastName: lastname,
+ };
+ if (additionalFields.fax) {
+ body.Fax = additionalFields.fax as string;
+ }
+ if (additionalFields.email) {
+ body.Email = additionalFields.email as string;
+ }
+ if (additionalFields.phone) {
+ body.Phone = additionalFields.phone as string;
+ }
+ if (additionalFields.title) {
+ body.Title = additionalFields.title as string;
+ }
+ if (additionalFields.jigsaw) {
+ body.Jigsaw = additionalFields.jigsaw as string;
+ }
+ if (additionalFields.owner) {
+ body.OwnerId = additionalFields.owner as string;
+ }
+ if (additionalFields.acconuntId) {
+ body.AccountId = additionalFields.acconuntId as string;
+ }
+ if (additionalFields.birthdate) {
+ body.Birthdate = additionalFields.birthdate as string;
+ }
+ if (additionalFields.firstName) {
+ body.FirstName = additionalFields.firstName as string;
+ }
+ if (additionalFields.homePhone) {
+ body.HomePhone = additionalFields.homePhone as string;
+ }
+ if (additionalFields.otherCity) {
+ body.OtherCity = additionalFields.otherCity as string;
+ }
+ if (additionalFields.department) {
+ body.Department = additionalFields.department as string;
+ }
+ if (additionalFields.leadSource) {
+ body.LeadSource = additionalFields.leadSource as string;
+ }
+ if (additionalFields.otherPhone) {
+ body.OtherPhone = additionalFields.otherPhone as string;
+ }
+ if (additionalFields.otherState) {
+ body.OtherState = additionalFields.otherState as string;
+ }
+ if (additionalFields.salutation) {
+ body.Salutation = additionalFields.salutation as string;
+ }
+ if (additionalFields.description) {
+ body.Description = additionalFields.description as string;
+ }
+ if (additionalFields.mailingCity) {
+ body.MailingCity = additionalFields.mailingCity as string;
+ }
+ if (additionalFields.mobilePhone) {
+ body.MobilePhone = additionalFields.mobilePhone as string;
+ }
+ if (additionalFields.otherStreet) {
+ body.OtherStreet = additionalFields.otherStreet as string;
+ }
+ if (additionalFields.mailingState) {
+ body.MailingState = additionalFields.mailingState as string;
+ }
+ if (additionalFields.otherCountry) {
+ body.OtherCountry = additionalFields.otherCountry as string;
+ }
+ if (additionalFields.assistantName) {
+ body.AssistantName = additionalFields.assistantName as string;
+ }
+ if (additionalFields.mailingStreet) {
+ body.MailingStreet = additionalFields.mailingStreet as string;
+ }
+ if (additionalFields.assistantPhone) {
+ body.AssistantPhone = additionalFields.assistantPhone as string;
+ }
+ if (additionalFields.mailingCountry) {
+ body.MailingCountry = additionalFields.mailingCountry as string;
+ }
+ if (additionalFields.otherPostalCode) {
+ body.OtherPostalCode = additionalFields.otherPostalCode as string;
+ }
+ if (additionalFields.emailBouncedDate) {
+ body.EmailBouncedDate = additionalFields.emailBouncedDate as string;
+ }
+ if (additionalFields.mailingPostalCode) {
+ body.MailingPostalCode = additionalFields.mailingPostalCode as string;
+ }
+ if (additionalFields.emailBouncedReason) {
+ body.EmailBouncedReason = additionalFields.emailBouncedReason as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/contact', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Contact/patch-contact-id
+ if (operation === 'update') {
+ const contactId = this.getNodeParameter('contactId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ const body: IContact = {};
+ if (!Object.keys(updateFields).length) {
+ throw new Error('You must add at least one update field');
+ }
+ if (updateFields.fax) {
+ body.Fax = updateFields.fax as string;
+ }
+ if (updateFields.email) {
+ body.Email = updateFields.email as string;
+ }
+ if (updateFields.phone) {
+ body.Phone = updateFields.phone as string;
+ }
+ if (updateFields.title) {
+ body.Title = updateFields.title as string;
+ }
+ if (updateFields.jigsaw) {
+ body.Jigsaw = updateFields.jigsaw as string;
+ }
+ if (updateFields.owner) {
+ body.OwnerId = updateFields.owner as string;
+ }
+ if (updateFields.acconuntId) {
+ body.AccountId = updateFields.acconuntId as string;
+ }
+ if (updateFields.birthdate) {
+ body.Birthdate = updateFields.birthdate as string;
+ }
+ if (updateFields.firstName) {
+ body.FirstName = updateFields.firstName as string;
+ }
+ if (updateFields.homePhone) {
+ body.HomePhone = updateFields.homePhone as string;
+ }
+ if (updateFields.otherCity) {
+ body.OtherCity = updateFields.otherCity as string;
+ }
+ if (updateFields.department) {
+ body.Department = updateFields.department as string;
+ }
+ if (updateFields.leadSource) {
+ body.LeadSource = updateFields.leadSource as string;
+ }
+ if (updateFields.otherPhone) {
+ body.OtherPhone = updateFields.otherPhone as string;
+ }
+ if (updateFields.otherState) {
+ body.OtherState = updateFields.otherState as string;
+ }
+ if (updateFields.salutation) {
+ body.Salutation = updateFields.salutation as string;
+ }
+ if (updateFields.description) {
+ body.Description = updateFields.description as string;
+ }
+ if (updateFields.mailingCity) {
+ body.MailingCity = updateFields.mailingCity as string;
+ }
+ if (updateFields.mobilePhone) {
+ body.MobilePhone = updateFields.mobilePhone as string;
+ }
+ if (updateFields.otherStreet) {
+ body.OtherStreet = updateFields.otherStreet as string;
+ }
+ if (updateFields.mailingState) {
+ body.MailingState = updateFields.mailingState as string;
+ }
+ if (updateFields.otherCountry) {
+ body.OtherCountry = updateFields.otherCountry as string;
+ }
+ if (updateFields.assistantName) {
+ body.AssistantName = updateFields.assistantName as string;
+ }
+ if (updateFields.mailingStreet) {
+ body.MailingStreet = updateFields.mailingStreet as string;
+ }
+ if (updateFields.assistantPhone) {
+ body.AssistantPhone = updateFields.assistantPhone as string;
+ }
+ if (updateFields.mailingCountry) {
+ body.MailingCountry = updateFields.mailingCountry as string;
+ }
+ if (updateFields.otherPostalCode) {
+ body.OtherPostalCode = updateFields.otherPostalCode as string;
+ }
+ if (updateFields.emailBouncedDate) {
+ body.EmailBouncedDate = updateFields.emailBouncedDate as string;
+ }
+ if (updateFields.mailingPostalCode) {
+ body.MailingPostalCode = updateFields.mailingPostalCode as string;
+ }
+ if (updateFields.emailBouncedReason) {
+ body.EmailBouncedReason = updateFields.emailBouncedReason as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'PATCH', `/sobjects/contact/${contactId}`, body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Contact/get-contact-id
+ if (operation === 'get') {
+ const contactId = this.getNodeParameter('contactId', i) as string;
+ responseData = await salesforceApiRequest.call(this, 'GET', `/sobjects/contact/${contactId}`);
+ }
+ //https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_query.htm
+ if (operation === 'getAll') {
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const fields = ['id'];
+ if (options.fields) {
+ // @ts-ignore
+ fields.push(...options.fields.split(','))
+ }
+ try {
+ if (returnAll) {
+ qs.q = `SELECT ${fields.join(',')} FROM Contact`,
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.q = `SELECT ${fields.join(',')} FROM Contact Limit ${limit}`;
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ }
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Contact/delete-contact-id
+ if (operation === 'delete') {
+ const contactId = this.getNodeParameter('contactId', i) as string;
+ try {
+ responseData = await salesforceApiRequest.call(this, 'DELETE', `/sobjects/contact/${contactId}`);
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Contact/get-contact
+ if (operation === 'getSummary') {
+ responseData = await salesforceApiRequest.call(this, 'GET', '/sobjects/contact');
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/CampaignMember
+ if (operation === 'addToCampaign') {
+ const contactId = this.getNodeParameter('contactId', i) as string;
+ const campaignId = this.getNodeParameter('campaignId', i) as string;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const body: ICampaignMember = {
+ ContactId: contactId,
+ CampaignId: campaignId,
+ };
+ if (options.status) {
+ body.Status = options.status as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/CampaignMember', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Note/post-note
+ if (operation === 'addNote') {
+ const contactId = this.getNodeParameter('contactId', i) as string;
+ const title = this.getNodeParameter('title', i) as string;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const body: INote = {
+ Title: title,
+ ParentId: contactId,
+ };
+ if (options.body) {
+ body.Body = options.body as string;
+ }
+ if (options.owner) {
+ body.OwnerId = options.owner as string;
+ }
+ if (options.isPrivate) {
+ body.IsPrivate = options.isPrivate as boolean;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/note', body);
+ }
+ }
+ if (resource === 'opportunity') {
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Opportunity/post-opportunity
+ if (operation === 'create') {
+ const name = this.getNodeParameter('name', i) as string;
+ const closeDate = this.getNodeParameter('closeDate', i) as string;
+ const stageName = this.getNodeParameter('stageName', i) as string;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const body: IOpportunity = {
+ Name: name,
+ CloseDate: closeDate,
+ StageName: stageName,
+ };
+ if (additionalFields.type) {
+ body.Type = additionalFields.type as string;
+ }
+ if (additionalFields.ammount) {
+ body.Amount = additionalFields.ammount as number;
+ }
+ if (additionalFields.owner) {
+ body.OwnerId = additionalFields.owner as string;
+ }
+ if (additionalFields.nextStep) {
+ body.NextStep = additionalFields.nextStep as string;
+ }
+ if (additionalFields.accountId) {
+ body.AccountId = additionalFields.accountId as string;
+ }
+ if (additionalFields.campaignId) {
+ body.CampaignId = additionalFields.campaignId as string;
+ }
+ if (additionalFields.leadSource) {
+ body.LeadSource = additionalFields.leadSource as string;
+ }
+ if (additionalFields.description) {
+ body.Description = additionalFields.description as string;
+ }
+ if (additionalFields.probability) {
+ body.Probability = additionalFields.probability as number;
+ }
+ if (additionalFields.pricebook2Id) {
+ body.Pricebook2Id = additionalFields.pricebook2Id as string;
+ }
+ if (additionalFields.forecastCategoryName) {
+ body.ForecastCategoryName = additionalFields.forecastCategoryName as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/opportunity', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Opportunity/post-opportunity
+ if (operation === 'update') {
+ const opportunityId = this.getNodeParameter('opportunityId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ const body: IOpportunity = {};
+ if (updateFields.name) {
+ body.Name = updateFields.name as string;
+ }
+ if (updateFields.closeDate) {
+ body.CloseDate = updateFields.closeDate as string;
+ }
+ if (updateFields.stageName) {
+ body.StageName = updateFields.stageName as string;
+ }
+ if (updateFields.type) {
+ body.Type = updateFields.type as string;
+ }
+ if (updateFields.ammount) {
+ body.Amount = updateFields.ammount as number;
+ }
+ if (updateFields.owner) {
+ body.OwnerId = updateFields.owner as string;
+ }
+ if (updateFields.nextStep) {
+ body.NextStep = updateFields.nextStep as string;
+ }
+ if (updateFields.accountId) {
+ body.AccountId = updateFields.accountId as string;
+ }
+ if (updateFields.campaignId) {
+ body.CampaignId = updateFields.campaignId as string;
+ }
+ if (updateFields.leadSource) {
+ body.LeadSource = updateFields.leadSource as string;
+ }
+ if (updateFields.description) {
+ body.Description = updateFields.description as string;
+ }
+ if (updateFields.probability) {
+ body.Probability = updateFields.probability as number;
+ }
+ if (updateFields.pricebook2Id) {
+ body.Pricebook2Id = updateFields.pricebook2Id as string;
+ }
+ if (updateFields.forecastCategoryName) {
+ body.ForecastCategoryName = updateFields.forecastCategoryName as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'PATCH', `/sobjects/opportunity/${opportunityId}`, body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Opportunity/get-opportunity-id
+ if (operation === 'get') {
+ const opportunityId = this.getNodeParameter('opportunityId', i) as string;
+ responseData = await salesforceApiRequest.call(this, 'GET', `/sobjects/opportunity/${opportunityId}`);
+ }
+ //https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_query.htm
+ if (operation === 'getAll') {
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const fields = ['id'];
+ if (options.fields) {
+ // @ts-ignore
+ fields.push(...options.fields.split(','))
+ }
+ try {
+ if (returnAll) {
+ qs.q = `SELECT ${fields.join(',')} FROM Opportunity`,
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.q = `SELECT ${fields.join(',')} FROM Opportunity Limit ${limit}`;
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ }
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Opportunity/delete-opportunity-id
+ if (operation === 'delete') {
+ const opportunityId = this.getNodeParameter('opportunityId', i) as string;
+ try {
+ responseData = await salesforceApiRequest.call(this, 'DELETE', `/sobjects/opportunity/${opportunityId}`);
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Opportunity/get-opportunity
+ if (operation === 'getSummary') {
+ responseData = await salesforceApiRequest.call(this, 'GET', '/sobjects/opportunity');
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Note/post-note
+ if (operation === 'addNote') {
+ const opportunityId = this.getNodeParameter('opportunityId', i) as string;
+ const title = this.getNodeParameter('title', i) as string;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const body: INote = {
+ Title: title,
+ ParentId: opportunityId,
+ };
+ if (options.body) {
+ body.Body = options.body as string;
+ }
+ if (options.owner) {
+ body.OwnerId = options.owner as string;
+ }
+ if (options.isPrivate) {
+ body.IsPrivate = options.isPrivate as boolean;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/note', body);
+ }
+ }
+ if (resource === 'account') {
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Account/post-account
+ if (operation === 'create') {
+ const name = this.getNodeParameter('name', i) as string;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const body: IAccount = {
+ Name: name,
+ };
+ if (additionalFields.fax) {
+ body.Fax = additionalFields.fax as string;
+ }
+ if (additionalFields.type) {
+ body.Type = additionalFields.type as string;
+ }
+ if (additionalFields.jigsaw) {
+ body.Jigsaw = additionalFields.jigsaw as string;
+ }
+ if (additionalFields.phone) {
+ body.Phone = additionalFields.phone as string;
+ }
+ if (additionalFields.owner) {
+ body.OwnerId = additionalFields.owner as string;
+ }
+ if (additionalFields.sicDesc) {
+ body.SicDesc = additionalFields.sicDesc as string;
+ }
+ if (additionalFields.website) {
+ body.Website = additionalFields.website as string;
+ }
+ if (additionalFields.industry) {
+ body.Industry = additionalFields.industry as string;
+ }
+ if (additionalFields.parentId) {
+ body.ParentId = additionalFields.parentId as string;
+ }
+ if (additionalFields.billingCity) {
+ body.BillingCity = additionalFields.billingCity as string;
+ }
+ if (additionalFields.description) {
+ body.Description = additionalFields.description as string;
+ }
+ if (additionalFields.billingState) {
+ body.BillingState = additionalFields.billingState as string;
+ }
+ if (additionalFields.shippingCity) {
+ body.ShippingCity = additionalFields.shippingCity as string;
+ }
+ if (additionalFields.accountSource) {
+ body.AccountSource = additionalFields.accountSource as string;
+ }
+ if (additionalFields.annualRevenue) {
+ body.AnnualRevenue = additionalFields.annualRevenue as number;
+ }
+ if (additionalFields.billingStreet) {
+ body.BillingStreet = additionalFields.billingStreet as string;
+ }
+ if (additionalFields.shippingState) {
+ body.ShippingState = additionalFields.shippingState as string;
+ }
+ if (additionalFields.billingCountry) {
+ body.BillingCountry = additionalFields.billingCountry as string;
+ }
+ if (additionalFields.shippingStreet) {
+ body.ShippingStreet = additionalFields.shippingStreet as string;
+ }
+ if (additionalFields.shippingCountry) {
+ body.ShippingCountry = additionalFields.shippingCountry as string;
+ }
+ if (additionalFields.billingPostalCode) {
+ body.BillingPostalCode = additionalFields.billingPostalCode as string;
+ }
+ if (additionalFields.numberOfEmployees) {
+ body.NumberOfEmployees = additionalFields.numberOfEmployees as string;
+ }
+ if (additionalFields.shippingPostalCode) {
+ body.ShippingPostalCode = additionalFields.shippingPostalCode as string;
+ }
+ if (additionalFields.shippingPostalCode) {
+ body.ShippingPostalCode = additionalFields.shippingPostalCode as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/account', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Account/patch-account-id
+ if (operation === 'update') {
+ const accountId = this.getNodeParameter('accountId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ const body: IAccount = {};
+ if (updateFields.name) {
+ body.Name = updateFields.name as string;
+ }
+ if (updateFields.fax) {
+ body.Fax = updateFields.fax as string;
+ }
+ if (updateFields.type) {
+ body.Type = updateFields.type as string;
+ }
+ if (updateFields.jigsaw) {
+ body.Jigsaw = updateFields.jigsaw as string;
+ }
+ if (updateFields.phone) {
+ body.Phone = updateFields.phone as string;
+ }
+ if (updateFields.owner) {
+ body.OwnerId = updateFields.owner as string;
+ }
+ if (updateFields.sicDesc) {
+ body.SicDesc = updateFields.sicDesc as string;
+ }
+ if (updateFields.website) {
+ body.Website = updateFields.website as string;
+ }
+ if (updateFields.industry) {
+ body.Industry = updateFields.industry as string;
+ }
+ if (updateFields.parentId) {
+ body.ParentId = updateFields.parentId as string;
+ }
+ if (updateFields.billingCity) {
+ body.BillingCity = updateFields.billingCity as string;
+ }
+ if (updateFields.description) {
+ body.Description = updateFields.description as string;
+ }
+ if (updateFields.billingState) {
+ body.BillingState = updateFields.billingState as string;
+ }
+ if (updateFields.shippingCity) {
+ body.ShippingCity = updateFields.shippingCity as string;
+ }
+ if (updateFields.accountSource) {
+ body.AccountSource = updateFields.accountSource as string;
+ }
+ if (updateFields.annualRevenue) {
+ body.AnnualRevenue = updateFields.annualRevenue as number;
+ }
+ if (updateFields.billingStreet) {
+ body.BillingStreet = updateFields.billingStreet as string;
+ }
+ if (updateFields.shippingState) {
+ body.ShippingState = updateFields.shippingState as string;
+ }
+ if (updateFields.billingCountry) {
+ body.BillingCountry = updateFields.billingCountry as string;
+ }
+ if (updateFields.shippingStreet) {
+ body.ShippingStreet = updateFields.shippingStreet as string;
+ }
+ if (updateFields.shippingCountry) {
+ body.ShippingCountry = updateFields.shippingCountry as string;
+ }
+ if (updateFields.billingPostalCode) {
+ body.BillingPostalCode = updateFields.billingPostalCode as string;
+ }
+ if (updateFields.numberOfEmployees) {
+ body.NumberOfEmployees = updateFields.numberOfEmployees as string;
+ }
+ if (updateFields.shippingPostalCode) {
+ body.ShippingPostalCode = updateFields.shippingPostalCode as string;
+ }
+ if (updateFields.shippingPostalCode) {
+ body.ShippingPostalCode = updateFields.shippingPostalCode as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'PATCH', `/sobjects/account/${accountId}`, body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Account/get-account-id
+ if (operation === 'get') {
+ const accountId = this.getNodeParameter('accountId', i) as string;
+ responseData = await salesforceApiRequest.call(this, 'GET', `/sobjects/account/${accountId}`);
+ }
+ //https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_query.htm
+ if (operation === 'getAll') {
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const fields = ['id'];
+ if (options.fields) {
+ // @ts-ignore
+ fields.push(...options.fields.split(','))
+ }
+ try {
+ if (returnAll) {
+ qs.q = `SELECT ${fields.join(',')} FROM Account`,
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.q = `SELECT ${fields.join(',')} FROM Account Limit ${limit}`;
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ }
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Account/delete-account-id
+ if (operation === 'delete') {
+ const accountId = this.getNodeParameter('accountId', i) as string;
+ try {
+ responseData = await salesforceApiRequest.call(this, 'DELETE', `/sobjects/account/${accountId}`);
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Account/get-account
+ if (operation === 'getSummary') {
+ responseData = await salesforceApiRequest.call(this, 'GET', '/sobjects/account');
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Note/post-note
+ if (operation === 'addNote') {
+ const accountId = this.getNodeParameter('accountId', i) as string;
+ const title = this.getNodeParameter('title', i) as string;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const body: INote = {
+ Title: title,
+ ParentId: accountId,
+ };
+ if (options.body) {
+ body.Body = options.body as string;
+ }
+ if (options.owner) {
+ body.OwnerId = options.owner as string;
+ }
+ if (options.isPrivate) {
+ body.IsPrivate = options.isPrivate as boolean;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/note', body);
+ }
+ }
+ if (resource === 'case') {
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Case/post-case
+ if (operation === 'create') {
+ const type = this.getNodeParameter('type', i) as string;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const body: ICase = {
+ Type: type,
+ };
+ if (additionalFields.origin) {
+ body.Origin = additionalFields.origin as string;
+ }
+ if (additionalFields.reason) {
+ body.Reason = additionalFields.reason as string;
+ }
+ if (additionalFields.owner) {
+ body.OwnerId = additionalFields.owner as string;
+ }
+ if (additionalFields.subject) {
+ body.Subject = additionalFields.subject as string;
+ }
+ if (additionalFields.parentId) {
+ body.ParentId = additionalFields.parentId as string;
+ }
+ if (additionalFields.priority) {
+ body.Priority = additionalFields.priority as string;
+ }
+ if (additionalFields.accountId) {
+ body.AccountId = additionalFields.accountId as string;
+ }
+ if (additionalFields.contactId) {
+ body.ContactId = additionalFields.contactId as string;
+ }
+ if (additionalFields.description) {
+ body.Description = additionalFields.description as string;
+ }
+ if (additionalFields.isEscalated) {
+ body.IsEscalated = additionalFields.isEscalated as boolean;
+ }
+ if (additionalFields.suppliedName) {
+ body.SuppliedName = additionalFields.suppliedName as string;
+ }
+ if (additionalFields.suppliedEmail) {
+ body.SuppliedEmail = additionalFields.suppliedEmail as string;
+ }
+ if (additionalFields.suppliedPhone) {
+ body.SuppliedPhone = additionalFields.suppliedPhone as string;
+ }
+ if (additionalFields.suppliedCompany) {
+ body.SuppliedCompany = additionalFields.suppliedCompany as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/case', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Case/patch-case-id
+ if (operation === 'update') {
+ const caseId = this.getNodeParameter('caseId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ const body: ICase = {};
+ if (updateFields.type) {
+ body.Type = updateFields.type as string;
+ }
+ if (updateFields.origin) {
+ body.Origin = updateFields.origin as string;
+ }
+ if (updateFields.reason) {
+ body.Reason = updateFields.reason as string;
+ }
+ if (updateFields.owner) {
+ body.OwnerId = updateFields.owner as string;
+ }
+ if (updateFields.subject) {
+ body.Subject = updateFields.subject as string;
+ }
+ if (updateFields.parentId) {
+ body.ParentId = updateFields.parentId as string;
+ }
+ if (updateFields.priority) {
+ body.Priority = updateFields.priority as string;
+ }
+ if (updateFields.accountId) {
+ body.AccountId = updateFields.accountId as string;
+ }
+ if (updateFields.contactId) {
+ body.ContactId = updateFields.contactId as string;
+ }
+ if (updateFields.description) {
+ body.Description = updateFields.description as string;
+ }
+ if (updateFields.isEscalated) {
+ body.IsEscalated = updateFields.isEscalated as boolean;
+ }
+ if (updateFields.suppliedName) {
+ body.SuppliedName = updateFields.suppliedName as string;
+ }
+ if (updateFields.suppliedEmail) {
+ body.SuppliedEmail = updateFields.suppliedEmail as string;
+ }
+ if (updateFields.suppliedPhone) {
+ body.SuppliedPhone = updateFields.suppliedPhone as string;
+ }
+ if (updateFields.suppliedCompany) {
+ body.SuppliedCompany = updateFields.suppliedCompany as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'PATCH', `/sobjects/case/${caseId}`, body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Case/get-case-id
+ if (operation === 'get') {
+ const caseId = this.getNodeParameter('caseId', i) as string;
+ responseData = await salesforceApiRequest.call(this, 'GET', `/sobjects/case/${caseId}`);
+ }
+ //https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_query.htm
+ if (operation === 'getAll') {
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const fields = ['id'];
+ if (options.fields) {
+ // @ts-ignore
+ fields.push(...options.fields.split(','))
+ }
+ try {
+ if (returnAll) {
+ qs.q = `SELECT ${fields.join(',')} FROM Case`,
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.q = `SELECT ${fields.join(',')} FROM Case Limit ${limit}`;
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ }
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Case/delete-case-id
+ if (operation === 'delete') {
+ const caseId = this.getNodeParameter('caseId', i) as string;
+ try {
+ responseData = await salesforceApiRequest.call(this, 'DELETE', `/sobjects/case/${caseId}`);
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Case/get-case
+ if (operation === 'getSummary') {
+ responseData = await salesforceApiRequest.call(this, 'GET', '/sobjects/case');
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/CaseComment/post-casecomment
+ if (operation === 'addComment') {
+ const caseId = this.getNodeParameter('caseId', i) as string;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const body: ICaseComment = {
+ ParentId: caseId,
+ };
+ if (options.commentBody) {
+ body.CommentBody = options.commentBody as string;
+ }
+ if (options.isPublished) {
+ body.IsPublished = options.isPublished as boolean;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/casecomment', body);
+ }
+ }
+ if (resource === 'task') {
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Task/post-task
+ if (operation === 'create') {
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const status = this.getNodeParameter('status', i) as string;
+ const body: ITask = {
+ Status: status,
+ };
+ if (additionalFields.whoId) {
+ body.WhoId = additionalFields.whoId as string;
+ }
+ if (additionalFields.whatId) {
+ body.WhatId = additionalFields.whatId as string;
+ }
+ if (additionalFields.owner) {
+ body.OwnerId = additionalFields.owner as string;
+ }
+ if (additionalFields.subject) {
+ body.Subject = additionalFields.subject as string;
+ }
+ if (additionalFields.callType) {
+ body.CallType = additionalFields.callType as string;
+ }
+ if (additionalFields.priority) {
+ body.Priority = additionalFields.priority as string;
+ }
+ if (additionalFields.callObject) {
+ body.CallObject = additionalFields.callObject as string;
+ }
+ if (additionalFields.description) {
+ body.Description = additionalFields.description as string;
+ }
+ if (additionalFields.activityDate) {
+ body.ActivityDate = additionalFields.activityDate as string;
+ }
+ if (additionalFields.isReminderSet) {
+ body.IsReminderSet = additionalFields.isReminderSet as boolean;
+ }
+ if (additionalFields.recurrenceType) {
+ body.RecurrenceType = additionalFields.recurrenceType as string;
+ }
+ if (additionalFields.callDisposition) {
+ body.CallDisposition = additionalFields.callDisposition as string;
+ }
+ if (additionalFields.reminderDateTime) {
+ body.ReminderDateTime = additionalFields.reminderDateTime as string;
+ }
+ if (additionalFields.recurrenceInstance) {
+ body.RecurrenceInstance = additionalFields.recurrenceInstance as string;
+ }
+ if (additionalFields.recurrenceInterval) {
+ body.RecurrenceInterval = additionalFields.recurrenceInterval as number;
+ }
+ if (additionalFields.recurrenceDayOfMonth) {
+ body.RecurrenceDayOfMonth = additionalFields.recurrenceDayOfMonth as number;
+ }
+ if (additionalFields.callDurationInSeconds) {
+ body.CallDurationInSeconds = additionalFields.callDurationInSeconds as number;
+ }
+ if (additionalFields.recurrenceEndDateOnly) {
+ body.RecurrenceEndDateOnly = additionalFields.recurrenceEndDateOnly as string;
+ }
+ if (additionalFields.recurrenceMonthOfYear) {
+ body.RecurrenceMonthOfYear = additionalFields.recurrenceMonthOfYear as string;
+ }
+ if (additionalFields.recurrenceDayOfWeekMask) {
+ body.RecurrenceDayOfWeekMask = additionalFields.recurrenceDayOfWeekMask as string;
+ }
+ if (additionalFields.recurrenceStartDateOnly) {
+ body.RecurrenceStartDateOnly = additionalFields.recurrenceStartDateOnly as string;
+ }
+ if (additionalFields.recurrenceTimeZoneSidKey) {
+ body.RecurrenceTimeZoneSidKey = additionalFields.recurrenceTimeZoneSidKey as string;
+ }
+ if (additionalFields.recurrenceRegeneratedType) {
+ body.RecurrenceRegeneratedType = additionalFields.recurrenceRegeneratedType as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/task', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Task/patch-task-id
+ if (operation === 'update') {
+ const taskId = this.getNodeParameter('taskId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ const body: ITask = {};
+ if (updateFields.whoId) {
+ body.WhoId = updateFields.whoId as string;
+ }
+ if (updateFields.status) {
+ body.Status = updateFields.status as string;
+ }
+ if (updateFields.whatId) {
+ body.WhatId = updateFields.whatId as string;
+ }
+ if (updateFields.owner) {
+ body.OwnerId = updateFields.owner as string;
+ }
+ if (updateFields.subject) {
+ body.Subject = updateFields.subject as string;
+ }
+ if (updateFields.callType) {
+ body.CallType = updateFields.callType as string;
+ }
+ if (updateFields.priority) {
+ body.Priority = updateFields.priority as string;
+ }
+ if (updateFields.callObject) {
+ body.CallObject = updateFields.callObject as string;
+ }
+ if (updateFields.description) {
+ body.Description = updateFields.description as string;
+ }
+ if (updateFields.activityDate) {
+ body.ActivityDate = updateFields.activityDate as string;
+ }
+ if (updateFields.isReminderSet) {
+ body.IsReminderSet = updateFields.isReminderSet as boolean;
+ }
+ if (updateFields.recurrenceType) {
+ body.RecurrenceType = updateFields.recurrenceType as string;
+ }
+ if (updateFields.callDisposition) {
+ body.CallDisposition = updateFields.callDisposition as string;
+ }
+ if (updateFields.reminderDateTime) {
+ body.ReminderDateTime = updateFields.reminderDateTime as string;
+ }
+ if (updateFields.recurrenceInstance) {
+ body.RecurrenceInstance = updateFields.recurrenceInstance as string;
+ }
+ if (updateFields.recurrenceInterval) {
+ body.RecurrenceInterval = updateFields.recurrenceInterval as number;
+ }
+ if (updateFields.recurrenceDayOfMonth) {
+ body.RecurrenceDayOfMonth = updateFields.recurrenceDayOfMonth as number;
+ }
+ if (updateFields.callDurationInSeconds) {
+ body.CallDurationInSeconds = updateFields.callDurationInSeconds as number;
+ }
+ if (updateFields.recurrenceEndDateOnly) {
+ body.RecurrenceEndDateOnly = updateFields.recurrenceEndDateOnly as string;
+ }
+ if (updateFields.recurrenceMonthOfYear) {
+ body.RecurrenceMonthOfYear = updateFields.recurrenceMonthOfYear as string;
+ }
+ if (updateFields.recurrenceDayOfWeekMask) {
+ body.RecurrenceDayOfWeekMask = updateFields.recurrenceDayOfWeekMask as string;
+ }
+ if (updateFields.recurrenceStartDateOnly) {
+ body.RecurrenceStartDateOnly = updateFields.recurrenceStartDateOnly as string;
+ }
+ if (updateFields.recurrenceTimeZoneSidKey) {
+ body.RecurrenceTimeZoneSidKey = updateFields.recurrenceTimeZoneSidKey as string;
+ }
+ if (updateFields.recurrenceRegeneratedType) {
+ body.RecurrenceRegeneratedType = updateFields.recurrenceRegeneratedType as string;
+ }
+ responseData = await salesforceApiRequest.call(this, 'PATCH', `/sobjects/task/${taskId}`, body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Task/get-task-id
+ if (operation === 'get') {
+ const taskId = this.getNodeParameter('taskId', i) as string;
+ responseData = await salesforceApiRequest.call(this, 'GET', `/sobjects/task/${taskId}`);
+ }
+ //https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_query.htm
+ if (operation === 'getAll') {
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const fields = ['id'];
+ if (options.fields) {
+ // @ts-ignore
+ fields.push(...options.fields.split(','))
+ }
+ try {
+ if (returnAll) {
+ qs.q = `SELECT ${fields.join(',')} FROM Task`,
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.q = `SELECT ${fields.join(',')} FROM Task Limit ${limit}`;
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ }
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Task/delete-task-id
+ if (operation === 'delete') {
+ const taskId = this.getNodeParameter('taskId', i) as string;
+ try {
+ responseData = await salesforceApiRequest.call(this, 'DELETE', `/sobjects/task/${taskId}`);
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Task/get-task
+ if (operation === 'getSummary') {
+ responseData = await salesforceApiRequest.call(this, 'GET', '/sobjects/task');
+ }
+ }
+ if (resource === 'attachment') {
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Attachment/post-attachment
+ if (operation === 'create') {
+ const name = this.getNodeParameter('name', i) as string;
+ const parentId = this.getNodeParameter('parentId', i) as string;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i) as string;
+ const body: IAttachment = {
+ Name: name,
+ ParentId: parentId,
+ };
+ if (items[i].binary && items[i].binary![binaryPropertyName]) {
+ body.Body = items[i].binary![binaryPropertyName].data;
+ body.ContentType = items[i].binary![binaryPropertyName].mimeType;
+ } else {
+ throw new Error(`The property ${binaryPropertyName} does not exist`);
+ }
+ if (additionalFields.description) {
+ body.Description = additionalFields.description as string;
+ }
+ if (additionalFields.owner) {
+ body.OwnerId = additionalFields.owner as string;
+ }
+ if (additionalFields.isPrivate) {
+ body.IsPrivate = additionalFields.isPrivate as boolean;
+ }
+ responseData = await salesforceApiRequest.call(this, 'POST', '/sobjects/attachment', body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Attachment/patch-attachment-id
+ if (operation === 'update') {
+ const attachmentId = this.getNodeParameter('attachmentId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ const body: IAttachment = {};
+ if (updateFields.binaryPropertyName) {
+ const binaryPropertyName = updateFields.binaryPropertyName as string;
+ if (items[i].binary && items[i].binary![binaryPropertyName]) {
+ body.Body = items[i].binary![binaryPropertyName].data;
+ body.ContentType = items[i].binary![binaryPropertyName].mimeType;
+ } else {
+ throw new Error(`The property ${binaryPropertyName} does not exist`);
+ }
+ }
+ if (updateFields.name) {
+ body.Name = updateFields.name as string;
+ }
+ if (updateFields.description) {
+ body.Description = updateFields.description as string;
+ }
+ if (updateFields.owner) {
+ body.OwnerId = updateFields.owner as string;
+ }
+ if (updateFields.isPrivate) {
+ body.IsPrivate = updateFields.isPrivate as boolean;
+ }
+ responseData = await salesforceApiRequest.call(this, 'PATCH', `/sobjects/attachment/${attachmentId}`, body);
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Attachment/get-attachment-id
+ if (operation === 'get') {
+ const attachmentId = this.getNodeParameter('attachmentId', i) as string;
+ responseData = await salesforceApiRequest.call(this, 'GET', `/sobjects/attachment/${attachmentId}`);
+ }
+ //https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_query.htm
+ if (operation === 'getAll') {
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ const fields = ['id'];
+ if (options.fields) {
+ // @ts-ignore
+ fields.push(...options.fields.split(','))
+ }
+ try {
+ if (returnAll) {
+ qs.q = `SELECT ${fields.join(',')} FROM Attachment`,
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.q = `SELECT ${fields.join(',')} FROM Attachment Limit ${limit}`;
+ responseData = await salesforceApiRequestAllItems.call(this, 'records', 'GET', '/query', {}, qs);
+ }
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Attachment/delete-attachment-id
+ if (operation === 'delete') {
+ const attachmentId = this.getNodeParameter('attachmentId', i) as string;
+ try {
+ responseData = await salesforceApiRequest.call(this, 'DELETE', `/sobjects/attachment/${attachmentId}`);
+ } catch(err) {
+ throw new Error(`Salesforce Error: ${err}`);
+ }
+ }
+ //https://developer.salesforce.com/docs/api-explorer/sobject/Attachment/get-attachment-id
+ if (operation === 'getSummary') {
+ responseData = await salesforceApiRequest.call(this, 'GET', '/sobjects/attachment');
+ }
+ }
+ 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/Salesforce/TaskDescription.ts b/packages/nodes-base/nodes/Salesforce/TaskDescription.ts
new file mode 100644
index 0000000000..79e13ec34f
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/TaskDescription.ts
@@ -0,0 +1,810 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const taskOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a task',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update a task',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a task',
+ },
+ {
+ name: 'Get Summary',
+ value: 'getSummary',
+ description: `Returns an overview of task's metadata.`,
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all tasks',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete a task',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const taskFields = [
+
+/* -------------------------------------------------------------------------- */
+/* task:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ typeOptions: {
+ loadOptionsMethod: 'getTaskStatuses',
+ },
+ description: 'The current status of the task, such as In Progress or Completed.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Who Id',
+ name: 'whoId',
+ type: 'string',
+ default: '',
+ description: `The WhoId represents a human such as a lead or a contact.
+ WhoIds are polymorphic. Polymorphic means a WhoId is equivalent to a contact’s ID or a lead’s ID.`,
+ },
+ {
+ displayName: 'What Id',
+ name: 'whatId',
+ type: 'string',
+ default: '',
+ description: `The WhatId represents nonhuman objects such as accounts, opportunities,
+ campaigns, cases, or custom objects. WhatIds are polymorphic. Polymorphic means a
+ WhatId is equivalent to the ID of a related object.`,
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the User who owns the record.',
+ },
+ {
+ displayName: 'Subject',
+ name: 'subject',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskSubjects',
+ },
+ description: 'The subject line of the task, such as “Call” or “Send Quote.” Limit: 255 characters.',
+ },
+ {
+ displayName: 'Call Type',
+ name: 'callType',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskCallTypes',
+ },
+ description: 'The type of call being answered: Inbound, Internal, or Outbound.',
+ },
+ {
+ displayName: 'Priority',
+ name: 'priority',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskPriorities',
+ },
+ description: `Indicates the importance or urgency of a task, such as high or low.`,
+ },
+ {
+ displayName: 'Call Object',
+ name: 'callObject',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Name of a call center. Limit is 255 characters.
+ Not subject to field-level security, available for any user in an
+ organization with Salesforce CRM Call Center.`,
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'Contains a text description of the task.',
+ },
+ {
+ displayName: 'Activity Date',
+ name: 'activityDate',
+ type: 'dateTime',
+ default: '',
+ description: `Represents the due date of the task.
+ This field has a timestamp that is always set to midnight
+ in the Coordinated Universal Time (UTC) time zone.`,
+ },
+ {
+ displayName: 'Is ReminderSet',
+ name: 'isReminderSet',
+ type: 'boolean',
+ default: false,
+ description: 'Indicates whether a popup reminder has been set for the task (true) or not (false).',
+ },
+ {
+ displayName: 'Recurrence Type',
+ name: 'recurrenceType',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskRecurrenceTypes'
+ },
+ description: 'Website for the task.',
+ },
+ {
+ displayName: 'Call Disposition',
+ name: 'callDisposition',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Represents the result of a given call, for example, “we'll call back,” or “call
+ unsuccessful.” Limit is 255 characters. Not subject to field-level security, available for any user
+ in an organization with Salesforce CRM Call Center.`,
+ },
+ {
+ displayName: 'Reminder Date Time',
+ name: 'reminderDateTime',
+ type: 'dateTime',
+ default: '',
+ description: `Represents the time when the reminder is scheduled to fire,
+ if IsReminderSet is set to true. If IsReminderSet is set to false, then the
+ user may have deselected the reminder checkbox in the Salesforce user interface,
+ or the reminder has already fired at the time indicated by the value.`,
+ },
+ {
+ displayName: 'Recurrence Instance',
+ name: 'recurrenceInstance',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskRecurrenceInstances',
+ },
+ default: '',
+ description: `The frequency of the recurring task. For example, “2nd” or “3rd.”`,
+ },
+ {
+ displayName: 'Recurrence Interval',
+ name: 'recurrenceInterval',
+ type: 'number',
+ default: '',
+ description: 'The interval between recurring tasks.',
+ },
+ {
+ displayName: 'Recurrence Day Of Month',
+ name: 'recurrenceDayOfMonth',
+ type: 'number',
+ default: '',
+ description: 'The day of the month in which the task repeats.',
+ },
+ {
+ displayName: 'Call Duration In Seconds',
+ name: 'callDurationInSeconds',
+ type: 'number',
+ default: '',
+ description: `Duration of the call in seconds. Not subject to field-level security,
+ available for any user in an organization with Salesforce CRM Call Cente`,
+ },
+ {
+ displayName: 'Recurrence End Date Only',
+ name: 'recurrenceEndDateOnly',
+ type: 'dateTime',
+ default: '',
+ description: `The last date on which the task repeats. This field has a timestamp that
+ is always set to midnight in the Coordinated Universal Time (UTC) time zone.`,
+ },
+ {
+ displayName: 'Recurrence Month Of Year',
+ name: 'recurrenceMonthOfYear',
+ type: 'options',
+ options: [
+ {
+ name: 'January',
+ value: 'January'
+ },
+ {
+ name: 'February',
+ value: 'February'
+ },
+ {
+ name: 'March',
+ value: 'March'
+ },
+ {
+ name: 'April',
+ value: 'April'
+ },
+ {
+ name: 'May',
+ value: 'May'
+ },
+ {
+ name: 'June',
+ value: 'June'
+ },
+ {
+ name: 'July',
+ value: 'July'
+ },
+ {
+ name: 'August',
+ value: 'August'
+ },
+ {
+ name: 'September',
+ value: 'September'
+ },
+ {
+ name: 'October',
+ value: 'October'
+ },
+ {
+ name: 'November',
+ value: 'November'
+ },
+ {
+ name: 'December',
+ value: 'December'
+ }
+ ],
+ default: '',
+ description: 'The month of the year in which the task repeats.',
+ },
+ {
+ displayName: 'Recurrence Day Of Week Mask',
+ name: 'recurrenceDayOfWeekMask',
+ type: 'number',
+ default: '',
+ description: `The day or days of the week on which the task repeats.
+ This field contains a bitmask. The values are as follows: Sunday = 1 Monday = 2
+ Tuesday = 4 Wednesday = 8 Thursday = 16 Friday = 32 Saturday = 64
+ Multiple days are represented as the sum of their numerical values.
+ For example, Tuesday and Thursday = 4 + 16 = 20.`,
+ },
+ {
+ displayName: 'recurrence Start Date Only',
+ name: 'recurrenceEndDateOnly',
+ type: 'dateTime',
+ default: '',
+ description: `The date when the recurring task begins.
+ Must be a date and time before RecurrenceEndDateOnly.`,
+ },
+ {
+ displayName: 'Recurrence TimeZone SidKey',
+ name: 'recurrenceTimeZoneSidKey',
+ type: 'string',
+ default: '',
+ description: `The time zone associated with the recurring task.
+ For example, “UTC-8:00” for Pacific Standard Time.`,
+ },
+ {
+ displayName: 'Recurrence Regenerated Type',
+ name: 'recurrenceRegeneratedType',
+ type: 'options',
+ default: '',
+ options: [
+ {
+ name: 'After due date',
+ value: 'RecurrenceRegenerateAfterDueDate'
+ },
+ {
+ name: 'After date completed',
+ value: 'RecurrenceRegenerateAfterToday'
+ },
+ {
+ name: '(Task Closed)',
+ value: 'RecurrenceRegenerated'
+ }
+ ],
+ description: `Represents what triggers a repeating task to repeat.
+ Add this field to a page layout together with the RecurrenceInterval field,
+ which determines the number of days between the triggering date (due date or close date)
+ and the due date of the next repeating task in the series.Label is Repeat This Task.`,
+ },
+ ]
+ },
+/* -------------------------------------------------------------------------- */
+/* task:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Task ID',
+ name: 'taskId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ operation: [
+ 'update',
+ ]
+ },
+ },
+ description: 'Id of task that needs to be fetched',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ operation: [
+ 'update',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Who Id',
+ name: 'whoId',
+ type: 'string',
+ default: '',
+ description: `The WhoId represents a human such as a lead or a contact.
+ WhoIds are polymorphic. Polymorphic means a WhoId is equivalent to a contact’s ID or a lead’s ID.`,
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskStatuses',
+ },
+ description: 'The current status of the task, such as In Progress or Completed.',
+ },
+ {
+ displayName: 'What Id',
+ name: 'whatId',
+ type: 'string',
+ default: '',
+ description: `The WhatId represents nonhuman objects such as accounts, opportunities,
+ campaigns, cases, or custom objects. WhatIds are polymorphic. Polymorphic means a
+ WhatId is equivalent to the ID of a related object.`,
+ },
+ {
+ displayName: 'Owner',
+ name: 'owner',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getUsers',
+ },
+ default: '',
+ description: 'ID of the User who owns the record.',
+ },
+ {
+ displayName: 'Subject',
+ name: 'subject',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskSubjects',
+ },
+ description: 'The subject line of the task, such as “Call” or “Send Quote.” Limit: 255 characters.',
+ },
+ {
+ displayName: 'Call Type',
+ name: 'callType',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskCallTypes',
+ },
+ description: 'The type of call being answered: Inbound, Internal, or Outbound.',
+ },
+ {
+ displayName: 'Priority',
+ name: 'priority',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskPriorities',
+ },
+ description: `Indicates the importance or urgency of a task, such as high or low.`,
+ },
+ {
+ displayName: 'Call Object',
+ name: 'callObject',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Name of a call center. Limit is 255 characters.
+ Not subject to field-level security, available for any user in an
+ organization with Salesforce CRM Call Center.`,
+ },
+ {
+ displayName: 'Description',
+ name: 'description',
+ type: 'string',
+ default: '',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ description: 'Contains a text description of the task.',
+ },
+ {
+ displayName: 'Activity Date',
+ name: 'activityDate',
+ type: 'dateTime',
+ default: '',
+ description: `Represents the due date of the task.
+ This field has a timestamp that is always set to midnight
+ in the Coordinated Universal Time (UTC) time zone.`,
+ },
+ {
+ displayName: 'Is ReminderSet',
+ name: 'isReminderSet',
+ type: 'boolean',
+ default: false,
+ description: 'Indicates whether a popup reminder has been set for the task (true) or not (false).',
+ },
+ {
+ displayName: 'Recurrence Type',
+ name: 'recurrenceType',
+ type: 'options',
+ default: '',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskRecurrenceTypes'
+ },
+ description: 'Website for the task.',
+ },
+ {
+ displayName: 'Call Disposition',
+ name: 'callDisposition',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Represents the result of a given call, for example, “we'll call back,” or “call
+ unsuccessful.” Limit is 255 characters. Not subject to field-level security, available for any user
+ in an organization with Salesforce CRM Call Center.`,
+ },
+ {
+ displayName: 'Reminder Date Time',
+ name: 'reminderDateTime',
+ type: 'dateTime',
+ default: '',
+ description: `Represents the time when the reminder is scheduled to fire,
+ if IsReminderSet is set to true. If IsReminderSet is set to false, then the
+ user may have deselected the reminder checkbox in the Salesforce user interface,
+ or the reminder has already fired at the time indicated by the value.`,
+ },
+ {
+ displayName: 'Recurrence Instance',
+ name: 'recurrenceInstance',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getTaskRecurrenceInstances',
+ },
+ default: '',
+ description: `The frequency of the recurring task. For example, “2nd” or “3rd.”`,
+ },
+ {
+ displayName: 'Recurrence Interval',
+ name: 'recurrenceInterval',
+ type: 'number',
+ default: '',
+ description: 'The interval between recurring tasks.',
+ },
+ {
+ displayName: 'Recurrence Day Of Month',
+ name: 'recurrenceDayOfMonth',
+ type: 'number',
+ default: '',
+ description: 'The day of the month in which the task repeats.',
+ },
+ {
+ displayName: 'Call Duration In Seconds',
+ name: 'callDurationInSeconds',
+ type: 'number',
+ default: '',
+ description: `Duration of the call in seconds. Not subject to field-level security,
+ available for any user in an organization with Salesforce CRM Call Cente`,
+ },
+ {
+ displayName: 'Recurrence End Date Only',
+ name: 'recurrenceEndDateOnly',
+ type: 'dateTime',
+ default: '',
+ description: `The last date on which the task repeats. This field has a timestamp that
+ is always set to midnight in the Coordinated Universal Time (UTC) time zone.`,
+ },
+ {
+ displayName: 'Recurrence Month Of Year',
+ name: 'recurrenceMonthOfYear',
+ type: 'options',
+ options: [
+ {
+ name: 'January',
+ value: 'January'
+ },
+ {
+ name: 'February',
+ value: 'February'
+ },
+ {
+ name: 'March',
+ value: 'March'
+ },
+ {
+ name: 'April',
+ value: 'April'
+ },
+ {
+ name: 'May',
+ value: 'May'
+ },
+ {
+ name: 'June',
+ value: 'June'
+ },
+ {
+ name: 'July',
+ value: 'July'
+ },
+ {
+ name: 'August',
+ value: 'August'
+ },
+ {
+ name: 'September',
+ value: 'September'
+ },
+ {
+ name: 'October',
+ value: 'October'
+ },
+ {
+ name: 'November',
+ value: 'November'
+ },
+ {
+ name: 'December',
+ value: 'December'
+ }
+ ],
+ default: '',
+ description: 'The month of the year in which the task repeats.',
+ },
+ {
+ displayName: 'Recurrence Day Of Week Mask',
+ name: 'recurrenceDayOfWeekMask',
+ type: 'number',
+ default: '',
+ description: `The day or days of the week on which the task repeats.
+ This field contains a bitmask. The values are as follows: Sunday = 1 Monday = 2
+ Tuesday = 4 Wednesday = 8 Thursday = 16 Friday = 32 Saturday = 64
+ Multiple days are represented as the sum of their numerical values.
+ For example, Tuesday and Thursday = 4 + 16 = 20.`,
+ },
+ {
+ displayName: 'recurrence Start Date Only',
+ name: 'recurrenceEndDateOnly',
+ type: 'dateTime',
+ default: '',
+ description: `The date when the recurring task begins.
+ Must be a date and time before RecurrenceEndDateOnly.`,
+ },
+ {
+ displayName: 'Recurrence TimeZone SidKey',
+ name: 'recurrenceTimeZoneSidKey',
+ type: 'string',
+ default: '',
+ description: `The time zone associated with the recurring task.
+ For example, “UTC-8:00” for Pacific Standard Time.`,
+ },
+ {
+ displayName: 'Recurrence Regenerated Type',
+ name: 'recurrenceRegeneratedType',
+ type: 'options',
+ default: '',
+ options: [
+ {
+ name: 'After due date',
+ value: 'RecurrenceRegenerateAfterDueDate'
+ },
+ {
+ name: 'After date completed',
+ value: 'RecurrenceRegenerateAfterToday'
+ },
+ {
+ name: '(Task Closed)',
+ value: 'RecurrenceRegenerated'
+ }
+ ],
+ description: `Represents what triggers a repeating task to repeat.
+ Add this field to a page layout together with the RecurrenceInterval field,
+ which determines the number of days between the triggering date (due date or close date)
+ and the due date of the next repeating task in the series.Label is Repeat This Task.`,
+ },
+ ]
+ },
+
+/* -------------------------------------------------------------------------- */
+/* task:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Task ID',
+ name: 'taskId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ operation: [
+ 'get',
+ ]
+ },
+ },
+ description: 'Id of task that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* task:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Task ID',
+ name: 'taskId',
+ type: 'string',
+ required: true,
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ operation: [
+ 'delete',
+ ]
+ },
+ },
+ description: 'Id of task that needs to be fetched',
+ },
+/* -------------------------------------------------------------------------- */
+/* task:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ 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: [
+ 'task',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 50,
+ description: 'How many results to return.',
+ },
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'task',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Fields',
+ name: 'fields',
+ type: 'string',
+ default: '',
+ description: 'Fields to include separated by ,',
+ },
+ ]
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Salesforce/TaskInterface.ts b/packages/nodes-base/nodes/Salesforce/TaskInterface.ts
new file mode 100644
index 0000000000..06f932e799
--- /dev/null
+++ b/packages/nodes-base/nodes/Salesforce/TaskInterface.ts
@@ -0,0 +1,27 @@
+
+export interface ITask {
+ WhoId?: string;
+ Status?: string;
+ WhatId?: string;
+ OwnerId?: string;
+ Subject?: string;
+ CallType?: string;
+ Priority?: string;
+ CallObject?: string;
+ Description?: string;
+ ActivityDate?: string;
+ IsReminderSet?: boolean;
+ RecurrenceType?: string;
+ CallDisposition?:string;
+ ReminderDateTime?: string;
+ RecurrenceInstance?: string;
+ RecurrenceInterval?: number;
+ RecurrenceDayOfMonth?: number;
+ CallDurationInSeconds?: number;
+ RecurrenceEndDateOnly?: string;
+ RecurrenceMonthOfYear?: string;
+ RecurrenceDayOfWeekMask?: string;
+ RecurrenceStartDateOnly?: string;
+ RecurrenceTimeZoneSidKey?: string;
+ RecurrenceRegeneratedType?: string;
+}
diff --git a/packages/nodes-base/nodes/Salesforce/salesforce.png b/packages/nodes-base/nodes/Salesforce/salesforce.png
new file mode 100644
index 0000000000..17876e8dea
Binary files /dev/null and b/packages/nodes-base/nodes/Salesforce/salesforce.png differ
diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json
index 0ae62f9f07..938424c6c9 100644
--- a/packages/nodes-base/package.json
+++ b/packages/nodes-base/package.json
@@ -69,6 +69,7 @@
"dist/credentials/SlackApi.credentials.js",
"dist/credentials/Smtp.credentials.js",
"dist/credentials/StripeApi.credentials.js",
+ "dist/credentials/SalesforceOAuth2Api.credentials.js",
"dist/credentials/TelegramApi.credentials.js",
"dist/credentials/TodoistApi.credentials.js",
"dist/credentials/TrelloApi.credentials.js",
@@ -160,6 +161,7 @@
"dist/nodes/Stripe/StripeTrigger.node.js",
"dist/nodes/Shopify/ShopifyTrigger.node.js",
"dist/nodes/Switch.node.js",
+ "dist/nodes/Salesforce/Salesforce.node.js",
"dist/nodes/Telegram/Telegram.node.js",
"dist/nodes/Telegram/TelegramTrigger.node.js",
"dist/nodes/Todoist/Todoist.node.js",