n8n-nodes-atendix 1.3.6 → 1.3.8

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.
@@ -216,7 +216,7 @@ class Atendix {
216
216
  noDataExpression: true,
217
217
  displayOptions: { show: { resource: ['invoice'] } },
218
218
  options: [
219
- { name: 'Listar Notas Fiscais', value: 'list', description: 'Lista notas fiscais da loja', action: 'Listar notas fiscais' },
219
+ { name: 'Listar NFs do Pedido', value: 'list', description: 'Lista notas fiscais de um pedido específico', action: 'Listar notas fiscais do pedido' },
220
220
  { name: 'Buscar Nota Fiscal', value: 'get', description: 'Busca uma nota fiscal por ID', action: 'Buscar nota fiscal por ID' },
221
221
  { name: 'Buscar NF por Pedido', value: 'getByOrder', description: 'Busca a nota fiscal vinculada a um pedido', action: 'Buscar nota fiscal por pedido' },
222
222
  { name: 'Cadastrar Nota Fiscal', value: 'create', description: 'Cadastra uma nova nota fiscal em um pedido', action: 'Cadastrar nota fiscal' },
@@ -225,7 +225,7 @@ class Atendix {
225
225
  },
226
226
  {
227
227
  displayName: 'ID do Pedido', name: 'invoiceOrderId', type: 'string', required: true,
228
- displayOptions: { show: { resource: ['invoice'], operation: ['get', 'getByOrder', 'create'] } },
228
+ displayOptions: { show: { resource: ['invoice'], operation: ['list', 'get', 'getByOrder', 'create'] } },
229
229
  default: '', description: 'ID do pedido vinculado à nota fiscal',
230
230
  },
231
231
  {
@@ -233,16 +233,7 @@ class Atendix {
233
233
  displayOptions: { show: { resource: ['invoice'], operation: ['get'] } },
234
234
  default: '', description: 'ID da nota fiscal (ex: 1347). Requer também o ID do Pedido.',
235
235
  },
236
- {
237
- displayName: 'Filtros', name: 'filters', type: 'collection',
238
- placeholder: 'Adicionar Filtro', default: {},
239
- displayOptions: { show: { resource: ['invoice'], operation: ['list'] } },
240
- options: [
241
- { displayName: 'ID do Pedido', name: 'orderId', type: 'string', default: '' },
242
- { displayName: 'Limite', name: 'limit', type: 'number', default: 50 },
243
- { displayName: 'Página', name: 'page', type: 'number', default: 1 },
244
- ],
245
- },
236
+ // invoice list usa GET /orders/:id/invoices — sem filtros adicionais
246
237
  {
247
238
  displayName: 'Dados da Nota Fiscal', name: 'invoiceData', type: 'collection',
248
239
  placeholder: 'Adicionar Campo', default: {},
@@ -261,27 +252,50 @@ class Atendix {
261
252
  };
262
253
  }
263
254
  async execute() {
264
- var _a;
255
+ var _a, _b, _c, _d;
265
256
  const items = this.getInputData();
266
257
  const returnData = [];
267
258
  const resource = this.getNodeParameter('resource', 0);
268
259
  const operation = this.getNodeParameter('operation', 0);
269
- // Chave internalizadas — não dependem de variáveis de ambiente
260
+ console.log(`\n========================================`);
261
+ console.log(`[ATENDIX v1.3.7] Iniciando execução`);
262
+ console.log(`[ATENDIX] resource=${resource} | operation=${operation} | items=${items.length}`);
263
+ console.log(`========================================`);
264
+ // Chaves internalizadas — não dependem de variáveis de ambiente
270
265
  if (!ATENDIX_AUTH_TOKEN) {
266
+ console.error('[ATENDIX] ❌ ATENDIX_AUTH_TOKEN não encontrado no pacote');
271
267
  throw new Error('Configuração de validação Atendix incompleta. Entre em contato com o suporte.');
272
268
  }
273
269
  // 1. Credenciais
274
270
  const credentials = await this.getCredentials('trayApiAuto');
275
- let baseUrl = (credentials.apiHost || credentials.apiAddress || '').trim().replace(/\/$/, '');
271
+ const apiHost = (credentials.apiHost || '').trim().replace(/\/$/, '');
272
+ const apiAddress = (credentials.apiAddress || '').trim().replace(/\/$/, '');
273
+ let baseUrl = (apiHost || apiAddress);
274
+ console.log(`[ATENDIX] apiHost = "${apiHost}"`);
275
+ console.log(`[ATENDIX] apiAddress = "${apiAddress}"`);
276
+ console.log(`[ATENDIX] baseUrl = "${baseUrl}"`);
277
+ console.log(`[ATENDIX] accessToken = ${credentials.accessToken ? '✅ presente em cache' : '⚠️ ausente — vai autenticar'}`);
278
+ console.log(`[ATENDIX] tokenExpiry = ${credentials.tokenExpiration || 'não definido'}`);
276
279
  // ==========================================
277
280
  // 1.1 VALIDAÇÃO DE LICENÇA (SaaS GATEKEEPER)
278
281
  // ==========================================
279
282
  const storeBaseUrl = baseUrl.replace('/web_api', '');
280
283
  let licenseCheck;
284
+ // Detecta se está rodando no servidor da Maria Pinho (mesma rede Docker)
285
+ // Se sim, usa endereço interno do container para evitar loop via Traefik
286
+ const n8nHost = process.env.N8N_HOST || '';
287
+ const isInternalServer = n8nHost.includes('mariapinho.com.br');
288
+ const licenseUrlExternal = 'https://n8n.mariapinho.com.br/webhook/valida-atendix';
289
+ const licenseUrlInternal = 'http://n8n_webhook:5678/webhook/valida-atendix';
290
+ const licenseUrl = isInternalServer ? licenseUrlInternal : licenseUrlExternal;
291
+ console.log(`[ATENDIX] 🔐 Validando licença para: ${storeBaseUrl}`);
292
+ console.log(`[ATENDIX] 🔐 N8N_HOST detectado: "${n8nHost}"`);
293
+ console.log(`[ATENDIX] 🔐 Modo: ${isInternalServer ? 'INTERNO (Docker)' : 'EXTERNO (internet)'}`);
294
+ console.log(`[ATENDIX] 🔐 License URL: ${licenseUrl}`);
281
295
  try {
282
296
  licenseCheck = await this.helpers.httpRequest({
283
297
  method: 'POST',
284
- url: 'https://n8n.mariapinho.com.br/webhook/valida-atendix',
298
+ url: licenseUrl,
285
299
  headers: {
286
300
  'Content-Type': 'application/json',
287
301
  'Authorization': ATENDIX_AUTH_TOKEN,
@@ -289,22 +303,29 @@ class Atendix {
289
303
  body: { url: storeBaseUrl },
290
304
  json: true,
291
305
  });
292
- console.error('LICENSE CHECK RESPONSE: ' + licenseCheck.autorizado);
306
+ console.log(`[ATENDIX] 🔐 License check response:`, JSON.stringify(licenseCheck));
293
307
  if (!licenseCheck || licenseCheck.autorizado !== true) {
294
- console.error('Resposta inválida do servidor de licenças:', licenseCheck);
308
+ console.error(`[ATENDIX] Licença NÃO autorizada para ${storeBaseUrl}`);
309
+ console.error(`[ATENDIX] ❌ Resposta do servidor:`, JSON.stringify(licenseCheck));
295
310
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Sua licença Atendix para a loja ${storeBaseUrl} não está ativa. Acesse https://atendix.co`);
296
311
  }
312
+ console.log(`[ATENDIX] ✅ Licença OK`);
297
313
  }
298
314
  catch (error) {
299
- console.error('STORE BASE URL:', storeBaseUrl);
300
- console.error('Erro HTTP licença:', (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status);
315
+ console.error(`[ATENDIX] Erro na validação de licença`);
316
+ console.error(`[ATENDIX] licenseUrl = ${licenseUrl}`);
317
+ console.error(`[ATENDIX] storeBaseUrl = ${storeBaseUrl}`);
318
+ console.error(`[ATENDIX] HTTP status = ${(_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status}`);
319
+ console.error(`[ATENDIX] HTTP body = ${JSON.stringify((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.data)}`);
320
+ console.error(`[ATENDIX] message = ${error === null || error === void 0 ? void 0 : error.message}`);
301
321
  if (error instanceof n8n_workflow_1.NodeOperationError)
302
322
  throw error;
303
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Erro crítico: Não foi possível validar a licença do Atendix no servidor MariaPinho.');
323
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Erro crítico na validação de licença: ${error === null || error === void 0 ? void 0 : error.message}`);
304
324
  }
305
- // 2. TOKEN MANAGER (Fallback)
325
+ // 2. TOKEN MANAGER (Fallback quando preAuthentication não preencheu)
306
326
  let accessToken = credentials.accessToken;
307
327
  if (!accessToken) {
328
+ console.log(`[ATENDIX] ⚠️ accessToken vazio — autenticando manualmente via ${baseUrl}/auth`);
308
329
  try {
309
330
  const authResponse = await this.helpers.httpRequest({
310
331
  method: 'POST',
@@ -317,11 +338,16 @@ class Atendix {
317
338
  json: true,
318
339
  });
319
340
  accessToken = authResponse.access_token;
341
+ console.log(`[ATENDIX] ✅ Token obtido via fallback: ${accessToken ? accessToken.substring(0, 20) + '...' : 'VAZIO'}`);
320
342
  }
321
343
  catch (authError) {
344
+ console.error(`[ATENDIX] ❌ Falha no fallback de autenticação: ${authError.message}`);
322
345
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Falha na Autenticação Tray: ${authError.message}`);
323
346
  }
324
347
  }
348
+ else {
349
+ console.log(`[ATENDIX] ✅ Usando token em cache: ${accessToken.substring(0, 20)}...`);
350
+ }
325
351
  // ==========================================
326
352
  // 3. LOOP PRINCIPAL — Rate limit: 500ms entre itens
327
353
  // ==========================================
@@ -335,8 +361,10 @@ class Atendix {
335
361
  if (resource === 'order') {
336
362
  if (operation === 'get') {
337
363
  const orderId = this.getNodeParameter('orderId', i);
338
- console.log(`>>> ATENDIX - GET ${baseUrl}/orders/${orderId}`);
339
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/orders/${orderId}`, qs, json: true });
364
+ const url = `${baseUrl}/orders/${orderId}`;
365
+ console.log(`[ATENDIX] 📦 GET ${url}`);
366
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
367
+ console.log(`[ATENDIX] ✅ Pedido retornado: ${JSON.stringify(responseData).substring(0, 200)}`);
340
368
  }
341
369
  if (operation === 'list') {
342
370
  const filters = this.getNodeParameter('filters', i, {});
@@ -344,7 +372,9 @@ class Atendix {
344
372
  qs.status = filters.status;
345
373
  if (filters.limit)
346
374
  qs.limit = filters.limit;
347
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/orders`, qs, json: true });
375
+ const url = `${baseUrl}/orders`;
376
+ console.log(`[ATENDIX] 📦 GET ${url} | qs=${JSON.stringify(qs)}`);
377
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
348
378
  }
349
379
  }
350
380
  // ==================== CLIENTES ====================
@@ -356,7 +386,9 @@ class Atendix {
356
386
  qs.email = searchValue;
357
387
  else
358
388
  qs.cpf_cnpj = searchValue;
359
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/customers`, qs, json: true });
389
+ const url = `${baseUrl}/customers`;
390
+ console.log(`[ATENDIX] 👤 GET ${url} | searchType=${searchType} value=${searchValue}`);
391
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
360
392
  }
361
393
  }
362
394
  // ==================== PRODUTOS ====================
@@ -365,11 +397,15 @@ class Atendix {
365
397
  const searchType = this.getNodeParameter('searchType', i);
366
398
  const searchValue = this.getNodeParameter('searchValue', i);
367
399
  if (searchType === 'id') {
368
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/products/${searchValue}`, qs, json: true });
400
+ const url = `${baseUrl}/products/${searchValue}`;
401
+ console.log(`[ATENDIX] 🛍️ GET ${url}`);
402
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
369
403
  }
370
404
  else {
405
+ const url = `${baseUrl}/products`;
371
406
  qs.sku = searchValue;
372
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/products`, qs, json: true });
407
+ console.log(`[ATENDIX] 🛍️ GET ${url} | sku=${searchValue}`);
408
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
373
409
  }
374
410
  }
375
411
  }
@@ -381,11 +417,15 @@ class Atendix {
381
417
  qs.limit = filters.limit;
382
418
  if (filters.page)
383
419
  qs.page = filters.page;
384
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/categories`, qs, json: true });
420
+ const url = `${baseUrl}/categories`;
421
+ console.log(`[ATENDIX] 📂 GET ${url} | qs=${JSON.stringify(qs)}`);
422
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
385
423
  }
