n8n-nodes-digitalsac 0.4.3 → 0.5.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.
- package/README.md +68 -0
- package/dist/nodes/Digitalsac/Digitalsac.node.js +386 -3
- package/nodes/Digitalsac/Digitalsac.node.ts +408 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,10 @@ Este pacote adiciona um nó personalizado ao n8n para interagir com a API do Dig
|
|
|
13
13
|
- Transferir para Atendente
|
|
14
14
|
- Fechar Ticket
|
|
15
15
|
- Enviar Mensagem (texto e arquivos)
|
|
16
|
+
- **Enviar Botões Interativos**
|
|
17
|
+
- **Enviar Listas**
|
|
18
|
+
- **Enviar Mídia com Caption**
|
|
19
|
+
- **Enviar Arquivo Base64**
|
|
16
20
|
- Listar Tags
|
|
17
21
|
- Vincular Tag
|
|
18
22
|
- Criar Tag
|
|
@@ -26,6 +30,7 @@ Este pacote adiciona um nó personalizado ao n8n para interagir com a API do Dig
|
|
|
26
30
|
- Listar Horários Disponíveis
|
|
27
31
|
- Criar Agendamento
|
|
28
32
|
- Cancelar Agendamento
|
|
33
|
+
- Gerar Link do Calendário (.ics)
|
|
29
34
|
|
|
30
35
|
## Instalação
|
|
31
36
|
|
|
@@ -45,6 +50,33 @@ cd ~/.n8n
|
|
|
45
50
|
npm install n8n-nodes-digitalsac
|
|
46
51
|
```
|
|
47
52
|
|
|
53
|
+
## ✨ Novas Funcionalidades (v0.5.0)
|
|
54
|
+
|
|
55
|
+
### 🔘 Enviar Botões Interativos
|
|
56
|
+
Envie mensagens com botões clicáveis:
|
|
57
|
+
- **Resposta Rápida**: Botão que responde instantaneamente
|
|
58
|
+
- **URL**: Botão que abre links
|
|
59
|
+
- **Copiar**: Botão que copia texto
|
|
60
|
+
- **Ligar**: Botão que inicia chamada
|
|
61
|
+
|
|
62
|
+
### 📋 Enviar Listas
|
|
63
|
+
Crie menus organizados com:
|
|
64
|
+
- Múltiplas seções
|
|
65
|
+
- Opções clicáveis
|
|
66
|
+
- Descrições detalhadas
|
|
67
|
+
|
|
68
|
+
### 🖼️ Enviar Mídia com Caption
|
|
69
|
+
Envie arquivos com legendas personalizadas:
|
|
70
|
+
- Upload direto de arquivos
|
|
71
|
+
- Caption obrigatório
|
|
72
|
+
- Suporte a imagens, PDFs, vídeos
|
|
73
|
+
|
|
74
|
+
### 📁 Enviar Base64
|
|
75
|
+
Envie arquivos via base64:
|
|
76
|
+
- Sem necessidade de upload
|
|
77
|
+
- Caption opcional
|
|
78
|
+
- Ideal para integração com APIs
|
|
79
|
+
|
|
48
80
|
## Autenticação
|
|
49
81
|
|
|
50
82
|
Configure as credenciais Digitalsac com a URL base e seu Bearer Token:
|
|
@@ -329,6 +361,15 @@ Onde:
|
|
|
329
361
|
}
|
|
330
362
|
```
|
|
331
363
|
|
|
364
|
+
### Gerar link de calendário para um agendamento
|
|
365
|
+
1. Adicione um nó **Digitalsac**
|
|
366
|
+
- Operação: **Gerar Link do Calendário (.ics)**
|
|
367
|
+
- ID do Agendamento: `123`
|
|
368
|
+
2. O retorno pode ser usado para:
|
|
369
|
+
- Enviar o link direto para o cliente
|
|
370
|
+
- Fazer download automático do arquivo .ics
|
|
371
|
+
- Integrar com outros sistemas de calendário
|
|
372
|
+
|
|
332
373
|
## Funcionalidades de Agendamento
|
|
333
374
|
|
|
334
375
|
### Listar Serviços
|
|
@@ -420,6 +461,33 @@ Cancela um agendamento existente.
|
|
|
420
461
|
}
|
|
421
462
|
```
|
|
422
463
|
|
|
464
|
+
### Gerar Link do Calendário (.ics)
|
|
465
|
+
Gera um link para download do arquivo .ics (calendário) de um agendamento específico.
|
|
466
|
+
1. Selecione a operação **Gerar Link do Calendário (.ics)**
|
|
467
|
+
2. Preencha:
|
|
468
|
+
- **ID do Agendamento**: ID do agendamento para gerar o link do calendário
|
|
469
|
+
|
|
470
|
+
**Retorno exemplo:**
|
|
471
|
+
```json
|
|
472
|
+
{
|
|
473
|
+
"status": 1,
|
|
474
|
+
"link": "https://seudominio.com/schedules/123/ics",
|
|
475
|
+
"scheduleId": 123,
|
|
476
|
+
"info": {
|
|
477
|
+
"cliente": "João Silva",
|
|
478
|
+
"servico": "Consulta Médica",
|
|
479
|
+
"data": "2025-01-15T14:30:00.000Z",
|
|
480
|
+
"funcionario": "Dr. Pedro Santos"
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**Uso do link:**
|
|
486
|
+
- O link gerado pode ser usado diretamente para download do arquivo .ics
|
|
487
|
+
- O arquivo .ics contém todas as informações do agendamento
|
|
488
|
+
- Pode ser importado em qualquer aplicativo de calendário (Google Calendar, Outlook, Apple Calendar, etc.)
|
|
489
|
+
- É útil para integração com sistemas externos ou envio para clientes
|
|
490
|
+
|
|
423
491
|
## Suporte
|
|
424
492
|
|
|
425
493
|
Para suporte, entre em contato com [contato@digitalsac.io](mailto:contato@digitalsac.io).
|
|
@@ -36,6 +36,10 @@ class Digitalsac {
|
|
|
36
36
|
{ name: 'Transferir para Atendente', value: 'transferAgent' },
|
|
37
37
|
{ name: 'Fechar Ticket', value: 'closeTicket' },
|
|
38
38
|
{ name: 'Enviar Mensagem', value: 'sendMessage' },
|
|
39
|
+
{ name: 'Enviar Botões', value: 'sendButtons' },
|
|
40
|
+
{ name: 'Enviar Lista', value: 'sendList' },
|
|
41
|
+
{ name: 'Enviar Mídia com Caption', value: 'sendMediaCaption' },
|
|
42
|
+
{ name: 'Enviar Base64', value: 'sendBase64' },
|
|
39
43
|
{ name: 'Listar Tags', value: 'listTags' },
|
|
40
44
|
{ name: 'Vincular Tag', value: 'linkTag' },
|
|
41
45
|
{ name: 'Criar Tag', value: 'createTag' },
|
|
@@ -61,10 +65,10 @@ class Digitalsac {
|
|
|
61
65
|
default: '',
|
|
62
66
|
displayOptions: {
|
|
63
67
|
show: {
|
|
64
|
-
operation: ['validateWhatsapp', 'validateCpf', 'sendMessage'],
|
|
68
|
+
operation: ['validateWhatsapp', 'validateCpf', 'sendMessage', 'sendButtons', 'sendList', 'sendMediaCaption', 'sendBase64'],
|
|
65
69
|
},
|
|
66
70
|
},
|
|
67
|
-
description: 'Número, CPF ou UUID da
|
|
71
|
+
description: 'Número, CPF ou UUID da conexão (conforme operação)',
|
|
68
72
|
},
|
|
69
73
|
{
|
|
70
74
|
displayName: 'User ID',
|
|
@@ -109,11 +113,219 @@ class Digitalsac {
|
|
|
109
113
|
default: 'Digitalsac123',
|
|
110
114
|
displayOptions: {
|
|
111
115
|
show: {
|
|
112
|
-
operation: ['sendMessage'],
|
|
116
|
+
operation: ['sendMessage', 'sendButtons', 'sendList', 'sendMediaCaption', 'sendBase64'],
|
|
113
117
|
},
|
|
114
118
|
},
|
|
115
119
|
description: 'Identificador único opcional para a mensagem',
|
|
116
120
|
},
|
|
121
|
+
// Campos para Enviar Botões
|
|
122
|
+
{
|
|
123
|
+
displayName: 'Título',
|
|
124
|
+
name: 'buttonTitle',
|
|
125
|
+
type: 'string',
|
|
126
|
+
default: 'Escolha uma opção',
|
|
127
|
+
displayOptions: {
|
|
128
|
+
show: {
|
|
129
|
+
operation: ['sendButtons'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
description: 'Título do conjunto de botões',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
displayName: 'Corpo da Mensagem',
|
|
136
|
+
name: 'buttonBody',
|
|
137
|
+
type: 'string',
|
|
138
|
+
default: 'Clique em uma das opções abaixo:',
|
|
139
|
+
displayOptions: {
|
|
140
|
+
show: {
|
|
141
|
+
operation: ['sendButtons'],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
description: 'Corpo da mensagem com botões',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
displayName: 'Número de Telefone',
|
|
148
|
+
name: 'buttonPhoneNumber',
|
|
149
|
+
type: 'string',
|
|
150
|
+
default: '5511999999999',
|
|
151
|
+
displayOptions: {
|
|
152
|
+
show: {
|
|
153
|
+
operation: ['sendButtons'],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
displayName: 'Botões (JSON)',
|
|
160
|
+
name: 'buttonsData',
|
|
161
|
+
type: 'json',
|
|
162
|
+
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]',
|
|
163
|
+
displayOptions: {
|
|
164
|
+
show: {
|
|
165
|
+
operation: ['sendButtons'],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
description: 'Array de botões em formato JSON',
|
|
169
|
+
},
|
|
170
|
+
// Campos para Enviar Lista
|
|
171
|
+
{
|
|
172
|
+
displayName: 'Título',
|
|
173
|
+
name: 'listTitle',
|
|
174
|
+
type: 'string',
|
|
175
|
+
default: 'Menu de Opções',
|
|
176
|
+
displayOptions: {
|
|
177
|
+
show: {
|
|
178
|
+
operation: ['sendList'],
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
description: 'Título da lista',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
displayName: 'Texto',
|
|
185
|
+
name: 'listText',
|
|
186
|
+
type: 'string',
|
|
187
|
+
default: 'Escolha uma categoria:',
|
|
188
|
+
displayOptions: {
|
|
189
|
+
show: {
|
|
190
|
+
operation: ['sendList'],
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
description: 'Texto da lista',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
displayName: 'Texto do Botão',
|
|
197
|
+
name: 'listButtonText',
|
|
198
|
+
type: 'string',
|
|
199
|
+
default: 'Ver Opções',
|
|
200
|
+
displayOptions: {
|
|
201
|
+
show: {
|
|
202
|
+
operation: ['sendList'],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
description: 'Texto do botão para abrir a lista',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
displayName: 'Rodapé',
|
|
209
|
+
name: 'listFooter',
|
|
210
|
+
type: 'string',
|
|
211
|
+
default: 'Powered by DigitalSac',
|
|
212
|
+
displayOptions: {
|
|
213
|
+
show: {
|
|
214
|
+
operation: ['sendList'],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
description: 'Rodapé da lista',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
displayName: 'Número de Telefone',
|
|
221
|
+
name: 'listPhoneNumber',
|
|
222
|
+
type: 'string',
|
|
223
|
+
default: '5511999999999',
|
|
224
|
+
displayOptions: {
|
|
225
|
+
show: {
|
|
226
|
+
operation: ['sendList'],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
displayName: 'Seções (JSON)',
|
|
233
|
+
name: 'sectionsData',
|
|
234
|
+
type: 'json',
|
|
235
|
+
default: '[\n {\n "title": "Produtos",\n "lines": [\n {\n "title": "Produto A",\n "description": "Descrição do produto A",\n "rowId": "prod_a"\n }\n ]\n }\n]',
|
|
236
|
+
displayOptions: {
|
|
237
|
+
show: {
|
|
238
|
+
operation: ['sendList'],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
description: 'Array de seções da lista em formato JSON',
|
|
242
|
+
},
|
|
243
|
+
// Campos para Enviar Mídia com Caption
|
|
244
|
+
{
|
|
245
|
+
displayName: 'Caption',
|
|
246
|
+
name: 'mediaCaption',
|
|
247
|
+
type: 'string',
|
|
248
|
+
default: 'Arquivo enviado via API',
|
|
249
|
+
displayOptions: {
|
|
250
|
+
show: {
|
|
251
|
+
operation: ['sendMediaCaption'],
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
description: 'Legenda do arquivo',
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
displayName: 'Número de Telefone',
|
|
258
|
+
name: 'mediaCaptionPhoneNumber',
|
|
259
|
+
type: 'string',
|
|
260
|
+
default: '5511999999999',
|
|
261
|
+
displayOptions: {
|
|
262
|
+
show: {
|
|
263
|
+
operation: ['sendMediaCaption'],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
267
|
+
},
|
|
268
|
+
// Campos para Enviar Base64
|
|
269
|
+
{
|
|
270
|
+
displayName: 'Caption (Opcional)',
|
|
271
|
+
name: 'base64Caption',
|
|
272
|
+
type: 'string',
|
|
273
|
+
default: '',
|
|
274
|
+
displayOptions: {
|
|
275
|
+
show: {
|
|
276
|
+
operation: ['sendBase64'],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
description: 'Legenda opcional do arquivo',
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
displayName: 'Número de Telefone',
|
|
283
|
+
name: 'base64PhoneNumber',
|
|
284
|
+
type: 'string',
|
|
285
|
+
default: '5511999999999',
|
|
286
|
+
displayOptions: {
|
|
287
|
+
show: {
|
|
288
|
+
operation: ['sendBase64'],
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
displayName: 'Arquivo Base64',
|
|
295
|
+
name: 'mediaBase64',
|
|
296
|
+
type: 'string',
|
|
297
|
+
default: '',
|
|
298
|
+
displayOptions: {
|
|
299
|
+
show: {
|
|
300
|
+
operation: ['sendBase64'],
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
description: 'Arquivo codificado em base64',
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
displayName: 'Tipo MIME',
|
|
307
|
+
name: 'mimeType',
|
|
308
|
+
type: 'string',
|
|
309
|
+
default: 'image/png',
|
|
310
|
+
displayOptions: {
|
|
311
|
+
show: {
|
|
312
|
+
operation: ['sendBase64'],
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
description: 'Tipo MIME do arquivo (ex: image/png, application/pdf)',
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
displayName: 'Nome do Arquivo',
|
|
319
|
+
name: 'fileName',
|
|
320
|
+
type: 'string',
|
|
321
|
+
default: 'arquivo.png',
|
|
322
|
+
displayOptions: {
|
|
323
|
+
show: {
|
|
324
|
+
operation: ['sendBase64'],
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
description: 'Nome do arquivo com extensão',
|
|
328
|
+
},
|
|
117
329
|
{
|
|
118
330
|
displayName: 'Nome da Tag',
|
|
119
331
|
name: 'tagName',
|
|
@@ -785,6 +997,177 @@ class Digitalsac {
|
|
|
785
997
|
const calendarScheduleId = this.getNodeParameter('calendarScheduleId', i);
|
|
786
998
|
url = `/typebot/calendar-link?scheduleId=${calendarScheduleId}`;
|
|
787
999
|
break;
|
|
1000
|
+
case 'sendButtons':
|
|
1001
|
+
// Validar se o UUID foi fornecido
|
|
1002
|
+
if (!param || param.trim() === '') {
|
|
1003
|
+
throw new Error('UUID da conexão é obrigatório para enviar botões. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1004
|
+
}
|
|
1005
|
+
url = `/v1/api/external/${param}/send-buttons`;
|
|
1006
|
+
method = 'POST';
|
|
1007
|
+
const buttonTitle = this.getNodeParameter('buttonTitle', i);
|
|
1008
|
+
const buttonBody = this.getNodeParameter('buttonBody', i);
|
|
1009
|
+
const buttonPhoneNumber = this.getNodeParameter('buttonPhoneNumber', i);
|
|
1010
|
+
const buttonExternalKey = this.getNodeParameter('externalKey', i);
|
|
1011
|
+
const buttonsData = this.getNodeParameter('buttonsData', i);
|
|
1012
|
+
let parsedButtons;
|
|
1013
|
+
try {
|
|
1014
|
+
parsedButtons = JSON.parse(buttonsData);
|
|
1015
|
+
}
|
|
1016
|
+
catch (error) {
|
|
1017
|
+
throw new Error('Erro ao fazer parse do JSON dos botões. Verifique a sintaxe.');
|
|
1018
|
+
}
|
|
1019
|
+
body = {
|
|
1020
|
+
title: buttonTitle,
|
|
1021
|
+
body: buttonBody,
|
|
1022
|
+
number: buttonPhoneNumber,
|
|
1023
|
+
extraButtons: parsedButtons,
|
|
1024
|
+
externalKey: buttonExternalKey
|
|
1025
|
+
};
|
|
1026
|
+
headers['Content-Type'] = 'application/json';
|
|
1027
|
+
options = {
|
|
1028
|
+
method,
|
|
1029
|
+
headers,
|
|
1030
|
+
body,
|
|
1031
|
+
uri: `${baseUrl}${url}`,
|
|
1032
|
+
json: true,
|
|
1033
|
+
};
|
|
1034
|
+
break;
|
|
1035
|
+
case 'sendList':
|
|
1036
|
+
// Validar se o UUID foi fornecido
|
|
1037
|
+
if (!param || param.trim() === '') {
|
|
1038
|
+
throw new Error('UUID da conexão é obrigatório para enviar lista. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1039
|
+
}
|
|
1040
|
+
url = `/v1/api/external/${param}/send-list`;
|
|
1041
|
+
method = 'POST';
|
|
1042
|
+
const listTitle = this.getNodeParameter('listTitle', i);
|
|
1043
|
+
const listText = this.getNodeParameter('listText', i);
|
|
1044
|
+
const listButtonText = this.getNodeParameter('listButtonText', i);
|
|
1045
|
+
const listFooter = this.getNodeParameter('listFooter', i);
|
|
1046
|
+
const listPhoneNumber = this.getNodeParameter('listPhoneNumber', i);
|
|
1047
|
+
const listExternalKey = this.getNodeParameter('externalKey', i);
|
|
1048
|
+
const sectionsData = this.getNodeParameter('sectionsData', i);
|
|
1049
|
+
let parsedSections;
|
|
1050
|
+
try {
|
|
1051
|
+
parsedSections = JSON.parse(sectionsData);
|
|
1052
|
+
}
|
|
1053
|
+
catch (error) {
|
|
1054
|
+
throw new Error('Erro ao fazer parse do JSON das seções. Verifique a sintaxe.');
|
|
1055
|
+
}
|
|
1056
|
+
body = {
|
|
1057
|
+
title: listTitle,
|
|
1058
|
+
text: listText,
|
|
1059
|
+
buttonText: listButtonText,
|
|
1060
|
+
footer: listFooter,
|
|
1061
|
+
number: listPhoneNumber,
|
|
1062
|
+
sections: parsedSections,
|
|
1063
|
+
externalKey: listExternalKey
|
|
1064
|
+
};
|
|
1065
|
+
headers['Content-Type'] = 'application/json';
|
|
1066
|
+
options = {
|
|
1067
|
+
method,
|
|
1068
|
+
headers,
|
|
1069
|
+
body,
|
|
1070
|
+
uri: `${baseUrl}${url}`,
|
|
1071
|
+
json: true,
|
|
1072
|
+
};
|
|
1073
|
+
break;
|
|
1074
|
+
case 'sendMediaCaption':
|
|
1075
|
+
// Validar se o UUID foi fornecido
|
|
1076
|
+
if (!param || param.trim() === '') {
|
|
1077
|
+
throw new Error('UUID da conexão é obrigatório para enviar mídia. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1078
|
+
}
|
|
1079
|
+
url = `/v1/api/external/${param}/send-media-caption`;
|
|
1080
|
+
method = 'POST';
|
|
1081
|
+
const mediaCaption = this.getNodeParameter('mediaCaption', i);
|
|
1082
|
+
const mediaCaptionPhoneNumber = this.getNodeParameter('mediaCaptionPhoneNumber', i);
|
|
1083
|
+
const mediaCaptionExternalKey = this.getNodeParameter('externalKey', i);
|
|
1084
|
+
// Verificar se há dados binários
|
|
1085
|
+
let hasBinaryDataCaption = false;
|
|
1086
|
+
let binaryDataCaption;
|
|
1087
|
+
let binaryFileNameCaption;
|
|
1088
|
+
let binaryContentTypeCaption;
|
|
1089
|
+
if (items[i].binary) {
|
|
1090
|
+
const binary = items[i].binary;
|
|
1091
|
+
const binaryKeys = Object.keys(binary);
|
|
1092
|
+
if (binaryKeys.length > 0) {
|
|
1093
|
+
const binaryPropertyName = binaryKeys[0];
|
|
1094
|
+
hasBinaryDataCaption = true;
|
|
1095
|
+
const binaryProperty = binary[binaryPropertyName];
|
|
1096
|
+
binaryDataCaption = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
1097
|
+
binaryFileNameCaption = binaryProperty.fileName || 'file';
|
|
1098
|
+
binaryContentTypeCaption = binaryProperty.mimeType;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
if (!hasBinaryDataCaption || !binaryDataCaption) {
|
|
1102
|
+
throw new Error('Arquivo binário é obrigatório para enviar mídia com caption. Conecte um nó com arquivo binário antes deste.');
|
|
1103
|
+
}
|
|
1104
|
+
// Enviar como FormData
|
|
1105
|
+
const formDataCaption = {
|
|
1106
|
+
caption: mediaCaption,
|
|
1107
|
+
number: mediaCaptionPhoneNumber,
|
|
1108
|
+
externalKey: mediaCaptionExternalKey,
|
|
1109
|
+
media: {
|
|
1110
|
+
value: binaryDataCaption,
|
|
1111
|
+
options: {
|
|
1112
|
+
filename: binaryFileNameCaption,
|
|
1113
|
+
contentType: binaryContentTypeCaption,
|
|
1114
|
+
},
|
|
1115
|
+
},
|
|
1116
|
+
};
|
|
1117
|
+
options = {
|
|
1118
|
+
method,
|
|
1119
|
+
headers: {
|
|
1120
|
+
Authorization: `Bearer ${token}`,
|
|
1121
|
+
Accept: 'application/json',
|
|
1122
|
+
},
|
|
1123
|
+
formData: formDataCaption,
|
|
1124
|
+
uri: `${baseUrl}${url}`,
|
|
1125
|
+
json: true,
|
|
1126
|
+
};
|
|
1127
|
+
break;
|
|
1128
|
+
case 'sendBase64':
|
|
1129
|
+
// Validar se o UUID foi fornecido
|
|
1130
|
+
if (!param || param.trim() === '') {
|
|
1131
|
+
throw new Error('UUID da conexão é obrigatório para enviar base64. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1132
|
+
}
|
|
1133
|
+
url = `/v1/api/external/${param}/send-base64-media`;
|
|
1134
|
+
method = 'POST';
|
|
1135
|
+
const base64Caption = this.getNodeParameter('base64Caption', i);
|
|
1136
|
+
const base64PhoneNumber = this.getNodeParameter('base64PhoneNumber', i);
|
|
1137
|
+
const base64ExternalKey = this.getNodeParameter('externalKey', i);
|
|
1138
|
+
const mediaBase64 = this.getNodeParameter('mediaBase64', i);
|
|
1139
|
+
const mimeType = this.getNodeParameter('mimeType', i);
|
|
1140
|
+
const fileName = this.getNodeParameter('fileName', i);
|
|
1141
|
+
// Validar campos obrigatórios
|
|
1142
|
+
if (!mediaBase64 || mediaBase64.trim() === '') {
|
|
1143
|
+
throw new Error('Arquivo Base64 é obrigatório.');
|
|
1144
|
+
}
|
|
1145
|
+
if (!mimeType || mimeType.trim() === '') {
|
|
1146
|
+
throw new Error('Tipo MIME é obrigatório.');
|
|
1147
|
+
}
|
|
1148
|
+
if (!fileName || fileName.trim() === '') {
|
|
1149
|
+
throw new Error('Nome do arquivo é obrigatório.');
|
|
1150
|
+
}
|
|
1151
|
+
const base64Body = {
|
|
1152
|
+
number: base64PhoneNumber,
|
|
1153
|
+
mediaBase64: mediaBase64,
|
|
1154
|
+
mimeType: mimeType,
|
|
1155
|
+
fileName: fileName,
|
|
1156
|
+
externalKey: base64ExternalKey
|
|
1157
|
+
};
|
|
1158
|
+
// Adicionar caption apenas se fornecido
|
|
1159
|
+
if (base64Caption && base64Caption.trim() !== '') {
|
|
1160
|
+
base64Body.caption = base64Caption;
|
|
1161
|
+
}
|
|
1162
|
+
headers['Content-Type'] = 'application/json';
|
|
1163
|
+
options = {
|
|
1164
|
+
method,
|
|
1165
|
+
headers,
|
|
1166
|
+
body: base64Body,
|
|
1167
|
+
uri: `${baseUrl}${url}`,
|
|
1168
|
+
json: true,
|
|
1169
|
+
};
|
|
1170
|
+
break;
|
|
788
1171
|
}
|
|
789
1172
|
// Se as opções não foram definidas no switch, defina-as aqui para operações GET
|
|
790
1173
|
if (!options.method) {
|
|
@@ -43,6 +43,10 @@ export class Digitalsac implements INodeType {
|
|
|
43
43
|
{ name: 'Transferir para Atendente', value: 'transferAgent' },
|
|
44
44
|
{ name: 'Fechar Ticket', value: 'closeTicket' },
|
|
45
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' },
|
|
46
50
|
{ name: 'Listar Tags', value: 'listTags' },
|
|
47
51
|
{ name: 'Vincular Tag', value: 'linkTag' },
|
|
48
52
|
{ name: 'Criar Tag', value: 'createTag' },
|
|
@@ -68,10 +72,10 @@ export class Digitalsac implements INodeType {
|
|
|
68
72
|
default: '',
|
|
69
73
|
displayOptions: {
|
|
70
74
|
show: {
|
|
71
|
-
operation: ['validateWhatsapp', 'validateCpf', 'sendMessage'],
|
|
75
|
+
operation: ['validateWhatsapp', 'validateCpf', 'sendMessage', 'sendButtons', 'sendList', 'sendMediaCaption', 'sendBase64'],
|
|
72
76
|
},
|
|
73
77
|
},
|
|
74
|
-
description: 'Número, CPF ou UUID da
|
|
78
|
+
description: 'Número, CPF ou UUID da conexão (conforme operação)',
|
|
75
79
|
},
|
|
76
80
|
{
|
|
77
81
|
displayName: 'User ID',
|
|
@@ -116,11 +120,219 @@ export class Digitalsac implements INodeType {
|
|
|
116
120
|
default: 'Digitalsac123',
|
|
117
121
|
displayOptions: {
|
|
118
122
|
show: {
|
|
119
|
-
operation: ['sendMessage'],
|
|
123
|
+
operation: ['sendMessage', 'sendButtons', 'sendList', 'sendMediaCaption', 'sendBase64'],
|
|
120
124
|
},
|
|
121
125
|
},
|
|
122
126
|
description: 'Identificador único opcional para a mensagem',
|
|
123
127
|
},
|
|
128
|
+
// Campos para Enviar Botões
|
|
129
|
+
{
|
|
130
|
+
displayName: 'Título',
|
|
131
|
+
name: 'buttonTitle',
|
|
132
|
+
type: 'string',
|
|
133
|
+
default: 'Escolha uma opção',
|
|
134
|
+
displayOptions: {
|
|
135
|
+
show: {
|
|
136
|
+
operation: ['sendButtons'],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
description: 'Título do conjunto de botões',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
displayName: 'Corpo da Mensagem',
|
|
143
|
+
name: 'buttonBody',
|
|
144
|
+
type: 'string',
|
|
145
|
+
default: 'Clique em uma das opções abaixo:',
|
|
146
|
+
displayOptions: {
|
|
147
|
+
show: {
|
|
148
|
+
operation: ['sendButtons'],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
description: 'Corpo da mensagem com botões',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
displayName: 'Número de Telefone',
|
|
155
|
+
name: 'buttonPhoneNumber',
|
|
156
|
+
type: 'string',
|
|
157
|
+
default: '5511999999999',
|
|
158
|
+
displayOptions: {
|
|
159
|
+
show: {
|
|
160
|
+
operation: ['sendButtons'],
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
displayName: 'Botões (JSON)',
|
|
167
|
+
name: 'buttonsData',
|
|
168
|
+
type: 'json',
|
|
169
|
+
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]',
|
|
170
|
+
displayOptions: {
|
|
171
|
+
show: {
|
|
172
|
+
operation: ['sendButtons'],
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
description: 'Array de botões em formato JSON',
|
|
176
|
+
},
|
|
177
|
+
// Campos para Enviar Lista
|
|
178
|
+
{
|
|
179
|
+
displayName: 'Título',
|
|
180
|
+
name: 'listTitle',
|
|
181
|
+
type: 'string',
|
|
182
|
+
default: 'Menu de Opções',
|
|
183
|
+
displayOptions: {
|
|
184
|
+
show: {
|
|
185
|
+
operation: ['sendList'],
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
description: 'Título da lista',
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
displayName: 'Texto',
|
|
192
|
+
name: 'listText',
|
|
193
|
+
type: 'string',
|
|
194
|
+
default: 'Escolha uma categoria:',
|
|
195
|
+
displayOptions: {
|
|
196
|
+
show: {
|
|
197
|
+
operation: ['sendList'],
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
description: 'Texto da lista',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
displayName: 'Texto do Botão',
|
|
204
|
+
name: 'listButtonText',
|
|
205
|
+
type: 'string',
|
|
206
|
+
default: 'Ver Opções',
|
|
207
|
+
displayOptions: {
|
|
208
|
+
show: {
|
|
209
|
+
operation: ['sendList'],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
description: 'Texto do botão para abrir a lista',
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
displayName: 'Rodapé',
|
|
216
|
+
name: 'listFooter',
|
|
217
|
+
type: 'string',
|
|
218
|
+
default: 'Powered by DigitalSac',
|
|
219
|
+
displayOptions: {
|
|
220
|
+
show: {
|
|
221
|
+
operation: ['sendList'],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
description: 'Rodapé da lista',
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
displayName: 'Número de Telefone',
|
|
228
|
+
name: 'listPhoneNumber',
|
|
229
|
+
type: 'string',
|
|
230
|
+
default: '5511999999999',
|
|
231
|
+
displayOptions: {
|
|
232
|
+
show: {
|
|
233
|
+
operation: ['sendList'],
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
displayName: 'Seções (JSON)',
|
|
240
|
+
name: 'sectionsData',
|
|
241
|
+
type: 'json',
|
|
242
|
+
default: '[\n {\n "title": "Produtos",\n "lines": [\n {\n "title": "Produto A",\n "description": "Descrição do produto A",\n "rowId": "prod_a"\n }\n ]\n }\n]',
|
|
243
|
+
displayOptions: {
|
|
244
|
+
show: {
|
|
245
|
+
operation: ['sendList'],
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
description: 'Array de seções da lista em formato JSON',
|
|
249
|
+
},
|
|
250
|
+
// Campos para Enviar Mídia com Caption
|
|
251
|
+
{
|
|
252
|
+
displayName: 'Caption',
|
|
253
|
+
name: 'mediaCaption',
|
|
254
|
+
type: 'string',
|
|
255
|
+
default: 'Arquivo enviado via API',
|
|
256
|
+
displayOptions: {
|
|
257
|
+
show: {
|
|
258
|
+
operation: ['sendMediaCaption'],
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
description: 'Legenda do arquivo',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
displayName: 'Número de Telefone',
|
|
265
|
+
name: 'mediaCaptionPhoneNumber',
|
|
266
|
+
type: 'string',
|
|
267
|
+
default: '5511999999999',
|
|
268
|
+
displayOptions: {
|
|
269
|
+
show: {
|
|
270
|
+
operation: ['sendMediaCaption'],
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
274
|
+
},
|
|
275
|
+
// Campos para Enviar Base64
|
|
276
|
+
{
|
|
277
|
+
displayName: 'Caption (Opcional)',
|
|
278
|
+
name: 'base64Caption',
|
|
279
|
+
type: 'string',
|
|
280
|
+
default: '',
|
|
281
|
+
displayOptions: {
|
|
282
|
+
show: {
|
|
283
|
+
operation: ['sendBase64'],
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
description: 'Legenda opcional do arquivo',
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
displayName: 'Número de Telefone',
|
|
290
|
+
name: 'base64PhoneNumber',
|
|
291
|
+
type: 'string',
|
|
292
|
+
default: '5511999999999',
|
|
293
|
+
displayOptions: {
|
|
294
|
+
show: {
|
|
295
|
+
operation: ['sendBase64'],
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
description: 'Número de telefone no formato DDI+DDD+Número',
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
displayName: 'Arquivo Base64',
|
|
302
|
+
name: 'mediaBase64',
|
|
303
|
+
type: 'string',
|
|
304
|
+
default: '',
|
|
305
|
+
displayOptions: {
|
|
306
|
+
show: {
|
|
307
|
+
operation: ['sendBase64'],
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
description: 'Arquivo codificado em base64',
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
displayName: 'Tipo MIME',
|
|
314
|
+
name: 'mimeType',
|
|
315
|
+
type: 'string',
|
|
316
|
+
default: 'image/png',
|
|
317
|
+
displayOptions: {
|
|
318
|
+
show: {
|
|
319
|
+
operation: ['sendBase64'],
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
description: 'Tipo MIME do arquivo (ex: image/png, application/pdf)',
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
displayName: 'Nome do Arquivo',
|
|
326
|
+
name: 'fileName',
|
|
327
|
+
type: 'string',
|
|
328
|
+
default: 'arquivo.png',
|
|
329
|
+
displayOptions: {
|
|
330
|
+
show: {
|
|
331
|
+
operation: ['sendBase64'],
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
description: 'Nome do arquivo com extensão',
|
|
335
|
+
},
|
|
124
336
|
{
|
|
125
337
|
displayName: 'Nome da Tag',
|
|
126
338
|
name: 'tagName',
|
|
@@ -817,6 +1029,199 @@ export class Digitalsac implements INodeType {
|
|
|
817
1029
|
|
|
818
1030
|
url = `/typebot/calendar-link?scheduleId=${calendarScheduleId}`;
|
|
819
1031
|
break;
|
|
1032
|
+
case 'sendButtons':
|
|
1033
|
+
// Validar se o UUID foi fornecido
|
|
1034
|
+
if (!param || param.trim() === '') {
|
|
1035
|
+
throw new Error('UUID da conexão é obrigatório para enviar botões. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
url = `/v1/api/external/${param}/send-buttons`;
|
|
1039
|
+
method = 'POST';
|
|
1040
|
+
|
|
1041
|
+
const buttonTitle = this.getNodeParameter('buttonTitle', i) as string;
|
|
1042
|
+
const buttonBody = this.getNodeParameter('buttonBody', i) as string;
|
|
1043
|
+
const buttonPhoneNumber = this.getNodeParameter('buttonPhoneNumber', i) as string;
|
|
1044
|
+
const buttonExternalKey = this.getNodeParameter('externalKey', i) as string;
|
|
1045
|
+
const buttonsData = this.getNodeParameter('buttonsData', i) as string;
|
|
1046
|
+
|
|
1047
|
+
let parsedButtons;
|
|
1048
|
+
try {
|
|
1049
|
+
parsedButtons = JSON.parse(buttonsData);
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
throw new Error('Erro ao fazer parse do JSON dos botões. Verifique a sintaxe.');
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
body = {
|
|
1055
|
+
title: buttonTitle,
|
|
1056
|
+
body: buttonBody,
|
|
1057
|
+
number: buttonPhoneNumber,
|
|
1058
|
+
extraButtons: parsedButtons,
|
|
1059
|
+
externalKey: buttonExternalKey
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
headers['Content-Type'] = 'application/json';
|
|
1063
|
+
options = {
|
|
1064
|
+
method,
|
|
1065
|
+
headers,
|
|
1066
|
+
body,
|
|
1067
|
+
uri: `${baseUrl}${url}`,
|
|
1068
|
+
json: true,
|
|
1069
|
+
};
|
|
1070
|
+
break;
|
|
1071
|
+
case 'sendList':
|
|
1072
|
+
// Validar se o UUID foi fornecido
|
|
1073
|
+
if (!param || param.trim() === '') {
|
|
1074
|
+
throw new Error('UUID da conexão é obrigatório para enviar lista. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
url = `/v1/api/external/${param}/send-list`;
|
|
1078
|
+
method = 'POST';
|
|
1079
|
+
|
|
1080
|
+
const listTitle = this.getNodeParameter('listTitle', i) as string;
|
|
1081
|
+
const listText = this.getNodeParameter('listText', i) as string;
|
|
1082
|
+
const listButtonText = this.getNodeParameter('listButtonText', i) as string;
|
|
1083
|
+
const listFooter = this.getNodeParameter('listFooter', i) as string;
|
|
1084
|
+
const listPhoneNumber = this.getNodeParameter('listPhoneNumber', i) as string;
|
|
1085
|
+
const listExternalKey = this.getNodeParameter('externalKey', i) as string;
|
|
1086
|
+
const sectionsData = this.getNodeParameter('sectionsData', i) as string;
|
|
1087
|
+
|
|
1088
|
+
let parsedSections;
|
|
1089
|
+
try {
|
|
1090
|
+
parsedSections = JSON.parse(sectionsData);
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
throw new Error('Erro ao fazer parse do JSON das seções. Verifique a sintaxe.');
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
body = {
|
|
1096
|
+
title: listTitle,
|
|
1097
|
+
text: listText,
|
|
1098
|
+
buttonText: listButtonText,
|
|
1099
|
+
footer: listFooter,
|
|
1100
|
+
number: listPhoneNumber,
|
|
1101
|
+
sections: parsedSections,
|
|
1102
|
+
externalKey: listExternalKey
|
|
1103
|
+
};
|
|
1104
|
+
|
|
1105
|
+
headers['Content-Type'] = 'application/json';
|
|
1106
|
+
options = {
|
|
1107
|
+
method,
|
|
1108
|
+
headers,
|
|
1109
|
+
body,
|
|
1110
|
+
uri: `${baseUrl}${url}`,
|
|
1111
|
+
json: true,
|
|
1112
|
+
};
|
|
1113
|
+
break;
|
|
1114
|
+
case 'sendMediaCaption':
|
|
1115
|
+
// Validar se o UUID foi fornecido
|
|
1116
|
+
if (!param || param.trim() === '') {
|
|
1117
|
+
throw new Error('UUID da conexão é obrigatório para enviar mídia. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
url = `/v1/api/external/${param}/send-media-caption`;
|
|
1121
|
+
method = 'POST';
|
|
1122
|
+
|
|
1123
|
+
const mediaCaption = this.getNodeParameter('mediaCaption', i) as string;
|
|
1124
|
+
const mediaCaptionPhoneNumber = this.getNodeParameter('mediaCaptionPhoneNumber', i) as string;
|
|
1125
|
+
const mediaCaptionExternalKey = this.getNodeParameter('externalKey', i) as string;
|
|
1126
|
+
|
|
1127
|
+
// Verificar se há dados binários
|
|
1128
|
+
let hasBinaryDataCaption = false;
|
|
1129
|
+
let binaryDataCaption: Buffer | undefined;
|
|
1130
|
+
let binaryFileNameCaption: string | undefined;
|
|
1131
|
+
let binaryContentTypeCaption: string | undefined;
|
|
1132
|
+
|
|
1133
|
+
if (items[i].binary) {
|
|
1134
|
+
const binary = items[i].binary as IBinaryKeyData;
|
|
1135
|
+
const binaryKeys = Object.keys(binary);
|
|
1136
|
+
if (binaryKeys.length > 0) {
|
|
1137
|
+
const binaryPropertyName = binaryKeys[0];
|
|
1138
|
+
hasBinaryDataCaption = true;
|
|
1139
|
+
|
|
1140
|
+
const binaryProperty = binary[binaryPropertyName];
|
|
1141
|
+
binaryDataCaption = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
1142
|
+
binaryFileNameCaption = binaryProperty.fileName || 'file';
|
|
1143
|
+
binaryContentTypeCaption = binaryProperty.mimeType;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
if (!hasBinaryDataCaption || !binaryDataCaption) {
|
|
1148
|
+
throw new Error('Arquivo binário é obrigatório para enviar mídia com caption. Conecte um nó com arquivo binário antes deste.');
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// Enviar como FormData
|
|
1152
|
+
const formDataCaption: IDataObject = {
|
|
1153
|
+
caption: mediaCaption,
|
|
1154
|
+
number: mediaCaptionPhoneNumber,
|
|
1155
|
+
externalKey: mediaCaptionExternalKey,
|
|
1156
|
+
media: {
|
|
1157
|
+
value: binaryDataCaption,
|
|
1158
|
+
options: {
|
|
1159
|
+
filename: binaryFileNameCaption,
|
|
1160
|
+
contentType: binaryContentTypeCaption,
|
|
1161
|
+
},
|
|
1162
|
+
},
|
|
1163
|
+
};
|
|
1164
|
+
|
|
1165
|
+
options = {
|
|
1166
|
+
method,
|
|
1167
|
+
headers: {
|
|
1168
|
+
Authorization: `Bearer ${token}`,
|
|
1169
|
+
Accept: 'application/json',
|
|
1170
|
+
},
|
|
1171
|
+
formData: formDataCaption,
|
|
1172
|
+
uri: `${baseUrl}${url}`,
|
|
1173
|
+
json: true,
|
|
1174
|
+
};
|
|
1175
|
+
break;
|
|
1176
|
+
case 'sendBase64':
|
|
1177
|
+
// Validar se o UUID foi fornecido
|
|
1178
|
+
if (!param || param.trim() === '') {
|
|
1179
|
+
throw new Error('UUID da conexão é obrigatório para enviar base64. Preencha o campo "Parâmetro" com o UUID da conexão.');
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
url = `/v1/api/external/${param}/send-base64-media`;
|
|
1183
|
+
method = 'POST';
|
|
1184
|
+
|
|
1185
|
+
const base64Caption = this.getNodeParameter('base64Caption', i) as string;
|
|
1186
|
+
const base64PhoneNumber = this.getNodeParameter('base64PhoneNumber', i) as string;
|
|
1187
|
+
const base64ExternalKey = this.getNodeParameter('externalKey', i) as string;
|
|
1188
|
+
const mediaBase64 = this.getNodeParameter('mediaBase64', i) as string;
|
|
1189
|
+
const mimeType = this.getNodeParameter('mimeType', i) as string;
|
|
1190
|
+
const fileName = this.getNodeParameter('fileName', i) as string;
|
|
1191
|
+
|
|
1192
|
+
// Validar campos obrigatórios
|
|
1193
|
+
if (!mediaBase64 || mediaBase64.trim() === '') {
|
|
1194
|
+
throw new Error('Arquivo Base64 é obrigatório.');
|
|
1195
|
+
}
|
|
1196
|
+
if (!mimeType || mimeType.trim() === '') {
|
|
1197
|
+
throw new Error('Tipo MIME é obrigatório.');
|
|
1198
|
+
}
|
|
1199
|
+
if (!fileName || fileName.trim() === '') {
|
|
1200
|
+
throw new Error('Nome do arquivo é obrigatório.');
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
const base64Body: IDataObject = {
|
|
1204
|
+
number: base64PhoneNumber,
|
|
1205
|
+
mediaBase64: mediaBase64,
|
|
1206
|
+
mimeType: mimeType,
|
|
1207
|
+
fileName: fileName,
|
|
1208
|
+
externalKey: base64ExternalKey
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1211
|
+
// Adicionar caption apenas se fornecido
|
|
1212
|
+
if (base64Caption && base64Caption.trim() !== '') {
|
|
1213
|
+
base64Body.caption = base64Caption;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
headers['Content-Type'] = 'application/json';
|
|
1217
|
+
options = {
|
|
1218
|
+
method,
|
|
1219
|
+
headers,
|
|
1220
|
+
body: base64Body,
|
|
1221
|
+
uri: `${baseUrl}${url}`,
|
|
1222
|
+
json: true,
|
|
1223
|
+
};
|
|
1224
|
+
break;
|
|
820
1225
|
}
|
|
821
1226
|
|
|
822
1227
|
// Se as opções não foram definidas no switch, defina-as aqui para operações GET
|