Fix: import script to fit the new structure of voucher table (is_printed field removed, voucher_type != KOT is now assumed to be printed)

Fix: Take-away bill type is now removed
Fix: Table overview now shows the right amounts
Voucher Save and Update should now work
Discounts now working (permissions are not checked)
This commit is contained in:
Amritanshu
2019-08-08 13:31:30 +05:30
parent 7d06a2f961
commit c81b92c336
24 changed files with 534 additions and 249 deletions

View File

@ -1,5 +1,5 @@
from datetime import datetime
from enum import IntEnum
from enum import Enum
import uuid
from decimal import Decimal
@ -16,12 +16,12 @@ from sqlalchemy import (
func,
case,
)
from sqlalchemy.orm import relationship, backref
from sqlalchemy.orm import relationship, backref, synonym
from barker.models.guidtype import GUID
from .meta import Base
class VoucherType(IntEnum):
class VoucherType(Enum):
KOT = 0
REGULAR_BILL = 1
NO_CHARGE = 2
@ -49,9 +49,15 @@ class GuestBook(Base):
class Overview(Base):
__tablename__ = "overview"
id = Column("id", GUID(), primary_key=True, default=uuid.uuid4)
voucher_id = Column("voucher_id", GUID(), ForeignKey("vouchers.id"), unique=True)
voucher_id = Column(
"voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, unique=True
)
food_table_id = Column(
"food_table_id", GUID(), ForeignKey("food_tables.id"), unique=True
"food_table_id",
GUID(),
ForeignKey("food_tables.id"),
nullable=False,
unique=True,
)
guest_book_id = Column(
"guest_book_id", GUID(), ForeignKey("guest_book.id"), unique=True
@ -62,11 +68,12 @@ class Overview(Base):
food_table = relationship("FoodTable", backref=backref("status", uselist=False))
guest = relationship("GuestBook", backref=backref("status", uselist=False))
def __init__(self, voucher_id, food_table_id, guest_book_id, status):
def __init__(self, voucher_id, food_table_id, guest_book_id, status, id_=None):
self.voucher_id = voucher_id
self.food_table_id = food_table_id
self.guest_book_id = guest_book_id
self.status = status
self.id = id_
class InventoryModifier(Base):
@ -109,8 +116,7 @@ class Voucher(Base):
narration = Column("narration", Unicode(1000), nullable=False)
is_void = Column("is_void", Boolean, nullable=False)
void_reason = Column("void_reason", Unicode(255))
is_printed = Column("is_printed", Boolean, nullable=False)
voucher_type = Column("voucher_type", Integer, nullable=False)
_voucher_type = Column("voucher_type", Integer, nullable=False)
user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False)
user = relationship("User", backref="vouchers")
@ -136,61 +142,57 @@ class Voucher(Base):
cascade_backrefs=False,
)
@property
def __name__(self):
return self.name
def _get_voucher_type(self):
return VoucherType(self._voucher_type)
def _set_voucher_type(self, voucher_type):
self._voucher_type = voucher_type.value
voucher_type = property(_get_voucher_type, _set_voucher_type)
voucher_type = synonym("_voucher_type", descriptor=voucher_type)
def __init__(
self,
date,
pax,
bill_id,
kot_id,
food_table_id,
customer_id,
is_printed,
voucher_type,
user_id,
dbsession,
):
now = datetime.now()
self.date = now
self.date = date
self.pax = pax
if is_printed:
type = [1, 3] if voucher_type in [1, 3] else [voucher_type]
self.bill_id = (
dbsession.query(func.coalesce(func.max(Voucher.bill_id), 0) + 1)
.filter(Voucher.voucher_type.in_(type))
.scalar()
)
self.kot_id = dbsession.query(
func.coalesce(func.max(Voucher.kot_id), 0) + 1
).scalar()
self.creation_date = now
self.last_edit_date = now
self.creation_date = date
self.last_edit_date = date
self.bill_id = bill_id
self.kot_id = kot_id
self.food_table_id = food_table_id
self.customer_id = customer_id
self.narration = ""
self.is_void = False
self.void_reason = None
self.is_printed = is_printed
self.voucher_type = voucher_type
self.user_id = user_id
@property
def full_bill_id(self):
if self.bill_id is None:
if self.voucher_type == VoucherType.KOT:
return "K-" + str(self.kot_id)
if self.voucher_type == VoucherType.NO_CHARGE.value:
if self.voucher_type == VoucherType.NO_CHARGE:
return "NC-" + str(self.bill_id)
if self.voucher_type == VoucherType.STAFF.value:
if self.voucher_type == VoucherType.STAFF:
return "ST-" + str(self.bill_id)
if self.voucher_type in [
VoucherType.TAKE_AWAY.value,
VoucherType.REGULAR_BILL.value,
]:
if self.voucher_type == VoucherType.REGULAR_BILL:
return str(self.bill_id // 10000) + "-" + str(self.bill_id % 10000)
else:
raise Exception
@property
def amount(self):
return sum(i.amount for k in self.kots for i in k.inventories)
class Kot(Base):
__tablename__ = "kots"
@ -212,15 +214,15 @@ class Kot(Base):
def __init__(
self,
voucher_id=None,
code=None,
food_table_id=None,
date=None,
user_id=None,
id=None,
dbsession=None,
id_=None,
):
self.id = id
self.id = id_
self.voucher_id = voucher_id
self.code = dbsession.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
self.code = code
self.food_table_id = food_table_id
self.date = date
self.user_id = user_id
@ -310,7 +312,7 @@ class Inventory(Base):
@hybrid_property
def effective_price(self):
return 0 if self.is_happy_hour == True else self.price
return 0 if self.is_happy_hour else self.price
@effective_price.expression
def effective_price(cls):
@ -320,9 +322,17 @@ class Inventory(Base):
def net(self):
return self.effective_price * self.quantity * (1 - self.discount)
@net.expression
def net(cls):
return cls.effective_price * cls.quantity * (1 - cls.discount)
@hybrid_property
def tax_amount(self):
return self.net_taxable * self.tax_rate
return self.net * self.tax_rate
@tax_amount.expression
def tax_amount(cls):
return cls.net * cls.tax_rate
@hybrid_property
def amount(self):

View File

@ -104,7 +104,7 @@ def show_voucher(request):
.first()
)
if voucher is not None:
return food_table_info(voucher.food_table)
return food_table_info(voucher.food_table, request.dbsession)
return {}
@ -143,7 +143,7 @@ def show_running(request):
ft["voucherId"] = item.status.voucher_id
ft["pax"] = item.status.voucher.pax
ft["date"] = item.status.voucher.date.strftime("%d-%b-%Y %H:%M")
ft["amount"] = 12345
ft["amount"] = item.status.voucher.amount
if item.status.guest is not None:
ft["guest"] = item.status.guest.customer.name
food_tables.append(ft)

