import re import uuid from datetime import datetime, timedelta from fastapi import APIRouter, HTTPException, Security, status from sqlalchemy import and_, or_, select from sqlalchemy.orm import Session, joinedload from ...core.config import settings from ...core.security import get_current_active_user as get_user from ...db.session import SessionFuture from ...models.bill import Bill from ...models.food_table import FoodTable from ...models.guest_book import GuestBook from ...models.overview import Overview from ...models.product_version import ProductVersion from ...models.regime import Regime from ...models.voucher import Voucher from ...models.voucher_type import VoucherType from ...schemas.user_token import UserToken router = APIRouter() @router.get("/from-id/{id_}") def from_id( id_: str, user: UserToken = Security(get_user), ): with SessionFuture() as db: item: Voucher = db.execute(select(Voucher).where(Voucher.id == id_)).scalar_one() return voucher_info(item, db) @router.get("/from-bill/{id_}") def from_bill( id_: str, user: UserToken = Security(get_user), ): with SessionFuture() as db: match = re.compile(r"^(\w+)-(\d+)$").match(id_) if not match or len(match.groups()) != 2: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Bill Number is invalid", ) voucher_id = ( select(Bill.voucher_id) .join(Bill.regime) .where(Regime.prefix == match.group(1), Bill.bill_number == int(match.group(2))) .options(joinedload(Regime.prefix, innerjoin=True)) ) item = db.execute(select(Voucher).where(Voucher.id.in_(voucher_id))).scalars().one_or_none() if item is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Bill not found", ) return voucher_info(item, db) @router.get("/from-table/{id_}") def from_table( id_: str, # table id v: uuid.UUID | None = None, # voucher id g: uuid.UUID | None = None, # guest id user: UserToken = Security(get_user), ): with SessionFuture() as db: guest = None if g is None else db.execute(select(GuestBook).where(GuestBook.id == g)).scalar_one() if v is not None: item = ( db.execute( select(Overview).where( Overview.voucher_id == v, Overview.food_table_id == id_, ) ) .scalars() .one_or_none() ) if item is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Voucher not found", ) else: if guest is not None: item.voucher.customer = guest.customer return voucher_info(item.voucher, db) table = db.execute(select(FoodTable).where(FoodTable.id == id_)).scalar_one() return voucher_blank(table, guest) def voucher_product(product_id: uuid.UUID, date_: datetime, is_happy_hour: bool, db: Session): product_date = ( date_ + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES) ).date() product: ProductVersion = db.execute( select(ProductVersion).where( and_( ProductVersion.product_id == product_id, or_( ProductVersion.valid_from == None, # noqa: E711 ProductVersion.valid_from <= product_date, ), or_( ProductVersion.valid_till == None, # noqa: E711 ProductVersion.valid_till >= product_date, ), ) ) ).scalar_one() return { "id": product_id, "name": ("H H " if is_happy_hour else "") + product.full_name, "menuCategory": { "id": product.menu_category_id, "name": product.menu_category.name, }, "saleCategory": { "id": product.sale_category_id, "name": product.sale_category.name, "discountLimit": product.sale_category.discount_limit, }, } def voucher_info(item: Voucher, db: Session): return { "id": item.id, "date": (item.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES)).strftime("%H:%M"), "dateTip": (item.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES)).strftime("%d-%b-%Y %H:%M:%S"), "pax": item.pax, "user": {"id": item.user_id, "name": item.user.name}, "creationDate": (item.creation_date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES)).strftime("%H:%M"), "creationDateTip": (item.creation_date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES)).strftime( "%d-%b-%Y %H:%M:%S" ), "lastEditDate": (item.last_edit_date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES)).strftime("%H:%M"), "lastEditDateTip": (item.last_edit_date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES)).strftime( "%d-%b-%Y %H:%M:%S" ), "kotId": item.kot_id, "billId": ", ".join(f"{x.regime.prefix}-{x.bill_number}" for x in item.bills), "table": {"id": item.food_table_id, "name": item.food_table.name}, "customer": {"id": item.customer.id, "name": item.customer.name} if item.customer is not None else None, "narration": item.narration, "reason": item.reason, "voucherType": item.voucher_type, "kots": [ { "id": k.id, "code": k.code, "date": (k.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES)).strftime("%d-%b-%Y %H:%M:%S"), "user": {"id": k.user_id, "name": k.user.name}, "inventories": [ { "id": i.id, "sortOrder": i.sort_order, "product": voucher_product(i.product_id, item.date, i.is_happy_hour, db), "quantity": i.quantity, "price": i.price, "isHappyHour": i.is_happy_hour, "taxRate": i.tax_rate, "tax": {"id": i.tax_id, "name": i.tax.name}, "discount": i.discount, "modifiers": [ { "id": m.modifier.id, "name": m.modifier.name, "price": m.price, } for m in i.modifiers ], } for i in k.inventories ], } for k in item.kots ], } def voucher_blank(table: FoodTable, guest: GuestBook | None): return { "pax": table.seats if guest is None else guest.pax, "table": {"id": table.id, "name": table.name}, "voucherType": VoucherType.KOT, "customer": {"id": guest.customer_id, "name": guest.customer.name} if guest is not None else None, "kots": [], }