n8n-nodes-digitalsac 0.2.1 → 0.2.4

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 CHANGED
@@ -53,19 +53,53 @@ Configure as credenciais Digitalsac com a URL base e seu Bearer Token:
53
53
 
54
54
  ### Validar Data
55
55
  1. Selecione a operação **Validar Data**
56
- 2. No campo **Dados (JSON)**, insira os dados no formato JSON
56
+ 2. No campo **Dados (JSON)**, insira os dados no formato:
57
+ ```json
58
+ {
59
+ "data": "string com a data a ser validada"
60
+ }
61
+ ```
57
62
 
58
63
  ### Listar Filas/Atendentes
59
64
  1. Selecione a operação **Listar Filas** ou **Listar Atendentes**
60
65
  2. Não é necessário configurar parâmetros adicionais
61
66
 
62
- ### Transferir para Fila/Atendente
63
- 1. Selecione a operação **Transferir para Fila** ou **Transferir para Atendente**
64
- 2. No campo **Dados (JSON)**, insira os dados no formato JSON
67
+ ### Transferir para Fila
68
+ 1. Selecione a operação **Transferir para Fila**
69
+ 2. No campo **Dados (JSON)**, insira os dados no formato:
70
+ ```json
71
+ {
72
+ "ticketId": 0,
73
+ "queueId": 0
74
+ }
75
+ ```
76
+ Onde:
77
+ - `ticketId`: ID do ticket a ser transferido
78
+ - `queueId`: ID da fila de destino
79
+
80
+ ### Transferir para Atendente
81
+ 1. Selecione a operação **Transferir para Atendente**
82
+ 2. No campo **Dados (JSON)**, insira os dados no formato:
83
+ ```json
84
+ {
85
+ "ticketId": 0,
86
+ "userId": 0
87
+ }
88
+ ```
89
+ Onde:
90
+ - `ticketId`: ID do ticket a ser transferido
91
+ - `userId`: ID do atendente de destino
65
92
 
66
93
  ### Fechar Ticket
67
94
  1. Selecione a operação **Fechar Ticket**
68
- 2. No campo **Dados (JSON)**, insira os dados no formato JSON
95
+ 2. No campo **Dados (JSON)**, insira os dados no formato:
96
+ ```json
97
+ {
98
+ "ticketId": 0
99
+ }
100
+ ```
101
+ Onde:
102
+ - `ticketId`: ID do ticket a ser fechado
69
103
 
70
104
  ### Enviar Mensagem de Texto
71
105
  1. Selecione a operação **Enviar Mensagem**
@@ -94,6 +128,38 @@ Configure as credenciais Digitalsac com a URL base e seu Bearer Token:
94
128
  ```
95
129
  Onde `data` é o nome da propriedade binária que contém o arquivo.
96
130
 
131
+ ## Exemplos de Respostas da API
132
+
133
+ ### Transferir para Fila
134
+ **Resposta de sucesso:**
135
+ ```json
136
+ {
137
+ "status": 0
138
+ }
139
+ ```
140
+
141
+ ### Transferir para Atendente
142
+ **Resposta de sucesso:**
143
+ ```json
144
+ {
145
+ "status": 0
146
+ }
147
+ ```
148
+
149
+ ### Fechar Ticket
150
+ **Resposta de sucesso:**
151
+ ```json
152
+ "string"
153
+ ```
154
+
155
+ ### Validar Data
156
+ **Resposta de sucesso:**
157
+ ```json
158
+ {
159
+ "status": 0
160
+ }
161
+ ```
162
+
97
163
  ## Exemplo de Fluxo
98
164
 
99
165
  ### Enviar PDF para um contato
@@ -111,6 +177,28 @@ Onde `data` é o nome da propriedade binária que contém o arquivo.
111
177
  }
112
178
  ```
113
179
 
180
+ ### Transferir ticket para uma fila específica
181
+ 1. Adicione um nó **Digitalsac**
182
+ - Operação: **Transferir para Fila**
183
+ - Dados (JSON):
184
+ ```json
185
+ {
186
+ "ticketId": 123,
187
+ "queueId": 5
188
+ }
189
+ ```
190
+
191
+ ### Transferir ticket para um atendente específico
192
+ 1. Adicione um nó **Digitalsac**
193
+ - Operação: **Transferir para Atendente**
194
+ - Dados (JSON):
195
+ ```json
196
+ {
197
+ "ticketId": 123,
198
+ "userId": 10
199
+ }
200
+ ```
201
+
114
202
  ## Suporte
