Replace single-select gestiune dropdown with multi-select checkboxes. Settings stores comma-separated IDs, Python builds IN clause with bind variables, Oracle PL/SQL splits CSV via REGEXP_SUBSTR for stock lookup. Empty selection = all warehouses (unchanged behavior). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
191 lines
8.9 KiB
JavaScript
191 lines
8.9 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 gestContainer = document.getElementById('settGestiuniContainer');
|
|
if (gestContainer) {
|
|
gestContainer.innerHTML = '';
|
|
gestiuni.forEach(g => {
|
|
gestContainer.innerHTML += `<div class="form-check mb-0"><input class="form-check-input" type="checkbox" value="${escHtml(g.id)}" id="gestChk_${escHtml(g.id)}"><label class="form-check-label" for="gestChk_${escHtml(g.id)}">${escHtml(g.label)}</label></div>`;
|
|
});
|
|
if (gestiuni.length === 0) gestContainer.innerHTML = '<span class="text-muted small">Nicio gestiune disponibilă</span>';
|
|
}
|
|
|
|
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 || '';
|
|
// Multi-gestiune checkboxes
|
|
const gestVal = data.id_gestiune || '';
|
|
if (gestVal) {
|
|
const selectedIds = gestVal.split(',').map(s => s.trim());
|
|
selectedIds.forEach(id => {
|
|
const chk = document.getElementById('gestChk_' + id);
|
|
if (chk) chk.checked = true;
|
|
});
|
|
}
|
|
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: Array.from(document.querySelectorAll('#settGestiuniContainer input:checked')).map(c => c.value).join(','),
|
|
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, ''');
|
|
}
|