n8n-nodes-pragma-bitrix24 1.0.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.
Files changed (51) hide show
  1. package/LICENSE +51 -0
  2. package/README.md +340 -0
  3. package/dist/credentials/Bitrix24Api.credentials.js +55 -0
  4. package/dist/nodes/Bitrix24/Bitrix24.node.js +1410 -0
  5. package/dist/nodes/Bitrix24/Company.js +17 -0
  6. package/dist/nodes/Bitrix24/Contact.js +31 -0
  7. package/dist/nodes/Bitrix24/Deal.js +17 -0
  8. package/dist/nodes/Bitrix24/Helpers.js +300 -0
  9. package/dist/nodes/Bitrix24/Lead.js +17 -0
  10. package/dist/nodes/Bitrix24/SmartProcess.js +1 -0
  11. package/dist/nodes/Bitrix24/bitrix24.svg +7 -0
  12. package/dist/nodes/Bitrix24/types.js +58 -0
  13. package/dist/nodes/Bitrix24AI/Bitrix24AI.node.js +205 -0
  14. package/dist/nodes/Bitrix24App/Bitrix24App.node.js +179 -0
  15. package/dist/nodes/Bitrix24Auxiliary/Bitrix24Auxiliary.node.js +566 -0
  16. package/dist/nodes/Bitrix24Booking/Bitrix24Booking.node.js +871 -0
  17. package/dist/nodes/Bitrix24Calendar/Bitrix24Calendar.node.js +471 -0
  18. package/dist/nodes/Bitrix24ChatBot/Bitrix24ChatBot.node.js +522 -0
  19. package/dist/nodes/Bitrix24Commerce/Bitrix24Commerce.node.js +431 -0
  20. package/dist/nodes/Bitrix24Department/Bitrix24Department.node.js +317 -0
  21. package/dist/nodes/Bitrix24Disk/Bitrix24Disk.node.js +334 -0
  22. package/dist/nodes/Bitrix24Document/Bitrix24Document.node.js +280 -0
  23. package/dist/nodes/Bitrix24Entity/Bitrix24Entity.node.js +263 -0
  24. package/dist/nodes/Bitrix24Group/Bitrix24Group.node.js +327 -0
  25. package/dist/nodes/Bitrix24Lists/Bitrix24Lists.node.js +406 -0
  26. package/dist/nodes/Bitrix24Log/Bitrix24Log.node.js +309 -0
  27. package/dist/nodes/Bitrix24Mail/Bitrix24Mail.node.js +109 -0
  28. package/dist/nodes/Bitrix24MessageService/Bitrix24MessageService.node.js +218 -0
  29. package/dist/nodes/Bitrix24OpenChannels/Bitrix24OpenChannels.node.js +379 -0
  30. package/dist/nodes/Bitrix24PaySystem/Bitrix24PaySystem.node.js +241 -0
  31. package/dist/nodes/Bitrix24Pipeline/Bitrix24Pipeline.node.js +553 -0
  32. package/dist/nodes/Bitrix24Pipeline/bitrix24.svg +7 -0
  33. package/dist/nodes/Bitrix24Sale/Bitrix24Sale.node.js +391 -0
  34. package/dist/nodes/Bitrix24Scrum/Bitrix24Scrum.node.js +555 -0
  35. package/dist/nodes/Bitrix24Scrum/bitrix24.svg +7 -0
  36. package/dist/nodes/Bitrix24Sign/Bitrix24Sign.node.js +132 -0
  37. package/dist/nodes/Bitrix24Social/Bitrix24Social.node.js +224 -0
  38. package/dist/nodes/Bitrix24Task/Bitrix24Task.node.js +444 -0
  39. package/dist/nodes/Bitrix24Telephony/Bitrix24Telephony.node.js +511 -0
  40. package/dist/nodes/Bitrix24Timeman/Bitrix24Timeman.node.js +196 -0
  41. package/dist/nodes/Bitrix24Tool/Bitrix24Tool.node.js +1035 -0
  42. package/dist/nodes/Bitrix24Tool/bitrix24.svg +7 -0
  43. package/dist/nodes/Bitrix24Trigger/Bitrix24Trigger.node.js +184 -0
  44. package/dist/nodes/Bitrix24User/Bitrix24User.node.js +351 -0
  45. package/dist/nodes/Bitrix24UserField/Bitrix24UserField.node.js +386 -0
  46. package/dist/nodes/Bitrix24UserField/bitrix24.svg +7 -0
  47. package/dist/nodes/shared/bitrix24.svg +7 -0
  48. package/dist/nodes/shared/localization.js +189 -0
  49. package/dist/nodes/shared/types.js +22 -0
  50. package/index.js +10 -0
  51. package/package.json +108 -0