View File

@ -172,7 +172,8 @@ def sale_list(request):
"isNotAvailable": p.is_not_available,
"sortOrder": p.sort_order,
"quantity": p.quantity,
} for p in products
}
for p in products
]
menu_categories.append(pg)
return menu_categories

View File

@ -109,10 +109,23 @@ def show_list(request):
.order_by(SaleCategory.name)
.all()
)
sale_categories = []
for item in list_:
sale_categories.append(sale_category_info(item, request.dbsession))
return sale_categories
return [sale_category_info(item, request.dbsession) for item in list_]
@view_config(
request_method="GET",
route_name="v1_sale_categories_list",
renderer="json",
request_param="d",
permission="Authenticated",
)
def show_list_for_discount(request):
list_ = (
request.dbsession.query(SaleCategory)
.order_by(SaleCategory.name)
.all()
)
return [{"id": item.id, "name": item.name, "discount": 0} for item in list_]
def sale_category_info(item, dbsession):

View File

@ -1,34 +1,14 @@
# import re
# import uuid
# from datetime import datetime
# from decimal import Decimal
#
# import transaction
# from pyramid.httpexceptions import HTTPForbidden
# from pyramid.view import view_config
# from sqlalchemy import func
#
# from barker.exceptions import ValidationFailure
# from barker.models import (
# Inventory,
# InventoryModifier,
# Kot,
# Settlement,
# SettleOption,
# Voucher,
# Overview,
# VoucherType,
# )
from barker.models import VoucherType, Settlement, SettleOption
from barker.models.validation_exception import ValidationError
def get_tax(tax, voucher_type):
if voucher_type == VoucherType.STAFF.value:
if voucher_type in [VoucherType.STAFF, VoucherType.NO_CHARGE]:
return 0
elif voucher_type == VoucherType.NO_CHARGE.value:
return 0
else: # voucher_type in [REGULAR_BILL, TAKE_AWAY]:
elif voucher_type in [VoucherType.KOT, VoucherType.REGULAR_BILL]:
return tax
else:
raise ValidationError("Unexpected Voucher Type")
def get_settlements(voucher, dbsession):

View File

