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 <noreply@anthropic.com>
This commit is contained in:
parent
5351cfb9c2
commit
bf08cd9b35
@ -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'<div class="ct" style="margin-bottom:4px"><img src="{_e(logo)}" alt="" '
|
||||
f'style="max-height:72px;max-width:200px;object-fit:contain"></div>') 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"""<div class="receipt-container" style="font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;line-height:1.6;color:#111;max-width:300px;margin:0 auto;padding:6px">
|
||||
<style>.receipt-container td{{padding:1px 0}} .receipt-container table{{width:100%;border-collapse:collapse}} .receipt-container .hr{{border-top:1px dashed #999;margin:7px 0}} .receipt-container .ct{{text-align:center}} @media print{{.receipt-actions{{display:none}}}}</style>
|
||||
<div class="ct" style="font-weight:700;font-size:15px">{_e(store)}</div>
|
||||
{logo_html}<div class="ct" style="font-weight:700;font-size:15px">{_e(store)}</div>
|
||||
{f'<div class="ct" style="color:#555">{_e(addr)}</div>' if addr else ''}
|
||||
<div class="ct" style="color:#555">{_e(sale.get('sale_number',''))} · {_e(date)} · {_e(who)}</div>
|
||||
<div class="hr"></div>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -167,6 +167,7 @@
|
||||
<div class="row" style="margin-bottom:8px"><span class="lbl">Store name</span><input id="setName" style="flex:1"></div>
|
||||
<div class="row" style="margin-bottom:8px"><span class="lbl">Address</span><input id="setAddr" style="flex:1" placeholder="prints under the store name"></div>
|
||||
<div class="row" style="margin-bottom:8px"><span class="lbl">Receipt footer</span><input id="setFooter" style="flex:1" placeholder="thanks for digging"></div>
|
||||
<div class="row" style="margin-bottom:8px"><span class="lbl">Logo URL</span><input id="setLogo" style="flex:1" placeholder="https://recordgod.com/receipt-logo.webp"></div>
|
||||
<div class="row" style="margin-bottom:8px"><span class="lbl">Currency</span><input id="setCur" style="width:60px">
|
||||
<span class="lbl" style="min-width:40px">Tax %</span><input id="setTax" class="num" type="number" step="0.1">
|
||||
<select id="setTaxType"><option value="exclusive">added on top</option><option value="inclusive">included (GST incl)</option></select></div>
|
||||
@ -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('<!doctype html><html><head><meta charset=utf-8><title>Receipt</title><style>body{margin:16px;background:#fff}</style></head><body>'+rcptHtml+'</body></html>');
|
||||
w.document.close(); w.focus(); setTimeout(()=>{ w.print(); }, 250);
|
||||
w.document.write('<!doctype html><html><head><meta charset=utf-8><title>Receipt</title><style>body{margin:16px;background:#fff}</style></head><body>'+rcptHtml+'<scr'+'ipt>window.onload=function(){setTimeout(function(){window.print()},350)}</scr'+'ipt></body></html>');
|
||||
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(){
|
||||
|
||||
BIN
site/receipt-logo.webp
Normal file
BIN
site/receipt-logo.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
Loading…
Reference in New Issue
Block a user