196 lines
8.5 KiB
Python
196 lines
8.5 KiB
Python
import uuid
|
|
|
|
from datetime import datetime, timedelta
|
|
from decimal import Decimal
|
|
|
|
import barker.schemas.voucher as schemas
|
|
|
|
from fastapi import APIRouter, HTTPException, Security, status
|
|
from sqlalchemy import and_, func, or_, select
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
from ...core.config import settings
|
|
from ...core.security import get_current_active_user as get_user
|
|
from ...db.session import SessionFuture
|
|
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_bill_numbers,
|
|
do_update_settlements,
|
|
do_update_table,
|
|
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()
|
|
|
|
|
|
@router.put("/update/{id_}")
|
|
def update_route(
|
|
id_: uuid.UUID,
|
|
data: schemas.VoucherIn,
|
|
u: bool, # Update table?
|
|
p: int, # Print type
|
|
g: uuid.UUID | None = None, # Guest book id
|
|
user: UserToken = Security(get_user),
|
|
):
|
|
try:
|
|
with SessionFuture() as db:
|
|
now = datetime.utcnow()
|
|
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.execute(select(Voucher).where(Voucher.id == id_)).scalar_one()
|
|
|
|
check_permissions(item, voucher_type, user.permissions)
|
|
|
|
item.pax = data.pax
|
|
if data.customer is not None:
|
|
item.customer_id = data.customer.id_
|
|
else:
|
|
item.customer_id = None
|
|
if guest_book is not None:
|
|
item.pax = guest_book.pax
|
|
item.customer_id = guest_book.customer_id
|
|
item.food_table_id = data.table.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.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 ik in item.kots:
|
|
for iki in ik.inventories:
|
|
iki.tax_rate = get_tax(iki.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.
|
|
iki.discount = next(
|
|
round(inv.discount, 5) for ko in data.kots for inv in ko.inventories if inv.id_ == iki.id
|
|
)
|
|
for dk in data.kots:
|
|
# Filter out nil inventories
|
|
dk.inventories = [dki for dki in dk.inventories if round(dki.quantity, 2) != 0]
|
|
# Filter out nil kots
|
|
data.kots = [k for k in data.kots if len(k.inventories) > 0]
|
|
for dk in data.kots:
|
|
if happy_hour_has_discount(dk.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(dk.inventories):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail="Happy hour products are not balanced.",
|
|
)
|
|
for nk in data.kots:
|
|
if nk.id_ is not None:
|
|
continue
|
|
need_to_print_kot = True
|
|
code = db.execute(select(func.coalesce(func.max(Kot.code), 0) + 1)).scalar_one()
|
|
kot = Kot(item.id, code, item.food_table_id, now, item.user_id)
|
|
item.kots.append(kot)
|
|
db.add(kot)
|
|
for index, nki in enumerate(nk.inventories):
|
|
product: ProductVersion = db.execute(
|
|
select(ProductVersion).where(
|
|
and_(
|
|
ProductVersion.product_id == nki.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()
|
|
if round(nki.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: Decimal = round(
|
|
Decimal(
|
|
sum(
|
|
inv.quantity
|
|
for ko in item.kots
|
|
for inv in ko.inventories
|
|
if ko.id is not None and inv.product_id == product.product_id
|
|
)
|
|
)
|
|
* -1,
|
|
2,
|
|
)
|
|
if round(nki.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=kot.id,
|
|
product_id=product.product_id,
|
|
quantity=round(nki.quantity, 2),
|
|
price=product.price,
|
|
discount=round(min(nki.discount, product.sale_category.discount_limit), 5),
|
|
is_hh=nki.is_happy_hour,
|
|
tax_rate=tax_rate,
|
|
sort_order=index,
|
|
tax=product.sale_category.tax,
|
|
)
|
|
kot.inventories.append(inv)
|
|
db.add(inv)
|
|
for m in nki.modifiers:
|
|
mod = InventoryModifier(None, m.id_, Decimal(0))
|
|
inv.modifiers.append(mod)
|
|
db.add(mod)
|
|
do_update_bill_numbers(item, db)
|
|
do_update_settlements(item, [], db)
|
|
if update_table:
|
|
do_update_table(item, guest_book, db)
|
|
db.commit()
|
|
voucher_id = item.id
|
|
with SessionFuture() as db:
|
|
if need_to_print_kot:
|
|
print_kot(voucher_id, db)
|
|
if item.voucher_type != VoucherType.KOT:
|
|
print_bill(voucher_id, db)
|
|
except SQLAlchemyError as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=str(e),
|
|
)
|