From 83b78b36848cdcd367563873ecd799304882ed4f Mon Sep 17 00:00:00 2001 From: Alexis M Date: Mon, 16 Sep 2019 23:09:23 +0200 Subject: [PATCH] Add support for product referents --- copanier/__init__.py | 12 ++++----- copanier/imports.py | 26 +++++++++++-------- copanier/models.py | 22 +++++++++++----- copanier/reports.py | 17 ++++++++---- .../includes/modal_import_products.html | 16 +++++++++--- 5 files changed, 62 insertions(+), 31 deletions(-) diff --git a/copanier/__init__.py b/copanier/__init__.py index 96090a2..75fc2a8 100644 --- a/copanier/__init__.py +++ b/copanier/__init__.py @@ -301,6 +301,9 @@ async def create_delivery(request, response): response.redirect = f"/livraison/{delivery.id}" + + + @app.route("/livraison/{id}/importer/produits", methods=["POST"]) @staff_only async def import_products(request, response, id): @@ -309,12 +312,9 @@ async def import_products(request, response, id): data = request.files.get("data") error_path = f"/livraison/{delivery.id}/edit" - if data.filename.endswith((".csv", ".xlsx")): + if data.filename.endswith(".xlsx"): try: - if data.filename.endswith(".csv"): - imports.products_from_csv(delivery, data.read().decode()) - else: - imports.products_from_xlsx(delivery, data) + imports.products_and_producers_from_xlsx(delivery, data) except ValueError as err: message = f"Impossible d'importer le fichier. {err.args[0]}" response.message(message, status="error") @@ -324,7 +324,7 @@ async def import_products(request, response, id): response.message("Format de fichier inconnu", status="error") response.redirect = error_path return - response.message("Les produits de la livraison ont bien été mis à jour!") + response.message("Les produits et producteur⋅ice⋅s ont bien été mis à jour!") response.redirect = f"/livraison/{delivery.id}" diff --git a/copanier/imports.py b/copanier/imports.py index 115fc6a..d9f1afd 100644 --- a/copanier/imports.py +++ b/copanier/imports.py @@ -9,15 +9,15 @@ from .models import Product, Producer PRODUCT_FIELDS = {"ref", "name", "price"} -PRODUCER_FIELDS = {"id", "name"} +PRODUCER_FIELDS = {"id"} def append_list(field, item): - return field.append(item) + field.append(item) def append_dict(field, item): - return field(item.id, item) + field[item.id] = item def items_from_xlsx(data, items, model_class, required_fields, append_method): @@ -25,7 +25,7 @@ def items_from_xlsx(data, items, model_class, required_fields, append_method): raise ValueError headers = data[0] if not set(headers) >= required_fields: - raise ValueError(f"Colonnes obligatoires: {', '.join(required_fields)}") + raise ValueError(f"Colonnes obligatoires: {', '.join(required_fields)}.") for row in data[1:]: raw = {k: v for k, v in dict(zip(headers, row)).items() if v} try: @@ -37,15 +37,19 @@ def items_from_xlsx(data, items, model_class, required_fields, append_method): def products_and_producers_from_xlsx(delivery, data): if not isinstance(data, Workbook): - try: - data = load_workbook(data) - except BadZipFile: - raise ValueError("Impossible de lire le fichier") + try: + data = load_workbook(data) + except BadZipFile: + raise ValueError("Impossible de lire le fichier") sheet_names = data.get_sheet_names() + if len(sheet_names) != 2: + raise ValueError("Le fichier doit comporter deux onglets.") # First, get the products data from the first tab. - delivery.products = items_from_xlsx(list(data.active.values), [], Products, PRODUCT_FIELDS, append_list) - + products_sheet = data.get_sheet_by_name(sheet_names[0]) + delivery.products = items_from_xlsx(list(products_sheet.values), [], Product, PRODUCT_FIELDS, append_list) + # Then import producers info - delivery.producers = items_from_xlsx(list(data.active.values), {}, Producer, PRODUCER_FIELDS, append_dict) + producers_sheet = data.get_sheet_by_name(sheet_names[1]) + delivery.producers = items_from_xlsx(list(producers_sheet.values), {}, Producer, PRODUCER_FIELDS, append_dict) delivery.persist() \ No newline at end of file diff --git a/copanier/models.py b/copanier/models.py index 9769201..3c9f69b 100644 --- a/copanier/models.py +++ b/copanier/models.py @@ -82,6 +82,7 @@ class PersistedBase(Base): return Path(config.DATA_ROOT) / cls.__root__ + @dataclass class Person(Base): email: str @@ -149,6 +150,14 @@ class Groups(PersistedBase): def init_fs(cls): cls.get_root().mkdir(parents=True, exist_ok=True) +@dataclass +class Producer(Base): + id: str + referent: str = "" + contact: str = "" + location: str = "" + + @dataclass class Product(Base): name: str @@ -230,6 +239,7 @@ class Delivery(PersistedBase): instructions: str = "" where: str = "Marché de la Briche" products: List[Product] = field(default_factory=list) + producers: Dict[str, Producer] = field(default_factory=dict) orders: Dict[str, Order] = field(default_factory=dict) infos_url: str = "" @@ -255,13 +265,13 @@ class Delivery(PersistedBase): def total(self): return round(sum(o.total(self.products) for o in self.orders.values()), 2) - @property - def producers(self): - return list(set([p.producer for p in self.products])) + # @property + # def producers(self): + # return list(set([p.producer for p in self.products])) - @property - def has_multiple_producers(self): - return len(self.producers) > 1 + # @property + # def has_multiple_producers(self): + # return len(self.producers) > 1 @property def is_open(self): diff --git a/copanier/reports.py b/copanier/reports.py index 231ba09..ec63083 100644 --- a/copanier/reports.py +++ b/copanier/reports.py @@ -3,7 +3,7 @@ from dataclasses import fields as get_fields from openpyxl import Workbook from openpyxl.writer.excel import save_virtual_workbook -from .models import Product +from .models import Product, Producer def summary_for_products(wb, title, delivery, total=None, products=None): if products == None: @@ -87,10 +87,17 @@ def products(delivery): wb = Workbook() ws = wb.active ws.title = f"{delivery.name} produits" - fields = [f.name for f in get_fields(Product)] - ws.append(fields) + product_fields = [f.name for f in get_fields(Product)] + ws.append(product_fields) for product in delivery.products: - ws.append([getattr(product, field) for field in fields]) + ws.append([getattr(product, field) for field in product_fields]) + + producer_sheet = wb.create_sheet(f"producteur⋅ice⋅s et référent⋅e⋅s") + producer_fields = [f.name for f in get_fields(Producer)] + producer_sheet.append(producer_fields) + for producer in delivery.producers.values(): + producer_sheet.append([getattr(producer, field) for field in producer_fields]) + return save_virtual_workbook(wb) @@ -103,4 +110,4 @@ def balance(delivery): ws.append( [email, order.total(delivery.products), "oui" if order.paid else "non"] ) - return save_virtual_workbook(wb) + return save_virtual_workbook(wb) \ No newline at end of file diff --git a/copanier/templates/includes/modal_import_products.html b/copanier/templates/includes/modal_import_products.html index ed71105..4a8e7f5 100644 --- a/copanier/templates/includes/modal_import_products.html +++ b/copanier/templates/includes/modal_import_products.html @@ -3,9 +3,10 @@ {% block modal_label %} Importer les produits{% endblock modal_label %} {% block modal_body %}

Importer des produits

-

Formats pris en charge: xlsx, csv

+

Format pris en charge: xlsx

- Détails des colonnes +

Le tableur doit contenir deux onglets, le premier avec les produits, le second avec les producteurs.

+ Détails des colonnes produits
ref
Référence unique du produit (permet de mettre à jour les produits en cours de commande ou d'importer des commandes individuelles).
@@ -26,9 +27,18 @@
img
Une URL éventuelle pointant sur une image du produit (attention, utiliser seulement des liens https).
+ Détails des colonnes producteur +
+
id
+
Nom du producteur (doit être le même que le premier onglet).
+
referent
+
Le nom du ou de la référent⋅e
+
contact
+
Un moyen de contacter le⋅a product⋅eur⋅rice
+
- +
{% endblock modal_body %}