386
424
  if (operation === 'get') {
387
425
  const categoryId = this.getNodeParameter('categoryId', i);
388
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/categories/${categoryId}`, qs, json: true });
426
+ const url = `${baseUrl}/categories/${categoryId}`;
427
+ console.log(`[ATENDIX] 📂 GET ${url}`);
428
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
389
429
  }
390
430
  }
391
431
  // ==================== VARIAÇÕES ====================
@@ -398,11 +438,15 @@ class Atendix {
398
438
  qs.limit = filters.limit;
399
439
  if (filters.page)
400
440
  qs.page = filters.page;
401
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/variants`, qs, json: true });
441
+ const url = `${baseUrl}/variants`;
442
+ console.log(`[ATENDIX] 🔀 GET ${url} | product_id=${productIdForVariant}`);
443
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
402
444
  }
403
445
  if (operation === 'get') {
404
446
  const variantId = this.getNodeParameter('variantId', i);
405
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/variants/${variantId}`, qs, json: true });
447
+ const url = `${baseUrl}/variants/${variantId}`;
448
+ console.log(`[ATENDIX] 🔀 GET ${url}`);
449
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
406
450
  }
407
451
  }
408
452
  // ==================== IMAGENS DE PRODUTO ====================
@@ -411,47 +455,61 @@ class Atendix {
411
455
  const imageUrl = this.getNodeParameter('imageUrl', i);
412
456
  if (operation === 'create') {
413
457
  const body = { ProductImage: { product_id: productIdForImage, url: imageUrl } };
414
- responseData = await this.helpers.httpRequest({ method: 'POST', url: `${baseUrl}/products/${productIdForImage}/images`, qs, body, json: true });
458
+ const url = `${baseUrl}/products/${productIdForImage}/images`;
459
+ console.log(`[ATENDIX] 🖼️ POST ${url} | body=${JSON.stringify(body)}`);
460
+ responseData = await this.helpers.httpRequest({ method: 'POST', url, qs, body, json: true });
415
461
  }
416
462
  if (operation === 'createVariant') {
417
463
  const variantIdForImage = this.getNodeParameter('variantIdForImage', i);
418
464
  const body = { VariantImage: { product_id: productIdForImage, variant_id: variantIdForImage, url: imageUrl } };
419
- responseData = await this.helpers.httpRequest({ method: 'POST', url: `${baseUrl}/variants/${variantIdForImage}/images`, qs, body, json: true });
465
+ const url = `${baseUrl}/variants/${variantIdForImage}/images`;
466
+ console.log(`[ATENDIX] 🖼️ POST ${url} | body=${JSON.stringify(body)}`);
467
+ responseData = await this.helpers.httpRequest({ method: 'POST', url, qs, body, json: true });
420
468
  }
421
469
  }
422
470
  // ==================== NOTA FISCAL ====================
423
471
  if (resource === 'invoice') {
424
472
  if (operation === 'list') {
425
- const filters = this.getNodeParameter('filters', i, {});
426
- if (filters.orderId)
427
- qs.order_id = filters.orderId;
428
- if (filters.limit)
429
- qs.limit = filters.limit;
430
- if (filters.page)
431
- qs.page = filters.page;
432
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/invoices`, qs, json: true });
473
+ // CORRETO: GET /orders/:order_id/invoices
474
+ // GET /invoices NÃO EXISTE na API Tray (confirmado no PRD §3.3)
475
+ const invoiceOrderId = this.getNodeParameter('invoiceOrderId', i);
476
+ const url = `${baseUrl}/orders/${invoiceOrderId}/invoices`;
477
+ console.log(`[ATENDIX] 🧾 GET ${url}`);
478
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
433
479
  }
