Anno Ammortamento ordinario Risparmio fiscale ordinario Risparmio fiscale extra (iper) Tot. deduzione TOT — — — —
Anno Rata annua Quota Interessi Quota Capitale Debito Residuo TOT — — — —
Anni Erogazione finanziamento Acquisto bene Rimborso rate Deduzione ordinaria Extra deduzione (nettizzata) Rimborso Sabatini Cash flow netto TOT — — — — — — —
Genera PDF
`;const win = window.open('', '_blank');if (!win) {
alert('Il browser ha bloccato la finestra di stampa. Abilita i popup per questa pagina.');
return;
}win.document.open();
win.document.write(printHtml);
win.document.close();win.onload = function () {
win.focus();
win.print();
};
}function calcola() {
const modalita = getModalitaAcquisto();
const isMutuo = modalita === 'mutuo';
const isLeasing = modalita === 'leasing';
const isMezziPropri = modalita === 'mezzi-propri';
setCalculatorLabels(modalita);if (coeffAmm <= 0 || aliqTass <= 0) {
['tbodyFiscale','tbodyMutuo','tbodyCF'].forEach(id => {
document.getElementById(id).innerHTML = '';
});
['tfC','tfD','tfE','tfF','tmC','tmD','tmE','tmF','tcC','tcD','tcE','tcF','tcG','tcH','tcI','kpiImporto','kpiNetto','kpiExtraDed','kpiAnniAmm','kpiCFnetto'].forEach(id => {
document.getElementById(id).textContent = '—';
});
document.getElementById('badgeAnni').textContent = '— anni';
document.getElementById('badgeMutuo').textContent = '— anni';
document.getElementById('badgeCF').textContent = '—';
document.getElementById('checkText').textContent = 'Seleziona settore, bene e tipo società per calcolare';
document.getElementById('checkTextCF').textContent = '—';
document.getElementById('contributoSabatini').textContent = '—';
updatePdfButtonState();
return;
}const importo = get('importo');
const sabatini = document.getElementById('sabatiniToggle').checked ? 1 : 0;
const aliqSab = 0.101;
const contributo = sabatini === 1 ? importo * aliqSab : 0;
const valoreNetto = importo - (sabatini === 1 ? aliqSab : 0) * importo;const tassoAnnuo = get('tasso');
const durataMesi = get('durataMesi');
const durataAnni = durataMesi / 12;
const tassoLeasing = get('tassoLeasing');
const durataLeasingMesi = get('durataLeasingMesi');
const durataLeasingAnni = durataLeasingMesi / 12;
const valoreRiscatto = isLeasing ? get('valoreRiscatto') : 0;
const maxiCanone = isLeasing ? get('maxiCanone') : 0;
const baseCanoniLeasing = Math.max(importo - valoreRiscatto, 0);
const baseExtraLeasing = Math.max(valoreNetto - valoreRiscatto, 0);
let erogazione = get('erogazione');const anniAmmOrdinario = Math.ceil(1 / coeffAmm) + 1;
const anniDeduzioneLeasing = Math.max(durataLeasingAnni, Math.ceil(0.5 / coeffAmm));
const anniFiscali = isLeasing ? anniDeduzioneLeasing : anniAmmOrdinario;
const durataFinanziamentoAnni = isLeasing ? durataLeasingAnni : durataAnni;
const pianoAnni = Math.max(12, Math.ceil(anniFiscali), Math.ceil(durataFinanziamentoAnni));
const extraDedC11 = isLeasing
? calcExtraDeduzioneNetta(baseExtraLeasing, aliqTass)
: calcExtraDeduzioneNetta(valoreNetto, aliqTass);
const checkBaseFiscale = isLeasing ? baseCanoniLeasing : importo;if (!isLeasing && document.activeElement.id !== 'erogazione') {
erogazione = valoreNetto;
setFormattedInputValue('erogazione', erogazione);
}document.getElementById('contributoSabatini').textContent = sabatini ? fmtEur(contributo) : '—';const MAX_ROWS = pianoAnni;
const fiscaleRows = [];for (let anno = 1; anno <= MAX_ROWS; anno++) {
let ammOrd = 0;
if (isLeasing) {
ammOrd = anno <= anniFiscali && anniFiscali > 0 ? baseCanoniLeasing / anniFiscali : 0;
} else if (anno <= anniFiscali) {
if (anno === 1) {
ammOrd = importo * coeffAmm / 2;
} else if (anno === anniFiscali) {
ammOrd = importo * (1 - coeffAmm / 2 - (anniFiscali - 2) * coeffAmm);
} else {
ammOrd = importo * coeffAmm;
}
}let extraDed = 0;
if (isLeasing) {
extraDed = anno <= anniFiscali && anniFiscali > 0 ? extraDedC11 / anniFiscali : 0;
} else if (anno <= anniFiscali) {
if (anno === 1) {
extraDed = extraDedC11 * coeffAmm / 2;
} else if (anno === anniFiscali) {
extraDed = extraDedC11 * (1 - coeffAmm / 2 - (anniFiscali - 2) * coeffAmm);
} else {
extraDed = extraDedC11 * coeffAmm;
}
}const rispOrd = ammOrd * aliqTass;
const totDed = rispOrd + extraDed;fiscaleRows.push({ anno, ammOrd, rispOrd, extraDed, totDed });
}const fiscTotAmm = fiscaleRows.reduce((s, r) => s + r.ammOrd, 0);
const fiscTotRisp = fiscaleRows.reduce((s, r) => s + r.rispOrd, 0);
const fiscTotExtra = fiscaleRows.reduce((s, r) => s + r.extraDed, 0);
const fiscTotTot = fiscaleRows.reduce((s, r) => s + r.totDed, 0);const tbodyF = document.getElementById('tbodyFiscale');
tbodyF.innerHTML = '';
fiscaleRows.forEach(r => {
const zero = r.ammOrd === 0 && r.extraDed === 0;
const tr = document.createElement('tr');
if (zero) tr.classList.add('zero-row');
tr.innerHTML = `
${r.anno} ${fmtEur(r.ammOrd)} ${fmtEur(r.rispOrd)} ${fmtEur(r.extraDed)} ${fmtEur(r.totDed)}
`;
tbodyF.appendChild(tr);
});document.getElementById('tfC').textContent = fmtEur(fiscTotAmm);
document.getElementById('tfD').textContent = fmtEur(fiscTotRisp);
document.getElementById('tfE').textContent = fmtEur(fiscTotExtra);
document.getElementById('tfF').textContent = fmtEur(fiscTotTot);const checkVal = fiscTotAmm - checkBaseFiscale;
const checkOk = Math.abs(checkVal) < 0.01;
document.getElementById('checkDot').className = 'check-dot' + (checkOk ? '' : ' error');
document.getElementById('checkText').textContent = `${isLeasing ? 'Check canoni deducibili' : 'Check ammortamento'}: ${fmtEur(checkVal)} (${checkOk ? 'OK ✓' : 'ERRORE ✗'})`;
document.getElementById('badgeAnni').textContent = `${Math.ceil(anniFiscali)} anni`;const maxMutuoAnni = pianoAnni;
const mutuoRows = [];if (isLeasing) {
let debResiduoLeasing = Math.max(baseCanoniLeasing - maxiCanone, 0);
const pvCanoni = Math.max(baseCanoniLeasing - maxiCanone - valoreRiscatto, 0);
const canoneAnnuo = durataLeasingAnni > 0 ? PMT(tassoLeasing, durataLeasingAnni, pvCanoni) : 0;
mutuoRows.push({
anno: 't0',
rata: maxiCanone,
interessi: 0,
capitale: maxiCanone,
residuo: debResiduoLeasing,
active: maxiCanone > 0 || debResiduoLeasing > 0
});for (let anno = 1; anno <= maxMutuoAnni; anno++) {
if (anno > durataLeasingAnni) {
mutuoRows.push({ anno, rata: 0, interessi: 0, capitale: 0, residuo: 0, active: false });
continue;
}
const rata = canoneAnnuo + (anno === durataLeasingAnni ? valoreRiscatto : 0);
const interessi = (anno === 1 || anno === durataLeasingAnni) ? 0 : Math.max(debResiduoLeasing, 0) * tassoLeasing;
const capitale = rata - interessi;
const residuo = anno === durataLeasingAnni ? 0 : Math.max(debResiduoLeasing - capitale, 0);
mutuoRows.push({ anno, rata, interessi, capitale, residuo, active: true });
debResiduoLeasing = residuo;
}
} else {
let debResiduo = importo;for (let anno = 1; anno <= maxMutuoAnni; anno++) {
if (!isMutuo || anno > durataAnni) {
mutuoRows.push({ anno, rata: 0, interessi: 0, capitale: 0, residuo: 0, active: false });
continue;
}
const rataMensile = PMT(tassoAnnuo / 12, durataMesi, importo);
const rata = rataMensile * 12;
const start = (anno - 1) * 12 + 1;
const end = anno * 12;
const interessi = CUMIPMT(tassoAnnuo / 12, durataMesi, importo, start, end);
const capitale = rata - interessi;
if (anno === 1) {
debResiduo = importo - capitale;
} else {
debResiduo = mutuoRows[anno - 2].residuo - capitale;
}
mutuoRows.push({ anno, rata, interessi, capitale, residuo: Math.max(0, debResiduo), active: true });
}
}const mutuoTotRata = mutuoRows.reduce((s, r) => s + r.rata, 0);
const mutuoTotInt = mutuoRows.reduce((s, r) => s + r.interessi, 0);
const mutuoTotCap = mutuoRows.reduce((s, r) => s + r.capitale, 0);
const mutuoTotRes = mutuoRows.reduce((s, r) => s + r.residuo, 0);const tbodyM = document.getElementById('tbodyMutuo');
tbodyM.innerHTML = '';
mutuoRows.forEach(r => {
const tr = document.createElement('tr');
if (!r.active) tr.classList.add('zero-row');
tr.innerHTML = `
${r.anno} ${fmtEur(r.rata)} ${fmtEur(r.interessi)} ${fmtEur(r.capitale)} ${fmtEur(r.residuo)}
`;
tbodyM.appendChild(tr);
});document.getElementById('tmC').textContent = fmtEur(mutuoTotRata);
document.getElementById('tmD').textContent = fmtEur(mutuoTotInt);
document.getElementById('tmE').textContent = fmtEur(mutuoTotCap);
document.getElementById('tmF').textContent = fmtEur(mutuoTotRes);
document.getElementById('badgeMutuo').textContent = isLeasing
? `${Math.round(durataLeasingAnni)} anni leasing`
: (isMezziPropri ? 'non previsto' : `${Math.round(durataAnni)} anni`);const cfRows = [];const cfT0 = {
anno: 't0',
erogazione: isLeasing ? 0 : erogazione,
acquisto: isLeasing ? 0 : -erogazione,
rimborso: isLeasing ? -(mutuoRows[0]?.rata || 0) : 0,
dedOrd: 0,
extraDedR: 0,
sabatiniFlow: 0
};
cfT0.cfNetto = cfT0.erogazione + cfT0.acquisto + cfT0.rimborso + cfT0.dedOrd + cfT0.extraDedR + cfT0.sabatiniFlow;for (let anno = 1; anno <= pianoAnni; anno++) {
const fRow = fiscaleRows[anno - 1] || { rispOrd: 0, extraDed: 0 };
const financeRow = isLeasing ? mutuoRows.find(r => r.anno === anno) : mutuoRows[anno - 1];let rimborso = 0;
if (isMutuo) {
rimborso = anno > durataAnni ? 0 : -(financeRow?.rata || 0);
} else if (isLeasing) {
rimborso = anno > durataLeasingAnni ? 0 : -(financeRow?.rata || 0);
}
const dedOrd = fRow.rispOrd;
const extraDedR = fRow.extraDed;
const sabatiniFlow = calcFlussoSabatini(anno, importo, contributo, sabatini);
const cfNetto = rimborso + dedOrd + extraDedR + sabatiniFlow;cfRows.push({ anno, erogazione: 0, acquisto: 0, rimborso, dedOrd, extraDedR, sabatiniFlow, cfNetto });
}const allCfRows = [cfT0, ...cfRows];
const cfTotC = allCfRows.reduce((s, r) => s + r.erogazione, 0);
const cfTotD = allCfRows.reduce((s, r) => s + r.acquisto, 0);
const cfTotE = allCfRows.reduce((s, r) => s + r.rimborso, 0);
const cfTotF = allCfRows.reduce((s, r) => s + r.dedOrd, 0);
const cfTotG = allCfRows.reduce((s, r) => s + r.extraDedR, 0);
const cfTotH = allCfRows.reduce((s, r) => s + r.sabatiniFlow, 0);
const cfTotI = allCfRows.reduce((s, r) => s + r.cfNetto, 0);const tbodyCF = document.getElementById('tbodyCF');
tbodyCF.innerHTML = '';const t0tr = document.createElement('tr');
t0tr.innerHTML = `
t0 ${fmtEur(cfT0.erogazione)} ${fmtEur(cfT0.acquisto)} ${fmtEur(cfT0.rimborso)} ${fmtEur(cfT0.dedOrd)} ${fmtEur(cfT0.extraDedR)} ${fmtEur(cfT0.sabatiniFlow)} ${fmtEur(cfT0.cfNetto)}
`;
tbodyCF.appendChild(t0tr);cfRows.forEach(r => {
const tr = document.createElement('tr');
const zero = r.rimborso === 0 && r.dedOrd === 0 && r.extraDedR === 0 && r.sabatiniFlow === 0;
if (zero) tr.classList.add('zero-row');
const cfClass = r.cfNetto >= 0 ? 'positive' : 'negative';
tr.innerHTML = `
${r.anno} ${fmtEur(r.erogazione)} ${fmtEur(r.acquisto)} ${fmtEur(r.rimborso)} ${fmtEur(r.dedOrd)} ${fmtEur(r.extraDedR)} ${fmtEur(r.sabatiniFlow)} ${fmtEur(r.cfNetto)}
`;
tbodyCF.appendChild(tr);
});document.getElementById('tcC').textContent = fmtEur(cfTotC);
document.getElementById('tcD').textContent = fmtEur(cfTotD);
document.getElementById('tcE').textContent = fmtEur(cfTotE);
document.getElementById('tcF').textContent = fmtEur(cfTotF);
document.getElementById('tcG').textContent = fmtEur(cfTotG);
document.getElementById('tcH').textContent = fmtEur(cfTotH);
document.getElementById('tcI').textContent = fmtEur(cfTotI);
document.getElementById('badgeCF').textContent = isLeasing
? `${Math.round(durataLeasingAnni)} anni leasing`
: (isMezziPropri ? 'mezzi propri' : `${Math.round(durataAnni)} anni mutuo`);const quadratura = cfTotG - extraDedC11;
const quadOk = Math.abs(quadratura) < 0.01;
document.getElementById('checkDotCF').className = 'check-dot' + (quadOk ? '' : ' error');
document.getElementById('checkTextCF').textContent = `Quadratura: ${fmtEur(quadratura)} (${quadOk ? 'OK ✓' : 'da verificare'})`;document.getElementById('kpiImporto').textContent = fmtEur(importo);
document.getElementById('kpiNetto').textContent = fmtEur(valoreNetto);
document.getElementById('kpiExtraDed').textContent = fmtEur(fiscTotExtra);
document.getElementById('kpiAnniAmm').textContent = Math.ceil(anniFiscali) + ' anni';
document.getElementById('kpiCFnetto').textContent = fmtEur(cfTotI);updatePdfButtonState();
}document.getElementById('importo').addEventListener('input', function() {
if (document.activeElement.id !== 'erogazione') {
document.getElementById('erogazione').value = this.value;
}
calcola();
});['importo', 'erogazione', 'valoreRiscatto', 'maxiCanone'].forEach(id => {
const input = document.getElementById(id);
input.value = fmtInputInteger(parseLocaleNumber(input.value));
input.addEventListener('blur', function() {
this.value = fmtInputInteger(parseLocaleNumber(this.value));
});
});onModalitaChange();