feat(pos): rewire history.html to /api/v1/pos/sales

Payment method now read from pos_sales.payment_method rather than
sniffed out of an order's notes with regexes.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Dave 2026-08-31 01:45:43 +02:00
parent 600b3ee3bf
commit fac417a697

View file

@ -163,7 +163,6 @@ button:focus-visible,input:focus-visible,select:focus-visible{outline:0;box-shad
<script>
(function(){
'use strict';
const cfg = window.PB_CONFIG;
const fmt = n => 'R ' + (Number(n)||0).toLocaleString('en-ZA',{minimumFractionDigits:2,maximumFractionDigits:2});
const esc = s => String(s||'').replace(/[&<>"']/g, c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c]);
@ -197,32 +196,32 @@ function paintDays(){
}));
}
const METHOD_LABELS = {cash:'Cash', card:'Card', eft:'EFT', account:'Account'};
async function load(){
const list = document.getElementById('list');
list.innerHTML = '<div class="empty"><h3>Loading…</h3></div>';
document.getElementById('kpiCount').textContent = '—';
document.getElementById('kpiTotal').textContent = 'R 0';
const start = activeDay + ' 00:00:00';
const end = activeDay + ' 23:59:59';
const filter = `created >= '${start}' && created <= '${end}'`;
const from = activeDay + ' 00:00:00';
const to = activeDay + ' 23:59:59';
try{
await window.pbAuth();
const r = await window.pbFetch(`/api/collections/${cfg.collections.orders}/records?perPage=200&sort=-created&filter=${encodeURIComponent(filter)}`);
const r = await window.posFetch(`/sales?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`);
if(!r.ok) throw new Error('sales returned ' + r.status);
const j = await r.json();
const rows = [];
let grandTotal = 0;
for(const o of j.items){
const li = await window.pbFetch(`/api/collections/${cfg.collections.orderItems}/records?perPage=200&filter=order='${o.id}'`);
const liJ = await li.json();
const items = liJ.items || [];
const total = items.reduce((s,it)=> s + (it.selling_price||0) * (it.quantity||0), 0);
grandTotal += total;
const isAccount = /ACCOUNT/.test(o.notes||'');
const method = isAccount ? 'Account' : (/EFT/.test(o.notes||'')?'EFT':(/CARD/.test(o.notes||'')?'Card':'Cash'));
const dt = new Date(o.created);
rows.push({o, items, total, method, dt});
const sales = j.sales || [];
const itemsBySale = new Map();
for(const it of (j.items||[])){
if(!itemsBySale.has(it.sale)) itemsBySale.set(it.sale, []);
itemsBySale.get(it.sale).push(it);
}
document.getElementById('kpiCount').textContent = j.items.length;
const rows = sales.map(s => ({
s, items: itemsBySale.get(s.id)||[], total: s.total,
method: METHOD_LABELS[s.payment_method] || 'Cash',
dt: new Date(s.created),
}));
const grandTotal = rows.reduce((sum,r)=>sum+r.total,0);
document.getElementById('kpiCount').textContent = sales.length;
document.getElementById('kpiTotal').textContent = fmt(grandTotal);
if(!rows.length){
list.innerHTML = '<div class="empty"><h3>No sales</h3><p>No sales recorded on this day.</p></div>';
@ -231,9 +230,9 @@ async function load(){
list.innerHTML = rows.map(r=>{
const dt = r.dt.toLocaleTimeString('en-ZA',{hour:'2-digit',minute:'2-digit'});
const mClass = r.method.toLowerCase();
return `<button class="sale-row" data-od-id="sale-${r.o.id}" onclick="reprint('${r.o.id}')">
return `<button class="sale-row" data-od-id="sale-${r.s.id}" onclick="reprint('${r.s.id}')">
<div class="nm">
<b>${esc(r.o.order_number||r.o.id.slice(-6))}</b>
<b>${esc(r.s.sale_number||r.s.id.slice(-6))}</b>
<small>${dt} · ${r.items.length} item${r.items.length===1?'':'s'}</small>
</div>
<span class="method ${mClass}">${esc(r.method)}</span>