Ported:
Guest Book Save bill Update bill Show bill Fix: Tax details was sending the rate multiplied by 100 but not dividing it on save/update Feature: Updated the auth service to check local storage for the latest user token
This commit is contained in:
@ -3,6 +3,7 @@ from fastapi import FastAPI
|
|||||||
from starlette.middleware.sessions import SessionMiddleware
|
from starlette.middleware.sessions import SessionMiddleware
|
||||||
|
|
||||||
from .routers import (
|
from .routers import (
|
||||||
|
guest_book,
|
||||||
menu_category,
|
menu_category,
|
||||||
modifier,
|
modifier,
|
||||||
modifier_category,
|
modifier_category,
|
||||||
@ -25,6 +26,7 @@ from .routers.reports import (
|
|||||||
sale_report,
|
sale_report,
|
||||||
tax_report
|
tax_report
|
||||||
)
|
)
|
||||||
|
from .routers.voucher import show, save, update
|
||||||
|
|
||||||
from .db.base_class import Base
|
from .db.base_class import Base
|
||||||
from .core.config import settings
|
from .core.config import settings
|
||||||
@ -66,6 +68,11 @@ app.include_router(product_sale_report.router, prefix="/api/product-sale-report"
|
|||||||
app.include_router(sale_report.router, prefix="/api/sale-report", tags=["reports"])
|
app.include_router(sale_report.router, prefix="/api/sale-report", tags=["reports"])
|
||||||
app.include_router(tax_report.router, prefix="/api/tax-report", tags=["reports"])
|
app.include_router(tax_report.router, prefix="/api/tax-report", tags=["reports"])
|
||||||
|
|
||||||
|
app.include_router(guest_book.router, prefix="/api/guest-book", tags=["guest-book"])
|
||||||
|
app.include_router(show.router, prefix="/api/voucher", tags=["voucher"])
|
||||||
|
app.include_router(save.router, prefix="/api/voucher", tags=["voucher"])
|
||||||
|
app.include_router(update.router, prefix="/api/voucher", tags=["voucher"])
|
||||||
|
|
||||||
# app.include_router(issue_grid.router, prefix="/api/issue-grid", tags=["vouchers"])
|
# app.include_router(issue_grid.router, prefix="/api/issue-grid", tags=["vouchers"])
|
||||||
# app.include_router(batch.router, prefix="/api/batch", tags=["vouchers"])
|
# app.include_router(batch.router, prefix="/api/batch", tags=["vouchers"])
|
||||||
# app.include_router(journal.router, prefix="/api/journal", tags=["vouchers"])
|
# app.include_router(journal.router, prefix="/api/journal", tags=["vouchers"])
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from ..schemas.auth import UserToken
|
|||||||
import barker.schemas.master as schemas
|
import barker.schemas.master as schemas
|
||||||
from ..core.security import get_current_active_user as get_user
|
from ..core.security import get_current_active_user as get_user
|
||||||
from ..db.session import SessionLocal
|
from ..db.session import SessionLocal
|
||||||
from ..models.master import SaleCategory, Printer
|
from ..models.master import Printer
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ def delete(
|
|||||||
|
|
||||||
@router.get("")
|
@router.get("")
|
||||||
def show_blank(
|
def show_blank(
|
||||||
db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=[""]),
|
db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["printers"]),
|
||||||
):
|
):
|
||||||
return printer_info(None)
|
return printer_info(None)
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
from decimal import Decimal
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, status, Depends, Security
|
from fastapi import APIRouter, HTTPException, status, Depends, Security
|
||||||
@ -28,7 +29,7 @@ def save(
|
|||||||
data: schemas.TaxIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["taxes"]),
|
data: schemas.TaxIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["taxes"]),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
item = Tax(name=data.name, rate=data.rate)
|
item = Tax(name=data.name, rate=round(data.rate / Decimal(100), 4))
|
||||||
db.add(item)
|
db.add(item)
|
||||||
db.commit()
|
db.commit()
|
||||||
return tax_info(item)
|
return tax_info(item)
|
||||||
@ -56,7 +57,7 @@ def update(
|
|||||||
status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.",
|
status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.",
|
||||||
)
|
)
|
||||||
item.name = data.name
|
item.name = data.name
|
||||||
item.rate = data.rate
|
item.rate = round(data.rate / Decimal(100), 4)
|
||||||
db.commit()
|
db.commit()
|
||||||
return tax_info(item)
|
return tax_info(item)
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from fastapi import HTTPException
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from starlette import status
|
||||||
|
|
||||||
from barker.models import (
|
from barker.models import (
|
||||||
VoucherType,
|
VoucherType,
|
||||||
@ -18,14 +21,16 @@ def get_tax(tax, voucher_type):
|
|||||||
elif voucher_type in [VoucherType.KOT, VoucherType.REGULAR_BILL]:
|
elif voucher_type in [VoucherType.KOT, VoucherType.REGULAR_BILL]:
|
||||||
return tax
|
return tax
|
||||||
else:
|
else:
|
||||||
raise ValidationError("Unexpected Voucher Type")
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Unexpected Voucher Type",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_bill_id(voucher_type, dbsession):
|
def get_bill_id(voucher_type, db):
|
||||||
if voucher_type == VoucherType.KOT:
|
if voucher_type == VoucherType.KOT:
|
||||||
return None
|
return None
|
||||||
bill_id = (
|
bill_id = (
|
||||||
dbsession.query(func.coalesce(func.max(Voucher.bill_id), 0) + 1)
|
db.query(func.coalesce(func.max(Voucher.bill_id), 0) + 1)
|
||||||
.filter(Voucher.voucher_type == voucher_type.value)
|
.filter(Voucher.voucher_type == voucher_type.value)
|
||||||
.scalar()
|
.scalar()
|
||||||
)
|
)
|
||||||
@ -34,46 +39,55 @@ def get_bill_id(voucher_type, dbsession):
|
|||||||
return bill_id
|
return bill_id
|
||||||
|
|
||||||
|
|
||||||
def do_update_table(item, guest_book, dbsession):
|
def do_update_table(item, guest_book, db):
|
||||||
status = "running" if item.voucher_type == VoucherType.KOT else "printed"
|
status_ = "running" if item.voucher_type == VoucherType.KOT else "printed"
|
||||||
if item.status is None:
|
if item.status is None:
|
||||||
item.status = Overview(
|
item.status = Overview(
|
||||||
voucher_id=item.id,
|
voucher_id=item.id,
|
||||||
food_table_id=item.food_table_id,
|
food_table_id=item.food_table_id,
|
||||||
guest_book_id=guest_book.id if guest_book is not None else None,
|
guest_book_id=guest_book.id if guest_book is not None else None,
|
||||||
status=status,
|
status=status_,
|
||||||
)
|
)
|
||||||
dbsession.add(item.status)
|
db.add(item.status)
|
||||||
else:
|
else:
|
||||||
item.status.status = status
|
item.status.status = status_
|
||||||
|
|
||||||
|
|
||||||
def check_permissions(item, voucher_type, permissions):
|
def check_permissions(item, voucher_type, permissions):
|
||||||
if voucher_type == VoucherType.KOT and "Print Kot" not in permissions:
|
if voucher_type == VoucherType.KOT and "print-kot" not in permissions:
|
||||||
raise ValidationFailure("You are not allowed to print a kot")
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to print a kot",
|
||||||
if voucher_type != VoucherType.KOT and "Print Bill" not in permissions:
|
)
|
||||||
raise ValidationFailure("You are not allowed to print bill")
|
if voucher_type != VoucherType.KOT and "print-bill" not in permissions:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to print bill",
|
||||||
|
)
|
||||||
|
|
||||||
if item is None:
|
if item is None:
|
||||||
return
|
return
|
||||||
if item.voucher_type != VoucherType.KOT and "Edit Printed Bill" not in permissions:
|
if item.voucher_type != VoucherType.KOT and "Edit Printed Bill" not in permissions:
|
||||||
raise ValidationFailure("You are not allowed to edit a printed bill")
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to edit a printed bill",
|
||||||
|
)
|
||||||
|
|
||||||
if item.voucher_type != VoucherType.KOT and voucher_type == VoucherType.KOT:
|
if item.voucher_type != VoucherType.KOT and voucher_type == VoucherType.KOT:
|
||||||
raise ValidationFailure("This Bill is already printed\nCannot add a Kot to it.")
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN, detail="This Bill is already printed\nCannot add a Kot to it.",
|
||||||
|
)
|
||||||
|
|
||||||
if item.voucher_type == VoucherType.VOID:
|
if item.voucher_type == VoucherType.VOID:
|
||||||
raise ValidationFailure("This Bill is already void.\nReason: {0}".format(item.reason))
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN, detail=f"This Bill is already void.\nReason: {item.reason}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_guest_book(guest_book_id, dbsession):
|
def get_guest_book(id_: uuid.UUID, db: Session):
|
||||||
if guest_book_id is None:
|
if id_ is None:
|
||||||
return guest_book_id
|
return id_
|
||||||
return dbsession.query(GuestBook).filter(GuestBook.id == uuid.UUID(guest_book_id)).first()
|
return db.query(GuestBook).filter(GuestBook.id == id_).first()
|
||||||
|
|
||||||
|
|
||||||
def do_update_settlements(voucher, dbsession):
|
def do_update_settlements(voucher, db: Session):
|
||||||
settlements = []
|
settlements = []
|
||||||
total_amount = voucher.amount
|
total_amount = voucher.amount
|
||||||
settlements.append({"id": SettleOption.AMOUNT(), "amount": -total_amount})
|
settlements.append({"id": SettleOption.AMOUNT(), "amount": -total_amount})
|
||||||
@ -91,8 +105,8 @@ def do_update_settlements(voucher, dbsession):
|
|||||||
else:
|
else:
|
||||||
s = Settlement(voucher.id, settlement_type_id, amount)
|
s = Settlement(voucher.id, settlement_type_id, amount)
|
||||||
voucher.settlements.append(s)
|
voucher.settlements.append(s)
|
||||||
dbsession.add(s)
|
db.add(s)
|
||||||
|
|
||||||
for i in (i for i in voucher.settlements if i.settled not in [x["id"] for x in settlements]):
|
for i in (i for i in voucher.settlements if i.settled not in [x["id"] for x in settlements]):
|
||||||
voucher.settlements.remove(i)
|
voucher.settlements.remove(i)
|
||||||
dbsession.delete(i)
|
db.delete(i)
|
||||||
|
|||||||
@ -1,22 +1,19 @@
|
|||||||
import datetime
|
|
||||||
import uuid
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import transaction
|
from fastapi import APIRouter, HTTPException, status, Depends, Security
|
||||||
from pyramid.view import view_config
|
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from barker.models import (
|
from ...schemas.auth import UserToken
|
||||||
Voucher,
|
import barker.schemas.voucher as schemas
|
||||||
Kot,
|
from ...core.security import get_current_active_user as get_user
|
||||||
Inventory,
|
from ...db.session import SessionLocal
|
||||||
InventoryModifier,
|
from ...models import Voucher, VoucherType, Kot, Product, Inventory, InventoryModifier
|
||||||
VoucherType,
|
from ...routers.voucher import (
|
||||||
Product,
|
|
||||||
FoodTable,
|
|
||||||
)
|
|
||||||
from barker.models.validation_exception import ValidationError
|
|
||||||
from barker.views.voucher import (
|
|
||||||
get_tax,
|
get_tax,
|
||||||
do_update_settlements,
|
do_update_settlements,
|
||||||
get_bill_id,
|
get_bill_id,
|
||||||
@ -25,61 +22,88 @@ from barker.views.voucher import (
|
|||||||
get_guest_book,
|
get_guest_book,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
@view_config(request_method="POST", route_name="v1_vouchers_new", renderer="json", trans=True)
|
|
||||||
def save(request):
|
|
||||||
json = request.json_body
|
|
||||||
now = datetime.datetime.now()
|
|
||||||
update_table = request.GET["u"] == "true"
|
|
||||||
voucher_type = VoucherType[request.GET["p"]]
|
|
||||||
guest_book = get_guest_book(request.GET.get("g", None), request.dbsession)
|
|
||||||
|
|
||||||
check_permissions(None, voucher_type, request.effective_principals)
|
# Dependency
|
||||||
|
def get_db():
|
||||||
|
try:
|
||||||
|
db = SessionLocal()
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
bill_id = get_bill_id(voucher_type, request.dbsession)
|
|
||||||
kot_id = request.dbsession.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar()
|
|
||||||
|
|
||||||
item = Voucher(
|
@router.post("/save")
|
||||||
now,
|
def save(
|
||||||
guest_book.pax if guest_book is not None else json["pax"],
|
data: schemas.VoucherIn,
|
||||||
bill_id,
|
u: bool, # Update table?
|
||||||
kot_id,
|
p: str, # Print type
|
||||||
json["table"]["id"],
|
g: Optional[uuid.UUID] = None, # Guest book id
|
||||||
json["customer"]["id"] if "id" in json["customer"] else None,
|
db: Session = Depends(get_db),
|
||||||
voucher_type,
|
user: UserToken = Security(get_user),
|
||||||
uuid.UUID(request.authenticated_userid),
|
):
|
||||||
)
|
try:
|
||||||
request.dbsession.add(item)
|
now = datetime.now()
|
||||||
for k in json["kots"]:
|
update_table = u
|
||||||
code = request.dbsession.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
voucher_type = VoucherType[p]
|
||||||
kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
|
guest_book = get_guest_book(g, db)
|
||||||
item.kots.append(kot)
|
|
||||||
request.dbsession.add(kot)
|
check_permissions(None, voucher_type, user.permissions)
|
||||||
for index, i in enumerate(k["inventories"]):
|
|
||||||
product = request.dbsession.query(Product).filter(Product.id == uuid.UUID(i["product"]["id"])).first()
|
bill_id = get_bill_id(voucher_type, db)
|
||||||
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
|
kot_id = db.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar()
|
||||||
inv = Inventory(
|
|
||||||
kot.id,
|
item = Voucher(
|
||||||
product.id,
|
now,
|
||||||
round(Decimal(i["quantity"]), 2),
|
guest_book.pax if guest_book is not None else data.pax,
|
||||||
product.price,
|
bill_id,
|
||||||
round(Decimal(i["discount"]), 5),
|
kot_id,
|
||||||
i["isHappyHour"],
|
data.table.id_,
|
||||||
product.sale_category.tax_id,
|
data.customer.id_ if data.customer is not None else None,
|
||||||
tax_rate,
|
voucher_type,
|
||||||
index,
|
user.id_,
|
||||||
|
)
|
||||||
|
db.add(item)
|
||||||
|
for k in data.kots:
|
||||||
|
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
||||||
|
kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
|
||||||
|
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()
|
||||||
|
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
|
||||||
|
inv = Inventory(
|
||||||
|
kot.id,
|
||||||
|
product.id,
|
||||||
|
round(i.quantity, 2),
|
||||||
|
product.price,
|
||||||
|
round(i.discount, 5),
|
||||||
|
i.is_happy_hour,
|
||||||
|
product.sale_category.tax_id,
|
||||||
|
tax_rate,
|
||||||
|
index,
|
||||||
|
)
|
||||||
|
kot.inventories.append(inv)
|
||||||
|
db.add(inv)
|
||||||
|
for m in i.modifiers:
|
||||||
|
mod = InventoryModifier(None, m.id_, 0)
|
||||||
|
inv.modifiers.append(mod)
|
||||||
|
db.add(mod)
|
||||||
|
do_update_settlements(item, db)
|
||||||
|
if len(item.kots) == 0 or len(item.kots[0].inventories) == 0:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Please add some products",
|
||||||
)
|
)
|
||||||
kot.inventories.append(inv)
|
|
||||||
request.dbsession.add(inv)
|
|
||||||
for m in i["modifiers"]:
|
|
||||||
mod = InventoryModifier(None, uuid.UUID(m["id"]), 0)
|
|
||||||
inv.modifiers.append(mod)
|
|
||||||
request.dbsession.add(mod)
|
|
||||||
do_update_settlements(item, request.dbsession)
|
|
||||||
if len(item.kots) == 0 or len(item.kots[0].inventories) == 0:
|
|
||||||
raise ValidationError("Please add some products!")
|
|
||||||
|
|
||||||
if update_table:
|
if update_table:
|
||||||
do_update_table(item, guest_book, request.dbsession)
|
do_update_table(item, guest_book, db)
|
||||||
transaction.commit()
|
db.commit()
|
||||||
return True
|
except SQLAlchemyError as e:
|
||||||
|
db.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
db.rollback()
|
||||||
|
raise
|
||||||
|
|||||||
@ -1,65 +1,77 @@
|
|||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from pyramid.view import view_config
|
from fastapi import APIRouter, HTTPException, status, Depends, Security
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from barker.exceptions import ValidationFailure
|
from ...schemas.auth import UserToken
|
||||||
from barker.models import Voucher, Overview, FoodTable, GuestBook, VoucherType
|
from ...core.security import get_current_active_user as get_user
|
||||||
|
from ...db.session import SessionLocal
|
||||||
|
from ...models import Voucher, Overview, FoodTable, GuestBook, VoucherType
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@view_config(
|
# Dependency
|
||||||
request_method="GET", route_name="v1_vouchers_id", renderer="json", permission="Authenticated",
|
def get_db():
|
||||||
)
|
try:
|
||||||
def show_id(request):
|
db = SessionLocal()
|
||||||
id_ = uuid.UUID(request.matchdict["id"])
|
yield db
|
||||||
item = request.dbsession.query(Voucher).filter(Voucher.id == id_).first()
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/from-id/{id_}")
|
||||||
|
def from_id(
|
||||||
|
id_: str, db: Session = Depends(get_db), user: UserToken = Security(get_user),
|
||||||
|
):
|
||||||
|
item = db.query(Voucher).filter(Voucher.id == id_).first()
|
||||||
return voucher_info(item)
|
return voucher_info(item)
|
||||||
|
|
||||||
|
|
||||||
@view_config(
|
@router.get("/from-bill/{id_}")
|
||||||
request_method="GET", route_name="v1_vouchers_new", request_param="b", renderer="json", permission="Authenticated",
|
def from_bill(
|
||||||
)
|
id_: str, db: Session = Depends(get_db), user: UserToken = Security(get_user),
|
||||||
def show(request):
|
):
|
||||||
bill_id = request.GET["b"]
|
item: Voucher = db.query(Voucher)
|
||||||
item = request.dbsession.query(Voucher)
|
if re.compile(r"^\d{2,}-\d{4}$").match(id_):
|
||||||
if re.compile("^\d{2,}-\d{4}$").match(bill_id):
|
item = item.filter(Voucher.bill_id == int(id_.replace("-", "")), Voucher.voucher_type.in_([1, 3]),)
|
||||||
item = item.filter(Voucher.bill_id == int(bill_id.replace("-", "")), Voucher.voucher_type.in_([1, 3]),)
|
elif re.compile(r"^NC-\d+$").match(id_):
|
||||||
elif re.compile("^NC-\d+$").match(bill_id):
|
item = item.filter(Voucher.bill_id == int(id_.replace("NC-", "")), Voucher.voucher_type == 2,)
|
||||||
item = item.filter(Voucher.bill_id == int(bill_id.replace("NC-", "")), Voucher.voucher_type == 2,)
|
elif re.compile(r"^ST-\d+$").match(id_):
|
||||||
elif re.compile("^ST-\d+$").match(bill_id):
|
item = item.filter(Voucher.bill_id == int(id_.replace("ST-", "")), Voucher.voucher_type == 4,)
|
||||||
item = item.filter(Voucher.bill_id == int(bill_id.replace("ST-", "")), Voucher.voucher_type == 4,)
|
|
||||||
item = item.first()
|
item = item.first()
|
||||||
if item is None:
|
if item is None:
|
||||||
return {}
|
return {}
|
||||||
return voucher_info(item)
|
return voucher_info(item)
|
||||||
|
|
||||||
|
|
||||||
@view_config(
|
@router.get("/from-table/{id_}")
|
||||||
request_method="GET", route_name="v1_vouchers_new", request_param="t", renderer="json", permission="Authenticated",
|
def from_bill(
|
||||||
)
|
id_: str, # Table ID
|
||||||
def show_for_table(request):
|
v: Optional[uuid.UUID] = None, # Voucher ID
|
||||||
table_id = uuid.UUID(request.GET["t"])
|
g: Optional[uuid.UUID] = None, # Guest ID
|
||||||
voucher_id = request.GET.get("v", None)
|
db: Session = Depends(get_db),
|
||||||
guest_id = request.GET.get("g", None)
|
user: UserToken = Security(get_user),
|
||||||
if voucher_id is not None:
|
):
|
||||||
item = (
|
if v is not None:
|
||||||
request.dbsession.query(Overview)
|
item = db.query(Overview).filter(Overview.voucher_id == v, Overview.food_table_id == id_,).first()
|
||||||
.filter(Overview.voucher_id == uuid.UUID(voucher_id), Overview.food_table_id == table_id,)
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
if item is None:
|
if item is None:
|
||||||
raise ValidationFailure("Bill Not Found")
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND, detail="Voucher not found",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return voucher_info(item.voucher)
|
return voucher_info(item.voucher)
|
||||||
table = request.dbsession.query(FoodTable).filter(FoodTable.id == table_id).first()
|
table = db.query(FoodTable).filter(FoodTable.id == id_).first()
|
||||||
if guest_id is not None:
|
if g is not None:
|
||||||
guest = request.dbsession.query(GuestBook).filter(GuestBook.id == guest_id).first()
|
guest = db.query(GuestBook).filter(GuestBook.id == g).first()
|
||||||
else:
|
else:
|
||||||
guest = None
|
guest = None
|
||||||
return voucher_blank(table, guest)
|
return voucher_blank(table, guest)
|
||||||
|
|
||||||
|
|
||||||
def voucher_info(item):
|
def voucher_info(item: Voucher):
|
||||||
return {
|
return {
|
||||||
"id": item.id,
|
"id": item.id,
|
||||||
"date": item.date.strftime("%H:%M"),
|
"date": item.date.strftime("%H:%M"),
|
||||||
|
|||||||
@ -1,20 +1,19 @@
|
|||||||
import datetime
|
|
||||||
import uuid
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import transaction
|
from fastapi import APIRouter, HTTPException, status, Depends, Security
|
||||||
from pyramid.view import view_config
|
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from barker.models import (
|
from ...schemas.auth import UserToken
|
||||||
Voucher,
|
import barker.schemas.voucher as schemas
|
||||||
Kot,
|
from ...core.security import get_current_active_user as get_user
|
||||||
Inventory,
|
from ...db.session import SessionLocal
|
||||||
InventoryModifier,
|
from ...models import Voucher, VoucherType, Kot, Product, Inventory, InventoryModifier
|
||||||
VoucherType,
|
from ...routers.voucher import (
|
||||||
Product,
|
|
||||||
)
|
|
||||||
from barker.views.voucher import (
|
|
||||||
get_tax,
|
get_tax,
|
||||||
do_update_settlements,
|
do_update_settlements,
|
||||||
get_bill_id,
|
get_bill_id,
|
||||||
@ -23,65 +22,89 @@ from barker.views.voucher import (
|
|||||||
get_guest_book,
|
get_guest_book,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
@view_config(request_method="PUT", route_name="v1_vouchers_id", renderer="json", trans=True)
|
|
||||||
def update(request):
|
|
||||||
json = request.json_body
|
|
||||||
now = datetime.datetime.now()
|
|
||||||
update_table = request.GET["u"] == "true"
|
|
||||||
voucher_type = VoucherType[request.GET["p"]]
|
|
||||||
guest_book = get_guest_book(request.GET.get("g", None), request.dbsession)
|
|
||||||
item = request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(request.matchdict["id"])).first()
|
|
||||||
|
|
||||||
check_permissions(item, voucher_type, request.effective_principals)
|
# Dependency
|
||||||
|
def get_db():
|
||||||
|
try:
|
||||||
|
db = SessionLocal()
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
if guest_book is not None:
|
|
||||||
item.pax = guest_book.pax
|
@router.put("/update/{id_}")
|
||||||
item.food_table_id = json["table"]["id"]
|
def update(
|
||||||
if "customer" in json and "id" in json["customer"]:
|
id_: uuid.UUID,
|
||||||
item.customer_id = json["customer"]["id"]
|
data: schemas.VoucherIn,
|
||||||
if item.voucher_type == VoucherType.KOT and voucher_type != VoucherType.KOT:
|
u: bool, # Update table?
|
||||||
item.date = now
|
p: str, # Print type
|
||||||
item.bill_id = get_bill_id(voucher_type, request.dbsession)
|
g: Optional[uuid.UUID] = None, # Guest book id
|
||||||
item.voucher_type = voucher_type
|
db: Session = Depends(get_db),
|
||||||
item.user_id = uuid.UUID(request.authenticated_userid)
|
user: UserToken = Security(get_user),
|
||||||
item.last_edit_date = now
|
):
|
||||||
for k in item.kots:
|
try:
|
||||||
for i in k.inventories:
|
now = datetime.now()
|
||||||
i.tax_rate = get_tax(i.tax_rate, voucher_type)
|
update_table = u
|
||||||
i.discount = next(
|
voucher_type = VoucherType[p]
|
||||||
round(Decimal(inv["discount"]), 5)
|
guest_book = get_guest_book(g, db)
|
||||||
for ko in json["kots"]
|
|
||||||
for inv in ko["inventories"]
|
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
|
||||||
if uuid.UUID(inv["id"]) == i.id
|
|
||||||
)
|
check_permissions(item, voucher_type, user.permissions)
|
||||||
for k in (k for k in json["kots"] if "id" not in k and len(k["inventories"]) > 0):
|
|
||||||
code = request.dbsession.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
if guest_book is not None:
|
||||||
kot = Kot(item.id, code, item.food_table_id, now, item.user_id)
|
item.pax = guest_book.pax
|
||||||
item.kots.append(kot)
|
item.food_table_id = data.table.id_
|
||||||
request.dbsession.add(kot)
|
if data.customer is not None:
|
||||||
for index, i in enumerate(k["inventories"]):
|
item.customer_id = data.customer.id_
|
||||||
product = request.dbsession.query(Product).filter(Product.id == uuid.UUID(i["product"]["id"])).first()
|
if item.voucher_type == VoucherType.KOT and voucher_type != VoucherType.KOT:
|
||||||
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
|
item.date = now
|
||||||
inv = Inventory(
|
item.bill_id = get_bill_id(voucher_type, db)
|
||||||
kot.id,
|
item.voucher_type = voucher_type
|
||||||
product.id,
|
item.user_id = user.id_
|
||||||
round(Decimal(i["quantity"]), 2),
|
item.last_edit_date = now
|
||||||
product.price,
|
for k in item.kots:
|
||||||
round(Decimal(i["discount"]), 5),
|
for i in k.inventories:
|
||||||
i["isHappyHour"],
|
i.tax_rate = get_tax(i.tax_rate, voucher_type)
|
||||||
product.sale_category.tax_id,
|
i.discount = next(
|
||||||
tax_rate,
|
round(inv.discount, 5) for ko in data.kots for inv in ko.inventories if inv.id_ == i.id
|
||||||
index,
|
)
|
||||||
)
|
for k in (k for k in data.kots if k.id_ is None and len(k.inventories) > 0):
|
||||||
kot.inventories.append(inv)
|
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
||||||
request.dbsession.add(inv)
|
kot = Kot(item.id, code, item.food_table_id, now, item.user_id)
|
||||||
for m in i["modifiers"]:
|
item.kots.append(kot)
|
||||||
mod = InventoryModifier(None, uuid.UUID(m["id"]), 0)
|
db.add(kot)
|
||||||
inv.modifiers.append(mod)
|
for index, i in enumerate(k.inventories):
|
||||||
request.dbsession.add(mod)
|
product = db.query(Product).filter(Product.id == i.product.id_).first()
|
||||||
do_update_settlements(item, request.dbsession)
|
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
|
||||||
if update_table:
|
inv = Inventory(
|
||||||
do_update_table(item, guest_book, request.dbsession)
|
kot.id,
|
||||||
transaction.commit()
|
product.id,
|
||||||
return True
|
round(i.quantity, 2),
|
||||||
|
product.price,
|
||||||
|
round(i.discount, 5),
|
||||||
|
i.is_happy_hour,
|
||||||
|
product.sale_category.tax_id,
|
||||||
|
tax_rate,
|
||||||
|
index,
|
||||||
|
)
|
||||||
|
kot.inventories.append(inv)
|
||||||
|
db.add(inv)
|
||||||
|
for m in i.modifiers:
|
||||||
|
mod = InventoryModifier(None, m.id_, 0)
|
||||||
|
inv.modifiers.append(mod)
|
||||||
|
db.add(mod)
|
||||||
|
do_update_settlements(item, db)
|
||||||
|
if update_table:
|
||||||
|
do_update_table(item, guest_book, db)
|
||||||
|
db.commit()
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
db.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
db.rollback()
|
||||||
|
raise
|
||||||
|
|||||||
@ -27,3 +27,12 @@ class Customer(CustomerIn):
|
|||||||
fields = {"id_": "id"}
|
fields = {"id_": "id"}
|
||||||
anystr_strip_whitespace = True
|
anystr_strip_whitespace = True
|
||||||
alias_generator = to_camel
|
alias_generator = to_camel
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerLink(BaseModel):
|
||||||
|
id_: uuid.UUID = Field(...)
|
||||||
|
name: Optional[str]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
fields = {"id_": "id"}
|
||||||
|
alias_generator = to_camel
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from barker.schemas import to_camel
|
|||||||
|
|
||||||
class TaxIn(BaseModel):
|
class TaxIn(BaseModel):
|
||||||
name: str = Field(..., min_length=1)
|
name: str = Field(..., min_length=1)
|
||||||
rate: Decimal = Field(ge=0, multiple_of=0.0001, default=0, le=1)
|
rate: Decimal = Field(ge=0, multiple_of=0.01, default=0)
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
fields = {"id_": "id"}
|
fields = {"id_": "id"}
|
||||||
|
|||||||
58
barker/schemas/voucher.py
Normal file
58
barker/schemas/voucher.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import uuid
|
||||||
|
from typing import Optional, List
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
class Inventory(BaseModel):
|
||||||
|
id_: Optional[uuid.UUID]
|
||||||
|
product: ProductLink
|
||||||
|
quantity: Decimal = Field(ge=0, multiple_of=0.01)
|
||||||
|
rate: Optional[Decimal]
|
||||||
|
tax: Optional[TaxLink]
|
||||||
|
taxRate: Optional[Decimal]
|
||||||
|
discount: Decimal = Field(ge=0, multiple_of=0.00001, le=1)
|
||||||
|
is_happy_hour: bool
|
||||||
|
modifiers: Optional[List[ModifierLink]]
|
||||||
|
amount: Optional[Decimal]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
alias_generator = to_camel
|
||||||
|
|
||||||
|
|
||||||
|
class Kot(BaseModel):
|
||||||
|
id_: Optional[uuid.UUID]
|
||||||
|
inventories: List[Inventory]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
anystr_strip_whitespace = True
|
||||||
|
alias_generator = to_camel
|
||||||
|
|
||||||
|
|
||||||
|
class VoucherIn(BaseModel):
|
||||||
|
pax: int
|
||||||
|
table: TableLink
|
||||||
|
customer: Optional[CustomerLink]
|
||||||
|
kots: List[Kot]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
fields = {"id_": "id"}
|
||||||
|
anystr_strip_whitespace = True
|
||||||
|
alias_generator = to_camel
|
||||||
|
|
||||||
|
|
||||||
|
class Voucher(VoucherIn):
|
||||||
|
id_: uuid.UUID
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
fields = {"id_": "id"}
|
||||||
|
anystr_strip_whitespace = True
|
||||||
|
alias_generator = to_camel
|
||||||
@ -16,22 +16,39 @@ export class AuthService {
|
|||||||
public currentUser: Observable<User>;
|
public currentUser: Observable<User>;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem(JWT_USER)));
|
this.checkStorage();
|
||||||
this.currentUser = this.currentUserSubject.asObservable();
|
this.currentUser = this.currentUserSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkStorage(): User {
|
||||||
|
const existingToken: User = JSON.parse(localStorage.getItem(JWT_USER));
|
||||||
|
if (existingToken === null || Date.now() > existingToken.exp * 1000) {
|
||||||
|
localStorage.removeItem(JWT_USER);
|
||||||
|
this.currentUserSubject = new BehaviorSubject<User>(null);
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
this.currentUserSubject = new BehaviorSubject<User>(existingToken);
|
||||||
|
return existingToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public get user(): User {
|
public get user(): User {
|
||||||
const val = this.currentUserSubject.value;
|
let val = this.currentUserSubject.value;
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
const expired = Date.now() > val.exp * 1000;
|
let expired = Date.now() > val.exp * 1000;
|
||||||
|
if (expired) {
|
||||||
|
val = this.checkStorage();
|
||||||
|
}
|
||||||
|
if (val == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
expired = Date.now() > val.exp * 1000;
|
||||||
if (expired) {
|
if (expired) {
|
||||||
this.logout();
|
this.logout();
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return this.currentUserSubject.value;
|
|
||||||
}
|
}
|
||||||
|
return this.currentUserSubject.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
login(username: string, password: string, otp: string) {
|
login(username: string, password: string, otp: string) {
|
||||||
@ -73,10 +90,6 @@ export class AuthService {
|
|||||||
return Date.now() > (this.user.exp - (environment.ACCESS_TOKEN_REFRESH_MINUTES * 60)) * 1000;
|
return Date.now() > (this.user.exp - (environment.ACCESS_TOKEN_REFRESH_MINUTES * 60)) * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
expired(): boolean {
|
|
||||||
return Date.now() > this.user.exp * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
// remove user from local storage to log user out
|
// remove user from local storage to log user out
|
||||||
localStorage.removeItem(JWT_USER);
|
localStorage.removeItem(JWT_USER);
|
||||||
|
|||||||
@ -10,9 +10,9 @@ const httpOptions = {
|
|||||||
headers: new HttpHeaders({'Content-Type': 'application/json'})
|
headers: new HttpHeaders({'Content-Type': 'application/json'})
|
||||||
};
|
};
|
||||||
|
|
||||||
const url = '/v1/vouchers';
|
const url = '/api/voucher';
|
||||||
const urlMoveTable = '/v1/move-table';
|
const urlMoveTable = '/api/move-table';
|
||||||
const urlMoveKot = '/v1/move-kot';
|
const urlMoveKot = '/api/move-kot';
|
||||||
const serviceName = 'VoucherService';
|
const serviceName = 'VoucherService';
|
||||||
|
|
||||||
@Injectable({providedIn: 'root'})
|
@Injectable({providedIn: 'root'})
|
||||||
@ -22,7 +22,7 @@ export class VoucherService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get(id: string): Observable<Bill> {
|
get(id: string): Observable<Bill> {
|
||||||
return <Observable<Bill>>this.http.get<Bill>(`${url}/${id}`)
|
return <Observable<Bill>>this.http.get<Bill>(`${url}/from-id/${id}`)
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError(this.log.handleError(serviceName, `get id=${id}`))
|
catchError(this.log.handleError(serviceName, `get id=${id}`))
|
||||||
);
|
);
|
||||||
@ -30,9 +30,6 @@ export class VoucherService {
|
|||||||
|
|
||||||
getFromTable(tableId: string, voucherId: string, guestId: string): Observable<Bill> {
|
getFromTable(tableId: string, voucherId: string, guestId: string): Observable<Bill> {
|
||||||
let params = new HttpParams();
|
let params = new HttpParams();
|
||||||
if (tableId !== null) {
|
|
||||||
params = params.set('t', tableId);
|
|
||||||
}
|
|
||||||
if (voucherId !== null) {
|
if (voucherId !== null) {
|
||||||
params = params.set('v', voucherId);
|
params = params.set('v', voucherId);
|
||||||
}
|
}
|
||||||
@ -40,7 +37,7 @@ export class VoucherService {
|
|||||||
params = params.set('g', guestId);
|
params = params.set('g', guestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Observable<Bill>>this.http.get<Bill>(`${url}/new`, {params: params})
|
return <Observable<Bill>>this.http.get<Bill>(`${url}/from-table/${tableId}`, {params: params})
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError(this.log.handleError(
|
catchError(this.log.handleError(
|
||||||
serviceName,
|
serviceName,
|
||||||
@ -54,7 +51,7 @@ export class VoucherService {
|
|||||||
if (guest_book_id !== null) {
|
if (guest_book_id !== null) {
|
||||||
options.params = options.params.set('g', guest_book_id);
|
options.params = options.params.set('g', guest_book_id);
|
||||||
}
|
}
|
||||||
return <Observable<boolean>>this.http.post<boolean>(`${url}/new`, voucher, options)
|
return <Observable<boolean>>this.http.post<boolean>(`${url}/save`, voucher, options)
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError(this.log.handleError(serviceName, 'save'))
|
catchError(this.log.handleError(serviceName, 'save'))
|
||||||
);
|
);
|
||||||
@ -65,7 +62,7 @@ export class VoucherService {
|
|||||||
if (guest_book_id !== null) {
|
if (guest_book_id !== null) {
|
||||||
options.params = options.params.set('g', guest_book_id);
|
options.params = options.params.set('g', guest_book_id);
|
||||||
}
|
}
|
||||||
return <Observable<boolean>>this.http.put<boolean>(`${url}/${voucher.id}`, voucher, options)
|
return <Observable<boolean>>this.http.put<boolean>(`${url}/update/${voucher.id}`, voucher, options)
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError(this.log.handleError(serviceName, 'update'))
|
catchError(this.log.handleError(serviceName, 'update'))
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user