From b3adffb8f75b07005841292d50179d2bc3b09c4b Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Mon, 18 Mar 2019 00:11:27 +0100 Subject: [PATCH] Minimal POC --- kaba/__init__.py | 49 ++++++++++++++++++++---- kaba/base.py | 66 ++++++++++++++++++++------------- kaba/templates/home.html | 1 + kaba/templates/order.html | 37 ++++++++++++------ kaba/templates/place_order.html | 20 ++++++++++ tests/test_models.py | 6 +++ 6 files changed, 136 insertions(+), 43 deletions(-) create mode 100644 kaba/templates/place_order.html diff --git a/kaba/__init__.py b/kaba/__init__.py index eff3d3b..194f574 100644 --- a/kaba/__init__.py +++ b/kaba/__init__.py @@ -71,14 +71,23 @@ class Person(Document): class ProductOrder(Document): - ref = Str() wanted = Int() ordered = Int() class PersonOrder(Document): person = Str() - products = Array(ProductOrder) + products = Mapping(str, ProductOrder) + + def get_quantity(self, product): + choice = self.products.get(product.ref) + return choice.wanted if choice else 0 + + def total(self, products): + products = {p.ref: p for p in products} + return round( + sum(p.wanted * products[ref].price for ref, p in self.products.items()), 2 + ) class Order(Document): @@ -87,7 +96,12 @@ class Order(Document): where = Str() producer = Reference(Producer, required=True) products = Array(Product) - orders = Mapping(Str, PersonOrder) + orders = Mapping(str, PersonOrder) + + def product_wanted(self, product): + return round( + sum([po.products[product.ref].wanted for po in self.orders.values()]) + ) app = Roll() @@ -110,12 +124,33 @@ async def home(request, response): response.html("home.html", {"orders": Order.find()}) -@app.route("/commande/{order_id}", methods=["GET"]) -async def get_order(request, response, order_id): +@app.route("/commande/{order_id}/total", methods=["GET"]) +async def view_order(request, response, order_id): order = Order.find_one(_id=ObjectId(order_id)) + total = round(sum(po.total(order.products) for po in order.orders.values()), 2) response.html( "order.html", - {"order": order, "person": request.query.get("email"), "person_order": None}, + { + "order": order, + "producer": Producer.find_one(_id=order.producer), + "total": total, + }, + ) + + +@app.route("/commande/{order_id}", methods=["GET"]) +async def order_form(request, response, order_id): + order = Order.find_one(_id=ObjectId(order_id)) + email = request.query.get("email") + person_order = order.orders.get(email) + response.html( + "place_order.html", + { + "order": order, + "person": email, + "person_order": person_order, + "producer": Producer.find_one(_id=order.producer), + }, ) @@ -128,7 +163,7 @@ async def place_order(request, response, order_id): for product in order.products: quantity = form.int(product.ref, 0) if quantity: - person_order.products.append(ProductOrder(ref=product.ref, wanted=quantity)) + person_order.products[product.ref] = ProductOrder(wanted=quantity) if not order.orders: order.orders = {} order.orders[email] = person_order diff --git a/kaba/base.py b/kaba/base.py index 846d8e1..0034d34 100644 --- a/kaba/base.py +++ b/kaba/base.py @@ -29,12 +29,16 @@ class Field: if obj is None: return self value = obj.get(self.name) - return value + if value is None and self.default is not None: + if callable(self.default): + value = self.default() + else: + value = self.default + self.__set__(obj, value) + return obj.get(self.name) def __set__(self, obj, value): - print("set", value, id(value)) value = self.coerce(value) - print("set after", value, id(value)) obj[self.name] = value @@ -51,7 +55,8 @@ class Int(Field): class Datetime(Field): - def coerce(self, value): + @staticmethod + def coerce(value): if isinstance(value, datetime): return value if isinstance(value, int): @@ -59,7 +64,8 @@ class Datetime(Field): class Email(Field): - def coerce(self, value): + @staticmethod + def coerce(value): # TODO proper validation if "@" not in value: raise ValueError(f"Invalid value for email: {value}") @@ -67,8 +73,8 @@ class Email(Field): class Reference(Field): - - def coerce(self, value): + @staticmethod + def coerce(value): if isinstance(value, dict): value = value["_id"] return ObjectId(value) @@ -83,22 +89,21 @@ class Dict(Field): class Mapping(Field): - def __init__(self, key_field, value_field, *args, **kwargs): - self.key_field = key_field - self.value_field = value_field - return super().__init__(*args, **kwargs) + def __init__(self, key_type, value_type, *args, **kwargs): + self.key_type = key_type + self.value_type = value_type + kwargs["default"] = dict - def coerce(self, value): - print("coerce raw", value, id(value)) - if value is None: - value = {} - if not isinstance(value, dict): - raise ValueError(f"{value} is not a dict") - print("coerce", value, id(value)) - return { - self.key_field.coerce(k): self.value_field.coerce(v) - for k, v in value.items() - } + def coerce(value): + if value is None: + value = {} + if not isinstance(value, dict): + raise ValueError(f"{value} is not a dict") + # TODO coerce in-place. + return {key_type(k): value_type(v) for k, v in value.items()} + + self.coerce = coerce + return super().__init__(*args, **kwargs) class Array(Field): @@ -111,11 +116,11 @@ class Array(Field): return self value = obj.get(self.name) if value is None: - value = [] - self.__set__(value) - return value + self.__set__(obj, value) + return obj[self.name] def __set__(self, obj, value): + # TODO do not replace reference. obj[self.name] = [self.coerce(v) for v in value or []] @@ -135,10 +140,21 @@ class Document(dict, metaclass=MetaDocument): # def __repr__(self): # return f"<{self.__class__.__name__} {self._id}>" + def __init__(self, data=None, **attrs): + if data: + for key, value in data.items(): + setattr(self, key, value) + for key, value in attrs.items(): + setattr(self, key, value) + @property def _id(self): return self["_id"] + @_id.setter + def _id(self, value): + self["_id"] = value + def insert_one(self): self.collection.insert_one(self) return self diff --git a/kaba/templates/home.html b/kaba/templates/home.html index 70d493f..67dfc06 100644 --- a/kaba/templates/home.html +++ b/kaba/templates/home.html @@ -10,5 +10,6 @@ + Résumé de la commande {% endfor %} {% endblock body %} diff --git a/kaba/templates/order.html b/kaba/templates/order.html index 2a732b6..3ac47d4 100644 --- a/kaba/templates/order.html +++ b/kaba/templates/order.html @@ -1,18 +1,33 @@ {% extends "base.html" %} {% block body %} -

