from datetime import datetime import uvicorn from fastapi import FastAPI, HTTPException from fastapi.params import Header from pydantic import BaseModel from escpos.printer import Usb MAX_LINE_LEN = 30 PRINTER = Usb(0x28e9, 0x0289) 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 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] 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) for item in items: printer_.text(item) 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: return 422 print_order(order, PRINTER) return "done" if __name__ == "__main__": print("Starting receipt printing server...") uvicorn.run(api, host="0.0.0.0", port=5000, log_level="warning")