293 lines
12 KiB
JavaScript
293 lines
12 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
const form = document.getElementById('calculator-form');
|
|
const contractTypeSelector = document.getElementById('contract-type-selector');
|
|
const dynamicOptionsContainer = document.getElementById('dynamic-options');
|
|
const resultsContainer = document.getElementById('results');
|
|
const resultsSummary = document.getElementById('results-summary');
|
|
|
|
// --- CONFIGURATION & CONSTANTS (for 2025, simplified) ---
|
|
const UOP_CONSTANTS = {
|
|
TAX_FREE_AMOUNT: 30000,
|
|
TAX_THRESHOLD_1: 120000,
|
|
TAX_RATE_1: 0.12,
|
|
TAX_RATE_2: 0.32,
|
|
PENSION_RATE: 0.0976,
|
|
DISABILITY_RATE: 0.015,
|
|
SICKNESS_RATE: 0.0245,
|
|
HEALTH_INSURANCE_RATE: 0.09,
|
|
};
|
|
|
|
const B2B_CONSTANTS = {
|
|
BIG_ZUS_HEALTH: 626.93,
|
|
BIG_ZUS_SOCIAL: 1600.32,
|
|
LINEAR_TAX_RATE: 0.19,
|
|
};
|
|
|
|
const INKUBATOR_CONSTANTS = {
|
|
FEE: 350,
|
|
ZUS_RATE: 0.0976 + 0.015,
|
|
};
|
|
|
|
const UZ_CONSTANTS = {
|
|
COST_OF_INCOME_RATE: 0.20,
|
|
};
|
|
|
|
const UOD_CONSTANTS = {
|
|
COST_OF_INCOME_RATE_20: 0.20,
|
|
COST_OF_INCOME_RATE_50: 0.50,
|
|
};
|
|
|
|
|
|
// --- UI UPDATE FUNCTIONS ---
|
|
function updateDynamicOptions() {
|
|
const contractType = document.querySelector('input[name="contractType"]:checked').value;
|
|
let optionsHtml = '';
|
|
|
|
if (contractType === 'b2b') {
|
|
optionsHtml = `
|
|
<div class="dynamic-option-set">
|
|
<label class="form-label fw-bold">Forma opodatkowania</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="b2bTaxType" id="b2bLinear" value="linear" checked>
|
|
<label class="form-check-label" for="b2bLinear">Liniowy (19%)</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="b2bTaxType" id="b2bScale" value="scale">
|
|
<label class="form-check-label" for="b2bScale">Skala podatkowa</label>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else if (contractType === 'uop') {
|
|
optionsHtml = `
|
|
<div class="dynamic-option-set">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" role="switch" id="uopUnder26" checked>
|
|
<label class="form-check-label" for="uopUnder26">Mam mniej niż 26 lat (zerowy PIT)</label>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else if (contractType === 'uz') {
|
|
optionsHtml = `
|
|
<div class="dynamic-option-set">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" role="switch" id="uzUnder26" checked>
|
|
<label class="form-check-label" for="uzUnder26">Jestem studentem/uczniem do 26 r.ż.</label>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" role="switch" id="uzVoluntarySickness">
|
|
<label class="form-check-label" for="uzVoluntarySickness">Dobrowolne ubezp. chorobowe</label>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else if (contractType === 'uod') {
|
|
optionsHtml = `
|
|
<div class="dynamic-option-set">
|
|
<label class="form-label fw-bold">Koszty uzyskania przychodu</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="uodCostType" id="uodCost20" value="20" checked>
|
|
<label class="form-check-label" for="uodCost20">Standardowe (20%)</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="uodCostType" id="uodCost50" value="50">
|
|
<label class="form-check-label" for="uodCost50">Prawa autorskie (50%)</label>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
dynamicOptionsContainer.innerHTML = optionsHtml;
|
|
}
|
|
|
|
// --- CALCULATION LOGIC ---
|
|
function calculateUoP(amount, amountType, options) {
|
|
let grossAmount, netAmount;
|
|
const isUnder26 = options.under26;
|
|
|
|
if (amountType === 'gross') {
|
|
grossAmount = amount;
|
|
const pension = grossAmount * UOP_CONSTANTS.PENSION_RATE;
|
|
const disability = grossAmount * UOP_CONSTANTS.DISABILITY_RATE;
|
|
const sickness = grossAmount * UOP_CONSTANTS.SICKNESS_RATE;
|
|
const socialContributions = pension + disability + sickness;
|
|
|
|
const healthInsuranceBase = grossAmount - socialContributions;
|
|
const healthInsurance = healthInsuranceBase * UOP_CONSTANTS.HEALTH_INSURANCE_RATE;
|
|
|
|
let taxBase = Math.round(healthInsuranceBase);
|
|
let tax = 0;
|
|
if (!isUnder26) {
|
|
const annualIncome = grossAmount * 12;
|
|
if (annualIncome > UOP_CONSTANTS.TAX_THRESHOLD_1) {
|
|
tax = (taxBase * UOP_CONSTANTS.TAX_RATE_2) / 12;
|
|
} else {
|
|
tax = (taxBase * UOP_CONSTANTS.TAX_RATE_1) / 12;
|
|
}
|
|
tax = Math.max(0, tax);
|
|
}
|
|
|
|
netAmount = grossAmount - socialContributions - healthInsurance - tax;
|
|
return { gross: grossAmount, net: netAmount, social: socialContributions, health: healthInsurance, tax: tax };
|
|
}
|
|
return { gross: 'Brak obliczeń', net: amount };
|
|
}
|
|
|
|
function calculateB2B(amount, amountType, options) {
|
|
if (amountType === 'gross') {
|
|
const income = amount;
|
|
const social = B2B_CONSTANTS.BIG_ZUS_SOCIAL;
|
|
const health = B2B_CONSTANTS.BIG_ZUS_HEALTH;
|
|
const taxBase = Math.max(0, income - social);
|
|
let tax = 0;
|
|
if (options.taxType === 'linear') {
|
|
tax = taxBase * B2B_CONSTANTS.LINEAR_TAX_RATE;
|
|
}
|
|
else {
|
|
tax = (taxBase * UOP_CONSTANTS.TAX_RATE_1);
|
|
}
|
|
const netAmount = income - social - health - tax;
|
|
return { gross: income, net: netAmount, social: social, health: health, tax: tax };
|
|
}
|
|
return { gross: 'Brak obliczeń', net: amount };
|
|
}
|
|
|
|
function calculateInkubator(amount, amountType) {
|
|
if (amountType === 'gross') {
|
|
const income = amount;
|
|
const fee = INKUBATOR_CONSTANTS.FEE;
|
|
const zus = 250; // Simplified fixed ZUS
|
|
const tax = (income - fee - zus) * UOP_CONSTANTS.TAX_RATE_1;
|
|
const netAmount = income - fee - zus - tax;
|
|
return { gross: income, net: netAmount, fee: fee, zus: zus, tax: tax };
|
|
}
|
|
return { gross: 'Brak obliczeń', net: amount };
|
|
}
|
|
|
|
function calculateUZ(amount, amountType, options) {
|
|
if (amountType === 'gross') {
|
|
const grossAmount = amount;
|
|
if (options.isStudent) {
|
|
return { gross: grossAmount, net: grossAmount, social: 0, health: 0, tax: 0 };
|
|
}
|
|
|
|
const costOfIncome = grossAmount * UZ_CONSTANTS.COST_OF_INCOME_RATE;
|
|
|
|
let socialContributions = 0;
|
|
let healthInsurance = 0;
|
|
let sickness = 0;
|
|
|
|
const pension = grossAmount * UOP_CONSTANTS.PENSION_RATE;
|
|
const disability = grossAmount * UOP_CONSTANTS.DISABILITY_RATE;
|
|
socialContributions = pension + disability;
|
|
|
|
if (options.voluntarySickness) {
|
|
sickness = grossAmount * UOP_CONSTANTS.SICKNESS_RATE;
|
|
socialContributions += sickness;
|
|
}
|
|
|
|
const healthInsuranceBase = grossAmount - socialContributions;
|
|
healthInsurance = healthInsuranceBase * UOP_CONSTANTS.HEALTH_INSURANCE_RATE;
|
|
|
|
const taxBase = Math.round(grossAmount - costOfIncome - socialContributions);
|
|
const tax = Math.max(0, taxBase * UOP_CONSTANTS.TAX_RATE_1);
|
|
|
|
const netAmount = grossAmount - socialContributions - healthInsurance - tax;
|
|
return { gross: grossAmount, net: netAmount, social: socialContributions, health: healthInsurance, tax: tax };
|
|
}
|
|
return { gross: 'Brak obliczeń', net: amount };
|
|
}
|
|
|
|
function calculateUOD(amount, amountType, options) {
|
|
if (amountType === 'gross') {
|
|
const grossAmount = amount;
|
|
const costRate = options.costRate === 50 ? UOD_CONSTANTS.COST_OF_INCOME_RATE_50 : UOD_CONSTANTS.COST_OF_INCOME_RATE_20;
|
|
const costOfIncome = grossAmount * costRate;
|
|
const taxBase = Math.round(grossAmount - costOfIncome);
|
|
const tax = Math.max(0, taxBase * UOP_CONSTANTS.TAX_RATE_1);
|
|
const netAmount = grossAmount - tax;
|
|
return { gross: grossAmount, net: netAmount, social: 0, health: 0, tax: tax };
|
|
}
|
|
return { gross: 'Brak obliczeń', net: amount };
|
|
}
|
|
|
|
// --- DISPLAY RESULTS ---
|
|
function displayResults(results) {
|
|
let html = '';
|
|
const { gross, net, ...details } = results;
|
|
|
|
html += `
|
|
<div class="col-md-6">
|
|
${createResultItem('Kwota Brutto', gross)}
|
|
${createResultItem('Składki ZUS', details.social || details.zus)}
|
|
${createResultItem('Ubezp. zdrowotne', details.health)}
|
|
${createResultItem('Podatek PIT', details.tax)}
|
|
${createResultItem('Opłata dla inkubatora', details.fee)}
|
|
</div>
|
|
<div class="col-md-6 d-flex align-items-center justify-content-center">
|
|
<div class="result-total w-100">
|
|
<span class="label">Na rękę</span>
|
|
<span class="value">${net.toFixed(2)} PLN</span>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
resultsSummary.innerHTML = html;
|
|
resultsContainer.style.display = 'block';
|
|
}
|
|
|
|
function createResultItem(label, value) {
|
|
if (value === undefined || value === null) return '';
|
|
const val = typeof value === 'number' ? `${value.toFixed(2)} PLN` : value;
|
|
return `
|
|
<div class="result-item">
|
|
<span class="label">${label}</span>
|
|
<span class="value">${val}</span>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// --- EVENT HANDLERS ---
|
|
form.addEventListener('submit', function (e) {
|
|
e.preventDefault();
|
|
|
|
const contractType = document.querySelector('input[name="contractType"]:checked').value;
|
|
const amount = parseFloat(document.getElementById('amount').value);
|
|
const amountType = document.querySelector('input[name="amountType"]:checked').value;
|
|
|
|
if (isNaN(amount) || amount <= 0) {
|
|
alert('Proszę podać poprawną kwotę.');
|
|
return;
|
|
}
|
|
|
|
let results;
|
|
if (contractType === 'uop') {
|
|
const options = { under26: document.getElementById('uopUnder26').checked };
|
|
results = calculateUoP(amount, amountType, options);
|
|
} else if (contractType === 'b2b') {
|
|
const options = { taxType: document.querySelector('input[name="b2bTaxType"]:checked').value };
|
|
results = calculateB2B(amount, amountType, options);
|
|
} else if (contractType === 'inkubator') {
|
|
results = calculateInkubator(amount, amountType);
|
|
} else if (contractType === 'uz') {
|
|
const options = {
|
|
isStudent: document.getElementById('uzUnder26').checked,
|
|
voluntarySickness: document.getElementById('uzVoluntarySickness').checked
|
|
};
|
|
results = calculateUZ(amount, amountType, options);
|
|
} else if (contractType === 'uod') {
|
|
const options = {
|
|
costRate: parseInt(document.querySelector('input[name="uodCostType"]:checked').value)
|
|
};
|
|
results = calculateUOD(amount, amountType, options);
|
|
}
|
|
|
|
|
|
if (results) {
|
|
displayResults(results);
|
|
}
|
|
});
|
|
|
|
contractTypeSelector.addEventListener('change', updateDynamicOptions);
|
|
|
|
// --- INITIALIZATION ---
|
|
updateDynamicOptions();
|
|
});
|