import uuid import barker.schemas.voucher as schemas from fastapi import APIRouter, HTTPException, Security, status from sqlalchemy import select, update from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session from ...core.security import get_current_active_user as get_user from ...db.session import SessionFuture from ...models.overview import Overview from ...models.reprint import Reprint from ...models.settle_option import SettleOption from ...models.voucher import Voucher from ...models.voucher_type import VoucherType from ...printing.bill import print_bill from ...printing.kot import print_kot from ...routers.voucher import ( do_update_bill_numbers, do_update_settlements, get_guest_book, ) from ...schemas.receive_payment import ReceivePaymentItem as SettleSchema from ...schemas.user_token import UserToken from .save import do_save router = APIRouter() @router.put("/change/{id_}") def change( id_: uuid.UUID, data: schemas.VoucherIn, u: bool, # Update table? g: uuid.UUID | None = None, # Guest book id user: UserToken = Security(get_user, scopes=["edit-printed-bill"]), ): try: with SessionFuture() as db: old: Voucher = db.execute(select(Voucher).where(Voucher.id == id_)).scalar_one() if old.voucher_type == VoucherType.VOID: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Voucher cannot be reprinted. It is already void.", ) bill_changed: bool = ( len( set((i.id, i.amount) for k in old.kots for i in k.inventories) ^ set((i.id_, i.amount) for k in data.kots for i in k.inventories) ) != 0 ) new_kot: bool = len([k for k in data.kots if k.id_ is None and len(k.inventories) > 0]) > 0 if bill_changed: id_ = void_and_issue_new_bill(data, u, g, old, db, user) else: if data.customer is not None: old.customer_id = data.customer.id_ else: old.customer_id = None reprint_bill(id_, user.id_, db) db.commit() with SessionFuture() as db: if bill_changed and new_kot: print_kot(id_, db) print_bill(id_, db) except SQLAlchemyError as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), ) def reprint_bill(voucher_id: uuid.UUID, user_id: uuid.UUID, db: Session): item = Reprint(voucher_id=voucher_id, user_id=user_id) db.add(item) def void_and_issue_new_bill( data: schemas.VoucherIn, u: bool, g: uuid.UUID | None, old: Voucher, db: Session, user: UserToken, ) -> uuid.UUID: update_table = u guest_book = get_guest_book(g, db) item: Voucher = do_save(data, old.voucher_type, guest_book, db, user) db.flush() new_bill_id = (", ".join(f"{x.regime.prefix}-{x.bill_number}" for x in item.bills),) old_bill_id = (", ".join(f"{x.regime.prefix}-{x.bill_number}" for x in old.bills),) old.reason = f"Bill Discounted or Changed / Old Bill: {old_bill_id} / New Bill: {new_bill_id}." old.voucher_type = VoucherType.VOID do_update_bill_numbers(old, db) do_update_settlements(old, [SettleSchema(id=SettleOption.VOID(), amount=round(old.amount))], db) if update_table: if old.status is None: guest_book_id = None if guest_book is None else guest_book.id item.status = Overview( voucher_id=None, food_table_id=item.food_table_id, guest_book_id=guest_book_id, status="printed" ) db.add(item.status) else: db.execute(update(Overview).where(Overview.voucher_id == old.id).values(voucher_id=item.id)) return item.id