from datetime import datetime from enum import Enum import uuid from decimal import Decimal from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy import ( Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey, UniqueConstraint, case, ) from sqlalchemy.orm import relationship, backref, synonym from barker.models.guidtype import GUID from .meta import Base class VoucherType(Enum): KOT = 0 REGULAR_BILL = 1 NO_CHARGE = 2 STAFF = 4 VOID = 5 class GuestBook(Base): __tablename__ = "guest_book" id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) customer_id = Column( "customer_id", GUID(), ForeignKey("customers.id"), nullable=False ) pax = Column("pax", Numeric, nullable=False) date = Column("creation_date", DateTime(timezone=True), nullable=False) customer = relationship("Customer") def __init__(self, customer_id=None, pax=None, id_=None): self.customer_id = customer_id self.pax = pax self.id = id_ self.date = datetime.utcnow() class Overview(Base): __tablename__ = "overview" id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) 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"), nullable=False, unique=True, ) guest_book_id = Column( "guest_book_id", GUID(), ForeignKey("guest_book.id"), unique=True ) status = Column("status", Unicode(255), nullable=False) voucher = relationship("Voucher", backref=backref("status", uselist=False)) 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, 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): __tablename__ = "inventory_modifiers" __table_args__ = (UniqueConstraint("inventory_id", "modifier_id"),) id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) inventory_id = Column( "inventory_id", GUID(), ForeignKey("inventories.id"), nullable=False ) modifier_id = Column( "modifier_id", GUID(), ForeignKey("modifiers.id"), nullable=False ) price = Column("price", Numeric, nullable=False) inventory = relationship("Inventory", backref="modifiers") modifier = relationship("Modifier") def __init__(self, inventory_id, modifier_id, price): self.inventory_id = inventory_id self.modifier_id = modifier_id self.price = price class Voucher(Base): __tablename__ = "vouchers" __table_args__ = (UniqueConstraint("bill_id", "voucher_type"),) id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) date = Column("date", DateTime, nullable=False, index=True) pax = Column("pax", Numeric, nullable=False) bill_id = Column("bill_id", Numeric) kot_id = Column("kot_id", Numeric, nullable=False, unique=True) creation_date = Column("creation_date", DateTime(timezone=True), nullable=False) last_edit_date = Column("last_edit_date", DateTime(timezone=True), nullable=False) food_table_id = Column( "food_table_id", GUID(), ForeignKey("food_tables.id"), nullable=False ) customer_id = Column("customer_id", GUID(), ForeignKey("customers.id")) narration = Column("narration", Unicode(1000), nullable=False) void_reason = Column("void_reason", Unicode(255)) _voucher_type = Column("voucher_type", Integer, nullable=False) user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False) user = relationship("User", backref="vouchers") food_table = relationship("FoodTable", backref="vouchers") customer = relationship("Customer", backref="vouchers") kots = relationship( "Kot", backref="voucher", cascade="delete, delete-orphan", cascade_backrefs=False, ) settlements = relationship( "Settlement", backref="voucher", cascade="delete, delete-orphan", cascade_backrefs=False, ) reprints = relationship( "Reprint", backref="voucher", cascade="delete, delete-orphan", cascade_backrefs=False, ) 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, voucher_type, user_id, ): self.date = date self.pax = pax 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.void_reason = None self.voucher_type = voucher_type self.user_id = user_id @property def full_bill_id(self): if self.voucher_type == VoucherType.KOT: return "K-" + str(self.kot_id) if self.voucher_type == VoucherType.NO_CHARGE: return "NC-" + str(self.bill_id) if self.voucher_type == VoucherType.STAFF: return "ST-" + str(self.bill_id) if self.voucher_type == VoucherType.REGULAR_BILL: return str(self.bill_id // 10000) + "-" + str(self.bill_id % 10000) if self.voucher_type == VoucherType.VOID: return "K-" + str(self.kot_id) else: raise Exception @property def amount(self): return round(sum(i.amount for k in self.kots for i in k.inventories), 2) class Kot(Base): __tablename__ = "kots" id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) voucher_id = Column( "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, index=True ) code = Column("code", Numeric, nullable=False, unique=True) food_table_id = Column( "food_table_id", GUID(), ForeignKey("food_tables.id"), nullable=False ) date = Column("date", DateTime, nullable=False, index=True) user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False) user = relationship("User", backref="kots") food_table = relationship("FoodTable", backref="kots") def __init__( self, voucher_id=None, code=None, food_table_id=None, date=None, user_id=None, id_=None, ): self.id = id_ self.voucher_id = voucher_id self.code = code self.food_table_id = food_table_id self.date = date self.user_id = user_id class Settlement(Base): __tablename__ = "settlements" __table_args__ = (UniqueConstraint("voucher_id", "settled"),) id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) voucher_id = Column( "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, index=True ) settled = Column("settled", ForeignKey("settle_options.id"), nullable=False) amount = Column("amount", Numeric, nullable=False) settle_option = relationship("SettleOption") def __init__(self, voucher_id=None, settled=None, amount=None, id=None): self.id = id self.voucher_id = voucher_id self.settled = settled self.amount = amount class Reprint(Base): __tablename__ = "reprints" id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) date = Column("date", DateTime, nullable=False, index=True) voucher_id = Column( "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, index=True ) user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False) user = relationship("User", backref="reprints") def __init__(self, voucher_id=None, user_id=None, id=None): self.id = id self.date = datetime.now() self.voucher_id = voucher_id self.user_id = user_id class Inventory(Base): __tablename__ = "inventories" __table_args__ = ( UniqueConstraint("kot_id", "product_id", "is_happy_hour", "price"), ) id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) kot_id = Column("kot_id", GUID(), ForeignKey("kots.id"), nullable=False, index=True) product_id = Column("product_id", GUID(), ForeignKey("products.id"), nullable=False) quantity = Column("quantity", Numeric) price = Column("price", Numeric) is_happy_hour = Column("is_happy_hour", Boolean, nullable=False) tax_rate = Column("tax_rate", Numeric) tax_id = Column("tax_id", GUID(), ForeignKey("taxes.id"), nullable=False) discount = Column("discount", Numeric) sort_order = Column("sort_order", Numeric, nullable=False) kot = relationship("Kot", backref="inventories") tax = relationship("Tax", foreign_keys=tax_id) product = relationship("Product", backref="inventories") def __init__( self, kot_id, product_id, quantity, price, discount, is_hh, tax_id, tax_rate, sort_order, ): self.kot_id = kot_id self.product_id = product_id self.quantity = quantity self.price = price self.discount = discount self.is_happy_hour = is_hh self.tax_id = tax_id self.tax_rate = tax_rate self.sort_order = sort_order @hybrid_property def effective_price(self): return 0 if self.is_happy_hour else self.price @effective_price.expression def effective_price(cls): return case([(cls.is_happy_hour == True, 0)], else_=cls.price) @hybrid_property 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 * self.tax_rate @tax_amount.expression def tax_amount(cls): return cls.net * cls.tax_rate @hybrid_property def amount(self): return Decimal(self.net * (1 + self.tax_rate)) @amount.expression def amount(cls): return cls.net * (1 + cls.tax_rate)