barker/barker/barker/routers/voucher/update.py

197 lines
7.5 KiB
Python

import uuid
from datetime import datetime, timedelta
from typing import Optional
import barker.schemas.voucher as schemas
from fastapi import APIRouter, Depends, HTTPException, Security, status
from sqlalchemy import and_, func, or_
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from ...core.config import settings
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionLocal
from ...models.inventory import Inventory
from ...models.inventory_modifier import InventoryModifier
from ...models.kot import Kot
from ...models.product_version import ProductVersion
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 (
check_permissions,
do_update_settlements,
do_update_table,
get_bill_id,
get_guest_book,
get_tax,
happy_hour_has_discount,
happy_hour_items_balanced,
happy_hour_items_more_than_regular,
)
from ...schemas.user_token import UserToken
router = APIRouter()
# Dependency
def get_db():
try:
db = SessionLocal()
yield db
finally:
db.close()
@router.put("/update/{id_}")
def update(
id_: uuid.UUID,
data: schemas.VoucherIn,
u: bool, # Update table?
p: int, # Print type
g: Optional[uuid.UUID] = None, # Guest book id
db: Session = Depends(get_db),
user: UserToken = Security(get_user),
):
try:
now = datetime.now()
product_date = (
now + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES)
).date()
update_table = u
voucher_type = VoucherType(p)
guest_book = get_guest_book(g, db)
need_to_print_kot = False
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
check_permissions(item, voucher_type, user.permissions)
if guest_book is not None:
item.pax = guest_book.pax
item.food_table_id = data.table.id_
if data.customer is not None:
item.customer_id = data.customer.id_
if item.voucher_type != VoucherType.KOT:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Internal error, reprints should not reach here",
)
if item.voucher_type == VoucherType.KOT and voucher_type != VoucherType.KOT:
item.date = now
item.bill_id = get_bill_id(voucher_type, db)
item.voucher_type = voucher_type
item.user_id = user.id_
item.last_edit_date = now
if happy_hour_items_more_than_regular(data.kots):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="When product has happy hours\n"
"Minimum same number of regular items also needed in the whole bill.",
)
for k in item.kots:
for i in k.inventories:
i.tax_rate = get_tax(i.tax_rate, voucher_type)
# TODO: Need to check from the database product for the max discount
# However simple relationship does not work as we need the product validity as well
# Still we should not fret too much as we are checking this in the frontend.
i.discount = next(
round(inv.discount, 5) for ko in data.kots for inv in ko.inventories if inv.id_ == i.id
)
for k in data.kots:
if happy_hour_has_discount(k.inventories):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Discount is not allowed on happy hour products.",
)
if not happy_hour_items_balanced(k.inventories):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Happy hour products are not balanced.",
)
for k in (k for k in data.kots if k.id_ is None and len(k.inventories) > 0):
need_to_print_kot = True
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
kot = Kot(item.id, code, item.food_table_id, now, item.user_id)
item.kots.append(kot)
db.add(kot)
for index, i in enumerate(k.inventories):
product: ProductVersion = (
db.query(ProductVersion)
.filter(
and_(
ProductVersion.product_id == i.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,
),
)
)
.first()
)
if round(i.quantity, 2) < 0:
if "edit-printed-product" not in user.permissions:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"You are not allowed to delete printed products."
f"\n In this case {product.full_name}",
)
minimum = round(
sum(
inv.quantity
for ko in item.kots
for inv in ko.inventories
if ko.id and inv.product_id == product.id
)
* -1,
2,
)
if round(i.quantity, 2) < minimum:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=f"Quantity of {product.full_name} cannot be less than {minimum}",
)
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
inv = Inventory(
kot.id,
product.product_id,
round(i.quantity, 2),
product.price,
round(min(i.discount, product.sale_category.discount_limit), 5),
i.is_happy_hour,
product.sale_category.tax_id,
tax_rate,
index,
)
kot.inventories.append(inv)
db.add(inv)
for m in i.modifiers:
mod = InventoryModifier(None, m.id_, 0)
inv.modifiers.append(mod)
db.add(mod)
do_update_settlements(item, [], db)
if update_table:
do_update_table(item, guest_book, db)
db.commit()
if need_to_print_kot:
print_kot(item.id, db)
if item.voucher_type != VoucherType.KOT:
print_bill(item.id, db)
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
)
except Exception:
db.rollback()
raise