// FluxoCash Pro - Financial Analysis Script // Financial data structure const financialData = { months: ['jan/25', 'fev/25', 'mar/25', 'abr/25', 'mai/25', 'jun/25', 'jul/25', 'ago/25', 'set/25', 'out/25', 'nov/25', 'dez/25'], openingBalance: [57765, 52114, 50371, 46703, 42816, 42529, 44457, 36478, 25195, 27204, 27102, 17611], totalRevenue: [32757, 36279, 37684, 34902, 34148, 42104, 33888, 44910, 46361, 49334, 51009, 47416], revenueBreakdown: { traffic: [22815, 23843, 25170, 19145, 23370, 32961, 27074, 34795, 30949, 39539, 37828, 38857], webDesign: [7476, 11217, 11324, 14952, 9151, 8596, 5985, 8236, 8135, 7985, 9165, 6165], services: [0, 497, 497, 0, 1216, 547, 829, 714, 5490, 1547, 2627, 2394], hosting: [0, 250, 250, 0, 0, 0, 0, 0, 0, 0, 222, 0], financial: [2466, 473, 0, 805, 412, 0, 0, 0, 1787, 263, 0, 0], other: [0, 0, 444, 0, 0, 0, 0, 1166, 0, 0, 1168, 0] }, totalExpenses: [38408, 38022, 41353, 38789, 38435, 46177, 43866, 44193, 50352, 51320, 52617, 50153], variableCosts: [5444, 8391, 9961, 9016, 9808, 13338, 10839, 11495, 13648, 13959, 11391, 10939], fixedCosts: [10559, 7062, 11989, 10367, 9224, 11385, 11627, 11298, 15675, 14320, 18201, 16247], plr: [19396, 19396, 19396, 19396, 19396, 21396, 21396, 21396, 20964, 22964, 22964, 22964], operationalProfit: [14289, 20353, 15290, 14714, 14704, 17381, 11422, 20951, 15252, 20792, 20249, 20231], netCashFlow: [-5651, -1743, -3668, -3887, -4286, -4073, -9978, 717, -3991, -1985, -1608, -2737], closingBalance: [52114, 50371, 46703, 42816, 42529, 44457, 36478, 25195, 27204, 27102, 27611, 14874] }; // 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)}%`; } function getCurrentMonthIndex() { return 10; // November (nov/25) } // Calculate KPIs function calculateKPIs() { const currentMonth = getCurrentMonthIndex(); // Total Revenue const totalRevenue = financialData.totalRevenue[currentMonth]; document.getElementById('total-revenue').textContent = formatCurrency(totalRevenue); // Total Expenses const totalExpenses = financialData.totalExpenses[currentMonth]; document.getElementById('total-expenses').textContent = formatCurrency(totalExpenses); // Net Profit const netProfit = financialData.operationalProfit[currentMonth] - financialData.plr[currentMonth]; document.getElementById('net-profit').textContent = formatCurrency(netProfit); // Contribution Margin const contributionMargin = (financialData.totalRevenue[currentMonth] - financialData.variableCosts[currentMonth]) / financialData.totalRevenue[currentMonth]; document.getElementById('contribution-margin').textContent = formatPercentage(contributionMargin); // PLR const totalPLR = financialData.plr.reduce((sum, value) => sum + value, 0); document.getElementById('total-plr').textContent = formatCurrency(totalPLR); const plrPercentage = financialData.plr[currentMonth] / financialData.operationalProfit[currentMonth]; document.getElementById('plr-percentage').textContent = formatPercentage(plrPercentage); } // Create charts function createCashFlowChart() { const ctx = document.getElementById('cashFlowChart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: financialData.months, datasets: [{ label: 'Saldo Final', data: financialData.closingBalance, borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', tension: 0.4, fill: true }, { label: 'Fluxo de Caixa', data: financialData.netCashFlow, borderColor: 'rgb(16, 185, 129)', backgroundColor: 'rgba(16, 185, 129, 0.1)', tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', }, title: { display: false } }, scales: { y: { beginAtZero: false, ticks: { callback: function(value) { return formatCurrency(value); } } } } } }); } function createRevenueCompositionChart() { const ctx = document.getElementById('revenueCompositionChart').getContext('2d'); const currentMonth = getCurrentMonthIndex(); const data = { labels: ['Tráfego', 'Web Design', 'Serviços', 'Hospedagem', 'Financeiras', 'Outras'], datasets: [{ data: [ financialData.revenueBreakdown.traffic[currentMonth], financialData.revenueBreakdown.webDesign[currentMonth], financialData.revenueBreakdown.services[currentMonth], financialData.revenueBreakdown.hosting[currentMonth], financialData.revenueBreakdown.financial[currentMonth], financialData.revenueBreakdown.other[currentMonth] ], backgroundColor: [ 'rgba(59, 130, 246, 0.8)', 'rgba(16, 185, 129, 0.8)', 'rgba(245, 158, 11, 0.8)', 'rgba(139, 92, 246, 0.8)', 'rgba(236, 72, 153, 0.8)', 'rgba(107, 114, 128, 0.8)' ] }] }; new Chart(ctx, { type: 'doughnut', data: data, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', }, tooltip: { callbacks: { label: function(context) { const label = context.label || ''; const value = context.parsed || 0; const total = context.dataset.data.reduce((a, b) => a + b, 0); const percentage = ((value / total) * 100).toFixed(1); return `${label}: ${formatCurrency(value)} (${percentage}%)`; } } } } } }); } // Populate tables and breakdowns function populateRevenueDetails() { const currentMonth = getCurrentMonthIndex(); const tbody = document.getElementById('revenue-details'); const totalRevenue = financialData.totalRevenue[currentMonth]; const revenueItems = [ { name: 'Receita de Tráfego', value: financialData.revenueBreakdown.traffic[currentMonth] }, { name: 'Receita de Web Design', value: financialData.revenueBreakdown.webDesign[currentMonth] }, { name: 'Receita de Serviços', value: financialData.revenueBreakdown.services[currentMonth] }, { name: 'Receita de Hospedagem', value: financialData.revenueBreakdown.hosting[currentMonth] }, { name: 'Receitas Financeiras', value: financialData.revenueBreakdown.financial[currentMonth] }, { name: 'Outras Receitas', value: financialData.revenueBreakdown.other[currentMonth] } ]; tbody.innerHTML = revenueItems.map(item => ` ${item.name} ${formatCurrency(item.value)} ${formatPercentage(item.value / totalRevenue)} `).join(''); } function populateExpenseBreakdown() { const currentMonth = getCurrentMonthIndex(); const container = document.getElementById('expense-breakdown'); const expenseCategories = [ { name: 'Impostos', value: -4813, icon: 'file-text', color: 'red' }, { name: 'Custos Variáveis', value: -11391, icon: 'package', color: 'orange' }, { name: 'Salários e Encargos', value: -11294, icon: 'users', color: 'blue' }, { name: 'Despesas Administrativas', value: -5827, icon: 'settings', color: 'gray' }, { name: 'Despesas Comerciais', value: -893, icon: 'shopping-cart', color: 'purple' }, { name: 'PLR', value: -22964, icon: 'gift', color: 'pink' } ]; container.innerHTML = expenseCategories.map(category => `
${category.name}
${formatCurrency(category.value)}
`).join(''); feather.replace(); } function calculateProjections() { const currentMonth = getCurrentMonthIndex(); const lastThreeMonths = financialData.netCashFlow.slice(currentMonth - 2, currentMonth + 1); const averageCashFlow = lastThreeMonths.reduce((sum, value) => sum + value, 0) / 3; // Base projection: closing balance + average cash flow const baseProjection = financialData.closingBalance[currentMonth] + averageCashFlow; // Optimistic scenario: +15% revenue, -5% expenses const optimistic = baseProjection * 1.15; document.getElementById('optimistic-scenario').textContent = formatCurrency(optimistic); // Realistic scenario: base projection document.getElementById('realistic-scenario').textContent = formatCurrency(baseProjection); // Conservative scenario: -10% revenue, +5% expenses const conservative = baseProjection * 0.85; document.getElementById('conservative-scenario').textContent = formatCurrency(conservative); } function generateAlertsAndRecommendations() { const currentMonth = getCurrentMonthIndex(); const container = document.getElementById('alerts-recommendations'); const alerts = []; // Check cash flow trend const lastThreeMonthsFlow = financialData.netCashFlow.slice(currentMonth - 2, currentMonth + 1); const negativeFlowCount = lastThreeMonthsFlow.filter(flow => flow < 0).length; if (negativeFlowCount >= 2) { alerts.push({ type: 'danger', icon: 'alert-alert-triangle', title: 'Atenção: Fluxo de Caixa Negativo', message: 'Nos últimos 3 meses, tivemos fluxo negativo em 2 períodos. Recomenda-se revisar despesas e acelerar recebíveis.' }); } // Check PLR percentage const plrPercentage = financialData.plr[currentMonth] / financialData.operationalProfit[currentMonth]; if (plrPercentage > 0.8) { alerts.push({ type: 'warning', icon: 'percent', title: 'PLR Elevada', message: 'A PLR está consumindo mais de 80% do lucro operacional. Considere ajustar a política de distribuição.' }); } // Check cash balance const currentBalance = financialData.closingBalance[currentMonth]; if (currentBalance < 20000) { alerts.push({ type: 'warning', icon: 'dollar-sign', title: 'Saldo de Caixa Baixo', message: 'O saldo atual está abaixo de R$ 20.000. Mantenha uma reserva de segurança equivalente a 2 meses de despesas.' }); } // Positive alerts if (financialData.totalRevenue[currentMonth] > financialData.totalRevenue[currentMonth - 1]) { alerts.push({ type: 'success', icon: 'trending-up', title: 'Crescimento de Receita', message: 'As receitas cresceram em relação ao mês anterior. Continue focando nas fontes principais de receita.' }); } container.innerHTML = alerts.map(alert => `

${alert.title}

${alert.message}

`).join(''); feather.replace(); } // Initialize dashboard function initializeDashboard() { calculateKPIs(); createCashFlowChart(); createRevenueCompositionChart(); populateRevenueDetails(); populateExpenseBreakdown(); calculateProjections(); generateAlertsAndRecommendations(); } // Dark mode toggle function setupDarkMode() { const darkModeToggle = document.createElement('button'); darkModeToggle.innerHTML = ''; darkModeToggle.className = 'fixed top-4 right-4 p-2 bg-gray-200 dark:bg-gray-700 rounded-lg shadow-lg'; darkModeToggle.addEventListener('click', () => { document.documentElement.classList.toggle('dark'); darkModeToggle.innerHTML = document.documentElement.classList.contains('dark') ? '' : ''; feather.replace(); }); document.body.appendChild(darkModeToggle); } // Document ready document.addEventListener('DOMContentLoaded', () => { initializeDashboard(); setupDarkMode(); });