diff --git a/api/app/routers/sync.py b/api/app/routers/sync.py
index 45338a8..7ca278d 100644
--- a/api/app/routers/sync.py
+++ b/api/app/routers/sync.py
@@ -416,6 +416,12 @@ async def order_detail(order_number: str):
except (json.JSONDecodeError, TypeError):
pass
+ # Add settings for receipt display
+ app_settings = await sqlite_service.get_app_settings()
+ order["transport_vat"] = app_settings.get("transport_vat") or "21"
+ order["transport_codmat"] = app_settings.get("transport_codmat") or ""
+ order["discount_codmat"] = app_settings.get("discount_codmat") or ""
+
return detail
diff --git a/api/app/static/js/dashboard.js b/api/app/static/js/dashboard.js
index 4079085..215b26d 100644
--- a/api/app/static/js/dashboard.js
+++ b/api/app/static/js/dashboard.js
@@ -522,14 +522,12 @@ async function openDashOrderDetail(orderNumber) {
document.getElementById('detailIdPartener').textContent = '-';
document.getElementById('detailIdAdresaFact').textContent = '-';
document.getElementById('detailIdAdresaLivr').textContent = '-';
- document.getElementById('detailItemsBody').innerHTML = '
' + items.map((item, idx) => {
+ let mobileHtml = items.map((item, idx) => {
const codmatText = item.codmat_details?.length
? item.codmat_details.map(d => `
${esc(d.codmat)}${d.direct ? '
direct' : ''}`).join(' ')
: `
${esc(item.codmat || '–')}`;
- const valoare = (Number(item.price || 0) * Number(item.quantity || 0)).toFixed(2);
+ const valoare = (Number(item.price || 0) * Number(item.quantity || 0));
return `
${esc(item.sku)}
@@ -622,29 +597,166 @@ async function openDashOrderDetail(orderNumber) {
${esc(item.product_name || '–')}
x${item.quantity || 0}
- ${valoare} lei
+ ${fmtNum(valoare)} lei
+ TVA ${item.vat != null ? Number(item.vat) : '?'}
`;
- }).join('') + '
';
+ }).join('');
+
+ // Transport row (mobile)
+ if (order.delivery_cost > 0) {
+ const tVat = order.transport_vat || '21';
+ mobileHtml += `
+
+ Transport
+ x1
+ ${fmtNum(order.delivery_cost)} lei
+ TVA ${tVat}
+
+
`;
+ }
+
+ // Discount rows (mobile)
+ if (order.discount_total > 0) {
+ const discSplit = computeDiscountSplit(items, order);
+ if (discSplit) {
+ Object.entries(discSplit)
+ .sort(([a], [b]) => Number(a) - Number(b))
+ .forEach(([rate, amt]) => {
+ if (amt > 0) mobileHtml += `
+
+ Discount
+ x\u20131
+ ${fmtNum(amt)} lei
+ TVA ${Number(rate)}
+
+
`;
+ });
+ } else {
+ mobileHtml += `
+
+ Discount
+ x\u20131
+ ${fmtNum(order.discount_total)} lei
+
+
`;
+ }
+ }
+
+ mobileContainer.innerHTML = '
' + mobileHtml + '
';
}
- document.getElementById('detailItemsBody').innerHTML = items.map((item, idx) => {
- const valoare = (Number(item.price || 0) * Number(item.quantity || 0)).toFixed(2);
+ let tableHtml = items.map((item, idx) => {
+ const valoare = Number(item.price || 0) * Number(item.quantity || 0);
return `
${esc(item.sku)} |
${esc(item.product_name || '-')} |
${renderCodmatCell(item)} |
- ${item.quantity || 0} |
- ${item.price != null ? Number(item.price).toFixed(2) : '-'} |
- ${valoare} |
+ ${item.quantity || 0} |
+ ${item.price != null ? fmtNum(item.price) : '-'} |
+ ${item.vat != null ? Number(item.vat) : '-'} |
+ ${fmtNum(valoare)} |
`;
}).join('');
+
+ // Transport row
+ if (order.delivery_cost > 0) {
+ const tVat = order.transport_vat || '21';
+ const tCodmat = order.transport_codmat || '';
+ tableHtml += `
+ | Transport |
+ ${tCodmat ? '' + esc(tCodmat) + '' : ''} |
+ 1 | ${fmtNum(order.delivery_cost)} |
+ ${tVat} | ${fmtNum(order.delivery_cost)} |
+
`;
+ }
+
+ // Discount rows (split by VAT rate)
+ if (order.discount_total > 0) {
+ const dCodmat = order.discount_codmat || '';
+ const discSplit = computeDiscountSplit(items, order);
+ if (discSplit) {
+ Object.entries(discSplit)
+ .sort(([a], [b]) => Number(a) - Number(b))
+ .forEach(([rate, amt]) => {
+ if (amt > 0) tableHtml += `
+ | Discount |
+ ${dCodmat ? '' + esc(dCodmat) + '' : ''} |
+ \u20131 | ${fmtNum(amt)} |
+ ${Number(rate)} | \u2013${fmtNum(amt)} |
+
`;
+ });
+ } else {
+ tableHtml += `
+ | Discount |
+ ${dCodmat ? '' + esc(dCodmat) + '' : ''} |
+ \u20131 | ${fmtNum(order.discount_total)} |
+ - | \u2013${fmtNum(order.discount_total)} |
+
`;
+ }
+ }
+
+ document.getElementById('detailItemsBody').innerHTML = tableHtml;
+
+ // Receipt footer (just total)
+ renderReceipt(items, order);
} catch (err) {
document.getElementById('detailError').textContent = err.message;
document.getElementById('detailError').style.display = '';
}
}
+function fmtNum(v) {
+ return Number(v).toLocaleString('ro-RO', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
+}
+
+function computeDiscountSplit(items, order) {
+ if (order.discount_split && typeof order.discount_split === 'object')
+ return order.discount_split;
+
+ // Compute proportionally from items by VAT rate
+ const byRate = {};
+ items.forEach(item => {
+ const rate = item.vat != null ? Number(item.vat) : null;
+ if (rate === null) return;
+ if (!byRate[rate]) byRate[rate] = 0;
+ byRate[rate] += Number(item.price || 0) * Number(item.quantity || 0);
+ });
+ const rates = Object.keys(byRate).sort((a, b) => Number(a) - Number(b));
+ if (rates.length === 0) return null;
+
+ const grandTotal = rates.reduce((s, r) => s + byRate[r], 0);
+ if (grandTotal <= 0) return null;
+
+ const split = {};
+ let remaining = order.discount_total;
+ rates.forEach((rate, i) => {
+ if (i === rates.length - 1) {
+ split[rate] = Math.round(remaining * 100) / 100;
+ } else {
+ const amt = Math.round(order.discount_total * byRate[rate] / grandTotal * 100) / 100;
+ split[rate] = amt;
+ remaining -= amt;
+ }
+ });
+ return split;
+}
+
+function renderReceipt(items, order) {
+ const desktop = document.getElementById('detailReceipt');
+ const mobile = document.getElementById('detailReceiptMobile');
+ if (!items.length) {
+ desktop.innerHTML = '';
+ mobile.innerHTML = '';
+ return;
+ }
+
+ const total = order.order_total != null ? fmtNum(order.order_total) : '-';
+ const html = `
Total: ${total} lei`;
+ desktop.innerHTML = html;
+ mobile.innerHTML = html;
+}
+
// ── Quick Map Modal ───────────────────────────────
function openQuickMap(sku, productName, orderNumber, itemIdx) {
diff --git a/api/app/templates/dashboard.html b/api/app/templates/dashboard.html
index ec1ac01..96af8a2 100644
--- a/api/app/templates/dashboard.html
+++ b/api/app/templates/dashboard.html
@@ -135,12 +135,6 @@
-