{ "name": "📊 Relatório Diário CRM | Local Sem Slack", "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "cronExpression", "value": "0 18 * * *" } ] } }, "id": "cron-report-trigger", "name": "Trigger Relatório 18h", "type": "n8n-nodes-base.cron", "typeVersion": 1, "position": [240, 300] }, { "parameters": { "jsCode": "// Configurar período do relatório (últimas 24h)\nconst now = new Date();\nconst yesterday = new Date(now.getTime() - (24 * 60 * 60 * 1000));\n\nconst config = {\n report_date: now.toISOString().split('T')[0],\n start_date: yesterday.toISOString().split('T')[0],\n end_date: now.toISOString().split('T')[0],\n timestamp: now.toISOString(),\n report_title: `Relatório Diário CRM - ${now.toLocaleDateString('pt-BR')}`,\n file_date: now.toISOString().split('T')[0].replace(/-/g, '')\n};\n\nreturn config;" }, "id": "setup-report-config", "name": "Configurar Relatório", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [460, 300] }, { "parameters": { "method": "GET", "url": "https://crm.memudecore.com.br/api/leads", "authentication": "predefinedCredentialType", "nodeCredentialType": "krayin-api", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "limit", "value": "200" }, { "name": "sort", "value": "created_at" }, { "name": "order", "value": "desc" } ] }, "options": {} }, "id": "fetch-leads", "name": "Buscar Leads", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [680, 200], "credentials": { "krayin-api": { "id": "krayin-crm-api", "name": "Krayin CRM API" } } }, { "parameters": { "method": "GET", "url": "https://crm.memudecore.com.br/api/contacts", "authentication": "predefinedCredentialType", "nodeCredentialType": "krayin-api", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "limit", "value": "100" }, { "name": "sort", "value": "created_at" }, { "name": "order", "value": "desc" } ] }, "options": {} }, "id": "fetch-contacts", "name": "Buscar Contatos", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [680, 400], "credentials": { "krayin-api": { "id": "krayin-crm-api", "name": "Krayin CRM API" } } }, { "parameters": { "jsCode": "// Processar dados dos leads\nconst config = $node[\"Configurar Relatório\"].json;\nconst leadsData = $node[\"Buscar Leads\"].json;\nconst contactsData = $node[\"Buscar Contatos\"].json;\n\nconst leads = leadsData.data || [];\nconst contacts = contactsData.data || [];\n\nconst startDate = new Date(config.start_date);\nconst endDate = new Date(config.end_date);\nendDate.setHours(23, 59, 59, 999); // Fim do dia\n\n// Filtrar leads das últimas 24h\nconst newLeads = leads.filter(lead => {\n const leadDate = new Date(lead.created_at);\n return leadDate >= startDate && leadDate <= endDate;\n});\n\n// Filtrar contatos das últimas 24h\nconst newContacts = contacts.filter(contact => {\n const contactDate = new Date(contact.created_at);\n return contactDate >= startDate && contactDate <= endDate;\n});\n\n// Análise de leads por status\nconst leadsByStatus = {};\nleads.forEach(lead => {\n const status = lead.stage?.name || 'Sem Status';\n leadsByStatus[status] = (leadsByStatus[status] || 0) + 1;\n});\n\n// Análise de leads por fonte\nconst leadsBySource = {};\nleads.forEach(lead => {\n const source = lead.lead_source?.name || 'Sem Fonte';\n leadsBySource[source] = (leadsBySource[source] || 0) + 1;\n});\n\n// Análise de valor dos leads\nconst leadsWithValue = leads.filter(lead => lead.lead_value && lead.lead_value > 0);\nconst totalLeadValue = leadsWithValue.reduce((sum, lead) => sum + (lead.lead_value || 0), 0);\nconst averageLeadValue = leadsWithValue.length > 0 ? totalLeadValue / leadsWithValue.length : 0;\n\n// Leads de alto valor (>= R$ 5.000)\nconst highValueLeads = newLeads.filter(lead => (lead.lead_value || 0) >= 5000);\n\n// Leads fechados/ganhos\nconst wonLeads = leads.filter(lead => {\n const status = (lead.stage?.name || '').toLowerCase();\n return status.includes('fechado') || status.includes('ganho') || status.includes('won');\n});\n\n// Leads perdidos\nconst lostLeads = leads.filter(lead => {\n const status = (lead.stage?.name || '').toLowerCase();\n return status.includes('perdido') || status.includes('lost') || status.includes('cancelado');\n});\n\nconst metrics = {\n // Métricas gerais\n total_leads: leads.length,\n new_leads_24h: newLeads.length,\n new_contacts_24h: newContacts.length,\n \n // Métricas de valor\n total_lead_value: totalLeadValue,\n average_lead_value: averageLeadValue,\n high_value_leads: highValueLeads.length,\n \n // Métricas de conversão\n won_leads: wonLeads.length,\n lost_leads: lostLeads.length,\n conversion_rate: leads.length > 0 ? ((wonLeads.length / leads.length) * 100).toFixed(2) : 0,\n \n // Distribuições\n leads_by_status: leadsByStatus,\n leads_by_source: leadsBySource,\n \n // Dados brutos para relatório\n new_leads_details: newLeads.slice(0, 10), // Top 10\n high_value_leads_details: highValueLeads.slice(0, 5), // Top 5\n \n // Configuração\n config: config\n};\n\nreturn metrics;" }, "id": "process-crm-data", "name": "Processar Dados CRM", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [900, 300] }, { "parameters": { "jsCode": "// Gerar relatório detalhado em markdown\nconst metrics = $node[\"Processar Dados CRM\"].json;\nconst config = metrics.config;\n\nconst formatCurrency = (value) => {\n return new Intl.NumberFormat('pt-BR', {\n style: 'currency',\n currency: 'BRL'\n }).format(value);\n};\n\nconst generateReport = () => {\n let report = `# ${config.report_title}\\n\\n`;\n \n report += `**Período:** ${config.start_date} a ${config.end_date}\\n`;\n report += `**Gerado em:** ${new Date(config.timestamp).toLocaleString('pt-BR')}\\n\\n`;\n \n report += `---\\n\\n`;\n \n // Resumo Executivo\n report += `## 📊 Resumo Executivo\\n\\n`;\n report += `| Métrica | Valor |\\n`;\n report += `|---------|-------|\\n`;\n report += `| 🆕 Novos Leads (24h) | **${metrics.new_leads_24h}** |\\n`;\n report += `| 📞 Novos Contatos (24h) | **${metrics.new_contacts_24h}** |\\n`;\n report += `| 📈 Total de Leads | **${metrics.total_leads}** |\\n`;\n report += `| 💰 Valor Total dos Leads | **${formatCurrency(metrics.total_lead_value)}** |\\n`;\n report += `| 📊 Ticket Médio | **${formatCurrency(metrics.average_lead_value)}** |\\n`;\n report += `| 🎯 Taxa de Conversão | **${metrics.conversion_rate}%** |\\n`;\n report += `| 💎 Leads Alto Valor | **${metrics.high_value_leads}** |\\n`;\n report += `| ✅ Leads Ganhos | **${metrics.won_leads}** |\\n`;\n report += `| ❌ Leads Perdidos | **${metrics.lost_leads}** |\\n\\n`;\n \n // Performance\n let performance = 'Regular';\n if (metrics.new_leads_24h >= 15) performance = 'Excelente';\n else if (metrics.new_leads_24h >= 10) performance = 'Boa';\n else if (metrics.new_leads_24h >= 5) performance = 'Regular';\n else performance = 'Baixa';\n \n report += `### 🚀 Performance do Dia: **${performance}**\\n\\n`;\n \n // Distribuição por Status\n report += `## 📋 Distribuição por Status\\n\\n`;\n Object.entries(metrics.leads_by_status).forEach(([status, count]) => {\n const percentage = ((count / metrics.total_leads) * 100).toFixed(1);\n report += `- **${status}**: ${count} leads (${percentage}%)\\n`;\n });\n report += `\\n`;\n \n // Distribuição por Fonte\n report += `## 🌐 Distribuição por Fonte\\n\\n`;\n Object.entries(metrics.leads_by_source).forEach(([source, count]) => {\n const percentage = ((count / metrics.total_leads) * 100).toFixed(1);\n report += `- **${source}**: ${count} leads (${percentage}%)\\n`;\n });\n report += `\\n`;\n \n // Novos Leads Detalhados\n if (metrics.new_leads_details.length > 0) {\n report += `## 🆕 Novos Leads (Últimas 24h)\\n\\n`;\n metrics.new_leads_details.forEach((lead, index) => {\n const leadValue = lead.lead_value ? formatCurrency(lead.lead_value) : 'Não informado';\n const contactName = lead.person?.name || 'Nome não informado';\n const createdAt = new Date(lead.created_at).toLocaleString('pt-BR');\n \n report += `### ${index + 1}. ${lead.title || 'Lead sem título'}\\n`;\n report += `- **Contato**: ${contactName}\\n`;\n report += `- **Valor**: ${leadValue}\\n`;\n report += `- **Status**: ${lead.stage?.name || 'Sem status'}\\n`;\n report += `- **Criado em**: ${createdAt}\\n\\n`;\n });\n }\n \n // Leads de Alto Valor\n if (metrics.high_value_leads_details.length > 0) {\n report += `## 💎 Leads de Alto Valor (≥ R$ 5.000)\\n\\n`;\n metrics.high_value_leads_details.forEach((lead, index) => {\n const leadValue = formatCurrency(lead.lead_value);\n const contactName = lead.person?.name || 'Nome não informado';\n \n report += `### ${index + 1}. ${lead.title || 'Lead sem título'}\\n`;\n report += `- **Contato**: ${contactName}\\n`;\n report += `- **Valor**: ${leadValue}\\n`;\n report += `- **Status**: ${lead.stage?.name || 'Sem status'}\\n\\n`;\n });\n }\n \n // Análise e Recomendações\n report += `## 🎯 Análise e Recomendações\\n\\n`;\n \n if (metrics.new_leads_24h === 0) {\n report += `⚠️ **Atenção**: Nenhum novo lead nas últimas 24h. Revisar estratégias de captação.\\n\\n`;\n } else if (metrics.new_leads_24h >= 10) {\n report += `🎉 **Excelente**: Ótimo volume de novos leads! Manter estratégias atuais.\\n\\n`;\n }\n \n if (metrics.high_value_leads > 0) {\n report += `💰 **Prioridade**: ${metrics.high_value_leads} leads de alto valor precisam de atenção especial.\\n\\n`;\n }\n \n if (parseFloat(metrics.conversion_rate) < 10) {\n report += `📈 **Oportunidade**: Taxa de conversão pode ser melhorada (atual: ${metrics.conversion_rate}%).\\n\\n`;\n }\n \n // Rodapé\n report += `---\\n\\n`;\n report += `*Relatório gerado automaticamente pelo sistema N8N*\\n`;\n report += `*Dados obtidos do Krayin CRM em ${new Date().toLocaleString('pt-BR')}*\\n`;\n \n return report;\n};\n\nconst reportData = {\n markdown_report: generateReport(),\n json_metrics: metrics,\n filename: `relatorio-crm-${config.file_date}.md`,\n json_filename: `metricas-crm-${config.file_date}.json`,\n timestamp: new Date().toISOString()\n};\n\nreturn reportData;" }, "id": "generate-report", "name": "Gerar Relatório", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [1120, 300] }, { "parameters": { "mode": "write", "fileName": "/tmp/reports/{{$node[\"Gerar Relatório\"].json[\"filename\"]}}", "fileContent": "={{$node[\"Gerar Relatório\"].json[\"markdown_report\"]}}" }, "id": "save-markdown-report", "name": "Salvar Relatório MD", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [1340, 200] }, { "parameters": { "mode": "write", "fileName": "/tmp/reports/{{$node[\"Gerar Relatório\"].json[\"json_filename\"]}}", "fileContent": "={{JSON.stringify($node[\"Gerar Relatório\"].json[\"json_metrics\"], null, 2)}}" }, "id": "save-json-metrics", "name": "Salvar Métricas JSON", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [1340, 400] }, { "parameters": { "jsCode": "// Gerar log da execução do relatório\nconst reportData = $node[\"Gerar Relatório\"].json;\nconst metrics = reportData.json_metrics;\n\nconst logEntry = {\n timestamp: new Date().toISOString(),\n action: 'DAILY_REPORT_GENERATED',\n report_date: metrics.config.report_date,\n new_leads_24h: metrics.new_leads_24h,\n new_contacts_24h: metrics.new_contacts_24h,\n total_leads: metrics.total_leads,\n total_lead_value: metrics.total_lead_value,\n high_value_leads: metrics.high_value_leads,\n conversion_rate: metrics.conversion_rate,\n files_created: [\n reportData.filename,\n reportData.json_filename\n ],\n status: 'SUCCESS'\n};\n\nreturn logEntry;" }, "id": "log-report-generation", "name": "Log Geração Relatório", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [1560, 300] }, { "parameters": { "mode": "append", "fileName": "/tmp/daily-reports-log.txt", "fileContent": "={{JSON.stringify($node[\"Log Geração Relatório\"].json, null, 2)}}\n---\n" }, "id": "save-report-log", "name": "Salvar Log Relatório", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [1780, 300] } ], "connections": { "Trigger Relatório 18h": { "main": [ [ { "node": "Configurar Relatório", "type": "main", "index": 0 } ] ] }, "Configurar Relatório": { "main": [ [ { "node": "Buscar Leads", "type": "main", "index": 0 }, { "node": "Buscar Contatos", "type": "main", "index": 0 } ] ] }, "Buscar Leads": { "main": [ [ { "node": "Processar Dados CRM", "type": "main", "index": 0 } ] ] }, "Buscar Contatos": { "main": [ [ { "node": "Processar Dados CRM", "type": "main", "index": 0 } ] ] }, "Processar Dados CRM": { "main": [ [ { "node": "Gerar Relatório", "type": "main", "index": 0 } ] ] }, "Gerar Relatório": { "main": [ [ { "node": "Salvar Relatório MD", "type": "main", "index": 0 }, { "node": "Salvar Métricas JSON", "type": "main", "index": 0 }, { "node": "Log Geração Relatório", "type": "main", "index": 0 } ] ] }, "Salvar Relatório MD": { "main": [ [ { "node": "Log Geração Relatório", "type": "main", "index": 0 } ] ] }, "Salvar Métricas JSON": { "main": [ [ { "node": "Log Geração Relatório", "type": "main", "index": 0 } ] ] }, "Log Geração Relatório": { "main": [ [ { "node": "Salvar Log Relatório", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": {}, "versionId": "1", "meta": { "instanceId": "relatorio-crm-local" }, "id": "5", "tags": [ "Relatório", "CRM", "Diário", "Local", "Sem Slack" ] }