ReceiptPrinter/main.py

112 lines
3.0 KiB
Python

from datetime import datetime
from typing import List
import uvicorn
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
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]
def sanitize_text(text: str) -> str:
return (text.replace("ä", "ae")
.replace("ö", "oe")
.replace("ü", "ue")
.replace("ß", "ss"))
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:
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()
@api.post("/print_order")
async def print_order_api_endpoint(order: Order, x_password: str = Header(None)):
if x_password != SECRET_PASSWORD:
raise HTTPException(status_code=401, detail="Unauthorized")
for item in order.items:
if item.amount < 1:
raise HTTPException(status_code=422, detail="Invalid item amount")
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"}
if __name__ == "__main__":
print("Starting receipt printing server...")
uvicorn.run(api, host="0.0.0.0", port=5000, log_level="warning")