From 3946b1a6b4c174cfc26a9ca0771a49f4d75890ad Mon Sep 17 00:00:00 2001 From: Laetitia Getti Date: Thu, 20 Jul 2023 14:01:39 +0200 Subject: [PATCH] generate pdf list with weasyprint --- .../templates/order/grouped_order_sheet.html | 87 +++++++++---------- la_chariotte/order/tests/test_views.py | 15 ++-- la_chariotte/order/urls.py | 2 +- la_chariotte/order/views.py | 51 +++++------ la_chariotte/settings.py | 2 +- la_chariotte/static/css/app.css | 23 +++++ requirements.txt | 2 + 7 files changed, 103 insertions(+), 79 deletions(-) diff --git a/la_chariotte/order/templates/order/grouped_order_sheet.html b/la_chariotte/order/templates/order/grouped_order_sheet.html index 4b8f5bc..117d2f6 100644 --- a/la_chariotte/order/templates/order/grouped_order_sheet.html +++ b/la_chariotte/order/templates/order/grouped_order_sheet.html @@ -3,57 +3,59 @@ - {{ name }} - Liste des commandes + {{ grouped_order.name }} - Liste des commandes -

- {{ name }} - {{ delivery_date }} -

+

+ {{ grouped_order.name }} - {{ grouped_order.delivery_date }} +

