{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "75e590c0-8032-41b7-b40b-434381e835f4",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3184,
        -944
      ],
      "parameters": {
        "width": 592,
        "height": 812,
        "content": "## How it works\n\nThis workflow automates month-end financial reporting with AI-powered insights. It runs automatically on the 1st of each month, pulls P&L data from your accounting system for current and previous periods, performs variance analysis, calculates a financial health score (0-100), and identifies anomalies (>20% revenue swings, >15% expense growth, >25% budget variances). AI generates an executive summary with top concerns and actionable recommendations. Critical reports (health <50 or 3+ anomalies) route through CFO approval. The system creates a comprehensive PDF with color-coded metrics, archives it to Drive, emails stakeholders, and sends context-aware Slack alerts.\n\n## Setup steps\n\n1. **Connect accounting system API** - Update URLs in both \"Fetch P&L\" nodes (QuickBooks/Xero/NetSuite)\n2. **Add authentication** - Configure API credentials for accounting system\n3. **Add OpenAI API key** - For AI financial insights (GPT-4 recommended)\n4. **Set thresholds** - Adjust anomaly detection limits in \"Analyze Financial Data\" if needed\n5. **Add HTML to PDF API** - Get key at htmlcsstoimage.com\n6. **Connect Google Drive** - Authenticate for report archival\n7. **Connect Gmail** - Authenticate for stakeholder emails and CFO approvals\n8. **Add Slack webhook** - Get URL from Slack for team notifications\n9. **Configure stakeholders** - Edit recipient list in \"Prepare Report Data\" node\n10. **Test manually first** - Use \"Execute Workflow\" before enabling monthly schedule\n\n\ud83d\udca1 **Required:** Accounting system API access with P&L data endpoints"
      },
      "typeVersion": 1
    },
    {
      "id": "ba296fdd-51e1-4c90-8ede-35ad61194683",
      "name": "Schedule Monthly",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -2144,
        16
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9 1 * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3d60a7b7-ab0d-4a3b-981e-61a06a9d0c51",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2192,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 772,
        "height": 480,
        "content": "## Scheduling & Data Collection\n\nRuns automatically 1st of month at 9 AM. Calculates previous month date range, pulls P&L data from accounting system for current and comparison periods, then merges datasets for analysis."
      },
      "typeVersion": 1
    },
    {
      "id": "4fadddfd-26a8-4abb-bb78-2f8f50e68889",
      "name": "Calculate Period",
      "type": "n8n-nodes-base.code",
      "position": [
        -1984,
        16
      ],
      "parameters": {
        "jsCode": "// Calculate reporting period (previous month)\nconst now = new Date();\nconst lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);\nconst startDate = new Date(lastMonth.getFullYear(), lastMonth.getMonth(), 1);\nconst endDate = new Date(lastMonth.getFullYear(), lastMonth.getMonth() + 1, 0);\n\n// Previous period for comparison\nconst prevStartDate = new Date(lastMonth.getFullYear(), lastMonth.getMonth() - 1, 1);\nconst prevEndDate = new Date(lastMonth.getFullYear(), lastMonth.getMonth(), 0);\n\nconst formatDate = (date) => date.toISOString().split('T')[0];\n\nreturn {\n  json: {\n    reportPeriod: {\n      startDate: formatDate(startDate),\n      endDate: formatDate(endDate),\n      month: lastMonth.toLocaleString('en-US', { month: 'long' }),\n      year: lastMonth.getFullYear()\n    },\n    previousPeriod: {\n      startDate: formatDate(prevStartDate),\n      endDate: formatDate(prevEndDate)\n    },\n    reportDate: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "d1295137-29b7-4dc3-b287-29c1ccf1663a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1360,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 772,
        "height": 560,
        "content": "## Financial Analysis & AI\n\nCalculates growth rates, identifies anomalies (revenue swings, expense increases, budget variances), computes 0-100 health score. AI generates executive summary with top concerns and actionable recommendations based on financial patterns."
      },
      "typeVersion": 1
    },
    {
      "id": "162844f9-0294-4706-ae80-b84509e3daec",
      "name": "Fetch Current P&L",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1760,
        -64
      ],
      "parameters": {
        "url": "https://api.youraccounting.com/reports/pl",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "start_date",
              "value": "={{ $json.reportPeriod.startDate }}"
            },
            {
              "name": "end_date",
              "value": "={{ $json.reportPeriod.endDate }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "a0a5ca76-2740-4d96-889f-86d0f22aebe0",
      "name": "Fetch Previous P&L",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1760,
        112
      ],
      "parameters": {
        "url": "https://api.youraccounting.com/reports/pl",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "start_date",
              "value": "={{ $json.previousPeriod.startDate }}"
            },
            {
              "name": "end_date",
              "value": "={{ $json.previousPeriod.endDate }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "348b6eea-74da-4384-a125-4d4ce6da20ab",
      "name": "Merge Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        -1552,
        16
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "809d6f3f-469b-49ef-b664-6e99f4bf955f",
      "name": "Analyze Financial Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -1328,
        16
      ],
      "parameters": {
        "jsCode": "// Process and analyze financial data\nconst item = $input.first().json;\n\n// Extract current period data\nconst current = item[0];\nconst previous = item[1];\n\n// Calculate key metrics\nconst revenue = parseFloat(current.revenue) || 0;\nconst expenses = parseFloat(current.expenses) || 0;\nconst netIncome = revenue - expenses;\n\nconst prevRevenue = parseFloat(previous.revenue) || 0;\nconst prevExpenses = parseFloat(previous.expenses) || 0;\nconst prevNetIncome = prevRevenue - prevExpenses;\n\n// Growth calculations\nconst revenueGrowth = prevRevenue > 0 ? ((revenue - prevRevenue) / prevRevenue * 100) : 0;\nconst expenseGrowth = prevExpenses > 0 ? ((expenses - prevExpenses) / prevExpenses * 100) : 0;\nconst incomeGrowth = prevNetIncome !== 0 ? ((netIncome - prevNetIncome) / Math.abs(prevNetIncome) * 100) : 0;\n\n// Process expense categories\nconst categories = (current.categories || []).map(cat => {\n  const actual = parseFloat(cat.actual) || 0;\n  const budget = parseFloat(cat.budget) || 0;\n  const variance = actual - budget;\n  const variancePercent = budget > 0 ? (variance / budget * 100) : 0;\n  \n  return {\n    name: cat.name,\n    actual,\n    budget,\n    variance,\n    variancePercent,\n    isOverBudget: variance > 0\n  };\n});\n\n// Identify anomalies\nconst anomalies = [];\n\nif (Math.abs(revenueGrowth) > 20) {\n  anomalies.push({\n    type: 'revenue',\n    severity: 'high',\n    message: `Revenue ${revenueGrowth > 0 ? 'increased' : 'decreased'} by ${Math.abs(revenueGrowth).toFixed(1)}% (>20% threshold)`\n  });\n}\n\nif (expenseGrowth > 15) {\n  anomalies.push({\n    type: 'expense',\n    severity: 'medium',\n    message: `Expenses increased by ${expenseGrowth.toFixed(1)}% (>15% threshold)`\n  });\n}\n\ncategories.forEach(cat => {\n  if (Math.abs(cat.variancePercent) > 25) {\n    anomalies.push({\n      type: 'budget_variance',\n      severity: 'medium',\n      message: `${cat.name}: ${Math.abs(cat.variancePercent).toFixed(1)}% ${cat.isOverBudget ? 'over' : 'under'} budget`\n    });\n  }\n});\n\n// Calculate health score (0-100)\nlet healthScore = 50;\nif (netIncome > 0) healthScore += 20;\nif (revenueGrowth > 0) healthScore += 15;\nif (expenseGrowth < 5) healthScore += 10;\nif (anomalies.length === 0) healthScore += 5;\n\nconst healthStatus = healthScore >= 80 ? 'Excellent' : \n                     healthScore >= 60 ? 'Good' : \n                     healthScore >= 40 ? 'Fair' : 'Concerning';\n\nreturn {\n  json: {\n    reportPeriod: item[0].reportPeriod || { startDate: '', endDate: '' },\n    revenue,\n    expenses,\n    netIncome,\n    previousPeriod: {\n      revenue: prevRevenue,\n      expenses: prevExpenses,\n      netIncome: prevNetIncome\n    },\n    revenueGrowth,\n    expenseGrowth,\n    incomeGrowth,\n    grossMargin: revenue > 0 ? ((revenue - expenses) / revenue * 100) : 0,\n    categories,\n    anomalies,\n    anomalyCount: anomalies.length,\n    healthScore,\n    healthStatus,\n    requiresReview: anomalies.length > 2 || healthScore < 50\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "c4fc1a69-1c4a-4d5e-a08d-062e1ef92f7e",
      "name": "Prepare AI Context",
      "type": "n8n-nodes-base.set",
      "position": [
        -1136,
        16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ai_context",
              "name": "aiContext",
              "type": "string",
              "value": "=Financial Performance Analysis:\n\nPeriod: {{ $json.reportPeriod.startDate }} to {{ $json.reportPeriod.endDate }}\n\nKey Metrics:\n- Revenue: ${{ $json.revenue }}\n- Expenses: ${{ $json.expenses }}\n- Net Income: ${{ $json.netIncome }}\n- Gross Margin: {{ $json.grossMargin }}%\n\nGrowth vs Previous Period:\n- Revenue Growth: {{ $json.revenueGrowth }}%\n- Expense Growth: {{ $json.expenseGrowth }}%\n- Income Growth: {{ $json.incomeGrowth }}%\n\nAnomalies Detected:\n{{ $json.anomalies.map(a => `- ${a.message}`).join('\\n') }}\n\nBudget Variances:\n{{ $json.categories.filter(c => Math.abs(c.variancePercent) > 10).map(c => `- ${c.name}: ${c.variancePercent.toFixed(1)}% ${c.isOverBudget ? 'over' : 'under'} budget`).join('\\n') }}\n\nHealth Score: {{ $json.healthScore }}/100 ({{ $json.healthStatus }})\n\nProvide:\n1. Executive summary (2-3 sentences)\n2. Top 3 insights or concerns\n3. 2-3 actionable recommendations\n\nRespond in JSON format:\n{\n  \"executiveSummary\": \"...\",\n  \"insights\": [\"...\", \"...\", \"...\"],\n  \"recommendations\": [\"...\", \"...\"]\n}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d0cc42c4-d749-4788-88ab-bbd54aa5c6de",
      "name": "AI Financial Insights",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -992,
        16
      ],
      "parameters": {
        "text": "={{ $json.aiContext }}",
        "agent": "conversationalAgent",
        "options": {
          "systemMessage": "You are a CFO advisor analyzing financial reports. Provide concise, actionable insights. Always respond with valid JSON only."
        },
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "8280b6ba-dfdf-4616-9cad-7ef4c55b3480",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -1008,
        224
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4-turbo"
        },
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "52e07a1f-6391-4ba8-8947-482091a2de85",
      "name": "Prepare Report Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -720,
        16
      ],
      "parameters": {
        "jsCode": "// Parse AI insights and prepare report data\nconst item = $input.first().json;\nconst analysisData = $('Analyze Financial Data').first().json;\n\n// Parse AI response\nlet aiInsights;\ntry {\n  const aiResponse = item.output || item.text || '{}';\n  const cleanResponse = aiResponse.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n  aiInsights = JSON.parse(cleanResponse);\n} catch (e) {\n  aiInsights = {\n    executiveSummary: 'Financial analysis complete. Review detailed metrics below.',\n    insights: ['Data successfully processed'],\n    recommendations: ['Continue monitoring key metrics']\n  };\n}\n\n// Company defaults\nconst companyData = {\n  companyName: 'Media Jade',\n  companyLogo: '',\n  reportTitle: 'Monthly Financial Report',\n  fiscalYear: new Date().getFullYear(),\n  preparedBy: 'Finance Department',\n  preparedByEmail: 'user@example.com',\n  currency: 'USD',\n  currencySymbol: '$',\n  stakeholders: [\n    { name: 'CEO', email: 'user@example.com' },\n    { name: 'CFO', email: 'user@example.com' }\n  ]\n};\n\n// Generate report ID\nconst date = new Date();\nconst reportId = `FIN-${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}-${Math.floor(Math.random() * 1000)}`;\n\n// Format dates\nconst formatDate = (dateStr) => {\n  return new Date(dateStr).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n};\n\nconst reportPeriod = analysisData.reportPeriod;\n\nreturn {\n  json: {\n    ...companyData,\n    ...analysisData,\n    aiInsights,\n    reportId,\n    reportDate: formatDate(new Date().toISOString()),\n    reportPeriod: {\n      ...reportPeriod,\n      startDateFormatted: formatDate(reportPeriod.startDate),\n      endDateFormatted: formatDate(reportPeriod.endDate)\n    }\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "16a34652-a2ad-4825-9e3d-922a2ba2f34b",
      "name": "Requires CFO Review?",
      "type": "n8n-nodes-base.if",
      "position": [
        -480,
        -96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "anomaly_check",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.requiresReview }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "2e0787d2-c462-4cfa-83cb-cfca657a1770",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 600,
        "height": 456,
        "content": "## Report Generation & Distribution\n\nCreates comprehensive PDF with health score banner, AI insights, anomaly alerts, P&L comparison, and budget variance analysis. Archives to Drive, then emails stakeholders (CEO, CFO, Board)."
      },
      "typeVersion": 1
    },
    {
      "id": "cabdec02-e1e2-41c6-b049-69b24cc3bc77",
      "name": "Request CFO Review",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -272,
        -96
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "77a0a0a1-c49e-4541-b5aa-e8ea9e4a02fb",
      "name": "Generate Report HTML",
      "type": "n8n-nodes-base.code",
      "position": [
        -208,
        256
      ],
      "parameters": {
        "jsCode": "// Generate comprehensive financial report HTML\nconst item = $input.first().json;\n\nconst formatCurrency = (amount) => {\n  return `${item.currencySymbol}${Math.abs(amount).toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`;\n};\n\nconst formatPercent = (value) => {\n  return `${value >= 0 ? '+' : ''}${value.toFixed(1)}%`;\n};\n\nconst getVarianceClass = (variance) => {\n  if (variance > 0) return 'negative';\n  if (variance < 0) return 'positive';\n  return 'neutral';\n};\n\nconst getHealthColor = (score) => {\n  if (score >= 80) return 'success';\n  if (score >= 60) return 'warning';\n  return 'danger';\n};\n\nconst html = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>${item.reportTitle} - ${item.reportId}</title>\n    <style>\n        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');\n        * { margin: 0; padding: 0; box-sizing: border-box; }\n        body { font-family: 'Inter', sans-serif; line-height: 1.6; color: #1f2937; background: #fff; }\n        .container { max-width: 1000px; margin: 0 auto; padding: 40px; }\n        .header { text-align: center; margin-bottom: 40px; padding-bottom: 25px; border-bottom: 4px solid #3b82f6; }\n        .report-title { color: #1e40af; font-size: 32px; font-weight: 700; margin-bottom: 10px; }\n        .report-subtitle { color: #6b7280; font-size: 16px; margin-bottom: 8px; }\n        .report-period { color: #3b82f6; font-size: 18px; font-weight: 600; }\n        \n        .health-banner { padding: 25px; border-radius: 12px; margin-bottom: 30px; text-align: center; }\n        .health-banner.success { background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%); border: 3px solid #10b981; }\n        .health-banner.warning { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); border: 3px solid #f59e0b; }\n        .health-banner.danger { background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); border: 3px solid #ef4444; }\n        .health-score { font-size: 48px; font-weight: 700; margin-bottom: 10px; }\n        .health-status { font-size: 20px; font-weight: 600; }\n        \n        .metrics-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-bottom: 40px; }\n        .metric-card { background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); padding: 25px; border-radius: 12px; border: 2px solid #93c5fd; text-align: center; }\n        .metric-card.success { background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); border-color: #86efac; }\n        .metric-card.warning { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); border-color: #fcd34d; }\n        .metric-card.danger { background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); border-color: #fca5a5; }\n        .metric-label { font-size: 13px; color: #6b7280; font-weight: 600; text-transform: uppercase; margin-bottom: 10px; }\n        .metric-value { font-size: 32px; font-weight: 700; color: #1e40af; margin-bottom: 8px; }\n        .metric-change { font-size: 14px; font-weight: 600; }\n        .positive { color: #16a34a; }\n        .negative { color: #dc2626; }\n        .neutral { color: #6b7280; }\n        \n        .ai-insights { background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%); padding: 30px; border-radius: 12px; border-left: 6px solid #a855f7; margin-bottom: 40px; }\n        .ai-insights h2 { color: #7e22ce; font-size: 22px; font-weight: 700; margin-bottom: 20px; }\n        .ai-insights .summary { color: #6b21a8; font-size: 16px; line-height: 1.8; margin-bottom: 20px; padding: 15px; background: rgba(255,255,255,0.6); border-radius: 8px; }\n        .insight-section { margin-bottom: 20px; }\n        .insight-section h3 { color: #7e22ce; font-size: 16px; font-weight: 700; margin-bottom: 12px; }\n        .insight-section ul { padding-left: 25px; }\n        .insight-section li { color: #6b21a8; font-size: 14px; margin-bottom: 8px; line-height: 1.6; }\n        \n        .anomaly-section { background: #fef2f2; padding: 25px; border-radius: 12px; border-left: 6px solid #dc2626; margin-bottom: 40px; }\n        .anomaly-section h2 { color: #991b1b; font-size: 20px; font-weight: 700; margin-bottom: 15px; }\n        .anomaly-item { background: white; padding: 15px; border-radius: 8px; margin-bottom: 10px; border-left: 4px solid #ef4444; }\n        .anomaly-item .severity { display: inline-block; padding: 4px 12px; border-radius: 12px; font-size: 11px; font-weight: 700; color: white; margin-bottom: 8px; }\n        .anomaly-item .severity.high { background: #dc2626; }\n        .anomaly-item .severity.medium { background: #f59e0b; }\n        .anomaly-item .message { color: #991b1b; font-size: 14px; }\n        \n        .section { margin-bottom: 40px; }\n        .section-title { color: #1e40af; font-size: 22px; font-weight: 700; margin-bottom: 20px; padding-bottom: 12px; border-bottom: 3px solid #dbeafe; }\n        \n        .financial-table { width: 100%; border-collapse: separate; border-spacing: 0; margin-bottom: 30px; box-shadow: 0 4px 6px rgba(0,0,0,0.07); border-radius: 12px; overflow: hidden; }\n        .financial-table thead { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); }\n        .financial-table th { padding: 16px; text-align: left; font-weight: 600; font-size: 13px; color: white; text-transform: uppercase; }\n        .financial-table tbody tr { background: white; }\n        .financial-table tbody tr:nth-child(even) { background: #f9fafb; }\n        .financial-table td { padding: 14px 16px; border-bottom: 1px solid #e5e7eb; font-size: 14px; color: #374151; }\n        .financial-table tbody tr:last-child td { border-bottom: none; }\n        .text-right { text-align: right; }\n        .text-bold { font-weight: 700; }\n        .total-row { background: #eff6ff !important; font-weight: 700; font-size: 16px; }\n        \n        .footer { margin-top: 50px; padding-top: 25px; border-top: 3px solid #e5e7eb; text-align: center; color: #6b7280; font-size: 13px; }\n        @media print { body { print-color-adjust: exact; -webkit-print-color-adjust: exact; } }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <div class=\"header\">\n            <h1 class=\"report-title\">${item.reportTitle}</h1>\n            <p class=\"report-subtitle\">${item.companyName}</p>\n            <p class=\"report-period\">${item.reportPeriod.startDateFormatted} - ${item.reportPeriod.endDateFormatted}</p>\n        </div>\n\n        <div class=\"health-banner ${getHealthColor(item.healthScore)}\">\n            <div class=\"health-score\">${item.healthScore}/100</div>\n            <div class=\"health-status\">Financial Health: ${item.healthStatus}</div>\n        </div>\n\n        <div class=\"metrics-grid\">\n            <div class=\"metric-card ${item.revenue >= item.previousPeriod.revenue ? 'success' : 'warning'}\">\n                <div class=\"metric-label\">Total Revenue</div>\n                <div class=\"metric-value\">${formatCurrency(item.revenue)}</div>\n                <div class=\"metric-change ${item.revenueGrowth >= 0 ? 'positive' : 'negative'}\">${formatPercent(item.revenueGrowth)} vs last month</div>\n            </div>\n            <div class=\"metric-card ${item.expenses <= item.previousPeriod.expenses ? 'success' : 'warning'}\">\n                <div class=\"metric-label\">Total Expenses</div>\n                <div class=\"metric-value\">${formatCurrency(item.expenses)}</div>\n                <div class=\"metric-change ${item.expenseGrowth <= 0 ? 'positive' : 'negative'}\">${formatPercent(item.expenseGrowth)} vs last month</div>\n            </div>\n            <div class=\"metric-card ${item.netIncome >= 0 ? 'success' : 'danger'}\">\n                <div class=\"metric-label\">Net Income</div>\n                <div class=\"metric-value\">${formatCurrency(item.netIncome)}</div>\n                <div class=\"metric-change ${item.incomeGrowth >= 0 ? 'positive' : 'negative'}\">${formatPercent(item.incomeGrowth)} vs last month</div>\n            </div>\n        </div>\n\n        ${item.aiInsights ? `\n        <div class=\"ai-insights\">\n            <h2>\ud83e\udd16 AI-Powered Executive Insights</h2>\n            <div class=\"summary\">${item.aiInsights.executiveSummary}</div>\n            \n            ${item.aiInsights.insights && item.aiInsights.insights.length > 0 ? `\n            <div class=\"insight-section\">\n                <h3>Key Insights</h3>\n                <ul>\n                    ${item.aiInsights.insights.map(insight => `<li>${insight}</li>`).join('')}\n                </ul>\n            </div>\n            ` : ''}\n            \n            ${item.aiInsights.recommendations && item.aiInsights.recommendations.length > 0 ? `\n            <div class=\"insight-section\">\n                <h3>Recommended Actions</h3>\n                <ul>\n                    ${item.aiInsights.recommendations.map(rec => `<li>${rec}</li>`).join('')}\n                </ul>\n            </div>\n            ` : ''}\n        </div>\n        ` : ''}\n\n        ${item.anomalies && item.anomalies.length > 0 ? `\n        <div class=\"anomaly-section\">\n            <h2>\u26a0\ufe0f Anomalies & Alerts (${item.anomalyCount})</h2>\n            ${item.anomalies.map(anomaly => `\n            <div class=\"anomaly-item\">\n                <span class=\"severity ${anomaly.severity}\">${anomaly.severity.toUpperCase()}</span>\n                <div class=\"message\">${anomaly.message}</div>\n            </div>\n            `).join('')}\n        </div>\n        ` : ''}\n\n        <div class=\"section\">\n            <h2 class=\"section-title\">Profit & Loss Statement</h2>\n            <table class=\"financial-table\">\n                <thead>\n                    <tr>\n                        <th>Item</th>\n                        <th class=\"text-right\">Current Period</th>\n                        <th class=\"text-right\">Previous Period</th>\n                        <th class=\"text-right\">Change</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr>\n                        <td class=\"text-bold\">Revenue</td>\n                        <td class=\"text-right text-bold\">${formatCurrency(item.revenue)}</td>\n                        <td class=\"text-right\">${formatCurrency(item.previousPeriod.revenue)}</td>\n                        <td class=\"text-right ${item.revenueGrowth >= 0 ? 'positive' : 'negative'}\">${formatPercent(item.revenueGrowth)}</td>\n                    </tr>\n                    <tr>\n                        <td class=\"text-bold\">Expenses</td>\n                        <td class=\"text-right text-bold\">${formatCurrency(item.expenses)}</td>\n                        <td class=\"text-right\">${formatCurrency(item.previousPeriod.expenses)}</td>\n                        <td class=\"text-right ${item.expenseGrowth <= 0 ? 'positive' : 'negative'}\">${formatPercent(item.expenseGrowth)}</td>\n                    </tr>\n                    <tr class=\"total-row\">\n                        <td class=\"text-bold\">Net Income</td>\n                        <td class=\"text-right text-bold\">${formatCurrency(item.netIncome)}</td>\n                        <td class=\"text-right\">${formatCurrency(item.previousPeriod.netIncome)}</td>\n                        <td class=\"text-right ${item.incomeGrowth >= 0 ? 'positive' : 'negative'}\">${formatPercent(item.incomeGrowth)}</td>\n                    </tr>\n                </tbody>\n            </table>\n        </div>\n\n        ${item.categories && item.categories.length > 0 ? `\n        <div class=\"section\">\n            <h2 class=\"section-title\">Budget vs Actual Analysis</h2>\n            <table class=\"financial-table\">\n                <thead>\n                    <tr>\n                        <th>Category</th>\n                        <th class=\"text-right\">Budget</th>\n                        <th class=\"text-right\">Actual</th>\n                        <th class=\"text-right\">Variance</th>\n                        <th class=\"text-right\">Variance %</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    ${item.categories.map(cat => `\n                    <tr>\n                        <td>${cat.name}</td>\n                        <td class=\"text-right\">${formatCurrency(cat.budget)}</td>\n                        <td class=\"text-right\">${formatCurrency(cat.actual)}</td>\n                        <td class=\"text-right ${getVarianceClass(cat.variance)}\">${formatCurrency(cat.variance)}</td>\n                        <td class=\"text-right ${getVarianceClass(cat.variance)}\">${formatPercent(cat.variancePercent)}</td>\n                    </tr>\n                    `).join('')}\n                </tbody>\n            </table>\n        </div>\n        ` : ''}\n\n        <div class=\"footer\">\n            <p><strong>Report ID:</strong> ${item.reportId} | <strong>Generated:</strong> ${item.reportDate}</p>\n            <p><strong>Prepared by:</strong> ${item.preparedBy} (${item.preparedByEmail})</p>\n            <p style=\"margin-top: 15px;\">This report is confidential and intended for internal use only.</p>\n        </div>\n    </div>\n</body>\n</html>\n`;\n\nreturn {\n  json: {\n    html,\n    fileName: `Financial_Report_${item.reportId}_${item.reportPeriod.startDate.replace(/[^0-9]/g, '')}.pdf`,\n    ...item\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "69ba81c6-33ea-43d9-9730-ce61524a51cf",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -528,
        -304
      ],
      "parameters": {
        "color": 7,
        "width": 408,
        "height": 388,
        "content": "## Approval Routing\n\nRoutes critical reports (health <50 or 3+ anomalies) through CFO email approval before distribution. Normal reports auto-proceed to generation, ensuring executive oversight of concerning financials."
      },
      "typeVersion": 1
    },
    {
      "id": "bebab518-94f2-4a1c-b3b2-279974176934",
      "name": "HTML to PDF",
      "type": "n8n-nodes-htmlcsstopdf.htmlcsstopdf",
      "position": [
        -32,
        256
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "eaea604b-a54f-45c5-9b63-002f71d2a6ed",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 476,
        "height": 552,
        "content": "## Context-Aware Alerts\n\nRoutes Slack notifications based on health score. Critical alerts (health <60) get urgent format with immediate attention flag. Normal reports get standard summary notification with key metrics."
      },
      "typeVersion": 1
    },
    {
      "id": "d7b63343-be96-4c39-aa56-b3839fb6bfa7",
      "name": "Save to Google Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        176,
        256
      ],
      "parameters": {
        "name": "={{ $('Generate Report HTML').item.json.fileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "0d310ef0-aaf4-4d5a-b2b8-4af8a23f4d5e",
      "name": "Send to Stakeholders",
      "type": "n8n-nodes-base.gmail",
      "position": [
        192,
        416
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "5d705049-c3a6-4e0b-ada2-9a35354962d5",
      "name": "Health Critical?",
      "type": "n8n-nodes-base.if",
      "position": [
        448,
        128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "health_check",
              "operator": {
                "type": "number",
                "operation": "lt"
              },
              "leftValue": "={{ $json.healthScore }}",
              "rightValue": "60"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "44edaca0-752e-4a5f-8367-b14d83ed806e",
      "name": "Alert - Critical",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        656,
        16
      ],
      "parameters": {
        "url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
        "options": {},
        "jsonBody": "={\n  \"text\": \"\u26a0\ufe0f CRITICAL: Financial Report Alert\",\n  \"blocks\": [\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*\u26a0\ufe0f CRITICAL Financial Alert*\\n\\n*Report:* {{ $('Generate Report HTML').item.json.reportId }}\\n*Period:* {{ $('Generate Report HTML').item.json.reportPeriod.startDateFormatted }} - {{ $('Generate Report HTML').item.json.reportPeriod.endDateFormatted }}\\n\\n*Health Score:* {{ $('Generate Report HTML').item.json.healthScore }}/100 ({{ $('Generate Report HTML').item.json.healthStatus }})\\n\\n*Key Metrics:*\\n\u2022 Revenue: {{ $('Generate Report HTML').item.json.currencySymbol }}{{ $('Generate Report HTML').item.json.revenue }} ({{ $('Generate Report HTML').item.json.revenueGrowth }}%)\\n\u2022 Net Income: {{ $('Generate Report HTML').item.json.currencySymbol }}{{ $('Generate Report HTML').item.json.netIncome }} ({{ $('Generate Report HTML').item.json.incomeGrowth }}%)\\n\\n*Anomalies Detected:* {{ $('Generate Report HTML').item.json.anomalyCount }}\\n\\n<{{ $('Save to Google Drive').item.json.webViewLink }}|View Full Report>\\n\\n\ud83d\udea8 *Immediate attention required*\"\n      }\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.1
    },
    {
      "id": "81b5729a-368f-49cf-9e17-8bcd5999b309",
      "name": "Notify - Standard",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        656,
        224
      ],
      "parameters": {
        "url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
        "options": {},
        "jsonBody": "={\n  \"text\": \"\ud83d\udcca Monthly Financial Report Published\",\n  \"blocks\": [\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*\ud83d\udcca Financial Report Published*\\n\\n*Report:* {{ $('Generate Report HTML').item.json.reportId }}\\n*Period:* {{ $('Generate Report HTML').item.json.reportPeriod.startDateFormatted }} - {{ $('Generate Report HTML').item.json.reportPeriod.endDateFormatted }}\\n\\n*Health Score:* {{ $('Generate Report HTML').item.json.healthScore }}/100 ({{ $('Generate Report HTML').item.json.healthStatus }})\\n\\n*Financial Summary:*\\n\u2022 Revenue: {{ $('Generate Report HTML').item.json.currencySymbol }}{{ $('Generate Report HTML').item.json.revenue }} ({{ $('Generate Report HTML').item.json.revenueGrowth }}% MoM)\\n\u2022 Expenses: {{ $('Generate Report HTML').item.json.currencySymbol }}{{ $('Generate Report HTML').item.json.expenses }} ({{ $('Generate Report HTML').item.json.expenseGrowth }}% MoM)\\n\u2022 Net Income: {{ $('Generate Report HTML').item.json.currencySymbol }}{{ $('Generate Report HTML').item.json.netIncome }} ({{ $('Generate Report HTML').item.json.incomeGrowth }}% MoM)\\n\\n<{{ $('Save to Google Drive').item.json.webViewLink }}|View Report>\"\n      }\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.1
    }
  ],
  "connections": {
    "Merge Data": {
      "main": [
        [
          {
            "node": "Analyze Financial Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTML to PDF": {
      "main": [
        [
          {
            "node": "Save to Google Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Period": {
      "main": [
        [
          {
            "node": "Fetch Current P&L",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Previous P&L",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Health Critical?": {
      "main": [
        [
          {
            "node": "Alert - Critical",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify - Standard",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Monthly": {
      "main": [
        [
          {
            "node": "Calculate Period",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Current P&L": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Financial Insights",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Previous P&L": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Prepare AI Context": {
      "main": [
        [
          {
            "node": "AI Financial Insights",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Request CFO Review": {
      "main": [
        [
          {
            "node": "Generate Report HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Report Data": {
      "main": [
        [
          {
            "node": "Requires CFO Review?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Report HTML": {
      "main": [
        [
          {
            "node": "HTML to PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Requires CFO Review?": {
      "main": [
        [
          {
            "node": "Request CFO Review",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Report HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Google Drive": {
      "main": [
        [
          {
            "node": "Send to Stakeholders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to Stakeholders": {
      "main": [
        [
          {
            "node": "Health Critical?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Financial Insights": {
      "main": [
        [
          {
            "node": "Prepare Report Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze Financial Data": {
      "main": [
        [
          {
            "node": "Prepare AI Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}