434
480
  if (operation === 'get') {
435
481
  const invoiceOrderId = this.getNodeParameter('invoiceOrderId', i);
436
482
  const invoiceId = this.getNodeParameter('invoiceId', i);
437
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/orders/${invoiceOrderId}/invoices/${invoiceId}`, qs, json: true });
483
+ const url = `${baseUrl}/orders/${invoiceOrderId}/invoices/${invoiceId}`;
484
+ console.log(`[ATENDIX] 🧾 GET ${url}`);
485
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
438
486
  }
439
487
  if (operation === 'getByOrder') {
440
488
  const invoiceOrderId = this.getNodeParameter('invoiceOrderId', i);
441
- responseData = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/orders/${invoiceOrderId}/invoices`, qs, json: true });
489
+ const url = `${baseUrl}/orders/${invoiceOrderId}/invoices`;
490
+ console.log(`[ATENDIX] 🧾 GET ${url}`);
491
+ responseData = await this.helpers.httpRequest({ method: 'GET', url, qs, json: true });
442
492
  }
443
493
  if (operation === 'create') {
444
494
  const invoiceOrderId = this.getNodeParameter('invoiceOrderId', i);
445
495
  const invoiceData = this.getNodeParameter('invoiceData', i, {});
446
496
  const body = { Invoice: { order_id: invoiceOrderId, ...invoiceData } };
447
- responseData = await this.helpers.httpRequest({ method: 'POST', url: `${baseUrl}/invoices`, qs, body, json: true });
497
+ const url = `${baseUrl}/invoices`;
498
+ console.log(`[ATENDIX] 🧾 POST ${url} | body=${JSON.stringify(body)}`);
499
+ responseData = await this.helpers.httpRequest({ method: 'POST', url, qs, body, json: true });
448
500
  }