{% if items %} @@ -69,12 +71,13 @@ - + {% for item in items %} - {% endfor %} + @@ -83,21 +86,21 @@ {{ item.ordered_nb }} {% endfor %} - + {% for order, ordered_items in orders_dict.items %} - {% for ordered_item in ordered_items %} - {% endfor %} - {% endfor %} @@ -106,11 +109,5 @@ Aucun produit n'a été commandé {% endif %} - diff --git a/la_chariotte/order/tests/test_views.py b/la_chariotte/order/tests/test_views.py index 1940b19..5bb50c1 100644 --- a/la_chariotte/order/tests/test_views.py +++ b/la_chariotte/order/tests/test_views.py @@ -1132,7 +1132,7 @@ class TestItemCreateView: class TestGroupedOrderSheetView: def test_get__not_orga(self, client_log, other_user): - """A user that is not organiszer of the GO accesses the sheet view. + """A user that is not organizer of the GO accesses the sheet view. They get a 403 error""" grouped_order = create_grouped_order( days_before_delivery_date=5, @@ -1149,7 +1149,7 @@ class TestGroupedOrderSheetView: response = client_log.get(generate_sheet_url) assert response.status_code == 403 - def test_get__not_orga(self, client, other_user): + def test_get__anonymous(self, client, other_user): """An anonymous user accesses the sheet view. They get redirected to login page""" grouped_order = create_grouped_order( @@ -1184,14 +1184,15 @@ class TestGroupedOrderSheetView: ) response = client_log.get(generate_sheet_url) assert response.status_code == 200 - assert response.context["name"] == "gr order test" - assert response.context["delivery_date"] == grouped_order.delivery_date + assert response.context["grouped_order"] == grouped_order assert response.context["items"].count() == 0 + assert len(response.context["orders_dict"]) == 0 + + # we order some items in the grouped order order = order_items_in_grouped_order(grouped_order) response = client_log.get(generate_sheet_url) assert response.status_code == 200 - assert response.context["name"] == "gr order test" - assert response.context["delivery_date"] == grouped_order.delivery_date + assert response.context["grouped_order"] == grouped_order assert response.context["items"].count() == 2 assert response.context["orders_dict"][order] == [3, 2] - assert response.context["total_price"] == 24 + assert response.context["grouped_order"].total_price == 24 diff --git a/la_chariotte/order/urls.py b/la_chariotte/order/urls.py index 11df9b9..f88036d 100644 --- a/la_chariotte/order/urls.py +++ b/la_chariotte/order/urls.py @@ -37,7 +37,7 @@ urlpatterns = [ ), path( "/gerer/imprimer", - views.GroupedOrderSheetView.as_view(), + views.DownloadGroupedOrderSheetView.as_view(), name="grouped_order_sheet", ), ] diff --git a/la_chariotte/order/views.py b/la_chariotte/order/views.py index 61cafb0..2e6562c 100644 --- a/la_chariotte/order/views.py +++ b/la_chariotte/order/views.py @@ -8,6 +8,8 @@ from django.template.loader import get_template from django.urls import reverse, reverse_lazy from django.utils import timezone from django.views import generic +from django_weasyprint import WeasyTemplateResponseMixin +from django_weasyprint.views import WeasyTemplateResponse, WeasyTemplateView from xhtml2pdf import pisa from .forms import GroupedOrderForm, ItemCreateForm @@ -266,11 +268,21 @@ class OrderDetailView(generic.DetailView): model = Order -class GroupedOrderSheetMixin: - """Mixin for grouped order info export (pdf sheet and csv)""" +class GroupedOrderSheetView(UserPassesTestMixin, generic.DetailView): + """View for gathering information about the groupedorder, in order to download it + in the DownloadGroupedOrderSheetView""" - def get_grouped_order_infos(self, grouped_order_id): - grouped_order = get_object_or_404(GroupedOrder, id=grouped_order_id) + model = GroupedOrder + template_name = "order/grouped_order_sheet.html" + context_object_name = "grouped_order" + + def test_func(self): + """Accessible only if the requesting user is the grouped order organizer""" + return self.get_object().orga == self.request.user + + def get_context_data(self, **kwargs): + context = super(GroupedOrderSheetView, self).get_context_data(**kwargs) + grouped_order = self.get_object() # Get ordered items items = grouped_order.item_set.filter(ordered_nb__gt=0).order_by("name") @@ -287,27 +299,16 @@ class GroupedOrderSheetMixin: ordered_values.append(value) orders_dict[order] = ordered_values # order as key of the dict - return { - "name": grouped_order.name, - "delivery_date": grouped_order.delivery_date, - "items": items, - "orders_dict": orders_dict, - "total_price": grouped_order.total_price, - } + context["items"] = items + context["orders_dict"] = orders_dict + + return context -class GroupedOrderSheetView(GroupedOrderOverview, GroupedOrderSheetMixin): - """View to get a pdf sheet summing up the grouped order for delivery""" +class DownloadGroupedOrderSheetView(WeasyTemplateResponseMixin, GroupedOrderSheetView): + """View for downloading the grouped order sheet, + using django-weasyprint : https://pypi.org/project/django-weasyprint/""" - template_name = "order/grouped_order_sheet.html" - - def get(self, request, pk): - grouped_order_sheet_info = self.get_grouped_order_infos(pk) - # should_include_prices = True if request.GET.get("with_prices", False) else False - # delivery_sheet_info["include_prices"] = should_include_prices - à ajouter plus tard - template = get_template(self.template_name) - html = template.render(grouped_order_sheet_info) - - result = BytesIO() - pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result) - return http.HttpResponse(result.getvalue(), content_type="application/pdf") + def get_pdf_filename(self): + # filename for download + return f"{self.get_object().delivery_date} - {self.get_object().name}" diff --git a/la_chariotte/settings.py b/la_chariotte/settings.py index dd261bd..b10055f 100644 --- a/la_chariotte/settings.py +++ b/la_chariotte/settings.py @@ -89,7 +89,7 @@ WSGI_APPLICATION = "la_chariotte.wsgi.application" DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", - "NAME": os.getenv("DB_NAME", "chariotte-db"), + "NAME": os.getenv("DB_NAME", "chariotte"), } } diff --git a/la_chariotte/static/css/app.css b/la_chariotte/static/css/app.css index 17828f5..83994c3 100644 --- a/la_chariotte/static/css/app.css +++ b/la_chariotte/static/css/app.css @@ -10400,3 +10400,26 @@ a.navbar-item:hover { white-space: nowrap; } } +@media print { + body { + color: #ffffff; + } + a::after { + content: " (" attr(href) ") "; + } + pre { + white-space: pre-wrap; + } + @page { + margin: 0.75in; + size: Letter; + @top-right { + content: counter(page); + } + } + @page :first { + @top-right { + content: ""; + } + } +} diff --git a/requirements.txt b/requirements.txt index 4a94e9b..5aac60a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -100,5 +100,7 @@ webencodings==0.5.1 # cssselect2 # html5lib # tinycss2 +weasyprint==58.0 #django-weasyprint doesn't work with weasyprint 59.0 +django-weasyprint==2.2.0 xhtml2pdf==0.2.11 # via la-chariotte (pyproject.toml)
Prix unitairePrix unitaire + {{ item.price }} € - +
TOTAL{{ total_price }} €{{ grouped_order.total_price }} €
+ {{ order.author }} - + + {{ ordered_item }} - + + {{ order.price }} € - +