// Forecasting module with 5 tabs
const Forecasting = () => {
const [tab, setTab] = React.useState('cashflow');
const [scenarioVars, setScenarioVars] = React.useState({ revenues: 0, costs: 0, rates: 3.8 });
const F = window.REGULA_EXT.forecasting;
const tabs = [
{ id: 'cashflow', label: 'Cash Flow' },
{ id: 'bva', label: 'Budget vs Actual' },
{ id: 'whatif', label: 'What-If Scenario' },
{ id: 'roi', label: 'ROI Simulator' },
{ id: 'stress', label: 'Stress Test Covenant' }
];
// Line chart helper
const LineChart = ({ data, w = 860, h = 180, label = "M€" }) => {
const padL = 28, padR = 12, padT = 12, padB = 24;
const cw = w - padL - padR, ch = h - padT - padB;
const min = Math.min(...data) * 0.95, max = Math.max(...data) * 1.05;
const step = cw / (data.length - 1);
const y = v => padT + ch - ((v - min) / (max - min)) * ch;
const pts = data.map((v, i) => [padL + i * step, y(v)]);
const d = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p[0] + ',' + p[1]).join(' ');
const areaD = d + ` L${padL + cw},${padT + ch} L${padL},${padT + ch} Z`;
return (
);
};
return (
Forecasting
Proiezioni AI · rolling 13 settimane · 12 mesi · 3-5 anni
{tabs.map(t => (
setTab(t.id)}>{t.label}
))}
{tab === 'cashflow' && (
<>
Cash flow rolling · 13 settimane
Min 39.6 M€
Max 44.8 M€
Cash in · principali flussi in ingresso
| Fonte | Società | 13w | 12m |
| Incassi clienti commerciali | MetalTech | 12.4 | 48.6 |
| Ticket parco stagionali | Aqua World | 4.8 | 18.6 |
| Incassi serate + bar | Club Lumière | 1.6 | 6.4 |
| Donazioni + 5×1000 | Fondazione | 0.9 | 3.8 |
| Totale | 19.7 | 77.4 |
Cash out · principali flussi in uscita
| Categoria | Società | 13w | 12m |
| Stipendi e contributi | Tutte | −6.2 | −24.8 |
| Fornitori materie prime | MetalTech | −5.4 | −21.6 |
| Rate mutui e oneri fin. | Tutte | −2.1 | −8.0 |
| F24 e imposte | Tutte | −1.8 | −16.0 |
| Totale | −15.5 | −70.4 |
>
)}
{tab === 'bva' && (
Scostamenti YTD con proiezione FY
Proiezione automatica
| Categoria |
Actual YTD |
Budget YTD |
Δ YTD |
Proiezione FY |
Budget FY |
Δ FY attesa |
{F.bva.map((row, i) => {
const dytd = ((row.actual - row.budget) / row.budget) * 100;
const dfy = ((row.fy - row.fyBudget) / row.fyBudget) * 100;
return (
| {row.category} |
{row.actual.toFixed(1)} |
{row.budget.toFixed(1)} |
0 ? 'var(--green)' : 'var(--red)' }}>{dytd > 0 ? '+' : ''}{dytd.toFixed(1)}% |
{row.fy.toFixed(1)} |
{row.fyBudget.toFixed(1)} |
0 ? 'var(--green)' : 'var(--red)' }}>{dfy > 0 ? '+' : ''}{dfy.toFixed(1)}% |
);
})}
)}
{tab === 'whatif' && (
{[
{ key: 'revenues', label: 'Ricavi', unit: '%', min: -20, max: 20 },
{ key: 'costs', label: 'Costi variabili', unit: '%', min: -10, max: 20 },
{ key: 'rates', label: 'Tasso medio debito', unit: '%', min: 2, max: 7, step: 0.1 }
].map(v => (
{v.label}
{scenarioVars[v.key]}{v.unit}
setScenarioVars({ ...scenarioVars, [v.key]: parseFloat(e.target.value) })}
style={{ width: '100%' }}
/>
{v.min}{v.unit}{v.max}{v.unit}
))}
| Scenario |
Ricavi | Costi | Tassi |
EBITDA | Utile netto | Cash EoY |
{F.scenarios.map((s, i) => (
| {s.name} |
0 ? 'var(--green)' : s.revenues < 0 ? 'var(--red)' : 'var(--muted)' }}>{s.revenues > 0 ? '+' : ''}{s.revenues}% |
0 ? 'var(--red)' : 'var(--muted)' }}>{s.costs > 0 ? '+' : ''}{s.costs}% |
{s.rates}% |
{s.ebitda.toFixed(1)} |
{s.netIncome.toFixed(1)} |
{s.cash.toFixed(1)} |
))}
)}
{tab === 'roi' && (
{[
['Importo investimento', '3.5 M€'],
['Cash flow annuale atteso', '820 k€'],
['Durata', '8 anni'],
['WACC', '6.2%'],
['Valore terminale', '1.2 M€']
].map(([l, v]) => (
{l}
{v}
))}
{[
['Payback', '5.2 anni'], ['IRR', '11.4%'], ['NPV', '+1.82 M€']
].map(([l, v]) => (
))}
| CF atteso \ WACC | 5.0% | 6.2% | 7.5% | 9.0% |
| 700 k€ | 0.88 | 0.24 | −0.40 | −1.08 |
| 820 k€ | 2.62 | 1.82 | 1.04 | 0.22 |
| 950 k€ | 4.50 | 3.50 | 2.58 | 1.62 |
)}
{tab === 'stress' && (
Monitoraggio covenant bancari
2 OK
2 Attenzione
2 Sforati
| Covenant | Società | Soglia | Valore | Margine | Rating |
{F.covenants.map((c, i) => (
| {c.name} |
{c.company} |
{c.threshold} |
{c.actual} |
{c.margin} |
● {c.status === 'green' ? 'OK' : c.status === 'amber' ? 'Attenzione' : 'Sforato'} |
))}
)}
);
};
Object.assign(window, { Forecasting });