n8n-nodes-digitalsac 0.5.7 → 0.5.9

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.
@@ -1,1366 +0,0 @@
1
- import {
2
- IExecuteFunctions,
3
- INodeExecutionData,
4
- INodeType,
5
- INodeTypeDescription,
6
- NodeConnectionType,
7
- IDataObject,
8
- IBinaryKeyData,
9
- } from 'n8n-workflow';
10
-
11
- export class Digitalsac implements INodeType {
12
- description: INodeTypeDescription = {
13
- displayName: 'Digitalsac Izing Pro',
14
- name: 'digitalsac',
15
- icon: 'file:digitalsac.svg',
16
- group: ['transform'],
17
- version: 1,
18
- description: 'Interage com a API do Digitalsac',
19
- defaults: {
20
- name: 'Digitalsac',
21
- },
22
- inputs: <NodeConnectionType[]>['main'],
23
- outputs: <NodeConnectionType[]>['main'],
24
-
25
- credentials: [
26
- {
27
- name: 'digitalsacApi',
28
- required: true,
29
- },
30
- ],
31
- properties: [
32
- {
33
- displayName: 'Operação',
34
- name: 'operation',
35
- type: 'options',
36
- options: [
37
- { name: 'Validar WhatsApp', value: 'validateWhatsapp' },
38
- { name: 'Validar CPF', value: 'validateCpf' },
39
- { name: 'Validar Data', value: 'validateDate' },
40
- { name: 'Listar Filas', value: 'listQueues' },
41
- { name: 'Listar Atendentes', value: 'listAgents' },
42
- { name: 'Transferir para Fila', value: 'transferQueue' },
43
- { name: 'Transferir para Atendente', value: 'transferAgent' },
44
- { name: 'Fechar Ticket', value: 'closeTicket' },
45
- { name: 'Enviar Mensagem', value: 'sendMessage' },
46
- { name: 'Enviar Botões', value: 'sendButtons' },
47
- { name: 'Enviar Lista', value: 'sendList' },
48
- { name: 'Enviar Mídia com Caption', value: 'sendMediaCaption' },
49
- { name: 'Enviar Base64', value: 'sendBase64' },
50
- { name: 'Listar Tags', value: 'listTags' },
51
- { name: 'Vincular Tag', value: 'linkTag' },
52
- { name: 'Criar Tag', value: 'createTag' },
53
- { name: 'Listar Kanbans', value: 'listKanbans' },
54
- { name: 'Vincular Kanban', value: 'linkKanban' },
55
- { name: 'Listar Carteiras', value: 'listCarteiras' },
56
- { name: 'Vincular Carteira', value: 'linkCarteira' },
57
- // Agendamento
58
- { name: 'Listar Serviços', value: 'listServices' },
59
- { name: 'Listar Usuários Disponíveis', value: 'listAvailableUsers' },
60
- { name: 'Listar Horários Disponíveis', value: 'listAvailableSlots' },
61
- { name: 'Listar Agendamentos', value: 'listSchedules' },
62
- { name: 'Criar Agendamento', value: 'createSchedule' },
63
- { name: 'Cancelar Agendamento', value: 'cancelSchedule' },
64
- { name: 'Gerar Link do Calendário (.ics)', value: 'calendarLink' },
65
- // Templates WABA
66
- { name: 'Listar Templates WABA', value: 'listWabaTemplates' },
67
- { name: 'Enviar Template WABA', value: 'sendWabaTemplate' },
68
- ],
69
- default: 'validateWhatsapp',
70
- },
71
- {
72
- displayName: 'Parâmetro',
73
- name: 'param',
74
- type: 'string',
75
- default: '',
76
- displayOptions: {
77
- show: {
78
- operation: ['validateWhatsapp', 'validateCpf', 'sendMessage', 'sendButtons', 'sendList', 'sendMediaCaption', 'sendBase64'],
79
- },
80
- },
81
- description: 'Número, CPF ou UUID da conexão (conforme operação)',
82
- },
83
- {
84
- displayName: 'User ID',
85
- name: 'userId',
86
- type: 'number',
87
- default: 1,
88
- displayOptions: {
89
- show: {
90
- operation: ['listKanbans'],
91
- },
92
- },
93
- description: 'ID do usuário para listar kanbans',
94
- },
95
- {
96
- displayName: 'Formato de Resposta',
97
- name: 'agentsFormat',
98
- type: 'options',
99
- options: [
100
- { name: 'JSON Completo (Recomendado)', value: 'json' },
101
- { name: 'Texto Formatado (Compatibilidade)', value: 'string' },
102
- ],
103
- default: 'json',
104
- displayOptions: {
105
- show: {
106
- operation: ['listAgents'],
107
- },
108
- },
109
- description: 'Formato de retorno: JSON completo com todos os campos (id, name, email, phoneNumber, status, profile, isOnline, isActive, isMaster) ou texto formatado para compatibilidade',
110
- },
111
- {
112
- displayName: 'Corpo da Mensagem',
113
- name: 'messageBody',
114
- type: 'string',
115
- default: 'Mensagem de teste',
116
- displayOptions: {
117
- show: {
118
- operation: ['sendMessage'],
119
- },
120
- },
121
- description: 'Texto da mensagem a ser enviada',
122
- },
123
- {
124
- displayName: 'Número de Telefone',
125
- name: 'phoneNumber',
126
- type: 'string',
127
- default: '5511999999999',
128
- displayOptions: {
129
- show: {
130
- operation: ['sendMessage'],
131
- },
132
- },
133
- description: 'Número de telefone no formato DDI+DDD+Número (ex: 5511999999999)',
134
- },
135
- {
136
- displayName: 'Chave Externa',
137
- name: 'externalKey',
138
- type: 'string',
139
- default: 'Digitalsac123',
140
- displayOptions: {
141
- show: {
142
- operation: ['sendMessage', 'sendButtons', 'sendList', 'sendMediaCaption', 'sendBase64'],
143
- },
144
- },
145
- description: 'Identificador único opcional para a mensagem',
146
- },
147
- // Campos para Enviar Botões
148
- {
149
- displayName: 'Título',
150
- name: 'buttonTitle',
151
- type: 'string',
152
- default: 'Escolha uma opção',
153
- displayOptions: {
154
- show: {
155
- operation: ['sendButtons'],
156
- },
157
- },
158
- description: 'Título do conjunto de botões',
159
- },
160
- {
161
- displayName: 'Corpo da Mensagem',
162
- name: 'buttonBody',
163
- type: 'string',
164
- default: 'Clique em uma das opções abaixo:',
165
- displayOptions: {
166
- show: {
167
- operation: ['sendButtons'],
168
- },
169
- },
170
- description: 'Corpo da mensagem com botões',
171
- },
172
- {
173
- displayName: 'Número de Telefone',
174
- name: 'buttonPhoneNumber',
175
- type: 'string',
176
- default: '5511999999999',
177
- displayOptions: {
178
- show: {
179
- operation: ['sendButtons'],
180
- },
181
- },
182
- description: 'Número de telefone no formato DDI+DDD+Número',
183
- },
184
- {
185
- displayName: 'Botões (JSON)',
186
- name: 'buttonsData',
187
- type: 'json',
188
- default: '[\n {\n "tipo": {"label": "Resposta Rápida", "value": "quick_reply"},\n "display_text": "Sim",\n "conteudo": "sim"\n },\n {\n "tipo": {"label": "URL", "value": "url"},\n "display_text": "Visitar Site",\n "conteudo": "https://exemplo.com"\n }\n]',
189
- displayOptions: {
190
- show: {
191
- operation: ['sendButtons'],
192
- },
193
- },
194
- description: 'Array de botões em formato JSON',
195
- },
196
- // Campos para Enviar Lista
197
- {
198
- displayName: 'Título',
199
- name: 'listTitle',
200
- type: 'string',
201
- default: 'Menu de Opções',
202
- displayOptions: {
203
- show: {
204
- operation: ['sendList'],
205
- },
206
- },
207
- description: 'Título da lista',
208
- },
209
- {
210
- displayName: 'Texto',
211
- name: 'listText',
212
- type: 'string',
213
- default: 'Escolha uma categoria:',
214
- displayOptions: {
215
- show: {
216
- operation: ['sendList'],
217
- },
218
- },
219
- description: 'Texto da lista',
220
- },
221
- {
222
- displayName: 'Texto do Botão',
223
- name: 'listButtonText',
224
- type: 'string',
225
- default: 'Ver Opções',
226
- displayOptions: {
227
- show: {
228
- operation: ['sendList'],
229
- },
230
- },
231
- description: 'Texto do botão para abrir a lista',
232
- },
233
- {
234
- displayName: 'Rodapé',
235
- name: 'listFooter',
236
- type: 'string',
237
- default: 'Powered by DigitalSac',
238
- displayOptions: {
239
- show: {
240
- operation: ['sendList'],
241
- },
242
- },
243
- description: 'Rodapé da lista',
244
- },
245
- {
246
- displayName: 'Número de Telefone',
247
- name: 'listPhoneNumber',
248
- type: 'string',
249
- default: '5511999999999',
250
- displayOptions: {
251
- show: {
252
- operation: ['sendList'],
253
- },
254
- },
255
- description: 'Número de telefone no formato DDI+DDD+Número',
256
- },
257
- {
258
- displayName: 'Seções (JSON)',
259
- name: 'sectionsData',
260
- type: 'json',
261
- default: '[\n {\n "title": "Produtos",\n "lines": [\n {\n "title": "Produto A",\n "description": "Descrição do produto A",\n "rowId": 1\n }\n ]\n }\n]',
262
- displayOptions: {
263
- show: {
264
- operation: ['sendList'],
265
- },
266
- },
267
- description: 'Array de seções da lista em formato JSON',
268
- },
269
- // Campos para Enviar Mídia com Caption
270
- {
271
- displayName: 'Caption',
272
- name: 'mediaCaption',
273
- type: 'string',
274
- default: 'Arquivo enviado via API',
275
- displayOptions: {
276
- show: {
277
- operation: ['sendMediaCaption'],
278
- },
279
- },
280
- description: 'Legenda do arquivo',
281
- },
282
- {
283
- displayName: 'Número de Telefone',
284
- name: 'mediaCaptionPhoneNumber',
285
- type: 'string',
286
- default: '5511999999999',
287
- displayOptions: {
288
- show: {
289
- operation: ['sendMediaCaption'],
290
- },
291
- },
292
- description: 'Número de telefone no formato DDI+DDD+Número',
293
- },
294
- // Campos para Enviar Base64
295
- {
296
- displayName: 'Caption (Opcional)',
297
- name: 'base64Caption',
298
- type: 'string',
299
- default: '',
300
- displayOptions: {
301
- show: {
302
- operation: ['sendBase64'],
303
- },
304
- },
305
- description: 'Legenda opcional do arquivo',
306
- },
307
- {
308
- displayName: 'Número de Telefone',
309
- name: 'base64PhoneNumber',
310
- type: 'string',
311
- default: '5511999999999',
312
- displayOptions: {
313
- show: {
314
- operation: ['sendBase64'],
315
- },
316
- },
317
- description: 'Número de telefone no formato DDI+DDD+Número',
318
- },
319
- {
320
- displayName: 'Arquivo Base64',
321
- name: 'mediaBase64',
322
- type: 'string',
323
- default: '',
324
- displayOptions: {
325
- show: {
326
- operation: ['sendBase64'],
327
- },
328
- },
329
- description: 'Arquivo codificado em base64',
330
- },
331
- {
332
- displayName: 'Tipo MIME',
333
- name: 'mimeType',
334
- type: 'string',
335
- default: 'image/png',
336
- displayOptions: {
337
- show: {
338
- operation: ['sendBase64'],
339
- },
340
- },
341
- description: 'Tipo MIME do arquivo (ex: image/png, application/pdf)',
342
- },
343
- {
344
- displayName: 'Nome do Arquivo',
345
- name: 'fileName',
346
- type: 'string',
347
- default: 'arquivo.png',
348
- displayOptions: {
349
- show: {
350
- operation: ['sendBase64'],
351
- },
352
- },
353
- description: 'Nome do arquivo com extensão',
354
- },
355
- {
356
- displayName: 'Nome da Tag',
357
- name: 'tagName',
358
- type: 'string',
359
- default: 'Nova Tag',
360
- displayOptions: {
361
- show: {
362
- operation: ['createTag'],
363
- },
364
- },
365
- description: 'Nome da tag a ser criada',
366
- },
367
- {
368
- displayName: 'Cor da Tag',
369
- name: 'tagColor',
370
- type: 'string',
371
- default: '#2196F3',
372
- displayOptions: {
373
- show: {
374
- operation: ['createTag'],
375
- },
376
- },
377
- description: 'Cor da tag em formato hexadecimal (ex: #FF5733, #2196F3, #4CAF50)',
378
- },
379
- {
380
- displayName: 'Dados (JSON)',
381
- name: 'bodyData',
382
- type: 'json',
383
- default: '{"data": "2024-01-15"}',
384
- displayOptions: {
385
- show: {
386
- operation: ['validateDate'],
387
- },
388
- },
389
- description: 'Data a ser validada no formato JSON',
390
- },
391
- {
392
- displayName: 'Dados (JSON)',
393
- name: 'bodyData',
394
- type: 'json',
395
- default: '{"ticketId": 123, "queueId": 1}',
396
- displayOptions: {
397
- show: {
398
- operation: ['transferQueue'],
399
- },
400
- },
401
- description: 'ID do ticket e ID da fila de destino',
402
- },
403
- {
404
- displayName: 'Dados (JSON)',
405
- name: 'bodyData',
406
- type: 'json',
407
- default: '{"ticketId": 123, "userId": 1}',
408
- displayOptions: {
409
- show: {
410
- operation: ['transferAgent'],
411
- },
412
- },
413
- description: 'ID do ticket e ID do atendente de destino',
414
- },
415
- {
416
- displayName: 'Dados (JSON)',
417
- name: 'bodyData',
418
- type: 'json',
419
- default: '{"ticketId": 123}',
420
- displayOptions: {
421
- show: {
422
- operation: ['closeTicket'],
423
- },
424
- },
425
- description: 'ID do ticket a ser fechado',
426
- },
427
- {
428
- displayName: 'Dados (JSON)',
429
- name: 'bodyData',
430
- type: 'json',
431
- default: '{"ticketId": 123, "tagId": 456}',
432
- displayOptions: {
433
- show: {
434
- operation: ['linkTag'],
435
- },
436
- },
437
- description: 'ID do ticket e ID da tag a ser vinculada',
438
- },
439
- {
440
- displayName: 'Dados (JSON)',
441
- name: 'bodyData',
442
- type: 'json',
443
- default: '{"ticketId": 123, "kanbanId": 456, "userId": 789}',
444
- displayOptions: {
445
- show: {
446
- operation: ['linkKanban'],
447
- },
448
- },
449
- description: 'ID do ticket, ID do kanban e ID do usuário',
450
- },
451
- {
452
- displayName: 'Dados (JSON)',
453
- name: 'bodyData',
454
- type: 'json',
455
- default: '{"ticketId": 123, "userId": 456}',
456
- displayOptions: {
457
- show: {
458
- operation: ['linkCarteira'],
459
- },
460
- },
461
- description: 'ID do ticket e ID do usuário da carteira',
462
- },
463
- // Campos para Agendamento
464
- {
465
- displayName: 'ID do Usuário',
466
- name: 'scheduleUserId',
467
- type: 'number',
468
- default: 0,
469
- displayOptions: {
470
- show: {
471
- operation: ['listServices'],
472
- },
473
- },
474
- description: 'ID do usuário para filtrar serviços (opcional)',
475
- },
476
- {
477
- displayName: 'ID do Serviço',
478
- name: 'serviceId',
479
- type: 'number',
480
- default: 1,
481
- displayOptions: {
482
- show: {
483
- operation: ['listAvailableUsers', 'listAvailableSlots', 'createSchedule'],
484
- },
485
- },
486
- description: 'ID do serviço',
487
- },
488
- {
489
- displayName: 'Data',
490
- name: 'scheduleDate',
491
- type: 'string',
492
- default: '',
493
- placeholder: '2025-08-07',
494
- displayOptions: {
495
- show: {
496
- operation: ['listAvailableUsers', 'listAvailableSlots', 'createSchedule'],
497
- },
498
- },
499
- description: 'Data no formato YYYY-MM-DD',
500
- },
501
- {
502
- displayName: 'Horário',
503
- name: 'scheduleTime',
504
- type: 'string',
505
- default: '',
506
- placeholder: '09:00',
507
- displayOptions: {
508
- show: {
509
- operation: ['listAvailableUsers', 'createSchedule'],
510
- },
511
- },
512
- description: 'Horário no formato HH:mm (opcional para listar usuários)',
513
- },
514
- {
515
- displayName: 'ID do Usuário',
516
- name: 'scheduleAttendantId',
517
- type: 'number',
518
- default: 1,
519
- displayOptions: {
520
- show: {
521
- operation: ['listAvailableSlots', 'createSchedule'],
522
- },
523
- },
524
- description: 'ID do atendente/usuário',
525
- },
526
- {
527
- displayName: 'Nome do Contato',
528
- name: 'contactName',
529
- type: 'string',
530
- default: '',
531
- displayOptions: {
532
- show: {
533
- operation: ['createSchedule'],
534
- },
535
- },
536
- description: 'Nome do cliente/contato',
537
- },
538
- {
539
- displayName: 'Telefone do Contato',
540
- name: 'contactPhone',
541
- type: 'string',
542
- default: '',
543
- placeholder: '5511999999999',
544
- displayOptions: {
545
- show: {
546
- operation: ['createSchedule'],
547
- },
548
- },
549
- description: 'Telefone do cliente/contato',
550
- },
551
- {
552
- displayName: 'Observações',
553
- name: 'scheduleNotes',
554
- type: 'string',
555
- default: '',
556
- displayOptions: {
557
- show: {
558
- operation: ['createSchedule'],
559
- },
560
- },
561
- description: 'Observações sobre o agendamento (opcional)',
562
- },
563
- {
564
- displayName: 'ID da Conexão WhatsApp',
565
- name: 'whatsappId',
566
- type: 'number',
567
- default: 0,
568
- displayOptions: {
569
- show: {
570
- operation: ['createSchedule'],
571
- },
572
- },
573
- description: 'ID da conexão WhatsApp (opcional - usa primeira disponível se não informado)',
574
- },
575
- {
576
- displayName: 'Mensagem Personalizada',
577
- name: 'customMessage',
578
- type: 'string',
579
- default: '',
580
- displayOptions: {
581
- show: {
582
- operation: ['createSchedule'],
583
- },
584
- },
585
- description: 'Mensagem personalizada do agendamento (opcional)',
586
- },
587
- {
588
- displayName: 'Lembretes (minutos)',
589
- name: 'reminders',
590
- type: 'string',
591
- default: '60,240',
592
- placeholder: '60,240,1440',
593
- displayOptions: {
594
- show: {
595
- operation: ['createSchedule'],
596
- },
597
- },
598
- description: 'Lembretes em minutos antes do agendamento (separados por vírgula)',
599
- },
600
- {
601
- displayName: 'Duração do Intervalo (minutos)',
602
- name: 'intervalDuration',
603
- type: 'number',
604
- default: 30,
605
- displayOptions: {
606
- show: {
607
- operation: ['createSchedule'],
608
- },
609
- },
610
- description: 'Duração do intervalo em minutos',
611
- },
612
- {
613
- displayName: 'Fechar Ticket',
614
- name: 'closeTicket',
615
- type: 'boolean',
616
- default: false,
617
- displayOptions: {
618
- show: {
619
- operation: ['createSchedule'],
620
- },
621
- },
622
- description: 'Se deve fechar o ticket após criar agendamento',
623
- },
624
- {
625
- displayName: 'Data',
626
- name: 'listScheduleDate',
627
- type: 'string',
628
- default: '',
629
- placeholder: '2025-08-08',
630
- displayOptions: {
631
- show: {
632
- operation: ['listSchedules'],
633
- },
634
- },
635
- description: 'Data no formato YYYY-MM-DD para listar agendamentos',
636
- },
637
- {
638
- displayName: 'User ID (Opcional)',
639
- name: 'listScheduleUserId',
640
- type: 'number',
641
- default: 0,
642
- displayOptions: {
643
- show: {
644
- operation: ['listSchedules'],
645
- },
646
- },
647
- description: 'ID do usuário para filtrar agendamentos (opcional)',
648
- },
649
- {
650
- displayName: 'ID do Agendamento',
651
- name: 'scheduleId',
652
- type: 'number',
653
- default: 0,
654
- displayOptions: {
655
- show: {
656
- operation: ['cancelSchedule'],
657
- },
658
- },
659
- description: 'ID do agendamento a ser cancelado',
660
- },
661
- {
662
- displayName: 'ID do Agendamento',
663
- name: 'calendarScheduleId',
664
- type: 'number',
665
- default: 0,
666
- displayOptions: {
667
- show: {
668
- operation: ['calendarLink'],
669
- },
670
- },
671
- description: 'ID do agendamento para gerar o link do calendário',
672
- },
673
- // Campos para Templates WABA
674
- {
675
- displayName: 'WhatsApp ID',
676
- name: 'wabaWhatsappId',
677
- type: 'number',
678
- default: 1,
679
- displayOptions: {
680
- show: {
681
- operation: ['listWabaTemplates', 'sendWabaTemplate'],
682
- },
683
- },
684
- description: 'ID da conexão WhatsApp WABA',
685
- },
686
- {
687
- displayName: 'Template ID',
688
- name: 'wabaTemplateId',
689
- type: 'number',
690
- default: 1,
691
- displayOptions: {
692
- show: {
693
- operation: ['sendWabaTemplate'],
694
- },
695
- },
696
- description: 'ID do template no sistema (obtido após importação)',
697
- },
698
- {
699
- displayName: 'Número de Telefone',
700
- name: 'wabaPhoneNumber',
701
- type: 'string',
702
- default: '5511999999999',
703
- displayOptions: {
704
- show: {
705
- operation: ['sendWabaTemplate'],
706
- },
707
- },
708
- description: 'Número do destinatário com DDI (ex: 5511999999999)',
709
- },
710
- {
711
- displayName: 'Parâmetros do Template (JSON)',
712
- name: 'wabaTemplateParams',
713
- type: 'json',
714
- default: '{}',
715
- displayOptions: {
716
- show: {
717
- operation: ['sendWabaTemplate'],
718
- },
719
- },
720
- description: 'Parâmetros customizados para substituir variáveis no template (ex: {"nome_cliente": "João", "numero_pedido": "12345"})',
721
- },
722
- ],
723
- };
724
-
725
- async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
726
- const items = this.getInputData();
727
- const returnData: INodeExecutionData[] = [];
728
-
729
- const credentials = await this.getCredentials('digitalsacApi');
730
- const baseUrl = credentials.baseUrl;
731
- const token = credentials.token;
732
-
733
- for (let i = 0; i < items.length; i++) {
734
- const operation = this.getNodeParameter('operation', i) as string;
735
- let responseData;
736
-
737
- const headers: Record<string, string> = {
738
- Authorization: `Bearer ${token}`,
739
- Accept: 'application/json',
740
- };
741
-
742
- let url = '';
743
- let method: 'GET' | 'POST' = 'GET';
744
- let body;
745
- let param = this.getNodeParameter('param', i, '') as string;
746
- let options: Record<string, any> = {};
747
-
748
- switch (operation) {
749
- case 'validateWhatsapp':
750
- url = `/typebot/whatsappnumber/${param}`;
751
- break;
752
- case 'validateCpf':
753
- url = `/typebot/validate/cpf/${param}`;
754
- break;
755
- case 'validateDate':
756
- url = '/typebot/validate/data';
757
- method = 'POST';
758
- try {
759
- body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
760
- } catch (e) {
761
- throw new Error('Formato de JSON inválido para Dados (JSON)');
762
- }
763
- headers['Content-Type'] = 'application/json';
764
- options = {
765
- method,
766
- headers,
767
- body,
768
- uri: `${baseUrl}${url}`,
769
- json: true,
770
- };
771
- break;
772
- case 'listQueues':
773
- url = '/typebot/listar_filas';
774
- break;
775
- case 'listAgents':
776
- const agentsFormat = this.getNodeParameter('agentsFormat', i, 'json') as string;
777
- url = '/typebot/listar_atendentes';
778
- if (agentsFormat === 'string') {
779
- url += '?format=string';
780
- }
781
- break;
782
- case 'transferQueue':
783
- url = '/typebot/transferir_para_fila';
784
- method = 'POST';
785
- try {
786
- body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
787
- } catch (e) {
788
- throw new Error('Formato de JSON inválido para Dados (JSON)');
789
- }
790
- headers['Content-Type'] = 'application/json';
791
- options = {
792
- method,
793
- headers,
794
- body,
795
- uri: `${baseUrl}${url}`,
796
- json: true,
797
- };
798
- break;
799
- case 'transferAgent':
800
- url = '/typebot/transferir_para_atendente';
801
- method = 'POST';
802
- try {
803
- body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
804
- } catch (e) {
805
- throw new Error('Formato de JSON inválido para Dados (JSON)');
806
- }
807
- headers['Content-Type'] = 'application/json';
808
- options = {
809
- method,
810
- headers,
811
- body,
812
- uri: `${baseUrl}${url}`,
813
- json: true,
814
- };
815
- break;
816
- case 'closeTicket':
817
- url = '/typebot/fechar_ticket';
818
- method = 'POST';
819
- try {
820
- body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
821
- } catch (e) {
822
- throw new Error('Formato de JSON inválido para Dados (JSON)');
823
- }
824
- headers['Content-Type'] = 'application/json';
825
- options = {
826
- method,
827
- headers,
828
- body,
829
- uri: `${baseUrl}${url}`,
830
- json: true,
831
- };
832
- break;
833
- case 'sendMessage':
834
- // Validar se o UUID foi fornecido
835
- if (!param || param.trim() === '') {
836
- throw new Error('UUID da conexão é obrigatório para enviar mensagem. Preencha o campo "Parâmetro" com o UUID da conexão.');
837
- }
838
-
839
- url = `/v1/api/external/${param}`;
840
- method = 'POST';
841
-
842
- // Usar campos separados em vez de JSON
843
- const messageBody = this.getNodeParameter('messageBody', i) as string;
844
- const phoneNumber = this.getNodeParameter('phoneNumber', i) as string;
845
- const externalKey = this.getNodeParameter('externalKey', i) as string;
846
-
847
- // Verificar se há dados binários (para envio de arquivo)
848
- let hasBinaryData = false;
849
- let binaryData: Buffer | undefined;
850
- let binaryFileName: string | undefined;
851
- let binaryContentType: string | undefined;
852
-
853
- if (items[i].binary) {
854
- const binary = items[i].binary as IBinaryKeyData;
855
- // Procurar por qualquer propriedade binária disponível
856
- const binaryKeys = Object.keys(binary);
857
- if (binaryKeys.length > 0) {
858
- const binaryPropertyName = binaryKeys[0]; // Usar a primeira propriedade binária encontrada
859
- hasBinaryData = true;
860
-
861
- const binaryProperty = binary[binaryPropertyName];
862
- binaryData = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
863
- binaryFileName = binaryProperty.fileName || 'file';
864
- binaryContentType = binaryProperty.mimeType;
865
- }
866
- }
867
-
868
- if (hasBinaryData && binaryData) {
869
- // Enviar como FormData (para arquivos)
870
- const formData: IDataObject = {
871
- body: messageBody,
872
- number: phoneNumber,
873
- externalKey: externalKey,
874
- media: {
875
- value: binaryData,
876
- options: {
877
- filename: binaryFileName,
878
- contentType: binaryContentType,
879
- },
880
- },
881
- };
882
-
883
- options = {
884
- method,
885
- headers: {
886
- Authorization: `Bearer ${token}`,
887
- Accept: 'application/json',
888
- },
889
- formData: formData,
890
- uri: `${baseUrl}${url}`,
891
- json: true,
892
- };
893
- } else {
894
- // Enviar como JSON (para texto)
895
- body = {
896
- body: messageBody,
897
- number: phoneNumber,
898
- externalKey: externalKey
899
- };
900
-
901
- headers['Content-Type'] = 'application/json';
902
- options = {
903
- method,
904
- headers,
905
- body,
906
- uri: `${baseUrl}${url}`,
907
- json: true,
908
- };
909
- }
910
- break;
911
- case 'listTags':
912
- url = '/typebot/listar_tags';
913
- break;
914
- case 'linkTag':
915
- url = '/typebot/vincular_tag';
916
- method = 'POST';
917
- try {
918
- body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
919
- } catch (e) {
920
- throw new Error('Formato de JSON inválido para Dados (JSON)');
921
- }
922
- headers['Content-Type'] = 'application/json';
923
- options = {
924
- method,
925
- headers,
926
- body,
927
- uri: `${baseUrl}${url}`,
928
- json: true,
929
- };
930
- break;
931
- case 'createTag':
932
- url = '/typebot/criar_tag';
933
- method = 'POST';
934
-
935
- // Usar campos separados para criar tag
936
- const tagName = this.getNodeParameter('tagName', i) as string;
937
- const tagColor = this.getNodeParameter('tagColor', i) as string;
938
-
939
- body = {
940
- tag: tagName,
941
- color: tagColor
942
- };
943
-
944
- headers['Content-Type'] = 'application/json';
945
- options = {
946
- method,
947
- headers,
948
- body,
949
- uri: `${baseUrl}${url}`,
950
- json: true,
951
- };
952
- break;
953
- case 'listKanbans':
954
- const userId = this.getNodeParameter('userId', i) as number;
955
- url = `/typebot/listar_kanbans?userId=${userId}`;
956
- break;
957
- case 'linkKanban':
958
- url = '/typebot/vincular_kanban';
959
- method = 'POST';
960
- try {
961
- body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
962
- } catch (e) {
963
- throw new Error('Formato de JSON inválido para Dados (JSON)');
964
- }
965
- headers['Content-Type'] = 'application/json';
966
- options = {
967
- method,
968
- headers,
969
- body,
970
- uri: `${baseUrl}${url}`,
971
- json: true,
972
- };
973
- break;
974
- case 'listCarteiras':
975
- url = '/typebot/listar_carteiras';
976
- break;
977
- case 'linkCarteira':
978
- url = '/typebot/vincular_carteira';
979
- method = 'POST';
980
- try {
981
- body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
982
- } catch (e) {
983
- throw new Error('Formato de JSON inválido para Dados (JSON)');
984
- }
985
- headers['Content-Type'] = 'application/json';
986
- options = {
987
- method,
988
- headers,
989
- body,
990
- uri: `${baseUrl}${url}`,
991
- json: true,
992
- };
993
- break;
994
-
995
- // Casos para Agendamento
996
- case 'listServices':
997
- const scheduleUserId = this.getNodeParameter('scheduleUserId', i) as number;
998
- if (scheduleUserId > 0) {
999
- url = `/typebot/listar_servicos?userId=${scheduleUserId}`;
1000
- } else {
1001
- url = '/typebot/listar_servicos';
1002
- }
1003
- break;
1004
-
1005
- case 'listAvailableUsers':
1006
- const serviceIdForUsers = this.getNodeParameter('serviceId', i) as number;
1007
- const dateForUsers = this.getNodeParameter('scheduleDate', i) as string;
1008
- const timeForUsers = this.getNodeParameter('scheduleTime', i) as string;
1009
-
1010
- url = `/typebot/listar_usuarios_disponiveis?serviceId=${serviceIdForUsers}&date=${dateForUsers}`;
1011
- if (timeForUsers) {
1012
- url += `&time=${timeForUsers}`;
1013
- }
1014
- break;
1015
-
1016
- case 'listAvailableSlots':
1017
- const serviceIdForSlots = this.getNodeParameter('serviceId', i) as number;
1018
- const userIdForSlots = this.getNodeParameter('scheduleAttendantId', i) as number;
1019
- const dateForSlots = this.getNodeParameter('scheduleDate', i) as string;
1020
-
1021
- url = `/typebot/listar_horarios_disponiveis?serviceId=${serviceIdForSlots}&userId=${userIdForSlots}&date=${dateForSlots}`;
1022
- break;
1023
-
1024
- case 'listSchedules':
1025
- const dateForList = this.getNodeParameter('listScheduleDate', i) as string;
1026
- const userIdForList = this.getNodeParameter('listScheduleUserId', i) as number;
1027
-
1028
- url = `/typebot/listar_agendamentos?date=${dateForList}`;
1029
- if (userIdForList && userIdForList > 0) {
1030
- url += `&userId=${userIdForList}`;
1031
- }
1032
- break;
1033
-
1034
- case 'createSchedule':
1035
- url = '/typebot/criar_agendamento';
1036
- method = 'POST';
1037
-
1038
- const serviceIdForCreate = this.getNodeParameter('serviceId', i) as number;
1039
- const userIdForCreate = this.getNodeParameter('scheduleAttendantId', i) as number;
1040
- const dateForCreate = this.getNodeParameter('scheduleDate', i) as string;
1041
- const timeForCreate = this.getNodeParameter('scheduleTime', i) as string;
1042
- const contactNameForCreate = this.getNodeParameter('contactName', i) as string;
1043
- const contactPhoneForCreate = this.getNodeParameter('contactPhone', i) as string;
1044
- const notesForCreate = this.getNodeParameter('scheduleNotes', i) as string;
1045
- const whatsappIdForCreate = this.getNodeParameter('whatsappId', i) as number;
1046
- const customMessageForCreate = this.getNodeParameter('customMessage', i) as string;
1047
- const remindersForCreate = this.getNodeParameter('reminders', i) as string;
1048
- const intervalDurationForCreate = this.getNodeParameter('intervalDuration', i) as number;
1049
- const closeTicketForCreate = this.getNodeParameter('closeTicket', i) as boolean;
1050
-
1051
- // Converter string de lembretes para array
1052
- const remindersArray = remindersForCreate ? remindersForCreate.split(',').map(r => parseInt(r.trim())) : [60, 240];
1053
-
1054
- body = {
1055
- serviceId: serviceIdForCreate,
1056
- userId: userIdForCreate,
1057
- date: dateForCreate,
1058
- time: timeForCreate,
1059
- contactName: contactNameForCreate,
1060
- contactPhone: contactPhoneForCreate,
1061
- notes: notesForCreate,
1062
- whatsappId: whatsappIdForCreate > 0 ? whatsappIdForCreate : undefined,
1063
- message: customMessageForCreate || undefined,
1064
- reminders: remindersArray,
1065
- intervalDuration: intervalDurationForCreate,
1066
- closeTicket: closeTicketForCreate
1067
- };
1068
-
1069
- headers['Content-Type'] = 'application/json';
1070
- options = {
1071
- method,
1072
- headers,
1073
- body,
1074
- uri: `${baseUrl}${url}`,
1075
- json: true,
1076
- };
1077
- break;
1078
-
1079
- case 'cancelSchedule':
1080
- url = '/typebot/cancelar_agendamento';
1081
- method = 'POST';
1082
-
1083
- const scheduleIdForCancel = this.getNodeParameter('scheduleId', i) as number;
1084
-
1085
- body = {
1086
- scheduleId: scheduleIdForCancel
1087
- };
1088
-
1089
- headers['Content-Type'] = 'application/json';
1090
- options = {
1091
- method,
1092
- headers,
1093
- body,
1094
- uri: `${baseUrl}${url}`,
1095
- json: true,
1096
- };
1097
- break;
1098
-
1099
- case 'calendarLink':
1100
- const calendarScheduleId = this.getNodeParameter('calendarScheduleId', i) as number;
1101
-
1102
- url = `/typebot/calendar-link?scheduleId=${calendarScheduleId}`;
1103
- break;
1104
-
1105
- case 'listWabaTemplates':
1106
- const wabaWhatsappIdForList = this.getNodeParameter('wabaWhatsappId', i) as number;
1107
-
1108
- url = `/typebot/listar_templates_waba/${wabaWhatsappIdForList}`;
1109
- method = 'GET';
1110
- break;
1111
-
1112
- case 'sendWabaTemplate':
1113
- url = '/typebot/enviar_template_waba';
1114
- method = 'POST';
1115
-
1116
- const wabaTemplateId = this.getNodeParameter('wabaTemplateId', i) as number;
1117
- const wabaPhoneNumber = this.getNodeParameter('wabaPhoneNumber', i) as string;
1118
- const wabaWhatsappId = this.getNodeParameter('wabaWhatsappId', i) as number;
1119
- const wabaTemplateParams = this.getNodeParameter('wabaTemplateParams', i) as string;
1120
-
1121
- let parsedTemplateParams = {};
1122
- if (wabaTemplateParams && wabaTemplateParams.trim() !== '' && wabaTemplateParams.trim() !== '{}') {
1123
- try {
1124
- parsedTemplateParams = JSON.parse(wabaTemplateParams);
1125
- } catch (error) {
1126
- throw new Error('Erro ao fazer parse do JSON dos parâmetros do template. Verifique a sintaxe.');
1127
- }
1128
- }
1129
-
1130
- body = {
1131
- templateId: wabaTemplateId,
1132
- phoneNumber: wabaPhoneNumber,
1133
- whatsappId: wabaWhatsappId,
1134
- templateParams: parsedTemplateParams
1135
- };
1136
-
1137
- headers['Content-Type'] = 'application/json';
1138
- options = {
1139
- method,
1140
- headers,
1141
- body,
1142
- uri: `${baseUrl}${url}`,
1143
- json: true,
1144
- };
1145
- break;
1146
-
1147
- case 'sendButtons':
1148
- // Validar se o UUID foi fornecido
1149
- if (!param || param.trim() === '') {
1150
- throw new Error('UUID da conexão é obrigatório para enviar botões. Preencha o campo "Parâmetro" com o UUID da conexão.');
1151
- }
1152
-
1153
- url = `/v1/api/external/${param}/send-buttons`;
1154
- method = 'POST';
1155
-
1156
- const buttonTitle = this.getNodeParameter('buttonTitle', i) as string;
1157
- const buttonBody = this.getNodeParameter('buttonBody', i) as string;
1158
- const buttonPhoneNumber = this.getNodeParameter('buttonPhoneNumber', i) as string;
1159
- const buttonExternalKey = this.getNodeParameter('externalKey', i) as string;
1160
- const buttonsData = this.getNodeParameter('buttonsData', i) as string;
1161
-
1162
- let parsedButtons;
1163
- try {
1164
- parsedButtons = JSON.parse(buttonsData);
1165
- } catch (error) {
1166
- throw new Error('Erro ao fazer parse do JSON dos botões. Verifique a sintaxe.');
1167
- }
1168
-
1169
- body = {
1170
- title: buttonTitle,
1171
- body: buttonBody,
1172
- number: buttonPhoneNumber,
1173
- extraButtons: parsedButtons,
1174
- externalKey: buttonExternalKey
1175
- };
1176
-
1177
- headers['Content-Type'] = 'application/json';
1178
- options = {
1179
- method,
1180
- headers,
1181
- body,
1182
- uri: `${baseUrl}${url}`,
1183
- json: true,
1184
- };
1185
- break;
1186
- case 'sendList':
1187
- // Validar se o UUID foi fornecido
1188
- if (!param || param.trim() === '') {
1189
- throw new Error('UUID da conexão é obrigatório para enviar lista. Preencha o campo "Parâmetro" com o UUID da conexão.');
1190
- }
1191
-
1192
- url = `/v1/api/external/${param}/send-list`;
1193
- method = 'POST';
1194
-
1195
- const listTitle = this.getNodeParameter('listTitle', i) as string;
1196
- const listText = this.getNodeParameter('listText', i) as string;
1197
- const listButtonText = this.getNodeParameter('listButtonText', i) as string;
1198
- const listFooter = this.getNodeParameter('listFooter', i) as string;
1199
- const listPhoneNumber = this.getNodeParameter('listPhoneNumber', i) as string;
1200
- const listExternalKey = this.getNodeParameter('externalKey', i) as string;
1201
- const sectionsData = this.getNodeParameter('sectionsData', i) as string;
1202
-
1203
- let parsedSections;
1204
- try {
1205
- parsedSections = JSON.parse(sectionsData);
1206
- } catch (error) {
1207
- throw new Error('Erro ao fazer parse do JSON das seções. Verifique a sintaxe.');
1208
- }
1209
-
1210
- body = {
1211
- title: listTitle,
1212
- text: listText,
1213
- buttonText: listButtonText,
1214
- footer: listFooter,
1215
- number: listPhoneNumber,
1216
- sections: parsedSections,
1217
- externalKey: listExternalKey
1218
- };
1219
-
1220
- headers['Content-Type'] = 'application/json';
1221
- options = {
1222
- method,
1223
- headers,
1224
- body,
1225
- uri: `${baseUrl}${url}`,
1226
- json: true,
1227
- };
1228
- break;
1229
- case 'sendMediaCaption':
1230
- // Validar se o UUID foi fornecido
1231
- if (!param || param.trim() === '') {
1232
- throw new Error('UUID da conexão é obrigatório para enviar mídia. Preencha o campo "Parâmetro" com o UUID da conexão.');
1233
- }
1234
-
1235
- url = `/v1/api/external/${param}/send-media-caption`;
1236
- method = 'POST';
1237
-
1238
- const mediaCaption = this.getNodeParameter('mediaCaption', i) as string;
1239
- const mediaCaptionPhoneNumber = this.getNodeParameter('mediaCaptionPhoneNumber', i) as string;
1240
- const mediaCaptionExternalKey = this.getNodeParameter('externalKey', i) as string;
1241
-
1242
- // Verificar se há dados binários
1243
- let hasBinaryDataCaption = false;
1244
- let binaryDataCaption: Buffer | undefined;
1245
- let binaryFileNameCaption: string | undefined;
1246
- let binaryContentTypeCaption: string | undefined;
1247
-
1248
- if (items[i].binary) {
1249
- const binary = items[i].binary as IBinaryKeyData;
1250
- const binaryKeys = Object.keys(binary);
1251
- if (binaryKeys.length > 0) {
1252
- const binaryPropertyName = binaryKeys[0];
1253
- hasBinaryDataCaption = true;
1254
-
1255
- const binaryProperty = binary[binaryPropertyName];
1256
- binaryDataCaption = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
1257
- binaryFileNameCaption = binaryProperty.fileName || 'file';
1258
- binaryContentTypeCaption = binaryProperty.mimeType;
1259
- }
1260
- }
1261
-
1262
- if (!hasBinaryDataCaption || !binaryDataCaption) {
1263
- throw new Error('Arquivo binário é obrigatório para enviar mídia com caption. Conecte um nó com arquivo binário antes deste.');
1264
- }
1265
-
1266
- // Enviar como FormData
1267
- const formDataCaption: IDataObject = {
1268
- caption: mediaCaption,
1269
- number: mediaCaptionPhoneNumber,
1270
- externalKey: mediaCaptionExternalKey,
1271
- media: {
1272
- value: binaryDataCaption,
1273
- options: {
1274
- filename: binaryFileNameCaption,
1275
- contentType: binaryContentTypeCaption,
1276
- },
1277
- },
1278
- };
1279
-
1280
- options = {
1281
- method,
1282
- headers: {
1283
- Authorization: `Bearer ${token}`,
1284
- Accept: 'application/json',
1285
- },
1286
- formData: formDataCaption,
1287
- uri: `${baseUrl}${url}`,
1288
- json: true,
1289
- };
1290
- break;
1291
- case 'sendBase64':
1292
- // Validar se o UUID foi fornecido
1293
- if (!param || param.trim() === '') {
1294
- throw new Error('UUID da conexão é obrigatório para enviar base64. Preencha o campo "Parâmetro" com o UUID da conexão.');
1295
- }
1296
-
1297
- url = `/v1/api/external/${param}/send-base64-media`;
1298
- method = 'POST';
1299
-
1300
- const base64Caption = this.getNodeParameter('base64Caption', i) as string;
1301
- const base64PhoneNumber = this.getNodeParameter('base64PhoneNumber', i) as string;
1302
- const base64ExternalKey = this.getNodeParameter('externalKey', i) as string;
1303
- const mediaBase64 = this.getNodeParameter('mediaBase64', i) as string;
1304
- const mimeType = this.getNodeParameter('mimeType', i) as string;
1305
- const fileName = this.getNodeParameter('fileName', i) as string;
1306
-
1307
- // Validar campos obrigatórios
1308
- if (!mediaBase64 || mediaBase64.trim() === '') {
1309
- throw new Error('Arquivo Base64 é obrigatório.');
1310
- }
1311
- if (!mimeType || mimeType.trim() === '') {
1312
- throw new Error('Tipo MIME é obrigatório.');
1313
- }
1314
- if (!fileName || fileName.trim() === '') {
1315
- throw new Error('Nome do arquivo é obrigatório.');
1316
- }
1317
-
1318
- const base64Body: IDataObject = {
1319
- number: base64PhoneNumber,
1320
- mediaBase64: mediaBase64,
1321
- mimeType: mimeType,
1322
- fileName: fileName,
1323
- externalKey: base64ExternalKey
1324
- };
1325
-
1326
- // Adicionar caption apenas se fornecido
1327
- if (base64Caption && base64Caption.trim() !== '') {
1328
- base64Body.caption = base64Caption;
1329
- }
1330
-
1331
- headers['Content-Type'] = 'application/json';
1332
- options = {
1333
- method,
1334
- headers,
1335
- body: base64Body,
1336
- uri: `${baseUrl}${url}`,
1337
- json: true,
1338
- };
1339
- break;
1340
- }
1341
-
1342
- // Se as opções não foram definidas no switch, defina-as aqui para operações GET
1343
- if (!options.method) {
1344
- options = {
1345
- method,
1346
- headers,
1347
- uri: `${baseUrl}${url}`,
1348
- json: true,
1349
- };
1350
- }
1351
-
1352
- try {
1353
- responseData = await this.helpers.request(options);
1354
- returnData.push({ json: responseData });
1355
- } catch (error: any) {
1356
- if (error.response) {
1357
- returnData.push({ json: { error: error.response.body || error.message } });
1358
- } else {
1359
- returnData.push({ json: { error: error.message } });
1360
- }
1361
- }
1362
- }
1363
-
1364
- return [returnData];
1365
- }
1366
- }