2022-04-20 02:05:10 +02:00
|
|
|
"""Script for everything Order related in the database"""
|
2019-09-08 00:41:50 +02:00
|
|
|
import typing
|
2021-06-21 02:05:11 +02:00
|
|
|
from collections import defaultdict
|
2022-04-19 22:03:00 +02:00
|
|
|
from datetime import datetime
|
2022-05-30 19:48:23 +02:00
|
|
|
import secrets
|
2022-04-20 02:05:10 +02:00
|
|
|
import string
|
2019-08-28 03:46:04 +02:00
|
|
|
|
2020-01-27 02:31:02 +01:00
|
|
|
from hlds.definitions import location_definitions
|
2022-04-19 22:03:00 +02:00
|
|
|
from utils import first
|
|
|
|
|
2019-08-28 03:46:04 +02:00
|
|
|
from .database import db
|
|
|
|
from .user import User
|
|
|
|
|
2022-06-03 19:05:33 +02:00
|
|
|
BASE34_ALPHABET = '123456789abcdefghijkmnopqrstuvwxyz'
|
2022-06-01 17:18:47 +02:00
|
|
|
|
2022-05-30 19:48:23 +02:00
|
|
|
def generate_slug():
|
2022-06-03 19:05:33 +02:00
|
|
|
secret = ''.join(secrets.choice(BASE34_ALPHABET) for i in range(8))
|
2022-05-30 19:48:23 +02:00
|
|
|
while Order.query.filter(Order.slug == secret).first() is not None:
|
2022-06-03 19:05:33 +02:00
|
|
|
secret = ''.join(secrets.choice(BASE34_ALPHABET) for i in range(8))
|
2022-05-30 19:48:23 +02:00
|
|
|
return secret
|
2019-08-28 03:46:04 +02:00
|
|
|
|
|
|
|
class Order(db.Model):
|
2022-04-20 02:05:10 +02:00
|
|
|
"""Class used for configuring the Order model in the database"""
|
2019-08-28 03:46:04 +02:00
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
2020-01-26 02:28:20 +01:00
|
|
|
courier_id = db.Column(db.Integer, nullable=True)
|
2020-01-26 02:39:58 +01:00
|
|
|
location_id = db.Column(db.String(64))
|
|
|
|
location_name = db.Column(db.String(128))
|
2019-08-28 03:46:04 +02:00
|
|
|
starttime = db.Column(db.DateTime)
|
|
|
|
stoptime = db.Column(db.DateTime)
|
|
|
|
public = db.Column(db.Boolean, default=True)
|
2022-06-03 19:05:33 +02:00
|
|
|
slug = db.Column(db.String(8), default=generate_slug, unique=True)
|
2022-05-24 21:26:51 +02:00
|
|
|
association = db.Column(db.String(120), nullable=False, server_default="")
|
2020-01-26 02:39:58 +01:00
|
|
|
|
2019-09-05 03:33:29 +02:00
|
|
|
items = db.relationship("OrderItem", backref="order", lazy="dynamic")
|
2019-08-28 03:46:04 +02:00
|
|
|
|
2020-01-27 02:31:02 +01:00
|
|
|
def __getattr__(self, name):
|
|
|
|
if name == "location":
|
2020-07-17 11:40:15 +02:00
|
|
|
return first(
|
|
|
|
filter(lambda l: l.id == self.location_id, location_definitions)
|
|
|
|
)
|
2020-01-27 02:31:02 +01:00
|
|
|
raise AttributeError()
|
2019-08-28 03:46:04 +02:00
|
|
|
|
2019-09-08 00:41:50 +02:00
|
|
|
def __repr__(self) -> str:
|
2019-09-10 01:06:11 +02:00
|
|
|
# pylint: disable=R1705
|
2019-08-28 03:46:04 +02:00
|
|
|
if self.location:
|
2022-04-19 22:03:00 +02:00
|
|
|
return f"Order {self.id} @ {self.location.name or 'None'}"
|
2019-08-28 03:46:04 +02:00
|
|
|
else:
|
2022-04-19 22:03:00 +02:00
|
|
|
return f"Order {self.id}"
|
2019-08-28 03:46:04 +02:00
|
|
|
|
2020-01-27 02:31:02 +01:00
|
|
|
def update_from_hlds(self) -> None:
|
|
|
|
"""
|
|
|
|
Update the location name from the HLDS definition.
|
|
|
|
User should commit after running this to make the change persistent.
|
|
|
|
"""
|
2020-07-17 11:40:15 +02:00
|
|
|
assert (
|
|
|
|
self.location_id
|
|
|
|
), "location_id must be configured before updating from HLDS"
|
2020-01-27 02:31:02 +01:00
|
|
|
self.location_name = self.location.name
|
|
|
|
|
2020-08-14 04:57:02 +02:00
|
|
|
def for_user(self, anon=None, user=None) -> typing.List:
|
2022-04-20 02:05:10 +02:00
|
|
|
"""Get the items for a certain user"""
|
2020-08-14 04:57:02 +02:00
|
|
|
return list(
|
|
|
|
filter(
|
|
|
|
(lambda i: i.user == user)
|
|
|
|
if user is not None
|
|
|
|
else (lambda i: i.user_name == anon),
|
2022-04-19 22:03:00 +02:00
|
|
|
self.items,
|
2020-08-14 04:57:02 +02:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
def group_by_user(self) -> typing.List[typing.Tuple[str, typing.List]]:
|
2022-04-20 02:05:10 +02:00
|
|
|
"""Group items of an Order by user"""
|
2022-04-19 22:03:00 +02:00
|
|
|
group: typing.Dict[str, typing.List] = {}
|
2020-08-14 04:57:02 +02:00
|
|
|
|
2022-04-19 22:03:00 +02:00
|
|
|
# pylint: disable=E1133
|
2019-08-28 03:46:04 +02:00
|
|
|
for item in self.items:
|
2020-08-14 04:57:02 +02:00
|
|
|
if item.for_name not in group:
|
|
|
|
group[item.for_name] = []
|
|
|
|
|
|
|
|
group[item.for_name].append(item)
|
|
|
|
|
|
|
|
for _user_name, order_items in group.items():
|
|
|
|
order_items.sort(key=lambda order_item: order_item.comment or "")
|
|
|
|
|
2020-08-19 13:02:14 +02:00
|
|
|
return list(sorted(group.items(), key=lambda t: (t[0] or "", t[1] or "")))
|
2020-08-14 04:57:02 +02:00
|
|
|
|
2022-04-19 22:03:00 +02:00
|
|
|
def group_by_dish(
|
|
|
|
self,
|
|
|
|
) -> typing.List[
|
|
|
|
typing.Tuple[str, int, typing.List[typing.Tuple[str, typing.List]]]
|
|
|
|
]:
|
2022-04-20 02:05:10 +02:00
|
|
|
"""Group items of an Order by dish"""
|
2022-04-19 22:03:00 +02:00
|
|
|
group: typing.Dict[str, typing.Dict[str, typing.List]] = defaultdict(
|
|
|
|
lambda: defaultdict(list)
|
|
|
|
)
|
2020-08-14 04:57:02 +02:00
|
|
|
|
2022-04-19 22:03:00 +02:00
|
|
|
# pylint: disable=E1133
|
2019-08-28 03:46:04 +02:00
|
|
|
for item in self.items:
|
2021-06-21 02:05:11 +02:00
|
|
|
group[item.dish_name][item.comment].append(item)
|
|
|
|
|
|
|
|
return sorted(
|
|
|
|
(
|
|
|
|
dish_name,
|
|
|
|
# Amount of items of this dish
|
|
|
|
sum(map(len, comment_group.values())),
|
|
|
|
sorted(
|
2021-06-21 02:08:32 +02:00
|
|
|
(comment, sorted(items, key=lambda x: (x.for_name or "")))
|
2021-06-21 02:05:11 +02:00
|
|
|
for comment, items in comment_group.items()
|
2022-04-19 22:03:00 +02:00
|
|
|
),
|
2021-06-21 02:05:11 +02:00
|
|
|
)
|
|
|
|
for dish_name, comment_group in group.items()
|
|
|
|
)
|
2019-08-28 03:46:04 +02:00
|
|
|
|
2020-01-27 03:41:38 +01:00
|
|
|
def is_closed(self) -> bool:
|
2022-04-20 02:05:10 +02:00
|
|
|
"""Return whether the order is closed"""
|
2020-01-27 03:52:29 +01:00
|
|
|
return self.stoptime and datetime.now() > self.stoptime
|
2020-01-27 03:41:38 +01:00
|
|
|
|
2019-09-08 00:41:50 +02:00
|
|
|
def can_close(self, user_id: int) -> bool:
|
2022-04-20 02:05:10 +02:00
|
|
|
"""Check if a user can close the Order"""
|
2019-08-28 03:46:04 +02:00
|
|
|
if self.stoptime and self.stoptime < datetime.now():
|
|
|
|
return False
|
|
|
|
user = None
|
|
|
|
if user_id:
|
|
|
|
user = User.query.filter_by(id=user_id).first()
|
2020-01-26 02:28:20 +01:00
|
|
|
if self.courier_id == user_id or (user and user.is_admin()):
|
2019-08-28 03:46:04 +02:00
|
|
|
return True
|
|
|
|
return False
|
2022-05-02 21:56:38 +02:00
|
|
|
|
|
|
|
def can_modify_prices(self, user_id: int) -> bool:
|
|
|
|
if not self.is_closed():
|
|
|
|
return False
|
|
|
|
user = User.query.filter_by(id=user_id).first()
|
2022-05-02 22:00:37 +02:00
|
|
|
return user and (user.is_admin() or user == self.courier)
|
2022-05-02 21:56:38 +02:00
|
|
|
|
|
|
|
def can_modify_payment(self, user_id: int) -> bool:
|
|
|
|
user = User.query.filter_by(id=user_id).first()
|
2022-05-02 22:00:37 +02:00
|
|
|
return user and (user.is_admin() or user == self.courier)
|