From bf08cd9b356bf33e5c48750ec28b880553844d9c Mon Sep 17 00:00:00 2001 From: type-two Date: Tue, 23 Jun 2026 17:33:08 +1000 Subject: [PATCH] feat(pos): receipt logo + Monster Robot template (store name/address/footer) receipts.py renders store_logo (img) above the title; store_logo added to sales settings (get/save) + a Logo URL field in POS Settings. Logo hosted at site/receipt-logo.webp (Monster Robot, from WowPlatter receipt_templates). Print window now waits for window.onload so the logo prints. Deploy via /opt/recordgod/deploy.sh. Co-Authored-By: Claude Opus 4.8 --- app/receipts.py | 5 ++++- app/sales_routes.py | 5 +++-- site/pos.html | 9 +++++---- site/receipt-logo.webp | Bin 0 -> 7006 bytes 4 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 site/receipt-logo.webp diff --git a/app/receipts.py b/app/receipts.py index f9bde15..c340ef3 100644 --- a/app/receipts.py +++ b/app/receipts.py @@ -18,6 +18,9 @@ def render_receipt_html(sale, items, customer, st): store = st.get("store_name") or "RecordGod" addr = st.get("store_address") or "" footer = st.get("receipt_footer") or "thanks for digging" + logo = st.get("store_logo") or "" + logo_html = (f'
') if logo else "" date = str(sale.get("sale_date") or "")[:16].replace("T", " ") who = (customer or {}).get("name") or "Guest" @@ -71,7 +74,7 @@ def render_receipt_html(sale, items, customer, st): return f"""
-
{_e(store)}
+{logo_html}
{_e(store)}
{f'
{_e(addr)}
' if addr else ''}
{_e(sale.get('sale_number',''))} · {_e(date)} · {_e(who)}
diff --git a/app/sales_routes.py b/app/sales_routes.py index 6695763..e898702 100644 --- a/app/sales_routes.py +++ b/app/sales_routes.py @@ -292,7 +292,8 @@ async def _settings(db): "tax_type": s.get("tax_type", "exclusive"), "store_name": s.get("store_name", "RecordGod"), "store_address": s.get("store_address", ""), - "receipt_footer": s.get("receipt_footer", "thanks for digging")} + "receipt_footer": s.get("receipt_footer", "thanks for digging"), + "store_logo": s.get("store_logo", "")} @router.get("/settings") @@ -305,7 +306,7 @@ async def save_settings(body: dict, ident=Depends(require_token), db=Depends(get m = {"currency_symbol": body.get("currency_symbol"), "default_tax_rate": body.get("tax_rate"), "default_discount_rate": body.get("discount_rate"), "tax_type": body.get("tax_type"), "store_name": body.get("store_name"), "store_address": body.get("store_address"), - "receipt_footer": body.get("receipt_footer")} + "receipt_footer": body.get("receipt_footer"), "store_logo": body.get("store_logo")} for k, v in m.items(): if v is None: continue diff --git a/site/pos.html b/site/pos.html index e0f6fda..701447d 100644 --- a/site/pos.html +++ b/site/pos.html @@ -167,6 +167,7 @@
Store name
Address
Receipt footer
+
Logo URL
Currency Tax %
@@ -353,8 +354,8 @@ async function showReceipt(id){ } function printReceipt(){ const w=window.open('','_blank','width=380,height=680'); if(!w){ alert('allow pop-ups to print the receipt'); return; } - w.document.write('Receipt'+rcptHtml+''); - w.document.close(); w.focus(); setTimeout(()=>{ w.print(); }, 250); + w.document.write('Receipt'+rcptHtml+'window.onload=function(){setTimeout(function(){window.print()},350)}'); + w.document.close(); w.focus(); } function newSale(){ $('#receiptPane').style.display='none'; $('#checkout').style.display='block'; resetCust(); $('#msg').textContent=''; setMethod('cash'); $('#q').focus(); } function emailDlg(){ @@ -433,14 +434,14 @@ async function runBulk(){ /* ── settings ── */ async function loadSettings(){ const s=await get('/sales/settings'); CUR=s.currency_symbol||'$'; - $('#setName').value=s.store_name||''; $('#setAddr').value=s.store_address||''; $('#setFooter').value=s.receipt_footer||''; + $('#setName').value=s.store_name||''; $('#setAddr').value=s.store_address||''; $('#setFooter').value=s.receipt_footer||''; $('#setLogo').value=s.store_logo||''; $('#setCur').value=CUR; $('#setTax').value=s.tax_rate; $('#setDisc').value=s.discount_rate; $('#setTaxType').value=s.tax_type||'exclusive'; if(!(+$('#tax').value)) $('#tax').value=s.tax_rate||0; render(); } async function saveSettings(){ await post('/sales/settings',{currency_symbol:$('#setCur').value,tax_rate:$('#setTax').value,discount_rate:$('#setDisc').value, - tax_type:$('#setTaxType').value,store_name:$('#setName').value,store_address:$('#setAddr').value,receipt_footer:$('#setFooter').value}); + tax_type:$('#setTaxType').value,store_name:$('#setName').value,store_address:$('#setAddr').value,receipt_footer:$('#setFooter').value,store_logo:$('#setLogo').value}); CUR=$('#setCur').value||'$'; $('#setMsg').textContent='saved'; setTimeout(()=>$('#setMsg').textContent='',1500); render(); } async function emailTest(){ diff --git a/site/receipt-logo.webp b/site/receipt-logo.webp new file mode 100644 index 0000000000000000000000000000000000000000..267729b227ee42bf6c9f5507393fce657b5cac26 GIT binary patch literal 7006 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 literal 0 HcmV?d00001