Compare commits
2 Commits
4803607e3b
...
2290072820
| Author | SHA1 | Date | |
|---|---|---|---|
| 2290072820 | |||
| 974ac7af3f |
@@ -0,0 +1,53 @@
|
||||
from typing import Literal
|
||||
|
||||
from rio import Component, Rectangle, Column, Spacer, Text, Row, TextInput, FlowContainer
|
||||
from rio.event import on_populate
|
||||
|
||||
from elm.components import ElmButton, CateringItemBox
|
||||
from elm.types.CateringTypes import CateringMenuItem, CateringMenuItemCategory
|
||||
|
||||
ITEM_CATEGORY_BY_DISPLAY_CATEGORY: dict[Literal["Frühstück", "Hauptspeisen", "Snacks & Dessert", "Softdrinks", "Alkohol"], list[CateringMenuItemCategory]] = {
|
||||
"Frühstück": [CateringMenuItemCategory.BREAKFAST],
|
||||
"Hauptspeisen": [CateringMenuItemCategory.MAIN_COURSE],
|
||||
"Snacks & Dessert": [CateringMenuItemCategory.SNACK, CateringMenuItemCategory.DESSERT],
|
||||
"Softdrinks": [CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC],
|
||||
"Alkohol": [CateringMenuItemCategory.BEVERAGE_ALCOHOLIC, CateringMenuItemCategory.BEVERAGE_COCKTAIL, CateringMenuItemCategory.BEVERAGE_SHOT]
|
||||
}
|
||||
|
||||
|
||||
class CateringCategoryDisplay(Component):
|
||||
active_category: Literal["Frühstück", "Hauptspeisen", "Snacks & Dessert", "Softdrinks", "Alkohol"]
|
||||
catering_menu_items: list[CateringMenuItem] = []
|
||||
|
||||
@on_populate
|
||||
async def on_populate(self) -> None:
|
||||
self.catering_menu_items = await CateringMenuItem.find(
|
||||
{
|
||||
"category": {
|
||||
"$in": ITEM_CATEGORY_BY_DISPLAY_CATEGORY[self.active_category]
|
||||
}
|
||||
}
|
||||
).to_list()
|
||||
def build(self) -> Component:
|
||||
if len(self.catering_menu_items) <= 0:
|
||||
return Spacer()
|
||||
|
||||
return Rectangle(
|
||||
content=Column(
|
||||
Rectangle(
|
||||
content=Rectangle(
|
||||
content=Text(self.active_category, margin=0.5, selectable=False, overflow="wrap"),
|
||||
fill=self.session.theme.header_box_background_color,
|
||||
margin=0.4
|
||||
),
|
||||
stroke_width=0.1,
|
||||
stroke_color=self.session.theme.box_border_color,
|
||||
),
|
||||
# Items here
|
||||
Column(*[CateringItemBox(i, margin=0.5, grow_y=True) for i in self.catering_menu_items]),
|
||||
Spacer()
|
||||
),
|
||||
fill=self.session.theme.box_color,
|
||||
stroke_width=0.1,
|
||||
stroke_color=self.session.theme.box_border_color
|
||||
)
|
||||
@@ -0,0 +1,67 @@
|
||||
from decimal import Decimal
|
||||
|
||||
from rio import Component, Rectangle, Column, Text, Row, Separator, Color, Checkbox, FlowContainer, IconButton, Icon, Spacer
|
||||
|
||||
from elm.services import AccountingService
|
||||
from elm.components import ElmButton
|
||||
from elm.types.CateringTypes import CateringMenuItem, CateringModificationKey
|
||||
|
||||
|
||||
class CateringItemBox(Component):
|
||||
item: CateringMenuItem
|
||||
|
||||
def make_money_string(self, money: Decimal) -> str:
|
||||
return self.session[AccountingService].make_euro_string_from_decimal(money)
|
||||
|
||||
def build(self) -> Component:
|
||||
base_mods = []
|
||||
extra_mods = []
|
||||
if self.item.active:
|
||||
for modifier_group in self.item.modifier_groups:
|
||||
if modifier_group.key == CateringModificationKey.BASE:
|
||||
base_mods.append(Text("Basis:", fill=self.session.theme.secondary_color, font_size=0.8, margin_top=0.5))
|
||||
container = FlowContainer(spacing=2.5)
|
||||
for option in modifier_group.options:
|
||||
container.children.append(Row(Checkbox(is_on=option.default_selected), Text(option.label), spacing=0.6))
|
||||
base_mods.append(container)
|
||||
if modifier_group.key == CateringModificationKey.EXTRA:
|
||||
extra_mods.append(Text("Extras:", fill=self.session.theme.secondary_color, font_size=0.8, margin_top=0.8))
|
||||
container = FlowContainer(spacing=2.5)
|
||||
for option in modifier_group.options:
|
||||
text = f"{option.label}"
|
||||
if option.price_delta > Decimal("0"):
|
||||
text += f" (+ {self.make_money_string(option.price_delta)})"
|
||||
container.children.append(Row(Checkbox(is_on=option.default_selected), Text(text), spacing=0.6))
|
||||
extra_mods.append(container)
|
||||
|
||||
return Rectangle(
|
||||
content=Column(
|
||||
Row(
|
||||
Column(
|
||||
Row(
|
||||
Text(text=self.item.name, overflow="nowrap", justify="left", font_size=1.1, margin_right=0.8, font_weight="bold", strikethrough=not self.item.active),
|
||||
Text(text=self.make_money_string(self.item.base_price), overflow="ellipsize", justify="left", font_size=0.8, grow_x=True, fill=self.session.theme.primary_color, align_y=1.2)
|
||||
),
|
||||
Text(self.item.description, font_size=0.7, margin_left=2),
|
||||
*base_mods,
|
||||
*extra_mods,
|
||||
spacing=0.5,
|
||||
margin=0.5,
|
||||
grow_x=True
|
||||
),
|
||||
Column(
|
||||
Spacer(),
|
||||
Rectangle(
|
||||
content=Icon(icon="material/add_shopping_cart", min_width=2, min_height=2, margin=1),
|
||||
hover_fill=Color.TRANSPARENT if not self.item.active else self.session.theme.hud_color,
|
||||
cursor="not-allowed" if not self.item.active else "pointer",
|
||||
transition_time=0.2
|
||||
),
|
||||
Spacer()
|
||||
)
|
||||
|
||||
),
|
||||
Separator(color=self.session.theme.box_border_color),
|
||||
spacing=0.5,
|
||||
)
|
||||
)
|
||||
@@ -75,17 +75,17 @@ class SeatingPlan(Component):
|
||||
|
||||
|
||||
# Block A
|
||||
grid.add(SeatPixel("A01", seat=self.get_seat("A01"), seat_orientation="bottom"), row=57, column=1, width=5, height=2)
|
||||
grid.add(SeatPixel("A02", seat=self.get_seat("A02"), seat_orientation="bottom"), row=57, column=6, width=5, height=2)
|
||||
grid.add(SeatPixel("A03", seat=self.get_seat("A03"), seat_orientation="bottom"), row=57, column=11, width=5, height=2)
|
||||
grid.add(SeatPixel("A04", seat=self.get_seat("A04"), seat_orientation="bottom"), row=57, column=16, width=5, height=2)
|
||||
grid.add(SeatPixel("A05", seat=self.get_seat("A05"), seat_orientation="bottom"), row=57, column=21, width=5, height=2)
|
||||
grid.add(SeatPixel("A01", seat=self.get_seat("A01"), seat_orientation="bottom"), row=57, column=1, width=6, height=2)
|
||||
grid.add(SeatPixel("A02", seat=self.get_seat("A02"), seat_orientation="bottom"), row=57, column=7, width=6, height=2)
|
||||
grid.add(SeatPixel("A03", seat=self.get_seat("A03"), seat_orientation="bottom"), row=57, column=13, width=6, height=2)
|
||||
grid.add(SeatPixel("A04", seat=self.get_seat("A04"), seat_orientation="bottom"), row=57, column=19, width=6, height=2)
|
||||
grid.add(SeatPixel("A05", seat=self.get_seat("A05"), seat_orientation="bottom"), row=57, column=25, width=6, height=2)
|
||||
|
||||
grid.add(SeatPixel("A10", seat=self.get_seat("A10"), seat_orientation="top"), row=55, column=1, width=5, height=2)
|
||||
grid.add(SeatPixel("A11", seat=self.get_seat("A11"), seat_orientation="top"), row=55, column=6, width=5, height=2)
|
||||
grid.add(SeatPixel("A12", seat=self.get_seat("A12"), seat_orientation="top"), row=55, column=11, width=5, height=2)
|
||||
grid.add(SeatPixel("A13", seat=self.get_seat("A13"), seat_orientation="top"), row=55, column=16, width=5, height=2)
|
||||
grid.add(SeatPixel("A14", seat=self.get_seat("A14"), seat_orientation="top"), row=55, column=21, width=5, height=2)
|
||||
grid.add(SeatPixel("A10", seat=self.get_seat("A10"), seat_orientation="top"), row=55, column=1, width=6, height=2)
|
||||
grid.add(SeatPixel("A11", seat=self.get_seat("A11"), seat_orientation="top"), row=55, column=7, width=6, height=2)
|
||||
grid.add(SeatPixel("A12", seat=self.get_seat("A12"), seat_orientation="top"), row=55, column=13, width=6, height=2)
|
||||
grid.add(SeatPixel("A13", seat=self.get_seat("A13"), seat_orientation="top"), row=55, column=19, width=6, height=2)
|
||||
grid.add(SeatPixel("A14", seat=self.get_seat("A14"), seat_orientation="top"), row=55, column=25, width=6, height=2)
|
||||
|
||||
# Block B
|
||||
grid.add(SeatPixel("B01", seat=self.get_seat("B01"), seat_orientation="bottom"), row=50, column=1, width=3, height=2)
|
||||
@@ -127,30 +127,30 @@ class SeatingPlan(Component):
|
||||
grid.add(SeatPixel("C17", seat=self.get_seat("C17"), seat_orientation="top"), row=41, column=22, width=3, height=2)
|
||||
|
||||
# Block D
|
||||
grid.add(SeatPixel("D01", seat=self.get_seat("D01"), seat_orientation="bottom"), row=34, column=1, width=5, height=2)
|
||||
grid.add(SeatPixel("D02", seat=self.get_seat("D02"), seat_orientation="bottom"), row=34, column=6, width=5, height=2)
|
||||
grid.add(SeatPixel("D03", seat=self.get_seat("D03"), seat_orientation="bottom"), row=34, column=11, width=5, height=2)
|
||||
grid.add(SeatPixel("D04", seat=self.get_seat("D04"), seat_orientation="bottom"), row=34, column=16, width=5, height=2)
|
||||
grid.add(SeatPixel("D05", seat=self.get_seat("D05"), seat_orientation="bottom"), row=34, column=21, width=5, height=2)
|
||||
grid.add(SeatPixel("D01", seat=self.get_seat("D01"), seat_orientation="bottom"), row=34, column=1, width=6, height=2)
|
||||
grid.add(SeatPixel("D02", seat=self.get_seat("D02"), seat_orientation="bottom"), row=34, column=7, width=6, height=2)
|
||||
grid.add(SeatPixel("D03", seat=self.get_seat("D03"), seat_orientation="bottom"), row=34, column=13, width=6, height=2)
|
||||
grid.add(SeatPixel("D04", seat=self.get_seat("D04"), seat_orientation="bottom"), row=34, column=19, width=6, height=2)
|
||||
grid.add(SeatPixel("D05", seat=self.get_seat("D05"), seat_orientation="bottom"), row=34, column=25, width=6, height=2)
|
||||
|
||||
grid.add(SeatPixel("D10", seat=self.get_seat("D10"), seat_orientation="top"), row=32, column=1, width=5, height=2)
|
||||
grid.add(SeatPixel("D11", seat=self.get_seat("D11"), seat_orientation="top"), row=32, column=6, width=5, height=2)
|
||||
grid.add(SeatPixel("D12", seat=self.get_seat("D12"), seat_orientation="top"), row=32, column=11, width=5, height=2)
|
||||
grid.add(SeatPixel("D13", seat=self.get_seat("D13"), seat_orientation="top"), row=32, column=16, width=5, height=2)
|
||||
grid.add(SeatPixel("D14", seat=self.get_seat("D14"), seat_orientation="top"), row=32, column=21, width=5, height=2)
|
||||
grid.add(SeatPixel("D10", seat=self.get_seat("D10"), seat_orientation="top"), row=32, column=1, width=6, height=2)
|
||||
grid.add(SeatPixel("D11", seat=self.get_seat("D11"), seat_orientation="top"), row=32, column=7, width=6, height=2)
|
||||
grid.add(SeatPixel("D12", seat=self.get_seat("D12"), seat_orientation="top"), row=32, column=13, width=6, height=2)
|
||||
grid.add(SeatPixel("D13", seat=self.get_seat("D13"), seat_orientation="top"), row=32, column=19, width=6, height=2)
|
||||
grid.add(SeatPixel("D14", seat=self.get_seat("D14"), seat_orientation="top"), row=32, column=25, width=6, height=2)
|
||||
|
||||
# Block E
|
||||
grid.add(SeatPixel("E01", seat=self.get_seat("E01"), seat_orientation="bottom"), row=27, column=1, width=5, height=2)
|
||||
grid.add(SeatPixel("E02", seat=self.get_seat("E02"), seat_orientation="bottom"), row=27, column=6, width=5, height=2)
|
||||
grid.add(SeatPixel("E03", seat=self.get_seat("E03"), seat_orientation="bottom"), row=27, column=11, width=5, height=2)
|
||||
grid.add(SeatPixel("E04", seat=self.get_seat("E04"), seat_orientation="bottom"), row=27, column=16, width=5, height=2)
|
||||
grid.add(SeatPixel("E05", seat=self.get_seat("E05"), seat_orientation="bottom"), row=27, column=21, width=5, height=2)
|
||||
grid.add(SeatPixel("E01", seat=self.get_seat("E01"), seat_orientation="bottom"), row=27, column=1, width=6, height=2)
|
||||
grid.add(SeatPixel("E02", seat=self.get_seat("E02"), seat_orientation="bottom"), row=27, column=7, width=6, height=2)
|
||||
grid.add(SeatPixel("E03", seat=self.get_seat("E03"), seat_orientation="bottom"), row=27, column=13, width=6, height=2)
|
||||
grid.add(SeatPixel("E04", seat=self.get_seat("E04"), seat_orientation="bottom"), row=27, column=19, width=6, height=2)
|
||||
grid.add(SeatPixel("E05", seat=self.get_seat("E05"), seat_orientation="bottom"), row=27, column=25, width=6, height=2)
|
||||
|
||||
grid.add(SeatPixel("E10", seat=self.get_seat("E10"), seat_orientation="top"), row=25, column=1, width=5, height=2)
|
||||
grid.add(SeatPixel("E11", seat=self.get_seat("E11"), seat_orientation="top"), row=25, column=6, width=5, height=2)
|
||||
grid.add(SeatPixel("E12", seat=self.get_seat("E12"), seat_orientation="top"), row=25, column=11, width=5, height=2)
|
||||
grid.add(SeatPixel("E13", seat=self.get_seat("E13"), seat_orientation="top"), row=25, column=16, width=5, height=2)
|
||||
grid.add(SeatPixel("E14", seat=self.get_seat("E14"), seat_orientation="top"), row=25, column=21, width=5, height=2)
|
||||
grid.add(SeatPixel("E10", seat=self.get_seat("E10"), seat_orientation="top"), row=25, column=1, width=6, height=2)
|
||||
grid.add(SeatPixel("E11", seat=self.get_seat("E11"), seat_orientation="top"), row=25, column=7, width=6, height=2)
|
||||
grid.add(SeatPixel("E12", seat=self.get_seat("E12"), seat_orientation="top"), row=25, column=13, width=6, height=2)
|
||||
grid.add(SeatPixel("E13", seat=self.get_seat("E13"), seat_orientation="top"), row=25, column=19, width=6, height=2)
|
||||
grid.add(SeatPixel("E14", seat=self.get_seat("E14"), seat_orientation="top"), row=25, column=25, width=6, height=2)
|
||||
|
||||
# Orga Block
|
||||
grid.add(SeatPixel("Z01", seat=self.get_seat("Z01"), seat_orientation="top"), row=40, column=35, width=4, height=2)
|
||||
@@ -167,7 +167,7 @@ class SeatingPlan(Component):
|
||||
grid.add(TextPixel(text="G\ne\nt\nr\nä\nn\nk\ne"), row=20, column=40, width=4, height=12)
|
||||
|
||||
# Main Entrance
|
||||
grid.add(TextPixel(text="H\na\nl\nl\ne\nn\n\nE\ni\nn\ng\na\nn\ng"), row=33, column=66, width=4, height=27)
|
||||
grid.add(TextPixel(text="H\na\nl\nl\ne\nn\n\nE\ni\nn\ng\na\nn\ng"), row=33, column=76, width=4, height=27)
|
||||
|
||||
# Sleeping
|
||||
grid.add(TextPixel(icon_name="material/bed"), row=1, column=1, width=30, height=14)
|
||||
|
||||
@@ -9,3 +9,5 @@ from .PersonalInfoBox import PersonalInfoBox
|
||||
from .BuyTicketBox import BuyTicketBox
|
||||
from .SeatingPlanPixels import *
|
||||
from .SeatingPlan import *
|
||||
from .CateringItemBox import CateringItemBox
|
||||
from .CateringCategoryDisplay import CateringCategoryDisplay
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import io
|
||||
from copy import copy
|
||||
from typing import Any, Optional, Literal
|
||||
from uuid import uuid4
|
||||
|
||||
from rio import Component, Column, Row, Text, Spacer, page, Color, Rectangle, TextInput, GuardEvent, SwitcherBar, SwitcherBarChangeEvent
|
||||
|
||||
from elm.types import UserSession, User
|
||||
from elm.types.CateringTypes import *
|
||||
from elm.services import UserService, LocalData, LocalDataService, ConfigurationService
|
||||
from elm.components import ElmButton, CateringCategoryDisplay
|
||||
|
||||
|
||||
@page(name="Catering", url_segment="catering")
|
||||
class CateringPage(Component):
|
||||
active_category: Literal["Frühstück", "Hauptspeisen", "Snacks & Dessert", "Softdrinks", "Alkohol"] = "Hauptspeisen"
|
||||
|
||||
async def on_switcher_bar_change(self, event: SwitcherBarChangeEvent) -> None:
|
||||
self.active_category = event.value
|
||||
print(event)
|
||||
|
||||
def build(self) -> Component:
|
||||
return Row(
|
||||
Column(
|
||||
Rectangle(
|
||||
content=Column(
|
||||
Rectangle(
|
||||
content=SwitcherBar("Frühstück", "Hauptspeisen", "Snacks & Dessert", "Softdrinks", "Alkohol", margin=0.5, selected_value=self.bind().active_category, on_change=self.on_switcher_bar_change),
|
||||
stroke_width=0.1,
|
||||
stroke_color=self.session.theme.box_border_color,
|
||||
)
|
||||
),
|
||||
fill=self.session.theme.box_color,
|
||||
stroke_width=0.1,
|
||||
stroke_color=self.session.theme.box_border_color
|
||||
),
|
||||
CateringCategoryDisplay(active_category=self.active_category, grow_y=True),
|
||||
grow_x=True,
|
||||
spacing=1
|
||||
),
|
||||
Column(
|
||||
Rectangle(
|
||||
content=Column(
|
||||
Rectangle(
|
||||
content=Rectangle(
|
||||
content=Text("Warenkorb", margin=0.5, selectable=False, overflow="wrap"),
|
||||
fill=self.session.theme.header_box_background_color,
|
||||
margin=0.4
|
||||
),
|
||||
stroke_width=0.1,
|
||||
stroke_color=self.session.theme.box_border_color,
|
||||
)
|
||||
),
|
||||
fill=self.session.theme.box_color,
|
||||
stroke_width=0.1,
|
||||
stroke_color=self.session.theme.box_border_color
|
||||
),
|
||||
Rectangle(
|
||||
content=Column(
|
||||
Text("ToDo", margin=1),
|
||||
Spacer()
|
||||
),
|
||||
fill=self.session.theme.box_color,
|
||||
stroke_width=0.1,
|
||||
stroke_color=self.session.theme.box_border_color,
|
||||
grow_y=True
|
||||
),
|
||||
spacing=1,
|
||||
min_width=18
|
||||
),
|
||||
spacing=1,
|
||||
margin=1
|
||||
)
|
||||
@@ -4,7 +4,7 @@ from beanie import init_beanie
|
||||
from pymongo import AsyncMongoClient
|
||||
from pymongo.asynchronous.collection import AsyncCollection
|
||||
|
||||
from elm.types import User, Transaction, Ticket, Seat
|
||||
from elm.types import User, Transaction, Ticket, Seat, CateringTypes
|
||||
from elm.types.ConfigurationTypes import DatabaseConfiguration
|
||||
|
||||
logger = logging.getLogger(__name__.split(".")[-1])
|
||||
@@ -33,5 +33,5 @@ class DatabaseService:
|
||||
self._users: AsyncCollection = self._database["users"]
|
||||
await init_beanie(
|
||||
database=self._database,
|
||||
document_models=[User, Transaction, Ticket, Seat]
|
||||
document_models=[User, Transaction, Ticket, Seat, CateringTypes.CateringMenuItem, CateringTypes.CateringOrder]
|
||||
)
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, UTC
|
||||
from decimal import Decimal
|
||||
from enum import StrEnum
|
||||
from typing import Optional, Annotated
|
||||
|
||||
from beanie import Document, PydanticObjectId, Indexed
|
||||
from bson import Decimal128
|
||||
from pydantic import BaseModel, Field, field_validator, ConfigDict
|
||||
|
||||
class CateringMenuItemCategory(StrEnum):
|
||||
MAIN_COURSE = "MAIN_COURSE"
|
||||
DESSERT = "DESSERT"
|
||||
BEVERAGE_NON_ALCOHOLIC = "BEVERAGE_NON_ALCOHOLIC"
|
||||
BEVERAGE_ALCOHOLIC = "BEVERAGE_ALCOHOLIC"
|
||||
BEVERAGE_COCKTAIL = "BEVERAGE_COCKTAIL"
|
||||
BEVERAGE_SHOT = "BEVERAGE_SHOT"
|
||||
BREAKFAST = "BREAKFAST"
|
||||
SNACK = "SNACK"
|
||||
NON_FOOD = "NON_FOOD"
|
||||
|
||||
class CateringOrderStatus(StrEnum):
|
||||
RECEIVED = "RECEIVED"
|
||||
DELAYED = "DELAYED"
|
||||
READY_FOR_PICKUP = "READY_FOR_PICKUP"
|
||||
EN_ROUTE = "EN_ROUTE"
|
||||
COMPLETED = "COMPLETED"
|
||||
CANCELED = "CANCELED"
|
||||
|
||||
class CateringModificationKey(StrEnum):
|
||||
BASE = "base" # For base ingredients that can be deselected, like butter on bread
|
||||
EXTRA = "extra" # For ingredients that can be added, like ketchup on fries
|
||||
|
||||
class MongoDecimalModel(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
arbitrary_types_allowed=True,
|
||||
json_encoders={
|
||||
Decimal: lambda v: str(v)
|
||||
}
|
||||
)
|
||||
|
||||
@field_validator("*", mode="before", check_fields=False)
|
||||
@classmethod
|
||||
def convert_decimal128(cls, v):
|
||||
if isinstance(v, Decimal128):
|
||||
return v.to_decimal()
|
||||
|
||||
return v
|
||||
|
||||
class CateringModifierOption(MongoDecimalModel):
|
||||
key: str
|
||||
label: str
|
||||
|
||||
default_selected: bool = False
|
||||
|
||||
price_delta: Decimal = Decimal("0.00")
|
||||
|
||||
class CateringModifierGroup(MongoDecimalModel):
|
||||
key: CateringModificationKey
|
||||
label: str
|
||||
|
||||
# True = checkbox group
|
||||
# False = radio button group
|
||||
multi_select: bool = True
|
||||
|
||||
min_selected: int = 0
|
||||
max_selected: Optional[int] = None
|
||||
|
||||
options: list[CateringModifierOption] = Field(default_factory=list)
|
||||
|
||||
|
||||
class CateringMenuItem(MongoDecimalModel, Document):
|
||||
name: Annotated[str, Indexed(unique=True)]
|
||||
|
||||
category: CateringMenuItemCategory
|
||||
|
||||
description: Optional[str] = None
|
||||
|
||||
base_price: Decimal = Decimal("0.00")
|
||||
|
||||
modifier_groups: list[CateringModifierGroup] = Field(default_factory=list)
|
||||
|
||||
active: bool = True
|
||||
|
||||
created_at: datetime = Field(
|
||||
default_factory=lambda: datetime.now(UTC)
|
||||
)
|
||||
|
||||
updated_at: datetime = Field(
|
||||
default_factory=lambda: datetime.now(UTC)
|
||||
)
|
||||
|
||||
class Settings:
|
||||
name = "catering_menu_items"
|
||||
|
||||
class CateringSelectedModifier(MongoDecimalModel):
|
||||
group_key: str
|
||||
option_key: str
|
||||
|
||||
label: str
|
||||
|
||||
selected: bool
|
||||
|
||||
price_delta: Decimal = Decimal("0.00")
|
||||
|
||||
|
||||
class CateringOrderedItem(MongoDecimalModel):
|
||||
menu_item_id: PydanticObjectId
|
||||
|
||||
# Snapshot fields
|
||||
name: str
|
||||
|
||||
quantity: int = 1
|
||||
|
||||
base_price: Decimal
|
||||
|
||||
selected_modifiers: list[CateringSelectedModifier] = Field(
|
||||
default_factory=list
|
||||
)
|
||||
|
||||
# Final calculated price INCLUDING modifiers
|
||||
final_unit_price: Decimal
|
||||
|
||||
notes: Optional[str] = None
|
||||
|
||||
class CateringOrder(Document):
|
||||
customer_id: PydanticObjectId
|
||||
|
||||
items: list[CateringOrderedItem] = Field(default_factory=list)
|
||||
|
||||
status: CateringOrderStatus = CateringOrderStatus.RECEIVED
|
||||
|
||||
created_at: datetime = Field(
|
||||
default_factory=lambda: datetime.now(UTC)
|
||||
)
|
||||
|
||||
class Settings:
|
||||
name = "catering_orders"
|
||||
@@ -4,7 +4,7 @@ from typing import Annotated
|
||||
|
||||
from beanie import Document, Indexed
|
||||
from bson import Decimal128
|
||||
from pydantic import field_validator
|
||||
from pydantic import field_validator, Field
|
||||
|
||||
|
||||
class Transaction(Document):
|
||||
@@ -12,7 +12,9 @@ class Transaction(Document):
|
||||
value: Decimal
|
||||
is_debit: bool
|
||||
title: str
|
||||
transaction_date: datetime = datetime.now(UTC)
|
||||
transaction_date: datetime = Field(
|
||||
default_factory=lambda: datetime.now(UTC)
|
||||
)
|
||||
|
||||
class Settings:
|
||||
name = "transactions"
|
||||
@@ -23,3 +25,4 @@ class Transaction(Document):
|
||||
if isinstance(v, Decimal128):
|
||||
return v.to_decimal()
|
||||
return v
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from datetime import date, datetime
|
||||
from datetime import date, datetime, UTC
|
||||
from typing import Optional, Annotated
|
||||
|
||||
from beanie import Document, Indexed
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class User(Document):
|
||||
@@ -15,7 +16,9 @@ class User(Document):
|
||||
user_birth_day: Optional[date] = None
|
||||
is_active: bool = True
|
||||
is_team_member: bool = False
|
||||
created_at: datetime = datetime.now()
|
||||
created_at: datetime = Field(
|
||||
default_factory=lambda: datetime.now(UTC)
|
||||
)
|
||||
|
||||
class Settings:
|
||||
name = "users"
|
||||
|
||||
@@ -4,3 +4,4 @@ from .ConfigurationTypes import *
|
||||
from .Transaction import Transaction
|
||||
from .Ticket import Ticket, TicketState
|
||||
from .Seat import Seat
|
||||
from .ConfigurationTypes import *
|
||||
|
||||
Reference in New Issue
Block a user