barker/barker/barker/routers/update_product_prices.py

174 lines
5.7 KiB
Python

import uuid
from datetime import date, timedelta
from decimal import Decimal
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Security, status
from sqlalchemy import and_, or_, select
from sqlalchemy.orm import Session, contains_eager, joinedload
from ..core.security import get_current_active_user as get_user
from ..db.session import SessionFuture
from ..models.menu_category import MenuCategory
from ..models.product_version import ProductVersion
from ..schemas.update_product_prices import UpdateProductPrices, UpdateProductPricesItem
from ..schemas.user_token import UserToken
from . import optional_query_date
router = APIRouter()
@router.get("", response_model=UpdateProductPrices)
def get_update_product_prices(
date_: Optional[date] = Depends(optional_query_date),
user: UserToken = Security(get_user, scopes=["products"]),
) -> UpdateProductPrices:
if date_ is None:
return UpdateProductPrices(
date=date.today(),
items=[],
)
with SessionFuture() as db:
return UpdateProductPrices(
date=date_,
items=update_product_prices_list(None, date_, db),
)
@router.get("/{id_}", response_model=UpdateProductPrices)
def get_update_product_prices_id(
id_: uuid.UUID,
date_: Optional[date] = Depends(optional_query_date),
user: UserToken = Security(get_user, scopes=["products"]),
) -> UpdateProductPrices:
if date_ is None:
return UpdateProductPrices(
date=date.today(),
menuCategoryId=id_,
items=[],
)
with SessionFuture() as db:
return UpdateProductPrices(
date=date_,
menuCategoryId=id_,
items=update_product_prices_list(id_, date_, db),
)
def update_product_prices_list(
menu_category_id: Optional[uuid.UUID], date_: date, db: Session
) -> List[UpdateProductPricesItem]:
list_ = (
select(ProductVersion)
.join(ProductVersion.menu_category)
.where(
and_(
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= date_,
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= date_,
),
)
)
)
if menu_category_id is not None:
list_ = list_.where(ProductVersion.menu_category_id == menu_category_id)
list_.order_by(
MenuCategory.sort_order,
MenuCategory.name,
ProductVersion.sort_order,
ProductVersion.name,
ProductVersion.valid_from.nullsfirst(),
).options(
joinedload(ProductVersion.menu_category, innerjoin=True),
contains_eager(ProductVersion.menu_category),
)
return [
UpdateProductPricesItem(id=item.product_id, name=item.full_name, oldPrice=item.price, newPrice=item.price)
for item in db.execute(list_).scalars().all()
]
@router.post("", response_model=UpdateProductPrices)
def save_update_product_prices(
data: UpdateProductPrices,
user: UserToken = Security(get_user, scopes=["products"]),
) -> UpdateProductPrices:
with SessionFuture() as db:
for item in data.items:
update_product(item.id, item.new_price, data.date_, db)
db.commit()
return UpdateProductPrices(
date=data.date_,
items=update_product_prices_list(None, data.date_, db),
)
@router.post("/{id_}", response_model=UpdateProductPrices)
def save_update_product_prices_id(
id_: uuid.UUID,
data: UpdateProductPrices,
user: UserToken = Security(get_user, scopes=["products"]),
) -> UpdateProductPrices:
with SessionFuture() as db:
for item in data.items:
update_product(item.id, item.new_price, data.date_, db)
db.commit()
return UpdateProductPrices(
date=data.date_,
menuCategoryId=id_,
items=update_product_prices_list(id_, data.date_, db),
)
def update_product(id_: uuid.UUID, price: Decimal, date_: date, db: Session):
item: ProductVersion = db.execute(
select(ProductVersion)
.join(ProductVersion.menu_category)
.where(
and_(
ProductVersion.product_id == id_,
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= date_,
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= date_,
),
)
)
).scalar_one()
if item.valid_till is not None:
# Allow adding a product here splitting the valid from and to, but not implemented right now
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Product has been invalidated",
)
if item.valid_from == date_: # Update the product as valid from the the same
item.price = price
db.commit()
else: # Create a new version of the product from the new details
item.valid_till = date_ - timedelta(days=1)
product_version = ProductVersion(
product_id=item.product_id,
name=item.name,
units=item.units,
menu_category_id=item.menu_category_id,
sale_category_id=item.sale_category_id,
price=price,
has_happy_hour=item.has_happy_hour,
is_not_available=item.is_not_available,
quantity=item.quantity,
valid_from=date_,
valid_till=None,
sort_order=item.sort_order,
)
db.add(product_version)