fix text centering, add automatic second copy
This commit is contained in:
parent
9b054652d7
commit
062e6b482f
105
main.py
105
main.py
@ -1,62 +1,90 @@
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.params import Header
|
||||
from fastapi import FastAPI, HTTPException, Header
|
||||
from pydantic import BaseModel
|
||||
|
||||
from escpos.printer import Usb
|
||||
from escpos.capabilities import get_profile
|
||||
from PIL import Image
|
||||
|
||||
MAX_LINE_LEN = 30
|
||||
|
||||
PRINTER = Usb(0x28e9, 0x0289)
|
||||
PRINTER = Usb(0x28e9, 0x0289, profile="simple")
|
||||
|
||||
MAX_LINE_LEN = 32
|
||||
SECRET_PASSWORD = "Alkohol1"
|
||||
|
||||
|
||||
class OrderItem(BaseModel):
|
||||
menu_item_name: str
|
||||
amount: int
|
||||
|
||||
|
||||
class Order(BaseModel):
|
||||
order_id: str
|
||||
order_date: datetime
|
||||
customer_name: str
|
||||
seat_id: str
|
||||
items: list[OrderItem]
|
||||
items: List[OrderItem]
|
||||
|
||||
def build_header(order_id: str, order_date: datetime, customer_name: str, seat_id: str) -> str:
|
||||
return (f"EZ GG e.V. - EZ LAN 1.0\n\n"
|
||||
f"Bestellungs-ID: {order_id}\n"
|
||||
f"Bestellt: {order_date.strftime('%d.%m. - %H:%M')}\n"
|
||||
f"Gast: {customer_name}\n"
|
||||
f"Sitzplatz: {seat_id}\n\n")
|
||||
|
||||
def format_order(order: list[OrderItem]) -> list[str]:
|
||||
formatted_order = []
|
||||
for item in order:
|
||||
formatted_text = f"{item.amount}x {item.menu_item_name}"
|
||||
formatted_text = formatted_text.replace("ä", "ae")
|
||||
formatted_text = formatted_text.replace("ö", "oe")
|
||||
formatted_text = formatted_text.replace("ü", "ue")
|
||||
formatted_text = formatted_text.replace("ß", "ss")
|
||||
if len(formatted_text) < MAX_LINE_LEN:
|
||||
while len(formatted_text) < MAX_LINE_LEN:
|
||||
formatted_text = formatted_text.replace(" ", " ", 1)
|
||||
else:
|
||||
formatted_text = formatted_text[:MAX_LINE_LEN]
|
||||
def sanitize_text(text: str) -> str:
|
||||
return (text.replace("ä", "ae")
|
||||
.replace("ö", "oe")
|
||||
.replace("ü", "ue")
|
||||
.replace("ß", "ss"))
|
||||
|
||||
formatted_order.append(formatted_text + "\n")
|
||||
return formatted_order
|
||||
|
||||
def print_order(order: Order, printer_: Usb) -> None:
|
||||
header = build_header(order.order_id, order.order_date, order.customer_name, order.seat_id)
|
||||
items = format_order(order.items)
|
||||
printer_.image("logo.png")
|
||||
printer_.text(header)
|
||||
def build_header(order: Order, copy_num: int) -> str:
|
||||
return (
|
||||
"EZ GG e.V. - EZGG LAN 1.0\n"
|
||||
"--------------------------------\n"
|
||||
f"ID: {order.order_id}\n"
|
||||
f"{order.order_date.strftime('%d.%m. %H:%M')}\n"
|
||||
f"Gast: {sanitize_text(order.customer_name)}\n"
|
||||
f"Sitz: {sanitize_text(order.seat_id)}\n"
|
||||
f"Kopie: {copy_num}\n"
|
||||
"--------------------------------\n"
|
||||
)
|
||||
|
||||
|
||||
def format_order(items: List[OrderItem]) -> List[str]:
|
||||
lines = []
|
||||
for item in items:
|
||||
printer_.text(item)
|
||||
name = sanitize_text(item.menu_item_name)
|
||||
line = f"{item.amount}x {name}"
|
||||
if len(line) > MAX_LINE_LEN:
|
||||
line = line[:MAX_LINE_LEN]
|
||||
lines.append(line + "\n")
|
||||
return lines
|
||||
|
||||
|
||||
def print_logo(printer_: Usb, path: str = "logo.png"):
|
||||
try:
|
||||
img = Image.open(path)
|
||||
max_width = 384
|
||||
if img.width > max_width:
|
||||
ratio = max_width / img.width
|
||||
new_height = int(img.height * ratio)
|
||||
img = img.resize((max_width, new_height))
|
||||
printer_.set(align="center")
|
||||
printer_.image(img)
|
||||
printer_.text("\n")
|
||||
except Exception:
|
||||
printer_.text("[Logo error]\n")
|
||||
|
||||
|
||||
def print_order(order: Order, printer_: Usb, copy_num: int) -> None:
|
||||
printer_.set(align="center")
|
||||
print_logo(printer_)
|
||||
printer_.text(build_header(order, copy_num))
|
||||
printer_.set(align="left")
|
||||
for line in format_order(order.items):
|
||||
printer_.text(line)
|
||||
printer_.text("--------------------------------\n\n")
|
||||
printer_.cut()
|
||||
|
||||
|
||||
api = FastAPI()
|
||||
|
||||
|
||||
@ -67,11 +95,16 @@ async def print_order_api_endpoint(order: Order, x_password: str = Header(None))
|
||||
|
||||
for item in order.items:
|
||||
if item.amount < 1:
|
||||
return 422
|
||||
raise HTTPException(status_code=422, detail="Invalid item amount")
|
||||
|
||||
print_order(order, PRINTER)
|
||||
for copy_num in range(1, 3):
|
||||
try:
|
||||
print_order(order, PRINTER, copy_num)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Printing failed: {str(e)}")
|
||||
|
||||
return {"status": "done"}
|
||||
|
||||
return "done"
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Starting receipt printing server...")
|
||||
|
||||
@ -7,7 +7,6 @@ fastapi==0.115.12
|
||||
h11==0.14.0
|
||||
idna==3.10
|
||||
importlib_resources==6.5.2
|
||||
pillow==11.2.0
|
||||
pydantic==2.11.1
|
||||
pydantic_core==2.33.0
|
||||
python-barcode==0.15.1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user