From de235f3d9ea1eeeb701127ef83555fdc62aa44cc Mon Sep 17 00:00:00 2001 From: tanshu Date: Tue, 10 Nov 2020 11:47:25 +0530 Subject: [PATCH] Product should now be fixed. Need to allow later editing now. --- barker/barker/models/master.py | 16 ++-- barker/barker/printing/bill.py | 32 +++++++- barker/barker/printing/kot.py | 51 ++++++++++-- barker/barker/routers/menu_category.py | 46 +---------- barker/barker/routers/modifier_category.py | 81 +++++++++++++++---- barker/barker/routers/product.py | 62 +++++++++++--- .../reports/beer_consumption_report.py | 19 +++-- .../barker/routers/reports/discount_report.py | 15 +++- .../routers/reports/product_sale_report.py | 30 ++++--- barker/barker/routers/reports/sale_report.py | 15 +++- barker/barker/routers/voucher/save.py | 29 +++++-- barker/barker/routers/voucher/show.py | 67 ++++++++++----- barker/barker/routers/voucher/update.py | 28 +++++-- 13 files changed, 350 insertions(+), 141 deletions(-) diff --git a/barker/barker/models/master.py b/barker/barker/models/master.py index 766a77a..317a16c 100644 --- a/barker/barker/models/master.py +++ b/barker/barker/models/master.py @@ -144,6 +144,12 @@ class ProductNew(Base): "id", UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()"), default=uuid.uuid4 ) versions = relationship("ProductVersion") + modifier_categories = relationship( + "ModifierCategory", + secondary="modifier_categories_products", + order_by="ModifierCategory.sort_order", + backref="products", + ) def __init__(self, id_=None, version_id=None): self.id = id_ @@ -196,15 +202,7 @@ class ProductVersion(Base): menu_category = relationship("MenuCategory", backref="products") sale_category = relationship("SaleCategory", backref="products") - # modifier_categories = relationship( - # "ModifierCategory", - # secondary="join(products, modifier_categories_products, " - # "ProductNew.id==modifier_categories_products.c.product_id)", - # primaryjoin="ProductVersion.id==ProductNew.version_id", - # secondaryjoin="modifier_categories_products.c.modifier_category_id==ModifierCategory.id", - # order_by="ModifierCategory.sort_order", - # backref="products", - # ) + product = relationship("ProductNew") __table_args__ = ( diff --git a/barker/barker/printing/bill.py b/barker/barker/printing/bill.py index 06b6ff3..fbfeb47 100644 --- a/barker/barker/printing/bill.py +++ b/barker/barker/printing/bill.py @@ -7,10 +7,19 @@ from typing import List, Tuple from arq import ArqRedis, create_pool from barker.core.config import settings +from sqlalchemy import and_, or_ from sqlalchemy.orm import Session from ..core.arq import settings as redis_settings -from ..models import DbSetting, Inventory, Printer, SectionPrinter, Voucher, VoucherType +from ..models import ( + DbSetting, + Inventory, + Printer, + ProductVersion, + SectionPrinter, + Voucher, + VoucherType, +) def print_bill(voucher_id: uuid.UUID, db: Session): @@ -71,7 +80,26 @@ def design_bill( s += "\n\r" + "Qty. Particulars Price Amount" s += "\n\r" + "-" * 42 for item in [i for i in items if i.quantity != 0]: - name = "H H " + item.product.full_name if item.is_happy_hour else item.product.full_name + product: ProductVersion = ( + db.query(ProductVersion) + .filter( + and_( + ProductVersion.product_id == item.product_id, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from + <= (voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).date(), + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till + >= (voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).date(), + ), + ) + ) + .first() + ) + name = "H H " + product.full_name if item.is_happy_hour else product.full_name s += "\n\r" + f"{item.quantity: >5.2f} {name:<22.22} {item.price: >6.2f} {item.price * item.quantity: >6.2f}" for m in [m for m in item.modifiers if m.modifier.show_in_bill]: s += f"\n\r -- {m.modifier.name: <38.38}" diff --git a/barker/barker/printing/kot.py b/barker/barker/printing/kot.py index 4d63de2..cd9a316 100644 --- a/barker/barker/printing/kot.py +++ b/barker/barker/printing/kot.py @@ -6,14 +6,14 @@ from typing import List from arq import ArqRedis, create_pool from barker.core.config import settings -from sqlalchemy import or_ +from sqlalchemy import and_, or_ from sqlalchemy.orm import Session from ..core.arq import settings as redis_settings -from ..models import Inventory, Kot, Printer, SectionPrinter, Voucher +from ..models import Inventory, Kot, Printer, ProductVersion, SectionPrinter, Voucher -def design_kot(voucher: Voucher, kot: Kot, items: List[Inventory], copy_number: int) -> str: +def design_kot(voucher: Voucher, kot: Kot, items: List[Inventory], copy_number: int, db: Session) -> str: date = voucher.date + timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES) s = ( "KOT / BOT".center(42) @@ -33,7 +33,26 @@ def design_kot(voucher: Voucher, kot: Kot, items: List[Inventory], copy_number: + "".ljust(42, "-") ) for item in items: - name = "H H " + item.product.full_name if item.is_happy_hour else item.product.full_name + product: ProductVersion = ( + db.query(ProductVersion) + .filter( + and_( + ProductVersion.product_id == item.product_id, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from + <= (voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).date(), + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till + >= (voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).date(), + ), + ) + ) + .first() + ) + name = "H H " + product.full_name if item.is_happy_hour else product.full_name s += "\n\r" + f"{item.quantity:6.2} x {name:<33}" for m in item.modifiers: s += "\n\r" + f" --- {m.modifier.name:<32}" @@ -46,13 +65,33 @@ def print_kot(voucher_id: uuid.UUID, db: Session): my_hash = {} kot: Kot = voucher.kots[-1] for item in kot.inventories: + product: ProductVersion = ( + db.query(ProductVersion) + .filter( + and_( + ProductVersion.product_id == item.product_id, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from + <= (voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).date(), + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till + >= (voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).date(), + ), + ) + ) + .first() + ) + printer, copies = ( db.query(Printer, SectionPrinter.copies) .join(SectionPrinter.printer) .filter(SectionPrinter.section_id == voucher.food_table.section_id) .filter( or_( - SectionPrinter.menu_category_id == item.product.menu_category_id, + SectionPrinter.menu_category_id == product.menu_category_id, SectionPrinter.menu_category_id == None, # noqa: E711 ) ) @@ -68,5 +107,5 @@ def print_kot(voucher_id: uuid.UUID, db: Session): printer_id, copies = key printer, items = value for c in range(int(copies)): - data = design_kot(voucher, kot, items, c) + data = design_kot(voucher, kot, items, c, db) asyncio.run(redis.enqueue_job("sent_to_printer", data, printer.address, printer.cut_code)) diff --git a/barker/barker/routers/menu_category.py b/barker/barker/routers/menu_category.py index 52dc83a..d88e520 100644 --- a/barker/barker/routers/menu_category.py +++ b/barker/barker/routers/menu_category.py @@ -10,7 +10,7 @@ from sqlalchemy.orm import Session from ..core.security import get_current_active_user as get_user from ..db.session import SessionLocal -from ..models.master import MenuCategory, ProductNew +from ..models.master import MenuCategory from ..schemas.auth import UserToken @@ -127,50 +127,6 @@ def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user) ] -@router.get("/sale-list") -async def sale_list( - db: Session = Depends(get_db), - current_user: UserToken = Depends(get_user), -): - list_ = ( - db.query(MenuCategory) - .filter(MenuCategory.is_active == True) # noqa: E712 - .order_by(MenuCategory.sort_order) - .order_by(MenuCategory.name) - .all() - ) - menu_categories = [] - for item in list_: - products = ( - db.query(Product) - .filter(Product.menu_category_id == item.id) - .filter(Product.is_active == True) # noqa: E712 - .order_by(Product.sort_order) - .order_by(Product.name) - .all() - ) - if len(products) == 0: - continue - pg = menu_category_info(item) - pg["products"] = [ - { - "id": p.id, - "name": p.name, - "units": p.units, - "tat": {"id": p.vat.id, "name": p.vat.name, "rate": p.vat.rate}, - "price": p.price, - "hasHappyHour": p.has_happy_hour, - "isActive": p.is_active, - "isNotAvailable": p.is_not_available, - "sortOrder": p.sort_order, - "quantity": p.quantity, - } - for p in products - ] - menu_categories.append(pg) - return menu_categories - - @router.get("/{id_}") def show_id( id_: uuid.UUID, diff --git a/barker/barker/routers/modifier_category.py b/barker/barker/routers/modifier_category.py index ad4c3f4..77b3f9b 100644 --- a/barker/barker/routers/modifier_category.py +++ b/barker/barker/routers/modifier_category.py @@ -1,17 +1,20 @@ import uuid +from datetime import date, datetime, timedelta from functools import reduce -from typing import Optional +from typing import List, Optional import barker.schemas.master as schemas from fastapi import APIRouter, Depends, HTTPException, Security, status +from sqlalchemy import and_, or_ from sqlalchemy.exc import SQLAlchemyError -from sqlalchemy.orm import Session +from sqlalchemy.orm import Session, contains_eager, joinedload +from ..core.config import settings from ..core.security import get_current_active_user as get_user from ..db.session import SessionLocal -from ..models.master import MenuCategory, ModifierCategory, ProductNew +from ..models.master import MenuCategory, ModifierCategory, ProductNew, ProductVersion from ..schemas.auth import UserToken @@ -27,6 +30,14 @@ def get_db(): db.close() +def effective_date(d: str = None) -> date: + return ( + (datetime.now() - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).date() + if d is None + else datetime.strptime(d, "%d-%b-%Y").date() + ) + + @router.post("", response_model=schemas.ModifierCategory) def save( data: schemas.ModifierCategoryIn, @@ -59,6 +70,7 @@ def save( def update( id_: uuid.UUID, data: schemas.ModifierCategoryIn, + date_: date = Depends(effective_date), db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["modifiers"]), ): @@ -70,7 +82,7 @@ def update( item.is_active = data.is_active add_products(item, data.menu_categories, db) db.commit() - return modifier_category_info(item, db=db) + return modifier_category_info(item, date_, db=db) except SQLAlchemyError as e: db.rollback() raise HTTPException( @@ -113,17 +125,35 @@ def show_blank( @router.get("/list") -def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): +def show_list( + date_: date = Depends(effective_date), db: Session = Depends(get_db), user: UserToken = Depends(get_user) +): list_ = db.query(ModifierCategory).order_by(ModifierCategory.sort_order).order_by(ModifierCategory.name).all() menu_categories = ( db.query(MenuCategory) .join(MenuCategory.products) - .filter(Product.is_active == True) # noqa: E712 - .order_by(MenuCategory.sort_order, Product.sort_order, Product.name) + .filter( + and_( + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), + ) + ) + .order_by(MenuCategory.sort_order, ProductVersion.sort_order, ProductVersion.name) + .options( + joinedload(MenuCategory.products, innerjoin=True), + contains_eager(MenuCategory.products), + ) .all() ) modifier_categories = [] for item in list_: + products = [x.id for x in item.products] modifier_category = { "id": item.id, "name": item.name, @@ -134,8 +164,8 @@ def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user) { "id": mc.id, "name": mc.name, - "enabled": reduce(lambda x, y: x and (y in item.products), mc.products, True), - "products": [{"id": p.id, "name": p.name} for p in mc.products if p in item.products], + "enabled": reduce(lambda x, y: x and (y.product_id in products), mc.products, True), + "products": [{"id": p.id, "name": p.name} for p in mc.products if p.product_id in products], } for mc in menu_categories ], @@ -151,7 +181,7 @@ def for_product( db: Session = Depends(get_db), user: UserToken = Security(get_user), ): - product: Product = db.query(Product).filter(Product.id == id_).first() + product: ProductNew = db.query(ProductNew).filter(ProductNew.id == id_).first() return [ { @@ -174,19 +204,35 @@ def for_product( @router.get("/{id_}") def show_id( id_: uuid.UUID, + date_: date = Depends(effective_date), db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["modifiers"]), ): item: ModifierCategory = db.query(ModifierCategory).filter(ModifierCategory.id == id_).first() - return modifier_category_info(item, db=db) + return modifier_category_info(item, date_, db=db) -def modifier_category_info(item: Optional[ModifierCategory], db: Session): +def modifier_category_info(item: Optional[ModifierCategory], date_: date, db: Session): menu_categories = ( db.query(MenuCategory) .join(MenuCategory.products) - .filter(Product.is_active == True) # noqa: E712 - .order_by(MenuCategory.sort_order, Product.sort_order, Product.name) + .filter( + and_( + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), + ) + ) + .order_by(MenuCategory.sort_order, ProductVersion.sort_order, ProductVersion.name) + .options( + joinedload(MenuCategory.products, innerjoin=True), + contains_eager(MenuCategory.products), + ) .all() ) if item is None: @@ -206,6 +252,7 @@ def modifier_category_info(item: Optional[ModifierCategory], db: Session): ], "sortOrder": item.sort_order, } + products = [p.id for p in item.products] return { "id": item.id, "name": item.name, @@ -221,7 +268,7 @@ def modifier_category_info(item: Optional[ModifierCategory], db: Session): { "id": p.id, "name": p.name, - "enabled": True if p in item.products else False, + "enabled": True if p.product_id in products else False, } for p in mc.products ], @@ -232,13 +279,13 @@ def modifier_category_info(item: Optional[ModifierCategory], db: Session): } -def add_products(modifier_category: ModifierCategory, menu_categories, db: Session): +def add_products(modifier_category: ModifierCategory, menu_categories: List[schemas.MenuCategoryLink], db: Session): for mc in menu_categories: for p in mc.products: old = [x for x in modifier_category.products if x.id == p.id_] old = None if len(old) == 0 else old[0] if p.enabled and old is None: - product_object = db.query(Product).filter(Product.id == p.id_).one() + product_object = db.query(ProductNew).filter(ProductNew.id == p.id_).one() modifier_category.products.append(product_object) elif not p.enabled and old: modifier_category.products.remove(old) diff --git a/barker/barker/routers/product.py b/barker/barker/routers/product.py index 45449e0..493680b 100644 --- a/barker/barker/routers/product.py +++ b/barker/barker/routers/product.py @@ -55,8 +55,14 @@ def sort_order( db.query(ProductVersion).filter( and_( ProductVersion.product_id == item.id_, - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), ) ).update({ProductVersion.sort_order: indexes[item.menu_category.id_]}) db.commit() @@ -125,13 +131,19 @@ def update( .filter( and_( ProductVersion.product_id == id_, - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), ) ) .first() ) - if item.valid_till != None: + 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, @@ -191,8 +203,14 @@ def delete( .filter( and_( ProductVersion.product_id == id_, - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), ) ) .first() @@ -245,8 +263,14 @@ def product_list(date_: date, db: Session) -> List[schemas.Product]: .join(ProductVersion.sale_category) .filter( and_( - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), ) ) .order_by(MenuCategory.sort_order) @@ -278,8 +302,14 @@ async def show_term( .filter( and_( ProductVersion.menu_category_id == mc, - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), ) ) .order_by(ProductVersion.sort_order, ProductVersion.name) @@ -311,8 +341,14 @@ def show_id( .filter( and_( ProductVersion.product_id == id_, - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), ) ) .order_by(ProductVersion.sort_order, ProductVersion.name) diff --git a/barker/barker/routers/reports/beer_consumption_report.py b/barker/barker/routers/reports/beer_consumption_report.py index 9f24ae9..0683fc6 100644 --- a/barker/barker/routers/reports/beer_consumption_report.py +++ b/barker/barker/routers/reports/beer_consumption_report.py @@ -1,4 +1,5 @@ from datetime import date, datetime, timedelta +from operator import or_ from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy.orm import Session @@ -7,7 +8,7 @@ from sqlalchemy.sql.expression import func from ...core.config import settings from ...core.security import get_current_active_user as get_user from ...db.session import SessionLocal -from ...models import Inventory, Kot, ProductNew, Voucher, VoucherType +from ...models import Inventory, Kot, ProductVersion, Voucher, VoucherType from ...schemas.auth import UserToken @@ -39,15 +40,23 @@ def beer_consumption( ) day = func.date_trunc("day", Voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).label("day") - sum_ = func.sum(Inventory.quantity * Product.quantity).label("sum") + sum_ = func.sum(Inventory.quantity * ProductVersion.quantity).label("sum") list_ = ( - db.query(day, Product.name, sum_) + db.query(day, ProductVersion.name, sum_) .join(Voucher.kots) .join(Kot.inventories) .join(Inventory.product) .filter( day >= start_date, day <= finish_date, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= day, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= day, + ), Voucher.voucher_type.in_( [ VoucherType.REGULAR_BILL.value, @@ -56,9 +65,9 @@ def beer_consumption( ] ), ) - .group_by(day, Product.name) + .group_by(day, ProductVersion.name) .having(sum_ != 0) - .order_by(day, Product.name) + .order_by(day, ProductVersion.name) .all() ) headers = [] diff --git a/barker/barker/routers/reports/discount_report.py b/barker/barker/routers/reports/discount_report.py index 5c7f52d..7579b04 100644 --- a/barker/barker/routers/reports/discount_report.py +++ b/barker/barker/routers/reports/discount_report.py @@ -4,13 +4,13 @@ from datetime import date, datetime, timedelta from typing import List from fastapi import APIRouter, Cookie, Depends, HTTPException, Security, status -from sqlalchemy import func +from sqlalchemy import func, or_ 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 import Inventory, Kot, ProductNew, SaleCategory, Voucher, VoucherType +from ...models import Inventory, Kot, ProductVersion, SaleCategory, Voucher, VoucherType from ...printing.discount_report import print_discount_report from ...schemas.auth import UserToken from ...schemas.discount_report import DiscountReport, DiscountReportItem @@ -53,17 +53,26 @@ def get_discount_report(s: date, f: date, db: Session) -> List[DiscountReportIte start_date = s + timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES) finish_date = f + timedelta(days=1, minutes=settings.NEW_DAY_OFFSET_MINUTES) + day = func.date_trunc("day", Voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).label("day") amount = func.sum(Inventory.quantity * Inventory.effective_price * Inventory.discount).label("Amount") list_ = ( db.query(SaleCategory.name, amount) .join(Voucher.kots) .join(Kot.inventories) .join(Inventory.product) - .join(Product.sale_category) + .join(ProductVersion.sale_category) .filter( Inventory.discount != 0, Voucher.date >= start_date, Voucher.date <= finish_date, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= day, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= day, + ), Voucher.voucher_type.in_([VoucherType.REGULAR_BILL.value, VoucherType.KOT.value]), ) .group_by(SaleCategory.name) diff --git a/barker/barker/routers/reports/product_sale_report.py b/barker/barker/routers/reports/product_sale_report.py index 86a5b71..7c43493 100644 --- a/barker/barker/routers/reports/product_sale_report.py +++ b/barker/barker/routers/reports/product_sale_report.py @@ -1,7 +1,7 @@ from datetime import date, datetime, timedelta from fastapi import APIRouter, Depends, HTTPException, Security, status -from sqlalchemy import func +from sqlalchemy import func, or_ from sqlalchemy.orm import Session from ...core.config import settings @@ -11,7 +11,7 @@ from ...models import ( Inventory, Kot, MenuCategory, - ProductNew, + ProductVersion, SaleCategory, Voucher, VoucherType, @@ -58,10 +58,11 @@ def product_sale_report(s: date, f: date, db: Session): start_date = s + timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES) finish_date = f + timedelta(days=1, minutes=settings.NEW_DAY_OFFSET_MINUTES) + day = func.date_trunc("day", Voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).label("day") list_ = ( db.query( - Product.id, - Product.full_name, + ProductVersion.product_id, + ProductVersion.full_name, Voucher.voucher_type, Inventory.is_happy_hour, func.sum(Inventory.quantity), @@ -69,14 +70,25 @@ def product_sale_report(s: date, f: date, db: Session): .join(Inventory.kot) .join(Kot.voucher) .join(Inventory.product) - .join(Product.sale_category) - .join(Product.menu_category) - .filter(Voucher.date >= start_date, Voucher.date <= finish_date) + .join(ProductVersion.sale_category) + .join(ProductVersion.menu_category) + .filter( + Voucher.date >= start_date, + Voucher.date <= finish_date, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= day, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= day, + ), + ) .group_by( SaleCategory.name, MenuCategory.name, - Product.id, - Product.full_name, + ProductVersion.product_id, + ProductVersion.full_name, Voucher.voucher_type, Inventory.is_happy_hour, ) diff --git a/barker/barker/routers/reports/sale_report.py b/barker/barker/routers/reports/sale_report.py index 5275ff0..7af42ee 100644 --- a/barker/barker/routers/reports/sale_report.py +++ b/barker/barker/routers/reports/sale_report.py @@ -4,7 +4,7 @@ from datetime import date, datetime, timedelta from typing import List from fastapi import APIRouter, Cookie, Depends, HTTPException, Security, status -from sqlalchemy import func +from sqlalchemy import func, or_ from sqlalchemy.orm import Session from ...core.config import settings @@ -13,7 +13,7 @@ from ...db.session import SessionLocal from ...models import ( Inventory, Kot, - ProductNew, + ProductVersion, SaleCategory, Settlement, SettleOption, @@ -71,16 +71,25 @@ def get_sale(s: date, f: date, db: Session) -> List[SaleReportItem]: start_date = s + timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES) finish_date = f + timedelta(days=1, minutes=settings.NEW_DAY_OFFSET_MINUTES) + day = func.date_trunc("day", Voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).label("day") list_ = ( db.query(SaleCategory.name, func.sum(Inventory.net)) .join(Inventory.kot) .join(Kot.voucher) .join(Inventory.product) - .join(Product.sale_category) + .join(ProductVersion.sale_category) .filter( Voucher.date >= start_date, Voucher.date <= finish_date, Voucher.voucher_type == VoucherType.REGULAR_BILL.value, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= day, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= day, + ), ) .group_by(SaleCategory.name) .order_by(SaleCategory.name) diff --git a/barker/barker/routers/voucher/save.py b/barker/barker/routers/voucher/save.py index 8f1ca39..fef82d4 100644 --- a/barker/barker/routers/voucher/save.py +++ b/barker/barker/routers/voucher/save.py @@ -1,15 +1,16 @@ import uuid -from datetime import datetime +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 func +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 import ( @@ -17,7 +18,7 @@ from ...models import ( Inventory, InventoryModifier, Kot, - ProductNew, + ProductVersion, Voucher, VoucherType, ) @@ -84,7 +85,7 @@ def do_save( user: UserToken, ): now = datetime.now() - + product_date = (now - timedelta(days=settings.NEW_DAY_OFFSET_MINUTES)).date() check_permissions(None, voucher_type, user.permissions) bill_id = get_bill_id(voucher_type, db) @@ -115,7 +116,23 @@ def do_save( sum(inv.quantity for ko in data.kots for inv in ko.inventories if inv.product.id_ == i.product.id_), 2, ) - product = db.query(Product).filter(Product.id == i.product.id_).first() + 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: FE711 + ProductVersion.valid_till >= product_date, + ), + ) + ) + .first() + ) if total_quantity < 0: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, @@ -131,7 +148,7 @@ def do_save( tax_rate = get_tax(product.sale_category.tax.rate, voucher_type) inv = Inventory( kot.id, - product.id, + product.product_id, round(i.quantity, 2), product.price, round(i.discount, 5), diff --git a/barker/barker/routers/voucher/show.py b/barker/barker/routers/voucher/show.py index 8159414..4ddca0c 100644 --- a/barker/barker/routers/voucher/show.py +++ b/barker/barker/routers/voucher/show.py @@ -1,14 +1,23 @@ import re import uuid +from datetime import date from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Security, status +from sqlalchemy import and_, or_ from sqlalchemy.orm import Session from ...core.security import get_current_active_user as get_user from ...db.session import SessionLocal -from ...models import FoodTable, GuestBook, Overview, Voucher, VoucherType +from ...models import ( + FoodTable, + GuestBook, + Overview, + ProductVersion, + Voucher, + VoucherType, +) from ...schemas.auth import UserToken @@ -31,7 +40,7 @@ def from_id( user: UserToken = Security(get_user), ): item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first() - return voucher_info(item) + return voucher_info(item, db) @router.get("/from-bill/{id_}") @@ -59,7 +68,7 @@ def from_bill( item = item.first() if item is None: return {} - return voucher_info(item) + return voucher_info(item, db) @router.get("/from-table/{id_}") @@ -85,7 +94,7 @@ def from_table( detail="Voucher not found", ) else: - return voucher_info(item.voucher) + return voucher_info(item.voucher, db) table = db.query(FoodTable).filter(FoodTable.id == id_).first() if g is not None: guest = db.query(GuestBook).filter(GuestBook.id == g).first() @@ -94,7 +103,41 @@ def from_table( return voucher_blank(table, guest) -def voucher_info(item: Voucher): +def voucher_product(product_id: uuid.UUID, date_: date, db: Session): + product: ProductVersion = ( + db.query(ProductVersion) + .filter( + and_( + ProductVersion.product_id == product_id, + or_( + ProductVersion.valid_from == None, # noqa: E711 + ProductVersion.valid_from <= date_, + ), + or_( + ProductVersion.valid_till == None, # noqa: FE711 + ProductVersion.valid_till >= date_, + ), + ) + ) + .first() + ) + + return { + "id": product_id, + "name": product.full_name, + "menuCategory": { + "id": product.menu_category_id, + "name": product.menu_category.name, + "discountLimit": product.menu_category.discount_limit, + }, + "saleCategory": { + "id": product.sale_category_id, + "name": product.sale_category.name, + }, + } + + +def voucher_info(item: Voucher, db: Session): return { "id": item.id, "date": item.date.strftime("%H:%M"), @@ -123,19 +166,7 @@ def voucher_info(item: Voucher): { "id": i.id, "sortOrder": i.sort_order, - "product": { - "id": i.product_id, - "name": i.product.full_name, - "menuCategory": { - "id": i.product.menu_category_id, - "name": i.product.menu_category.name, - "discountLimit": i.product.menu_category.discount_limit, - }, - "saleCategory": { - "id": i.product.sale_category_id, - "name": i.product.sale_category.name, - }, - }, + "product": voucher_product(i.product_id, item.date.date(), db), "quantity": i.quantity, "price": i.price, "isHappyHour": i.is_happy_hour, diff --git a/barker/barker/routers/voucher/update.py b/barker/barker/routers/voucher/update.py index b9d9892..791c760 100644 --- a/barker/barker/routers/voucher/update.py +++ b/barker/barker/routers/voucher/update.py @@ -1,22 +1,23 @@ import uuid -from datetime import datetime +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 func +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 import ( Inventory, InventoryModifier, Kot, - ProductNew, + ProductVersion, Voucher, VoucherType, ) @@ -56,6 +57,7 @@ def update( ): try: now = datetime.now() + product_date = (now - timedelta(days=settings.NEW_DAY_OFFSET_MINUTES)).date() update_table = u voucher_type = VoucherType[p] guest_book = get_guest_book(g, db) @@ -94,7 +96,23 @@ def update( item.kots.append(kot) db.add(kot) for index, i in enumerate(k.inventories): - product = db.query(Product).filter(Product.id == i.product.id_).first() + 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: FE711 + ProductVersion.valid_till >= product_date, + ), + ) + ) + .first() + ) if round(i.quantity, 2) < 0: if "edit-printed-product" not in user.permissions: raise HTTPException( @@ -120,7 +138,7 @@ def update( tax_rate = get_tax(product.sale_category.tax.rate, voucher_type) inv = Inventory( kot.id, - product.id, + product.product_id, round(i.quantity, 2), product.price, round(i.discount, 5),