Introduce receipt printing

This commit is contained in:
David Rodenkirchen 2025-04-03 06:53:58 +02:00
parent fa90e16fdf
commit 336bd0e108
7 changed files with 85 additions and 5 deletions

View File

@ -34,5 +34,11 @@
additional_info="Berechtigt zur Nutzung eines verbesserten Platzes. Dieser ist mit einer höheren Internet-Bandbreite und einem Sitzkissen ausgestattet." additional_info="Berechtigt zur Nutzung eines verbesserten Platzes. Dieser ist mit einer höheren Internet-Bandbreite und einem Sitzkissen ausgestattet."
is_default=false is_default=false
[receipt_printing]
host="127.0.0.1"
port="5000"
order_print_endpoint="print_order"
password="Alkohol1"
[misc] [misc]
dev_mode_active=true # Supresses E-Mail sending dev_mode_active=true # Supresses E-Mail sending

Binary file not shown.

View File

@ -10,13 +10,14 @@ from src.ez_lan_manager.services.DatabaseService import DatabaseService
from src.ez_lan_manager.services.LocalDataService import LocalDataService from src.ez_lan_manager.services.LocalDataService import LocalDataService
from src.ez_lan_manager.services.MailingService import MailingService from src.ez_lan_manager.services.MailingService import MailingService
from src.ez_lan_manager.services.NewsService import NewsService from src.ez_lan_manager.services.NewsService import NewsService
from src.ez_lan_manager.services.ReceiptPrintingService import ReceiptPrintingService
from src.ez_lan_manager.services.SeatingService import SeatingService from src.ez_lan_manager.services.SeatingService import SeatingService
from src.ez_lan_manager.services.TicketingService import TicketingService from src.ez_lan_manager.services.TicketingService import TicketingService
from src.ez_lan_manager.services.UserService import UserService from src.ez_lan_manager.services.UserService import UserService
from src.ez_lan_manager.types import * from src.ez_lan_manager.types import *
# Inits services in the correct order # Inits services in the correct order
def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService, LocalDataService]: def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService, LocalDataService, ReceiptPrintingService]:
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
configuration_service = ConfigurationService(from_root("config.toml")) configuration_service = ConfigurationService(from_root("config.toml"))
db_service = DatabaseService(configuration_service.get_database_configuration()) db_service = DatabaseService(configuration_service.get_database_configuration())
@ -26,7 +27,9 @@ def init_services() -> tuple[AccountingService, CateringService, ConfigurationSe
mailing_service = MailingService(configuration_service) mailing_service = MailingService(configuration_service)
ticketing_service = TicketingService(configuration_service.get_ticket_info(), db_service, accounting_service) ticketing_service = TicketingService(configuration_service.get_ticket_info(), db_service, accounting_service)
seating_service = SeatingService(configuration_service.get_lan_info(), db_service, ticketing_service) seating_service = SeatingService(configuration_service.get_lan_info(), db_service, ticketing_service)
catering_service = CateringService(db_service, accounting_service, user_service) receipt_printing_service = ReceiptPrintingService(seating_service, configuration_service.get_receipt_printing_configuration(), configuration_service.DEV_MODE_ACTIVE)
catering_service = CateringService(db_service, accounting_service, user_service, receipt_printing_service)
local_data_service = LocalDataService() local_data_service = LocalDataService()
return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service, local_data_service
return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service, local_data_service, receipt_printing_service

View File

@ -6,6 +6,7 @@ from typing import Optional
from src.ez_lan_manager.services.AccountingService import AccountingService from src.ez_lan_manager.services.AccountingService import AccountingService
from src.ez_lan_manager.services.DatabaseService import DatabaseService from src.ez_lan_manager.services.DatabaseService import DatabaseService
from src.ez_lan_manager.services.UserService import UserService from src.ez_lan_manager.services.UserService import UserService
from src.ez_lan_manager.services.ReceiptPrintingService import ReceiptPrintingService
from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus, CateringMenuItemsWithAmount from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus, CateringMenuItemsWithAmount
from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory
@ -25,10 +26,11 @@ class CateringError(Exception):
class CateringService: class CateringService:
def __init__(self, db_service: DatabaseService, accounting_service: AccountingService, user_service: UserService): def __init__(self, db_service: DatabaseService, accounting_service: AccountingService, user_service: UserService, receipt_printing_service: ReceiptPrintingService) -> None:
self._db_service = db_service self._db_service = db_service
self._accounting_service = accounting_service self._accounting_service = accounting_service
self._user_service = user_service self._user_service = user_service
self._receipt_printing_service = receipt_printing_service
self.cached_cart: dict[int, list[CateringMenuItem]] = {} self.cached_cart: dict[int, list[CateringMenuItem]] = {}
# ORDERS # ORDERS
@ -52,6 +54,7 @@ class CateringService:
await self._accounting_service.remove_balance(user_id, total_price, f"CATERING - {order.order_id}") await self._accounting_service.remove_balance(user_id, total_price, f"CATERING - {order.order_id}")
logger.info( logger.info(
f"User '{order.customer.user_name}' (ID:{order.customer.user_id}) ordered from catering for {self._accounting_service.make_euro_string_from_decimal(total_price)}") f"User '{order.customer.user_name}' (ID:{order.customer.user_id}) ordered from catering for {self._accounting_service.make_euro_string_from_decimal(total_price)}")
await self._receipt_printing_service.print_order(user, order)
# await self.cancel_order(order) # ToDo: Check if commented out before commit. Un-comment to auto-cancel every placed order # await self.cancel_order(order) # ToDo: Check if commented out before commit. Un-comment to auto-cancel every placed order
return order return order

View File

@ -8,7 +8,7 @@ import tomllib
from from_root import from_root from from_root import from_root
from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration, MailingServiceConfiguration, LanInfo, \ from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration, MailingServiceConfiguration, LanInfo, \
SeatingConfiguration, TicketInfo SeatingConfiguration, TicketInfo, ReceiptPrintingConfiguration
logger = logging.getLogger(__name__.split(".")[-1]) logger = logging.getLogger(__name__.split(".")[-1])
@ -86,6 +86,19 @@ class ConfigurationService:
logger.fatal("Error loading seating configuration, exiting...") logger.fatal("Error loading seating configuration, exiting...")
sys.exit(1) sys.exit(1)
def get_receipt_printing_configuration(self) -> ReceiptPrintingConfiguration:
try:
receipt_printing_configuration = self._config["receipt_printing"]
return ReceiptPrintingConfiguration(
host=receipt_printing_configuration["host"],
port=receipt_printing_configuration["port"],
order_print_endpoint=receipt_printing_configuration["order_print_endpoint"],
password=receipt_printing_configuration["password"]
)
except KeyError:
logger.fatal("Error loading Receipt Printing Configuration, exiting...")
sys.exit(1)
@property @property
def APP_VERSION(self) -> str: def APP_VERSION(self) -> str:
return self._version return self._version

View File

@ -0,0 +1,48 @@
import logging
import requests
from src.ez_lan_manager.services.SeatingService import SeatingService
from src.ez_lan_manager.types.CateringOrder import CateringOrder
from src.ez_lan_manager.types.ConfigurationTypes import ReceiptPrintingConfiguration
from src.ez_lan_manager.types.User import User
logger = logging.getLogger(__name__.split(".")[-1])
logging.getLogger("urllib3").setLevel(logging.FATAL) # Disable logging for urllib3
class ReceiptPrintingService:
def __init__(self, seating_service: SeatingService, config: ReceiptPrintingConfiguration, dev_mode_enabled: bool) -> None:
self._seating_service = seating_service
self._config = config
self._dev_mode_enabled = dev_mode_enabled
async def print_order(self, user: User, order: CateringOrder) -> None:
seat_id = await self._seating_service.get_user_seat(user.user_id)
if not seat_id:
seat_id = " - "
menu_items_payload = []
for item, amount in order.items.items():
menu_items_payload.append({
"menu_item_name": item.name,
"amount": amount
})
payload = {
"order_id": str(order.order_id),
"order_date": order.order_date.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z',
"customer_name": user.user_name,
"seat_id": seat_id,
"items": menu_items_payload
}
try:
requests.post(
f"http://{self._config.host}:{self._config.port}/{self._config.order_print_endpoint}",
json=payload,
headers={"x-password": self._config.password}
)
except Exception as e:
if self._dev_mode_enabled:
logger.info("An error occurred trying to print a receipt:", e)
return
logger.error("An error occurred trying to print a receipt:", e)

View File

@ -48,3 +48,10 @@ class LanInfo:
@dataclass(frozen=True) @dataclass(frozen=True)
class SeatingConfiguration: class SeatingConfiguration:
seats: dict[str, str] seats: dict[str, str]
@dataclass(frozen=True)
class ReceiptPrintingConfiguration:
host: str
port: int
order_print_endpoint: str
password: str