n8n-nodes-idb2b 1.1.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -382,6 +382,12 @@ class IDB2B {
382
382
  },
383
383
  },
384
384
  options: [
385
+ {
386
+ name: 'Get All',
387
+ value: 'getAll',
388
+ action: 'Get all activities for a lead',
389
+ description: 'Retrieve all activities for a specific lead',
390
+ },
385
391
  {
386
392
  name: 'Create',
387
393
  value: 'create',
@@ -389,7 +395,7 @@ class IDB2B {
389
395
  description: 'Create a new activity for a lead',
390
396
  },
391
397
  ],
392
- default: 'create',
398
+ default: 'getAll',
393
399
  },
394
400
  {
395
401
  displayName: 'Operation',
@@ -801,10 +807,10 @@ class IDB2B {
801
807
  displayOptions: {
802
808
  show: {
803
809
  resource: ['leadActivities'],
804
- operation: ['create'],
810
+ operation: ['create', 'getAll'],
805
811
  },
806
812
  },
807
- description: 'ID of the lead to add activity to',
813
+ description: 'ID of the lead to get activities for or add activity to',
808
814
  },
809
815
  {
810
816
  displayName: 'Subject',
@@ -916,6 +922,124 @@ class IDB2B {
916
922
  },
917
923
  ],
918
924
  },
925
+ {
926
+ displayName: 'Limit',
927
+ name: 'limit',
928
+ type: 'number',
929
+ default: 50,
930
+ description: 'Maximum number of activities to return',
931
+ displayOptions: {
932
+ show: {
933
+ resource: ['leadActivities'],
934
+ operation: ['getAll'],
935
+ },
936
+ },
937
+ },
938
+ {
939
+ displayName: 'Page',
940
+ name: 'page',
941
+ type: 'number',
942
+ default: 1,
943
+ description: 'Page number to retrieve',
944
+ displayOptions: {
945
+ show: {
946
+ resource: ['leadActivities'],
947
+ operation: ['getAll'],
948
+ },
949
+ },
950
+ },
951
+ {
952
+ displayName: 'Fields to Return',
953
+ name: 'fields',
954
+ type: 'multiOptions',
955
+ default: [],
956
+ description: 'Select specific fields to return (leave empty for all fields)',
957
+ displayOptions: {
958
+ show: {
959
+ resource: ['leadActivities'],
960
+ operation: ['getAll'],
961
+ },
962
+ },
963
+ options: [
964
+ {
965
+ name: 'ID',
966
+ value: 'id',
967
+ },
968
+ {
969
+ name: 'Lead ID',
970
+ value: 'lead_id',
971
+ },
972
+ {
973
+ name: 'Icon',
974
+ value: 'icon',
975
+ },
976
+ {
977
+ name: 'Subject',
978
+ value: 'subject',
979
+ },
980
+ {
981
+ name: 'Description',
982
+ value: 'description',
983
+ },
984
+ {
985
+ name: 'Date and Time',
986
+ value: 'datetime',
987
+ },
988
+ {
989
+ name: 'User ID',
990
+ value: 'user_id',
991
+ },
992
+ {
993
+ name: 'Attachments',
994
+ value: 'attachments',
995
+ },
996
+ {
997
+ name: 'Created At',
998
+ value: 'created_at',
999
+ },
1000
+ {
1001
+ name: 'Updated At',
1002
+ value: 'updated_at',
1003
+ },
1004
+ ],
1005
+ },
1006
+ {
1007
+ displayName: 'Query Parameters',
1008
+ name: 'queryParameters',
1009
+ type: 'fixedCollection',
1010
+ typeOptions: {
1011
+ multipleValues: true,
1012
+ },
1013
+ default: {},
1014
+ placeholder: 'Add Parameter',
1015
+ description: 'Additional query parameters',
1016
+ displayOptions: {
1017
+ show: {
1018
+ resource: ['leadActivities'],
1019
+ operation: ['getAll'],
1020
+ },
1021
+ },
1022
+ options: [
1023
+ {
1024
+ name: 'parameter',
1025
+ displayName: 'Parameter',
1026
+ values: [
1027
+ {
1028
+ displayName: 'Name',
1029
+ name: 'name',
1030
+ type: 'string',
1031
+ default: '',
1032
+ },
1033
+ {
1034
+ displayName: 'Value',
1035
+ name: 'value',
1036
+ type: 'string',
1037
+ default: '',
1038
+ },
1039
+ ],
1040
+ },
1041
+ ],
1042
+ },
919
1043
  {
920
1044
  displayName: 'Endpoint',
921
1045
  name: 'endpoint',
@@ -1239,7 +1363,25 @@ class IDB2B {
1239
1363
  }
1240
1364
  }
1241
1365
  else if (resource === 'leadActivities') {
1242
- if (operation === 'create') {
1366
+ if (operation === 'getAll') {
1367
+ method = 'GET';
1368
+ const leadId = this.getNodeParameter('lead_id', i);
1369
+ // Validate required fields
1370
+ if (!leadId || typeof leadId !== 'string' || leadId.trim().length === 0) {
1371
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Lead ID is required and must be a non-empty string', { itemIndex: i });
1372
+ }
1373
+ endpoint = `/leads/${leadId.trim()}/activities`;
1374
+ // Add pagination parameters
1375
+ const limit = this.getNodeParameter('limit', i, 50);
1376
+ const page = this.getNodeParameter('page', i, 1);
1377
+ qs.limit = limit;
1378
+ qs.page = page;
1379
+ // Add additional query parameters
1380
+ const queryParameters = this.getNodeParameter('queryParameters', i, {});
1381
+ const additionalQs = buildQueryString(queryParameters);
1382
+ qs = Object.assign(Object.assign({}, qs), additionalQs);
1383
+ }
1384
+ else if (operation === 'create') {
1243
1385
  method = 'POST';
1244
1386
  const leadId = this.getNodeParameter('lead_id', i);
1245
1387
  const subject = this.getNodeParameter('subject', i);
@@ -1356,6 +1498,21 @@ class IDB2B {
1356
1498
  }) });
