barker/barker/barker/models/product_version.py

128 lines
4.2 KiB
Python

import uuid
from datetime import date
from decimal import Decimal
from typing import TYPE_CHECKING, Optional
from barker.models.product import Product
from sqlalchemy import (
Boolean,
Date,
ForeignKey,
Integer,
Numeric,
Unicode,
case,
func,
text,
)
from sqlalchemy.dialects import postgresql
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Mapped, mapped_column, relationship
from ..db.base_class import reg
if TYPE_CHECKING:
from .menu_category import MenuCategory
from .sale_category import SaleCategory
@reg.mapped_as_dataclass(unsafe_hash=True)
class ProductVersion:
__tablename__ = "product_versions"
id: Mapped[uuid.UUID] = mapped_column(
"id", UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()"), insert_default=uuid.uuid4
)
product_id: Mapped[uuid.UUID] = mapped_column(
"product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False
)
name: Mapped[str] = mapped_column("name", Unicode(255), nullable=False)
units: Mapped[str] = mapped_column("units", Unicode(255), nullable=False)
menu_category_id: Mapped[uuid.UUID] = mapped_column(
"menu_category_id",
UUID(as_uuid=True),
ForeignKey("menu_categories.id"),
nullable=False,
)
sale_category_id: Mapped[uuid.UUID] = mapped_column(
"sale_category_id",
UUID(as_uuid=True),
ForeignKey("sale_categories.id"),
nullable=False,
)
price: Mapped[Decimal] = mapped_column("price", Numeric(precision=15, scale=2), nullable=False)
has_happy_hour: Mapped[bool] = mapped_column("has_happy_hour", Boolean, nullable=False)
is_not_available: Mapped[bool] = mapped_column("is_not_available", Boolean, nullable=False)
quantity: Mapped[Decimal] = mapped_column("quantity", Numeric(precision=15, scale=2), nullable=False)
sort_order: Mapped[int] = mapped_column("sort_order", Integer, nullable=False)
valid_from: Mapped[Optional[date]] = mapped_column("valid_from", Date(), nullable=True)
valid_till: Mapped[Optional[date]] = mapped_column("valid_till", Date(), nullable=True)
menu_category: Mapped["MenuCategory"] = relationship(back_populates="products")
sale_category: Mapped["SaleCategory"] = relationship(back_populates="products")
product: Mapped["Product"] = relationship(back_populates="versions")
__table_args__ = (
postgresql.ExcludeConstraint(
(name, "="),
(units, "="),
(func.daterange(valid_from, valid_till, text("'[]'")), "&&"),
),
postgresql.ExcludeConstraint(
(product_id, "="),
(units, "="),
(func.daterange(valid_from, valid_till, text("'[]'")), "&&"),
),
)
def __init__(
self,
product_id=None,
name=None,
units=None,
menu_category_id=None,
sale_category_id=None,
price=None,
has_happy_hour=None,
is_not_available=None,
quantity=None,
valid_from=None,
valid_till=None,
sort_order=0,
id_=None,
):
self.product_id = product_id
self.name = name
self.units = units
self.menu_category_id = menu_category_id
self.sale_category_id = sale_category_id
self.price = price
self.has_happy_hour = has_happy_hour
self.is_not_available = is_not_available
self.quantity = quantity
self.valid_from = valid_from
self.valid_till = valid_till
self.sort_order = sort_order
self.id = id_
@hybrid_property
def full_name(self):
return f"{self.name} ({self.units})" if self.units else self.name
@full_name.inplace.expression
def _full_name_expression(cls):
return cls.name + case((cls.units != "", " (" + cls.units + ")"), else_="")
def can_delete(self, advanced_delete):
if self.is_fixture:
return False, f"{self.name} is a fixture and cannot be edited or deleted."
if self.is_active:
return False, "Product is active"
# if len(self.inventories) > 0 and not advanced_delete:
# return False, "Product has entries"
return True, ""