receipts/printer.py
2025-01-31 02:31:56 -05:00

131 lines
3.2 KiB
Python

import logging
import os
from itertools import zip_longest
from dotenv import find_dotenv, load_dotenv
from escpos.printer import CupsPrinter
log = logging.getLogger("receipt-printer")
log.setLevel(logging.WARNING)
if load_dotenv(find_dotenv(usecwd=True)):
log.debug("Loaded .env")
else:
log.debug("Didn't find .env")
RECEIPT_PRINTER = os.getenv("RECEIPT_PRINTER")
class CallbackContext:
def __init__(self, enter=None, exit=None):
self.enter = enter
self.exit = exit
def __enter__(self):
if self.enter:
return self.enter()
def __exit__(self, *_):
if self.exit:
self.exit()
class Split2Context:
def __init__(
self, printer, num_cols=2, widths=None, align="<", aligns=None, columns=48
):
self.printer = printer
self.num_cols = num_cols or len(widths)
self.widths = widths or [columns // self.num_cols] * self.num_cols
self.aligns = aligns or [align] * self.num_cols
self.col_length = columns // 2
self.columns = [[] for i in range(self.num_cols)]
def col(self, num, text):
self.columns[num].append(f"{text:{self.aligns[num]}{self.widths[num]}}")
def left(self, text):
self.col(0, text)
def right(self, text):
self.col(-1, text)
def __enter__(self):
return self
def __exit__(self, *_):
lines = map("".join, zip_longest(*self.columns, fillvalue=" " * self.num_cols))
for line in lines:
self.printer.textln(line)
class ReceiptPrinter(CupsPrinter):
def __init__(self, *args, autocut=True, **kwargs):
self.autocut = autocut
super().__init__(*args, **kwargs)
def __enter__(self):
self.open()
return self
def __exit__(self, _type, _value, _traceback):
if self.autocut:
self.cut()
self.close()
def set(self, *args, **kwargs):
super().set(*args, **kwargs)
return CallbackContext(exit=super().set_with_default)
def set_with_default(self, *args, **kwargs):
super().set_with_default(*args, **kwargs)
return CallbackContext(exit=super().set_with_default)
def split(self, left, right, cols=48):
self.textln(f"{left:<{cols // 2}}{right:<{cols // 2}}")
def vsplit(self, *args, **kwargs):
return Split2Context(self, *args, **kwargs)
def invert(self, text):
with self.set(invert=True):
self.text(text)
def invertln(self, text):
self.invert(text)
self.ln()
def bold(self, text):
with self.set(bold=True):
self.text(text)
def boldln(self, text):
self.bold(text)
self.ln()
def title(self, text, size=6, width=None, height=None):
width = width or size
height = height or size
with self.set(
align="center",
bold=True,
invert=True,
smooth=True,
custom_size=True,
width=width,
height=height,
):
self.textln(text)
self.ln()
def subtitle(self, text):
with self.set(align="center", double_height=True, double_width=True):
p.textln(text)
p = ReceiptPrinter(RECEIPT_PRINTER, profile="default")