@@ -0,0 +1,1035 @@
1
+ "use strict";
2
+ /**
3
+ * Bitrix24 Tool — AI-реди операции для LLM
4
+ *
5
+ * Bitrix24 PRAGMA.by nodes for n8n
6
+ * Профессиональная интеграция с Битрикс24.
7
+ *
8
+ * @author PRAGMA & Азбука Решений
9
+ * @copyright 2026 PRAGMA (https://pragma.by/) & Азбука Решений (https://abc-solution.ru/)
10
+ *
11
+ * Контакты:
12
+ * 🇧🇾 PRAGMA: +375 (44) 702-70-90 | https://pragma.by/
13
+ * 🇷🇺 Азбука Решений: +7 (939) 555-19-60 | https://abc-solution.ru/
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.Bitrix24Tool = void 0;
17
+ const Helpers_1 = require("../Bitrix24/Helpers");
18
+ class Bitrix24Tool {
19
+ constructor() {
20
+ this.description = {
21
+ displayName: 'Bitrix24 AI Инструмент',
22
+ name: 'pragmaBitrix24Tool',
23
+ icon: 'file:bitrix24.svg',
24
+ group: ['transform'],
25
+ version: 2,
26
+ subtitle: '={{$parameter["operation"]}}',
27
+ description: 'AI-операции для LLM: поиск CRM, создание сущностей, бизнес-процессы, аналитика',
28
+ defaults: {
29
+ name: 'Bitrix24 AI Tool',
30
+ },
31
+ inputs: ['main'],
32
+ outputs: ['main'],
33
+ credentials: [
34
+ {
35
+ name: 'bitrix24Api',
36
+ required: true,
37
+ },
38
+ ],
39
+ properties: [
40
+ {
41
+ displayName: 'Operation',
42
+ name: 'operation',
43
+ type: 'options',
44
+ noDataExpression: true,
45
+ options: [
46
+ {
47
+ name: 'Search CRM',
48
+ value: 'searchCrm',
49
+ description: 'Search Leads, Deals, Contacts, Companies by text',
50
+ action: 'Search CRM entities',
51
+ },
52
+ {
53
+ name: 'Get Entity Details',
54
+ value: 'getEntity',
55
+ description: 'Get full details of a specific entity (CRM, Task, etc.)',
56
+ action: 'Get entity details',
57
+ },
58
+ {
59
+ name: 'Create Entity (AI)',
60
+ value: 'createEntity',
61
+ description: 'Create Task, Deal, or Lead with simplified input',
62
+ action: 'Create an entity',
63
+ },
64
+ {
65
+ name: 'Find User',
66
+ value: 'findUser',
67
+ description: 'Find a user by name or email',
68
+ action: 'Find user',
69
+ },
70
+ {
71
+ name: 'Call API Method',
72
+ value: 'callMethod',
73
+ description: 'Execute any Bitrix24 REST API method (Advanced)',
74
+ action: 'Call API method',
75
+ },
76
+ {
77
+ name: 'Check Availability (Calendar)',
78
+ value: 'checkAvailability',
79
+ description: 'Check if users are free (for scheduling)',
80
+ action: 'Check user availability',
81
+ },
82
+ {
83
+ name: 'Get History (Context)',
84
+ value: 'getHistory',
85
+ description: 'Get recent activities/timeline for an entity',
86
+ action: 'Get entity history',
87
+ },
88
+ {
89
+ name: 'Send Message (Notify)',
90
+ value: 'sendMessage',
91
+ description: 'Send a message or notification to a user',
92
+ action: 'Send message',
93
+ },
94
+ {
95
+ name: 'Start Workflow (Bizproc)',
96
+ value: 'startWorkflow',
97
+ description: 'Trigger a Business Process on an entity',
98
+ action: 'Start workflow',
99
+ },
100
+ {
101
+ name: 'Handle Workflow Task',
102
+ value: 'handleWorkflowTask',
103
+ description: 'Complete/Approve/Reject a Business Process task',
104
+ action: 'Handle workflow task',
105
+ },
106
+ {
107
+ name: 'Forecast Deal (AI)',
108
+ value: 'forecastDeal',
109
+ description: 'Predict deal win probability',
110
+ action: 'Forecast deal',
111
+ },
112
+ {
113
+ name: 'Create Segment (Marketing)',
114
+ value: 'createMarketingSegment',
115
+ description: 'Create a new CRM Marketing segment',
116
+ action: 'Create marketing segment',
117
+ },
118
+ {
119
+ name: 'Create Campaign (Marketing)',
120
+ value: 'createMarketingCampaign',
121
+ description: 'Start an Email/SMS campaign',
122
+ action: 'Create marketing campaign',
123
+ },
124
+ {
125
+ name: 'Get Funnel Structure (Analytics)',
126
+ value: 'getFunnelStructure',
127
+ description: 'Get Sales Funnels and Stages for analysis',
128
+ action: 'Get funnel structure',
129
+ },
130
+ {
131
+ name: 'Register Ad Source (Tracking)',
132
+ value: 'registerAdSource',
133
+ description: 'Register a new traffic source',
134
+ action: 'Register ad source',
135
+ },
136
+ {
137
+ name: 'Find Duplicates',
138
+ value: 'findDuplicates',
139
+ description: 'Check for duplicate entities',
140
+ action: 'Find duplicates',
141
+ },
142
+ // System Operations
143
+ {
144
+ name: 'Get Scope',
145
+ value: 'getScope',
146
+ action: 'Check auth scope',
147
+ },
148
+ {
149
+ name: 'Get Features',
150
+ value: 'getFeatures',
151
+ action: 'Check enabled features',
152
+ },
153
+ {
154
+ name: 'List Offline Events',
155
+ value: 'listOffline',
156
+ action: 'List offline events',
157
+ },
158
+ {
159
+ name: 'Add CRM Status',
160
+ value: 'addCrmStatus',
161
+ description: 'Add comment to a task',
162
+ },
163
+ {
164
+ name: 'Find Duplicates',
165
+ value: 'findDuplicates',
166
+ description: 'Check for duplicate entities',
167
+ action: 'Find duplicates',
168
+ },
169
+ ],
170
+ default: 'searchCrm',
171
+ },
172
+ // ----------------------------------
173
+ // Operation: Search CRM
174
+ // ----------------------------------
175
+ {
176
+ displayName: 'Entity Type',
177
+ name: 'entityType',
178
+ type: 'options',
179
+ displayOptions: {
180
+ show: {
181
+ operation: ['searchCrm'],
182
+ },
183
+ },
184
+ options: [
185
+ { name: 'All CRM', value: 'all' },
186
+ { name: 'Lead', value: 'lead' },
187
+ { name: 'Deal', value: 'deal' },
188
+ { name: 'Contact', value: 'contact' },
189
+ { name: 'Company', value: 'company' },
190
+ ],
191
+ default: 'all',
192
+ description: 'Type of entity to search for',
193
+ },
194
+ {
195
+ displayName: 'Query',
196
+ name: 'query',
197
+ type: 'string',
198
+ displayOptions: {
199
+ show: {
200
+ operation: ['searchCrm'],
201
+ },
202
+ },
203
+ default: '',
204
+ description: 'Search string (name, email, phone, title)',
205
+ },
206
+ // ----------------------------------
207
+ // Operation: Get Entity
208
+ // ----------------------------------
209
+ {
210
+ displayName: 'Entity Type',
211
+ name: 'entityTypeGet',
212
+ type: 'options',
213
+ displayOptions: {
214
+ show: {
215
+ operation: ['getEntity'],
216
+ },
217
+ },
218
+ options: [
219
+ { name: 'Lead', value: 'crm.lead' },
220
+ { name: 'Deal', value: 'crm.deal' },
221
+ { name: 'Contact', value: 'crm.contact' },
222
+ { name: 'Company', value: 'crm.company' },
223
+ { name: 'Task', value: 'tasks.task' },
224
+ { name: 'User', value: 'user' },
225
+ ],
226
+ default: 'crm.deal',
227
+ description: 'Type of entity to retrieve',
228
+ },
229
+ {
230
+ displayName: 'ID',
231
+ name: 'id',
232
+ type: 'string',
233
+ displayOptions: {
234
+ show: {
235
+ operation: ['getEntity'],
236
+ },
237
+ },
238
+ default: '',
239
+ description: 'ID of the entity',
240
+ },
241
+ // ----------------------------------
242
+ // Operation: Create Entity (AI)
243
+ // ----------------------------------
244
+ {
245
+ displayName: 'Entity Type',
246
+ name: 'createEntityType',
247
+ type: 'options',
248
+ displayOptions: {
249
+ show: {
250
+ operation: ['createEntity'],
251
+ },
252
+ },
253
+ options: [
254
+ { name: 'Task', value: 'tasks.task' },
255
+ { name: 'Lead', value: 'crm.lead' },
256
+ { name: 'Deal', value: 'crm.deal' },
257
+ ],
258
+ default: 'tasks.task',
259
+ },
260
+ {
261
+ displayName: 'Title',
262
+ name: 'title',
263
+ type: 'string',
264
+ displayOptions: {
265
+ show: {
266
+ operation: ['createEntity'],
267
+ },
268
+ },
269
+ default: '',
270
+ description: 'Title of the entity',
271
+ },
272
+ {
273
+ displayName: 'Description',
274
+ name: 'description',
275
+ type: 'string',
276
+ displayOptions: {
277
+ show: {
278
+ operation: ['createEntity'],
279
+ },
280
+ },
281
+ default: '',
282
+ },
283
+ {
284
+ displayName: 'Responsible User ID',
285
+ name: 'responsibleId',
286
+ type: 'string',
287
+ displayOptions: {
288
+ show: {
289
+ operation: ['createEntity'],
290
+ },
291
+ },
292
+ default: '',
293
+ description: 'ID of the user responsible',
294
+ },
295
+ // ----------------------------------
296
+ // Operation: Find User
297
+ // ----------------------------------
298
+ {
299
+ displayName: 'Search String',
300
+ name: 'userQuery',
301
+ type: 'string',
302
+ displayOptions: {
303
+ show: {
304
+ operation: ['findUser'],
305
+ },
306
+ },
307
+ default: '',
308
+ description: 'Name or email to search for',
309
+ },
310
+ // ----------------------------------
311
+ // Operation: Check Availability
312
+ // ----------------------------------
313
+ {
314
+ displayName: 'User IDs',
315
+ name: 'users',
316
+ type: 'string',
317
+ displayOptions: {
318
+ show: {
319
+ operation: ['checkAvailability'],
320
+ },
321
+ },
322
+ default: '',
323
+ description: 'Comma-separated user IDs to check',
324
+ },
325
+ {
326
+ displayName: 'From (Date)',
327
+ name: 'dateFrom',
328
+ type: 'dateTime',
329
+ displayOptions: {
330
+ show: {
331
+ operation: ['checkAvailability'],
332
+ },
333
+ },
334
+ default: '',
335
+ description: 'Start of check period',
336
+ },
337
+ {
338
+ displayName: 'To (Date)',
339
+ name: 'dateTo',
340
+ type: 'dateTime',
341
+ displayOptions: {
342
+ show: {
343
+ operation: ['checkAvailability'],
344
+ },
345
+ },
346
+ default: '',
347
+ description: 'End of check period',
348
+ },
349
+ // ----------------------------------
350
+ // Operation: Get History
351
+ // ----------------------------------
352
+ {
353
+ displayName: 'Entity Type',
354
+ name: 'historyEntityType',
355
+ type: 'options',
356
+ displayOptions: {
357
+ show: {
358
+ operation: ['getHistory'],
359
+ },
360
+ },
361
+ options: [
362
+ { name: 'Lead', value: '1' },
363
+ { name: 'Deal', value: '2' },
364
+ { name: 'Contact', value: '3' },
365
+ { name: 'Company', value: '4' },
366
+ ],
367
+ default: '2',
368
+ },
369
+ {
370
+ displayName: 'Entity ID',
371
+ name: 'historyEntityId',
372
+ type: 'string',
373
+ displayOptions: {
374
+ show: {
375
+ operation: ['getHistory'],
376
+ },
377
+ },
378
+ default: '',
379
+ },
380
+ // ----------------------------------
381
+ // Operation: Send Message
382
+ // ----------------------------------
383
+ {
384
+ displayName: 'Recipient ID',
385
+ name: 'messageUserId',
386
+ type: 'string',
387
+ displayOptions: {
388
+ show: {
389
+ operation: ['sendMessage'],
390
+ },
391
+ },
392
+ default: '',
393
+ },
394
+ {
395
+ displayName: 'Message',
396
+ name: 'messageBody',
397
+ type: 'string',
398
+ displayOptions: {
399
+ show: {
400
+ operation: ['sendMessage'],
401
+ },
402
+ },
403
+ default: '',
404
+ },
405
+ {
406
+ displayName: 'Type',
407
+ name: 'messageType',
408
+ type: 'options',
409
+ options: [
410
+ { name: 'System Notification', value: 'notify' },
411
+ { name: 'Chat Message', value: 'chat' },
412
+ ],
413
+ displayOptions: {
414
+ show: {
415
+ operation: ['sendMessage'],
416
+ },
417
+ },
418
+ default: 'chat',
419
+ },
420
+ // ----------------------------------
421
+ // Operation: Start Workflow
422
+ // ----------------------------------
423
+ {
424
+ displayName: 'Template ID',
425
+ name: 'bizprocTemplateId',
426
+ type: 'string',
427
+ displayOptions: {
428
+ show: {
429
+ operation: ['startWorkflow'],
430
+ },
431
+ },
432
+ default: '',
433
+ description: 'ID of the Workflow Template (Bizproc)',
434
+ },
435
+ {
436
+ displayName: 'Document ID (Entity)',
437
+ name: 'bizprocDocumentId',
438
+ type: 'string',
439
+ displayOptions: {
440
+ show: {
441
+ operation: ['startWorkflow'],
442
+ },
443
+ },
444
+ default: '',
445
+ description: 'ID of the entity (e.g. "DEAL_123" or just "123" if type selected implies it)',
446
+ },
447
+ {
448
+ displayName: 'Document Type',
449
+ name: 'bizprocDocumentType',
450
+ type: 'options',
451
+ options: [
452
+ { name: 'Lead', value: 'crm_lead' },
453
+ { name: 'Deal', value: 'crm_deal' },
454
+ { name: 'Contact', value: 'crm_contact' },
455
+ { name: 'Company', value: 'crm_company' },
456
+ { name: 'Task', value: 'tasks' }, // Complex in B24, usually tasks have separate runner
457
+ ],
458
+ displayOptions: {
459
+ show: {
460
+ operation: ['startWorkflow'],
461
+ },
462
+ },
463
+ default: 'crm_deal',
464
+ },
465
+ {
466
+ displayName: 'Parameters (JSON)',
467
+ name: 'bizprocParams',
468
+ type: 'json',
469
+ displayOptions: {
470
+ show: {
471
+ operation: ['startWorkflow'],
472
+ },
473
+ },
474
+ default: '{}',
475
+ description: 'Input parameters for the workflow',
476
+ },
477
+ // ----------------------------------
478
+ // Operation: Handle Workflow Task
479
+ // ----------------------------------
480
+ {
481
+ displayName: 'Task ID',
482
+ name: 'bizprocTaskId',
483
+ type: 'string',
484
+ displayOptions: {
485
+ show: {
486
+ operation: ['handleWorkflowTask'],
487
+ },
488
+ },
489
+ default: '',
490
+ description: 'ID of the extensive task (not regular task)',
491
+ },
492
+ {
493
+ displayName: 'Status',
494
+ name: 'bizprocStatus',
495
+ type: 'options',
496
+ options: [
497
+ { name: 'Approve (1)', value: '1' },
498
+ { name: 'Reject (2)', value: '2' },
499
+ { name: 'Ok (3)', value: '3' },
500
+ { name: 'Custom (4)', value: '4' },
501
+ ],
502
+ displayOptions: {
503
+ show: {
504
+ operation: ['handleWorkflowTask'],
505
+ },
506
+ },
507
+ default: '1',
508
+ },
509
+ {
510
+ displayName: 'Comment',
511
+ name: 'bizprocComment',
512
+ type: 'string',
513
+ displayOptions: {
514
+ show: {
515
+ operation: ['handleWorkflowTask'],
516
+ },
517
+ },
518
+ default: '',
519
+ },
520
+ // ----------------------------------
521
+ // Operation: Forecast Deal
522
+ // ----------------------------------
523
+ {
524
+ displayName: 'Deal ID',
525
+ name: 'forecastDealId',
526
+ type: 'string',
527
+ displayOptions: {
528
+ show: {
529
+ operation: ['forecastDeal'],
530
+ },
531
+ },
532
+ default: '',
533
+ },
534
+ // ----------------------------------
535
+ // Operation: Marketing (Segment & Campaign)
536
+ // ----------------------------------
537
+ {
538
+ displayName: 'Name',
539
+ name: 'marketingName',
540
+ type: 'string',
541
+ displayOptions: {
542
+ show: {
543
+ operation: ['createMarketingSegment', 'createMarketingCampaign'],
544
+ },
545
+ },
546
+ default: '',
547
+ description: 'Name of the segment or campaign',
548
+ },
549
+ {
550
+ displayName: 'Type',
551
+ name: 'campaignType',
552
+ type: 'options',
553
+ options: [
554
+ { name: 'Email', value: 'email' },
555
+ { name: 'SMS', value: 'sms' },
556
+ { name: 'Voice Broadcasting', value: 'voice' },
557
+ ],
558
+ displayOptions: {
559
+ show: {
560
+ operation: ['createMarketingCampaign'],
561
+ },
562
+ },
563
+ default: 'email',
564
+ },
565
+ {
566
+ displayName: 'Segment ID',
567
+ name: 'campaignSegmentId',
568
+ type: 'string',
569
+ displayOptions: {
570
+ show: {
571
+ operation: ['createMarketingCampaign'],
572
+ },
573
+ },
574
+ default: '',
575
+ description: 'ID of the segment to target',
576
+ },
577
+ {
578
+ displayName: 'Message Body',
579
+ name: 'campaignBody',
580
+ type: 'string',
581
+ displayOptions: {
582
+ show: {
583
+ operation: ['createMarketingCampaign'],
584
+ },
585
+ },
586
+ default: '',
587
+ },
588
+ // ----------------------------------
589
+ // Operation: Call Method
590
+ // ----------------------------------
591
+ {
592
+ displayName: 'Method',
593
+ name: 'method',
594
+ type: 'string',
595
+ displayOptions: {
596
+ show: {
597
+ operation: ['callMethod'],
598
+ },
599
+ },
600
+ default: 'server.time',
601
+ description: 'Bitrix24 REST method (e.g. crm.deal.list)',
602
+ },
603
+ {
604
+ displayName: 'Parameters (JSON)',
605
+ name: 'paramsJson',
606
+ type: 'json',
607
+ displayOptions: {
608
+ show: {
609
+ operation: ['callMethod'],
610
+ },
611
+ },
612
+ default: '{}',
613
+ description: 'Parameters for the method',
614
+ },
615
+ ],
616
+ };
617
+ }
618
+ async execute() {
619
+ const items = this.getInputData();
620
+ const returnData = [];
621
+ const operation = this.getNodeParameter('operation', 0);
622
+ for (let i = 0; i < items.length; i++) {
623
+ try {
624
+ if (operation === 'searchCrm') {
625
+ const entityType = this.getNodeParameter('entityType', i);
626
+ const query = this.getNodeParameter('query', i);
627
+ const types = entityType === 'all' ? ['lead', 'deal', 'contact', 'company'] : [entityType];
628
+ const results = [];
629
+ for (const type of types) {
630
+ // crm.X.list with fuzzy search logic
631
+ // Bitrix search is weird. %QUERY% works for strings.
632
+ const filter = { 'LOGIC': 'OR' };
633
+ // Add fields based on common patterns
634
+ filter['%TITLE'] = query;
635
+ if (type === 'contact' || type === 'lead') {
636
+ filter['%NAME'] = query;
637
+ filter['%LAST_NAME'] = query;
638
+ // Phones/Emails are complex to wildcard search in some B24 versions, usually requires exact.
639
+ // But we try.
640
+ filter['%EMAIL'] = query; // might not work directly but worth trying
641
+ filter['PHONE'] = query; // Phone usually exact
642
+ }
643
+ try {
644
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', `crm.${type}.list`, {
645
+ select: ['ID', 'TITLE', 'NAME', 'LAST_NAME', 'PHONE', 'EMAIL'],
646
+ filter
647
+ });
648
+ const list = response.result || [];
649
+ list.forEach(item => results.push({ ...item, _type: type }));
650
+ }
651
+ catch (e) {
652
+ // Ignore sub-search errors
653
+ }
654
+ }
655
+ returnData.push({
656
+ json: {
657
+ tool_call_result: results.slice(0, 20), // Limit context
658
+ summary: `Found ${results.length} results for "${query}"`
659
+ },
660
+ pairedItem: { item: i }
661
+ });
662
+ }
663
+ if (operation === 'createEntity') {
664
+ const entityType = this.getNodeParameter('createEntityType', i);
665
+ const title = this.getNodeParameter('title', i);
666
+ const description = this.getNodeParameter('description', i);
667
+ const responsibleId = this.getNodeParameter('responsibleId', i);
668
+ let method = `${entityType}.add`;
669
+ let params = {};
670
+ if (entityType === 'tasks.task') {
671
+ params = { fields: { TITLE: title, DESCRIPTION: description } };
672
+ if (responsibleId)
673
+ params.fields.RESPONSIBLE_ID = responsibleId;
674
+ }
675
+ else if (entityType === 'crm.lead' || entityType === 'crm.deal') {
676
+ params = { fields: { TITLE: title, COMMENTS: description } };
677
+ if (responsibleId)
678
+ params.fields.ASSIGNED_BY_ID = responsibleId;
679
+ }
680
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', method, params);
681
+ returnData.push({
682
+ json: {
683
+ tool_call_result: { id: response.result, success: true },
684
+ summary: `Created ${entityType} with ID ${response.result}`
685
+ },
686
+ pairedItem: { item: i }
687
+ });
688
+ }
689
+ if (operation === 'getEntity') {
690
+ const entityType = this.getNodeParameter('entityTypeGet', i);
691
+ const id = this.getNodeParameter('id', i);
692
+ let start = 0;
693
+ // Handle slight API diffs
694
+ let method = `${entityType}.get`;
695
+ let params = { id };
696
+ if (entityType === 'tasks.task') {
697
+ params = { taskId: id, select: ['*', 'UF_*'] };
698
+ }
699
+ else if (entityType === 'user') {
700
+ params = { ID: id };
701
+ }
702
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', method, params);
703
+ // Optimize output - remove nulls?
704
+ const data = response.result;
705
+ // Maybe flatten or clean up data for LLM?
706
+ // For now, raw is fine but maybe strict selection later.
707
+ returnData.push({
708
+ json: {
709
+ tool_call_result: data
710
+ },
711
+ pairedItem: { item: i }
712
+ });
713
+ }
714
+ if (operation === 'findUser') {
715
+ const query = this.getNodeParameter('userQuery', i);
716
+ // user.search method exists? user.get with filter.
717
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'user.get', {
718
+ FILTER: {
719
+ 'LOGIC': 'OR',
720
+ '%NAME': query,
721
+ '%LAST_NAME': query,
722
+ '%EMAIL': query,
723
+ '%WORK_POSITION': query
724
+ }
725
+ });
726
+ const users = response.result || [];
727
+ const simplified = users.map(u => ({
728
+ id: u.ID,
729
+ name: `${u.NAME} ${u.LAST_NAME}`,
730
+ email: u.EMAIL,
731
+ position: u.WORK_POSITION,
732
+ active: u.ACTIVE
733
+ }));
734
+ returnData.push({ json: { tool_call_result: simplified }, pairedItem: { item: i } });
735
+ }
736
+ if (operation === 'callMethod') {
737
+ const method = this.getNodeParameter('method', i);
738
+ const paramsJson = this.getNodeParameter('paramsJson', i, '{}');
739
+ const params = JSON.parse(paramsJson);
740
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', method, params);
741
+ returnData.push({ json: { tool_call_result: response.result }, pairedItem: { item: i } });
742
+ }
743
+ if (operation === 'checkAvailability') {
744
+ const usersStr = this.getNodeParameter('users', i);
745
+ const users = usersStr.split(',').map(s => s.trim());
746
+ const from = this.getNodeParameter('dateFrom', i);
747
+ const to = this.getNodeParameter('dateTo', i);
748
+ // calendar.accessibility.get
749
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'calendar.accessibility.get', {
750
+ from: from, // Yyyy-mm-dd format usually needed or ISO?
751
+ to: to,
752
+ users: users
753
+ });
754
+ // Return raw for AI to parse.
755
+ returnData.push({ json: { tool_call_result: response.result }, pairedItem: { item: i } });
756
+ }
757
+ if (operation === 'getHistory') {
758
+ const ownerTypeId = this.getNodeParameter('historyEntityType', i);
759
+ const ownerId = this.getNodeParameter('historyEntityId', i);
760
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.activity.list', {
761
+ filter: {
762
+ OWNER_TYPE_ID: ownerTypeId,
763
+ OWNER_ID: ownerId,
764
+ },
765
+ select: ['ID', 'SUBJECT', 'DESCRIPTION', 'CREATED', 'COMPLETED', 'AUTHOR_ID', 'DIRECTION'],
766
+ order: { CREATED: 'DESC' }
767
+ });
768
+ // AI needs concise history
769
+ const activities = response.result || [];
770
+ const summary = activities.slice(0, 10).map(a => `[${a.CREATED}] ${a.SUBJECT} (${a.DIRECTION === '1' ? 'Incoming' : 'Outgoing'}) - ${a.DESCRIPTION}`).join('\n');
771
+ returnData.push({
772
+ json: {
773
+ tool_call_result: activities.slice(0, 10),
774
+ summary: summary
775
+ },
776
+ pairedItem: { item: i }
777
+ });
778
+ }
779
+ if (operation === 'sendMessage') {
780
+ const userId = this.getNodeParameter('messageUserId', i);
781
+ const message = this.getNodeParameter('messageBody', i);
782
+ const type = this.getNodeParameter('messageType', i);
783
+ if (type === 'notify') {
784
+ await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'im.notify.system.add', {
785
+ TO_USER_ID: userId,
786
+ MESSAGE: message
787
+ });
788
+ }
789
+ else {
790
+ await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'im.message.add', {
791
+ DIALOG_ID: userId,
792
+ MESSAGE: message
793
+ });
794
+ }
795
+ returnData.push({ json: { tool_call_result: { success: true } }, pairedItem: { item: i } });
796
+ }
797
+ if (operation === 'startWorkflow') {
798
+ const templateId = this.getNodeParameter('bizprocTemplateId', i);
799
+ const docId = this.getNodeParameter('bizprocDocumentId', i);
800
+ const docType = this.getNodeParameter('bizprocDocumentType', i);
801
+ const params = this.getNodeParameter('bizprocParams', i, '{}');
802
+ // Construct complex document ID for B24
803
+ // LEAD: ['crm', 'CCrmDocumentLead', 'LEAD_ID']
804
+ let complexDocId = [];
805
+ if (docType === 'crm_lead')
806
+ complexDocId = ['crm', 'CCrmDocumentLead', 'LEAD_' + docId];
807
+ if (docType === 'crm_deal')
808
+ complexDocId = ['crm', 'CCrmDocumentDeal', 'DEAL_' + docId];
809
+ if (docType === 'crm_contact')
810
+ complexDocId = ['crm', 'CCrmDocumentContact', 'CONTACT_' + docId];
811
+ if (docType === 'crm_company')
812
+ complexDocId = ['crm', 'CCrmDocumentCompany', 'COMPANY_' + docId];
813
+ // bizproc.workflow.start
814
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'bizproc.workflow.start', {
815
+ TEMPLATE_ID: templateId,
816
+ DOCUMENT_ID: complexDocId,
817
+ PARAMETERS: JSON.parse(params) // Values for BP
818
+ });
819
+ returnData.push({
820
+ json: {
821
+ tool_call_result: {
822
+ workflowId: response.result,
823
+ success: true
824
+ },
825
+ summary: `Started Workflow ${templateId} on ${docType} ${docId}`
826
+ },
827
+ pairedItem: { item: i }
828
+ });
829
+ }
830
+ if (operation === 'handleWorkflowTask') {
831
+ const taskId = this.getNodeParameter('bizprocTaskId', i);
832
+ const status = this.getNodeParameter('bizprocStatus', i);
833
+ const comment = this.getNodeParameter('bizprocComment', i);
834
+ // bizproc.task.complete
835
+ await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'bizproc.task.complete', {
836
+ TASK_ID: taskId,
837
+ STATUS: status,
838
+ COMMENT: comment
839
+ });
840
+ returnData.push({
841
+ json: {
842
+ tool_call_result: { success: true },
843
+ summary: `Completed workflow task ${taskId} with status ${status}`
844
+ },
845
+ pairedItem: { item: i }
846
+ });
847
+ }
848
+ if (operation === 'forecastDeal') {
849
+ const dealId = this.getNodeParameter('forecastDealId', i);
850
+ // Get deal history and current state
851
+ const deal = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.deal.get', { id: dealId });
852
+ const dealResult = deal.result;
853
+ // Just a mock "AI" logic here for V19
854
+ // Real implementation would check stage history duration
855
+ const amount = parseFloat(dealResult?.OPPORTUNITY || '0');
856
+ let probability = 'Medium';
857
+ let reason = 'Standard deal flow.';
858
+ const stageId = dealResult?.STAGE_ID || '';
859
+ if (stageId.includes('WON')) {
860
+ probability = 'Won';
861
+ reason = 'Deal is already won.';
862
+ }
863
+ else if (amount > 10000) {
864
+ probability = 'High';
865
+ reason = 'High value deal, usually prioritized.';
866
+ }
867
+ else if (!dealResult?.ASSIGNED_BY_ID) {
868
+ probability = 'Low';
869
+ reason = 'No assigned manager.';
870
+ }
871
+ returnData.push({
872
+ json: {
873
+ tool_call_result: {
874
+ dealId,
875
+ probability,
876
+ reason,
877
+ amount,
878
+ currency: dealResult?.CURRENCY_ID
879
+ },
880
+ summary: `Deal Forecast: ${probability} (Reason: ${reason})`
881
+ },
882
+ pairedItem: { item: i }
883
+ });
884
+ }
885
+ if (operation === 'createMarketingSegment') {
886
+ const name = this.getNodeParameter('marketingName', i);
887
+ // Basic segment creation
888
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.marketing.segment.add', {
889
+ fields: {
890
+ NAME: name,
891
+ active: 'Y'
892
+ }
893
+ });
894
+ returnData.push({
895
+ json: {
896
+ tool_call_result: {
897
+ segmentId: response.result,
898
+ name
899
+ },
900
+ summary: `Created Marketing Segment "${name}" (ID: ${response.result})`
901
+ },
902
+ pairedItem: { item: i }
903
+ });
904
+ }
905
+ if (operation === 'createMarketingCampaign') {
906
+ const name = this.getNodeParameter('marketingName', i);
907
+ const type = this.getNodeParameter('campaignType', i);
908
+ const segmentId = this.getNodeParameter('campaignSegmentId', i);
909
+ const body = this.getNodeParameter('campaignBody', i);
910
+ // crm.marketing.campaign.add (Complex API, usually requires layout)
911
+ // Simplified for AI: just create draft
912
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.marketing.campaign.add', {
913
+ fields: {
914
+ NAME: name,
915
+ CODE: 'n8n_auto_' + Date.now(),
916
+ ACTIVE: 'Y',
917
+ TYPE_ID: type.toUpperCase(),
918
+ SEGMENT_ID: segmentId,
919
+ BODY: body // HTML/Text body
920
+ }
921
+ });
922
+ returnData.push({
923
+ json: {
924
+ tool_call_result: {
925
+ campaignId: response.result,
926
+ status: 'DRAFT'
927
+ },
928
+ summary: `Created ${type} Campaign "${name}" (Draft)`
929
+ },
930
+ pairedItem: { item: i }
931
+ });
932
+ }
933
+ if (operation === 'getFunnelStructure') {
934
+ // 1. Get Categories (Funnels)
935
+ const categories = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.dealcategory.list', {});
936
+ const funnels = categories.result || [];
937
+ // 2. Get Stages for default funnel (ID 0)
938
+ const defaultStages = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.dealcategory.stage.list', { id: 0 });
939
+ // 3. Construct structure
940
+ const result = [
941
+ {
942
+ ID: '0',
943
+ NAME: 'General',
944
+ STAGES: defaultStages.result
945
+ }
946
+ ];
947
+ // For other funnels, fetch stages?
948
+ // crm.dealcategory.stage.list with id=CATEGORY_ID
949
+ for (const f of funnels) {
950
+ if (f.ID === '0')
951
+ continue; // Skip default if present
952
+ const stages = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.dealcategory.stage.list', { id: f.ID });
953
+ result.push({
954
+ ID: f.ID,
955
+ NAME: f.NAME,
956
+ STAGES: stages.result
957
+ });
958
+ }
959
+ returnData.push({ json: { funnels: result }, pairedItem: { item: i } });
960
+ }
961
+ if (operation === 'registerAdSource') {
962
+ const name = this.getNodeParameter('marketingName', i); // Reuse marketingName
963
+ const code = 'n8n_' + Date.now();
964
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.tracking.source.add', {
965
+ fields: {
966
+ NAME: name,
967
+ CODE: code
968
+ }
969
+ });
970
+ returnData.push({
971
+ json: {
972
+ tool_call_result: { sourceId: response.result, code },
973
+ summary: `Registered Ad Source "${name}"`
974
+ },
975
+ pairedItem: { item: i }
976
+ });
977
+ }
978
+ if (operation === 'findDuplicates') {
979
+ const type = this.getNodeParameter('entityType', i); // Reuse entityType?
980
+ // crm.duplicate.find requires entity_type (LEAD, CONTACT, COMPANY)
981
+ // And type (EMAIL, PHONE, PERSON)
982
+ // Let's simplify: Search by Phone or Email?
983
+ // Or just use generic 'query' parameter as value?
984
+ // Ideally we need dedicated inputs. Reuse 'query' as value (e.g. phone number).
985
+ // We need to know WHAT to search (Phone, Email).
986
+ // Let's assume user passes JSON in 'query' or we stick to simple Phone search for now?
987
+ // Bitrix24Tool 'searchCrm' handles simple search.
988
+ // 'findDuplicates' is stricter.
989
+ // crm.duplicate.findbycomm params: type=EMAIL, values=[...], entity_type=LEAD
990
+ // Simplification for V26: Search by Email/Phone automatically based on regex of query?
991
+ // Or just search by Phone (most common).
992
+ const query = this.getNodeParameter('query', i);
993
+ let typeToSearch = 'PHONE';
994
+ if (query.includes('@'))
995
+ typeToSearch = 'EMAIL';
996
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'crm.duplicate.findbycomm', {
997
+ type: typeToSearch,
998
+ values: [query],
999
+ entity_type: type.toUpperCase() // LEAD, CONTACT...
1000
+ });
1001
+ returnData.push({ json: { duplicates: response.result }, pairedItem: { item: i } });
1002
+ }
1003
+ if (operation === 'addCrmStatus') {
1004
+ // Pending implementation
1005
+ }
1006
+ if (operation === 'getScope') {
1007
+ // scope returns json with 'result' array of scopes
1008
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'GET', 'scope.json', {});
1009
+ returnData.push({ json: { scope: response.result }, pairedItem: { item: i } });
1010
+ }
1011
+ if (operation === 'getFeatures') {
1012
+ // feature.get
1013
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'feature.get', {});
1014
+ returnData.push({ json: { features: response.result }, pairedItem: { item: i } });
1015
+ }
1016
+ if (operation === 'listOffline') {
1017
+ // event.offline.list
1018
+ // Requires scope: 'im'? No, 'event' scope? Usually included in basic.
1019
+ const params = JSON.parse(this.getNodeParameter('jsonParameters', i, '{}'));
1020
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'event.offline.list', params);
1021
+ returnData.push({ json: { events: response.result }, pairedItem: { item: i } });
1022
+ }
1023
+ }
1024
+ catch (error) {
1025
+ if (this.continueOnFail()) {
1026
+ returnData.push({ json: { error: error.message }, pairedItem: { item: i } });
1027
+ continue;
1028
+ }
1029
+ throw error;
1030
+ }
1031
+ }
1032
+ return [returnData];
1033
+ }
1034
+ }
1035
+ exports.Bitrix24Tool = Bitrix24Tool;