diff --git a/docker-compose.yml b/docker-compose.yml index 2565fbb..63dce58 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,7 @@ services: - N8N_WEBHOOK_URL=${N8N_WEBHOOK_URL} - TINY_WEBHOOK_SECRET=${TINY_WEBHOOK_SECRET} - N8N_AUTH_TOKEN=${N8N_AUTH_TOKEN} + - TINY_API_TOKEN=${TINY_API_TOKEN} # Optional: If you use a shared Docker network for Nginx Proxy Manager, you can attach it here: # networks: # - nginx-proxy-manager-network diff --git a/src/controllers/webhook.controller.ts b/src/controllers/webhook.controller.ts index 030e18c..5f6ae38 100644 --- a/src/controllers/webhook.controller.ts +++ b/src/controllers/webhook.controller.ts @@ -1,5 +1,6 @@ import { Request, Response } from 'express'; import { sendToN8n } from '../services/n8n.service'; +import axios from 'axios'; export const handleTinyOrderUpdate = async (req: Request, res: Response): Promise => { try { @@ -15,39 +16,76 @@ export const handleTinyOrderUpdate = async (req: Request, res: Response): Promis let payload = req.body; - // Parse 'dados' if it comes as a JSON string if (typeof payload.dados === 'string') { try { payload.dados = JSON.parse(payload.dados); - } catch (e) { - console.error('Could not parse "dados" as JSON string.', e); - } + } catch (e) {} } - console.log('Received webhook from Tiny:', JSON.stringify(payload, null, 2)); + console.log('Received webhook from Tiny. Acknowledging immediately...'); - // Acknowledge Tiny immediately + // Acknowledge Tiny immediately to prevent timeouts res.status(200).send('OK'); - if (!payload || Object.keys(payload).length === 0) { - console.warn('Received empty payload from Tiny webhook.'); - return; + const orderId = payload?.dados?.id; + if (!orderId) { + console.warn('No order ID found in webhook payload. Cannot fetch details.'); + return; } - const transformedData = { - source: 'tiny_webhook_middleware', - event: payload.tipo || 'atualizacao_pedido', - dados: payload.dados, - raw_payload: payload + const tinyApiToken = process.env.TINY_API_TOKEN; + let fullOrderDetails: any = null; + + if (tinyApiToken) { + try { + console.log(`Fetching full details for Order ID: ${orderId} from Tiny API...`); + const params = new URLSearchParams(); + params.append('token', tinyApiToken); + params.append('id', orderId); + params.append('formato', 'JSON'); + + const response = await axios.post('https://api.tiny.com.br/api2/pedido.obter.php', params, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + }); + + if (response.data?.retorno?.status === 'OK') { + fullOrderDetails = response.data.retorno.pedido; + console.log(`Successfully fetched order details! Found phone: ${fullOrderDetails.cliente?.celular || fullOrderDetails.cliente?.fone || 'None'}`); + } else { + console.error('Tiny API returned an error:', response.data?.retorno?.erros || 'Unknown error'); + } + } catch (apiError: any) { + console.error('Failed to fetch from Tiny API:', apiError.message); + } + } else { + console.warn('TINY_API_TOKEN is not set in environment variables. Skipping full details fetch.'); + } + + // Build the exact flat JSON payload requested by the user + const finalPayload = { + id: fullOrderDetails?.id || payload.dados?.id || "", + numero: fullOrderDetails?.numero || payload.dados?.numero || "", + numero_ecommerce: fullOrderDetails?.numero_ecommerce || payload.dados?.idPedidoEcommerce || "", + data_pedido: fullOrderDetails?.data_pedido || payload.dados?.data || "", + data_prevista: fullOrderDetails?.data_prevista || "", + nome: fullOrderDetails?.cliente?.nome || payload.dados?.cliente?.nome || "", + valor: parseFloat(fullOrderDetails?.valor_pedido || fullOrderDetails?.valor_total || "0"), + id_vendedor: fullOrderDetails?.vendedor?.id || "", + nome_vendedor: fullOrderDetails?.vendedor?.nome || "", + whatsapp_vendedor: "", // Tiny doesn't expose this natively on the order + situacao: fullOrderDetails?.situacao || payload.dados?.descricaoSituacao || "", + fone: fullOrderDetails?.cliente?.celular || fullOrderDetails?.cliente?.telefone || fullOrderDetails?.cliente?.fone || "", + email: fullOrderDetails?.cliente?.email || "", + status_processamento: fullOrderDetails?.status_processamento || "", + forma_envio: fullOrderDetails?.forma_envio || "", + codigo_rastreamento: fullOrderDetails?.codigo_rastreamento || "", + url_rastreamento: fullOrderDetails?.url_rastreamento || "" }; - // Forward to n8n asynchronously - await sendToN8n(transformedData); + console.log('Forwarding formatted payload to n8n...'); + await sendToN8n(finalPayload); } catch (error) { console.error('Error handling Tiny webhook:', error); - if (!res.headersSent) { - res.status(500).json({ error: 'Internal server error processing webhook.' }); - } } };