Add own logic and form elements
Bypass WTForms and use manually written <select> and all that.
This commit is contained in:
parent
f900c85931
commit
513e495665
4 changed files with 45 additions and 50 deletions
25
app/forms.py
25
app/forms.py
|
@ -50,8 +50,6 @@ class OrderItemForm(Form):
|
||||||
"New Item in an Order"
|
"New Item in an Order"
|
||||||
# pylint: disable=R0903
|
# pylint: disable=R0903
|
||||||
dish_id = SelectField("Dish")
|
dish_id = SelectField("Dish")
|
||||||
single_choices = FieldList(SelectField())
|
|
||||||
multi_choices = FieldList(SelectMultipleField())
|
|
||||||
comment = StringField("Comment")
|
comment = StringField("Comment")
|
||||||
submit_button = SubmitField("Submit")
|
submit_button = SubmitField("Submit")
|
||||||
|
|
||||||
|
@ -60,29 +58,6 @@ class OrderItemForm(Form):
|
||||||
(i.id, (i.name + ": " + euro_string(i.price)))
|
(i.id, (i.name + ": " + euro_string(i.price)))
|
||||||
for i in location.dishes
|
for i in location.dishes
|
||||||
]
|
]
|
||||||
dish = location.dish_by_id(dish_id) if dish_id else None
|
|
||||||
if dish:
|
|
||||||
self.add_choices_for(dish)
|
|
||||||
|
|
||||||
def add_choices_for(self, dish: Dish):
|
|
||||||
for (choice_type, choice) in dish.choices:
|
|
||||||
if choice_type == "single_choice":
|
|
||||||
field = self.single_choices.append_entry(choice.name)
|
|
||||||
elif choice_type == "multi_choice":
|
|
||||||
field = self.multi_choices.append_entry(choice.name)
|
|
||||||
else:
|
|
||||||
assert False, "Unsupported choice type"
|
|
||||||
field.label.text = choice.name
|
|
||||||
field.choices = self.options_for(choice)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def options_for(choice: Choice):
|
|
||||||
return [
|
|
||||||
(c.id, (c.name +
|
|
||||||
(" (" + c.description + ")" if c.description else "") +
|
|
||||||
(": +" + euro_string(c.price) if c.price else "")))
|
|
||||||
for c in choice.options
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class AnonOrderItemForm(OrderItemForm):
|
class AnonOrderItemForm(OrderItemForm):
|
||||||
|
|
|
@ -54,6 +54,9 @@ class Choice:
|
||||||
"\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]:
|
||||||
|
return first(filter(lambda o: o.id == option_id, self.options))
|
||||||
|
|
||||||
|
|
||||||
class Dish:
|
class Dish:
|
||||||
def __init__(self, id_, *, name, description, price, tags, choices):
|
def __init__(self, id_, *, name, description, price, tags, choices):
|
||||||
|
|
|
@ -52,26 +52,32 @@
|
||||||
{{ form.dish_id(class='form-control select') }}
|
{{ form.dish_id(class='form-control select') }}
|
||||||
{{ util.render_form_field_errors(form.dish_id) }}
|
{{ util.render_form_field_errors(form.dish_id) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if dish and dish.choices %}
|
||||||
|
{% for (choice_type, choice) in dish.choices %}
|
||||||
|
<div class="form-group select2-container select2">
|
||||||
|
<label class="control-label" for="choice_{{ choice.id }}">{{ choice.name }}</label><br/>
|
||||||
|
<select
|
||||||
|
{{ "multiple=multiple" if choice_type=="multi_choice" else "required=required" }}
|
||||||
|
name="choice_{{ choice.id }}"
|
||||||
|
class="form-control select">
|
||||||
|
{% for option in choice.options %}
|
||||||
|
<option value="{{ option.id }}">
|
||||||
|
{{ option.name }}{{ ": " + option.price|euro if option.price else "" }}
|
||||||
|
{{ " (" + option.description + ")" if option.description else "" }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="form-group {{ 'has-errors' if form.dish_id.errors }}">
|
<div class="form-group {{ 'has-errors' if form.dish_id.errors }}">
|
||||||
{{ form.comment.label(class='control-label') }}<br>
|
{{ form.comment.label(class='control-label') }}<br>
|
||||||
{{ form.comment(class='form-control', placeholder='Fill in comment, when applicable') }}
|
{{ form.comment(class='form-control', placeholder='Fill in comment, when applicable') }}
|
||||||
{{ util.render_form_field_errors(form.comment) }}
|
{{ util.render_form_field_errors(form.comment) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% for choice_field in form.single_choices %}
|
|
||||||
<div class="form-group {{ 'has-errors' if choice_field }}">
|
|
||||||
{{ choice_field.label(class='control-label') }}<br>
|
|
||||||
{{ choice_field(class='form-control') }}
|
|
||||||
{{ util.render_form_field_errors(choice_field) }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% for choice_field in form.multi_choices %}
|
|
||||||
<div class="form-group {{ 'has-errors' if choice_field }}">
|
|
||||||
{{ choice_field.label(class='control-label') }}<br>
|
|
||||||
{{ choice_field(class='form-control') }}
|
|
||||||
{{ util.render_form_field_errors(choice_field) }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% if current_user.is_anonymous() %}
|
{% if current_user.is_anonymous() %}
|
||||||
<div class="form-group{{ ' has-error' if form.name.errors }}{{ ' required' if form.name.flags.required }}">
|
<div class="form-group{{ ' has-error' if form.name.errors }}{{ ' required' if form.name.flags.required }}">
|
||||||
{{ form.name.label(class='control-label') }}
|
{{ form.name.label(class='control-label') }}
|
||||||
|
|
|
@ -47,7 +47,7 @@ def order_create() -> typing.Union[str, Response]:
|
||||||
|
|
||||||
|
|
||||||
@order_bp.route("/<order_id>")
|
@order_bp.route("/<order_id>")
|
||||||
def order_from_id(order_id: int, form: OrderForm = None) -> str:
|
def order_from_id(order_id: int, form: OrderForm = None, dish_id=None) -> str:
|
||||||
"Generate order view from id"
|
"Generate order view from id"
|
||||||
order = Order.query.filter(Order.id == order_id).first()
|
order = Order.query.filter(Order.id == order_id).first()
|
||||||
if order is None:
|
if order is None:
|
||||||
|
@ -64,8 +64,11 @@ def order_from_id(order_id: int, form: OrderForm = None) -> str:
|
||||||
form = None
|
form = None
|
||||||
total_price = sum([o.price for o in order.items])
|
total_price = sum([o.price for o in order.items])
|
||||||
debts = sum([o.price for o in order.items if not o.paid])
|
debts = sum([o.price for o in order.items if not o.paid])
|
||||||
|
|
||||||
|
dish = order.location.dish_by_id(dish_id) if order.location else None
|
||||||
|
|
||||||
return render_template("order.html", order=order, form=form,
|
return render_template("order.html", order=order, form=form,
|
||||||
total_price=total_price, debts=debts)
|
total_price=total_price, debts=debts, dish=dish)
|
||||||
|
|
||||||
|
|
||||||
@order_bp.route("/<order_id>/items")
|
@order_bp.route("/<order_id>/items")
|
||||||
|
@ -122,26 +125,29 @@ def order_item_create(order_id: int) -> typing.Any:
|
||||||
form = AnonOrderItemForm() if current_user.is_anonymous() \
|
form = AnonOrderItemForm() if current_user.is_anonymous() \
|
||||||
else OrderItemForm()
|
else OrderItemForm()
|
||||||
|
|
||||||
dish_id = form.dish_id.data if form.is_submitted() else request.args.get("dish")
|
dish_id_in_url = request.args.get("dish")
|
||||||
|
dish_id = form.dish_id.data if form.is_submitted() else dish_id_in_url
|
||||||
if dish_id and not location.dish_by_id(dish_id):
|
if dish_id and not location.dish_by_id(dish_id):
|
||||||
abort(404)
|
abort(404)
|
||||||
|
form.dish_id.data = dish_id
|
||||||
form.populate(current_order.location, dish_id)
|
form.populate(current_order.location, dish_id)
|
||||||
|
|
||||||
if not form.validate_on_submit():
|
# If the form was not submitted (GET request), the form had errors, or the dish was changed: show form again
|
||||||
return order_from_id(order_id, form=form)
|
if not form.validate_on_submit() or (dish_id_in_url and dish_id_in_url != dish_id):
|
||||||
|
return order_from_id(order_id, form=form, dish_id=dish_id)
|
||||||
|
|
||||||
# Form was submitted and is valid
|
# Form was submitted and is valid
|
||||||
|
|
||||||
# The form's validation tests that dish_id is valid and gives a friendly error if it's not
|
# The form's validation tests that dish_id is valid and gives a friendly error if it's not
|
||||||
form_data = form.data
|
choices = location.dish_by_id(form.dish_id.data).choices
|
||||||
choices = location.dish_by_id(form_data["dish_id"]).choices
|
chosen = [
|
||||||
all_choices_present = all(
|
choice.option_by_id(request.form.get("choice_" + choice.id))
|
||||||
("choice_" + choice.id) in form_data
|
|
||||||
for (_choice_type, choice) in choices
|
for (_choice_type, choice) in choices
|
||||||
)
|
]
|
||||||
|
all_choices_present = all(chosen)
|
||||||
if not all_choices_present:
|
if not all_choices_present:
|
||||||
return redirect(url_for("order_bp.order_item_create",
|
return redirect(url_for("order_bp.order_item_create",
|
||||||
order_id=order_id, dish=form_data["dish_id"]))
|
order_id=order_id, dish=form.dish_id.data))
|
||||||
|
|
||||||
item = OrderItem()
|
item = OrderItem()
|
||||||
form.populate_obj(item)
|
form.populate_obj(item)
|
||||||
|
@ -150,6 +156,11 @@ def order_item_create(order_id: int) -> typing.Any:
|
||||||
item.user_id = current_user.id
|
item.user_id = current_user.id
|
||||||
else:
|
else:
|
||||||
session["anon_name"] = item.name
|
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
|
||||||
|
|
||||||
item.update_from_hlds()
|
item.update_from_hlds()
|
||||||
db.session.add(item)
|
db.session.add(item)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
Loading…
Reference in a new issue