// Financial Data and Analysis const financialData = { months: ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov'], revenues: [32757, 36279, 37684, 34902, 34148, 42104, 33888, 44910, 46361, 49334, 51009], expenses: [38408, 38022, 41353, 38789, 38435, 46177, 43866, 44193, 50352, 51320, 52617], operationalProfit: [14289, 20353, 15290, 14714, 14704, 17381, 11422, 20951, 15252, 20792, 20249], plr: [19396, 19396, 19396, 19396, 19396, 21396, 21396, 21396, 20964, 22964, 22964], cashBalance: [57765, 52114, 50371, 46703, 42816, 42529, 44457, 36478, 25195, 27204, 27102, 27611], revenueBreakdown: { november: { traffic: 37828, webDesign: 9165, services: 2627, hosting: 222, financial: 0, others: 1168 } }, expensesBreakdown: { november: { plr: 22964, salaries: 11294, variableCosts: 11391, taxes: 4813, administrative: 5827, commercial: 893, property: 89, financial: 61, others: 0 } } }; // Utility Functions function formatCurrency(value) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value); } function formatPercentage(value) { return (value * 100).toFixed(1) + '%'; } // Calculate Financial Metrics function calculateMetrics() { const totalRevenues = financialData.revenues.reduce((a, b) => a + b, 0); const totalExpenses = financialData.expenses.reduce((a, b) => a + b, 0); const avgOperationalProfit = financialData.operationalProfit.reduce((a, b) => a + b, 0) / financialData.operationalProfit.length; // Calculate average contribution margin let totalContributionMargin = 0; for (let i = 0; i < financialData.months.length; i++) { const contributionMargin = financialData.revenues[i] * 0.754; // Using average 75.4% totalContributionMargin += contributionMargin; } const avgContributionMargin = totalContributionMargin / totalRevenues; return { totalRevenues, totalExpenses, avgOperationalProfit, avgContributionMargin }; } // Update KPI Cards function updateKPIs() { const metrics = calculateMetrics(); document.getElementById('totalRevenues').textContent = formatCurrency(metrics.totalRevenues); document.getElementById('totalExpenses').textContent = formatCurrency(metrics.totalExpenses); document.getElementById('operationalProfit').textContent = formatCurrency(metrics.avgOperationalProfit); document.getElementById('contributionMargin').textContent = formatPercentage(metrics.avgContributionMargin); } // Create Monthly Flow Chart function createMonthlyFlowChart() { const ctx = document.getElementById('monthlyFlowChart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov'], datasets: [{ label: 'Receitas', data: financialData.revenues, borderColor: '#10B981', backgroundColor: 'rgba(16, 185, 129, 0.1)', tension: 0.4, fill: true }, { label: 'Despesas', data: financialData.expenses, borderColor: '#EF4444', backgroundColor: 'rgba(239, 68, 68, 0.1)', tension: 0.4, fill: true }, { label: 'Saldo Caixa', data: financialData.cashBalance.slice(1), borderColor: '#3B82F6', backgroundColor: 'rgba(59, 130, 246, 0.1)', tension: 0.4, fill: false, yAxisID: 'y1' }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', } }, scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return formatCurrency(value); } } }, y1: { type: 'linear', display: true, position: 'right', grid: { drawOnChartArea: false, }, ticks: { callback: function(value) { return formatCurrency(value); } } } } } }); } // Create Revenue Composition Chart function createRevenueCompositionChart() { const ctx = document.getElementById('revenueCompositionChart').getContext('2d'); const novemberData = financialData.revenueBreakdown.november; new Chart(ctx, { type: 'doughnut', data: { labels: ['Tráfego', 'Web Design', 'Serviços', 'Hospedagem', 'Outras'], datasets: [{ data: [novemberData.traffic, novemberData.webDesign, novemberData.services, novemberData.hosting, novemberData.others], backgroundColor: [ '#3B82F6', '#10B981', '#F59E0B', '#8B5CF6', '#EF4444' ] }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'right', }, tooltip: { callbacks: { label: function(context) { const total = context.dataset.data.reduce((a, b) => a + b, 0); const percentage = ((context.raw / total) * 100).toFixed(1); return context.label + ': ' + formatCurrency(context.raw) + ' (' + percentage + '%)'; } } } } } }); } // Create Projection Chart function createProjectionChart() { const ctx = document.getElementById('projectionChart').getContext('2d'); // Project next 6 months based on trends const projectionMonths = ['Dez', 'Jan', 'Fev', 'Mar', 'Abr', 'Mai']; const lastRevenue = financialData.revenues[financialData.revenues.length - 1]; const lastExpense = financialData.expenses[financialData.expenses.length - 1]; // Simple linear projection with slight growth for revenues and controlled expenses const projectedRevenues = [ lastRevenue * 0.9, // December lower due to holidays lastRevenue * 1.02, lastRevenue * 1.04, lastRevenue * 1.06, lastRevenue * 1.08, lastRevenue * 1.10 ]; const projectedExpenses = [ lastExpense * 0.8, // December lower expenses lastExpense * 0.95, // Cost reduction measures lastExpense * 0.96, lastExpense * 0.97, lastExpense * 0.98, lastExpense * 0.99 ]; let projectedCash = financialData.cashBalance[financialData.cashBalance.length - 1]; const projectedCashFlow = [projectedCash]; for (let i = 0; i < projectedRevenues.length; i++) { projectedCash += (projectedRevenues[i] - projectedExpenses[i]); projectedCashFlow.push(projectedCash); } new Chart(ctx, { type: 'line', data: { labels: ['Nov', ...projectionMonths], datasets: [{ label: 'Receitas Projetadas', data: [null, ...projectedRevenues], borderColor: '#10B981', borderDash: [5, 5], tension: 0.4 }, { label: 'Despesas Projetadas', data: [null, ...projectedExpenses], borderColor: '#EF4444', borderDash: [5, 5], tension: 0.4 }, { label: 'Saldo Caixa Projetado', data: projectedCashFlow, borderColor: '#3B82F6', backgroundColor: 'rgba(59, 130, 246, 0.2)', fill: true, tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', } }, scales: { y: { beginAtZero: false, ticks: { callback: function(value) { return formatCurrency(value); } } } } } }); } // Populate Monthly Table function populateMonthlyTable() { const tableBody = document.getElementById('monthlyTable'); tableBody.innerHTML = ''; for (let i = 0; i < financialData.months.length; i++) { const revenue = financialData.revenues[i]; const expense = financialData.expenses[i]; const result = revenue - expense; const cashBalance = financialData.cashBalance[i + 1]; const row = document.createElement('tr'); row.className = 'border-b border-gray-100'; row.innerHTML = `