449
501
  }
502
+ console.log(`[ATENDIX] ✅ item[${i}] concluído`);
450
503
  const executionData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), { itemData: { item: i } });
451
504
  returnData.push(...executionData);
452
505
  }
453
506
  catch (error) {
454
507
  const errorMessage = error instanceof Error ? error.message : String(error);
508
+ console.error(`[ATENDIX] ❌ Erro no item[${i}]: ${errorMessage}`);
509
+ if (error instanceof Error && error.response) {
510
+ console.error(`[ATENDIX] ❌ HTTP status : ${(_c = error.response) === null || _c === void 0 ? void 0 : _c.status}`);
511
+ console.error(`[ATENDIX] ❌ HTTP body : ${JSON.stringify((_d = error.response) === null || _d === void 0 ? void 0 : _d.data)}`);
512
+ }
455
513
  if (this.continueOnFail()) {
456
514
  returnData.push({ json: { error: errorMessage }, pairedItem: { item: i } });
457
515
  continue;
@@ -459,6 +517,7 @@ class Atendix {
459
517
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), errorMessage, { itemIndex: i });
460
518
  }
461
519
  }
520
+ console.log(`[ATENDIX] ✅ Execução finalizada — ${returnData.length} item(s) retornados`);
462
521
  return [returnData];
463
522
  }
464
523
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-atendix",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Conector Atendix para integração com Tray Commerce",
5
5
  "keywords": [
6
6
  "n8n-community-node-package"