EraDigital's picture
criar uma análise financeira completa de fluxo de caixa a partir dos dados colados do relatório. Considerar Novembro como mês de fechamento e destacar os pontos principais como Receitas totais, Despesas totais, resultado operacional, lucro líquido, margem de contribuição, etc. Detalhar a composição das despesas e receitas (incluir a divisão das receitas, Receitas de Trafego, de Web, de Serviços, etc) e informar o PLR. Inclui também uma análise com principais pontos de atenção e diretrizes. Incluir uma projeção do fluxo da caixa. Seguem dados: FLUXO DE CAIXA Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Realizado (R$) Previsto (R$) Realizado (R$)
2f61e46 verified
// 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 = `
<td class="py-2 px-3 font-medium">${financialData.months[i].charAt(0).toUpperCase() + financialData.months[i].slice(1)}/25</td>
<td class="py-2 px-3 text-right font-medium text-green-600">${formatCurrency(revenue)}</td>
<td class="py-2 px-3 text-right font-medium text-red-600">${formatCurrency(expense)}</td>
<td class="py-2 px-3 text-right font-medium ${result >= 0 ? 'text-green-600' : 'text-red-600'}">${formatCurrency(result)}</td>
<td class="py-2 px-3 text-right font-medium">${formatCurrency(cashBalance)}</td>
`;
tableBody.appendChild(row);
}
// Add totals row
const totalRevenue = financialData.revenues.reduce((a, b) => a + b, 0);
const totalExpense = financialData.expenses.reduce((a, b) => a + b, 0);
const totalResult = totalRevenue - totalExpense;
const totalsRow = document.createElement('tr');
totalsRow.className = 'font-bold bg-gray-50';
totalsRow.innerHTML = `
<td class="py-2 px-3">TOTAL</td>
<td class="py-2 px-3 text-right text-green-600">${formatCurrency(totalRevenue)}</td>
<td class="py-2 px-3 text-right text-red-600">${formatCurrency(totalExpense)}</td>
<td class="py-2 px-3 text-right ${totalResult >= 0 ? 'text-green-600' : 'text-red-600'}">${formatCurrency(totalResult)}</td>
<td class="py-2 px-3 text-right">${formatCurrency(financialData.cashBalance[financialData.cashBalance.length - 1])}</td>
`;
tableBody.appendChild(totalsRow);
}
// Export to PDF (placeholder function)
function exportToPDF() {
alert('Função de exportação para PDF será implementada com integração de biblioteca PDF como jsPDF');
}
// Refresh Data (placeholder function)
function refreshData() {
const cards = document.querySelectorAll('.bg-white');
cards.forEach(card => card.classList.add('loading'));
setTimeout(() => {
cards.forEach(card => card.classList.remove('loading'));
updateKPIs();
populateMonthlyTable();
}, 1000);
}
// Initialize Dashboard
document.addEventListener('DOMContentLoaded', function() {
updateKPIs();
createMonthlyFlowChart();
createRevenueCompositionChart();
createProjectionChart();
populateMonthlyTable();
});
// Smooth scroll for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});