n8n-nodes-digitalsac 0.4.4 → 0.5.1
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 +244 -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
|
|
@@ -46,6 +50,33 @@ cd ~/.n8n
|
|
|
46
50
|
npm install n8n-nodes-digitalsac
|
|
47
51
|
```
|
|
48
52
|
|
|
53
|
+
## ✨ Novas Funcionalidades (v0.5.1)
|
|
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
|
+
|
|
49
80
|
## Autenticação
|
|
50
81
|
|
|
51
82
|
Configure as credenciais Digitalsac com a URL base e seu Bearer Token:
|
|
@@ -134,6 +165,151 @@ Onde:
|
|
|
134
165
|
- **Sem arquivo**: Envia como JSON (texto)
|
|
135
166
|
- **Com arquivo**: Envia como FormData (arquivo + texto)
|
|
136
167
|
|
|
168
|
+
### 🔘 Enviar Botões Interativos
|
|
169
|
+
1. Selecione a operação **Enviar Botões**
|
|
170
|
+
2. No campo **Parâmetro**, insira o UUID da conexão
|
|
171
|
+
3. Preencha os campos básicos:
|
|
172
|
+
- **Título**: "Escolha uma opção"
|
|
173
|
+
- **Corpo da Mensagem**: "Clique em uma das opções abaixo:"
|
|
174
|
+
- **Número de Telefone**: "5511999999999"
|
|
175
|
+
- **Chave Externa**: "btn_001"
|
|
176
|
+
4. No campo **Botões (JSON)**, configure os botões:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
[
|
|
180
|
+
{
|
|
181
|
+
"tipo": {"label": "Resposta Rápida", "value": "quick_reply"},
|
|
182
|
+
"display_text": "✅ Sim",
|
|
183
|
+
"conteudo": "sim"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"tipo": {"label": "Resposta Rápida", "value": "quick_reply"},
|
|
187
|
+
"display_text": "❌ Não",
|
|
188
|
+
"conteudo": "nao"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"tipo": {"label": "URL", "value": "url"},
|
|
192
|
+
"display_text": "🌐 Visitar Site",
|
|
193
|
+
"conteudo": "https://www.digitalsac.com.br"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"tipo": {"label": "Copiar", "value": "copy"},
|
|
197
|
+
"display_text": "📋 Copiar Código",
|
|
198
|
+
"conteudo": "PROMO2024"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"tipo": {"label": "Ligar", "value": "call"},
|
|
202
|
+
"display_text": "📞 Ligar Agora",
|
|
203
|
+
"conteudo": "5511999999999"
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Tipos de botão disponíveis:**
|
|
209
|
+
- `quick_reply`: Resposta rápida (o texto vai para o chat)
|
|
210
|
+
- `url`: Abre um link no navegador
|
|
211
|
+
- `copy`: Copia texto para área de transferência
|
|
212
|
+
- `call`: Inicia uma chamada telefônica
|
|
213
|
+
|
|
214
|
+
### 📋 Enviar Lista
|
|
215
|
+
1. Selecione a operação **Enviar Lista**
|
|
216
|
+
2. No campo **Parâmetro**, insira o UUID da conexão
|
|
217
|
+
3. Preencha os campos básicos:
|
|
218
|
+
- **Título**: "Menu de Opções"
|
|
219
|
+
- **Texto**: "Escolha uma categoria:"
|
|
220
|
+
- **Texto do Botão**: "Ver Opções"
|
|
221
|
+
- **Rodapé**: "Powered by DigitalSac"
|
|
222
|
+
- **Número de Telefone**: "5511999999999"
|
|
223
|
+
- **Chave Externa**: "list_001"
|
|
224
|
+
4. No campo **Seções (JSON)**, configure as seções:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
[
|
|
228
|
+
{
|
|
229
|
+
"title": "🛍️ Produtos",
|
|
230
|
+
"lines": [
|
|
231
|
+
{
|
|
232
|
+
"title": "Smartphone Premium",
|
|
233
|
+
"description": "iPhone 15 Pro Max 256GB",
|
|
234
|
+
"rowId": "prod_iphone"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"title": "Notebook Gamer",
|
|
238
|
+
"description": "Dell Alienware com RTX 4090",
|
|
239
|
+
"rowId": "prod_notebook"
|
|
240
|
+
}
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"title": "🛠️ Serviços",
|
|
245
|
+
"lines": [
|
|
246
|
+
{
|
|
247
|
+
"title": "Suporte Técnico",
|
|
248
|
+
"description": "Assistência técnica especializada",
|
|
249
|
+
"rowId": "serv_suporte"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"title": "Consultoria",
|
|
253
|
+
"description": "Consultoria personalizada",
|
|
254
|
+
"rowId": "serv_consultoria"
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"title": "📞 Contato",
|
|
260
|
+
"lines": [
|
|
261
|
+
{
|
|
262
|
+
"title": "Falar com Vendedor",
|
|
263
|
+
"description": "Atendimento comercial",
|
|
264
|
+
"rowId": "cont_vendas"
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
]
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 🖼️ Enviar Mídia com Caption
|
|
272
|
+
1. **Conecte um nó com arquivo** (ex: HTTP Request, Read Binary File, Google Drive)
|
|
273
|
+
2. Conecte ao nó **Digitalsac**
|
|
274
|
+
3. Selecione a operação **Enviar Mídia com Caption**
|
|
275
|
+
4. No campo **Parâmetro**, insira o UUID da conexão
|
|
276
|
+
5. Preencha os campos:
|
|
277
|
+
- **Caption**: "Esta é uma imagem importante do produto"
|
|
278
|
+
- **Número de Telefone**: "5511999999999"
|
|
279
|
+
- **Chave Externa**: "media_001"
|
|
280
|
+
|
|
281
|
+
**Tipos de arquivo suportados:**
|
|
282
|
+
- 🖼️ Imagens: JPG, PNG, GIF
|
|
283
|
+
- 📄 Documentos: PDF, DOC, DOCX
|
|
284
|
+
- 🎥 Vídeos: MP4, AVI
|
|
285
|
+
- 🎵 Áudio: MP3, WAV
|
|
286
|
+
|
|
287
|
+
### 📁 Enviar Base64
|
|
288
|
+
1. Selecione a operação **Enviar Base64**
|
|
289
|
+
2. No campo **Parâmetro**, insira o UUID da conexão
|
|
290
|
+
3. Preencha os campos:
|
|
291
|
+
- **Caption (Opcional)**: "Documento enviado via API"
|
|
292
|
+
- **Número de Telefone**: "5511999999999"
|
|
293
|
+
- **Arquivo Base64**: Cole o arquivo codificado em base64
|
|
294
|
+
- **Tipo MIME**: "application/pdf" (ou conforme o arquivo)
|
|
295
|
+
- **Nome do Arquivo**: "documento.pdf"
|
|
296
|
+
- **Chave Externa**: "base64_001"
|
|
297
|
+
|
|
298
|
+
**Exemplo de uso com código base64:**
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"caption": "Relatório mensal de vendas",
|
|
302
|
+
"mediaBase64": "JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKPD4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQo+PgplbmRvYmoKeHJlZgowIDQKMDAwMDAwMDAwMCA2NTUzNSBmCjAwMDAwMDAwMDkgMDAwMDAgbgowMDAwMDAwMDc0IDAwMDAwIG4KMDAwMDAwMDEyMCAwMDAwMCBuCnRyYWlsZXIKPDwKL1NpemUgNAovUm9vdCAxIDAgUgo+PgpzdGFydHhyZWYKMTc5CiUlRU9G",
|
|
303
|
+
"mimeType": "application/pdf",
|
|
304
|
+
"fileName": "relatorio.pdf"
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Dica**: Para converter arquivo para base64:
|
|
309
|
+
- **Linux/Mac**: `base64 arquivo.pdf`
|
|
310
|
+
- **Windows**: Use PowerShell: `[Convert]::ToBase64String([IO.File]::ReadAllBytes("arquivo.pdf"))`
|
|
311
|
+
- **Online**: Use conversores como base64encode.org
|
|
312
|
+
|
|
137
313
|
### Listar Tags
|
|
138
314
|
1. Selecione a operação **Listar Tags**
|
|
139
315
|
2. Não é necessário configurar parâmetros adicionais
|
|
@@ -457,6 +633,74 @@ Gera um link para download do arquivo .ics (calendário) de um agendamento espec
|
|
|
457
633
|
- Pode ser importado em qualquer aplicativo de calendário (Google Calendar, Outlook, Apple Calendar, etc.)
|
|
458
634
|
- É útil para integração com sistemas externos ou envio para clientes
|
|
459
635
|
|
|
636
|
+
## 💡 Casos de Uso Práticos
|
|
637
|
+
|
|
638
|
+
### 🤖 Bot de Atendimento Interativo
|
|
639
|
+
Combine as novas operações para criar um fluxo completo:
|
|
640
|
+
|
|
641
|
+
1. **Enviar Botões** → Menu inicial com opções
|
|
642
|
+
2. **Enviar Lista** → Catálogo de produtos/serviços
|
|
643
|
+
3. **Enviar Mídia** → Imagens dos produtos
|
|
644
|
+
4. **Enviar Base64** → Contratos/documentos
|
|
645
|
+
|
|
646
|
+
### 🛒 E-commerce Automation
|
|
647
|
+
```
|
|
648
|
+
Trigger (Webhook)
|
|
649
|
+
↓
|
|
650
|
+
Enviar Botões (Confirmar pedido?)
|
|
651
|
+
↓
|
|
652
|
+
Enviar Lista (Formas de pagamento)
|
|
653
|
+
↓
|
|
654
|
+
Enviar Base64 (Contrato PDF)
|
|
655
|
+
↓
|
|
656
|
+
Enviar Mídia (Comprovante)
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### 📊 Relatórios Automatizados
|
|
660
|
+
```
|
|
661
|
+
Scheduler (Diário)
|
|
662
|
+
↓
|
|
663
|
+
HTTP Request (Buscar dados)
|
|
664
|
+
↓
|
|
665
|
+
Code (Gerar gráfico base64)
|
|
666
|
+
↓
|
|
667
|
+
Enviar Base64 (Relatório visual)
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### 🎯 Marketing Campaigns
|
|
671
|
+
```
|
|
672
|
+
Database (Lista clientes)
|
|
673
|
+
↓
|
|
674
|
+
Loop (Para cada cliente)
|
|
675
|
+
↓
|
|
676
|
+
Enviar Botões (CTA personalizado)
|
|
677
|
+
↓
|
|
678
|
+
Webhook (Capturar resposta)
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### 🔄 Workflow Exemplo Completo
|
|
682
|
+
**Cenário**: Venda de produto com confirmação interativa
|
|
683
|
+
|
|
684
|
+
```
|
|
685
|
+
1. Webhook (Novo lead)
|
|
686
|
+
↓
|
|
687
|
+
2. Enviar Botões ("Interesse em comprar?")
|
|
688
|
+
↓
|
|
689
|
+
3. IF (Resposta = "Sim")
|
|
690
|
+
↓
|
|
691
|
+
4. Enviar Lista (Catálogo produtos)
|
|
692
|
+
↓
|
|
693
|
+
5. HTTP Request (Buscar detalhes do produto)
|
|
694
|
+
↓
|
|
695
|
+
6. Enviar Mídia (Foto do produto)
|
|
696
|
+
↓
|
|
697
|
+
7. Enviar Botões ("Fechar pedido?")
|
|
698
|
+
↓
|
|
699
|
+
8. Enviar Base64 (Contrato PDF)
|
|
700
|
+
↓
|
|
701
|
+
9. Webhook (Notificar vendedor)
|
|
702
|
+
```
|
|
703
|
+
|
|
460
704
|
## Suporte
|
|
461
705
|
|
|
462
706
|
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
|