mirror of
https://github.com/itflow-org/itflow
synced 2026-11-11 07:01:16 +00:00
110 lines
4.6 KiB
JavaScript
110 lines
4.6 KiB
JavaScript
// New Tax and Edit Tax (admin/modals/tax/tax_form.php): one rate, or parts.
|
|
// "Split into parts" turns the rate into a first part; parts can be added
|
|
// and removed, and "Comes to" shows the whole rate as it is typed - a part
|
|
// on top is charged on the line plus the parts above it, like
|
|
// taxEffectivePercent() in functions/tax.php. Removing every part goes back
|
|
// to one rate. The server works the rate out again on saving.
|
|
//
|
|
// Wrapped in an IIFE because a modal can be opened, closed and opened again
|
|
// in one page load, which re-runs this file.
|
|
|
|
(function () {
|
|
|
|
document.querySelectorAll('[data-tax-form]:not([data-wired])').forEach(function (form) {
|
|
form.setAttribute('data-wired', '1');
|
|
|
|
const single = form.querySelector('[data-tax-single]');
|
|
const percent = form.querySelector('[data-tax-percent]');
|
|
const partsBox = form.querySelector('[data-tax-parts]');
|
|
const rows = form.querySelector('[data-tax-part-rows]');
|
|
const template = form.querySelector('[data-tax-part-template]');
|
|
const total = form.querySelector('[data-tax-total]');
|
|
const name = form.querySelector('input[name="name"]');
|
|
let nextKey = rows.querySelectorAll('[data-tax-part]').length;
|
|
|
|
function number(value) {
|
|
const n = parseFloat(String(value).replace(/[%\s]/g, ''));
|
|
return isNaN(n) ? 0 : n;
|
|
}
|
|
|
|
function text(n) {
|
|
return String(Math.round(n * 10000) / 10000);
|
|
}
|
|
|
|
function update() {
|
|
const parts = rows.querySelectorAll('[data-tax-part]');
|
|
const usingParts = parts.length > 0;
|
|
single.classList.toggle('d-none', usingParts);
|
|
partsBox.classList.toggle('d-none', !usingParts);
|
|
percent.disabled = usingParts;
|
|
percent.required = !usingParts;
|
|
|
|
let sum = 0;
|
|
parts.forEach(function (row, i) {
|
|
const compound = row.querySelector('[data-tax-part-compound]');
|
|
const nameInput = row.querySelector('[data-tax-part-name]');
|
|
const percentInput = row.querySelector('[data-tax-part-percent]');
|
|
// The first part has nothing above it to go on top of
|
|
compound.disabled = i === 0;
|
|
if (i === 0) {
|
|
compound.checked = false;
|
|
}
|
|
compound.closest('.form-check').classList.toggle('invisible', i === 0);
|
|
nameInput.required = true;
|
|
percentInput.required = true;
|
|
const p = number(percentInput.value);
|
|
sum += compound.checked ? p * (1 + sum / 100) : p;
|
|
});
|
|
total.textContent = text(sum) + '%';
|
|
}
|
|
|
|
function addPart(values) {
|
|
const key = 'n' + (nextKey++);
|
|
const holder = document.createElement('div');
|
|
holder.innerHTML = template.innerHTML.replace(/__KEY__/g, key);
|
|
const row = holder.firstElementChild;
|
|
if (values) {
|
|
row.querySelector('[data-tax-part-name]').value = values.name || '';
|
|
row.querySelector('[data-tax-part-percent]').value = values.percent || '';
|
|
}
|
|
rows.appendChild(row);
|
|
update();
|
|
return row;
|
|
}
|
|
|
|
form.querySelector('[data-tax-split]').addEventListener('click', function () {
|
|
addPart({name: name.value.trim(), percent: percent.value.trim()});
|
|
addPart().querySelector('[data-tax-part-name]').focus();
|
|
});
|
|
|
|
form.querySelector('[data-tax-add-part]').addEventListener('click', function () {
|
|
addPart().querySelector('[data-tax-part-name]').focus();
|
|
});
|
|
|
|
rows.addEventListener('click', function (e) {
|
|
const remove = e.target.closest('[data-tax-remove-part]');
|
|
if (!remove) {
|
|
return;
|
|
}
|
|
const parts = rows.querySelectorAll('[data-tax-part]');
|
|
// Down to one part, it is just the rate again
|
|
if (parts.length === 2) {
|
|
const keep = parts[0] === remove.closest('[data-tax-part]') ? parts[1] : parts[0];
|
|
const keepPercent = keep.querySelector('[data-tax-part-percent]').value;
|
|
parts.forEach(function (row) {
|
|
row.remove();
|
|
});
|
|
percent.value = keepPercent;
|
|
} else {
|
|
remove.closest('[data-tax-part]').remove();
|
|
}
|
|
update();
|
|
});
|
|
|
|
rows.addEventListener('input', update);
|
|
rows.addEventListener('change', update);
|
|
update();
|
|
});
|
|
|
|
})();
|