115
203
 
116
204
  Para suporte, entre em contato com [contato@digitalsac.io](mailto:contato@digitalsac.io).
@@ -49,19 +49,19 @@ class Digitalsac {
49
49
  operation: ['validateWhatsapp', 'validateCpf', 'sendMessage'],
50
50
  },
51
51
  },
52
- description: 'Número, CPF ou UUID da conexão (conforme operação)',
52
+ description: 'Número, CPF ou UUID da mensagem (conforme operação)',
53
53
  },
54
54
  {
55
55
  displayName: 'Dados (JSON)',
56
56
  name: 'bodyData',
57
57
  type: 'json',
58
- default: '{\n "body": "Mensagem a ser enviada",\n "number": "5511999999999",\n "externalKey": "chave_opcional"\n // Para enviar arquivo, adicione: "binaryPropertyName": "data"\n}',
58
+ default: '{"body": "Mensagem de teste", "number": "5511999999999", "externalKey": "chave123"}',
59
59
  displayOptions: {
60
60
  show: {
61
61
  operation: ['validateDate', 'transferQueue', 'transferAgent', 'closeTicket', 'sendMessage'],
62
62
  },
63
63
  },
64
- description: 'Para enviar mensagem: {"body": "texto", "number": "5511999999999", "externalKey": "opcional"}. Para enviar arquivo, adicione "binaryPropertyName": "data" (onde "data" é o nome da propriedade binária)',
64
+ description: 'Dados no formato JSON',
65
65
  },
66
66
  ],
67
67
  };