1357
1499
  }
1358
1500
  }
1501
+ // Apply field filtering for leadActivities getAll operation
1502
+ if (resource === 'leadActivities' && operation === 'getAll') {
1503
+ const fieldsToReturn = this.getNodeParameter('fields', i, []);
1504
+ if (fieldsToReturn.length > 0 && Array.isArray(response.data)) {
1505
+ processedResponse = Object.assign(Object.assign({}, response), { data: response.data.map((activity) => {
1506
+ const filteredActivity = {};
1507
+ fieldsToReturn.forEach(field => {
1508
+ if (field in activity) {
1509
+ filteredActivity[field] = activity[field];
1510
+ }
1511
+ });
1512
+ return filteredActivity;
1513
+ }) });
1514
+ }
1515
+ }
1359
1516
  returnData.push({
1360
1517
  json: processedResponse,
1361
1518
  pairedItem: { item: i },
@@ -6,6 +6,8 @@ const authentication_1 = require("./methods/authentication");
6
6
  const requests_1 = require("./methods/requests");
7
7
  const validation_1 = require("./methods/validation");
8
8
  const utils_1 = require("./methods/utils");
9
+ const LeadService_1 = require("./services/LeadService");
10
+ const LeadOperations_1 = require("./handlers/LeadOperations");
9
11
  const sharedProperties_1 = require("./descriptions/sharedProperties");
10
12
  const contactProperties_1 = require("./descriptions/contactProperties");
11
13
  const leadProperties_1 = require("./descriptions/leadProperties");
@@ -123,36 +125,19 @@ class IDB2B {
123
125
  }
124
126
  // Handle Lead operations
125
127
  else if (resource === 'lead') {
126
- if (operation === 'getAll') {
127
- method = 'GET';
128
- endpoint = '/leads';
129
- const limit = this.getNodeParameter('limit', i, 50);
130
- const page = this.getNodeParameter('page', i, 1);
131
- qs.limit = limit;
132
- qs.page = page;
133
- const queryParameters = this.getNodeParameter('queryParameters', i, {});
134
- const additionalQs = (0, utils_1.buildQueryString)(queryParameters);
135
- qs = Object.assign(Object.assign({}, qs), additionalQs);
136
- }
137
- else if (operation === 'create') {
138
- method = 'POST';
139
- endpoint = '/leads';
140
- const name = this.getNodeParameter('name', i);
141
- const additionalFields = this.getNodeParameter('additionalFields', i, {});
142
- (0, validation_1.validateLeadData)(name);
143
- body = { name: name.trim() };
144
- // Add additional fields if provided
145
- const fieldMappings = [
146
- 'owner_id', 'website', 'description', 'status_id', 'source_id',
147
- 'size_id', 'industry_id', 'main_contact_id', 'contact_name',
148
- 'contact_email', 'contact_phone_number'
149
- ];
150
- fieldMappings.forEach(field => {
151
- if (additionalFields[field]) {
152
- body[field] = additionalFields[field];
153
- }
154
- });
155
- }
128
+ const leadService = new LeadService_1.LeadService({
129
+ executeFunctions: this,
130
+ credentials,
131
+ accessToken,
132
+ itemIndex: i,
133
+ });
134
+ const leadOperations = new LeadOperations_1.LeadOperations(leadService, this, i);
135
+ const response = await leadOperations.execute(operation);
136
+ returnData.push({
137
+ json: response,
138
+ pairedItem: { item: i },
139
+ });
140
+ continue;
156
141
  }
157
142
  // Handle Custom operations
158
143
  else if (resource === 'custom') {
@@ -173,36 +158,39 @@ class IDB2B {
173
158
  const queryParameters = this.getNodeParameter('queryParameters', i, {});
174
159
  qs = (0, utils_1.buildQueryString)(queryParameters);
175
160
  }
176
- const response = await (0, requests_1.makeRequestWithRetry)(this, {
177
- method,
178
- url: `${credentials.baseUrl}${endpoint}`,
179
- headers: {
180
- Authorization: `Bearer ${accessToken}`,
181
- },
182
- body,
183
- qs,
184
- json: true,
185
- });
186
- let processedResponse = response;
187
- // Apply field filtering for getAll operations
188
- if (operation === 'getAll') {
189
- const fieldsToReturn = this.getNodeParameter('fields', i, []);
190
- if (fieldsToReturn.length > 0 && Array.isArray(response.data)) {
191
- processedResponse = Object.assign(Object.assign({}, response), { data: response.data.map((item) => {
192
- const filteredItem = {};
193
- fieldsToReturn.forEach(field => {
194
- if (field in item) {
195
- filteredItem[field] = item[field];
196
- }
197
- });
198
- return filteredItem;
199
- }) });
161
+ // Only execute request for contact and custom operations
162
+ if (resource === 'contact' || resource === 'custom') {
163
+ const response = await (0, requests_1.makeRequestWithRetry)(this, {
164
+ method,
165
+ url: `${credentials.baseUrl}${endpoint}`,
166
+ headers: {
167
+ Authorization: `Bearer ${accessToken}`,
168
+ },
169
+ body,
170
+ qs,
171
+ json: true,
172
+ });
173
+ let processedResponse = response;
174
+ // Apply field filtering for contact getAll operations
175
+ if (resource === 'contact' && operation === 'getAll') {
176
+ const fieldsToReturn = this.getNodeParameter('fields', i, []);
177
+ if (fieldsToReturn.length > 0 && Array.isArray(response.data)) {
178
+ processedResponse = Object.assign(Object.assign({}, response), { data: response.data.map((item) => {
179
+ const filteredItem = {};
180
+ fieldsToReturn.forEach(field => {
181
+ if (field in item) {
182
+ filteredItem[field] = item[field];
183
+ }
184
+ });
185
+ return filteredItem;
186
+ }) });
187
+ }
200
188
  }
189
+ returnData.push({
190
+ json: processedResponse,
191
+ pairedItem: { item: i },
192
+ });
201
193
  }
202
- returnData.push({
203
- json: processedResponse,
204
- pairedItem: { item: i },
205
- });
206
194
  }
207
195
  catch (error) {
208
196
  if (this.continueOnFail()) {
@@ -18,16 +18,125 @@ exports.leadOperations = {
18
18
  action: 'Get all leads',
19
19
  description: 'Retrieve all leads',
20
20
  },
21
+ {
22
+ name: 'Get',
23
+ value: 'get',
24
+ action: 'Get a lead',
25
+ description: 'Get a single lead by ID',
26
+ },
21
27
  {
22
28
  name: 'Create',
23
29
  value: 'create',
24
30
  action: 'Create a lead',
25
31
  description: 'Create a new lead',
26
32
  },
33
+ {
34
+ name: 'Update',
35
+ value: 'update',
36
+ action: 'Update a lead',
37
+ description: 'Update an existing lead',
38
+ },
39
+ {
40
+ name: 'Delete',
41
+ value: 'delete',
42
+ action: 'Delete a lead',
43
+ description: 'Delete a lead by ID',
44
+ },
45
+ {
46
+ name: 'Create Multiple',
47
+ value: 'createMultiple',
48
+ action: 'Create multiple leads',
49
+ description: 'Create multiple leads in bulk',
50
+ },
51
+ {
52
+ name: 'Delete Multiple',
53
+ value: 'deleteMultiple',
54
+ action: 'Delete multiple leads',
55
+ description: 'Delete multiple leads by IDs',
56
+ },
57
+ {
58
+ name: 'Get Call Logs',
59
+ value: 'getCallLogs',
60
+ action: 'Get lead call logs',
61
+ description: 'Get call logs for a specific lead',
62
+ },
63
+ {
64
+ name: 'Assign New Contact',
65
+ value: 'assignNewContact',
66
+ action: 'Assign new contact to lead',
67
+ description: 'Create and assign a new contact to a lead',
68
+ },
69
+ {
70
+ name: 'Assign Contacts',
71
+ value: 'assignContacts',
72
+ action: 'Assign contacts to lead',
73
+ description: 'Assign existing contacts to a lead',
74
+ },
75
+ {
76
+ name: 'Remove Contact',
77
+ value: 'removeContact',
78
+ action: 'Remove contact from lead',
79
+ description: 'Remove a contact from a lead',
80
+ },
81
+ {
82
+ name: 'Import',
83
+ value: 'import',
84
+ action: 'Import leads',
85
+ description: 'Import leads from CSV/Excel file',
86
+ },
87
+ {
88
+ name: 'Get Import Template',
89
+ value: 'getImportTemplate',
90
+ action: 'Get import template',
91
+ description: 'Download import template for leads',
92
+ },
93
+ {
94
+ name: 'Geocode',
95
+ value: 'geocode',
96
+ action: 'Geocode lead address',
97
+ description: 'Manually geocode a lead address',
98
+ },
99
+ {
100
+ name: 'Search Nearby',
101
+ value: 'searchNearby',
102
+ action: 'Find leads near location',
103
+ description: 'Find leads near a specific location',
104
+ },
27
105
  ],
28
106
  default: 'getAll',
29
107
  };
30
108
  exports.leadFields = [
109
+ // Lead ID field for operations that require it
110
+ {
111
+ displayName: 'Lead ID',
112
+ name: 'leadId',
113
+ type: 'string',
114
+ default: '',
115
+ required: true,
116
+ displayOptions: {
117
+ show: {
118
+ resource: ['lead'],
119
+ operation: ['get', 'update', 'delete', 'getCallLogs', 'assignNewContact', 'assignContacts', 'removeContact', 'geocode'],
120
+ },
121
+ },
122
+ description: 'ID of the lead',
123
+ },
124
+ // Contact ID field for remove contact operation
125
+ {
126
+ displayName: 'Contact ID',
127
+ name: 'contactId',
128
+ type: 'string',
129
+ default: '',
130
+ required: true,
131
+ displayOptions: {
132
+ show: {
133
+ resource: ['lead'],
134
+ operation: ['removeContact'],
135
+ },
136
+ },
137
+ description: 'ID of the contact to remove from the lead',
138
+ },
139
+ // Name field for create and update operations
31
140
  {
32
141
  displayName: 'Name',
33
142
  name: 'name',
@@ -42,6 +151,93 @@ exports.leadFields = [
42
151
  },
43
152
  description: 'Lead name',
44
153
  },
154
+ {
155
+ displayName: 'Name',
156
+ name: 'name',
157
+ type: 'string',
158
+ default: '',
159
+ displayOptions: {
160
+ show: {
161
+ resource: ['lead'],
162
+ operation: ['update'],
163
+ },
164
+ },
165
+ description: 'Lead name (leave empty to keep current value)',
166
+ },
167
+ // Lead IDs for bulk operations
168
+ {
169
+ displayName: 'Lead IDs',
170
+ name: 'leadIds',
171
+ type: 'string',
172
+ default: '',
173
+ required: true,
174
+ displayOptions: {
175
+ show: {
176
+ resource: ['lead'],
177
+ operation: ['deleteMultiple'],
178
+ },
179
+ },
180
+ description: 'Comma-separated list of lead IDs to delete',
181
+ },
182
+ // Contact IDs for assign contacts operation
183
+ {
184
+ displayName: 'Contact IDs',
185
+ name: 'contactIds',
186
+ type: 'string',
187
+ default: '',
188
+ required: true,
189
+ displayOptions: {
190
+ show: {
191
+ resource: ['lead'],
192
+ operation: ['assignContacts'],
193
+ },
194
+ },
195
+ description: 'Comma-separated list of contact IDs to assign to the lead',
196
+ },
197
+ // Leads data for bulk create
198
+ {
199
+ displayName: 'Leads Data',
200
+ name: 'leadsData',
201
+ type: 'json',
202
+ default: '[]',
203
+ required: true,
204
+ displayOptions: {
205
+ show: {
206
+ resource: ['lead'],
207
+ operation: ['createMultiple'],
208
+ },
209
+ },
210
+ description: 'Array of lead objects to create',
211
+ },
212
+ // Location fields for search nearby
213
+ {
214
+ displayName: 'Latitude',
215
+ name: 'latitude',
216
+ type: 'number',
217
+ default: 0,
218
+ required: true,
219
+ displayOptions: {
220
+ show: {
221
+ resource: ['lead'],
222
+ operation: ['searchNearby'],
223
+ },
224
+ },
225
+ description: 'Latitude for nearby search',
226
+ },
227
+ {
228
+ displayName: 'Longitude',
229
+ name: 'longitude',
230
+ type: 'number',
231
+ default: 0,
232
+ required: true,
233
+ displayOptions: {
234
+ show: {
235
+ resource: ['lead'],
236
+ operation: ['searchNearby'],
237
+ },
238
+ },
239
+ description: 'Longitude for nearby search',
240
+ },
45
241
  {
46
242
  displayName: 'Additional Fields',
47
243
  name: 'additionalFields',
@@ -51,7 +247,7 @@ exports.leadFields = [
51
247
  displayOptions: {
52
248
  show: {
53
249
  resource: ['lead'],
54
- operation: ['create'],
250
+ operation: ['create', 'update'],
55
251
  },
56
252
  },
57
253
  options: [
@@ -134,16 +330,159 @@ exports.leadFields = [
134
330
  },
135
331
  ],
136
332
  },
333
+ // Additional fields for specialized operations
334
+ {
335
+ displayName: 'New Contact Data',
336
+ name: 'newContactData',
337
+ type: 'collection',
338
+ placeholder: 'Add Contact Field',
339
+ default: {},
340
+ displayOptions: {
341
+ show: {
342
+ resource: ['lead'],
343
+ operation: ['assignNewContact'],
344
+ },
345
+ },
346
+ options: [
347
+ {
348
+ displayName: 'Name',
349
+ name: 'name',
350
+ type: 'string',
351
+ default: '',
352
+ required: true,
353
+ description: 'Contact name',
354
+ },
355
+ {
356
+ displayName: 'Email',
357
+ name: 'email',
358
+ type: 'string',
359
+ default: '',
360
+ required: true,
361
+ description: 'Contact email',
362
+ },
363
+ {
364
+ displayName: 'Phone Number',
365
+ name: 'phone_number',
366
+ type: 'string',
367
+ default: '',
368
+ description: 'Contact phone number',
369
+ },
370
+ ],
371
+ },
372
+ {
373
+ displayName: 'Geocode Data',
374
+ name: 'geocodeData',
375
+ type: 'collection',
376
+ placeholder: 'Add Geocode Field',
377
+ default: {},
378
+ displayOptions: {
379
+ show: {
380
+ resource: ['lead'],
381
+ operation: ['geocode'],
382
+ },
383
+ },
384
+ options: [
385
+ {
386
+ displayName: 'Address',
387
+ name: 'address',
388
+ type: 'string',
389
+ default: '',
390
+ description: 'Address to geocode',
391
+ },
392
+ {
393
+ displayName: 'Latitude',
394
+ name: 'latitude',
395
+ type: 'number',
396
+ default: 0,
397
+ description: 'Latitude coordinate',
398
+ },
399
+ {
400
+ displayName: 'Longitude',
401
+ name: 'longitude',
402
+ type: 'number',
403
+ default: 0,
404
+ description: 'Longitude coordinate',
405
+ },
406
+ ],
407
+ },
408
+ {
409
+ displayName: 'Import Data',
410
+ name: 'importData',
411
+ type: 'collection',
412
+ placeholder: 'Add Import Field',
413
+ default: {},
414
+ displayOptions: {
415
+ show: {
416
+ resource: ['lead'],
417
+ operation: ['import'],
418
+ },
419
+ },
420
+ options: [
421
+ {
422
+ displayName: 'File Path/URL',
423
+ name: 'file',
424
+ type: 'string',
425
+ default: '',
426
+ description: 'Path or URL to the import file (CSV/Excel)',
427
+ },
428
+ {
429
+ displayName: 'Field Mapping (JSON)',
430
+ name: 'mapping',
431
+ type: 'json',
432
+ default: '{}',
433
+ description: 'JSON object mapping CSV columns to lead fields',
434
+ },
435
+ ],
436
+ },
437
+ {
438
+ displayName: 'Search Options',
439
+ name: 'searchOptions',
440
+ type: 'collection',
441
+ placeholder: 'Add Search Option',
442
+ default: {},
443
+ displayOptions: {
444
+ show: {
445
+ resource: ['lead'],
446
+ operation: ['searchNearby'],
447
+ },
448
+ },
449
+ options: [
450
+ {
451
+ displayName: 'Radius',
452
+ name: 'radius',
453
+ type: 'number',
454
+ default: 10,
455
+ description: 'Search radius',
456
+ },
457
+ {
458
+ displayName: 'Unit',
459
+ name: 'unit',
460
+ type: 'options',
461
+ default: 'km',
462
+ options: [
463
+ {
464
+ name: 'Kilometers',
465
+ value: 'km',
466
+ },
467
+ {
468
+ name: 'Miles',
469
+ value: 'miles',
470
+ },
471
+ ],
472
+ description: 'Distance unit',
473
+ },
474
+ ],
475
+ },
137
476
  {
138
477
  displayName: 'Limit',
139
478
  name: 'limit',
140
479
  type: 'number',
141
480
  default: 50,
142
- description: 'Maximum number of leads to return',
481
+ description: 'Maximum number of records to return',
143
482
  displayOptions: {
144
483
  show: {
145
484
  resource: ['lead'],
146
- operation: ['getAll'],
485
+ operation: ['getAll', 'getCallLogs', 'searchNearby'],
147
486
  },
148
487
  },
149
488
  },
@@ -156,7 +495,7 @@ exports.leadFields = [
156
495
  displayOptions: {
157
496
  show: {
158
497
  resource: ['lead'],
159
- operation: ['getAll'],
498
+ operation: ['getAll', 'getCallLogs', 'searchNearby'],
160
499
  },
161
500
  },
162
501
  },
@@ -0,0 +1,24 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ import { LeadService } from '../services/LeadService';
3
+ export declare class LeadOperations {
4
+ private leadService;
5
+ private executeFunctions;
6
+ private itemIndex;
7
+ constructor(leadService: LeadService, executeFunctions: IExecuteFunctions, itemIndex: number);
8
+ execute(operation: string): Promise<any>;
9
+ private handleGetAll;
10
+ private handleGet;
11
+ private handleCreate;
12
+ private handleUpdate;
13
+ private handleDelete;
14
+ private handleCreateMultiple;
15
+ private handleDeleteMultiple;
16
+ private handleGetCallLogs;
17
+ private handleAssignNewContact;
18
+ private handleAssignContacts;
19
+ private handleRemoveContact;
20
+ private handleImport;
21
+ private handleGetImportTemplate;
22
+ private handleGeocode;
23
+ private handleSearchNearby;
24
+ }
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LeadOperations = void 0;
4
+ const utils_1 = require("../methods/utils");
5
+ class LeadOperations {
6
+ constructor(leadService, executeFunctions, itemIndex) {
7
+ this.leadService = leadService;
8
+ this.executeFunctions = executeFunctions;
9
+ this.itemIndex = itemIndex;
10
+ }
11
+ async execute(operation) {
12
+ switch (operation) {
13
+ case 'getAll':
14
+ return this.handleGetAll();
15
+ case 'get':
16
+ return this.handleGet();
17
+ case 'create':
18
+ return this.handleCreate();
19
+ case 'update':
20
+ return this.handleUpdate();
21
+ case 'delete':
22
+ return this.handleDelete();
23
+ case 'createMultiple':
24
+ return this.handleCreateMultiple();
25
+ case 'deleteMultiple':
26
+ return this.handleDeleteMultiple();
27
+ case 'getCallLogs':
28
+ return this.handleGetCallLogs();
29
+ case 'assignNewContact':
30
+ return this.handleAssignNewContact();
31
+ case 'assignContacts':
32
+ return this.handleAssignContacts();
33
+ case 'removeContact':
34
+ return this.handleRemoveContact();
35
+ case 'import':
36
+ return this.handleImport();
37
+ case 'getImportTemplate':
38
+ return this.handleGetImportTemplate();
39
+ case 'geocode':
40
+ return this.handleGeocode();
41
+ case 'searchNearby':
42
+ return this.handleSearchNearby();
43
+ default:
44
+ throw new Error(`Unknown operation: ${operation}`);
45
+ }
46
+ }
47
+ async handleGetAll() {
48
+ const limit = this.executeFunctions.getNodeParameter('limit', this.itemIndex, 50);
49
+ const page = this.executeFunctions.getNodeParameter('page', this.itemIndex, 1);
50
+ const fields = this.executeFunctions.getNodeParameter('fields', this.itemIndex, []);
51
+ const queryParameters = this.executeFunctions.getNodeParameter('queryParameters', this.itemIndex, {});
52
+ // Build query parameters
53
+ const queryParams = {};
54
+ if (queryParameters === null || queryParameters === void 0 ? void 0 : queryParameters.parameter) {
55
+ queryParameters.parameter.forEach((param) => {
56
+ if (param.name && param.value !== undefined) {
57
+ queryParams[param.name] = param.value;
58
+ }
59
+ });
60
+ }
61
+ return await this.leadService.getAll({
62
+ limit,
63
+ page,
64
+ fields,
65
+ queryParams,
66
+ });
67
+ }
68
+ async handleGet() {
69
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
70
+ return await this.leadService.getById(leadId);
71
+ }
72
+ async handleCreate() {
73
+ const name = this.executeFunctions.getNodeParameter('name', this.itemIndex);
74
+ const additionalFields = this.executeFunctions.getNodeParameter('additionalFields', this.itemIndex, {});
75
+ const leadData = {
76
+ name: name.trim(),
77
+ };
78
+ // Add additional fields
79
+ const optionalFields = [
80
+ 'owner_id', 'website', 'description', 'status_id', 'source_id',
81
+ 'size_id', 'industry_id', 'main_contact_id', 'contact_name',
82
+ 'contact_email', 'contact_phone_number'
83
+ ];
84
+ optionalFields.forEach(field => {
85
+ if (additionalFields[field] !== undefined) {
86
+ leadData[field] = additionalFields[field];
87
+ }
88
+ });
89
+ return await this.leadService.create(leadData);
90
+ }
91
+ async handleUpdate() {
92
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
93
+ const name = this.executeFunctions.getNodeParameter('name', this.itemIndex, '');
94
+ const additionalFields = this.executeFunctions.getNodeParameter('additionalFields', this.itemIndex, {});
95
+ const updateData = {};
96
+ // Add name if provided
97
+ if (name && name.trim()) {
98
+ updateData.name = name.trim();
99
+ }
100
+ // Add additional fields
101
+ const optionalFields = [
102
+ 'owner_id', 'website', 'description', 'status_id', 'source_id',
103
+ 'size_id', 'industry_id', 'main_contact_id', 'contact_name',
104
+ 'contact_email', 'contact_phone_number'
105
+ ];
106
+ optionalFields.forEach(field => {
107
+ if (additionalFields[field] !== undefined) {
108
+ updateData[field] = additionalFields[field];
109
+ }
110
+ });
111
+ return await this.leadService.update(leadId, updateData);
112
+ }
113
+ async handleDelete() {
114
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
115
+ return await this.leadService.delete(leadId);
116
+ }
117
+ async handleCreateMultiple() {
118
+ const leadsDataString = this.executeFunctions.getNodeParameter('leadsData', this.itemIndex);
119
+ const leadsData = (0, utils_1.safeJsonParse)(leadsDataString, 'Leads Data');
120
+ if (!Array.isArray(leadsData)) {
121
+ throw new Error('Leads data must be an array');
122
+ }
123
+ return await this.leadService.bulkCreate(leadsData);
124
+ }
125
+ async handleDeleteMultiple() {
126
+ const leadIdsString = this.executeFunctions.getNodeParameter('leadIds', this.itemIndex);
127
+ const leadIds = leadIdsString.split(',').map(id => id.trim()).filter(id => id);
128
+ if (leadIds.length === 0) {
129
+ throw new Error('At least one lead ID is required');
130
+ }
131
+ return await this.leadService.bulkDelete(leadIds);
132
+ }
133
+ async handleGetCallLogs() {
134
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
135
+ const limit = this.executeFunctions.getNodeParameter('limit', this.itemIndex, 50);
136
+ const page = this.executeFunctions.getNodeParameter('page', this.itemIndex, 1);
137
+ return await this.leadService.getCallLogs(leadId, { limit, page });
138
+ }
139
+ async handleAssignNewContact() {
140
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
141
+ const newContactData = this.executeFunctions.getNodeParameter('newContactData', this.itemIndex, {});
142
+ return await this.leadService.assignNewContact(leadId, newContactData);
143
+ }
144
+ async handleAssignContacts() {
145
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
146
+ const contactIdsString = this.executeFunctions.getNodeParameter('contactIds', this.itemIndex);
147
+ const contactIds = contactIdsString.split(',').map(id => id.trim()).filter(id => id);
148
+ if (contactIds.length === 0) {
149
+ throw new Error('At least one contact ID is required');
150
+ }
151
+ return await this.leadService.assignContacts(leadId, contactIds);
152
+ }
153
+ async handleRemoveContact() {
154
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
155
+ const contactId = this.executeFunctions.getNodeParameter('contactId', this.itemIndex);
156
+ return await this.leadService.removeContact(leadId, contactId);
157
+ }
158
+ async handleImport() {
159
+ const importData = this.executeFunctions.getNodeParameter('importData', this.itemIndex, {});
160
+ const data = {};
161
+ if (importData.file) {
162
+ data.file = importData.file;
163
+ }
164
+ if (importData.mapping) {
165
+ data.mapping = (0, utils_1.safeJsonParse)(importData.mapping, 'Field Mapping');
166
+ }
167
+ return await this.leadService.import(data);
168
+ }
169
+ async handleGetImportTemplate() {
170
+ return await this.leadService.getImportTemplate();
171
+ }
172
+ async handleGeocode() {
173
+ const leadId = this.executeFunctions.getNodeParameter('leadId', this.itemIndex);
174
+ const geocodeData = this.executeFunctions.getNodeParameter('geocodeData', this.itemIndex, {});
175
+ return await this.leadService.geocode(leadId, geocodeData);
176
+ }
177
+ async handleSearchNearby() {
178
+ const latitude = this.executeFunctions.getNodeParameter('latitude', this.itemIndex);
179
+ const longitude = this.executeFunctions.getNodeParameter('longitude', this.itemIndex);
180
+ const limit = this.executeFunctions.getNodeParameter('limit', this.itemIndex, 50);
181
+ const page = this.executeFunctions.getNodeParameter('page', this.itemIndex, 1);
182
+ const searchOptions = this.executeFunctions.getNodeParameter('searchOptions', this.itemIndex, {});
183
+ const params = {
184
+ latitude,
185
+ longitude,
186
+ limit,
187
+ page,
188
+ };
189
+ if (searchOptions.radius !== undefined) {
190
+ params.radius = searchOptions.radius;
191
+ }
192
+ if (searchOptions.unit) {
193
+ params.unit = searchOptions.unit;
194
+ }
195
+ return await this.leadService.searchNearby(params);
196
+ }
197
+ }
198
+ exports.LeadOperations = LeadOperations;
@@ -0,0 +1,13 @@
1
+ export interface IDB2BCallLog {
2
+ id?: string;
3
+ lead_id?: string;
4
+ contact_id?: string;
5
+ user_id?: string;
6
+ type?: 'incoming' | 'outgoing' | 'missed';
7
+ duration?: number;
8
+ notes?: string;
9
+ recording_url?: string;
10
+ call_date?: string;
11
+ created_at?: string;
12
+ updated_at?: string;
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ export interface IDB2BImportResponse {
2
+ success: boolean;
3
+ message: string;
4
+ imported_count?: number;
5
+ failed_count?: number;
6
+ errors?: Array<{
7
+ row: number;
8
+ field: string;
9
+ error: string;
10
+ }>;
11
+ job_id?: string;
12
+ status?: 'pending' | 'processing' | 'completed' | 'failed';
13
+ }
14
+ export interface IDB2BImportTemplate {
15
+ fields: Array<{
16
+ name: string;
17
+ type: string;
18
+ required: boolean;
19
+ description?: string;
20
+ }>;
21
+ sample_data?: Record<string, any>[];
22
+ format?: 'csv' | 'excel';
23
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,77 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ import { IDB2BLead } from '../interfaces/IDB2BLead';
3
+ export interface LeadServiceOptions {
4
+ executeFunctions: IExecuteFunctions;
5
+ credentials: any;
6
+ accessToken: string;
7
+ itemIndex: number;
8
+ }
9
+ export interface PaginationParams {
10
+ limit?: number;
11
+ page?: number;
12
+ }
13
+ export interface QueryParams {
14
+ [key: string]: string | number | boolean;
15
+ }
16
+ export interface LeadGetOptions extends PaginationParams {
17
+ fields?: string[];
18
+ queryParams?: QueryParams;
19
+ }
20
+ export interface LeadCreateData {
21
+ name: string;
22
+ owner_id?: string;
23
+ website?: string;
24
+ description?: string;
25
+ status_id?: string;
26
+ source_id?: string;
27
+ size_id?: string;
28
+ industry_id?: string;
29
+ main_contact_id?: string;
30
+ contact_name?: string;
31
+ contact_email?: string;
32
+ contact_phone_number?: string;
33
+ }
34
+ export interface LeadUpdateData extends Partial<LeadCreateData> {
35
+ }
36
+ export interface LeadImportData {
37
+ file?: string;
38
+ data?: IDB2BLead[];
39
+ mapping?: Record<string, string>;
40
+ }
41
+ export interface GeocodeData {
42
+ address?: string;
43
+ latitude?: number;
44
+ longitude?: number;
45
+ }
46
+ export interface NearbySearchParams extends PaginationParams {
47
+ latitude: number;
48
+ longitude: number;
49
+ radius?: number;
50
+ unit?: 'km' | 'miles';
51
+ }
52
+ export declare class LeadService {
53
+ private executeFunctions;
54
+ private credentials;
55
+ private accessToken;
56
+ private itemIndex;
57
+ private baseUrl;
58
+ constructor(options: LeadServiceOptions);
59
+ private makeRequest;
60
+ private validateLeadId;
61
+ private buildQueryString;
62
+ getAll(options?: LeadGetOptions): Promise<any>;
63
+ getById(leadId: string): Promise<any>;
64
+ create(leadData: LeadCreateData): Promise<any>;
65
+ update(leadId: string, updateData: LeadUpdateData): Promise<any>;
66
+ delete(leadId: string): Promise<any>;
67
+ bulkCreate(leads: LeadCreateData[]): Promise<any>;
68
+ bulkDelete(leadIds: string[]): Promise<any>;
69
+ getCallLogs(leadId: string, options?: PaginationParams): Promise<any>;
70
+ assignNewContact(leadId: string, contactData: any): Promise<any>;
71
+ assignContacts(leadId: string, contactIds: string[]): Promise<any>;
72
+ removeContact(leadId: string, contactId: string): Promise<any>;
73
+ import(importData: LeadImportData): Promise<any>;
74
+ getImportTemplate(): Promise<any>;
75
+ geocode(leadId: string, geocodeData: GeocodeData): Promise<any>;
76
+ searchNearby(params: NearbySearchParams): Promise<any>;
77
+ }
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LeadService = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const requests_1 = require("../methods/requests");
6
+ const validation_1 = require("../methods/validation");
7
+ class LeadService {
8
+ constructor(options) {
9
+ this.executeFunctions = options.executeFunctions;
10
+ this.credentials = options.credentials;
11
+ this.accessToken = options.accessToken;
12
+ this.itemIndex = options.itemIndex;
13
+ this.baseUrl = this.credentials.baseUrl;
14
+ }
15
+ async makeRequest(options) {
16
+ const { method, endpoint, body, qs } = options;
17
+ return await (0, requests_1.makeRequestWithRetry)(this.executeFunctions, {
18
+ method,
19
+ url: `${this.baseUrl}${endpoint}`,
20
+ headers: {
21
+ Authorization: `Bearer ${this.accessToken}`,
22
+ },
23
+ body,
24
+ qs,
25
+ json: true,
26
+ });
27
+ }
28
+ validateLeadId(leadId) {
29
+ if (!leadId || typeof leadId !== 'string' || leadId.trim().length === 0) {
30
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), 'Lead ID is required and must be a non-empty string', { itemIndex: this.itemIndex });
31
+ }
32
+ }
33
+ buildQueryString(queryParameters) {
34
+ const qs = {};
35
+ if (queryParameters === null || queryParameters === void 0 ? void 0 : queryParameters.parameter) {
36
+ queryParameters.parameter.forEach((param) => {
37
+ if (param.name && param.value !== undefined) {
38
+ qs[param.name] = param.value;
39
+ }
40
+ });
41
+ }
42
+ return qs;
43
+ }
44
+ async getAll(options = {}) {
45
+ const { limit = 50, page = 1, fields = [], queryParams = {} } = options;
46
+ const qs = { limit, page };
47
+ // Add additional query parameters
48
+ Object.assign(qs, queryParams);
49
+ const response = await this.makeRequest({
50
+ method: 'GET',
51
+ endpoint: '/leads',
52
+ qs,
53
+ });
54
+ // Apply field filtering if specified
55
+ if (fields.length > 0 && Array.isArray(response.data)) {
56
+ return Object.assign(Object.assign({}, response), { data: response.data.map((lead) => {
57
+ const filteredLead = {};
58
+ fields.forEach(field => {
59
+ if (field in lead) {
60
+ filteredLead[field] = lead[field];
61
+ }
62
+ });
63
+ return filteredLead;
64
+ }) });
65
+ }
66
+ return response;
67
+ }
68
+ async getById(leadId) {
69
+ this.validateLeadId(leadId);
70
+ return await this.makeRequest({
71
+ method: 'GET',
72
+ endpoint: `/leads/${leadId.trim()}`,
73
+ });
74
+ }
75
+ async create(leadData) {
76
+ (0, validation_1.validateLeadData)(leadData.name);
77
+ const body = {
78
+ name: leadData.name.trim(),
79
+ };
80
+ // Add optional fields
81
+ const optionalFields = [
82
+ 'owner_id', 'website', 'description', 'status_id', 'source_id',
83
+ 'size_id', 'industry_id', 'main_contact_id', 'contact_name',
84
+ 'contact_email', 'contact_phone_number'
85
+ ];
86
+ optionalFields.forEach(field => {
87
+ if (leadData[field]) {
88
+ body[field] = leadData[field];
89
+ }
90
+ });
91
+ return await this.makeRequest({
92
+ method: 'POST',
93
+ endpoint: '/leads',
94
+ body,
95
+ });
96
+ }
97
+ async update(leadId, updateData) {
98
+ this.validateLeadId(leadId);
99
+ if (updateData.name) {
100
+ (0, validation_1.validateLeadData)(updateData.name);
101
+ }
102
+ const body = {};
103
+ // Add fields to update
104
+ Object.keys(updateData).forEach(key => {
105
+ const value = updateData[key];
106
+ if (value !== undefined) {
107
+ if (key === 'name' && typeof value === 'string') {
108
+ body[key] = value.trim();
109
+ }
110
+ else {
111
+ body[key] = value;
112
+ }
113
+ }
114
+ });
115
+ return await this.makeRequest({
116
+ method: 'PATCH',
117
+ endpoint: `/leads/${leadId.trim()}`,
118
+ body,
119
+ });
120
+ }
121
+ async delete(leadId) {
122
+ this.validateLeadId(leadId);
123
+ return await this.makeRequest({
124
+ method: 'DELETE',
125
+ endpoint: `/leads/${leadId.trim()}`,
126
+ });
127
+ }
128
+ async bulkCreate(leads) {
129
+ if (!Array.isArray(leads) || leads.length === 0) {
130
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), 'Leads array is required and must not be empty', { itemIndex: this.itemIndex });
131
+ }
132
+ // Validate each lead
133
+ leads.forEach((lead, index) => {
134
+ try {
135
+ (0, validation_1.validateLeadData)(lead.name);
136
+ }
137
+ catch (error) {
138
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), `Lead at index ${index}: ${error instanceof Error ? error.message : 'Validation failed'}`, { itemIndex: this.itemIndex });
139
+ }
140
+ });
141
+ return await this.makeRequest({
142
+ method: 'POST',
143
+ endpoint: '/leads/bulk',
144
+ body: { leads },
145
+ });
146
+ }
147
+ async bulkDelete(leadIds) {
148
+ if (!Array.isArray(leadIds) || leadIds.length === 0) {
149
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), 'Lead IDs array is required and must not be empty', { itemIndex: this.itemIndex });
150
+ }
151
+ // Validate each lead ID
152
+ leadIds.forEach((id, index) => {
153
+ if (!id || typeof id !== 'string' || id.trim().length === 0) {
154
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), `Invalid lead ID at index ${index}`, { itemIndex: this.itemIndex });
155
+ }
156
+ });
157
+ return await this.makeRequest({
158
+ method: 'DELETE',
159
+ endpoint: '/leads/bulk',
160
+ body: { lead_ids: leadIds.map(id => id.trim()) },
161
+ });
162
+ }
163
+ async getCallLogs(leadId, options = {}) {
164
+ this.validateLeadId(leadId);
165
+ const { limit = 50, page = 1 } = options;
166
+ return await this.makeRequest({
167
+ method: 'GET',
168
+ endpoint: `/leads/${leadId.trim()}/call-logs`,
169
+ qs: { limit, page },
170
+ });
171
+ }
172
+ async assignNewContact(leadId, contactData) {
173
+ this.validateLeadId(leadId);
174
+ return await this.makeRequest({
175
+ method: 'POST',
176
+ endpoint: `/leads/${leadId.trim()}/assign-new-contact`,
177
+ body: contactData,
178
+ });
179
+ }
180
+ async assignContacts(leadId, contactIds) {
181
+ this.validateLeadId(leadId);
182
+ if (!Array.isArray(contactIds) || contactIds.length === 0) {
183
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), 'Contact IDs array is required and must not be empty', { itemIndex: this.itemIndex });
184
+ }
185
+ return await this.makeRequest({
186
+ method: 'POST',
187
+ endpoint: `/leads/${leadId.trim()}/assign-contacts`,
188
+ body: { contact_ids: contactIds },
189
+ });
190
+ }
191
+ async removeContact(leadId, contactId) {
192
+ this.validateLeadId(leadId);
193
+ if (!contactId || typeof contactId !== 'string' || contactId.trim().length === 0) {
194
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), 'Contact ID is required and must be a non-empty string', { itemIndex: this.itemIndex });
195
+ }
196
+ return await this.makeRequest({
197
+ method: 'DELETE',
198
+ endpoint: `/leads/${leadId.trim()}/contacts/${contactId.trim()}`,
199
+ });
200
+ }
201
+ async import(importData) {
202
+ return await this.makeRequest({
203
+ method: 'POST',
204
+ endpoint: '/leads/import',
205
+ body: importData,
206
+ });
207
+ }
208
+ async getImportTemplate() {
209
+ return await this.makeRequest({
210
+ method: 'GET',
211
+ endpoint: '/leads/import/template',
212
+ });
213
+ }
214
+ async geocode(leadId, geocodeData) {
215
+ this.validateLeadId(leadId);
216
+ return await this.makeRequest({
217
+ method: 'POST',
218
+ endpoint: `/leads/${leadId.trim()}/geocode`,
219
+ body: geocodeData,
220
+ });
221
+ }
222
+ async searchNearby(params) {
223
+ const { latitude, longitude, radius = 10, unit = 'km', limit = 50, page = 1 } = params;
224
+ if (typeof latitude !== 'number' || typeof longitude !== 'number') {
225
+ throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), 'Latitude and longitude are required and must be numbers', { itemIndex: this.itemIndex });
226
+ }
227
+ return await this.makeRequest({
228
+ method: 'GET',
229
+ endpoint: '/leads/nearby/search',
230
+ qs: {
231
+ latitude,
232
+ longitude,
233
+ radius,
234
+ unit,
235
+ limit,
236
+ page,
237
+ },
238
+ });
239
+ }
240
+ }
241
+ exports.LeadService = LeadService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-idb2b",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "n8n community node for IDB2B CRM",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -20,7 +20,7 @@
20
20
  "dist/credentials/IDB2BApi.credentials.js"
21
21
  ],
22
22
  "nodes": [
23
- "dist/nodes/IDB2B/IDB2B.node.js"
23
+ "dist/nodes/IDB2B/IDB2B.refactored.node.js"
24
24
  ]
25
25
  },
26
26
  "keywords": [