131 lines
3.2 KiB
Python
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")
|