import html as _html
import json
def _e(s):
return _html.escape(str(s if s is not None else ""))
def render_receipt_html(sale, items, customer, st):
"""One self-contained receipt (inline CSS) used by both the print window and the email body."""
cur = st.get("currency_symbol", "$")
def m(v):
try:
return f"{cur}{float(v or 0):.2f}"
except (TypeError, ValueError):
return f"{cur}0.00"
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"
rows = ""
for i in items:
disc = float(i.get("discount") or 0)
dtag = f' −{m(disc)}' if disc > 0 else ""
rows += (f'| {i.get("qty",1)}× {_e(i.get("item_name") or i.get("sku"))}{dtag} | '
f'{m(i.get("line_total"))} |
')
sub = sale.get("subtotal")
disc_total = float(sale.get("discount_amount") or 0)
tax = float(sale.get("tax_amount") or 0)
incl = (st.get("tax_type") or "exclusive") == "inclusive"
trade = float(sale.get("trade_in_credit") or 0)
tot = float(sale.get("total") or 0)
summ = f'| Subtotal | {m(sub)} |
'
if disc_total > 0:
summ += f'| Discount | −{m(disc_total)} |
'
if tax > 0:
summ += f'| GST{" incl" if incl else ""} ({st.get("tax_rate","0")}%) | {m(tax)} |
'
if trade > 0:
summ += f'| Trade-in credit | −{m(trade)} |
'
# split-payment lines, else the single method + (cash) tender/change
pay = ""
method = sale.get("payment_method") or ""
splits = sale.get("split_payments")
if isinstance(splits, str):
try:
splits = json.loads(splits)
except ValueError:
splits = None
if splits and isinstance(splits, list):
for p in splits:
if p.get("method") and p.get("amount"):
pay += f'| {_e(p["method"].title())} | {m(p["amount"])} |
'
else:
pay += f'| {_e(method.title() or "Paid")} | {m(sale.get("amount_paid", tot))} |
'
tendered = sale.get("amount_tendered")
if method == "cash" and tendered:
pay += f'| Tendered | {m(tendered)} |
'
pay += f'| Change | {m(float(tendered) - tot)} |
'
bal = round(tot - float(sale.get("amount_paid") or 0), 2)
bal_line = (f'| Balance due | '
f'{m(bal)} |
') if bal > 0.005 else ""
notes = f'{_e(sale.get("notes"))}
' if sale.get("notes") else ""
return f"""
{logo_html}
{_e(store)}
{f'
{_e(addr)}
' if addr else ''}
{_e(sale.get('sale_number',''))} · {_e(date)} · {_e(who)}
{summ}| Total | {m(tot)} |
{pay}{bal_line}
{notes}
{_e(footer)}
"""