barker/barker/models/voucher.py

263 lines
10 KiB
Python
Raw Normal View History

from datetime import datetime
from enum import IntEnum
import uuid
from decimal import Decimal
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey, UniqueConstraint, func, case
from sqlalchemy.orm import relationship, synonym, backref
from barker.models.guidtype import GUID
from .meta import Base
class VoucherType(IntEnum):
REGULAR_BILL = 1
NO_CHARGE = 2
TAKE_AWAY = 3
STAFF = 4
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'), unique=True)
food_table_id = Column('food_table_id', GUID(), ForeignKey('food_tables.id'), 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):
self.voucher_id = voucher_id
self.food_table_id = food_table_id
self.guest_book_id = guest_book_id
self.status = status
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'), nullable=False)
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)
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)
@property
def __name__(self):
return self.name
def __init__(self, pax, food_table_id, customer_id, is_printed, voucher_type, user_id, dbsession):
now = datetime.now()
self.date = now
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.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:
return 'K-' + str(self.kot_id)
if self.voucher_type == VoucherType.NO_CHARGE.value:
return "NC-" + str(self.bill_id)
if self.voucher_type == VoucherType.STAFF.value:
return "ST-" + str(self.bill_id)
if self.voucher_type in [VoucherType.TAKE_AWAY.value, VoucherType.REGULAR_BILL.value]:
return str(self.bill_id // 10000) + "-" + str(self.bill_id % 10000)
else:
raise Exception
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, food_table_id=None, date=None, user_id=None, id=None, dbsession=None):
self.id = id
self.voucher_id = voucher_id
self.code = dbsession.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
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 == True 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)
@hybrid_property
def st_amount(self):
return self.net_taxable * self.service_tax_rate
@hybrid_property
def vat_amount(self):
return self.net_taxable * self.vat_rate
@hybrid_property
def amount(self):
return Decimal(self.net * (1 + self.service_tax_rate + self.vat_rate))
@amount.expression
def amount(cls):
return cls.net * (1 + cls.service_tax_rate + cls.vat_rate)