Fix validation and saving for multi_choice, add price range

This commit is contained in:
Midgard 2020-02-24 00:31:14 +01:00
parent 513e495665
commit 1025ade758
Signed by: midgard
GPG key ID: 511C112F1331BBB4
5 changed files with 53 additions and 11 deletions

View file

@ -53,10 +53,17 @@ class OrderItemForm(Form):
comment = StringField("Comment")
submit_button = SubmitField("Submit")
@staticmethod
def format_price_range(price_range):
if price_range[0] == price_range[1]:
return euro_string(price_range[0])
else:
return "from {}".format(euro_string(price_range[0]))
def populate(self, location: Location, dish_id: Optional[str]) -> None:
self.dish_id.choices = [
(i.id, (i.name + ": " + euro_string(i.price)))
for i in location.dishes
(dish.id, (dish.name + ": " + self.format_price_range(dish.price_range())))
for dish in location.dishes
]

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# pylint: disable=too-few-public-methods
from typing import Iterable, List, Mapping, Any, Optional
from typing import Iterable, List, Tuple, Mapping, Any, Optional
from utils import euro_string, first
@ -78,6 +78,17 @@ class Dish:
"\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))
def _sum_f_option_prices(self, f):
return sum(
f(option.price for option in choice.options)
for (choice_type, choice) in self.choices
if choice_type == "single_choice"
)
class Location:
def __init__(self, id_, *, name, dishes, osm=None, address=None, telephone=None, website=None):

View file

@ -8,6 +8,7 @@ from tatsu import parse as tatsu_parse
from tatsu.ast import AST
from tatsu.exceptions import SemanticError
from .models import Location, Choice, Option, Dish
from utils import first
# TODO Use proper way to get resources, see https://stackoverflow.com/a/10935674
@ -29,8 +30,16 @@ class HldsSemanticActions:
if not isinstance(choice[1], Choice):
dish.choices[i] = (dish.choices[i][0], choices[choice[1]])
# Move the base price to the first single choice if there is any
first_single_choice = first(c[1] for c in dish.choices if c[0] == "single_choice")
if dish.price and first_single_choice:
for option in first_single_choice.options:
option.price += dish.price
dish.price = 0
attributes = {att["key"]: att["value"] for att in ast["attributes"]}
return Location(
ast["id"],
name=ast["name"],
@ -46,8 +55,8 @@ class HldsSemanticActions:
ast["id"],
name=ast["name"],
description=ast["description"],
price=ast["price"] if ast["price"] else 0,
tags=ast["tags"] if ast["tags"] else [],
price=ast["price"] or 0,
tags=ast["tags"] or [],
choices=ast["choices"],
)
@ -74,7 +83,7 @@ class HldsSemanticActions:
ast["id"],
name=ast["name"],
description=ast["description"],
price=ast["price"] if ast["price"] else 0,
price=ast["price"] or 0,
tags=ast["tags"],
)

View file

@ -19,3 +19,6 @@ def first(iterable: Iterable, default=None):
except StopIteration:
return default
def ignore_none(iterable: Iterable):
return filter(lambda x: x is not None, iterable)

View file

@ -13,6 +13,7 @@ from forms import AnonOrderItemForm, OrderForm, OrderItemForm
from models import Order, OrderItem, User, db
from hlds.definitions import location_definitions
from notification import post_order_to_webhook
from utils import ignore_none
order_bp = Blueprint("order_bp", "order")
@ -104,6 +105,11 @@ def order_edit(order_id: int) -> typing.Union[str, Response]:
return render_template("order_edit.html", form=orderForm,
order_id=order_id)
def _name(option):
try:
return option.name
except AttributeError:
return ", ".join(o.name for o in option)
@order_bp.route("/<order_id>/create", methods=["GET", "POST"])
def order_item_create(order_id: int) -> typing.Any:
@ -141,10 +147,14 @@ def order_item_create(order_id: int) -> typing.Any:
# The form's validation tests that dish_id is valid and gives a friendly error if it's not
choices = location.dish_by_id(form.dish_id.data).choices
chosen = [
choice.option_by_id(request.form.get("choice_" + choice.id))
for (_choice_type, choice) in choices
(
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)))
)
for (choice_type, choice) in choices
]
all_choices_present = all(chosen)
all_choices_present = all(x is not None for x in chosen)
if not all_choices_present:
return redirect(url_for("order_bp.order_item_create",
order_id=order_id, dish=form.dish_id.data))
@ -158,8 +168,10 @@ def order_item_create(order_id: int) -> typing.Any:
session["anon_name"] = item.name
# XXX Temporary
chosen_text = "; ".join(option.name for option in chosen)
item.comment = chosen_text + "; Comment: " + item.comment if item.comment else chosen_text
comments = [_name(option) for option in chosen if option]
if item.comment:
comments.append("Comment: " + item.comment)
item.comment = "; ".join(comments)
item.update_from_hlds()
db.session.add(item)