From b13d9a466ce448ff5deca1f3586c9e136aa8c48c Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Mon, 4 May 2026 07:28:55 +0000 Subject: [PATCH] fix(ui): show Reimporta button on DELETED_IN_ROA orders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mark_order_deleted_in_roa wipes order_items, so renderOrderDetailModal hit the items.length===0 early-return BEFORE configuring footer buttons — leaving DELETED_IN_ROA orders with no way to retry from the UI. Extract the 3 button configurators (Retry/Resync/Delete) into _configureDetailButtons() and call it before the early-return. Also fire onAfterRender on the empty-items path for consistency. Cache-bust shared.js v47 → v48. Co-Authored-By: Claude Opus 4.7 (1M context) --- api/app/static/js/shared.js | 279 ++++++++++++++++++------------------ api/app/templates/base.html | 2 +- 2 files changed, 143 insertions(+), 138 deletions(-) diff --git a/api/app/static/js/shared.js b/api/app/static/js/shared.js index e2c4403..0a2d0ad 100644 --- a/api/app/static/js/shared.js +++ b/api/app/static/js/shared.js @@ -601,6 +601,143 @@ function _renderReceipt(items, order) { } // ── Order Detail Modal (shared) ────────────────── +/** +function _configureDetailButtons(order, orderNumber, opts) { + const status = (order.status || '').toUpperCase(); + const isInvoiced = !!(order.factura_numar); + + const retryBtn = document.getElementById('detailRetryBtn'); + if (retryBtn) { + const canRetry = [ORDER_STATUS.ERROR, ORDER_STATUS.SKIPPED, ORDER_STATUS.DELETED_IN_ROA].includes(status); + retryBtn.style.display = canRetry ? '' : 'none'; + if (canRetry) { + retryBtn.onclick = async () => { + retryBtn.disabled = true; + retryBtn.innerHTML = ' Reimportare...'; + try { + const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/retry`, { method: 'POST' }); + const data = await res.json(); + if (data.success) { + retryBtn.innerHTML = ' ' + (data.message || 'Reimportat'); + retryBtn.className = 'btn btn-sm btn-success'; + if (opts.onStatusChange) opts.onStatusChange(); + setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500); + } else { + retryBtn.innerHTML = ' ' + (data.message || 'Eroare'); + retryBtn.className = 'btn btn-sm btn-danger'; + setTimeout(() => { + retryBtn.innerHTML = ' Reimporta'; + retryBtn.className = 'btn btn-sm btn-outline-primary'; + retryBtn.disabled = false; + }, 3000); + } + } catch (err) { + retryBtn.innerHTML = 'Eroare: ' + err.message; + retryBtn.disabled = false; + } + }; + } + } + + const resyncBtn = document.getElementById('detailResyncBtn'); + if (resyncBtn) { + const canResync = [ORDER_STATUS.IMPORTED, ORDER_STATUS.ALREADY_IMPORTED].includes(status); + resyncBtn.style.display = canResync ? '' : 'none'; + if (canResync) { + if (isInvoiced) { + resyncBtn.disabled = true; + resyncBtn.style.opacity = '0.5'; + resyncBtn.style.pointerEvents = 'none'; + resyncBtn.title = 'Comanda facturata'; + } else { + resyncBtn.disabled = false; + resyncBtn.style.opacity = ''; + resyncBtn.style.pointerEvents = ''; + resyncBtn.title = ''; + resyncBtn.onclick = () => { + inlineConfirmAction(resyncBtn, 'Confirmi resync?', async (btn) => { + try { + const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/resync`, { method: 'POST' }); + const data = await res.json(); + if (data.success) { + btn.innerHTML = ' Reimportat'; + btn.className = 'btn btn-sm btn-success'; + if (opts.onStatusChange) opts.onStatusChange(); + setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500); + } else { + btn.innerHTML = ' ' + (data.message || 'Eroare'); + btn.className = 'btn btn-sm btn-danger'; + setTimeout(() => { + btn.innerHTML = ' Resync'; + btn.className = 'btn btn-sm btn-outline-warning'; + btn.disabled = false; + }, 3000); + } + } catch (err) { + btn.innerHTML = 'Eroare: ' + err.message; + btn.disabled = false; + } + }, { + defaultHtml: ' Resync', + loadingText: 'Resync...', + confirmClass: 'btn-warning', + defaultBtnClass: 'btn-outline-warning' + }); + }; + } + } + } + + const deleteBtn = document.getElementById('detailDeleteBtn'); + if (deleteBtn) { + const canDelete = [ORDER_STATUS.IMPORTED, ORDER_STATUS.ALREADY_IMPORTED].includes(status); + deleteBtn.style.display = canDelete ? '' : 'none'; + if (canDelete) { + if (isInvoiced) { + deleteBtn.disabled = true; + deleteBtn.style.opacity = '0.5'; + deleteBtn.style.pointerEvents = 'none'; + deleteBtn.title = 'Comanda facturata'; + } else { + deleteBtn.disabled = false; + deleteBtn.style.opacity = ''; + deleteBtn.style.pointerEvents = ''; + deleteBtn.title = ''; + deleteBtn.onclick = () => { + inlineConfirmAction(deleteBtn, 'Confirmi stergerea?', async (btn) => { + try { + const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/delete`, { method: 'POST' }); + const data = await res.json(); + if (data.success) { + btn.innerHTML = ' Sters'; + btn.className = 'btn btn-sm btn-danger'; + if (opts.onStatusChange) opts.onStatusChange(); + setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500); + } else { + btn.innerHTML = ' ' + (data.message || 'Eroare'); + btn.className = 'btn btn-sm btn-danger'; + setTimeout(() => { + btn.innerHTML = ' Sterge din ROA'; + btn.className = 'btn btn-sm btn-outline-danger'; + btn.disabled = false; + }, 3000); + } + } catch (err) { + btn.innerHTML = 'Eroare: ' + err.message; + btn.disabled = false; + } + }, { + defaultHtml: ' Sterge din ROA', + loadingText: 'Stergere...', + confirmClass: 'btn-danger', + defaultBtnClass: 'btn-outline-danger' + }); + }; + } + } + } +} + /** * Render and show the order detail modal. * @param {string} orderNumber @@ -717,9 +854,14 @@ async function renderOrderDetailModal(orderNumber, opts) { document.getElementById('detailError').style.display = ''; } + // Configure footer action buttons BEFORE any early-return on items — + // DELETED_IN_ROA orders have no items but must still expose the Reimporta button. + _configureDetailButtons(order, orderNumber, opts); + const items = data.items || []; if (items.length === 0) { document.getElementById('detailItemsBody').innerHTML = 'Niciun articol'; + if (opts.onAfterRender) opts.onAfterRender(order, items); return; } @@ -853,143 +995,6 @@ async function renderOrderDetailModal(orderNumber, opts) { document.getElementById('detailItemsBody').innerHTML = tableHtml; _renderReceipt(items, order); - // Retry button (only for ERROR/SKIPPED orders) - const retryBtn = document.getElementById('detailRetryBtn'); - if (retryBtn) { - const canRetry = [ORDER_STATUS.ERROR, ORDER_STATUS.SKIPPED, ORDER_STATUS.DELETED_IN_ROA].includes((order.status || '').toUpperCase()); - retryBtn.style.display = canRetry ? '' : 'none'; - if (canRetry) { - retryBtn.onclick = async () => { - retryBtn.disabled = true; - retryBtn.innerHTML = ' Reimportare...'; - try { - const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/retry`, { method: 'POST' }); - const data = await res.json(); - if (data.success) { - retryBtn.innerHTML = ' ' + (data.message || 'Reimportat'); - retryBtn.className = 'btn btn-sm btn-success'; - if (opts.onStatusChange) opts.onStatusChange(); - // Refresh modal after short delay - setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500); - } else { - retryBtn.innerHTML = ' ' + (data.message || 'Eroare'); - retryBtn.className = 'btn btn-sm btn-danger'; - setTimeout(() => { - retryBtn.innerHTML = ' Reimporta'; - retryBtn.className = 'btn btn-sm btn-outline-primary'; - retryBtn.disabled = false; - }, 3000); - } - } catch (err) { - retryBtn.innerHTML = 'Eroare: ' + err.message; - retryBtn.disabled = false; - } - }; - } - } - - // Resync button (IMPORTED/ALREADY_IMPORTED only) - const resyncBtn = document.getElementById('detailResyncBtn'); - if (resyncBtn) { - const canResync = [ORDER_STATUS.IMPORTED, ORDER_STATUS.ALREADY_IMPORTED].includes((order.status || '').toUpperCase()); - resyncBtn.style.display = canResync ? '' : 'none'; - if (canResync) { - const isInvoiced = !!(order.factura_numar); - if (isInvoiced) { - resyncBtn.disabled = true; - resyncBtn.style.opacity = '0.5'; - resyncBtn.style.pointerEvents = 'none'; - resyncBtn.title = 'Comanda facturata'; - } else { - resyncBtn.disabled = false; - resyncBtn.style.opacity = ''; - resyncBtn.style.pointerEvents = ''; - resyncBtn.title = ''; - resyncBtn.onclick = () => { - inlineConfirmAction(resyncBtn, 'Confirmi resync?', async (btn) => { - try { - const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/resync`, { method: 'POST' }); - const data = await res.json(); - if (data.success) { - btn.innerHTML = ' Reimportat'; - btn.className = 'btn btn-sm btn-success'; - if (opts.onStatusChange) opts.onStatusChange(); - setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500); - } else { - btn.innerHTML = ' ' + (data.message || 'Eroare'); - btn.className = 'btn btn-sm btn-danger'; - setTimeout(() => { - btn.innerHTML = ' Resync'; - btn.className = 'btn btn-sm btn-outline-warning'; - btn.disabled = false; - }, 3000); - } - } catch (err) { - btn.innerHTML = 'Eroare: ' + err.message; - btn.disabled = false; - } - }, { - defaultHtml: ' Resync', - loadingText: 'Resync...', - confirmClass: 'btn-warning', - defaultBtnClass: 'btn-outline-warning' - }); - }; - } - } - } - - // Delete button (IMPORTED/ALREADY_IMPORTED only) - const deleteBtn = document.getElementById('detailDeleteBtn'); - if (deleteBtn) { - const canDelete = [ORDER_STATUS.IMPORTED, ORDER_STATUS.ALREADY_IMPORTED].includes((order.status || '').toUpperCase()); - deleteBtn.style.display = canDelete ? '' : 'none'; - if (canDelete) { - const isInvoiced = !!(order.factura_numar); - if (isInvoiced) { - deleteBtn.disabled = true; - deleteBtn.style.opacity = '0.5'; - deleteBtn.style.pointerEvents = 'none'; - deleteBtn.title = 'Comanda facturata'; - } else { - deleteBtn.disabled = false; - deleteBtn.style.opacity = ''; - deleteBtn.style.pointerEvents = ''; - deleteBtn.title = ''; - deleteBtn.onclick = () => { - inlineConfirmAction(deleteBtn, 'Confirmi stergerea?', async (btn) => { - try { - const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/delete`, { method: 'POST' }); - const data = await res.json(); - if (data.success) { - btn.innerHTML = ' Sters'; - btn.className = 'btn btn-sm btn-danger'; - if (opts.onStatusChange) opts.onStatusChange(); - setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500); - } else { - btn.innerHTML = ' ' + (data.message || 'Eroare'); - btn.className = 'btn btn-sm btn-danger'; - setTimeout(() => { - btn.innerHTML = ' Sterge din ROA'; - btn.className = 'btn btn-sm btn-outline-danger'; - btn.disabled = false; - }, 3000); - } - } catch (err) { - btn.innerHTML = 'Eroare: ' + err.message; - btn.disabled = false; - } - }, { - defaultHtml: ' Sterge din ROA', - loadingText: 'Stergere...', - confirmClass: 'btn-danger', - defaultBtnClass: 'btn-outline-danger' - }); - }; - } - } - } - if (opts.onAfterRender) opts.onAfterRender(order, items); } catch (err) { document.getElementById('detailError').textContent = err.message; diff --git a/api/app/templates/base.html b/api/app/templates/base.html index 8fb1d80..0ace371 100644 --- a/api/app/templates/base.html +++ b/api/app/templates/base.html @@ -169,7 +169,7 @@ - +