diff --git a/CLAUDE.md b/CLAUDE.md index ecb8a4e..19e9237 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -34,7 +34,7 @@ python api/test_integration.py # cu Oracle 1. Download GoMag API → JSON → parse → validate SKU-uri → import Oracle 2. Ordinea: **parteneri** (cauta/creeaza) → **adrese** → **comanda** → **factura cache** 3. SKU lookup: ARTICOLE_TERTI (mapped) are prioritate fata de NOM_ARTICOLE (direct) -4. Complex sets: un SKU → multiple CODMAT-uri cu `procent_pret` (trebuie sa fie sum=100%) +4. Complex sets (kituri/pachete): un SKU → multiple CODMAT-uri cu `cantitate_roa`; preturile se preiau din lista de preturi Oracle 5. Comenzi anulate (GoMag statusId=7): verifica daca au factura inainte de stergere din Oracle ### Statusuri comenzi @@ -51,6 +51,11 @@ python api/test_integration.py # cu Oracle - Dual policy: articolele sunt rutate la `id_pol_vanzare` sau `id_pol_productie` pe baza contului contabil (341/345 = productie) - Daca pretul lipseste, se insereaza automat pret=0 +### Dashboard paginare +- Contorul din paginare arata **totalul comenzilor** din perioada selectata (ex: "378 comenzi"), NU doar cele filtrate +- Butoanele de filtru (Importat, Omise, Erori, Facturate, Nefacturate, Anulate) arata fiecare cate comenzi are pe langa total +- Aceasta este comportamentul dorit: userul vede cate comenzi totale sunt, din care cate importate, cu erori etc. + ### Invoice cache - Coloanele `factura_*` pe `orders` (SQLite), populate lazy din Oracle (`vanzari WHERE sters=0`) - Refresh complet: verifica facturi noi + facturi sterse + comenzi sterse din ROA diff --git a/api/app/services/gomag_client.py b/api/app/services/gomag_client.py index e1f7bd4..3ca523a 100644 --- a/api/app/services/gomag_client.py +++ b/api/app/services/gomag_client.py @@ -157,7 +157,12 @@ async def download_products( products = data.get("products", []) if isinstance(products, dict): - products = [products] + # GoMag returns products as {"1": {...}, "2": {...}} dict + first_val = next(iter(products.values()), None) if products else None + if isinstance(first_val, dict): + products = list(products.values()) + else: + products = [products] if isinstance(products, list): for p in products: if isinstance(p, dict) and p.get("sku"): diff --git a/api/app/static/js/dashboard.js b/api/app/static/js/dashboard.js index 215b26d..3f7b2fc 100644 --- a/api/app/static/js/dashboard.js +++ b/api/app/static/js/dashboard.js @@ -484,7 +484,7 @@ function renderCodmatCell(item) { return `${esc(d.codmat)}`; } return item.codmat_details.map(d => - `
${esc(d.codmat)} \xd7${d.cantitate_roa} (${d.procent_pret}%)
` + `
${esc(d.codmat)} \xd7${d.cantitate_roa}
` ).join(''); } @@ -792,7 +792,7 @@ function openQuickMap(sku, productName, orderNumber, itemIdx) { // Pre-populate with existing codmat_details if available if (details && details.length > 0) { details.forEach(d => { - addQmCodmatLine({ codmat: d.codmat, cantitate: d.cantitate_roa, procent: d.procent_pret, denumire: d.denumire }); + addQmCodmatLine({ codmat: d.codmat, cantitate: d.cantitate_roa, denumire: d.denumire }); }); } else { addQmCodmatLine(); @@ -807,7 +807,6 @@ function addQmCodmatLine(prefill) { const idx = container.children.length; const codmatVal = prefill?.codmat || ''; const cantVal = prefill?.cantitate || 1; - const pctVal = prefill?.procent || 100; const denumireVal = prefill?.denumire || ''; const div = document.createElement('div'); div.className = 'qm-line'; @@ -818,7 +817,6 @@ function addQmCodmatLine(prefill) {
- ${idx > 0 ? `` : ''}
${escHtml(denumireVal)}
@@ -870,30 +868,19 @@ async function saveQuickMapping() { for (const line of lines) { const codmat = line.querySelector('.qm-codmat').value.trim(); const cantitate = parseFloat(line.querySelector('.qm-cantitate').value) || 1; - const procent = parseFloat(line.querySelector('.qm-procent').value) || 100; if (!codmat) continue; - mappings.push({ codmat, cantitate_roa: cantitate, procent_pret: procent }); + mappings.push({ codmat, cantitate_roa: cantitate }); } if (mappings.length === 0) { alert('Selecteaza cel putin un CODMAT'); return; } - if (mappings.length > 1) { - const totalPct = mappings.reduce((s, m) => s + m.procent_pret, 0); - if (Math.abs(totalPct - 100) > 0.01) { - document.getElementById('qmPctWarning').textContent = `Suma procentelor trebuie sa fie 100% (actual: ${totalPct.toFixed(2)}%)`; - document.getElementById('qmPctWarning').style.display = ''; - return; - } - } - document.getElementById('qmPctWarning').style.display = 'none'; - try { let res; if (mappings.length === 1) { res = await fetch('/api/mappings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ sku: currentQmSku, codmat: mappings[0].codmat, cantitate_roa: mappings[0].cantitate_roa, procent_pret: mappings[0].procent_pret }) + body: JSON.stringify({ sku: currentQmSku, codmat: mappings[0].codmat, cantitate_roa: mappings[0].cantitate_roa }) }); } else { res = await fetch('/api/mappings/batch', { diff --git a/api/app/static/js/logs.js b/api/app/static/js/logs.js index cc17658..6cf8a97 100644 --- a/api/app/static/js/logs.js +++ b/api/app/static/js/logs.js @@ -310,7 +310,7 @@ function renderCodmatCell(item) { } // Multi-CODMAT: compact list return item.codmat_details.map(d => - `
${esc(d.codmat)} \xd7${d.cantitate_roa} (${d.procent_pret}%)
` + `
${esc(d.codmat)} \xd7${d.cantitate_roa}
` ).join(''); } @@ -456,11 +456,7 @@ function addQmCodmatLine() { -
- - -
-
+
${idx > 0 ? `` : ''}
@@ -513,31 +509,19 @@ async function saveQuickMapping() { for (const line of lines) { const codmat = line.querySelector('.qm-codmat').value.trim(); const cantitate = parseFloat(line.querySelector('.qm-cantitate').value) || 1; - const procent = parseFloat(line.querySelector('.qm-procent').value) || 100; if (!codmat) continue; - mappings.push({ codmat, cantitate_roa: cantitate, procent_pret: procent }); + mappings.push({ codmat, cantitate_roa: cantitate }); } if (mappings.length === 0) { alert('Selecteaza cel putin un CODMAT'); return; } - // Validate percentage sum for multi-line - if (mappings.length > 1) { - const totalPct = mappings.reduce((s, m) => s + m.procent_pret, 0); - if (Math.abs(totalPct - 100) > 0.01) { - document.getElementById('qmPctWarning').textContent = `Suma procentelor trebuie sa fie 100% (actual: ${totalPct.toFixed(2)}%)`; - document.getElementById('qmPctWarning').style.display = ''; - return; - } - } - document.getElementById('qmPctWarning').style.display = 'none'; - try { let res; if (mappings.length === 1) { res = await fetch('/api/mappings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ sku: currentQmSku, codmat: mappings[0].codmat, cantitate_roa: mappings[0].cantitate_roa, procent_pret: mappings[0].procent_pret }) + body: JSON.stringify({ sku: currentQmSku, codmat: mappings[0].codmat, cantitate_roa: mappings[0].cantitate_roa }) }); } else { res = await fetch('/api/mappings/batch', { diff --git a/api/app/templates/dashboard.html b/api/app/templates/dashboard.html index 96af8a2..2c5ab21 100644 --- a/api/app/templates/dashboard.html +++ b/api/app/templates/dashboard.html @@ -201,5 +201,5 @@ {% endblock %} {% block scripts %} - + {% endblock %} diff --git a/api/app/templates/logs.html b/api/app/templates/logs.html index a10c9ce..1f8b7ef 100644 --- a/api/app/templates/logs.html +++ b/api/app/templates/logs.html @@ -183,5 +183,5 @@ {% endblock %} {% block scripts %} - + {% endblock %} diff --git a/api/app/templates/missing_skus.html b/api/app/templates/missing_skus.html index fe3c35a..9a2719c 100644 --- a/api/app/templates/missing_skus.html +++ b/api/app/templates/missing_skus.html @@ -289,9 +289,6 @@ function addMapCodmatLine() {
-
- -
${idx > 0 ? `` : '
'}
@@ -343,30 +340,19 @@ async function saveQuickMap() { for (const line of lines) { const codmat = line.querySelector('.mc-codmat').value.trim(); const cantitate = parseFloat(line.querySelector('.mc-cantitate').value) || 1; - const procent = parseFloat(line.querySelector('.mc-procent').value) || 100; if (!codmat) continue; - mappings.push({ codmat, cantitate_roa: cantitate, procent_pret: procent }); + mappings.push({ codmat, cantitate_roa: cantitate }); } if (mappings.length === 0) { alert('Selecteaza cel putin un CODMAT'); return; } - if (mappings.length > 1) { - const totalPct = mappings.reduce((s, m) => s + m.procent_pret, 0); - if (Math.abs(totalPct - 100) > 0.01) { - document.getElementById('mapPctWarning').textContent = `Suma procentelor trebuie sa fie 100% (actual: ${totalPct.toFixed(2)}%)`; - document.getElementById('mapPctWarning').style.display = ''; - return; - } - } - document.getElementById('mapPctWarning').style.display = 'none'; - try { let res; if (mappings.length === 1) { res = await fetch('/api/mappings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ sku: currentMapSku, codmat: mappings[0].codmat, cantitate_roa: mappings[0].cantitate_roa, procent_pret: mappings[0].procent_pret }) + body: JSON.stringify({ sku: currentMapSku, codmat: mappings[0].codmat, cantitate_roa: mappings[0].cantitate_roa }) }); } else { res = await fetch('/api/mappings/batch', {