Strategic Financial Planning Simulator
1. Enter Initial Data & Assumptions
Initial Financials (Year 0)
Growth & Operating Assumptions
Investment & Working Capital Assumptions
2. Projected Income Statement
Calculate the model to see the Income Statement.
3. Projected Cash Flow Statement
Calculate the model to see the Cash Flow Statement.
4. Projected Balance Sheet
Calculate the model to see the Balance Sheet.
5. Key Metrics
Calculate the model to see the Key Metrics.
Please fix input errors to see financial statements.
'; cashFlowOutputDiv.innerHTML = 'Please fix input errors to see financial statements.
'; balanceSheetOutputDiv.innerHTML = 'Please fix input errors to see financial statements.
'; keyMetricsOutputDiv.innerHTML = 'Please fix input errors to see key metrics.
'; return; } // Initialize arrays to store annual financial data const incomeStatementData = []; const cashFlowData = []; const balanceSheetData = []; const keyMetricsData = []; // Add Year 0 (Current) to the data arrays // Income Statement (Year 0 - no projections, just input values) incomeStatementData.push({ year: 0, revenue: initialRevenue, cogs: initialCogs, grossProfit: initialRevenue - initialCogs, operatingExpenses: initialOperatingExpenses, ebitda: (initialRevenue - initialCogs - initialOperatingExpenses), depreciation: 0, // Placeholder, usually calculated from fixed assets ebit: (initialRevenue - initialCogs - initialOperatingExpenses), interestExpense: 0, // Placeholder ebt: (initialRevenue - initialCogs - initialOperatingExpenses), taxes: 0, // Placeholder netIncome: (initialRevenue - initialCogs - initialOperatingExpenses) }); // Balance Sheet (Year 0 - current values) balanceSheetData.push({ year: 0, cash: initialCash, accountsReceivable: initialAccountsReceivable, inventory: initialInventory, totalCurrentAssets: initialCash + initialAccountsReceivable + initialInventory, fixedAssetsNet: initialFixedAssets, totalAssets: initialCash + initialAccountsReceivable + initialInventory + initialFixedAssets, accountsPayable: initialAccountsPayable, accruedExpenses: initialAccruedExpenses, totalCurrentLiabilities: initialAccountsPayable + initialAccruedExpenses, longTermDebt: initialLongTermDebt, totalLiabilities: initialAccountsPayable + initialAccruedExpenses + initialLongTermDebt, equity: initialEquity, totalLiabilitiesAndEquity: initialAccountsPayable + initialAccruedExpenses + initialLongTermDebt + initialEquity }); // Cash Flow (Year 0 - no cash flow activity, just starting cash) cashFlowData.push({ year: 0, netIncome: initialRevenue - initialCogs - initialOperatingExpenses, // For completeness, based on IS depreciation: 0, changeInAR: 0, changeInInventory: 0, changeInAP: 0, changeInAccruedExpenses: 0, cashFlowFromOperations: 0, capex: 0, cashFlowFromInvesting: 0, debtIssuanceRepayment: 0, equityIssuanceDividends: 0, cashFlowFromFinancing: 0, netChangeInCash: 0, endingCash: initialCash }); // 3. Project Financials for each year for (let i = 1; i <= projectionYears; i++) { const prevIS = incomeStatementData[i - 1]; const prevBS = balanceSheetData[i - 1]; // --- Income Statement Projections --- const revenue = prevIS.revenue * (1 + revenueGrowthRate); const cogs = revenue * cogsAsPctRevenue; const grossProfit = revenue - cogs; const operatingExpenses = revenue * opexAsPctRevenue; const ebitda = grossProfit - operatingExpenses; // Depreciation: based on previous year's Fixed Assets (Net) const depreciation = prevBS.fixedAssetsNet * depreciationRate; const ebit = ebitda - depreciation; // Interest Expense: based on previous year's Long-Term Debt const interestExpense = prevBS.longTermDebt * interestRateOnDebt; const ebt = ebit - interestExpense; const taxes = Math.max(0, ebt * taxRate); // Taxes cannot be negative const netIncome = ebt - taxes; incomeStatementData.push({ year: i, revenue: revenue, cogs: cogs, grossProfit: grossProfit, operatingExpenses: operatingExpenses, ebitda: ebitda, depreciation: depreciation, ebit: ebit, interestExpense: interestExpense, ebt: ebt, taxes: taxes, netIncome: netIncome }); // --- Balance Sheet Projections --- const currentRevenue = incomeStatementData[i].revenue; // Current year's revenue const currentCOGS = incomeStatementData[i].cogs; // Current year's COGS const accountsReceivable = (currentRevenue / 365) * arDays; const inventory = (currentCOGS / 365) * inventoryDays; // Inventory typically linked to COGS const accountsPayable = (currentCOGS / 365) * apDays; // AP typically linked to COGS const accruedExpenses = (operatingExpenses / 365) * accruedDays; // Accrued expenses to OpEx const totalCurrentAssets = prevBS.cash + accountsReceivable + inventory; // Cash from CFS const fixedAssetsGross = prevBS.fixedAssetsNet + (currentRevenue * capexAsPctRevenue) + depreciation; // Simplified gross for calculation if needed for D&A base const fixedAssetsNet = prevBS.fixedAssetsNet + (currentRevenue * capexAsPctRevenue) - depreciation; const totalAssets = totalCurrentAssets + fixedAssetsNet; const totalCurrentLiabilities = accountsPayable + accruedExpenses; const longTermDebt = prevBS.longTermDebt; // Assuming no new debt issuance/repayment for simplicity const totalLiabilities = totalCurrentLiabilities + longTermDebt; // Equity: Prev Equity + Net Income - Dividends (assuming no dividends for simplicity) const equity = prevBS.equity + netIncome; // Assuming no new equity issuance or dividends const totalLiabilitiesAndEquity = totalLiabilities + equity; // --- Cash Flow Statement Projections --- const cashFlowFromOperations = netIncome + depreciation + // Non-cash expenses (prevBS.accountsReceivable - accountsReceivable) + // Change in AR (prevBS.inventory - inventory) + // Change in Inventory (accountsPayable - prevBS.accountsPayable) + // Change in AP (accruedExpenses - prevBS.accruedExpenses); // Change in Accrued Expenses const capex = currentRevenue * capexAsPctRevenue; const cashFlowFromInvesting = -capex; const debtIssuanceRepayment = 0; // Assuming no manual changes for now const equityIssuanceDividends = 0; // Assuming no manual changes for now const cashFlowFromFinancing = debtIssuanceRepayment + equityIssuanceDividends; const netChangeInCash = cashFlowFromOperations + cashFlowFromInvesting + cashFlowFromFinancing; const endingCash = prevBS.cash + netChangeInCash; balanceSheetData.push({ year: i, cash: endingCash, // This is a key link: cash from CFS accountsReceivable: accountsReceivable, inventory: inventory, totalCurrentAssets: endingCash + accountsReceivable + inventory, fixedAssetsNet: fixedAssetsNet, totalAssets: endingCash + accountsReceivable + inventory + fixedAssetsNet, accountsPayable: accountsPayable, accruedExpenses: accruedExpenses, totalCurrentLiabilities: accountsPayable + accruedExpenses, longTermDebt: longTermDebt, totalLiabilities: accountsPayable + accruedExpenses + longTermDebt, equity: equity, totalLiabilitiesAndEquity: accountsPayable + accruedExpenses + longTermDebt + equity }); cashFlowData.push({ year: i, netIncome: netIncome, depreciation: depreciation, changeInAR: (prevBS.accountsReceivable - accountsReceivable), changeInInventory: (prevBS.inventory - inventory), changeInAP: (accountsPayable - prevBS.accountsPayable), changeInAccruedExpenses: (accruedExpenses - prevBS.accruedExpenses), cashFlowFromOperations: cashFlowFromOperations, capex: capex, cashFlowFromInvesting: cashFlowFromInvesting, debtIssuanceRepayment: debtIssuanceRepayment, equityIssuanceDividends: equityIssuanceDividends, cashFlowFromFinancing: cashFlowFromFinancing, netChangeInCash: netChangeInCash, endingCash: endingCash }); // --- Key Metrics Calculations --- const ebitdaMargin = ebitda / revenue; const netProfitMargin = netIncome / revenue; const currentRatio = (endingCash + accountsReceivable + inventory) / (accountsPayable + accruedExpenses); const debtToEquity = longTermDebt / equity; const unleveredFreeCashFlow = ebitda - (revenue * capexAsPctRevenue) - (currentRevenue * cogsAsPctRevenue * inventoryDays / 365) + (currentCOGS * apDays / 365) + (operatingExpenses * accruedDays / 365); // Simplified example keyMetricsData.push({ year: i, ebitdaMargin: ebitdaMargin, netProfitMargin: netProfitMargin, currentRatio: currentRatio, debtToEquity: debtToEquity, unleveredFreeCashFlow: cashFlowFromOperations - (currentRevenue * capexAsPctRevenue) // Simplified from operations }); } // Check if final balance sheet balances (after projection) const lastBS = balanceSheetData[projectionYears]; const finalTotalAssets = lastBS.totalCurrentAssets + lastBS.fixedAssetsNet; const finalTotalLiabilitiesAndEquity = lastBS.totalLiabilities + lastBS.equity; if (Math.abs(finalTotalAssets - finalTotalLiabilitiesAndEquity) > balanceSheetTolerance) { showMessage(`WARNING: Final Balance Sheet Mismatch: Assets (${formatCurrency(finalTotalAssets)}) DO NOT equal Liabilities + Equity (${formatCurrency(finalTotalLiabilitiesAndEquity)}). This model is simplified; adjustments may be needed.`, 'error'); } // 4. Store results for display and PDF window.financialProjections = { inputs: { initialRevenue, initialCogs, initialOperatingExpenses, initialCash, initialAccountsReceivable, initialInventory, initialFixedAssets, initialAccountsPayable, initialAccruedExpenses, initialLongTermDebt, initialEquity, projectionYears, revenueGrowthRate, cogsAsPctRevenue, opexAsPctRevenue, depreciationRate, interestRateOnDebt, taxRate, capexAsPctRevenue, arDays, inventoryDays, apDays, accruedDays }, incomeStatement: incomeStatementData, cashFlow: cashFlowData, balanceSheet: balanceSheetData, keyMetrics: keyMetricsData }; // 5. Update UI displayIncomeStatement(incomeStatementData); displayCashFlowStatement(cashFlowData); displayBalanceSheet(balanceSheetData); displayKeyMetrics(keyMetricsData); // Optionally navigate to Income Statement tab after calculation openTab('income-statement'); showMessage('Financial projections calculated successfully!', 'success'); } /** * Displays the projected Income Statement. * @param {Array} data The income statement data array. */ function displayIncomeStatement(data) { let tableHtml = `| Line Item | `; for (let i = 0; i < data.length; i++) { tableHtml += `${data[i].year === 0 ? 'Current Year' : `Year ${data[i].year}`} | `; } tableHtml += `
|---|---|
| ${displayNames[item]} | `; data.forEach(yearData => { tableHtml += `${formatCurrency(yearData[item])} | `; }); tableHtml += `
| Line Item | `; for (let i = 0; i < data.length; i++) { tableHtml += `${data[i].year === 0 ? 'Current Year' : `Year ${data[i].year}`} | `; } tableHtml += `
|---|---|
| ${displayNames[item]} | `; data.forEach(yearData => { tableHtml += `${formatCurrency(yearData[item])} | `; }); tableHtml += `
| Line Item | `; for (let i = 0; i < data.length; i++) { tableHtml += `${data[i].year === 0 ? 'Current Year' : `Year ${data[i].year}`} | `; } tableHtml += `
|---|---|
| ${displayNames[item]} | `; data.forEach(yearData => { tableHtml += `${formatCurrency(yearData[item])} | `; }); tableHtml += `
| Metric | `; for (let i = 0; i < data.length; i++) { tableHtml += `Year ${data[i].year} | `; } tableHtml += `
|---|---|
| ${displayNames[item]} | `; data.forEach(yearData => { tableHtml += `${formatters[item](yearData[item])} | `; }); tableHtml += `
Calculate the model to see the Income Statement.
'; cashFlowOutputDiv.innerHTML = 'Calculate the model to see the Cash Flow Statement.
'; balanceSheetOutputDiv.innerHTML = 'Calculate the model to see the Balance Sheet.
'; keyMetricsOutputDiv.innerHTML = 'Calculate the model to see the Key Metrics.
'; // Reset to the first tab openTab('inputs'); hideMessage(); } /** * Downloads the financial projections as a PDF. */ function downloadPDF() { if (!window.financialProjections) { showMessage('Please calculate the financial projections first.', 'info'); return; } const { jsPDF } = window.jspdf; const pdf = new jsPDF('l', 'mm', 'a4'); // 'l' for landscape, 'mm', 'a4' size (better for wide tables) const BLACK_COLOR = [31, 41, 55]; // Tailwind gray-900 equivalent const BLUE_HEADER_COLOR = [29, 78, 216]; // Tailwind blue-700 equivalent let y = 15; // Y-coordinate for placing content // Title pdf.setFontSize(22); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(BLACK_COLOR[0], BLACK_COLOR[1], BLACK_COLOR[2]); pdf.text('Strategic Financial Planning Simulator Results', 148, y, { align: 'center' }); // Centered for landscape y += 15; // --- 1. Input Parameters Section --- pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text('1. Input Parameters & Assumptions', 15, y); y += 8; const inputs = window.financialProjections.inputs; const inputData = [ ['Initial Revenue', formatCurrency(inputs.initialRevenue)], ['Initial COGS', formatCurrency(inputs.initialCogs)], ['Initial Operating Expenses', formatCurrency(inputs.initialOperatingExpenses)], ['Initial Cash', formatCurrency(inputs.initialCash)], ['Initial Accounts Receivable', formatCurrency(inputs.initialAccountsReceivable)], ['Initial Inventory', formatCurrency(inputs.initialInventory)], ['Initial Fixed Assets (Net)', formatCurrency(inputs.initialFixedAssets)], ['Initial Accounts Payable', formatCurrency(inputs.initialAccountsPayable)], ['Initial Accrued Expenses', formatCurrency(inputs.initialAccruedExpenses)], ['Initial Long-Term Debt', formatCurrency(inputs.initialLongTermDebt)], ['Initial Equity', formatCurrency(inputs.initialEquity)], ['Projection Years', inputs.projectionYears], ['Annual Revenue Growth Rate', `${(inputs.revenueGrowthRate * 100).toFixed(2)}%`], ['COGS as % of Revenue', `${(inputs.cogsAsPctRevenue * 100).toFixed(2)}%`], ['Operating Expenses as % of Revenue', `${(inputs.opexAsPctRevenue * 100).toFixed(2)}%`], ['Depreciation Rate (% of Fixed Assets)', `${(inputs.depreciationRate * 100).toFixed(2)}%`], ['Interest Rate on Debt', `${(inputs.interestRateOnDebt * 100).toFixed(2)}%`], ['Tax Rate', `${(inputs.taxRate * 100).toFixed(2)}%`], ['CAPEX as % of Revenue', `${(inputs.capexAsPctRevenue * 100).toFixed(2)}%`], ['Accounts Receivable Days', inputs.arDays], ['Inventory Days', inputs.inventoryDays], ['Accounts Payable Days', inputs.apDays], ['Accrued Expenses Days', inputs.accruedDays] ]; pdf.autoTable({ startY: y, head: [['Parameter', 'Value']], body: inputData, theme: 'grid', styles: { fontSize: 8, cellPadding: 2, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, columnStyles: { 0: { cellWidth: 80 }, 1: { cellWidth: 'auto' } } }); y = pdf.autoTable.previous.finalY + 15; // Helper to add a financial statement table const addFinancialStatementTable = (title, data, displayNames, formatters, startY) => { // Add new page if current content won't fit if (startY + 30 + (Object.keys(displayNames).length * 7) > pdf.internal.pageSize.height - 15) { pdf.addPage('l', 'a4'); // Add a new page in landscape startY = 15; // Reset Y } pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text(title, 15, startY); startY += 8; const headers = ['Line Item']; for (let i = 0; i < data.length; i++) { headers.push(data[i].year === 0 ? 'Current Year' : `Year ${data[i].year}`); } const tableBody = []; Object.keys(displayNames).forEach(item => { const row = [displayNames[item]]; data.forEach(yearData => { const formattedValue = formatters[item] ? formatters[item](yearData[item]) : formatCurrency(yearData[item]); row.push({ content: formattedValue, styles: { halign: 'right' } }); }); tableBody.push(row); }); pdf.autoTable({ startY: startY, head: [headers], body: tableBody, theme: 'grid', styles: { fontSize: 7, cellPadding: 1, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, didParseCell: function (data) { if (data.column.index > 0) { // All data columns are right-aligned data.cell.styles.halign = 'right'; } } }); return pdf.autoTable.previous.finalY + 15; }; // --- Income Statement --- const isDisplayNames = { revenue: 'Revenue', cogs: 'Cost of Goods Sold (COGS)', grossProfit: 'Gross Profit', operatingExpenses: 'Operating Expenses', ebitda: 'EBITDA', depreciation: 'Depreciation', ebit: 'EBIT', interestExpense: 'Interest Expense', ebt: 'Earnings Before Tax (EBT)', taxes: 'Taxes', netIncome: 'Net Income' }; const isFormatters = {}; // All are currency, handled by default formatCurrency for this y = addFinancialStatementTable('2. Projected Income Statement', window.financialProjections.incomeStatement, isDisplayNames, isFormatters, y); // --- Cash Flow Statement --- const cfsDisplayNames = { netIncome: 'Net Income', depreciation: 'Depreciation', changeInAR: 'Change in Accounts Receivable', changeInInventory: 'Change in Inventory', changeInAP: 'Change in Accounts Payable', changeInAccruedExpenses: 'Change in Accrued Expenses', cashFlowFromOperations: 'Cash Flow From Operations', capex: 'Capital Expenditures (CAPEX)', cashFlowFromInvesting: 'Cash Flow From Investing', debtIssuanceRepayment: 'Debt Issuance / (Repayment)', equityIssuanceDividends: 'Equity Issuance / (Dividends)', cashFlowFromFinancing: 'Cash Flow From Financing', netChangeInCash: 'Net Change in Cash', endingCash: 'Ending Cash Balance' }; const cfsFormatters = {}; // All are currency y = addFinancialStatementTable('3. Projected Cash Flow Statement', window.financialProjections.cashFlow, cfsDisplayNames, cfsFormatters, y); // --- Balance Sheet --- const bsDisplayNames = { cash: 'Cash', accountsReceivable: 'Accounts Receivable', inventory: 'Inventory', totalCurrentAssets: 'Total Current Assets', fixedAssetsNet: 'Fixed Assets (Net)', totalAssets: 'TOTAL ASSETS', accountsPayable: 'Accounts Payable', accruedExpenses: 'Accrued Expenses', totalCurrentLiabilities: 'Total Current Liabilities', longTermDebt: 'Long-Term Debt', totalLiabilities: 'TOTAL LIABILITIES', equity: 'Equity', totalLiabilitiesAndEquity: 'TOTAL LIABILITIES & EQUITY' }; const bsFormatters = {}; // All are currency y = addFinancialStatementTable('4. Projected Balance Sheet', window.financialProjections.balanceSheet, bsDisplayNames, bsFormatters, y); // --- Key Metrics --- const kmDisplayNames = { ebitdaMargin: 'EBITDA Margin', netProfitMargin: 'Net Profit Margin', currentRatio: 'Current Ratio', debtToEquity: 'Debt to Equity', unleveredFreeCashFlow: 'Unlevered Free Cash Flow' }; const kmFormatters = { ebitdaMargin: (val) => `${(val * 100).toFixed(2)}%`, netProfitMargin: (val) => `${(val * 100).toFixed(2)}%`, currentRatio: (val) => `${val.toFixed(2)}x`, debtToEquity: (val) => `${val.toFixed(2)}x`, unleveredFreeCashFlow: formatCurrency }; y = addFinancialStatementTable('5. Key Metrics', window.financialProjections.keyMetrics.filter(m => m.year > 0), kmDisplayNames, kmFormatters, y); // Exclude Year 0 from key metrics pdf.save('Strategic_Financial_Planning_Simulator_Results.pdf'); } /** * Initializes DOM element references once the document is fully loaded. */ document.addEventListener('DOMContentLoaded', () => { // Initial Financials Inputs initialRevenueInput = document.getElementById('initialRevenue'); initialCogsInput = document.getElementById('initialCogs'); initialOperatingExpensesInput = document.getElementById('initialOperatingExpenses'); initialCashInput = document.getElementById('initialCash'); initialAccountsReceivableInput = document.getElementById('initialAccountsReceivable'); initialInventoryInput = document.getElementById('initialInventory'); initialFixedAssetsInput = document.getElementById('initialFixedAssets'); initialAccountsPayableInput = document.getElementById('initialAccountsPayable'); initialAccruedExpensesInput = document.getElementById('initialAccruedExpenses'); initialLongTermDebtInput = document.getElementById('initialLongTermDebt'); initialEquityInput = document.getElementById('initialEquity'); // Growth & Operating Assumptions Inputs projectionYearsInput = document.getElementById('projectionYears'); revenueGrowthRateInput = document.getElementById('revenueGrowthRate'); cogsAsPctRevenueInput = document.getElementById('cogsAsPctRevenue'); opexAsPctRevenueInput = document.getElementById('opexAsPctRevenue'); depreciationRateInput = document.getElementById('depreciationRate'); interestRateOnDebtInput = document.getElementById('interestRateOnDebt'); taxRateInput = document.getElementById('taxRate'); // Investment & Working Capital Assumptions Inputs capexAsPctRevenueInput = document.getElementById('capexAsPctRevenue'); arDaysInput = document.getElementById('arDays'); inventoryDaysInput = document.getElementById('inventoryDays'); apDaysInput = document.getElementById('apDays'); accruedDaysInput = document.getElementById('accruedDays'); // Output Elements incomeStatementOutputDiv = document.getElementById('incomeStatementOutput'); cashFlowOutputDiv = document.getElementById('cashFlowOutput'); balanceSheetOutputDiv = document.getElementById('balanceSheetOutput'); keyMetricsOutputDiv = document.getElementById('keyMetricsOutput'); messageBox = document.getElementById('messageBox'); // Initialize navigation button states updateNavigationButtons(); });