diff --git a/barker/barker/routers/table.py b/barker/barker/routers/table.py index b1310db..71748bd 100644 --- a/barker/barker/routers/table.py +++ b/barker/barker/routers/table.py @@ -1,6 +1,6 @@ import uuid -from typing import List, Optional +from typing import List, Union import barker.schemas.table as schemas @@ -32,7 +32,7 @@ def sort_order( data: List[schemas.Table], db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["sections"]), -): +) -> List[schemas.Table]: try: for index, item in enumerate(data): db.query(FoodTable).filter(FoodTable.id == item.id_).update({FoodTable.sort_order: index}) @@ -64,7 +64,7 @@ def save( data: schemas.TableIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["sections"]), -): +) -> schemas.Table: try: item = FoodTable( name=data.name, @@ -92,7 +92,7 @@ def update( data: schemas.TableIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["sections"]), -): +) -> schemas.Table: try: item: FoodTable = db.query(FoodTable).filter(FoodTable.id == id_).first() item.name = data.name @@ -112,17 +112,17 @@ def update( raise -@router.delete("/{id_}") +@router.delete("/{id_}", response_model=schemas.TableBlank) def delete( id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["sections"]), -): +) -> schemas.TableBlank: try: item: FoodTable = db.query(FoodTable).filter(FoodTable.id == id_).first() db.delete(item) db.commit() - return food_table_info(item) + return food_table_blank() except SQLAlchemyError as e: db.rollback() raise HTTPException( @@ -134,27 +134,17 @@ def delete( raise -@router.get("") +@router.get("", response_model=schemas.TableBlank) def show_blank( db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["sections"]), -): - return food_table_info(None) +) -> schemas.TableBlank: + return food_table_blank() -@router.get("/list") +@router.get("/list", response_model=List[schemas.Table]) def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): - return [ - { - "id": item.id, - "name": item.name, - "seats": item.seats, - "section": {"id": item.section_id, "name": item.section.name}, - "isActive": item.is_active, - "sortOrder": item.sort_order, - } - for item in db.query(FoodTable).order_by(FoodTable.sort_order).all() - ] + return [food_table_info(item) for item in db.query(FoodTable).order_by(FoodTable.sort_order).all()] @router.get("/running") @@ -183,38 +173,40 @@ def show_running(db: Session = Depends(get_db), user: UserToken = Depends(get_us return food_tables -@router.get("/from-voucher/{id_}") +@router.get("/from-voucher/{id_}", response_model=Union[schemas.Table, schemas.TableBlank]) def show_voucher( id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user), -): +) -> Union[schemas.Table, schemas.TableBlank]: overview: Overview = db.query(Overview).filter(Overview.voucher_id == id_).first() if overview is not None: return food_table_info(overview.food_table) - return food_table_info(None) + return food_table_blank() -@router.get("/{id_}") +@router.get("/{id_}", response_model=schemas.Table) def show_id( id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["sections"]), -): +) -> schemas.Table: item: FoodTable = db.query(FoodTable).filter(FoodTable.id == id_).first() return food_table_info(item) -def food_table_info(item: Optional[FoodTable]): - if item is None: - return {"name": "", "seats": 0, "section": {}, "isActive": True, "sortOrder": 0} - return { - "id": item.id, - "name": item.name, - "seats": item.seats, - "section": {"id": item.section_id, "name": item.section.name}, - "isActive": item.is_active, - "status": "" if item.status is None else item.status.status, - "sortOrder": item.sort_order, - "voucherId": None if item.status is None else item.status.voucher_id, - } +def food_table_info(item: FoodTable) -> schemas.Table: + return schemas.Table( + id=item.id, + name=item.name, + seats=item.seats, + section=schemas.SectionLink(id=item.section_id, name=item.section.name), + isActive=item.is_active, + status="" if item.status is None else item.status.status, + sortOrder=item.sort_order, + voucherId=None if item.status is None else item.status.voucher_id, + ) + + +def food_table_blank() -> schemas.TableBlank: + return schemas.TableBlank(name="", seats=0, isActive=True, sortOrder=0) diff --git a/barker/barker/routers/tax.py b/barker/barker/routers/tax.py index e723dec..f333ae7 100644 --- a/barker/barker/routers/tax.py +++ b/barker/barker/routers/tax.py @@ -2,17 +2,19 @@ import re import uuid from decimal import Decimal -from typing import Optional +from typing import List import barker.schemas.tax as schemas from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session +from sqlalchemy.sql.functions import count from ..core.security import get_current_active_user as get_user from ..db.session import SessionLocal -from ..models.master import Tax +from ..models.master import SaleCategory, Tax +from ..models.voucher import Inventory from ..schemas.auth import UserToken @@ -33,9 +35,9 @@ def save( data: schemas.TaxIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["taxes"]), -): +) -> schemas.Tax: try: - item = Tax(name=data.name, rate=round(data.rate / Decimal(100), 4)) + item = Tax(name=data.name, rate=round(data.rate, 5)) if not name_valid(data.name): raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, @@ -61,7 +63,7 @@ def update( data: schemas.TaxIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["taxes"]), -): +) -> schemas.Tax: try: item: Tax = db.query(Tax).filter(Tax.id == id_).first() if item.is_fixture: @@ -75,7 +77,7 @@ def update( detail="The name is not valid", ) item.name = data.name - item.rate = round(data.rate / Decimal(100), 4) + item.rate = round(data.rate, 5) db.commit() return tax_info(item) except SQLAlchemyError as e: @@ -89,12 +91,12 @@ def update( raise -@router.delete("/{id_}") +@router.delete("/{id_}", response_model=schemas.TaxBlank) def delete( id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["taxes"]), -): +) -> schemas.TaxBlank: try: item: Tax = db.query(Tax).filter(Tax.id == id_).first() if item is None: @@ -102,62 +104,63 @@ def delete( status_code=status.HTTP_404_NOT_FOUND, detail="Tax not found", ) - elif item.is_fixture: + if item.is_fixture: raise HTTPException( status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) - else: - db.delete(item) - db.commit() - return tax_info(None) + if db.query(count(SaleCategory.tax_id)).filter(SaleCategory.tax_id == item.id).scalar() > 0: + raise HTTPException( + status_code=status.HTTP_423_LOCKED, + detail=f"{item.name} has associated Sale Categories and cannot be deleted", + ) + if db.query(count(Inventory.tax_id)).filter(Inventory.tax_id == item.id).scalar() > 0: + raise HTTPException( + status_code=status.HTTP_423_LOCKED, + detail=f"{item.name} has associated Inventories and cannot be deleted", + ) + db.delete(item) + db.commit() + return tax_blank() except Exception: db.rollback() raise -@router.get("") +@router.get("", response_model=schemas.TaxBlank) def show_blank( db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["taxes"]), -): - return tax_info(None) +) -> schemas.TaxBlank: + return tax_blank() -@router.get("/list") -def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): - return [ - { - "id": item.id, - "name": item.name, - "rate": item.rate, - "isFixture": item.is_fixture, - } - for item in db.query(Tax).order_by(Tax.name).all() - ] +@router.get("/list", response_model=List[schemas.Tax]) +def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)) -> List[schemas.Tax]: + return [tax_info(item) for item in db.query(Tax).order_by(Tax.name).all()] -@router.get("/{id_}") +@router.get("/{id_}", response_model=schemas.Tax) def show_id( id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["taxes"]), -): +) -> schemas.Tax: item: Tax = db.query(Tax).filter(Tax.id == id_).first() return tax_info(item) -def tax_info(item: Optional[Tax]): - if item is None: - tax = {"name": "", "rate": 0, "isFixture": False} - else: - tax = { - "id": item.id, - "name": item.name, - "rate": item.rate * 100, - "isFixture": item.is_fixture, - } - return tax +def tax_info(item: Tax) -> schemas.Tax: + return schemas.Tax( + id=item.id, + name=item.name, + rate=item.rate, + isFixture=item.is_fixture, + ) + + +def tax_blank() -> schemas.TaxBlank: + return schemas.TaxBlank(name="", rate=0, isFixture=False) def name_valid(name: str) -> bool: diff --git a/barker/barker/schemas/menu_category.py b/barker/barker/schemas/menu_category.py index 3d0f761..ee25db2 100644 --- a/barker/barker/schemas/menu_category.py +++ b/barker/barker/schemas/menu_category.py @@ -11,6 +11,7 @@ from .product_link import ProductLink class MenuCategoryIn(BaseModel): name: str = Field(..., min_length=1) is_active: bool + is_fixture: bool class Config: anystr_strip_whitespace = True @@ -19,7 +20,6 @@ class MenuCategoryIn(BaseModel): class MenuCategory(MenuCategoryIn): id_: uuid.UUID - is_fixture: bool sort_order: int class Config: diff --git a/barker/barker/schemas/table.py b/barker/barker/schemas/table.py index 9614f7b..77a5cc7 100644 --- a/barker/barker/schemas/table.py +++ b/barker/barker/schemas/table.py @@ -27,6 +27,14 @@ class Table(TableIn): alias_generator = to_camel +class TableBlank(TableIn): + name: str = Field(..., min_length=1) + section: Optional[SectionLink] + + class Config: + alias_generator = to_camel + + class TableLink(BaseModel): id_: uuid.UUID = Field(...) name: Optional[str] diff --git a/barker/barker/schemas/tax.py b/barker/barker/schemas/tax.py index 22c5ae4..518aab1 100644 --- a/barker/barker/schemas/tax.py +++ b/barker/barker/schemas/tax.py @@ -10,20 +10,26 @@ from . import to_camel class TaxIn(BaseModel): name: str = Field(..., min_length=1) - rate: Decimal = Field(ge=0, multiple_of=0.01, default=0) + rate: Decimal = Field(ge=0, default=0) + is_fixture: bool class Config: - fields = {"id_": "id"} anystr_strip_whitespace = True alias_generator = to_camel class Tax(TaxIn): id_: uuid.UUID - is_fixture: bool class Config: - fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class TaxBlank(TaxIn): + name: str + + class Config: anystr_strip_whitespace = True alias_generator = to_camel diff --git a/bookie/src/app/taxes/tax-detail/tax-detail.component.ts b/bookie/src/app/taxes/tax-detail/tax-detail.component.ts index c07455d..b154853 100644 --- a/bookie/src/app/taxes/tax-detail/tax-detail.component.ts +++ b/bookie/src/app/taxes/tax-detail/tax-detail.component.ts @@ -2,6 +2,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angula import { FormBuilder, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; +import { round } from 'mathjs'; import { Tax } from '../../core/tax'; import { ToasterService } from '../../core/toaster.service'; @@ -44,7 +45,7 @@ export class TaxDetailComponent implements OnInit, AfterViewInit { this.item = item; this.form.setValue({ name: this.item.name || '', - rate: this.item.rate || '', + rate: this.item.rate * 100, }); } @@ -96,7 +97,7 @@ export class TaxDetailComponent implements OnInit, AfterViewInit { getItem(): Tax { const formModel = this.form.value; this.item.name = formModel.name; - this.item.rate = +formModel.rate; + this.item.rate = round(+formModel.rate / 100, 5); return this.item; } }