import uuid from decimal import Decimal from typing import Set import barker.schemas.voucher as schemas from fastapi import HTTPException, status from sqlalchemy import func from sqlalchemy.orm import Session from sqlalchemy.sql import expression from ...models.bill import Bill from ...models.guest_book import GuestBook from ...models.overview import Overview from ...models.regime import Regime from ...models.settle_option import SettleOption from ...models.settlement import Settlement from ...models.voucher import Voucher from ...models.voucher_type import VoucherType from ...schemas.receive_payment import ReceivePaymentItem as SettleSchema def get_tax(tax, voucher_type): if voucher_type in [VoucherType.STAFF, VoucherType.NO_CHARGE]: return 0 elif voucher_type in [VoucherType.KOT, VoucherType.REGULAR_BILL]: return tax else: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Unexpected Voucher Type", ) def do_update_table(item: Voucher, guest_book: GuestBook | None, db: Session): status_ = "running" if item.voucher_type == VoucherType.KOT else "printed" if item.status is None: item.status = Overview( voucher_id=item.id, food_table_id=item.food_table_id, guest_book_id=guest_book.id if guest_book is not None else None, status=status_, ) db.add(item.status) else: item.status.status = status_ if guest_book is not None: item.status.guest_book_id = guest_book.id def check_permissions(item: Voucher | None, voucher_type: VoucherType, permissions: list[str]): if voucher_type == VoucherType.KOT and "print-kot" not in permissions: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to print a kot", ) if voucher_type != VoucherType.KOT and "print-bill" not in permissions: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to print bill", ) if item is None: return if item.voucher_type != VoucherType.KOT and "edit-printed-bill" not in permissions: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to edit a printed bill", ) if item.voucher_type != VoucherType.KOT and voucher_type == VoucherType.KOT: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="This Bill is already printed\nCannot add a Kot to it.", ) if item.voucher_type == VoucherType.VOID: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"This Bill is already void.\nReason: {item.reason}", ) def get_guest_book(id_: uuid.UUID | None, db: Session) -> GuestBook | None: if id_ is None: return id_ return db.execute(expression.select(GuestBook).where(GuestBook.id == id_)).scalar_one() def do_update_settlements(voucher: Voucher, others: list[SettleSchema], db: Session) -> bool: fully_settled = True settlements: list[SettleSchema] = [] settlements += others total_amount = voucher.amount settlements.append(SettleSchema(id=SettleOption.AMOUNT(), amount=-total_amount)) round_off = round(total_amount) - total_amount if round_off != 0: settlements.append(SettleSchema(id=SettleOption.ROUND_OFF(), amount=-round_off)) unsettled = sum(x.amount for x in settlements) if len(others) and unsettled != 0: # This should not be allowed raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Payment received is not equal to bill amount", ) if unsettled != 0: settlements.append(SettleSchema(id=SettleOption.UNSETTLED(), amount=unsettled)) fully_settled = False for settlement in settlements: old = [vs for vs in voucher.settlements if vs.settled == settlement.id_] if len(old) == 1: old[0].amount = settlement.amount else: ns = Settlement(voucher.id, settlement.id_, settlement.amount) voucher.settlements.append(ns) db.add(ns) for removable in (os for os in voucher.settlements if os.settled not in [x.id_ for x in settlements]): voucher.settlements.remove(removable) db.delete(removable) return fully_settled def do_update_bill_numbers(voucher: Voucher, db: Session) -> bool: regimes: Set[int] = set() old_regimes: Set[int] = set() old_regimes = set( db.execute(expression.select(Bill.regime_id).where(Bill.voucher_id == voucher.id)).scalars().all() ) if voucher.voucher_type != VoucherType.REGULAR_BILL: regimes = set([int(voucher.voucher_type)]) else: regimes = set(i.tax.regime.id for k in voucher.kots for i in k.inventories) db.execute( expression.update(Bill) .where(Bill.voucher_id == voucher.id, Bill.regime_id.in_(old_regimes - regimes)) .values(is_valid=False) ) if Regime.KOT() not in old_regimes | regimes: regimes.add(Regime.KOT()) for r in regimes - old_regimes: bill_id = db.execute( expression.select(func.coalesce(func.max(Bill.bill_number), 0) + 1).where(Bill.regime_id == r) ).scalar_one() bill = Bill(regime_id=r, is_valid=True, bill_number=bill_id) voucher.bills.append(bill) db.add(bill) return True def happy_hour_items_balanced(inventories: list[schemas.Inventory]) -> bool: happy = set((i.product.id_, i.quantity) for i in inventories if i.is_happy_hour) products = set(i.product.id_ for i in inventories if i.is_happy_hour) other = set((i.product.id_, i.quantity) for i in inventories if not i.is_happy_hour and i.product.id_ in products) return happy == other def happy_hour_has_discount(inventories: list[schemas.Inventory]) -> bool: happy = set(i.product.id_ for i in inventories if i.is_happy_hour) offenders = [i for i in inventories if i.product.id_ in happy and i.discount != 0] return len(offenders) > 0 # This is for the whole bill. eg. Kot 1 => Reg 2 + HH 2; Kot 2 => Reg 4; Kot 3 => Reg - 4 # This is pass okay in happy hours items balanced, but overall this is wrong. Hence this check def happy_hour_items_more_than_regular(kots: list[schemas.Kot]) -> bool: inventories = {} for kot in kots: for inventory in kot.inventories: if inventory.product.id_ not in inventories: inventories[inventory.product.id_] = {"normal": Decimal(0), "happy": Decimal(0)} if inventory.is_happy_hour: inventories[inventory.product.id_]["happy"] += inventory.quantity else: inventories[inventory.product.id_]["normal"] += inventory.quantity for value in inventories.values(): if value["happy"] > value["normal"]: return True return False