@@ -77,32 +77,32 @@ class Digitalsac {
77
77
  let responseData;
78
78
  const headers = {
79
79
  Authorization: `Bearer ${token}`,
80
- 'Content-Type': 'application/json',
81
80
  Accept: 'application/json',
82
81
  };
83
82
  let url = '';
84
83
  let method = 'GET';
85
84
  let body;
86
- let param = '';
85
+ let param = this.getNodeParameter('param', i, '');
87
86
  let options = {};
88
- let isFormData = false;
89
- let formDataFields = {};
90
- let binaryData;
91
- let binaryFileName;
92
- let binaryContentType;
93
87
  switch (operation) {
94
88
  case 'validateWhatsapp':
95
- param = this.getNodeParameter('param', i);
96
89
  url = `/typebot/whatsappnumber/${param}`;
97
90
  break;
98
91
  case 'validateCpf':
99
- param = this.getNodeParameter('param', i);
100
92
  url = `/typebot/validate/cpf/${param}`;
101
93
  break;
102
94
  case 'validateDate':
103
95
  url = '/typebot/validate/data';
104
96
  method = 'POST';
105
- body = this.getNodeParameter('bodyData', i);
97
+ body = JSON.parse(this.getNodeParameter('bodyData', i));
98
+ headers['Content-Type'] = 'application/json';
99
+ options = {
100
+ method,
101
+ headers,
102
+ body: JSON.stringify(body),
103
+ uri: `${baseUrl}${url}`,
104
+ json: true,
105
+ };
106
106
  break;
107
107
  case 'listQueues':
108
108
  url = '/typebot/listar_filas';
@@ -113,116 +113,76 @@ class Digitalsac {
113
113
  case 'transferQueue':
114
114
  url = '/typebot/transferir_para_fila';
115
115
  method = 'POST';
116
- body = this.getNodeParameter('bodyData', i);
116
+ body = JSON.parse(this.getNodeParameter('bodyData', i));
117
+ headers['Content-Type'] = 'application/json';
118
+ options = {
119
+ method,
120
+ headers,
121
+ body: JSON.stringify(body),
122
+ uri: `${baseUrl}${url}`,
123
+ json: true,
124
+ };
117
125
  break;
118
126
  case 'transferAgent':
119
127
  url = '/typebot/transferir_para_atendente';
120
128
  method = 'POST';
121
- body = this.getNodeParameter('bodyData', i);
129
+ body = JSON.parse(this.getNodeParameter('bodyData', i));
130
+ headers['Content-Type'] = 'application/json';
131
+ options = {
132
+ method,
133
+ headers,
134
+ body: JSON.stringify(body),
135
+ uri: `${baseUrl}${url}`,
136
+ json: true,
137
+ };
122
138
  break;
123
139
  case 'closeTicket':
124
140
  url = '/typebot/fechar_ticket';
125
141
  method = 'POST';
126
- body = this.getNodeParameter('bodyData', i);
142
+ body = JSON.parse(this.getNodeParameter('bodyData', i));
143
+ headers['Content-Type'] = 'application/json';
144
+ options = {
145
+ method,
146
+ headers,
147
+ body: JSON.stringify(body),
148
+ uri: `${baseUrl}${url}`,
149
+ json: true,
150
+ };
127
151
  break;
128
152
  case 'sendMessage':
129
- // Obter UUID da conexão do campo parâmetro
130
- const uuid = this.getNodeParameter('param', i);
131
- url = `/v1/api/external/${uuid}`;
153
+ url = `/v1/api/external/${param}`;
132
154
  method = 'POST';
133
- // Verificar se há dados binários (para envio de arquivo)
134
- const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i, '');
135
- let hasBinaryData = false;
136
- if (binaryPropertyName && items[i].binary) {
137
- const binary = items[i].binary;
138
- hasBinaryData = binary[binaryPropertyName] !== undefined;
139
- }
140
- // Obter dados do corpo da mensagem
141
- const messageData = this.getNodeParameter('bodyData', i, '{}');
142
- let messageBody = {};
143
- try {
144
- // Tentar fazer parse do JSON
145
- if (typeof messageData === 'string') {
146
- messageBody = JSON.parse(messageData);
147
- }
148
- else {
149
- messageBody = messageData;
150
- }
151
- }
152
- catch (error) {
153
- // Se falhar, usar como está
154
- messageBody = { body: messageData };
155
- }
156
- // Se não tiver dados binários, enviar como JSON normal
157
- if (!hasBinaryData) {
158
- body = messageBody;
159
- }
160
- else {
161
- // Configurar para envio de arquivo
162
- isFormData = true;
163
- formDataFields = messageBody;
164
- // Preparar arquivo binário
165
- if (items[i].binary) {
166
- const binaryKeyData = items[i].binary;
167
- if (binaryKeyData[binaryPropertyName]) {
168
- const binaryProperty = binaryKeyData[binaryPropertyName];
169
- binaryData = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
170
- binaryFileName = binaryProperty.fileName || 'file';
171
- binaryContentType = binaryProperty.mimeType;
172
- }
173
- else {
174
- throw new Error(`Nenhum dado binário encontrado na propriedade "${binaryPropertyName}"`);
175
- }
176
- }
177
- headers['Content-Type'] = 'multipart/form-data';
178
- options = {
179
- formData: true,
180
- };
181
- }
155
+ body = JSON.parse(this.getNodeParameter('bodyData', i));
156
+ headers['Content-Type'] = 'application/json';
157
+ options = {
158
+ method,
159
+ headers,
160
+ body: JSON.stringify(body),
161
+ uri: `${baseUrl}${url}`,
162
+ json: true,
163
+ };
182
164
  break;
183
165
  }
184
- // Configurar opções da requisição
185
- const requestOptions = {
186
- method,
187
- headers,
188
- uri: `${baseUrl}${url}`,
189
- json: true,
190
- };
191
- // Adicionar body quando necessário
192
- if (body && !isFormData) {
193
- requestOptions.body = body;
166
+ // Se as opções não foram definidas no switch, defina-as aqui para operações GET
167
+ if (!options.method) {
168
+ options = {
169
+ method,
170
+ headers,
171
+ uri: `${baseUrl}${url}`,
172
+ json: true,
173
+ };
194
174
  }
195
- // Configurar FormData quando necessário
196
- if (isFormData) {
197
- const formData = {};
198
- // Adicionar campos de texto
199
- Object.entries(formDataFields).forEach(([key, value]) => {
200
- formData[key] = value;
201
- });
202
- // Adicionar arquivo se disponível
203
- if (binaryData && binaryFileName) {
204
- formData.media = {
205
- value: binaryData,
206
- options: {
207
- filename: binaryFileName,
208
- contentType: binaryContentType,
209
- },
210
- };
211
- }
212
- requestOptions.formData = formData;
213
- }
214
- // Mesclar opções adicionais
215
- Object.assign(requestOptions, options);
216
175
  try {
217
- responseData = await this.helpers.request(requestOptions);
176
+ responseData = await this.helpers.request(options);
218
177
  returnData.push({ json: responseData });
219
178
  }
220
179
  catch (error) {
221
- if (this.continueOnFail()) {
180
+ if (error.response) {
181
+ returnData.push({ json: { error: error.response.body } });
182
+ }
183
+ else {
222
184
  returnData.push({ json: { error: error.message } });
223
- continue;
224
185
  }
225
- throw error;
226
186
  }
227
187
  }
228
188
  return [returnData];
package/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { Digitalsac } from './nodes/Digitalsac/Digitalsac.node';
2
+ import { DigitalsacApi } from './credentials/DigitalsacApi.credentials';
3
+
4
+ export const nodes = [Digitalsac];
5
+ export const credentials = [DigitalsacApi];
@@ -0,0 +1,201 @@
1
+ import {
2
+ IExecuteFunctions,
3
+ INodeExecutionData,
4
+ INodeType,
5
+ INodeTypeDescription,
6
+ NodeConnectionType,
7
+ } from 'n8n-workflow';
8
+
9
+ export class Digitalsac implements INodeType {
10
+ description: INodeTypeDescription = {
11
+ displayName: 'Digitalsac Izing Pro',
12
+ name: 'digitalsac',
13
+ icon: 'file:digitalsac.svg',
14
+ group: ['transform'],
15
+ version: 1,
16
+ description: 'Interage com a API do Digitalsac',
17
+ defaults: {
18
+ name: 'Digitalsac',
19
+ },
20
+ inputs: <NodeConnectionType[]>['main'],
21
+ outputs: <NodeConnectionType[]>['main'],
22
+
23
+ credentials: [
24
+ {
25
+ name: 'digitalsacApi',
26
+ required: true,
27
+ },
28
+ ],
29
+ properties: [
30
+ {
31
+ displayName: 'Operação',
32
+ name: 'operation',
33
+ type: 'options',
34
+ options: [
35
+ { name: 'Validar WhatsApp', value: 'validateWhatsapp' },
36
+ { name: 'Validar CPF', value: 'validateCpf' },
37
+ { name: 'Validar Data', value: 'validateDate' },
38
+ { name: 'Listar Filas', value: 'listQueues' },
39
+ { name: 'Listar Atendentes', value: 'listAgents' },
40
+ { name: 'Transferir para Fila', value: 'transferQueue' },
41
+ { name: 'Transferir para Atendente', value: 'transferAgent' },
42
+ { name: 'Fechar Ticket', value: 'closeTicket' },
43
+ { name: 'Enviar Mensagem', value: 'sendMessage' },
44
+ ],
45
+ default: 'validateWhatsapp',
46
+ },
47
+ {
48
+ displayName: 'Parâmetro',
49
+ name: 'param',
50
+ type: 'string',
51
+ default: '',
52
+ displayOptions: {
53
+ show: {
54
+ operation: ['validateWhatsapp', 'validateCpf', 'sendMessage'],
55
+ },
56
+ },
57
+ description: 'Número, CPF ou UUID da mensagem (conforme operação)',
58
+ },
59
+ {
60
+ displayName: 'Dados (JSON)',
61
+ name: 'bodyData',
62
+ type: 'json',
63
+ default: '{"body": "Mensagem de teste", "number": "5511999999999", "externalKey": "chave123"}',
64
+ displayOptions: {
65
+ show: {
66
+ operation: ['validateDate', 'transferQueue', 'transferAgent', 'closeTicket', 'sendMessage'],
67
+ },
68
+ },
69
+ description: 'Dados no formato JSON',
70
+ },
71
+ ],
72
+ };
73
+
74
+ async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
75
+ const items = this.getInputData();
76
+ const returnData: INodeExecutionData[] = [];
77
+
78
+ const credentials = await this.getCredentials('digitalsacApi');
79
+ const baseUrl = credentials.baseUrl;
80
+ const token = credentials.token;
81
+
82
+ for (let i = 0; i < items.length; i++) {
83
+ const operation = this.getNodeParameter('operation', i) as string;
84
+ let responseData;
85
+
86
+ const headers: Record<string, string> = {
87
+ Authorization: `Bearer ${token}`,
88
+ Accept: 'application/json',
89
+ };
90
+
91
+ let url = '';
92
+ let method: 'GET' | 'POST' = 'GET';
93
+ let body;
94
+ let param = this.getNodeParameter('param', i, '') as string;
95
+ let options: Record<string, any> = {};
96
+
97
+ switch (operation) {
98
+ case 'validateWhatsapp':
99
+ url = `/typebot/whatsappnumber/${param}`;
100
+ break;
101
+ case 'validateCpf':
102
+ url = `/typebot/validate/cpf/${param}`;
103
+ break;
104
+ case 'validateDate':
105
+ url = '/typebot/validate/data';
106
+ method = 'POST';
107
+ body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
108
+ headers['Content-Type'] = 'application/json';
109
+ options = {
110
+ method,
111
+ headers,
112
+ body: JSON.stringify(body),
113
+ uri: `${baseUrl}${url}`,
114
+ json: true,
115
+ };
116
+ break;
117
+ case 'listQueues':
118
+ url = '/typebot/listar_filas';
119
+ break;
120
+ case 'listAgents':
121
+ url = '/typebot/listar_atendentes';
122
+ break;
123
+ case 'transferQueue':
124
+ url = '/typebot/transferir_para_fila';
125
+ method = 'POST';
126
+ body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
127
+ headers['Content-Type'] = 'application/json';
128
+ options = {
129
+ method,
130
+ headers,
131
+ body: JSON.stringify(body),
132
+ uri: `${baseUrl}${url}`,
133
+ json: true,
134
+ };
135
+ break;
136
+ case 'transferAgent':
137
+ url = '/typebot/transferir_para_atendente';
138
+ method = 'POST';
139
+ body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
140
+ headers['Content-Type'] = 'application/json';
141
+ options = {
142
+ method,
143
+ headers,
144
+ body: JSON.stringify(body),
145
+ uri: `${baseUrl}${url}`,
146
+ json: true,
147
+ };
148
+ break;
149
+ case 'closeTicket':
150
+ url = '/typebot/fechar_ticket';
151
+ method = 'POST';
152
+ body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
153
+ headers['Content-Type'] = 'application/json';
154
+ options = {
155
+ method,
156
+ headers,
157
+ body: JSON.stringify(body),
158
+ uri: `${baseUrl}${url}`,
159
+ json: true,
160
+ };
161
+ break;
162
+ case 'sendMessage':
163
+ url = `/v1/api/external/${param}`;
164
+ method = 'POST';
165
+ body = JSON.parse(this.getNodeParameter('bodyData', i) as string);
166
+ headers['Content-Type'] = 'application/json';
167
+ options = {
168
+ method,
169
+ headers,
170
+ body: JSON.stringify(body),
171
+ uri: `${baseUrl}${url}`,
172
+ json: true,
173
+ };
174
+ break;
175
+ }
176
+
177
+ // Se as opções não foram definidas no switch, defina-as aqui para operações GET
178
+ if (!options.method) {
179
+ options = {
180
+ method,
181
+ headers,
182
+ uri: `${baseUrl}${url}`,
183
+ json: true,
184
+ };
185
+ }
186
+
187
+ try {
188
+ responseData = await this.helpers.request(options);
189
+ returnData.push({ json: responseData });
190
+ } catch (error: any) {
191
+ if (error.response) {
192
+ returnData.push({ json: { error: error.response.body } });
193
+ } else {
194
+ returnData.push({ json: { error: error.message } });
195
+ }
196
+ }
197
+ }
198
+
199
+ return [returnData];
200
+ }
201
+ }