From 7a3195d065d7d81ce80b3a88b64e7a2938915d21 Mon Sep 17 00:00:00 2001 From: nusquama Date: Sun, 15 Mar 2026 12:02:10 +0800 Subject: [PATCH] creation --- ...nd_weekly_reports_with_stripe_sheets_slack_and_gemini_ai.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 workflows/Forecast sales trends and weekly reports with Stripe, Sheets, Slack, and Gemini AI-13982/forecast_sales_trends_and_weekly_reports_with_stripe_sheets_slack_and_gemini_ai.json diff --git a/workflows/Forecast sales trends and weekly reports with Stripe, Sheets, Slack, and Gemini AI-13982/forecast_sales_trends_and_weekly_reports_with_stripe_sheets_slack_and_gemini_ai.json b/workflows/Forecast sales trends and weekly reports with Stripe, Sheets, Slack, and Gemini AI-13982/forecast_sales_trends_and_weekly_reports_with_stripe_sheets_slack_and_gemini_ai.json new file mode 100644 index 000000000..a73c58ec9 --- /dev/null +++ b/workflows/Forecast sales trends and weekly reports with Stripe, Sheets, Slack, and Gemini AI-13982/forecast_sales_trends_and_weekly_reports_with_stripe_sheets_slack_and_gemini_ai.json @@ -0,0 +1 @@ +{"meta":{"instanceId":"0fd24758e45cbed1f63c03b9ca7326acab4b855985945af441ee95f8874d3e22","templateCredsSetupCompleted":true},"nodes":[{"id":"ecdc7892-848f-4eb2-9a12-13c8ab982794","name":"Main Overview","type":"n8n-nodes-base.stickyNote","position":[-1424,-192],"parameters":{"width":400,"height":856,"content":"### 📊 Automated Sales Intelligence\n\nTransform your Stripe payment data into actionable business insights with AI-powered analysis and automated reporting.\n\n### How it works\n1. **Data Collection**: Pulls weekly Stripe charges, subscriptions, and refunds\n2. **Historical Context**: Merges with Google Sheets historical data\n3. **Trend Analysis**: Calculates growth rates, MRR, and moving averages\n4. **AI Insights**: Gemini AI analyzes patterns and predicts future performance\n5. **Smart Alerts**: Automatically detects revenue anomalies (±50% variance)\n6. **Multi-Channel Delivery**: Updates Notion dashboard, posts to Slack, emails executives\n\n### Setup steps\n1. Configure Stripe API credentials in HTTP Request nodes\n2. Set Google Sheets ID in Configuration Settings\n3. Update Notion page ID and Slack channel IDs\n4. Test with Gmail SMTP credentials\n5. Customize alert thresholds in Calculate Trends node\n\n**Runs every Monday at 9 AM UTC**\n\nTip: Use the Configuration Settings node to easily update all IDs and credentials in one place."},"typeVersion":1},{"id":"45a117ff-7f57-4abf-b048-feab409ad282","name":"Data Collection Section","type":"n8n-nodes-base.stickyNote","position":[-1008,-192],"parameters":{"color":7,"width":776,"height":848,"content":"## Data collection\nScheduled trigger fetches last 7 days of Stripe data (charges, subscriptions, refunds) and loads historical sales records from Google Sheets."},"typeVersion":1},{"id":"42509b6f-1d0a-4d6f-8e73-608915a3be4c","name":"Processing Section","type":"n8n-nodes-base.stickyNote","position":[-208,-192],"parameters":{"color":7,"width":728,"height":848,"content":"## Processing & analysis\nCode nodes merge and calculate daily totals, trends, MRR estimates. Gemini AI provides comprehensive insights, forecasting, and strategic recommendations."},"typeVersion":1},{"id":"4a159a0a-9c8d-43a2-9469-641a2913b52b","name":"Output Section","type":"n8n-nodes-base.stickyNote","position":[544,-192],"parameters":{"color":7,"width":824,"height":848,"content":"## Output & alerts\nIF node detects significant changes, triggers alerts via Slack. All results logged to Sheets, dashboard updated in Notion, weekly reports sent via Slack and Gmail."},"typeVersion":1},{"id":"93706bae-5717-481d-a844-28e64c41b774","name":"Weekly Sales Analysis","type":"n8n-nodes-base.scheduleTrigger","position":[-960,112],"timezone":"UTC","parameters":{"rule":{"interval":[{}]}},"typeVersion":1.2,"cronExpression":"0 9 * * 1"},{"id":"36fe5b1b-a867-466d-a8d8-9f226a52799b","name":"Get Stripe Charges","type":"n8n-nodes-base.httpRequest","position":[-448,-64],"parameters":{"url":"https://api.stripe.com/v1/charges","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"typeVersion":4.2},{"id":"ee8c3926-ae41-4c4d-a6d4-cdba86ef9a6c","name":"Get Stripe Subscriptions","type":"n8n-nodes-base.httpRequest","position":[-448,112],"parameters":{"url":"https://api.stripe.com/v1/subscriptions","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"typeVersion":4.2},{"id":"7fb94465-a90b-43a9-9dfe-22ee694c1ec2","name":"Get Stripe Refunds","type":"n8n-nodes-base.httpRequest","position":[-448,304],"parameters":{"url":"https://api.stripe.com/v1/refunds","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"typeVersion":4.2},{"id":"71369ccb-0d64-4d3e-a080-76334291270f","name":"Load Historical Sales","type":"n8n-nodes-base.googleSheets","position":[-448,480],"parameters":{"options":{},"sheetName":"Historical_Sales_Data","documentId":"YOUR_SPREADSHEET_ID","authentication":"googleOAuth2Api"},"typeVersion":4.5},{"id":"ab566c7f-8181-40a9-b0e0-160d4ec81db0","name":"Merge and Process Data","type":"n8n-nodes-base.code","position":[-192,112],"parameters":{"jsCode":"// Merge Stripe data with historical data\nconst stripeCharges = $input.first().json.data || [];\nconst subscriptions = $input.all()[1]?.json.data || [];\nconst refunds = $input.all()[2]?.json.data || [];\nconst historicalData = $input.all()[3]?.json.values || [];\n\n// Process charges\nconst chargeData = stripeCharges.map(charge => ({\n date: new Date(charge.created * 1000).toISOString().split('T')[0],\n amount: charge.amount / 100,\n currency: charge.currency,\n customer_id: charge.customer,\n type: 'charge',\n status: charge.status\n}));\n\n// Process subscriptions\nconst subscriptionData = subscriptions.map(sub => ({\n date: new Date(sub.created * 1000).toISOString().split('T')[0],\n amount: sub.items.data[0]?.price?.unit_amount / 100 || 0,\n currency: sub.currency,\n customer_id: sub.customer,\n type: 'subscription',\n status: sub.status,\n interval: sub.items.data[0]?.price?.recurring?.interval\n}));\n\n// Process refunds\nconst refundData = refunds.map(refund => ({\n date: new Date(refund.created * 1000).toISOString().split('T')[0],\n amount: -(refund.amount / 100),\n currency: refund.currency,\n customer_id: refund.charge?.customer,\n type: 'refund',\n status: refund.status\n}));\n\n// Combine all data\nconst allSalesData = [...chargeData, ...subscriptionData, ...refundData];\n\n// Group by date and calculate daily totals\nconst dailyTotals = {};\nallSalesData.forEach(item => {\n if (!dailyTotals[item.date]) {\n dailyTotals[item.date] = {\n date: item.date,\n total_revenue: 0,\n charges: 0,\n subscriptions: 0,\n refunds: 0,\n net_revenue: 0\n };\n }\n \n dailyTotals[item.date].total_revenue += item.amount;\n dailyTotals[item.date][item.type + 's'] += item.amount;\n if (item.type !== 'refund') {\n dailyTotals[item.date].net_revenue += item.amount;\n } else {\n dailyTotals[item.date].net_revenue += item.amount; // Already negative\n }\n});\n\n// Convert to array and sort by date\nconst processedData = Object.values(dailyTotals)\n .sort((a, b) => new Date(a.date) - new Date(b.date));\n\nreturn [{ json: { processed_sales_data: processedData, raw_data: allSalesData } }];"},"typeVersion":2},{"id":"06631c07-3688-4c39-a2b0-86f214c5eee0","name":"Calculate Trends","type":"n8n-nodes-base.code","position":[48,112],"parameters":{"jsCode":"// Calculate trends and metrics\nconst salesData = $json.processed_sales_data;\nconst currentWeekStart = new Date();\ncurrentWeekStart.setDate(currentWeekStart.getDate() - 7);\n\n// Calculate weekly aggregates\nconst currentWeekData = salesData.filter(d => \n new Date(d.date) >= currentWeekStart\n);\n\nconst currentWeekRevenue = currentWeekData.reduce((sum, d) => sum + d.net_revenue, 0);\nconst currentWeekTransactions = currentWeekData.length;\n\n// Calculate previous week for comparison\nconst previousWeekStart = new Date(currentWeekStart);\npreviousWeekStart.setDate(previousWeekStart.getDate() - 7);\nconst previousWeekEnd = new Date(currentWeekStart);\n\nconst previousWeekData = salesData.filter(d => {\n const date = new Date(d.date);\n return date >= previousWeekStart && date < previousWeekEnd;\n});\n\nconst previousWeekRevenue = previousWeekData.reduce((sum, d) => sum + d.net_revenue, 0);\n\n// Calculate growth rate\nconst weekOverWeekGrowth = previousWeekRevenue > 0 ? \n ((currentWeekRevenue - previousWeekRevenue) / previousWeekRevenue) * 100 : 0;\n\n// Calculate moving averages (7-day)\nconst last30Days = salesData.slice(-30);\nconst movingAverage7Day = last30Days.slice(-7)\n .reduce((sum, d) => sum + d.net_revenue, 0) / 7;\n\n// Calculate MRR (Monthly Recurring Revenue) estimate\nconst monthlyData = salesData.slice(-30);\nconst estimatedMRR = monthlyData\n .filter(d => d.date >= new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0])\n .reduce((sum, d) => sum + d.subscriptions, 0);\n\n// Detect anomalies (revenue 50% higher or lower than moving average)\nconst anomalies = [];\nfor (let i = 6; i < salesData.length; i++) {\n const current = salesData[i].net_revenue;\n const avgPrevious7 = salesData.slice(i-7, i)\n .reduce((sum, d) => sum + d.net_revenue, 0) / 7;\n \n if (Math.abs(current - avgPrevious7) / avgPrevious7 > 0.5) {\n anomalies.push({\n date: salesData[i].date,\n value: current,\n expected: avgPrevious7,\n deviation: ((current - avgPrevious7) / avgPrevious7) * 100\n });\n }\n}\n\nconst trendAnalysis = {\n current_week: {\n revenue: Math.round(currentWeekRevenue * 100) / 100,\n transactions: currentWeekTransactions\n },\n previous_week: {\n revenue: Math.round(previousWeekRevenue * 100) / 100\n },\n growth_metrics: {\n week_over_week_growth: Math.round(weekOverWeekGrowth * 100) / 100,\n moving_average_7day: Math.round(movingAverage7Day * 100) / 100,\n estimated_mrr: Math.round(estimatedMRR * 100) / 100\n },\n anomalies: anomalies,\n has_significant_change: Math.abs(weekOverWeekGrowth) > 20\n};\n\nreturn [{ json: trendAnalysis }];"},"typeVersion":2},{"id":"81fb26f5-df51-48b8-9576-09f029b0d05c","name":"Gemini AI Model","type":"@n8n/n8n-nodes-langchain.lmChatGoogleGemini","position":[288,352],"parameters":{"options":{}},"typeVersion":1},{"id":"cc3940c1-8bb0-4719-bf2d-91e506acac33","name":"Generate Sales Analysis","type":"@n8n/n8n-nodes-langchain.chainLlm","position":[288,112],"parameters":{"text":"You are a sales analytics expert. Analyze the following sales data and provide actionable insights.\n\nCurrent week revenue: ${{ $json.current_week.revenue }}\nPrevious week revenue: ${{ $json.previous_week.revenue }}\nWeek-over-week growth: {{ $json.growth_metrics.week_over_week_growth }}%\n7-day moving average: ${{ $json.growth_metrics.moving_average_7day }}\nEstimated MRR: ${{ $json.growth_metrics.estimated_mrr }}\n\nAnomalies detected: {{ $json.anomalies.length }} events\n{% if $json.anomalies.length > 0 %}\nAnomaly details:\n{% for anomaly in $json.anomalies %}\n- {{ anomaly.date }}: ${{ anomaly.value }} ({{ anomaly.deviation }}% deviation)\n{% endfor %}\n{% endif %}\n\nSignificant change detected: {{ $json.has_significant_change }}\n\nProvide a comprehensive analysis in the following JSON format:\n{\n \"executive_summary\": \"Brief 2-3 sentence overview\",\n \"key_insights\": [\"insight 1\", \"insight 2\", \"insight 3\"],\n \"trend_analysis\": \"Detailed trend interpretation\",\n \"forecasting\": {\n \"next_week_prediction\": \"predicted revenue range\",\n \"confidence_level\": \"high/medium/low\",\n \"factors\": [\"factor 1\", \"factor 2\"]\n },\n \"risk_assessment\": {\n \"level\": \"low/medium/high\",\n \"concerns\": [\"concern 1\", \"concern 2\"]\n },\n \"recommendations\": [\"action 1\", \"action 2\", \"action 3\"]\n}\n\nEnsure the response is valid JSON only.","promptType":"define"},"typeVersion":1.4},{"id":"f3094d0c-c852-44fa-8d99-0bdae66bdf5e","name":"Check for Anomalies","type":"n8n-nodes-base.if","position":[592,112],"parameters":{"options":{},"conditions":{"options":{"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"1","operator":{"type":"boolean","operation":"equals"},"leftValue":"={{ $json.has_significant_change }}","rightValue":true}]}},"typeVersion":2},{"id":"b165413f-78d9-4d5c-aee0-9e45f5486788","name":"Log to Historical Sheet","type":"n8n-nodes-base.googleSheets","position":[768,-64],"parameters":{"columns":{"value":{"date":"={{ $now.format('yyyy-MM-dd') }}","growth_rate":"={{ $('Calculate Trends').item.json.growth_metrics.week_over_week_growth }}","mrr_estimate":"={{ $('Calculate Trends').item.json.growth_metrics.estimated_mrr }}","anomalies_count":"={{ $('Calculate Trends').item.json.anomalies.length }}","analysis_summary":"={{ JSON.parse($('Generate Sales Analysis').item.json.response).executive_summary }}","current_week_revenue":"={{ $('Calculate Trends').item.json.current_week.revenue }}","previous_week_revenue":"={{ $('Calculate Trends').item.json.previous_week.revenue }}"},"mappingMode":"defineBelow"},"options":{},"operation":"append","sheetName":"Sales_Analysis_Log","documentId":"YOUR_SPREADSHEET_ID","authentication":"googleOAuth2Api"},"typeVersion":4.5},{"id":"5f70a690-e7a6-4a7b-940e-e11a2d00105c","name":"Update Notion Dashboard","type":"n8n-nodes-base.notion","position":[768,112],"parameters":{"operation":"update"},"typeVersion":2.2},{"id":"34995307-1ce6-4529-bf55-553adf83c9d0","name":"Send Weekly Report to Slack","type":"n8n-nodes-base.slack","position":[768,304],"webhookId":"b8ea565f-4f52-4704-b7b7-1850acd642c9","parameters":{"text":"📊 **Weekly Sales Report**\\n\\n**Revenue:** ${{ $('Calculate Trends').item.json.current_week.revenue }} ({{ $('Calculate Trends').item.json.growth_metrics.week_over_week_growth > 0 ? '+' : '' }}{{ $('Calculate Trends').item.json.growth_metrics.week_over_week_growth }}%)\\n**MRR:** ${{ $('Calculate Trends').item.json.growth_metrics.estimated_mrr }}\\n**Transactions:** {{ $('Calculate Trends').item.json.current_week.transactions }}\\n\\n**AI Analysis:**\\n{{ JSON.parse($('Generate Sales Analysis').item.json.response).executive_summary }}\\n\\n**Top Insights:**\\n{{ JSON.parse($('Generate Sales Analysis').item.json.response).key_insights.slice(0,3).map((insight, i) => (i+1) + '. ' + insight).join('\\n') }}\\n\\nView full dashboard: [Notion Dashboard](YOUR_NOTION_URL)","select":"channel","channelId":{"value":"YOUR_SALES_CHANNEL"},"otherOptions":{},"authentication":"slackOAuth2Api"},"typeVersion":2.2},{"id":"327f097e-066a-4ccb-9302-25eabb1b1c3a","name":"Email Executive Report","type":"n8n-nodes-base.gmail","position":[768,480],"webhookId":"49b8bb4f-0219-4aba-9a29-4a612f37deff","parameters":{"message":"Dear Leadership Team,\\n\\nPlease find attached this week's automated sales analysis:\\n\\n**Executive Summary:**\\n{{ JSON.parse($('Generate Sales Analysis').item.json.response).executive_summary }}\\n\\n**Key Metrics:**\\n• Current week revenue: ${{ $('Calculate Trends').item.json.current_week.revenue }}\\n• Growth rate: {{ $('Calculate Trends').item.json.growth_metrics.week_over_week_growth }}%\\n• MRR estimate: ${{ $('Calculate Trends').item.json.growth_metrics.estimated_mrr }}\\n\\n**Strategic Recommendations:**\\n{{ JSON.parse($('Generate Sales Analysis').item.json.response).recommendations.map((rec, i) => (i+1) + '. ' + rec).join('\\n') }}\\n\\n**Risk Assessment:**\\nLevel: {{ JSON.parse($('Generate Sales Analysis').item.json.response).risk_assessment.level | upper }}\\n{{ JSON.parse($('Generate Sales Analysis').item.json.response).risk_assessment.concerns.length > 0 ? 'Concerns: ' + JSON.parse($('Generate Sales Analysis').item.json.response).risk_assessment.concerns.join(', ') : 'No significant concerns identified.' }}\\n\\nFor detailed dashboard: {{ YOUR_NOTION_DASHBOARD_URL }}\\n\\nBest regards,\\nAutomated Sales Analytics System","options":{},"subject":"Weekly Sales Analysis - {{ $now.format('MMM dd, yyyy') }}"},"typeVersion":2.1},{"id":"f9554b4b-7982-4f04-abe8-2522fe431bcf","name":"Send Anomaly Alert","type":"n8n-nodes-base.slack","position":[1008,112],"webhookId":"b9433b92-ed60-4da7-9b45-4663a1d69eec","parameters":{"text":"🚨 **Sales Anomaly Detected** 🚨\\n\\n**Significant change detected:** {{ $('Calculate Trends').item.json.growth_metrics.week_over_week_growth > 0 ? 'Unusual revenue spike' : 'Revenue decline' }} of {{ Math.abs($('Calculate Trends').item.json.growth_metrics.week_over_week_growth) }}%\\n\\n**Details:**\\n• Current week: ${{ $('Calculate Trends').item.json.current_week.revenue }}\\n• Previous week: ${{ $('Calculate Trends').item.json.previous_week.revenue }}\\n• Change: {{ $('Calculate Trends').item.json.growth_metrics.week_over_week_growth > 0 ? '+' : '' }}{{ $('Calculate Trends').item.json.growth_metrics.week_over_week_growth }}%\\n\\n**Risk Level:** {{ JSON.parse($('Generate Sales Analysis').item.json.response).risk_assessment.level | upper }}\\n\\n**Immediate Actions Needed:**\\n{{ JSON.parse($('Generate Sales Analysis').item.json.response).recommendations.slice(0,2).map((rec, i) => (i+1) + '. ' + rec).join('\\n') }}\\n\\n@channel Please review immediately.","select":"channel","channelId":{"value":"YOUR_ALERTS_CHANNEL"},"otherOptions":{},"authentication":"slackOAuth2Api"},"typeVersion":2.2},{"id":"3ee626de-b582-41c8-8a1f-4dc97bcf1dc8","name":"Configuration Settings","type":"n8n-nodes-base.set","position":[-688,112],"parameters":{"options":{}},"typeVersion":3.4}],"pinData":{},"connections":{"Gemini AI Model":{"ai_languageModel":[[{"node":"Generate Sales Analysis","type":"ai_languageModel","index":0}]]},"Calculate Trends":{"main":[[{"node":"Generate Sales Analysis","type":"main","index":0}]]},"Get Stripe Charges":{"main":[[{"node":"Merge and Process Data","type":"main","index":0}]]},"Get Stripe Refunds":{"main":[[{"node":"Merge and Process Data","type":"main","index":0}]]},"Check for Anomalies":{"main":[[{"node":"Log to Historical Sheet","type":"main","index":0},{"node":"Update Notion Dashboard","type":"main","index":0},{"node":"Send Weekly Report to Slack","type":"main","index":0},{"node":"Email Executive Report","type":"main","index":0}],[{"node":"Send Anomaly Alert","type":"main","index":0}]]},"Load Historical Sales":{"main":[[{"node":"Merge and Process Data","type":"main","index":0}]]},"Weekly Sales Analysis":{"main":[[{"node":"Configuration Settings","type":"main","index":0}]]},"Configuration Settings":{"main":[[{"node":"Get Stripe Charges","type":"main","index":0},{"node":"Get Stripe Subscriptions","type":"main","index":0},{"node":"Get Stripe Refunds","type":"main","index":0},{"node":"Load Historical Sales","type":"main","index":0}]]},"Merge and Process Data":{"main":[[{"node":"Calculate Trends","type":"main","index":0}]]},"Generate Sales Analysis":{"main":[[{"node":"Check for Anomalies","type":"main","index":0}]]},"Get Stripe Subscriptions":{"main":[[{"node":"Merge and Process Data","type":"main","index":0}]]}}} \ No newline at end of file