Reformat with black
This commit is contained in:
parent
588ffdadfb
commit
4f7ffc0e3d
18 changed files with 204 additions and 131 deletions
17
app/app.py
17
app/app.py
|
@ -92,8 +92,7 @@ def register_plugins(app: Flask) -> Manager:
|
|||
|
||||
# Make cookies more secure
|
||||
app.config.update(
|
||||
SESSION_COOKIE_HTTPONLY=True,
|
||||
SESSION_COOKIE_SAMESITE='Lax',
|
||||
SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE="Lax",
|
||||
)
|
||||
|
||||
if not app.debug:
|
||||
|
@ -140,15 +139,16 @@ def add_template_filters(app: Flask) -> None:
|
|||
"Add functions which can be used in the templates"
|
||||
# pylint: disable=W0612
|
||||
@app.template_filter("countdown")
|
||||
def countdown(value, only_positive: bool = True,
|
||||
show_text: bool = True, reload: bool = True) -> str:
|
||||
def countdown(
|
||||
value, only_positive: bool = True, show_text: bool = True, reload: bool = True
|
||||
) -> str:
|
||||
delta = int(value.timestamp() - datetime.now().timestamp())
|
||||
if delta < 0 and only_positive:
|
||||
text = "closed"
|
||||
else:
|
||||
carry, seconds = divmod(delta, 60)
|
||||
carry, minutes = divmod(carry, 60)
|
||||
days, hours = divmod(carry, 24)
|
||||
days, hours = divmod(carry, 24)
|
||||
|
||||
days_text = f"{days} days, " if days else ""
|
||||
|
||||
|
@ -157,8 +157,11 @@ def add_template_filters(app: Flask) -> None:
|
|||
|
||||
reload_str = "yes" if reload else "no"
|
||||
|
||||
return Markup(f"<span class='time' data-seconds='{delta}' data-reload='{reload_str}'>" +
|
||||
text + "</span>")
|
||||
return Markup(
|
||||
f"<span class='time' data-seconds='{delta}' data-reload='{reload_str}'>"
|
||||
+ text
|
||||
+ "</span>"
|
||||
)
|
||||
|
||||
@app.template_filter("year")
|
||||
def current_year(_value: typing.Any) -> str:
|
||||
|
|
|
@ -71,7 +71,7 @@ def add_to_current() -> None:
|
|||
|
||||
|
||||
@app_manager.command
|
||||
def setup_database(): #type: None
|
||||
def setup_database(): # type: None
|
||||
"Start the database interaction script"
|
||||
print("Database modification script!")
|
||||
print("=============================\n\n")
|
||||
|
|
|
@ -36,9 +36,9 @@ class FatOrder(Order, FatModel):
|
|||
@classmethod
|
||||
def items_per_order(cls):
|
||||
return (
|
||||
Order.query.join(OrderItem).group_by(Order.id)
|
||||
.with_entities(Order.id,
|
||||
func.count(OrderItem.user_id).label("total"))
|
||||
Order.query.join(OrderItem)
|
||||
.group_by(Order.id)
|
||||
.with_entities(Order.id, func.count(OrderItem.user_id).label("total"))
|
||||
)
|
||||
|
||||
|
||||
|
|
16
app/forms.py
16
app/forms.py
|
@ -6,8 +6,15 @@ from typing import Optional
|
|||
from flask import session, request
|
||||
from flask_login import current_user
|
||||
from flask_wtf import FlaskForm as Form
|
||||
from wtforms import (DateTimeField, SelectField, SelectMultipleField, StringField, SubmitField,
|
||||
FieldList, validators)
|
||||
from wtforms import (
|
||||
DateTimeField,
|
||||
SelectField,
|
||||
SelectMultipleField,
|
||||
StringField,
|
||||
SubmitField,
|
||||
FieldList,
|
||||
validators,
|
||||
)
|
||||
|
||||
from utils import euro_string, price_range_string
|
||||
from hlds.definitions import location_definitions
|
||||
|
@ -39,9 +46,7 @@ class OrderForm(Form):
|
|||
(0, None),
|
||||
(current_user.id, current_user.username),
|
||||
]
|
||||
self.location_id.choices = [
|
||||
(l.id, l.name) for l in location_definitions
|
||||
]
|
||||
self.location_id.choices = [(l.id, l.name) for l in location_definitions]
|
||||
if self.stoptime.data is None:
|
||||
self.stoptime.data = datetime.now() + timedelta(hours=1)
|
||||
|
||||
|
@ -67,6 +72,7 @@ class AnonOrderItemForm(OrderItemForm):
|
|||
Class which defines the form for a new Item in an Order
|
||||
For Users who aren't logged in
|
||||
"""
|
||||
|
||||
user_name = StringField("Name", validators=[validators.required()])
|
||||
|
||||
def populate(self, location: Location) -> None:
|
||||
|
|
|
@ -6,11 +6,9 @@ from utils import euro_string, first
|
|||
|
||||
|
||||
def _format_tags(tags: Iterable[str]) -> str:
|
||||
return (
|
||||
" :: {}".format(" ".join(["{" + tag + "}" for tag in tags]))
|
||||
if tags else
|
||||
""
|
||||
)
|
||||
return " :: {}".format(" ".join(["{" + tag + "}" for tag in tags])) \
|
||||
if tags \
|
||||
else ""
|
||||
|
||||
|
||||
def _format_price(price: int) -> str:
|
||||
|
@ -35,7 +33,7 @@ class Option:
|
|||
self,
|
||||
" -- {}".format(self.description) if self.description else "",
|
||||
_format_tags(self.tags),
|
||||
_format_price(self.price)
|
||||
_format_price(self.price),
|
||||
)
|
||||
|
||||
|
||||
|
@ -51,7 +49,7 @@ class Choice:
|
|||
return "{0.id}: {0.name}{1}\n\t\t{2}".format(
|
||||
self,
|
||||
" -- {}".format(self.description) if self.description else "",
|
||||
"\n\t\t".join(map(str, self.options))
|
||||
"\n\t\t".join(map(str, self.options)),
|
||||
)
|
||||
|
||||
def option_by_id(self, option_id: str) -> Optional[Option]:
|
||||
|
@ -75,12 +73,14 @@ class Dish:
|
|||
" -- {}".format(self.description) if self.description else "",
|
||||
_format_tags(self.tags),
|
||||
_format_price(self.price),
|
||||
"\n\t".join(map(_format_type_and_choice, self.choices))
|
||||
"\n\t".join(map(_format_type_and_choice, self.choices)),
|
||||
)
|
||||
|
||||
def price_range(self) -> Tuple[int, int]:
|
||||
return (self.price + self._sum_f_option_prices(min),
|
||||
self.price + self._sum_f_option_prices(max))
|
||||
return (
|
||||
self.price + self._sum_f_option_prices(min),
|
||||
self.price + self._sum_f_option_prices(max),
|
||||
)
|
||||
|
||||
def _sum_f_option_prices(self, f):
|
||||
return sum(
|
||||
|
@ -91,7 +91,9 @@ class Dish:
|
|||
|
||||
|
||||
class Location:
|
||||
def __init__(self, id_, *, name, dishes, osm=None, address=None, telephone=None, website=None):
|
||||
def __init__(
|
||||
self, id_, *, name, dishes, osm=None, address=None, telephone=None, website=None
|
||||
):
|
||||
self.id: str = id_
|
||||
self.name: str = name
|
||||
self.osm: Optional[str] = osm
|
||||
|
@ -114,11 +116,15 @@ class Location:
|
|||
"{2}"
|
||||
).format(
|
||||
self,
|
||||
"".join("\n\t{} {}".format(k, v) for k, v in (
|
||||
("osm", self.osm),
|
||||
("address", self.address),
|
||||
("telephone", self.telephone),
|
||||
("website", self.website),
|
||||
) if v is not None),
|
||||
"\n".join(map(str, self.dishes))
|
||||
"".join(
|
||||
"\n\t{} {}".format(k, v)
|
||||
for k, v in (
|
||||
("osm", self.osm),
|
||||
("address", self.address),
|
||||
("telephone", self.telephone),
|
||||
("website", self.website),
|
||||
)
|
||||
if v is not None
|
||||
),
|
||||
"\n".join(map(str, self.dishes)),
|
||||
)
|
||||
|
|
|
@ -24,7 +24,9 @@ def filter_instance(cls, iterable):
|
|||
# pylint: disable=no-self-use
|
||||
class HldsSemanticActions:
|
||||
def location(self, ast) -> Location:
|
||||
choices = {choice.id: choice for choice in filter_instance(Choice, ast["items_"])}
|
||||
choices = {
|
||||
choice.id: choice for choice in filter_instance(Choice, ast["items_"])
|
||||
}
|
||||
dishes: Iterable[Dish] = filter_instance(Dish, ast["items_"])
|
||||
for dish in dishes:
|
||||
for i, choice in enumerate(dish.choices):
|
||||
|
@ -32,7 +34,9 @@ class HldsSemanticActions:
|
|||
dish.choices[i] = (dish.choices[i][0], deepcopy(choices[choice[1]]))
|
||||
|
||||
# Move the base price to the first single_choice if the dish has a fixed price
|
||||
first_single_choice = first(c[1] for c in dish.choices if c[0] == "single_choice")
|
||||
first_single_choice = first(
|
||||
c[1] for c in dish.choices if c[0] == "single_choice"
|
||||
)
|
||||
price_range = dish.price_range()
|
||||
if dish.price and price_range[0] != price_range[1] and first_single_choice:
|
||||
for option in first_single_choice.options:
|
||||
|
@ -41,7 +45,6 @@ class HldsSemanticActions:
|
|||
|
||||
attributes = {att["key"]: att["value"] for att in ast["attributes"]}
|
||||
|
||||
|
||||
return Location(
|
||||
ast["id"],
|
||||
name=ast["name"],
|
||||
|
@ -64,7 +67,9 @@ class HldsSemanticActions:
|
|||
|
||||
def choice_block(self, ast) -> Choice:
|
||||
if ast["price"] or ast["tags"]:
|
||||
raise SemanticError("Choice blocks cannot have price or tags, put them on each of its options instead")
|
||||
raise SemanticError(
|
||||
"Choice blocks cannot have price or tags, put them on each of its options instead"
|
||||
)
|
||||
|
||||
return Choice(
|
||||
ast["id"],
|
||||
|
@ -76,8 +81,8 @@ class HldsSemanticActions:
|
|||
def indent_choice_block(self, ast) -> Tuple[str, Union[Choice, AST]]:
|
||||
return (
|
||||
(ast["type"], self.choice_block(ast))
|
||||
if ast["kind"] == "declaration" else
|
||||
(ast["type"], ast["id"])
|
||||
if ast["kind"] == "declaration"
|
||||
else (ast["type"], ast["id"])
|
||||
)
|
||||
|
||||
def indent_choice_entry(self, ast) -> Option:
|
||||
|
@ -92,18 +97,18 @@ class HldsSemanticActions:
|
|||
noindent_choice_entry = indent_choice_entry
|
||||
|
||||
def price(self, ast) -> int:
|
||||
return (
|
||||
100 * int(ast["value_unit"]) +
|
||||
(
|
||||
0 if not ast["value_cents"] else
|
||||
10 * int(ast["value_cents"]) if len(ast["value_cents"]) == 1 else
|
||||
int(ast["value_cents"])
|
||||
)
|
||||
return 100 * int(ast["value_unit"]) + (
|
||||
0
|
||||
if not ast["value_cents"]
|
||||
else 10 * int(ast["value_cents"])
|
||||
if len(ast["value_cents"]) == 1
|
||||
else int(ast["value_cents"])
|
||||
)
|
||||
|
||||
def _default(self, ast):
|
||||
return ast
|
||||
|
||||
|
||||
SEMANTICS = HldsSemanticActions()
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import with_statement
|
|||
from logging.config import fileConfig
|
||||
|
||||
from alembic import context
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
|
|
|
@ -22,7 +22,9 @@ class Order(db.Model):
|
|||
|
||||
def __getattr__(self, name):
|
||||
if name == "location":
|
||||
return first(filter(lambda l: l.id == self.location_id, location_definitions))
|
||||
return first(
|
||||
filter(lambda l: l.id == self.location_id, location_definitions)
|
||||
)
|
||||
raise AttributeError()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
@ -37,7 +39,9 @@ class Order(db.Model):
|
|||
Update the location name from the HLDS definition.
|
||||
User should commit after running this to make the change persistent.
|
||||
"""
|
||||
assert self.location_id, "location_id must be configured before updating from HLDS"
|
||||
assert (
|
||||
self.location_id
|
||||
), "location_id must be configured before updating from HLDS"
|
||||
self.location_name = self.location.name
|
||||
|
||||
def group_by_user(self) -> typing.Dict[str, typing.Any]:
|
||||
|
@ -46,17 +50,16 @@ class Order(db.Model):
|
|||
for item in self.items:
|
||||
user = group.get(item.get_name(), dict())
|
||||
user["total"] = user.get("total", 0) + item.price
|
||||
user["to_pay"] = (
|
||||
user.get("to_pay", 0) +
|
||||
item.price if not item.paid else 0
|
||||
)
|
||||
user["to_pay"] = user.get("to_pay", 0) + item.price if not item.paid else 0
|
||||
user["paid"] = user.get("paid", True) and item.paid
|
||||
user["dishes"] = user.get("dishes", []) + [item.dish_name]
|
||||
group[str(item.get_name())] = user
|
||||
|
||||
return group
|
||||
|
||||
def group_by_dish(self, sort_comments=False) -> typing.Dict[str, typing.Dict[str, typing.Any]]:
|
||||
def group_by_dish(
|
||||
self, sort_comments=False
|
||||
) -> typing.Dict[str, typing.Dict[str, typing.Any]]:
|
||||
"Group items of an Order by dish"
|
||||
group: typing.Dict[str, typing.Dict[str, typing.Any]] = dict()
|
||||
for item in self.items:
|
||||
|
|
|
@ -17,9 +17,7 @@ class OrderItem(db.Model):
|
|||
dish_id = db.Column(db.String(64), nullable=True)
|
||||
dish_name = db.Column(db.String(120), nullable=True)
|
||||
price = db.Column(db.Integer, nullable=True)
|
||||
paid = db.Column(
|
||||
db.Boolean, default=False, nullable=True
|
||||
)
|
||||
paid = db.Column(db.Boolean, default=False, nullable=True)
|
||||
comment = db.Column(db.Text(), nullable=True)
|
||||
hlds_data_version = db.Column(db.String(40), nullable=True)
|
||||
|
||||
|
@ -27,8 +25,12 @@ class OrderItem(db.Model):
|
|||
|
||||
def __getattr__(self, name):
|
||||
if name == "dish":
|
||||
location_id = Order.query.filter(Order.id == self.order_id).first().location_id
|
||||
location = first(filter(lambda l: l.id == location_id, location_definitions))
|
||||
location_id = (
|
||||
Order.query.filter(Order.id == self.order_id).first().location_id
|
||||
)
|
||||
location = first(
|
||||
filter(lambda l: l.id == location_id, location_definitions)
|
||||
)
|
||||
if location:
|
||||
return first(filter(lambda d: d.id == self.dish_id, location.dishes))
|
||||
else:
|
||||
|
|
|
@ -7,7 +7,9 @@ from .orderitem import OrderItem
|
|||
class OrderItemChoice(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
choice_id = db.Column(db.String(64), nullable=True)
|
||||
order_item_id = db.Column(db.Integer, db.ForeignKey("order_item.id"), nullable=False)
|
||||
order_item_id = db.Column(
|
||||
db.Integer, db.ForeignKey("order_item.id"), nullable=False
|
||||
)
|
||||
kind = db.Column(db.String(1), nullable=False)
|
||||
name = db.Column(db.String(120), nullable=True)
|
||||
value = db.Column(db.String(120), nullable=True)
|
||||
|
|
|
@ -35,8 +35,7 @@ def post_order_to_webhook(order: Order) -> None:
|
|||
"Function that sends the notification for the order"
|
||||
message = webhook_text(order)
|
||||
if message:
|
||||
webhookthread = WebhookSenderThread(
|
||||
message, app.config["SLACK_WEBHOOK"])
|
||||
webhookthread = WebhookSenderThread(message, app.config["SLACK_WEBHOOK"])
|
||||
webhookthread.start()
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ def main(filenames):
|
|||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
args = sys.argv[1:]
|
||||
if "-h" in args or "--help" in args:
|
||||
print(USAGE.format(sys.argv[0]), file=sys.stderr)
|
||||
|
|
|
@ -10,6 +10,7 @@ if sys.executable != INTERP:
|
|||
|
||||
sys.path.append(os.getcwd())
|
||||
from app import create_app
|
||||
|
||||
application = create_app().app
|
||||
|
||||
# For running on the server with passenger etc
|
||||
|
|
|
@ -9,10 +9,13 @@ def euro_string(value: int) -> str:
|
|||
"""
|
||||
return "€ {}.{:02}".format(*divmod(value, 100))
|
||||
|
||||
|
||||
def price_range_string(price_range, include_upper=False):
|
||||
if price_range[0] == price_range[1]:
|
||||
return euro_string(price_range[0])
|
||||
return ("{}—{}" if include_upper else "from {}").format(*map(euro_string, price_range))
|
||||
return ("{}—{}" if include_upper else "from {}").format(
|
||||
*map(euro_string, price_range)
|
||||
)
|
||||
|
||||
|
||||
def first(iterable: Iterable, default=None):
|
||||
|
|
|
@ -16,6 +16,7 @@ from utils import first
|
|||
from hlds.definitions import location_definitions
|
||||
from hlds.models import Location
|
||||
from models import Order
|
||||
|
||||
# import views
|
||||
from views.order import get_orders
|
||||
|
||||
|
@ -43,7 +44,7 @@ def get_css_dict(css_path):
|
|||
|
||||
# Open the YAML file with all the themes.
|
||||
path = os.path.join(app.root_path, "views/themes.yml")
|
||||
with open(path, 'r') as stream:
|
||||
with open(path, "r") as stream:
|
||||
data = yaml.safe_load(stream)
|
||||
# Build a dictionary from the YAML file with all the themes and their attributes.
|
||||
themes = {}
|
||||
|
@ -57,46 +58,46 @@ def get_css_dict(css_path):
|
|||
|
||||
# Check each theme in the dictionary and return the first one that is "correct"
|
||||
for key, theme in themes.items():
|
||||
if theme['type'] == 'static-date':
|
||||
start_day, start_month = theme['start'].split('/')
|
||||
start_date = datetime(year=current_year, day=int(
|
||||
start_day), month=int(start_month))
|
||||
if theme["type"] == "static-date":
|
||||
start_day, start_month = theme["start"].split("/")
|
||||
start_date = datetime(year=current_year, day=int(start_day), month=int(start_month))
|
||||
|
||||
end_day, end_month = theme['end'].split('/')
|
||||
end_day, end_month = theme["end"].split("/")
|
||||
if int(start_month) > int(end_month):
|
||||
current_year += 1
|
||||
end_date = datetime(
|
||||
year=current_year, day=int(end_day), month=int(end_month))
|
||||
end_date = datetime(year=current_year, day=int(end_day), month=int(end_month))
|
||||
|
||||
if start_date <= current_date <= end_date:
|
||||
path = os.path.join(app.root_path, css_path, theme['file'])
|
||||
path = os.path.join(app.root_path, css_path, theme["file"])
|
||||
themes_dict[key] = path
|
||||
themes_dict['darkmode'] = os.path.join(
|
||||
app.root_path, "static/css/themes/lowPerformance/darkmode.css")
|
||||
themes_dict['lightmode'] = os.path.join(
|
||||
app.root_path, "static/css/themes/lowPerformance/lightmode.css")
|
||||
themes_dict["darkmode"] = os.path.join(
|
||||
app.root_path, "static/css/themes/lowPerformance/darkmode.css"
|
||||
)
|
||||
themes_dict["lightmode"] = os.path.join(
|
||||
app.root_path, "static/css/themes/lowPerformance/lightmode.css"
|
||||
)
|
||||
|
||||
return themes_dict
|
||||
|
||||
|
||||
def css_list():
|
||||
"Generate the list of names of all the currently available themes"
|
||||
if request.cookies.get('performance', '') == 'highPerformance':
|
||||
css_path = 'static/css/themes/highPerformance/'
|
||||
if request.cookies.get("performance", "") == "highPerformance":
|
||||
css_path = "static/css/themes/highPerformance/"
|
||||
else:
|
||||
css_path = 'static/css/themes/lowPerformance/'
|
||||
css_path = "static/css/themes/lowPerformance/"
|
||||
return list(get_css_dict(css_path).keys())
|
||||
|
||||
|
||||
@general_bp.route("/css")
|
||||
def css():
|
||||
"Generate the css"
|
||||
if request.cookies.get('performance', '') == 'highPerformance':
|
||||
css_path = 'static/css/themes/highPerformance/'
|
||||
if request.cookies.get("performance", "") == "highPerformance":
|
||||
css_path = "static/css/themes/highPerformance/"
|
||||
else:
|
||||
css_path = 'static/css/themes/lowPerformance/'
|
||||
css_path = "static/css/themes/lowPerformance/"
|
||||
|
||||
cookie_theme = request.cookies.get('theme', '')
|
||||
cookie_theme = request.cookies.get("theme", "")
|
||||
|
||||
themes_dict = get_css_dict(css_path)
|
||||
|
||||
|
@ -108,7 +109,7 @@ def css():
|
|||
|
||||
f = open(path)
|
||||
response = make_response(f.read())
|
||||
response.headers['Content-Type'] = 'text/css'
|
||||
response.headers["Content-Type"] = "text/css"
|
||||
f.close()
|
||||
return response
|
||||
|
||||
|
@ -136,7 +137,9 @@ def location(location_id) -> str:
|
|||
|
||||
@general_bp.route("/location/<location_id>/<dish_id>")
|
||||
def location_dish(location_id, dish_id) -> str:
|
||||
loc: Optional[Location] = first(filter(lambda l: l.id == location_id, location_definitions))
|
||||
loc: Optional[Location] = first(
|
||||
filter(lambda l: l.id == location_id, location_definitions)
|
||||
)
|
||||
if loc is None:
|
||||
abort(404)
|
||||
dish = loc.dish_by_id(dish_id)
|
||||
|
@ -154,10 +157,10 @@ def location_dish(location_id, dish_id) -> str:
|
|||
"name": o.name,
|
||||
"description": o.description,
|
||||
"price": o.price,
|
||||
"tags": o.tags
|
||||
"tags": o.tags,
|
||||
}
|
||||
for o in c[1].options
|
||||
]
|
||||
],
|
||||
}
|
||||
for c in dish.choices
|
||||
])
|
||||
|
|
|
@ -4,9 +4,19 @@ import typing
|
|||
from datetime import datetime
|
||||
|
||||
from werkzeug.wrappers import Response
|
||||
|
||||
# from flask import current_app as app
|
||||
from flask import (Blueprint, abort, flash, redirect, render_template, request,
|
||||
session, url_for, wrappers)
|
||||
from flask import (
|
||||
Blueprint,
|
||||
abort,
|
||||
flash,
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
session,
|
||||
url_for,
|
||||
wrappers,
|
||||
)
|
||||
from flask_login import current_user, login_required
|
||||
|
||||
from forms import AnonOrderItemForm, OrderForm, OrderItemForm
|
||||
|
@ -57,8 +67,7 @@ def order_from_id(order_id: int, form: OrderForm = None, dish_id=None) -> str:
|
|||
flash("Please login to see this order.", "info")
|
||||
abort(401)
|
||||
if form is None:
|
||||
form = AnonOrderItemForm() if current_user.is_anonymous() \
|
||||
else OrderItemForm()
|
||||
form = AnonOrderItemForm() if current_user.is_anonymous() else OrderItemForm()
|
||||
if order.location:
|
||||
form.populate(order.location)
|
||||
if order.is_closed():
|
||||
|
@ -68,8 +77,14 @@ def order_from_id(order_id: int, form: OrderForm = None, dish_id=None) -> str:
|
|||
|
||||
dish = order.location.dish_by_id(dish_id) if order.location else None
|
||||
|
||||
return render_template("order.html", order=order, form=form,
|
||||
total_price=total_price, debts=debts, dish=dish)
|
||||
return render_template(
|
||||
"order.html",
|
||||
order=order,
|
||||
form=form,
|
||||
total_price=total_price,
|
||||
debts=debts,
|
||||
dish=dish,
|
||||
)
|
||||
|
||||
|
||||
@order_bp.route("/<order_id>/items")
|
||||
|
@ -90,8 +105,7 @@ def items_showcase(order_id: int) -> str:
|
|||
def order_edit(order_id: int) -> typing.Union[str, Response]:
|
||||
"Generate order edit view from id"
|
||||
order = Order.query.filter(Order.id == order_id).first()
|
||||
if current_user.id is not order.courier_id and \
|
||||
not current_user.is_admin():
|
||||
if current_user.id is not order.courier_id and not current_user.is_admin():
|
||||
abort(401)
|
||||
if order is None:
|
||||
abort(404)
|
||||
|
@ -102,8 +116,7 @@ def order_edit(order_id: int) -> typing.Union[str, Response]:
|
|||
order.update_from_hlds()
|
||||
db.session.commit()
|
||||
return redirect(url_for("order_bp.order_from_id", order_id=order.id))
|
||||
return render_template("order_edit.html", form=orderForm,
|
||||
order_id=order_id)
|
||||
return render_template("order_edit.html", form=orderForm, order_id=order_id)
|
||||
|
||||
|
||||
@order_bp.route("/<order_id>/create", methods=["GET", "POST"])
|
||||
|
@ -123,8 +136,7 @@ def order_item_create(order_id: int) -> typing.Any:
|
|||
# If location doesn't exist any more, adding items is nonsensical
|
||||
if not location:
|
||||
abort(404)
|
||||
form = AnonOrderItemForm() if current_user.is_anonymous() \
|
||||
else OrderItemForm()
|
||||
form = AnonOrderItemForm() if current_user.is_anonymous() else OrderItemForm()
|
||||
|
||||
dish_id = form.dish_id.data if form.is_submitted() else request.args.get("dish")
|
||||
if dish_id and not location.dish_by_id(dish_id):
|
||||
|
@ -142,8 +154,14 @@ def order_item_create(order_id: int) -> typing.Any:
|
|||
chosen = [
|
||||
(
|
||||
choice.option_by_id(request.form.get("choice_" + choice.id))
|
||||
if choice_type == "single_choice" else
|
||||
list(ignore_none(request.form.getlist("choice_" + choice.id, type=choice.option_by_id)))
|
||||
if choice_type == "single_choice"
|
||||
else list(
|
||||
ignore_none(
|
||||
request.form.getlist(
|
||||
"choice_" + choice.id, type=choice.option_by_id
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
for (choice_type, choice) in choices
|
||||
]
|
||||
|
@ -151,14 +169,22 @@ def order_item_create(order_id: int) -> typing.Any:
|
|||
|
||||
if dish_was_changed or not all_choices_present:
|
||||
try:
|
||||
user_name = form.user_name.data if form.user_name.validate(form) else None
|
||||
user_name = (
|
||||
form.user_name.data if form.user_name.validate(form) else None
|
||||
)
|
||||
except AttributeError:
|
||||
user_name = None
|
||||
comment = form.comment.data if form.comment.validate(form) else None
|
||||
|
||||
return redirect(url_for("order_bp.order_item_create",
|
||||
order_id=order_id, dish=form.dish_id.data,
|
||||
user_name=user_name, comment=comment))
|
||||
return redirect(
|
||||
url_for(
|
||||
"order_bp.order_item_create",
|
||||
order_id=order_id,
|
||||
dish=form.dish_id.data,
|
||||
user_name=user_name,
|
||||
comment=comment,
|
||||
)
|
||||
)
|
||||
|
||||
# If the form was not submitted (GET request) or the form had errors: show form again
|
||||
if not form.validate_on_submit():
|
||||
|
@ -184,6 +210,7 @@ def order_item_create(order_id: int) -> typing.Any:
|
|||
return option.name
|
||||
except AttributeError:
|
||||
return ", ".join(o.name for o in option if no_text_tag not in o.tags)
|
||||
|
||||
comments = list(ignore_none(_name(option) for option in chosen))
|
||||
if item.comment:
|
||||
comments.append("Comment: " + item.comment)
|
||||
|
@ -198,6 +225,7 @@ def order_item_create(order_id: int) -> typing.Any:
|
|||
return option.price or 0
|
||||
except AttributeError:
|
||||
return sum(o.price or 0 for o in option)
|
||||
|
||||
item.price += sum(_price(option) for option in chosen)
|
||||
|
||||
db.session.add(item)
|
||||
|
@ -216,8 +244,7 @@ def item_paid(order_id: int, item_id: int) -> typing.Optional[Response]:
|
|||
if item.order.courier_id == user_id or current_user.admin:
|
||||
item.paid = True
|
||||
db.session.commit()
|
||||
flash("Paid %s by %s" % (item.dish_name, item.get_name()),
|
||||
"success")
|
||||
flash("Paid %s by %s" % (item.dish_name, item.get_name()), "success")
|
||||
return redirect(url_for("order_bp.order_from_id", order_id=order_id))
|
||||
abort(404)
|
||||
|
||||
|
@ -244,8 +271,7 @@ def items_user_paid(order_id: int, user_name: str) -> typing.Optional[Response]:
|
|||
for item in items:
|
||||
item.paid = True
|
||||
db.session.commit()
|
||||
flash("Paid %d items for %s" %
|
||||
(len(items), item.get_name()), "success")
|
||||
flash("Paid %d items for %s" % (len(items), item.get_name()), "success")
|
||||
return redirect(url_for("order_bp.order_from_id", order_id=order_id))
|
||||
abort(404)
|
||||
|
||||
|
@ -293,7 +319,9 @@ def close_order(order_id: int) -> typing.Optional[Response]:
|
|||
order = Order.query.filter(Order.id == order_id).first()
|
||||
if order is None:
|
||||
abort(404)
|
||||
if (current_user.id == order.courier_id or current_user.is_admin()) and not order.is_closed():
|
||||
if (
|
||||
current_user.id == order.courier_id or current_user.is_admin()
|
||||
) and not order.is_closed():
|
||||
order.stoptime = datetime.now()
|
||||
if order.courier_id == 0 or order.courier_id is None:
|
||||
courier = select_user(order.items)
|
||||
|
@ -332,7 +360,8 @@ def get_orders(expression=None) -> typing.List[Order]:
|
|||
order_list: typing.List[OrderForm] = []
|
||||
if expression is None:
|
||||
expression = (datetime.now() > Order.starttime) & (
|
||||
Order.stoptime > datetime.now()
|
||||
Order.stoptime
|
||||
> datetime.now()
|
||||
# pylint: disable=C0121
|
||||
) | (Order.stoptime == None)
|
||||
if not current_user.is_anonymous():
|
||||
|
@ -340,5 +369,6 @@ def get_orders(expression=None) -> typing.List[Order]:
|
|||
else:
|
||||
order_list = Order.query.filter(
|
||||
# pylint: disable=C0121
|
||||
(expression & (Order.public == True))).all()
|
||||
(expression & (Order.public == True))
|
||||
).all()
|
||||
return order_list
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
"Script containing everything specific to ZeusWPI"
|
||||
import typing
|
||||
|
||||
from flask import (Blueprint, current_app, flash, redirect, request, session,
|
||||
url_for)
|
||||
from flask import Blueprint, current_app, flash, redirect, request, session, url_for
|
||||
from flask_login import login_user
|
||||
from flask_oauthlib.client import OAuth, OAuthException
|
||||
from werkzeug.wrappers import Response
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
print("""============================
|
||||
print(
|
||||
"""============================
|
||||
s5: S5
|
||||
osm https://www.openstreetmap.org/node/3752879366
|
||||
address Krijgslaan 281, 9000 Gent
|
||||
website https://www.ugent.be/student/nl/meer-dan-studeren/resto/restos/restocampussterre.htm
|
||||
============================""")
|
||||
============================"""
|
||||
)
|
||||
|
||||
# Paste menu from https://www.ugent.be/student/nl/meer-dan-studeren/resto/broodjes/overzicht.htm
|
||||
# here
|
||||
MENU = [l.split("\t") for l in """
|
||||
MENU = [
|
||||
l.split("\t")
|
||||
for l in """
|
||||
Spring break Erwten-munt spread, komkommer, radijs, sla, croutons, cocktailsaus € 1,50 € 2,40
|
||||
Groentespread Weekelijks wisselende groentespread € 1,60 € 2,60
|
||||
Brie Brie, honing, pijnboompitten, sla € 1,50 € 2,50
|
||||
|
@ -30,40 +34,44 @@ Maison Ham, kaas, augurk, ei, sla, tomaat, cocktailsaus en mayonaise € 1,60
|
|||
Tropical Ham, kaas, ananas, ei, sla, cocktailsaus € 1,60 € 2,40
|
||||
Toscane Mozzarella, prosciutto ham, sla en tomatensalsa € 1,60 € 2,70
|
||||
Argenteuil Ham, asperge, ei, komkommer, sla, tomaat en mayonaise € 1,50 € 2,40
|
||||
""".strip().split("\n")]
|
||||
""".strip().split(
|
||||
"\n"
|
||||
)
|
||||
]
|
||||
# Sort by price. This fails if price is not always exactly "€ x,xx" but whatever
|
||||
MENU.sort(key=lambda dish: dish[2] + dish[3])
|
||||
|
||||
SANDWICHES = [
|
||||
[ # First price
|
||||
("small_white", "Klein wit "),
|
||||
("small_brown", "Klein bruin"),
|
||||
],
|
||||
[ # Second price
|
||||
[("small_white", "Klein wit "), ("small_brown", "Klein bruin"),], # First price
|
||||
[ # Second price
|
||||
("large_white", "Groot wit "),
|
||||
("large_brown", "Groot bruin"),
|
||||
("quattro", " Quattro "),
|
||||
]
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
def name_to_id(name):
|
||||
return "".join(filter(
|
||||
lambda c: ord("a") <= ord(c) <= ord("z"),
|
||||
name.lower().replace("é", "e")
|
||||
))
|
||||
return "".join(
|
||||
filter(lambda c: ord("a") <= ord(c) <= ord("z"), name.lower().replace("é", "e"))
|
||||
)
|
||||
|
||||
|
||||
for dish in MENU:
|
||||
print()
|
||||
name, description = dish[0], dish[1]
|
||||
prices = [p.replace(",", ".") for p in dish[2:]]
|
||||
|
||||
print("dish sandwich_{}: Broodje {} -- {}".format(name_to_id(name), name, description))
|
||||
print(
|
||||
"dish sandwich_{}: Broodje {} -- {}".format(name_to_id(name), name, description)
|
||||
)
|
||||
print("\tsingle_choice sandwich: Broodje")
|
||||
for sandwiches, price in zip(SANDWICHES, prices):
|
||||
for sw_id, sw_name in sandwiches:
|
||||
print("\t\t{}: {} {}".format(sw_id, sw_name, price))
|
||||
|
||||
print("""
|
||||
print(
|
||||
"""
|
||||
dish yoghurt: Natuuryoghurt € 0.4
|
||||
dish yofu: Plantaardige yofu € 1
|
||||
dish yoghurt_muesli: Yoghurt met muesli € 1
|
||||
|
@ -86,4 +94,5 @@ dish bionade: Bionade € 1.5
|
|||
dish finley: Finley € 1
|
||||
dish iced_coffee: IJskoffie € 2
|
||||
dish iced_tea: IJsthee € 2
|
||||
dish smoothie: Smoothie € 2""")
|
||||
dish smoothie: Smoothie € 2"""
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue