Add index.html
This commit is contained in:
512
index.html
Normal file
512
index.html
Normal file
@@ -0,0 +1,512 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Calcolatore Prezzi Software (Italia)</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
.card {
|
||||
background-color: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
.card:hover {
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.input-group label {
|
||||
margin-bottom: 0.5rem;
|
||||
color: #4b5563;
|
||||
font-weight: 500;
|
||||
}
|
||||
.input-field {
|
||||
padding: 0.75rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.5rem;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.input-field:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
.btn {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
}
|
||||
.btn-secondary {
|
||||
background-color: #e5e7eb;
|
||||
color: #374151;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background-color: #d1d5db;
|
||||
}
|
||||
.results-grid {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.results-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
.result-box {
|
||||
padding: 1.5rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
.result-box h3 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding-bottom: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.result-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid #f3f4f6;
|
||||
}
|
||||
.result-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.result-item-label {
|
||||
color: #6b7280;
|
||||
}
|
||||
.result-item-value {
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
}
|
||||
.total {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: #16a34a;
|
||||
}
|
||||
.net-total {
|
||||
color: #059669;
|
||||
}
|
||||
.info-tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.info-tooltip .tooltip-text {
|
||||
visibility: hidden;
|
||||
width: 250px;
|
||||
background-color: #374151;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 125%;
|
||||
left: 50%;
|
||||
margin-left: -125px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
.info-tooltip:hover .tooltip-text {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="p-4 sm:p-6 lg:p-8">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<!-- Header -->
|
||||
<header class="text-center mb-8">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-gray-800">Calcolatore Prezzi Software</h1>
|
||||
<p id="sub-header" class="mt-2 text-lg text-gray-600">Per Liberi Professionisti in Italia</p>
|
||||
</header>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<!-- Colonna Sinistra: Input -->
|
||||
<div class="lg:col-span-1 space-y-6">
|
||||
<!-- Card Configurazione -->
|
||||
<div class="card p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-700 border-b pb-3 mb-4">Configurazione</h2>
|
||||
<div class="input-group">
|
||||
<label for="taxRegime">Seleziona Tipologia Fiscale</label>
|
||||
<select id="taxRegime" class="input-field bg-white">
|
||||
<option value="forfettario">Regime Forfettario</option>
|
||||
<option value="ordinario">Regime Ordinario (Semplificato)</option>
|
||||
<option value="occasionale">Lavoro Autonomo Occasionale</option>
|
||||
<option value="minimi">Regime dei Minimi (ad esaurimento)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="forfettario-options">
|
||||
<div class="input-group">
|
||||
<label for="coeffRedditivita">Coefficiente di Redditività (%)</label>
|
||||
<input type="number" id="coeffRedditivita" class="input-field" value="78">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="impostaSostitutiva">Aliquota Imposta Sostitutiva</label>
|
||||
<select id="impostaSostitutiva" class="input-field bg-white">
|
||||
<option value="0.05">5% (Startup)</option>
|
||||
<option value="0.15">15% (Standard)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="devRate">Tariffa Oraria Sviluppo (€)</label>
|
||||
<input type="number" id="devRate" class="input-field" value="50">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="supportRate">Tariffa Oraria Supporto (€)</label>
|
||||
<input type="number" id="supportRate" class="input-field" value="40">
|
||||
</div>
|
||||
<div id="annualIncomeGroup" class="input-group">
|
||||
<label for="estimatedAnnualTaxable" class="flex items-center">
|
||||
Altri Redditi IRPEF St. (€)
|
||||
<div class="info-tooltip ml-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" /></svg>
|
||||
<span class="tooltip-text">Inserisci altri redditi imponibili IRPEF per calcolare l'imposta marginale per questo progetto in modo più accurato.</span>
|
||||
</div>
|
||||
</label>
|
||||
<input type="number" id="estimatedAnnualTaxable" class="input-field" value="25000">
|
||||
</div>
|
||||
<div class="flex items-center justify-between" id="inps-rivalsa-group">
|
||||
<label for="includeINPS" class="text-gray-700 flex items-center">
|
||||
Includi rivalsa INPS 4%?
|
||||
<div class="info-tooltip ml-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" /></svg>
|
||||
<span class="tooltip-text">Aggiunge un contributo previdenziale INPS del 4% (rivalsa) alla fattura del cliente. Questo importo fa parte del tuo fatturato.</span>
|
||||
</div>
|
||||
</label>
|
||||
<input type="checkbox" id="includeINPS" class="h-5 w-5 text-blue-600 border-gray-300 rounded focus:ring-blue-500" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card MVP -->
|
||||
<div class="card p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-700 border-b pb-3 mb-4">Prima Milestone (MVP)</h2>
|
||||
<div class="input-group">
|
||||
<label for="mvpDevHours">Token Sviluppo (Ore)</label>
|
||||
<input type="number" id="mvpDevHours" class="input-field" value="100">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="mvpSupportHours">Token Supporto (Ore)</label>
|
||||
<input type="number" id="mvpSupportHours" class="input-field" value="20">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card Milestone Aggiuntive -->
|
||||
<div class="card p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-700 border-b pb-3 mb-4">Milestone Aggiuntive</h2>
|
||||
<div id="custom-milestones" class="space-y-4"></div>
|
||||
<button id="add-milestone" class="btn btn-secondary w-full mt-4">Aggiungi Milestone</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Colonna Destra: Risultati -->
|
||||
<div class="lg:col-span-2">
|
||||
<div class="card p-6 sm:p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">Riepilogo Preventivo e Guadagni</h2>
|
||||
<div class="results-grid">
|
||||
|
||||
<!-- Box Preventivo Cliente -->
|
||||
<div class="result-box bg-blue-50">
|
||||
<h3>Preventivo per il Cliente</h3>
|
||||
<div class="result-item"><span class="result-item-label" id="subtotal-label">Imponibile</span><span id="subtotal" class="result-item-value font-bold">€0.00</span></div>
|
||||
<div id="inpsChargeRow" class="result-item"><span class="result-item-label">Rivalsa INPS (4%)</span><span id="inpsCharge" class="result-item-value">€0.00</span></div>
|
||||
<div id="ivaRow" class="result-item"><span class="result-item-label">IVA (22%)</span><span id="iva" class="result-item-value">€0.00</span></div>
|
||||
<div id="totalInvoiceRow" class="result-item"><span class="result-item-label font-bold">Totale Fattura</span><span id="totalInvoice" class="result-item-value font-bold">€0.00</span></div>
|
||||
<div id="withholdingTaxRow" class="result-item"><span class="result-item-label text-red-600">Ritenuta d'acconto (20%)</span><span id="withholdingTax" class="result-item-value text-red-600">- €0.00</span></div>
|
||||
<div id="amountDueRow" class="result-item mt-4"><span class="result-item-label font-bold text-lg" id="amountDueLabel">Importo dovuto dal Cliente</span><span id="amountDue" class="result-item-value total">€0.00</span></div>
|
||||
</div>
|
||||
|
||||
<!-- Box Riepilogo Guadagni -->
|
||||
<div class="result-box bg-green-50">
|
||||
<h3>Riepilogo Guadagni (Stima)</h3>
|
||||
<div class="result-item"><span id="grossRevenueLabel" class="result-item-label">Fatturato</span><span id="grossRevenue" class="result-item-value">€0.00</span></div>
|
||||
<div class="result-item"><span class="result-item-label text-red-600">Commissione Rete Vendita (10%)</span><span id="sellerFee" class="result-item-value text-red-600">- €0.00</span></div>
|
||||
<div class="result-item"><span id="netRevenueLabel" class="result-item-label">Ricavo Netto</span><span id="netRevenue" class="result-item-value font-bold">€0.00</span></div>
|
||||
<div id="inpsDueRow" class="result-item"><span class="result-item-label text-red-600">Contributi INPS (~26.07%)</span><span id="inpsDue" class="result-item-value text-red-600">- €0.00</span></div>
|
||||
<div class="result-item"><span id="taxDueLabel" class="result-item-label text-red-600">Imposta Dovuta</span><span id="taxDue" class="result-item-value text-red-600">- €0.00</span></div>
|
||||
<div class="result-item mt-4"><span class="result-item-label font-bold text-lg">Reddito Netto Stimato</span><span id="netIncome" class="result-item-value total net-total">€0.00</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6 text-xs text-gray-500 text-center">
|
||||
<p><strong>Disclaimer:</strong> Questo è uno strumento di stima. Il calcolo è basato sui principi dei regimi fiscali italiani e della Gestione Separata INPS (aliquota assunta al 26,07%). Per il Lavoro Occasionale, l'INPS non è dovuta sotto i 5.000€ annui di compensi. L'IVA è considerata neutrale per il professionista. La tassazione effettiva dipende dal reddito annuo totale e dai costi deducibili. Consulta sempre un commercialista per una consulenza finanziaria accurata.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const inputs = document.querySelectorAll('input, select');
|
||||
const addMilestoneBtn = document.getElementById('add-milestone');
|
||||
const customMilestonesContainer = document.getElementById('custom-milestones');
|
||||
const taxRegimeSelector = document.getElementById('taxRegime');
|
||||
|
||||
const calculateIrpef = (income) => {
|
||||
if (income <= 0) return 0;
|
||||
let tax = 0;
|
||||
const bracket1 = 28000;
|
||||
const bracket2 = 50000;
|
||||
|
||||
if (income <= bracket1) {
|
||||
tax = income * 0.23;
|
||||
} else if (income <= bracket2) {
|
||||
tax = (bracket1 * 0.23) + ((income - bracket1) * 0.35);
|
||||
} else {
|
||||
tax = (bracket1 * 0.23) + ((bracket2 - bracket1) * 0.35) + ((income - bracket2) * 0.43);
|
||||
}
|
||||
return tax;
|
||||
};
|
||||
|
||||
const calculate = () => {
|
||||
const regime = taxRegimeSelector.value;
|
||||
const devRate = parseFloat(document.getElementById('devRate').value) || 0;
|
||||
const supportRate = parseFloat(document.getElementById('supportRate').value) || 0;
|
||||
const mvpDevHours = parseFloat(document.getElementById('mvpDevHours').value) || 0;
|
||||
const mvpSupportHours = parseFloat(document.getElementById('mvpSupportHours').value) || 0;
|
||||
const includeINPS = document.getElementById('includeINPS').checked;
|
||||
|
||||
let totalCustomCost = 0;
|
||||
document.querySelectorAll('.custom-milestone').forEach(milestone => {
|
||||
const devHours = parseFloat(milestone.querySelector('.milestone-dev-hours').value) || 0;
|
||||
const supportHours = parseFloat(milestone.querySelector('.milestone-support-hours').value) || 0;
|
||||
totalCustomCost += (devHours * devRate) + (supportHours * supportRate);
|
||||
});
|
||||
|
||||
const subtotal = (mvpDevHours * devRate) + (mvpSupportHours * supportRate) + totalCustomCost;
|
||||
|
||||
let uiData = {};
|
||||
const INPS_RATE = 0.2607;
|
||||
const inpsCharge = (regime !== 'occasionale' && includeINPS) ? subtotal * 0.04 : 0;
|
||||
|
||||
switch(regime) {
|
||||
case 'ordinario': {
|
||||
const estimatedAnnualTaxable = parseFloat(document.getElementById('estimatedAnnualTaxable').value) || 0;
|
||||
const ivaBase = subtotal + inpsCharge;
|
||||
const iva = ivaBase * 0.22;
|
||||
const totalInvoice = ivaBase + iva;
|
||||
const withholdingTax = subtotal * 0.20;
|
||||
const amountDue = totalInvoice - withholdingTax;
|
||||
|
||||
const grossRevenue = subtotal + inpsCharge;
|
||||
const sellerFee = grossRevenue * 0.10;
|
||||
const netRevenue = grossRevenue - sellerFee;
|
||||
const inpsDue = netRevenue * INPS_RATE;
|
||||
const taxableForIrpef = netRevenue - inpsDue;
|
||||
|
||||
const totalIrpefWithProject = calculateIrpef(estimatedAnnualTaxable + taxableForIrpef);
|
||||
const irpefOnPreviousIncome = calculateIrpef(estimatedAnnualTaxable);
|
||||
const taxDue = totalIrpefWithProject - irpefOnPreviousIncome;
|
||||
|
||||
const netIncome = netRevenue - inpsDue - taxDue;
|
||||
|
||||
uiData = { regime, subtotal, inpsCharge, iva, totalInvoice, withholdingTax, amountDue, grossRevenue, sellerFee, netRevenue, inpsDue, taxDue, netIncome };
|
||||
break;
|
||||
}
|
||||
case 'forfettario': {
|
||||
const coeffRedditivita = (parseFloat(document.getElementById('coeffRedditivita').value) || 0) / 100;
|
||||
const impostaSostitutiva = parseFloat(document.getElementById('impostaSostitutiva').value) || 0;
|
||||
const totalInvoice = subtotal + inpsCharge;
|
||||
|
||||
const grossRevenue = totalInvoice;
|
||||
const sellerFee = grossRevenue * 0.10;
|
||||
const revenueAfterFee = grossRevenue - sellerFee;
|
||||
const taxableIncome = revenueAfterFee * coeffRedditivita;
|
||||
|
||||
const inpsDue = taxableIncome * INPS_RATE;
|
||||
const taxDue = taxableIncome * impostaSostitutiva;
|
||||
const netIncome = revenueAfterFee - inpsDue - taxDue;
|
||||
|
||||
uiData = { regime, subtotal, inpsCharge, iva: 0, totalInvoice, withholdingTax: 0, amountDue: totalInvoice, grossRevenue, sellerFee, netRevenue: revenueAfterFee, inpsDue, taxDue, netIncome };
|
||||
break;
|
||||
}
|
||||
case 'occasionale': {
|
||||
const estimatedAnnualTaxable = parseFloat(document.getElementById('estimatedAnnualTaxable').value) || 0;
|
||||
const totalReceipt = subtotal; // No INPS charge, no VAT
|
||||
const withholdingTax = subtotal * 0.20;
|
||||
const amountDue = totalReceipt - withholdingTax;
|
||||
|
||||
const grossRevenue = subtotal;
|
||||
const sellerFee = grossRevenue * 0.10;
|
||||
const netRevenue = grossRevenue - sellerFee;
|
||||
|
||||
const inpsDue = 0; // Assuming under 5k threshold
|
||||
const taxableForIrpef = netRevenue;
|
||||
|
||||
const totalIrpefWithProject = calculateIrpef(estimatedAnnualTaxable + taxableForIrpef);
|
||||
const irpefOnPreviousIncome = calculateIrpef(estimatedAnnualTaxable);
|
||||
const taxDue = totalIrpefWithProject - irpefOnPreviousIncome;
|
||||
|
||||
const netIncome = netRevenue - taxDue;
|
||||
|
||||
uiData = { regime, subtotal, inpsCharge: 0, iva: 0, totalInvoice: totalReceipt, withholdingTax, amountDue, grossRevenue, sellerFee, netRevenue, inpsDue, taxDue, netIncome };
|
||||
break;
|
||||
}
|
||||
case 'minimi': {
|
||||
const TAX_RATE = 0.05;
|
||||
const totalInvoice = subtotal + inpsCharge;
|
||||
|
||||
const grossRevenue = totalInvoice;
|
||||
const sellerFee = grossRevenue * 0.10;
|
||||
const taxableIncome = grossRevenue - sellerFee;
|
||||
|
||||
const inpsDue = taxableIncome * INPS_RATE;
|
||||
const taxDue = taxableIncome * TAX_RATE;
|
||||
const netIncome = taxableIncome - inpsDue - taxDue;
|
||||
|
||||
uiData = { regime, subtotal, inpsCharge, iva: 0, totalInvoice, withholdingTax: 0, amountDue: totalInvoice, grossRevenue, sellerFee, netRevenue: taxableIncome, inpsDue, taxDue, netIncome };
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateUI(uiData);
|
||||
};
|
||||
|
||||
const updateUI = (data) => {
|
||||
const formatCurrency = (value) => `€${value.toFixed(2)}`;
|
||||
|
||||
const forfettarioOptions = document.getElementById('forfettario-options');
|
||||
const annualIncomeGroup = document.getElementById('annualIncomeGroup');
|
||||
const ivaRow = document.getElementById('ivaRow');
|
||||
const withholdingTaxRow = document.getElementById('withholdingTaxRow');
|
||||
const amountDueRow = document.getElementById('amountDueRow');
|
||||
const inpsRivalsaGroup = document.getElementById('inps-rivalsa-group');
|
||||
const inpsChargeRow = document.getElementById('inpsChargeRow');
|
||||
const totalInvoiceRow = document.getElementById('totalInvoiceRow');
|
||||
const inpsDueRow = document.getElementById('inpsDueRow');
|
||||
|
||||
// Reset all to hidden, then enable based on regime
|
||||
forfettarioOptions.style.display = 'none';
|
||||
annualIncomeGroup.style.display = 'none';
|
||||
ivaRow.style.display = 'none';
|
||||
withholdingTaxRow.style.display = 'none';
|
||||
inpsRivalsaGroup.style.display = 'flex';
|
||||
inpsChargeRow.style.display = 'flex';
|
||||
totalInvoiceRow.style.display = 'flex';
|
||||
inpsDueRow.style.display = 'flex';
|
||||
|
||||
let subHeaderText = '';
|
||||
|
||||
switch(data.regime) {
|
||||
case 'ordinario':
|
||||
annualIncomeGroup.style.display = 'flex';
|
||||
ivaRow.style.display = 'flex';
|
||||
withholdingTaxRow.style.display = 'flex';
|
||||
document.getElementById('subtotal-label').textContent = "Imponibile";
|
||||
document.getElementById('netRevenueLabel').textContent = "Ricavo Netto";
|
||||
document.getElementById('taxDueLabel').textContent = "IRPEF Stimato";
|
||||
document.getElementById('grossRevenueLabel').textContent = "Fatturato (Imponibile + Rivalsa)";
|
||||
subHeaderText = 'Regime Ordinario (Semplificato)';
|
||||
break;
|
||||
case 'forfettario':
|
||||
forfettarioOptions.style.display = 'block';
|
||||
document.getElementById('subtotal-label').textContent = "Imponibile";
|
||||
document.getElementById('netRevenueLabel').textContent = "Ricavo Post-Commissioni";
|
||||
const taxRateText = (parseFloat(document.getElementById('impostaSostitutiva').value) * 100) + '%';
|
||||
document.getElementById('taxDueLabel').textContent = `Imposta Sostitutiva (${taxRateText})`;
|
||||
document.getElementById('grossRevenueLabel').textContent = "Fatturato";
|
||||
subHeaderText = 'Regime Forfettario';
|
||||
break;
|
||||
case 'occasionale':
|
||||
annualIncomeGroup.style.display = 'flex';
|
||||
withholdingTaxRow.style.display = 'flex';
|
||||
inpsRivalsaGroup.style.display = 'none';
|
||||
inpsChargeRow.style.display = 'none';
|
||||
totalInvoiceRow.style.display = 'none';
|
||||
inpsDueRow.style.display = 'none';
|
||||
document.getElementById('subtotal-label').textContent = "Compenso Lordo";
|
||||
document.getElementById('amountDueLabel').textContent = "Netto a pagare";
|
||||
document.getElementById('netRevenueLabel').textContent = "Ricavo Netto";
|
||||
document.getElementById('taxDueLabel').textContent = "IRPEF Stimata";
|
||||
document.getElementById('grossRevenueLabel').textContent = "Compenso Lordo";
|
||||
subHeaderText = 'Lavoro Autonomo Occasionale';
|
||||
break;
|
||||
case 'minimi':
|
||||
document.getElementById('subtotal-label').textContent = "Imponibile";
|
||||
document.getElementById('netRevenueLabel').textContent = "Reddito Imponibile";
|
||||
document.getElementById('taxDueLabel').textContent = "Imposta Sostitutiva (5%)";
|
||||
document.getElementById('grossRevenueLabel').textContent = "Fatturato";
|
||||
subHeaderText = 'Regime dei Minimi';
|
||||
break;
|
||||
}
|
||||
|
||||
document.getElementById('sub-header').textContent = `Per ${subHeaderText}`;
|
||||
const finalAmountDue = data.amountDue;
|
||||
amountDueRow.style.display = 'flex';
|
||||
|
||||
document.getElementById('subtotal').textContent = formatCurrency(data.subtotal);
|
||||
document.getElementById('inpsCharge').textContent = formatCurrency(data.inpsCharge);
|
||||
document.getElementById('iva').textContent = formatCurrency(data.iva);
|
||||
document.getElementById('totalInvoice').textContent = formatCurrency(data.totalInvoice);
|
||||
document.getElementById('withholdingTax').textContent = `- ${formatCurrency(data.withholdingTax)}`;
|
||||
document.getElementById('amountDue').textContent = formatCurrency(finalAmountDue);
|
||||
|
||||
document.getElementById('grossRevenue').textContent = formatCurrency(data.grossRevenue);
|
||||
document.getElementById('sellerFee').textContent = `- ${formatCurrency(data.sellerFee)}`;
|
||||
document.getElementById('netRevenue').textContent = formatCurrency(data.netRevenue);
|
||||
document.getElementById('inpsDue').textContent = `- ${formatCurrency(data.inpsDue)}`;
|
||||
document.getElementById('taxDue').textContent = `- ${formatCurrency(data.taxDue)}`;
|
||||
document.getElementById('netIncome').textContent = formatCurrency(data.netIncome);
|
||||
};
|
||||
|
||||
inputs.forEach(input => input.addEventListener('input', calculate));
|
||||
|
||||
let milestoneCounter = 0;
|
||||
addMilestoneBtn.addEventListener('click', () => {
|
||||
milestoneCounter++;
|
||||
const milestoneId = `milestone-${milestoneCounter}`;
|
||||
const milestoneDiv = document.createElement('div');
|
||||
milestoneDiv.className = 'custom-milestone p-4 border border-dashed rounded-lg relative';
|
||||
milestoneDiv.innerHTML = `
|
||||
<button class="remove-milestone absolute -top-2 -right-2 bg-red-500 text-white rounded-full h-6 w-6 flex items-center justify-center text-xs font-bold">×</button>
|
||||
<div class="input-group">
|
||||
<label class="text-sm" for="${milestoneId}-name">Nome Milestone</label>
|
||||
<input type="text" id="${milestoneId}-name" class="input-field text-sm" placeholder="es. Integrazione API">
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="input-group mb-0">
|
||||
<label class="text-sm" for="${milestoneId}-dev">Sviluppo (h)</label>
|
||||
<input type="number" id="${milestoneId}-dev" class="input-field text-sm milestone-dev-hours" value="0">
|
||||
</div>
|
||||
<div class="input-group mb-0">
|
||||
<label class="text-sm" for="${milestoneId}-support">Supporto (h)</label>
|
||||
<input type="number" id="${milestoneId}-support" class="input-field text-sm milestone-support-hours" value="0">
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
customMilestonesContainer.appendChild(milestoneDiv);
|
||||
|
||||
milestoneDiv.querySelectorAll('input').forEach(input => input.addEventListener('input', calculate));
|
||||
|
||||
milestoneDiv.querySelector('.remove-milestone').addEventListener('click', () => {
|
||||
milestoneDiv.remove();
|
||||
calculate();
|
||||
});
|
||||
});
|
||||
|
||||
calculate();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user