33976-vm/assets/js/main.js
Flatlogic Bot 51dadbaf0e v1
2025-09-09 21:45:18 +00:00

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();
});