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,511 @@
1
+ "use strict";
2
+ /**
3
+ * Bitrix24 Telephony — Нода управления телефонией
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.Bitrix24Telephony = void 0;
17
+ const n8n_workflow_1 = require("n8n-workflow");
18
+ const Helpers_1 = require("../Bitrix24/Helpers");
19
+ class Bitrix24Telephony {
20
+ constructor() {
21
+ this.description = {
22
+ displayName: 'Bitrix24 Телефония',
23
+ name: 'bitrix24Telephony',
24
+ icon: 'file:bitrix24.svg',
25
+ group: ['transform'],
26
+ version: 1,
27
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
28
+ description: 'Управление звонками, записями разговоров и внешней телефонией',
29
+ defaults: {
30
+ name: 'Bitrix24 Телефония',
31
+ },
32
+ inputs: ['main'],
33
+ outputs: ['main'],
34
+ credentials: [
35
+ {
36
+ name: 'bitrix24Api',
37
+ required: true,
38
+ },
39
+ ],
40
+ properties: [
41
+ {
42
+ displayName: 'Resource',
43
+ name: 'resource',
44
+ type: 'options',
45
+ noDataExpression: true,
46
+ options: [
47
+ {
48
+ name: 'Call Statistic (History)',
49
+ value: 'statistic',
50
+ description: 'Get call history and recording IDs',
51
+ },
52
+ {
53
+ name: 'Call Recording',
54
+ value: 'recording',
55
+ description: 'Get download URL for call recording',
56
+ },
57
+ {
58
+ name: 'External Call',
59
+ value: 'external_call',
60
+ description: 'Register and finish calls from external PBX',
61
+ },
62
+ {
63
+ name: 'SIP Line',
64
+ value: 'sip_line',
65
+ description: 'List SIP lines and status',
66
+ },
67
+ {
68
+ name: 'User Settings',
69
+ value: 'user_settings',
70
+ description: 'Manage user extensions and telephony settings',
71
+ },
72
+ ],
73
+ default: 'statistic',
74
+ required: true,
75
+ },
76
+ {
77
+ displayName: 'Operation',
78
+ name: 'operation',
79
+ type: 'options',
80
+ noDataExpression: true,
81
+ options: [
82
+ {
83
+ name: 'List',
84
+ value: 'list',
85
+ description: 'List call statistics',
86
+ action: 'List call statistics',
87
+ displayOptions: {
88
+ show: {
89
+ resource: ['statistic'],
90
+ },
91
+ },
92
+ },
93
+ {
94
+ name: 'Get Download URL',
95
+ value: 'get_url',
96
+ description: 'Get temporary download URL for recording',
97
+ action: 'Get recording url',
98
+ displayOptions: {
99
+ show: {
100
+ resource: ['recording'],
101
+ },
102
+ },
103
+ },
104
+ {
105
+ name: 'Register Call',
106
+ value: 'register',
107
+ action: 'Register an external call',
108
+ displayOptions: {
109
+ show: {
110
+ resource: ['external_call'],
111
+ },
112
+ },
113
+ },
114
+ {
115
+ name: 'Finish Call',
116
+ value: 'finish',
117
+ action: 'Finish an external call',
118
+ displayOptions: {
119
+ show: {
120
+ resource: ['external_call'],
121
+ },
122
+ },
123
+ },
124
+ {
125
+ name: 'Attach Record (External)',
126
+ value: 'attach_record_external',
127
+ action: 'Attach record to external call',
128
+ displayOptions: {
129
+ show: {
130
+ resource: ['external_call'],
131
+ },
132
+ },
133
+ },
134
+ {
135
+ name: 'Search CRM',
136
+ value: 'search_crm',
137
+ action: 'Search CRM by phone',
138
+ displayOptions: {
139
+ show: {
140
+ resource: ['external_call'],
141
+ },
142
+ },
143
+ },
144
+ // SIP & User
145
+ {
146
+ name: 'List', // Reused
147
+ value: 'list',
148
+ action: 'List items',
149
+ displayOptions: {
150
+ show: {
151
+ resource: ['statistic', 'sip_line', 'user_settings'],
152
+ },
153
+ },
154
+ },
155
+ {
156
+ name: 'Get',
157
+ value: 'get',
158
+ action: 'Get item',
159
+ displayOptions: {
160
+ show: {
161
+ resource: ['user_settings'], // specific user
162
+ },
163
+ },
164
+ },
165
+ {
166
+ name: 'Update',
167
+ value: 'update',
168
+ action: 'Update item',
169
+ displayOptions: {
170
+ show: {
171
+ resource: ['user_settings'],
172
+ },
173
+ },
174
+ },
175
+ ],
176
+ default: 'list',
177
+ required: true,
178
+ },
179
+ // Recording Fields
180
+ {
181
+ displayName: 'Record File ID',
182
+ name: 'recordId',
183
+ type: 'string',
184
+ default: '',
185
+ required: true,
186
+ displayOptions: {
187
+ show: {
188
+ resource: ['recording'],
189
+ operation: ['get_url'],
190
+ },
191
+ },
192
+ description: 'ID of the recording file (from Statistic)',
193
+ },
194
+ // External Call Fields
195
+ {
196
+ displayName: 'Phone Number',
197
+ name: 'phoneNumber',
198
+ type: 'string',
199
+ default: '',
200
+ required: true,
201
+ displayOptions: {
202
+ show: {
203
+ resource: ['external_call'],
204
+ operation: ['register', 'search_crm'],
205
+ },
206
+ },
207
+ description: 'Phone number involved in the call',
208
+ },
209
+ {
210
+ displayName: 'Call Type',
211
+ name: 'callType',
212
+ type: 'options',
213
+ options: [
214
+ { name: 'Outgoing', value: '1' },
215
+ { name: 'Incoming', value: '2' },
216
+ { name: 'Incoming with Redirection', value: '3' },
217
+ { name: 'Callback', value: '4' },
218
+ ],
219
+ default: '2',
220
+ required: true,
221
+ displayOptions: {
222
+ show: {
223
+ resource: ['external_call'],
224
+ operation: ['register'],
225
+ },
226
+ },
227
+ },
228
+ {
229
+ displayName: 'User ID',
230
+ name: 'userId',
231
+ type: 'string',
232
+ default: '',
233
+ required: true,
234
+ displayOptions: {
235
+ show: {
236
+ resource: ['external_call', 'user_settings'],
237
+ operation: ['register', 'finish', 'get', 'update'],
238
+ },
239
+ },
240
+ description: 'User ID responsible or involved',
241
+ },
242
+ {
243
+ displayName: 'Call ID (External)',
244
+ name: 'callId',
245
+ type: 'string',
246
+ default: '',
247
+ required: true,
248
+ displayOptions: {
249
+ show: {
250
+ resource: ['external_call'],
251
+ operation: ['finish', 'attach_record_external'],
252
+ },
253
+ },
254
+ description: 'Call ID returned by register method',
255
+ },
256
+ {
257
+ displayName: 'Duration (Sec)',
258
+ name: 'duration',
259
+ type: 'number',
260
+ default: 0,
261
+ displayOptions: {
262
+ show: {
263
+ resource: ['external_call'],
264
+ operation: ['finish'],
265
+ },
266
+ },
267
+ },
268
+ {
269
+ displayName: 'Record URL',
270
+ name: 'recordUrl',
271
+ type: 'string',
272
+ default: '',
273
+ displayOptions: {
274
+ show: {
275
+ resource: ['external_call'],
276
+ operation: ['attach_record_external'],
277
+ },
278
+ },
279
+ description: 'Publicly accessible URL of the record file',
280
+ },
281
+ // User Settings
282
+ {
283
+ displayName: 'Inner Phone (Extension)',
284
+ name: 'innerPhone',
285
+ type: 'string',
286
+ default: '',
287
+ displayOptions: {
288
+ show: {
289
+ resource: ['user_settings'],
290
+ operation: ['update'],
291
+ },
292
+ },
293
+ },
294
+ // List Fields
295
+ {
296
+ displayName: 'Return All',
297
+ name: 'returnAll',
298
+ type: 'boolean',
299
+ default: false,
300
+ displayOptions: {
301
+ show: {
302
+ operation: ['list'],
303
+ },
304
+ },
305
+ description: 'Whether to return all results or only up to a given limit',
306
+ },
307
+ {
308
+ displayName: 'Limit',
309
+ name: 'limit',
310
+ type: 'number',
311
+ default: 50,
312
+ displayOptions: {
313
+ show: {
314
+ operation: ['list'],
315
+ returnAll: [false],
316
+ },
317
+ },
318
+ },
319
+ {
320
+ displayName: 'Filter JSON',
321
+ name: 'filterJson',
322
+ type: 'json',
323
+ default: '{}',
324
+ displayOptions: {
325
+ show: {
326
+ operation: ['list'],
327
+ },
328
+ },
329
+ description: 'Filter parameters',
330
+ },
331
+ ],
332
+ };
333
+ }
334
+ async execute() {
335
+ const items = this.getInputData();
336
+ const returnData = [];
337
+ const resource = this.getNodeParameter('resource', 0);
338
+ const operation = this.getNodeParameter('operation', 0);
339
+ for (let i = 0; i < items.length; i++) {
340
+ try {
341
+ if (resource === 'statistic' && operation === 'list') {
342
+ const returnAll = this.getNodeParameter('returnAll', i);
343
+ const filterJson = this.getNodeParameter('filterJson', i, '{}');
344
+ let filter = {};
345
+ try {
346
+ filter = JSON.parse(filterJson);
347
+ }
348
+ catch (e) { }
349
+ const body = { filter, sort: { CALL_START_DATE: 'DESC' } };
350
+ const limit = returnAll ? 100000 : this.getNodeParameter('limit', i);
351
+ // voximplant.statistic.get supports pagination
352
+ // But docs say max 1000 per request? Usually 50.
353
+ if (returnAll) {
354
+ let start = 0;
355
+ let hasMore = true;
356
+ while (hasMore) {
357
+ // Safety break usually needed?
358
+ // voximplant.statistic.get acts like list methods ?
359
+ // Docs: "next" parameter is not mentioned standardly, usually 'start' works.
360
+ // But some Bitrix methods use 'next'. 'voximplant.statistic.get' normally uses 'start'.
361
+ // Actually, telephony statistics might require special handling.
362
+ // Let's assume standard 'start' for now, check docs if fails.
363
+ // Docs say: returns list.
364
+ body.start = start;
365
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'voximplant.statistic.get.json', body);
366
+ const results = response.result;
367
+ if (!results || results.length === 0) {
368
+ hasMore = false;
369
+ }
370
+ else {
371
+ for (const item of results) {
372
+ returnData.push({
373
+ json: item,
374
+ pairedItem: { item: i },
375
+ });
376
+ }
377
+ start += results.length;
378
+ if (results.length < 50)
379
+ hasMore = false;
380
+ }
381
+ }
382
+ }
383
+ else {
384
+ // Single page
385
+ // Note: Bitrix might ignore limit param in body and just use server limit (50).
386
+ // We might need to slice result if user wants 10.
387
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'voximplant.statistic.get.json', body);
388
+ let results = response.result;
389
+ if (results) {
390
+ if (limit < results.length) {
391
+ results = results.slice(0, limit);
392
+ }
393
+ for (const item of results) {
394
+ returnData.push({
395
+ json: item,
396
+ pairedItem: { item: i },
397
+ });
398
+ }
399
+ }
400
+ }
401
+ }
402
+ // External Call Logic
403
+ if (resource === 'external_call') {
404
+ if (operation === 'register') {
405
+ const PHONE_NUMBER = this.getNodeParameter('phoneNumber', i);
406
+ const USER_ID = this.getNodeParameter('userId', i);
407
+ const TYPE = this.getNodeParameter('callType', i);
408
+ // Other optional params like CRM_CREATE, CALL_START_DATE ignored for brevity unless requested
409
+ const body = { PHONE_NUMBER, USER_ID, TYPE, CRM_CREATE: 1, CALL_START_DATE: new Date().toISOString() };
410
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'telephony.externalcall.register.json', body);
411
+ returnData.push({ json: response.result, pairedItem: { item: i } });
412
+ }
413
+ if (operation === 'finish') {
414
+ const CADLL_ID = this.getNodeParameter('callId', i);
415
+ const USER_ID = this.getNodeParameter('userId', i);
416
+ const DURATION = this.getNodeParameter('duration', i);
417
+ const body = { CALL_ID: CADLL_ID, USER_ID, DURATION, STATUS_CODE: 200 };
418
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'telephony.externalcall.finish.json', body);
419
+ returnData.push({ json: response.result, pairedItem: { item: i } });
420
+ }
421
+ if (operation === 'attach_record_external') {
422
+ const CALL_ID = this.getNodeParameter('callId', i);
423
+ const FILENAME = 'record.mp3'; // Default
424
+ const RECORD_URL = this.getNodeParameter('recordUrl', i);
425
+ const body = { CALL_ID, FILENAME, RECORD_URL };
426
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'telephony.externalCall.attachRecord.json', body);
427
+ returnData.push({ json: response.result, pairedItem: { item: i } });
428
+ }
429
+ if (operation === 'search_crm') {
430
+ const PHONE_NUMBER = this.getNodeParameter('phoneNumber', i);
431
+ const body = { PHONE_NUMBER };
432
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'telephony.externalCall.searchCrmEntities.json', body);
433
+ returnData.push({ json: response.result, pairedItem: { item: i } });
434
+ }
435
+ }
436
+ // SIP Line Logic
437
+ if (resource === 'sip_line') {
438
+ if (operation === 'list') {
439
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'voximplant.sip.get.json', {});
440
+ const results = response.result || [];
441
+ for (const item of results) {
442
+ returnData.push({ json: item, pairedItem: { item: i } });
443
+ }
444
+ }
445
+ }
446
+ // User Settings Logic
447
+ if (resource === 'user_settings') {
448
+ if (operation === 'list') {
449
+ // voximplant.user.get returns all if no filter?
450
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'voximplant.user.get.json', {});
451
+ const results = response.result || [];
452
+ for (const item of results) {
453
+ returnData.push({ json: item, pairedItem: { item: i } });
454
+ }
455
+ }
456
+ if (operation === 'get') {
457
+ const USER_ID = this.getNodeParameter('userId', i);
458
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'voximplant.user.get.json', { ID: USER_ID });
459
+ // Returns array usually
460
+ const results = response.result || [];
461
+ if (results.length > 0) {
462
+ returnData.push({ json: results[0], pairedItem: { item: i } });
463
+ }
464
+ else {
465
+ // Return empty or error? Empty better.
466
+ }
467
+ }
468
+ if (operation === 'update') {
469
+ const USER_ID = this.getNodeParameter('userId', i);
470
+ const USER_PHONE_INNER = this.getNodeParameter('innerPhone', i);
471
+ const body = { ID: USER_ID, USER_PHONE_INNER };
472
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'voximplant.user.update.json', body);
473
+ returnData.push({ json: response.result, pairedItem: { item: i } });
474
+ }
475
+ }
476
+ if (resource === 'recording' && operation === 'get_url') {
477
+ const recordId = this.getNodeParameter('recordId', i);
478
+ // Use disk.file.get to retrieve download URL
479
+ const response = await Helpers_1.bitrixRequestWithRetry.call(this, 'POST', 'disk.file.get.json', { id: recordId });
480
+ const result = response.result;
481
+ if (result && result.DOWNLOAD_URL) {
482
+ returnData.push({
483
+ json: {
484
+ recordId,
485
+ downloadUrl: result.DOWNLOAD_URL,
486
+ fileName: result.NAME,
487
+ size: result.SIZE
488
+ },
489
+ pairedItem: { item: i },
490
+ });
491
+ }
492
+ else {
493
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Could not retrieve download URL. File might be deleted or access denied.', { itemIndex: i });
494
+ }
495
+ }
496
+ }
497
+ catch (error) {
498
+ if (this.continueOnFail()) {
499
+ returnData.push({
500
+ json: { error: error.message },
501
+ pairedItem: { item: i },
502
+ });
503
+ continue;
504
+ }
505
+ throw error;
506
+ }
507
+ }
508
+ return [returnData];
509
+ }
510
+ }
511
+ exports.Bitrix24Telephony = Bitrix24Telephony;