From 20e460644b9f62cf8b3d2e9df94b335aff23c042 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 3 Sep 2026 18:28:55 +0200 Subject: [PATCH] feat(pos): wire history reprint to redirect to receipt page --- public/pos/history.html | 58 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/public/pos/history.html b/public/pos/history.html index 6892d6c..10a6711 100644 --- a/public/pos/history.html +++ b/public/pos/history.html @@ -220,6 +220,9 @@ async function load(){ method: METHOD_LABELS[s.payment_method] || 'Cash', dt: new Date(s.created), })); + // Cache for reprint() — needs both the PosSale and its PosSaleItems + // to reconstruct the sessionStorage shape that receipt.html expects. + cachedRows = rows; const grandTotal = rows.reduce((sum,r)=>sum+r.total,0); document.getElementById('kpiCount').textContent = sales.length; document.getElementById('kpiTotal').textContent = fmt(grandTotal); @@ -244,8 +247,61 @@ async function load(){ } } +// Cached after each load() — lets reprint() look up the full PosSale + +// PosSaleItems for a clicked row without re-fetching. The list is the +// only source of truth for "what's on screen", so this stays in sync +// whenever the user picks a different day. +let cachedRows = []; + +// Reprint = hop to receipt.html with the sale stashed in +// sessionStorage. The receipt page already handles loading from +// sessionStorage and has the full Bluetooth / Network print logic +// (including the epos-print.js network path added 2026-09-03), so we +// just translate the API shape into the till-rendered shape and let +// the existing code drive the printer. window.reprint = function(orderId){ - alert('Reprint: slip ' + orderId + '. (Use the browser print dialog to re-print.)'); + const row = cachedRows.find(r => r.s.id === orderId); + if(!row){ + alert('Sale not loaded — try again after the list finishes loading.'); + return; + } + const s = row.s; + const sessionSale = { + localId: s.client_ref || s.id, + createdAt: s.created, + payment: s.payment_method, + cashGiven: s.cash_given || 0, + change: s.change_given || 0, + gross: s.gross_total, + discount: { + kind: s.discount_kind || 'none', + input: s.discount_input || 0, + amount: s.discount_amount || 0, + }, + sub: s.subtotal, + vat: s.vat, + total: s.total, + items: row.items.map(it => ({ + sku: it.sku, + description: it.description, + unit: 'ea', + cost_price: it.unit_cost, + selling_price: it.unit_price, + edited: false, + qty: it.qty, + product_id: it.stock_item, + })), + // The API returns the customer as a relation id only (no name + // expansion in the sales list). Pass null so receipt.html's + // `if (s.customer)` guard skips the line — better than printing + // "Customer: undefined". If we need the name, the user can add + // a /api/v1/pos/sales/:id endpoint that expands it. + customer: null, + synced: true, + serverRef: s.id, + }; + try{ sessionStorage.setItem('pos.lastSale', JSON.stringify(sessionSale)); }catch(_){} + setTimeout(() => { location.href = 'receipt.html'; }, 80); }; paintDays(); load();