@ -4,7 +4,7 @@ import transaction
from pyramid.view import view_config
from barker.models import Voucher, Overview
from barker.views.voucher.save import save_voucher
from barker.views.voucher.save import save
from barker.views.voucher.show import voucher_info
@ -18,7 +18,7 @@ from barker.views.voucher.show import voucher_info
def voucher_change(request):
json = request.json_body
id_ = uuid.UUID(request.matchdict["id"])
item = save_voucher(json, request.dbsession)
item = save(json, request.dbsession)
old = request.dbsession.query(Voucher).filter(Voucher.id == id_).first()
old.void = True
old.void_reason = "Bill Discounted / Changed. New Bill ID is {0}".format(

View File

@ -1,8 +1,11 @@
import datetime
import uuid
from decimal import Decimal
import transaction
from pyramid.httpexceptions import HTTPForbidden
from pyramid.view import view_config
from sqlalchemy import func
from barker.models import (
Overview,
@ -12,7 +15,10 @@ from barker.models import (
InventoryModifier,
VoucherType,
Product,
GuestBook,
FoodTable,
)
from barker.models.validation_exception import ValidationError
from barker.views.voucher import get_tax, get_settlements
from barker.views.voucher.show import voucher_info
@ -21,63 +27,102 @@ from barker.views.voucher.show import voucher_info
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_id = request.GET.get("g", None)
if guest_book_id is not None:
guest_book_id = uuid.UUID(guest_book_id)
json = request.json_body
guest_book = get_guest_book(request.GET.get("g", None), request.dbsession)
if not json["isPrinted"] and "Print Kot" not in request.effective_principals:
raise HTTPForbidden("You are not allowed to print a kot")
if json["isPrinted"] and "Print Bill" not in request.effective_principals:
raise HTTPForbidden("You are not allowed to print bill")
item = save_voucher(
json, voucher_type, uuid.UUID(request.authenticated_userid), request.dbsession
table = (
request.dbsession.query(FoodTable)
.filter(FoodTable.id == uuid.UUID(json["table"]["id"]))
.first()
)
check_permissions(voucher_type, request.effective_principals)
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(
now,
guest_book.pax if guest_book is not None else table.seats,
bill_id,
kot_id,
json["table"]["id"],
json["customer"]["id"] if "id" in json["customer"] else None,
voucher_type,
uuid.UUID(request.authenticated_userid)
)
request.dbsession.add(item)
add_kots(json, item, voucher_type, request.dbsession)
if len(item.kots) == 0 or len(item.kots[0].inventories) == 0:
raise ValidationError("Please add some products!")
if update_table:
status = "printed" if item.is_printed else "running"
item.status = Overview(
voucher_id=None,
food_table_id=item.food_table_id,
guest_book_id=guest_book_id,
status=status,
)
request.dbsession.add(item.status)
do_update_table(item, voucher_type, guest_book, request.dbsession)
transaction.commit()
item = request.dbsession.query(Voucher).filter(Voucher.id == item.id).first()
return voucher_info(item)
def save_voucher(json, voucher_type, user_id, dbsession):
item = Voucher(
json["pax"],
json["table"]["id"],
json["customer"]["id"] if "id" in json["customer"] else None,
json["isPrinted"],
voucher_type,
user_id,
dbsession,
def check_permissions(voucher_type, permissions):
if voucher_type == VoucherType.KOT and "Print Kot" not in permissions:
raise HTTPForbidden("You are not allowed to print a kot")
if voucher_type != VoucherType.KOT and "Print Bill" not in permissions:
raise HTTPForbidden("You are not allowed to print bill")
def get_guest_book(guest_book_id, dbsession):
if guest_book_id is None:
return guest_book_id
return (
dbsession.query(GuestBook)
.filter(GuestBook.id == uuid.UUID(guest_book_id))
.first()
)
dbsession.add(item)
def get_bill_id(voucher_type, dbsession):
if voucher_type == VoucherType.KOT:
return None
return (
dbsession.query(func.coalesce(func.max(Voucher.bill_id), 0) + 1)
.filter(Voucher.voucher_type == voucher_type.value)
.scalar()
)
def do_update_table(item, voucher_type, guest_book, dbsession):
status = "running" if voucher_type == VoucherType.KOT else "printed"
item.status = Overview(
voucher_id=None,
food_table_id=item.food_table_id,
guest_book_id=guest_book.id if guest_book is not None else None,
status=status,
)
dbsession.add(item.status)
def add_kots(json, item, voucher_type, dbsession):
for k in json["kots"]:
kot = Kot(
item.id, item.food_table_id, item.date, item.user_id, dbsession=dbsession
)
code = dbsession.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)
dbsession.add(kot)
for index, i in enumerate(k["inventories"]):
product_id = uuid.UUID(i["product"]["id"])
product = dbsession.query(Product).filter(Product.id == product_id).first()
product = dbsession.query(Product).filter(Product.id == uuid.UUID(i["product"]["id"])).first()
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
inv = Inventory(
kot.id,
product_id,
i["quantity"],
product.id,
round(Decimal(i["quantity"]), 2),
product.price,
i["discount"],
round(Decimal(i["discount"]), 5),
i["isHappyHour"],
product.sale_category.tax_id,
tax_rate,
@ -90,4 +135,3 @@ def save_voucher(json, voucher_type, user_id, dbsession):
inv.modifiers.append(mod)
dbsession.add(mod)
get_settlements(item, dbsession)
return item

View File

@ -97,8 +97,7 @@ def voucher_info(item):
"narration": item.narration,
"void": item.is_void,
"voidReason": item.void_reason,
"isPrinted": item.is_printed,
"voucherType": item.voucher_type,
"voucherType": item.voucher_type.value,
"kotId": item.kot_id,
"kots": [
{
@ -156,7 +155,6 @@ def voucher_blank(table, guest):
"pax": table.seats if guest is None else guest.pax,
"table": {"id": table.id, "name": table.name},
"customer": {"id": guest.customer_id, "name": guest.customer.name} if guest is not None else {},
"isPrinted": False,
"kots": []
}

View File

@ -4,7 +4,7 @@ import transaction
from pyramid.view import view_config
from barker.models import Voucher, Overview
from barker.views.voucher.save import save_voucher
from barker.views.voucher.save import save
@view_config(
@ -22,8 +22,8 @@ def split_voucher(request):
item.void_reason = "Bill Split"
# TODO: Set the Void Settlement
new_one = save_voucher(json["One"], request.dbsession)
new_two = save_voucher(json["Two"], request.dbsession)
new_one = save(json["One"], request.dbsession)
new_two = save(json["Two"], request.dbsession)
status = "printed" if item.is_printed else "running"
new_one.status = Overview(

View File

@ -8,7 +8,16 @@ from pyramid.view import view_config
from sqlalchemy import func
from barker.exceptions import ValidationFailure
from barker.models import Voucher, Kot, Inventory, InventoryModifier, Overview
from barker.models import (
Voucher,
Kot,
Inventory,
InventoryModifier,
Overview,
VoucherType,
GuestBook,
Product,
)
from barker.views.voucher import get_tax, get_settlements
from barker.views.voucher.show import voucher_info
@ -17,22 +26,89 @@ from barker.views.voucher.show import voucher_info
request_method="PUT", route_name="v1_vouchers_id", renderer="json", trans=True
)
def update(request):
now = datetime.now()
update_table = request.GET["u"] == "true"
json = request.json_body
id = uuid.UUID(request.matchdict["id"])
item = request.dbsession.query(Voucher).filter(Voucher.id == id).first()
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()
)
if not json["Printed"] and "Print Kot" not in request.effective_principals:
check_permissions(item, voucher_type, request.effective_principals)
if guest_book is not None:
item.pax = guest_book.pax
item.food_table_id = json["table"]["id"]
if "customer" in json and "id" in json["customer"]:
item.customer_id = json["customer"]["id"]
if item.voucher_type == VoucherType.KOT and voucher_type != VoucherType.KOT:
item.date = now
item.bill_id = get_bill_id(voucher_type, request.dbsession)
item.voucher_type = voucher_type
item.user_id = uuid.UUID(request.authenticated_userid)
item.last_edit_date = now
for k in item.kots:
for i in k.inventories:
i.tax_rate = get_tax(i.tax_rate, voucher_type)
i.discount = next(
round(Decimal(inv["discount"]), 5)
for ko in json["kots"]
for inv in ko["inventories"]
if uuid.UUID(inv["id"]) == i.id
)
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()
kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
item.kots.append(kot)
request.dbsession.add(kot)
for index, i in enumerate(k["inventories"]):
product = (
request.dbsession.query(Product)
.filter(Product.id == uuid.UUID(i["product"]["id"]))
.first()
)
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
inv = Inventory(
kot.id,
product.id,
round(Decimal(i["quantity"]), 2),
product.price,
round(Decimal(i["discount"]), 5),
i["isHappyHour"],
product.sale_category.tax_id,
tax_rate,
index,
)
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)
get_settlements(item, request.dbsession)
if update_table:
do_update_table(item, voucher_type, guest_book, request.dbsession)
transaction.commit()
item = request.dbsession.query(Voucher).filter(Voucher.id == item.id).first()
return voucher_info(item)
def check_permissions(item, voucher_type, permissions):
if voucher_type == VoucherType.KOT and "Print Kot" not in permissions:
raise HTTPForbidden("You are not allowed to print a kot")
if json["Printed"] and "Print Bill" not in request.effective_principals:
if voucher_type != VoucherType.KOT and "Print Bill" not in permissions:
raise HTTPForbidden("You are not allowed to print bill")
if item.is_printed and "Edit Printed Bill" not in request.effective_principals:
if item.voucher_type != VoucherType.KOT and "Edit Printed Bill" not in permissions:
raise HTTPForbidden("You are not allowed to edit a printed bill")
if item.is_printed and not json["Printed"]:
if item.voucher_type != VoucherType.KOT and voucher_type == VoucherType.KOT:
transaction.abort()
raise ValidationFailure("This Bill is already printed\nCannot add a Kot to it.")
@ -42,84 +118,36 @@ def update(request):
"This Bill is already void.\nReason: {0}".format(item.void_reason)
)
if item.is_printed and not json["Printed"]:
transaction.abort()
raise ValidationFailure("This Bill is already printed\nCannot add a Kot to it.")
item.pax = json["Pax"]
item.food_table_id = json["Table"]["FoodTableID"]
item.customer_id = json["Customer"]["CustomerID"]
item.voucher_type = json["VoucherType"]
if not item.is_printed and json["Printed"]:
item.date = now
type = [1, 3] if item.voucher_type in [1, 3] else [item.voucher_type]
item.bill_id = (
request.dbsession.query(func.coalesce(func.max(Voucher.bill_id), 0) + 1)
.filter(Voucher.voucher_type.in_(type))
.scalar()
def get_guest_book(guest_book_id, dbsession):
if guest_book_id is None:
return guest_book_id
return (
dbsession.query(GuestBook)
.filter(GuestBook.id == uuid.UUID(guest_book_id))
.first()
)
def get_bill_id(voucher_type, dbsession):
if voucher_type == VoucherType.KOT:
return None
return (
dbsession.query(func.coalesce(func.max(Voucher.bill_id), 0) + 1)
.filter(Voucher.voucher_type == voucher_type.value)
.scalar()
)
def do_update_table(item, voucher_type, guest_book, dbsession):
status = "running" if voucher_type == VoucherType.KOT else "printed"
if item.status is None:
item.status = Overview(
voucher_id=item.id,
food_table_id=item.food_table_id,
guest_book_id=guest_book.id if guest_book is not None else None,
status=status,
)
item.is_printed = item.is_printed or json["Printed"]
item.user_id = json["User"]["UserID"]
item.last_edit_date = now
for k in item.kots:
for i in k.inventories:
i.tax_rate = get_tax(i.tax_rate, item.voucher_type)
i.discount = next(
Decimal(inv["Discount"])
for ko in json["Kots"]
for inv in ko["Inventories"]
if uuid.UUID(inv["InventoryID"]) == i.id
)
for k in (
k for k in json["Kots"] if k["KotID"] == "00000000-0000-0000-0000-000000000000"
):
kot = Kot(
item.id,
item.food_table_id,
item.date,
item.user_id,
dbsession=request.dbsession,
)
item.kots.append(kot)
request.dbsession.add(kot)
for index, i in enumerate(k["Inventories"]):
tax_rate = get_tax(i["taxRate"], json["VoucherType"])
inv = Inventory(
kot.id,
uuid.UUID(i["product"]["id"]),
i["quantity"],
i["price"],
i["discount"],
i["isHappyHour"],
i["tax"]["id"],
tax_rate,
index,
)
kot.inventories.append(inv)
request.dbsession.add(inv)
for m in i["Modifiers"]:
mod = InventoryModifier(None, uuid.UUID(m["ModifierID"]), 0)
inv.modifiers.append(mod)
request.dbsession.add(mod)
get_settlements(item, request.dbsession)
if update_table:
vft = (
request.dbsession.query(Overview)
.filter(Overview.voucher_id == item.id)
.first()
)
status = "printed" if item.is_printed else "running"
if vft is None:
item.status = Overview(
voucher_id=None, food_table_id=item.food_table_id, status=status
)
request.dbsession.add(item.status)
else:
vft.status = status
vft.food_table_id = item.food_table_id
transaction.commit()
item = request.dbsession.query(Voucher).filter(Voucher.id == item.id).first()
return voucher_info(item)
dbsession.add(item.status)
else:
item.status.status = status