Producteur: {{ order.producer }}

+

< Commandes

+

Producteur: {{ producer.name }}

Lieu: {{ order.where }}

Date: {{ order.when }}

-

Commande pour {{ person }}

-
- - - {% for product in order.products %} - +
ProduitPrixQuantité
{{ product.name }}{{ product.price }} €
+ + + + {% for email, person_order in order.orders.items() %} + {% endfor %} -
ProduitPrix{{ email }}
- - -
+ Total + + {% for product in order.products %} + + {{ product.name }} + {{ product.price }} € + {% for email, person_order in order.orders.items() %} + {% if product.ref in person_order.products %} + {{ person_order.products[product.ref].wanted }} + {% else %} + — + {% endif %} + {% endfor %} + {{ order.product_wanted(product) }} + + {% endfor %} + +

Total: {{ total }} €

{% endblock body %} diff --git a/kaba/templates/place_order.html b/kaba/templates/place_order.html new file mode 100644 index 0000000..2874721 --- /dev/null +++ b/kaba/templates/place_order.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} + +{% block body %} +

< Commandes

+

Producteur: {{ producer.name }}

+

Lieu: {{ order.where }}

+

Date: {{ order.when }}

+

Commande de «{{ person }}»

+
+ + + {% for product in order.products %} + + {% endfor %} +
ProduitPrixQuantité
{{ product.name }}{{ product.price }} €
+

Total: {{ person_order.total(order.products) if person_order else 0 }} €

+ + +
+{% endblock body %} diff --git a/tests/test_models.py b/tests/test_models.py index d4c3d16..81f21f9 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -15,3 +15,9 @@ def test_can_create_order(): order.insert_one() retrieved = Order.find_one(_id=order._id) assert retrieved.products[0].name == "riz" + + +def test_can_update_order_products(): + order = Order() + order.products.append(Product(name="riz", price="2.4")) + assert len(order.products) == 1