diff --git a/barker/barker/__main__.py b/barker/barker/__main__.py index c727fcc..0d0c320 100644 --- a/barker/barker/__main__.py +++ b/barker/barker/__main__.py @@ -1,4 +1,4 @@ -from barker.main import init +from .main import init init() diff --git a/barker/barker/core/security.py b/barker/barker/core/security.py index 20e1854..d7c32c4 100644 --- a/barker/barker/core/security.py +++ b/barker/barker/core/security.py @@ -3,9 +3,6 @@ import uuid from datetime import datetime, timedelta from typing import List, Optional -from barker.core.config import settings -from barker.models.auth import Client -from barker.models.auth import User as UserModel from fastapi import Depends, HTTPException, Security, status from fastapi.security import OAuth2PasswordBearer, SecurityScopes from jose import jwt @@ -14,7 +11,10 @@ from jwt import PyJWTError from pydantic import BaseModel, ValidationError from sqlalchemy.orm import Session +from ..core.config import settings from ..db.session import SessionLocal +from ..models.auth import Client +from ..models.auth import User as UserModel # to get a string like this run: from ..schemas.auth import UserToken diff --git a/barker/barker/db/session.py b/barker/barker/db/session.py index f5056a7..3329a6a 100644 --- a/barker/barker/db/session.py +++ b/barker/barker/db/session.py @@ -1,9 +1,10 @@ import logging -from barker.core.config import settings from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker +from ..core.config import settings + logging.basicConfig() logging.getLogger("sqlalchemy.engine").setLevel(settings.LOG_LEVEL) diff --git a/barker/barker/models/voucher.py b/barker/barker/models/voucher.py index e7db9f2..f66abc2 100644 --- a/barker/barker/models/voucher.py +++ b/barker/barker/models/voucher.py @@ -14,6 +14,7 @@ from sqlalchemy import ( Unicode, UniqueConstraint, case, + func, ) from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.ext.hybrid import hybrid_property @@ -375,8 +376,8 @@ class Inventory(Base): @hybrid_property def amount(self): - return Decimal(self.net * (1 + self.tax_rate)) + return round(Decimal(self.net * (1 + self.tax_rate)), 2) @amount.expression def amount(cls): - return cls.net * (1 + cls.tax_rate) + return func.round(cls.net * (1 + cls.tax_rate), 2) diff --git a/barker/barker/printing/__init__.py b/barker/barker/printing/__init__.py index 1f57910..b0f3906 100644 --- a/barker/barker/printing/__init__.py +++ b/barker/barker/printing/__init__.py @@ -1,2 +1,2 @@ -from barker.printing.bill import print_bill # noqa: F401 -from barker.printing.kot import print_kot # noqa: F401 +from ..printing.bill import print_bill # noqa: F401 +from ..printing.kot import print_kot # noqa: F401 diff --git a/barker/barker/printing/bill.py b/barker/barker/printing/bill.py index cf1ff3c..8a3c37e 100644 --- a/barker/barker/printing/bill.py +++ b/barker/barker/printing/bill.py @@ -3,17 +3,11 @@ import uuid from decimal import Decimal from typing import List, Tuple -from barker.models import ( - DbSetting, - Inventory, - Printer, - SectionPrinter, - Voucher, - VoucherType, -) -from barker.worker import sent_to_printer from sqlalchemy.orm import Session +from ..models import DbSetting, Inventory, Printer, SectionPrinter, Voucher, VoucherType +from ..worker import sent_to_printer + def print_bill(voucher_id: uuid.UUID, db: Session): voucher: Voucher = db.query(Voucher).filter(Voucher.id == voucher_id).first() diff --git a/barker/barker/printing/kot.py b/barker/barker/printing/kot.py index e7791ec..d85d71c 100644 --- a/barker/barker/printing/kot.py +++ b/barker/barker/printing/kot.py @@ -2,11 +2,12 @@ import uuid from typing import List -from barker.models import Inventory, Kot, Printer, SectionPrinter, Voucher -from barker.worker import sent_to_printer from sqlalchemy import or_ from sqlalchemy.orm import Session +from ..models import Inventory, Kot, Printer, SectionPrinter, Voucher +from ..worker import sent_to_printer + def design_kot( voucher: Voucher, kot: Kot, items: List[Inventory], copy_number: int diff --git a/barker/barker/routers/auth/user.py b/barker/barker/routers/auth/user.py index cb25148..24aaab6 100644 --- a/barker/barker/routers/auth/user.py +++ b/barker/barker/routers/auth/user.py @@ -4,13 +4,13 @@ from typing import List, Optional import barker.schemas.auth as schemas -from barker.models.auth import Role, User from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session from ...core.security import get_current_active_user as get_user from ...db.session import SessionLocal +from ...models.auth import Role, User from ...schemas.auth import UserToken diff --git a/barker/barker/routers/login.py b/barker/barker/routers/login.py index 6fc11c1..cad9f4a 100644 --- a/barker/barker/routers/login.py +++ b/barker/barker/routers/login.py @@ -1,6 +1,5 @@ from datetime import timedelta -from barker.core.config import settings from fastapi import ( APIRouter, Cookie, @@ -16,6 +15,7 @@ from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.orm import Session from .. import __version__ +from ..core.config import settings from ..core.security import ( Token, authenticate_user, diff --git a/barker/barker/routers/reports/beer_consumption_report.py b/barker/barker/routers/reports/beer_consumption_report.py index ab5c8bb..fb93c8c 100644 --- a/barker/barker/routers/reports/beer_consumption_report.py +++ b/barker/barker/routers/reports/beer_consumption_report.py @@ -1,10 +1,10 @@ from datetime import date, datetime, timedelta -from barker.core.config import settings from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy.orm import Session 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, Product, Voucher, VoucherType diff --git a/barker/barker/routers/reports/bill_settlement_report.py b/barker/barker/routers/reports/bill_settlement_report.py index de41f27..7927d64 100644 --- a/barker/barker/routers/reports/bill_settlement_report.py +++ b/barker/barker/routers/reports/bill_settlement_report.py @@ -1,9 +1,9 @@ from datetime import date, datetime, timedelta -from barker.core.config import settings from fastapi import APIRouter, Depends, HTTPException, Security, status 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 Reprint, Settlement, SettleOption, Voucher, VoucherType diff --git a/barker/barker/routers/reports/discount_report.py b/barker/barker/routers/reports/discount_report.py index 6de1d55..bb65f20 100644 --- a/barker/barker/routers/reports/discount_report.py +++ b/barker/barker/routers/reports/discount_report.py @@ -1,10 +1,10 @@ from datetime import date, datetime, timedelta -from barker.core.config import settings from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import func 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 ( diff --git a/barker/barker/routers/reports/product_sale_report.py b/barker/barker/routers/reports/product_sale_report.py index 467ba4b..601b241 100644 --- a/barker/barker/routers/reports/product_sale_report.py +++ b/barker/barker/routers/reports/product_sale_report.py @@ -1,10 +1,10 @@ from datetime import date, datetime, timedelta -from barker.core.config import settings from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import func 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 ( diff --git a/barker/barker/routers/reports/sale_report.py b/barker/barker/routers/reports/sale_report.py index 973f959..8a5e2f0 100644 --- a/barker/barker/routers/reports/sale_report.py +++ b/barker/barker/routers/reports/sale_report.py @@ -1,10 +1,10 @@ from datetime import date, datetime, timedelta -from barker.core.config import settings from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import func 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 ( diff --git a/barker/barker/routers/reports/tax_report.py b/barker/barker/routers/reports/tax_report.py index 260ffac..aa5924f 100644 --- a/barker/barker/routers/reports/tax_report.py +++ b/barker/barker/routers/reports/tax_report.py @@ -1,10 +1,10 @@ from datetime import date, datetime, timedelta -from barker.core.config import settings from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import func 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, Tax, Voucher, VoucherType diff --git a/barker/barker/routers/reprint.py b/barker/barker/routers/reprint.py deleted file mode 100644 index 41ac8e9..0000000 --- a/barker/barker/routers/reprint.py +++ /dev/null @@ -1,21 +0,0 @@ -import uuid - -import transaction - -from barker.models import Reprint -from pyramid.view import view_config - - -@view_config( - request_method="POST", - route_name="v1_reprint", - renderer="json", - permission="Print Bill", - trans=True, -) -def save(request): - id_ = uuid.UUID(request.matchdict["id"]) - item = Reprint(id_, uuid.UUID(request.authenticated_userid)) - request.dbsession.add(item) - transaction.commit() - return True diff --git a/barker/barker/routers/voucher/__init__.py b/barker/barker/routers/voucher/__init__.py index c3a47c9..ea7be8c 100644 --- a/barker/barker/routers/voucher/__init__.py +++ b/barker/barker/routers/voucher/__init__.py @@ -2,7 +2,11 @@ import uuid from typing import List, Optional -from barker.models import ( +from fastapi import HTTPException, status +from sqlalchemy import func +from sqlalchemy.orm import Session + +from ...models import ( GuestBook, Overview, Settlement, @@ -10,10 +14,7 @@ from barker.models import ( Voucher, VoucherType, ) -from barker.schemas.receive_payment import ReceivePaymentItem as SettleSchema -from fastapi import HTTPException, status -from sqlalchemy import func -from sqlalchemy.orm import Session +from ...schemas.receive_payment import ReceivePaymentItem as SettleSchema def get_tax(tax, voucher_type): diff --git a/barker/barker/routers/voucher/change.py b/barker/barker/routers/voucher/change.py index 90e4e49..11f6a1c 100644 --- a/barker/barker/routers/voucher/change.py +++ b/barker/barker/routers/voucher/change.py @@ -4,8 +4,8 @@ from decimal import Decimal from typing import Optional import barker.schemas.voucher as schemas +from barker.models import VoucherType -from barker.schemas.receive_payment import ReceivePaymentItem as SettleSchema from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session @@ -15,6 +15,7 @@ from ...db.session import SessionLocal from ...models import Overview, Reprint, SettleOption, Voucher from ...routers.voucher import do_update_settlements, get_guest_book from ...schemas.auth import UserToken +from ...schemas.receive_payment import ReceivePaymentItem as SettleSchema from .save import do_save @@ -37,27 +38,23 @@ def change( u: bool, # Update table? g: Optional[uuid.UUID] = None, # Guest book id db: Session = Depends(get_db), - user: UserToken = Security(get_user), + user: UserToken = Security(get_user, scopes=["edit-printed-bill"]), ): try: old: Voucher = db.query(Voucher).filter(Voucher.id == id_).first() - amount_changed: bool = old.amount != round( - sum( - Decimal( - (0 if i.is_happy_hour else i.price) - * i.quantity - * (1 - i.discount) - * (1 + i.tax_rate) - ) - for k in data.kots - for i in k.inventories - ), - 2, + if old.voucher_type == VoucherType.VOID: + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Voucher cannot be reprinted. It is already void.", + ) + bill_changed: bool = ( + len( + set((i.id, i.amount) for k in old.kots for i in k.inventories) + ^ set((i.id_, i.amount) for k in data.kots for i in k.inventories) + ) + != 0 ) - items_changed: bool = len([i for k in old.kots for i in k.inventories]) != len( - [i for k in data.kots for i in k.inventories] - ) - if amount_changed or items_changed: + if bill_changed: void_and_issue_new_bill(data, u, g, old, db, user) else: reprint_bill(id_, user.id_, db) @@ -88,10 +85,11 @@ def void_and_issue_new_bill( ): update_table = u guest_book = get_guest_book(g, db) - item = do_save(data, old.voucher_type, guest_book, db, user) + item: Voucher = do_save(data, old.voucher_type, guest_book, db, user) db.flush() - old.void = True - old.void_reason = f"Bill Discounted / Changed. New Bill ID is {item.full_bill_id}" + old.bill_id = None + old.voucher_type = VoucherType.VOID + old.reason = f"Bill Discounted / Changed. New Bill ID is {item.full_bill_id}" do_update_settlements( old, [SettleSchema(id=SettleOption.VOID(), amount=round(old.amount))], db ) diff --git a/barker/barker/routers/voucher/receive_payment.py b/barker/barker/routers/voucher/receive_payment.py index 1a93a60..50d7b2e 100644 --- a/barker/barker/routers/voucher/receive_payment.py +++ b/barker/barker/routers/voucher/receive_payment.py @@ -8,7 +8,7 @@ from sqlalchemy.orm import Session from ...core.security import get_current_active_user as get_user from ...db.session import SessionLocal -from ...models import Overview, Settlement, SettleOption, Voucher, VoucherType +from ...models import Overview, SettleOption, Voucher, VoucherType from ...schemas.auth import UserToken from . import do_update_settlements diff --git a/barker/barker/routers/voucher/save.py b/barker/barker/routers/voucher/save.py index 76df740..08cc0e5 100644 --- a/barker/barker/routers/voucher/save.py +++ b/barker/barker/routers/voucher/save.py @@ -5,7 +5,6 @@ from typing import Optional import barker.schemas.voucher as schemas -from barker.printing import print_bill, print_kot from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import func from sqlalchemy.exc import SQLAlchemyError @@ -22,6 +21,7 @@ from ...models import ( Voucher, VoucherType, ) +from ...printing import print_bill, print_kot from ...routers.voucher import ( check_permissions, do_update_settlements, @@ -109,7 +109,30 @@ def do_save( item.kots.append(kot) db.add(kot) for index, i in enumerate(k.inventories): + if i.quantity == 0: + continue + total_quantity = round( + 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() + if total_quantity < 0: + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Quantity of {product.full_name} cannot be less than 0", + ) + 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}", + ) tax_rate = get_tax(product.sale_category.tax.rate, voucher_type) inv = Inventory( kot.id, diff --git a/barker/barker/routers/voucher/split.py b/barker/barker/routers/voucher/split.py index b5cbdce..93a95a7 100644 --- a/barker/barker/routers/voucher/split.py +++ b/barker/barker/routers/voucher/split.py @@ -5,7 +5,6 @@ from typing import List, Optional import barker.schemas.split as schemas -from barker.schemas.receive_payment import ReceivePaymentItem as SettleSchema from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import func from sqlalchemy.exc import SQLAlchemyError @@ -29,6 +28,7 @@ from ...routers.voucher import ( get_bill_id, ) from ...schemas.auth import UserToken +from ...schemas.receive_payment import ReceivePaymentItem as SettleSchema router = APIRouter() @@ -55,7 +55,8 @@ def split( now = datetime.now() update_table = u item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first() - item.void = True + item.bill_id = None + item.voucher_type = VoucherType.VOID item.reason = "Bill Split" do_update_settlements( item, [SettleSchema(id=SettleOption.VOID(), amount=round(item.amount))], db diff --git a/barker/barker/routers/voucher/update.py b/barker/barker/routers/voucher/update.py index bd496d5..1c1246e 100644 --- a/barker/barker/routers/voucher/update.py +++ b/barker/barker/routers/voucher/update.py @@ -91,6 +91,28 @@ def update( db.add(kot) for index, i in enumerate(k.inventories): product = db.query(Product).filter(Product.id == i.product.id_).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, diff --git a/barker/barker/routers/voucher/void.py b/barker/barker/routers/voucher/void.py index 3c48852..5844b3b 100644 --- a/barker/barker/routers/voucher/void.py +++ b/barker/barker/routers/voucher/void.py @@ -1,6 +1,5 @@ import uuid -from barker.schemas.receive_payment import ReceivePaymentItem as SettleSchema from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session @@ -9,6 +8,7 @@ from ...core.security import get_current_active_user as get_user from ...db.session import SessionLocal from ...models import Overview, SettleOption, Voucher, VoucherType from ...schemas.auth import UserToken +from ...schemas.receive_payment import ReceivePaymentItem as SettleSchema from . import do_update_settlements @@ -25,7 +25,7 @@ def get_db(): @router.post("/void-bill/{id_}") -def update( +def void( id_: uuid.UUID, u: bool, # Update table? reason: str, @@ -34,11 +34,9 @@ def update( ): try: item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first() - - item.void = True item.reason = reason + item.bill_id = None item.voucher_type = VoucherType.VOID - do_update_settlements( item, [SettleSchema(id=SettleOption.VOID(), amount=round(item.amount))], db ) diff --git a/barker/barker/routes.py b/barker/barker/routes.py deleted file mode 100644 index 0d48ab2..0000000 --- a/barker/barker/routes.py +++ /dev/null @@ -1,472 +0,0 @@ -def includeme(config): - config.add_route("home", "/") - config.add_route("login", "/login") - config.add_route("v1_login", "/v1/login") - config.add_route("logout", "/logout") - config.add_route("v1_auth", "/v1/auth") - - config.add_route("v1_devices_new", "/v1/devices/new") - config.add_route("v1_devices_id", "/v1/devices/{id}") - config.add_route("v1_devices_list", "/v1/devices") - config.add_route("devices_new", "/devices/new") - config.add_view( - "barker.views.home", - route_name="devices_new", - request_method="GET", - permission="Tables", - ) - config.add_route("devices_id", "/devices/{id}") - config.add_view( - "barker.views.home", - route_name="devices_id", - request_method="GET", - permission="Tables", - ) - config.add_route("devices_list", "/devices") - config.add_view( - "barker.views.home", - route_name="devices_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_guest_book_new", "/v1/guest-book/new") - config.add_route("v1_guest_book_id", "/v1/guest-book/{id}") - config.add_route("v1_guest_book_list", "/v1/guest-book") - config.add_route("guest_book_new", "/guest-book/new") - config.add_view( - "barker.views.home", - route_name="guest_book_new", - request_method="GET", - permission="Guest Book", - ) - config.add_route("guest_book_id", "/guest-book/{id}") - config.add_view( - "barker.views.home", - route_name="guest_book_id", - request_method="GET", - permission="Guest Book", - ) - config.add_route("guest_book_list", "/guest-book") - config.add_view( - "barker.views.home", - route_name="guest_book_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_menu_categories_new", "/v1/menu-categories/new") - config.add_route("v1_menu_categories_id", "/v1/menu-categories/{id}") - config.add_route("v1_menu_categories_list", "/v1/menu-categories") - config.add_route("menu_categories_new", "/menu-categories/new") - config.add_view( - "barker.views.home", - route_name="menu_categories_new", - request_method="GET", - permission="Products", - ) - config.add_route("menu_categories_id", "/menu-categories/{id}") - config.add_view( - "barker.views.home", - route_name="menu_categories_id", - request_method="GET", - permission="Products", - ) - config.add_route("menu_categories_list", "/menu-categories") - config.add_view( - "barker.views.home", - route_name="menu_categories_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_modifier_categories_new", "/v1/modifier-categories/new") - config.add_route("v1_modifier_categories_id", "/v1/modifier-categories/{id}") - config.add_route("v1_modifier_categories_list", "/v1/modifier-categories") - config.add_route("modifier_categories_new", "/modifier-categories/new") - config.add_view( - "barker.views.home", - route_name="modifier_categories_new", - request_method="GET", - permission="Products", - ) - config.add_route("modifier_categories_id", "/modifier-categories/{id}") - config.add_view( - "barker.views.home", - route_name="modifier_categories_id", - request_method="GET", - permission="Products", - ) - config.add_route("modifier_categories_list", "/modifier-categories") - config.add_view( - "barker.views.home", - route_name="modifier_categories_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_modifiers_new", "/v1/modifiers/new") - config.add_route("v1_modifiers_id", "/v1/modifiers/{id}") - config.add_route("v1_modifiers_list", "/v1/modifiers") - config.add_route("modifiers_new", "/modifiers/new") - config.add_view( - "barker.views.home", - route_name="modifiers_new", - request_method="GET", - permission="Products", - ) - config.add_route("modifiers_id", "/modifiers/{id}") - config.add_view( - "barker.views.home", - route_name="modifiers_id", - request_method="GET", - permission="Products", - ) - config.add_route("modifiers_list", "/modifiers") - config.add_view( - "barker.views.home", - route_name="modifiers_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_printers_new", "/v1/printers/new") - config.add_route("v1_printers_id", "/v1/printers/{id}") - config.add_route("v1_printers_list", "/v1/printers") - config.add_route("printers_new", "/printers/new") - config.add_view( - "barker.views.home", - route_name="printers_new", - request_method="GET", - permission="Printers", - ) - config.add_route("printers_id", "/printers/{id}") - config.add_view( - "barker.views.home", - route_name="printers_id", - request_method="GET", - permission="Printers", - ) - config.add_route("printers_list", "/printers") - config.add_view( - "barker.views.home", - route_name="printers_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_products_new", "/v1/products/new") - config.add_route("v1_products_id", "/v1/products/{id}") - config.add_route("v1_products_list", "/v1/products") - config.add_route("products_new", "/products/new") - config.add_view( - "barker.views.home", - route_name="products_new", - request_method="GET", - permission="Products", - ) - config.add_route("products_id", "/products/{id}") - config.add_view( - "barker.views.home", - route_name="products_id", - request_method="GET", - permission="Products", - ) - config.add_route("products_list", "/products") - config.add_view( - "barker.views.home", - route_name="products_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_roles_new", "/v1/roles/new") - config.add_route("v1_roles_id", "/v1/roles/{id}") - config.add_route("v1_roles_list", "/v1/roles") - config.add_route("roles_new", "/roles/new") - config.add_view( - "barker.views.home", - route_name="roles_new", - request_method="GET", - permission="Users", - ) - config.add_route("roles_id", "/roles/{id}") - config.add_view( - "barker.views.home", - route_name="roles_id", - request_method="GET", - permission="Users", - ) - config.add_route("roles_list", "/roles") - config.add_view( - "barker.views.home", - route_name="roles_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_sale_categories_new", "/v1/sale-categories/new") - config.add_route("v1_sale_categories_id", "/v1/sale-categories/{id}") - config.add_route("v1_sale_categories_list", "/v1/sale-categories") - config.add_route("sale_categories_new", "/sale-categories/new") - config.add_view( - "barker.views.home", - route_name="sale_categories_new", - request_method="GET", - permission="Products", - ) - config.add_route("sale_categories_id", "/sale-categories/{id}") - config.add_view( - "barker.views.home", - route_name="sale_categories_id", - request_method="GET", - permission="Products", - ) - config.add_route("sale_categories_list", "/sale-categories") - config.add_view( - "barker.views.home", - route_name="sale_categories_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_section_printers", "/v1/section-printers") - config.add_route("v1_section_printers_id", "/v1/section-printers/{section_id}") - config.add_route("section_printers_id", "/section-printers/{section_id}") - config.add_view( - "barker.views.home", - route_name="section_printers_id", - request_method="GET", - permission="Tables", - ) - config.add_route("section_printers", "/section-printers") - config.add_view( - "barker.views.home", - route_name="section_printers", - request_method="GET", - permission="Tables", - ) - - config.add_route("v1_sections_new", "/v1/sections/new") - config.add_route("v1_sections_id", "/v1/sections/{id}") - config.add_route("v1_sections_list", "/v1/sections") - config.add_route("sections_new", "/sections/new") - config.add_view( - "barker.views.home", - route_name="sections_new", - request_method="GET", - permission="Tables", - ) - config.add_route("sections_id", "/sections/{id}") - config.add_view( - "barker.views.home", - route_name="sections_id", - request_method="GET", - permission="Tables", - ) - config.add_route("sections_list", "/sections") - config.add_view( - "barker.views.home", - route_name="sections_list", - request_method="GET", - permission="Tables", - ) - - config.add_route("v1_tables_new", "/v1/tables/new") - config.add_route("v1_tables_id", "/v1/tables/{id}") - config.add_route("v1_tables_list", "/v1/tables") - config.add_route("tables_new", "/tables/new") - config.add_view( - "barker.views.home", - route_name="tables_new", - request_method="GET", - permission="Tables", - ) - config.add_route("tables_id", "/tables/{id}") - config.add_view( - "barker.views.home", - route_name="tables_id", - request_method="GET", - permission="Tables", - ) - config.add_route("tables_list", "/tables") - config.add_view( - "barker.views.home", - route_name="tables_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_taxes_new", "/v1/taxes/new") - config.add_route("v1_taxes_id", "/v1/taxes/{id}") - config.add_route("v1_taxes_list", "/v1/taxes") - config.add_route("taxes_new", "/taxes/new") - config.add_view( - "barker.views.home", - route_name="taxes_new", - request_method="GET", - permission="Taxes", - ) - config.add_route("taxes_id", "/taxes/{id}") - config.add_view( - "barker.views.home", - route_name="taxes_id", - request_method="GET", - permission="Taxes", - ) - config.add_route("taxes_list", "/taxes") - config.add_view( - "barker.views.home", - route_name="taxes_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_users_new", "/v1/users/new") - config.add_route("v1_users_id", "/v1/users/{id}") - config.add_route("v1_users_list", "/v1/users") - config.add_route("users_new", "/users/new") - config.add_view( - "barker.views.home", - route_name="users_new", - request_method="GET", - permission="Users", - ) - config.add_route("users_id", "/users/{id}") - config.add_view( - "barker.views.home", - route_name="users_id", - request_method="GET", - permission="Users", - ) - config.add_route("users_list", "/users") - config.add_view( - "barker.views.home", - route_name="users_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_vouchers_new", "/v1/vouchers/new") - config.add_route("v1_vouchers_id", "/v1/vouchers/{id}") - - config.add_route("sales", "/sales") - config.add_view( - "barker.views.home", - route_name="sales", - request_method="GET", - permission="Authenticated", - ) - config.add_route("sales_catch", "/sales/*rest") - config.add_view( - "barker.views.home", - route_name="sales_catch", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_move_table", "/v1/move-table") - config.add_route("v1_move_kot", "/v1/move-kot") - - config.add_route("v1_active_cashiers", "/v1/active-cashiers") - config.add_route("v1_cashier_report_id", "/v1/cashier-report/{id}") - config.add_route("cashier_report_id", "/cashier-report/{id}") - config.add_view( - "barker.views.home", - route_name="cashier_report_id", - request_method="GET", - permission="Cashier Checkout", - ) - config.add_route("v1_cashier_report", "/v1/cashier-report") - config.add_route("cashier_report", "/cashier-report") - config.add_view( - "barker.views.home", - route_name="cashier_report", - request_method="GET", - permission="Cashier Checkout", - ) - - config.add_route("v1_sale_report", "/v1/sale-report") - config.add_route("sale_report", "/sale-report") - config.add_view( - "barker.views.home", - route_name="sale_report", - request_method="GET", - permission="Sales Analysis", - ) - config.add_route("v1_tax_report", "/v1/tax-report") - config.add_route("tax_report", "/tax-report") - config.add_view( - "barker.views.home", - route_name="tax_report", - request_method="GET", - permission="Tax Analysis", - ) - - config.add_route("v1_product_sale_report", "/v1/product-sale-report") - config.add_route("product_sale_report", "/product-sale-report") - config.add_view( - "barker.views.home", - route_name="product_sale_report", - request_method="GET", - permission="Sales Detail", - ) - config.add_route("v1_bill_settlement_report", "/v1/bill-settlement-report") - config.add_route("bill_settlement_report", "/bill-settlement-report") - config.add_view( - "barker.views.home", - route_name="bill_settlement_report", - request_method="GET", - permission="Bill Details", - ) - - config.add_route("v1_beer_consumption_report", "/v1/beer-consumption-report") - config.add_route("beer_consumption_report", "/beer-consumption-report") - config.add_view( - "barker.views.home", - route_name="beer_consumption_report", - request_method="GET", - permission="Beer Consumption", - ) - - config.add_route("v1_discount_report", "/v1/discount-report") - config.add_route("discount_report", "/discount-report") - config.add_view( - "barker.views.home", - route_name="discount_report", - request_method="GET", - permission="Discount Report", - ) - - # config.add_route("v1_bills_new", "/v1/bills/new") - # config.add_route("v1_bills_id", "/v1/bills/{id}") - - config.add_route("v1_customers_new", "/v1/customers/new") - config.add_route("v1_customers_id", "/v1/customers/{id}") - config.add_route("v1_customers_list", "/v1/customers") - config.add_route("customers_new", "/customers/new") - config.add_view( - "barker.views.home", - route_name="customers_new", - request_method="GET", - permission="Customers", - ) - config.add_route("customers_id", "/customers/{id}") - config.add_view( - "barker.views.home", - route_name="customers_id", - request_method="GET", - permission="Customers", - ) - config.add_route("customers_list", "/customers") - config.add_view( - "barker.views.home", - route_name="customers_list", - request_method="GET", - permission="Authenticated", - ) - - config.add_route("v1_reprint", "/v1/reprint/{id}") - config.add_route("v1_settings_id", "/v1/settings/{id}") - - config.add_static_view("", "barker:static") diff --git a/barker/barker/schemas/auth.py b/barker/barker/schemas/auth.py index c8a024f..78fadae 100644 --- a/barker/barker/schemas/auth.py +++ b/barker/barker/schemas/auth.py @@ -3,9 +3,10 @@ import uuid from datetime import datetime from typing import List, Optional -from barker.schemas import to_camel from pydantic import BaseModel +from . import to_camel + class ClientIn(BaseModel): name: str diff --git a/barker/barker/schemas/customer.py b/barker/barker/schemas/customer.py index 2e1534f..7beb2d8 100644 --- a/barker/barker/schemas/customer.py +++ b/barker/barker/schemas/customer.py @@ -1,12 +1,11 @@ import uuid -from decimal import Decimal -from typing import List, Optional +from typing import Optional -from barker.schemas import to_camel -from barker.schemas.product import ProductLink from pydantic import BaseModel, Field +from . import to_camel + class CustomerIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/device.py b/barker/barker/schemas/device.py index db71773..3c266fb 100644 --- a/barker/barker/schemas/device.py +++ b/barker/barker/schemas/device.py @@ -2,10 +2,11 @@ import uuid from typing import Optional -from barker.schemas import to_camel -from barker.schemas.section import SectionLink from pydantic import BaseModel, Field +from . import to_camel +from .section import SectionLink + class DeviceIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/guest_book.py b/barker/barker/schemas/guest_book.py index eb7610a..a92be00 100644 --- a/barker/barker/schemas/guest_book.py +++ b/barker/barker/schemas/guest_book.py @@ -1,8 +1,9 @@ import uuid -from barker.schemas import to_camel -from barker.schemas.customer import CustomerIn -from pydantic import BaseModel, Field +from pydantic import Field + +from . import to_camel +from .customer import CustomerIn class GuestBookIn(CustomerIn): diff --git a/barker/barker/schemas/master.py b/barker/barker/schemas/master.py index 3233abb..e654dde 100644 --- a/barker/barker/schemas/master.py +++ b/barker/barker/schemas/master.py @@ -4,33 +4,26 @@ from datetime import date, datetime from decimal import Decimal from typing import Optional -from barker.schemas import to_camel -from barker.schemas.customer import Customer, CustomerIn # noqa: F401 -from barker.schemas.device import Device, DeviceIn, DeviceLink # noqa: F401 -from barker.schemas.guest_book import GuestBook, GuestBookIn # noqa: F401 -from barker.schemas.menu_category import ( # noqa: F401 - MenuCategory, - MenuCategoryIn, - MenuCategoryLink, -) -from barker.schemas.modifier import Modifier, ModifierIn, ModifierLink # noqa: F401 -from barker.schemas.modifier_category import ( # noqa: F401 +from pydantic import BaseModel, Field, validator + +from . import to_camel +from .customer import Customer, CustomerIn # noqa: F401 +from .device import Device, DeviceIn, DeviceLink # noqa: F401 +from .guest_book import GuestBook, GuestBookIn # noqa: F401 +from .menu_category import MenuCategory, MenuCategoryIn, MenuCategoryLink # noqa: F401 +from .modifier import Modifier, ModifierIn, ModifierLink # noqa: F401 +from .modifier_category import ( # noqa: F401 ModifierCategory, ModifierCategoryIn, ModifierCategoryLink, ) -from barker.schemas.printer import Printer, PrinterIn, PrinterLink # noqa: F401 -from barker.schemas.product import Product, ProductIn, ProductLink # noqa: F401 -from barker.schemas.sale_category import ( # noqa: F401 - SaleCategory, - SaleCategoryIn, - SaleCategoryLink, -) -from barker.schemas.section import Section, SectionIn, SectionLink # noqa: F401 -from barker.schemas.section_printer import SectionPrinter # noqa: F401 -from barker.schemas.table import Table, TableIn, TableLink # noqa: F401 -from barker.schemas.tax import Tax, TaxIn, TaxLink # noqa: F401 -from pydantic import BaseModel, Field, validator +from .printer import Printer, PrinterIn, PrinterLink # noqa: F401 +from .product import Product, ProductIn, ProductLink # noqa: F401 +from .sale_category import SaleCategory, SaleCategoryIn, SaleCategoryLink # noqa: F401 +from .section import Section, SectionIn, SectionLink # noqa: F401 +from .section_printer import SectionPrinter # noqa: F401 +from .table import Table, TableIn, TableLink # noqa: F401 +from .tax import Tax, TaxIn, TaxLink # noqa: F401 class AccountBase(BaseModel): diff --git a/barker/barker/schemas/menu_category.py b/barker/barker/schemas/menu_category.py index cf7b937..4a4809f 100644 --- a/barker/barker/schemas/menu_category.py +++ b/barker/barker/schemas/menu_category.py @@ -3,10 +3,11 @@ import uuid from decimal import Decimal from typing import List, Optional -from barker.schemas import to_camel -from barker.schemas.product import ProductLink from pydantic import BaseModel, Field +from . import to_camel +from .product import ProductLink + class MenuCategoryIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/merge_move.py b/barker/barker/schemas/merge_move.py index 3c65bf3..bcd00a9 100644 --- a/barker/barker/schemas/merge_move.py +++ b/barker/barker/schemas/merge_move.py @@ -1,8 +1,9 @@ import uuid -from barker.schemas import to_camel from pydantic import BaseModel +from . import to_camel + class MergeKot(BaseModel): voucher_id: uuid.UUID diff --git a/barker/barker/schemas/modifier.py b/barker/barker/schemas/modifier.py index 97a02db..0ad967e 100644 --- a/barker/barker/schemas/modifier.py +++ b/barker/barker/schemas/modifier.py @@ -3,10 +3,11 @@ import uuid from decimal import Decimal from typing import Optional -from barker.schemas import to_camel -from barker.schemas.modifier_category import ModifierCategoryLink from pydantic import BaseModel, Field +from . import to_camel +from .modifier_category import ModifierCategoryLink + class ModifierIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/modifier_category.py b/barker/barker/schemas/modifier_category.py index 077cda9..a61419b 100644 --- a/barker/barker/schemas/modifier_category.py +++ b/barker/barker/schemas/modifier_category.py @@ -2,10 +2,11 @@ import uuid from typing import List, Optional -from barker.schemas import to_camel -from barker.schemas.menu_category import MenuCategoryLink from pydantic import BaseModel, Field +from . import to_camel +from .menu_category import MenuCategoryLink + class ModifierCategoryIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/printer.py b/barker/barker/schemas/printer.py index 23d0e9e..4cabcab 100644 --- a/barker/barker/schemas/printer.py +++ b/barker/barker/schemas/printer.py @@ -2,9 +2,10 @@ import uuid from typing import Optional -from barker.schemas import to_camel from pydantic import BaseModel, Field +from . import to_camel + class PrinterIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/product.py b/barker/barker/schemas/product.py index aab383e..1d05283 100644 --- a/barker/barker/schemas/product.py +++ b/barker/barker/schemas/product.py @@ -3,10 +3,11 @@ import uuid from decimal import Decimal from typing import List, Optional -from barker.schemas import to_camel -from barker.schemas.sale_category import SaleCategoryLink from pydantic import BaseModel, Field +from . import to_camel +from .sale_category import SaleCategoryLink + class ProductLink(BaseModel): id_: uuid.UUID = Field(...) diff --git a/barker/barker/schemas/receive_payment.py b/barker/barker/schemas/receive_payment.py index 97317c4..bb2611a 100644 --- a/barker/barker/schemas/receive_payment.py +++ b/barker/barker/schemas/receive_payment.py @@ -1,15 +1,11 @@ import uuid from decimal import Decimal -from typing import List, Optional +from typing import List -from barker.schemas import to_camel -from barker.schemas.customer import CustomerLink -from barker.schemas.modifier import ModifierLink -from barker.schemas.product import ProductLink -from barker.schemas.table import TableLink -from barker.schemas.tax import TaxLink -from pydantic import BaseModel, Field +from pydantic import BaseModel + +from . import to_camel class ReceivePaymentItem(BaseModel): diff --git a/barker/barker/schemas/sale_category.py b/barker/barker/schemas/sale_category.py index 117798d..51fad52 100644 --- a/barker/barker/schemas/sale_category.py +++ b/barker/barker/schemas/sale_category.py @@ -1,9 +1,10 @@ import uuid -from barker.schemas import to_camel -from barker.schemas.tax import TaxLink from pydantic import BaseModel, Field +from . import to_camel +from .tax import TaxLink + class SaleCategoryIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/section.py b/barker/barker/schemas/section.py index 2bd1bf3..6f5cd5b 100644 --- a/barker/barker/schemas/section.py +++ b/barker/barker/schemas/section.py @@ -2,9 +2,10 @@ import uuid from typing import Optional -from barker.schemas import to_camel from pydantic import BaseModel, Field +from . import to_camel + class SectionIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/section_printer.py b/barker/barker/schemas/section_printer.py index cc4d49b..7d53465 100644 --- a/barker/barker/schemas/section_printer.py +++ b/barker/barker/schemas/section_printer.py @@ -2,9 +2,10 @@ import uuid from typing import Optional -from barker.schemas import to_camel from pydantic import BaseModel, Field +from . import to_camel + class MenuCategoryLink(BaseModel): id_: Optional[uuid.UUID] diff --git a/barker/barker/schemas/split.py b/barker/barker/schemas/split.py index ab38df3..cf9ed03 100644 --- a/barker/barker/schemas/split.py +++ b/barker/barker/schemas/split.py @@ -2,9 +2,10 @@ import uuid from typing import List -from barker.schemas import to_camel from pydantic import BaseModel +from . import to_camel + class Split(BaseModel): inventories: List[uuid.UUID] diff --git a/barker/barker/schemas/table.py b/barker/barker/schemas/table.py index ed55f1b..9614f7b 100644 --- a/barker/barker/schemas/table.py +++ b/barker/barker/schemas/table.py @@ -2,10 +2,11 @@ import uuid from typing import Optional -from barker.schemas import to_camel -from barker.schemas.section import SectionLink from pydantic import BaseModel, Field +from . import to_camel +from .section import SectionLink + class TableIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/tax.py b/barker/barker/schemas/tax.py index f0c41a3..b22c6a3 100644 --- a/barker/barker/schemas/tax.py +++ b/barker/barker/schemas/tax.py @@ -3,9 +3,10 @@ import uuid from decimal import Decimal from typing import Optional -from barker.schemas import to_camel from pydantic import BaseModel, Field +from . import to_camel + class TaxIn(BaseModel): name: str = Field(..., min_length=1) diff --git a/barker/barker/schemas/voucher.py b/barker/barker/schemas/voucher.py index 3caefae..5fd2a7f 100644 --- a/barker/barker/schemas/voucher.py +++ b/barker/barker/schemas/voucher.py @@ -3,19 +3,20 @@ import uuid from decimal import Decimal from typing import List, Optional -from barker.schemas import to_camel -from barker.schemas.customer import CustomerLink -from barker.schemas.modifier import ModifierLink -from barker.schemas.product import ProductLink -from barker.schemas.table import TableLink -from barker.schemas.tax import TaxLink -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, validator + +from . import to_camel +from .customer import CustomerLink +from .modifier import ModifierLink +from .product import ProductLink +from .table import TableLink +from .tax import TaxLink class Inventory(BaseModel): id_: Optional[uuid.UUID] product: ProductLink - quantity: Decimal = Field(ge=0, multiple_of=0.01) + quantity: Decimal = Field(multiple_of=0.01) price: Optional[Decimal] tax: Optional[TaxLink] tax_rate: Optional[Decimal] @@ -27,6 +28,15 @@ class Inventory(BaseModel): class Config: alias_generator = to_camel + @validator("amount", always=True) + def calculate_amount(cls, v, values): + is_happy_hour = values["is_happy_hour"] if "is_happy_hour" in values else False + price = values["price"] if "price" in values and not is_happy_hour else 0 + quantity = values["quantity"] if "quantity" in values else 0 + discount = values["discount"] if "discount" in values else 0 + tax_rate = values["tax_rate"] if "tax_rate" in values else 0 + return round(Decimal(price * quantity * (1 - discount) * (1 + tax_rate)), 2) + class Kot(BaseModel): id_: Optional[uuid.UUID] diff --git a/bookie/src/app/home/home.component.html b/bookie/src/app/home/home.component.html index fbb3b0a..5a7ab4d 100644 --- a/bookie/src/app/home/home.component.html +++ b/bookie/src/app/home/home.component.html @@ -199,5 +199,5 @@ diff --git a/bookie/src/app/sales/bill.service.ts b/bookie/src/app/sales/bill.service.ts index f3340e5..b6d1dd2 100644 --- a/bookie/src/app/sales/bill.service.ts +++ b/bookie/src/app/sales/bill.service.ts @@ -79,13 +79,27 @@ export class BillService { this.updateAmounts(); } - addProduct(product: Product): void { + minimum(productId: string, happyHour: boolean): number { + return this.data.reduce( + (a, c) => (c.productId === productId && c.isHappyHour === happyHour ? a + c.quantity : a), + 0, + ); + } + + addProduct(product: Product, quantity: number, discount: number): void { const old = this.data.find( (x) => !x.isKot && !x.id && x.productId === product.id && x.isHappyHour === product.hasHappyHour, ); + if (quantity < 0) { + const minimum = this.minimum(product.id, product.hasHappyHour) + quantity; + if (minimum + quantity < 0) { + this.toaster.show('Error', 'Total quantity cannot be negative!'); + return; + } + } if (old !== undefined) { - old.quantity += 1; + old.quantity += quantity; } else { const item = { isKot: false, @@ -94,8 +108,8 @@ export class BillService { isHappyHour: product.hasHappyHour, info: `${product.name} @ ${product.price} - ${0}%`, price: product.price, - quantity: 1, - discount: 0, + quantity, + discount, taxRate: product.tax.rate, tax: product.tax, modifiers: [], @@ -146,8 +160,8 @@ export class BillService { this.updateAmounts(); } - subtractOne(item: any): void { - if (item.quantity > 1) { + subtractOne(item: any, canEdit: boolean): void { + if (item.quantity > 1 || (canEdit && this.minimum(item.productId, item.isHappyHour) >= 1)) { item.quantity -= 1; this.dataObs.next(this.data); this.updateAmounts(); diff --git a/bookie/src/app/sales/bills/bills.component.html b/bookie/src/app/sales/bills/bills.component.html index 79051d4..5950a16 100644 --- a/bookie/src/app/sales/bills/bills.component.html +++ b/bookie/src/app/sales/bills/bills.component.html @@ -94,7 +94,7 @@