Add production pricing policy (id_pol_productie) for articles with cont 341/345, smart discount VAT splitting across multiple rates, per-article id_pol support, and mapped SKU price validation. Settings UI updated with new controls. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
182 lines
8.3 KiB
JavaScript
182 lines
8.3 KiB
JavaScript
let settAcTimeout = null;
|
|
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
await loadDropdowns();
|
|
await loadSettings();
|
|
wireAutocomplete('settTransportCodmat', 'settTransportAc');
|
|
wireAutocomplete('settDiscountCodmat', 'settDiscountAc');
|
|
});
|
|
|
|
async function loadDropdowns() {
|
|
try {
|
|
const [sectiiRes, politiciRes, gestiuniRes] = await Promise.all([
|
|
fetch('/api/settings/sectii'),
|
|
fetch('/api/settings/politici'),
|
|
fetch('/api/settings/gestiuni')
|
|
]);
|
|
const sectii = await sectiiRes.json();
|
|
const politici = await politiciRes.json();
|
|
const gestiuni = await gestiuniRes.json();
|
|
|
|
const gestiuneEl = document.getElementById('settIdGestiune');
|
|
if (gestiuneEl) {
|
|
gestiuneEl.innerHTML = '<option value="">— orice gestiune —</option>';
|
|
gestiuni.forEach(g => {
|
|
gestiuneEl.innerHTML += `<option value="${escHtml(g.id)}">${escHtml(g.label)}</option>`;
|
|
});
|
|
}
|
|
|
|
const sectieEl = document.getElementById('settIdSectie');
|
|
if (sectieEl) {
|
|
sectieEl.innerHTML = '<option value="">— selectează secție —</option>';
|
|
sectii.forEach(s => {
|
|
sectieEl.innerHTML += `<option value="${escHtml(s.id)}">${escHtml(s.label)}</option>`;
|
|
});
|
|
}
|
|
|
|
const polEl = document.getElementById('settIdPol');
|
|
if (polEl) {
|
|
polEl.innerHTML = '<option value="">— selectează politică —</option>';
|
|
politici.forEach(p => {
|
|
polEl.innerHTML += `<option value="${escHtml(p.id)}">${escHtml(p.label)}</option>`;
|
|
});
|
|
}
|
|
|
|
const tPolEl = document.getElementById('settTransportIdPol');
|
|
if (tPolEl) {
|
|
tPolEl.innerHTML = '<option value="">— implicită —</option>';
|
|
politici.forEach(p => {
|
|
tPolEl.innerHTML += `<option value="${escHtml(p.id)}">${escHtml(p.label)}</option>`;
|
|
});
|
|
}
|
|
|
|
const dPolEl = document.getElementById('settDiscountIdPol');
|
|
if (dPolEl) {
|
|
dPolEl.innerHTML = '<option value="">— implicită —</option>';
|
|
politici.forEach(p => {
|
|
dPolEl.innerHTML += `<option value="${escHtml(p.id)}">${escHtml(p.label)}</option>`;
|
|
});
|
|
}
|
|
|
|
const pPolEl = document.getElementById('settIdPolProductie');
|
|
if (pPolEl) {
|
|
pPolEl.innerHTML = '<option value="">— fără politică producție —</option>';
|
|
politici.forEach(p => {
|
|
pPolEl.innerHTML += `<option value="${escHtml(p.id)}">${escHtml(p.label)}</option>`;
|
|
});
|
|
}
|
|
} catch (err) {
|
|
console.error('loadDropdowns error:', err);
|
|
}
|
|
}
|
|
|
|
async function loadSettings() {
|
|
try {
|
|
const res = await fetch('/api/settings');
|
|
const data = await res.json();
|
|
const el = (id) => document.getElementById(id);
|
|
if (el('settTransportCodmat')) el('settTransportCodmat').value = data.transport_codmat || '';
|
|
if (el('settTransportVat')) el('settTransportVat').value = data.transport_vat || '21';
|
|
if (el('settTransportIdPol')) el('settTransportIdPol').value = data.transport_id_pol || '';
|
|
if (el('settDiscountCodmat')) el('settDiscountCodmat').value = data.discount_codmat || '';
|
|
if (el('settDiscountVat')) el('settDiscountVat').value = data.discount_vat || '21';
|
|
if (el('settDiscountIdPol')) el('settDiscountIdPol').value = data.discount_id_pol || '';
|
|
if (el('settSplitDiscountVat')) el('settSplitDiscountVat').checked = data.split_discount_vat === "1";
|
|
if (el('settIdPol')) el('settIdPol').value = data.id_pol || '';
|
|
if (el('settIdPolProductie')) el('settIdPolProductie').value = data.id_pol_productie || '';
|
|
if (el('settIdSectie')) el('settIdSectie').value = data.id_sectie || '';
|
|
if (el('settIdGestiune')) el('settIdGestiune').value = data.id_gestiune || '';
|
|
if (el('settGomagApiKey')) el('settGomagApiKey').value = data.gomag_api_key || '';
|
|
if (el('settGomagApiShop')) el('settGomagApiShop').value = data.gomag_api_shop || '';
|
|
if (el('settGomagDaysBack')) el('settGomagDaysBack').value = data.gomag_order_days_back || '7';
|
|
if (el('settGomagLimit')) el('settGomagLimit').value = data.gomag_limit || '100';
|
|
if (el('settDashPollSeconds')) el('settDashPollSeconds').value = data.dashboard_poll_seconds || '5';
|
|
} catch (err) {
|
|
console.error('loadSettings error:', err);
|
|
}
|
|
}
|
|
|
|
async function saveSettings() {
|
|
const el = (id) => document.getElementById(id);
|
|
const payload = {
|
|
transport_codmat: el('settTransportCodmat')?.value?.trim() || '',
|
|
transport_vat: el('settTransportVat')?.value || '21',
|
|
transport_id_pol: el('settTransportIdPol')?.value?.trim() || '',
|
|
discount_codmat: el('settDiscountCodmat')?.value?.trim() || '',
|
|
discount_vat: el('settDiscountVat')?.value || '21',
|
|
discount_id_pol: el('settDiscountIdPol')?.value?.trim() || '',
|
|
split_discount_vat: el('settSplitDiscountVat')?.checked ? "1" : "",
|
|
id_pol: el('settIdPol')?.value?.trim() || '',
|
|
id_pol_productie: el('settIdPolProductie')?.value?.trim() || '',
|
|
id_sectie: el('settIdSectie')?.value?.trim() || '',
|
|
id_gestiune: el('settIdGestiune')?.value?.trim() || '',
|
|
gomag_api_key: el('settGomagApiKey')?.value?.trim() || '',
|
|
gomag_api_shop: el('settGomagApiShop')?.value?.trim() || '',
|
|
gomag_order_days_back: el('settGomagDaysBack')?.value?.trim() || '7',
|
|
gomag_limit: el('settGomagLimit')?.value?.trim() || '100',
|
|
dashboard_poll_seconds: el('settDashPollSeconds')?.value?.trim() || '5',
|
|
};
|
|
try {
|
|
const res = await fetch('/api/settings', {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
});
|
|
const data = await res.json();
|
|
const resultEl = document.getElementById('settSaveResult');
|
|
if (data.success) {
|
|
if (resultEl) { resultEl.textContent = 'Salvat!'; resultEl.style.color = '#16a34a'; }
|
|
setTimeout(() => { if (resultEl) resultEl.textContent = ''; }, 3000);
|
|
} else {
|
|
if (resultEl) { resultEl.textContent = 'Eroare: ' + JSON.stringify(data); resultEl.style.color = '#dc2626'; }
|
|
}
|
|
} catch (err) {
|
|
const resultEl = document.getElementById('settSaveResult');
|
|
if (resultEl) { resultEl.textContent = 'Eroare: ' + err.message; resultEl.style.color = '#dc2626'; }
|
|
}
|
|
}
|
|
|
|
function wireAutocomplete(inputId, dropdownId) {
|
|
const input = document.getElementById(inputId);
|
|
const dropdown = document.getElementById(dropdownId);
|
|
if (!input || !dropdown) return;
|
|
|
|
input.addEventListener('input', () => {
|
|
clearTimeout(settAcTimeout);
|
|
settAcTimeout = setTimeout(async () => {
|
|
const q = input.value.trim();
|
|
if (q.length < 2) { dropdown.classList.add('d-none'); return; }
|
|
try {
|
|
const res = await fetch(`/api/articles/search?q=${encodeURIComponent(q)}`);
|
|
const data = await res.json();
|
|
if (!data.results || data.results.length === 0) { dropdown.classList.add('d-none'); return; }
|
|
dropdown.innerHTML = data.results.map(r =>
|
|
`<div class="autocomplete-item" onmousedown="settSelectArticle('${inputId}', '${dropdownId}', '${escHtml(r.codmat)}')">
|
|
<span class="codmat">${escHtml(r.codmat)}</span> — <span class="denumire">${escHtml(r.denumire)}</span>
|
|
</div>`
|
|
).join('');
|
|
dropdown.classList.remove('d-none');
|
|
} catch { dropdown.classList.add('d-none'); }
|
|
}, 250);
|
|
});
|
|
|
|
input.addEventListener('blur', () => {
|
|
setTimeout(() => dropdown.classList.add('d-none'), 200);
|
|
});
|
|
}
|
|
|
|
function settSelectArticle(inputId, dropdownId, codmat) {
|
|
document.getElementById(inputId).value = codmat;
|
|
document.getElementById(dropdownId).classList.add('d-none');
|
|
}
|
|
|
|
function escHtml(s) {
|
|
if (s == null) return '';
|
|
return String(s)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|