mirror of
https://framagit.org/la-chariotte/la-chariotte.git
synced 2025-05-01 11:22:24 +02:00
pdf sheet generation - part 2
This commit is contained in:
parent
761a28770c
commit
26f7c313fc
4 changed files with 161 additions and 118 deletions
|
@ -36,14 +36,15 @@
|
|||
<button class="button is-info" onclick="copyLink()">Copier le lien</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p>Pour vous aider à distribuer les produits le jour J, vous pouvez imprimer la liste des commandes :
|
||||
<a href="{% url 'order:grouped_order_sheet' grouped_order.id %}">ici</a></p>
|
||||
<p>Pour vous aider à distribuer les produits le jour J, vous pouvez imprimer la liste des commandes :</p>
|
||||
<a class="button is-info" href="{% url 'order:grouped_order_sheet' grouped_order.id %}" target="_blank">Liste des commandes</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<p class="title">Produits commandés</p>
|
||||
{% if grouped_order.item_set.all %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -70,10 +71,14 @@
|
|||
<th>{{ grouped_order.total_price }} €</th>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Vous n'avez pas ajouté de produits à cette commande groupée. Ajoutez-en <a href="{% url 'order:manage_items' %}">ici</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<p class="title">Liste des commandes</p>
|
||||
{% if grouped_order.order_set.all %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -97,6 +102,9 @@
|
|||
<th></th>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Personne n'a encore commandé. Partagez l'info à votre entourage !</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>
|
||||
Commande groupée - date
|
||||
{{ name }} - Liste des commandes
|
||||
</title>
|
||||
<style type="text/css">
|
||||
@page {
|
||||
{% if headers|length > 6 %}
|
||||
{% if items|length > 6 %}
|
||||
size: letter landscape;
|
||||
{% else %}
|
||||
size: A4;
|
||||
|
@ -18,7 +18,7 @@
|
|||
bottom: 0cm;
|
||||
height: 1.5cm;
|
||||
right: 0cm;
|
||||
width: 3.5cm;
|
||||
width: 10cm;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,26 +27,10 @@
|
|||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.green {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px black solid;
|
||||
border-collapse: collapse;
|
||||
|
@ -70,13 +54,7 @@
|
|||
<h1 style="text-align: center">
|
||||
{{ name }} - {{ delivery_date }}
|
||||
</h1>
|
||||
<p>
|
||||
Produits : {% for item in items.all %}
|
||||
{{ item }}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% if items %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -90,82 +68,46 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="background-color: #bababa">Total</th>
|
||||
<tr style="background-color: #bababa">
|
||||
<th style="text-align: left">Prix unitaire</th>
|
||||
{% for item in items %}
|
||||
<th style="text-align: center">{{ item.ordered_nb }}</th>
|
||||
<th>
|
||||
{{ item.price }} €
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for order in orders_dict %}
|
||||
<tr>
|
||||
poeut
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<tr style="background-color: #bababa">
|
||||
<th style="text-align: left">TOTAL</th>
|
||||
{% for total in totals %}
|
||||
<th style="text-align: center">
|
||||
{{ total }}
|
||||
{% endfor %} {% if include_prices %}
|
||||
{% for item in items %}
|
||||
<th>
|
||||
{{ item.ordered_nb }}
|
||||
</th>
|
||||
|
||||
<th style="text-align: right">{{ total_to_pay|floatformat:2 }} €</th>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<th>{{ total_price }} €</th>
|
||||
</tr>
|
||||
|
||||
{% for user in user_info %}
|
||||
<tr> {% if include_prices %}
|
||||
<td style="text-align: right">
|
||||
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for order, ordered_items in orders_dict.items %}
|
||||
<tr>
|
||||
<th>
|
||||
{{ order.author }}
|
||||
</th>
|
||||
{% for ordered_item in ordered_items %}
|
||||
<th>
|
||||
{{ ordered_item }}
|
||||
</th>
|
||||
{% endfor %}
|
||||
<th>
|
||||
{{ order.price }} €
|
||||
</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 8cm; text-align: left">Nom</th>
|
||||
<th style="width: 4cm">{{Quantité}}</th>
|
||||
<th style="width: 4cm">Récupéré ?</th>
|
||||
|
||||
{% if include_prices %}
|
||||
<th style="width: 3cm">À payer</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in user_info %}
|
||||
<tr>
|
||||
<td style="width: 6cm"></td>
|
||||
{% if include_prices %}
|
||||
<td style="text-align: right">
|
||||
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
<tr>
|
||||
<th>TOTAL</th>
|
||||
{% for total in totals %}
|
||||
<th style="text-align: center">{{ total }}</th>
|
||||
{% endfor %}
|
||||
<th style="background-color: #ccc; width: 4cm"></th>
|
||||
|
||||
{% if include_prices %}
|
||||
<th style="text-align: right">{{ total_to_pay|floatformat:2 }} €</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
Aucun produit n'a été commandé
|
||||
{% endif %}
|
||||
|
||||
<div id="footer">
|
||||
Page
|
||||
Liste générée par la Chariotte - chariotte.fr | Page
|
||||
<pdf:pagenumber />
|
||||
/
|
||||
<pdf:pagecount />
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.contrib import auth
|
|||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from la_chariotte.order.models import GroupedOrder, Item, Order, OrderAuthor
|
||||
from la_chariotte.order import models
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -18,11 +18,29 @@ def create_grouped_order(
|
|||
"""
|
||||
date = timezone.now().date() + datetime.timedelta(days=days_before_delivery_date)
|
||||
deadline = timezone.now() + datetime.timedelta(days=days_before_deadline)
|
||||
return GroupedOrder.objects.create(
|
||||
return models.GroupedOrder.objects.create(
|
||||
name=name, orga=orga_user, delivery_date=date, deadline=deadline
|
||||
)
|
||||
|
||||
|
||||
def order_items_in_grouped_order(grouped_order):
|
||||
"""Creates 2 OrderedItems and orders for those items in the given grouped order"""
|
||||
item_1 = grouped_order.item_set.create(name="test item", price="2")
|
||||
item_2 = grouped_order.item_set.create(name="test item 2", price="9")
|
||||
author = models.OrderAuthor.objects.create(
|
||||
first_name="bob", last_name="lescargot", phone="000", email="bob@escargot.fr"
|
||||
)
|
||||
order = grouped_order.order_set.create(author=author)
|
||||
models.OrderedItem.objects.create(order=order, item=item_1, nb=3)
|
||||
models.OrderedItem.objects.create(order=order, item=item_2, nb=2)
|
||||
item_1.compute_ordered_nb()
|
||||
item_2.compute_ordered_nb()
|
||||
order.compute_order_price()
|
||||
grouped_order.compute_total_price()
|
||||
grouped_order.save()
|
||||
return order
|
||||
|
||||
|
||||
class TestGroupedOrderIndexView:
|
||||
def test_anonymous_user_redirection(self, client):
|
||||
"""
|
||||
|
@ -205,7 +223,7 @@ class TestGroupedOrderIndexView:
|
|||
class TestGroupedOrderDetailView:
|
||||
def test_order_item(self, client, other_user):
|
||||
"""
|
||||
From the OrderDetailView, we order an item using the order form, and it creates an Order with an Ordered_item inside
|
||||
From the OrderDetailView, we order an item using the order form, and it creates an models.Order with an Ordered_item inside
|
||||
"""
|
||||
grouped_order = create_grouped_order(
|
||||
days_before_delivery_date=5,
|
||||
|
@ -213,10 +231,10 @@ class TestGroupedOrderDetailView:
|
|||
name="gr order test",
|
||||
orga_user=other_user,
|
||||
)
|
||||
item = Item.objects.create(
|
||||
item = models.Item.objects.create(
|
||||
name="test item 1", grouped_order=grouped_order, price=1
|
||||
)
|
||||
item2 = Item.objects.create(
|
||||
item2 = models.Item.objects.create(
|
||||
name="test item 2", grouped_order=grouped_order, price=5
|
||||
)
|
||||
detail_url = reverse(
|
||||
|
@ -249,7 +267,7 @@ class TestGroupedOrderDetailView:
|
|||
},
|
||||
)
|
||||
assert response.status_code == 302
|
||||
order = Order.objects.get(grouped_order=grouped_order.pk)
|
||||
order = models.Order.objects.get(grouped_order=grouped_order.pk)
|
||||
assert response.url == reverse(
|
||||
"order:order_confirm",
|
||||
kwargs={
|
||||
|
@ -259,12 +277,12 @@ class TestGroupedOrderDetailView:
|
|||
)
|
||||
item.refresh_from_db()
|
||||
item2.refresh_from_db()
|
||||
assert OrderAuthor.objects.first().first_name == "Prénom"
|
||||
assert OrderAuthor.objects.first().email == "test@mail.fr"
|
||||
assert OrderAuthor.objects.first().phone == "0645632569"
|
||||
assert models.OrderAuthor.objects.first().first_name == "Prénom"
|
||||
assert models.OrderAuthor.objects.first().email == "test@mail.fr"
|
||||
assert models.OrderAuthor.objects.first().phone == "0645632569"
|
||||
assert item.ordered_nb == 4
|
||||
assert item2.ordered_nb == 1
|
||||
order = Order.objects.first()
|
||||
order = models.Order.objects.first()
|
||||
assert order.ordered_items.count() == 2
|
||||
assert order.articles_nb == 5
|
||||
assert order.price == 9
|
||||
|
@ -280,7 +298,7 @@ class TestGroupedOrderDetailView:
|
|||
name="gr order test",
|
||||
orga_user=other_user,
|
||||
)
|
||||
item = Item.objects.create(
|
||||
item = models.Item.objects.create(
|
||||
name="test item 1", grouped_order=grouped_order, price=1
|
||||
)
|
||||
detail_url = reverse(
|
||||
|
@ -310,7 +328,7 @@ class TestGroupedOrderDetailView:
|
|||
"email": "test@mail.fr",
|
||||
},
|
||||
)
|
||||
order = Order.objects.first()
|
||||
order = models.Order.objects.first()
|
||||
order.articles_nb == 0
|
||||
assert response.status_code == 200
|
||||
assert (
|
||||
|
@ -322,7 +340,7 @@ class TestGroupedOrderDetailView:
|
|||
class TestGroupedOrderOverview:
|
||||
def test_get_overview(self, client_log):
|
||||
"""
|
||||
From the OrderDetailView, we order an item using the order form, and it creates an Order with an Ordered_item inside
|
||||
From the OrderDetailView, we order an item using the order form, and it creates an models.Order with an Ordered_item inside
|
||||
"""
|
||||
grouped_order = create_grouped_order(
|
||||
days_before_delivery_date=5,
|
||||
|
@ -330,7 +348,7 @@ class TestGroupedOrderOverview:
|
|||
name="gr order test",
|
||||
orga_user=auth.get_user(client_log),
|
||||
)
|
||||
item = Item.objects.create(
|
||||
item = models.Item.objects.create(
|
||||
name="test item 1", grouped_order=grouped_order, price=2
|
||||
)
|
||||
|
||||
|
@ -421,7 +439,7 @@ class TestGroupedOrderCreateView:
|
|||
A logged user gets the grouped order creation page, and creates a grouped order.
|
||||
They are redirected to the manage items page.
|
||||
"""
|
||||
assert GroupedOrder.objects.count() == 0
|
||||
assert models.GroupedOrder.objects.count() == 0
|
||||
create_gorder_url = reverse("order:create_grouped_order")
|
||||
response = client_log.get(create_gorder_url)
|
||||
assert response.status_code == 200
|
||||
|
@ -433,7 +451,7 @@ class TestGroupedOrderCreateView:
|
|||
)
|
||||
assert response.status_code == 302
|
||||
assert response.url.endswith("gerer-produits")
|
||||
assert GroupedOrder.objects.count() == 1
|
||||
assert models.GroupedOrder.objects.count() == 1
|
||||
|
||||
def test_create_grouped_order__anonymous_user(self, client):
|
||||
create_gorder_url = reverse("order:create_grouped_order")
|
||||
|
@ -523,7 +541,7 @@ class TestItemCreateView:
|
|||
"pk": grouped_order.pk,
|
||||
},
|
||||
)
|
||||
assert Item.objects.first().name == "titre item"
|
||||
assert models.Item.objects.first().name == "titre item"
|
||||
response = client_log.get(response.url)
|
||||
assert "titre item" in response.content.decode()
|
||||
|
||||
|
@ -567,3 +585,70 @@ class TestItemCreateView:
|
|||
)
|
||||
response = client_log.post(create_item_view_url, {"name": "titre item"})
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
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.
|
||||
They get a 403 error"""
|
||||
grouped_order = create_grouped_order(
|
||||
days_before_delivery_date=5,
|
||||
days_before_deadline=2,
|
||||
name="gr order test",
|
||||
orga_user=other_user,
|
||||
)
|
||||
generate_sheet_url = reverse(
|
||||
"order:grouped_order_sheet",
|
||||
kwargs={
|
||||
"pk": grouped_order.pk,
|
||||
},
|
||||
)
|
||||
response = client_log.get(generate_sheet_url)
|
||||
assert response.status_code == 403
|
||||
|
||||
def test_get__not_orga(self, client, other_user):
|
||||
"""An anonymous user accesses the sheet view.
|
||||
They get redirected to login page"""
|
||||
grouped_order = create_grouped_order(
|
||||
days_before_delivery_date=5,
|
||||
days_before_deadline=2,
|
||||
name="gr order test",
|
||||
orga_user=other_user,
|
||||
)
|
||||
generate_sheet_url = reverse(
|
||||
"order:grouped_order_sheet",
|
||||
kwargs={
|
||||
"pk": grouped_order.pk,
|
||||
},
|
||||
)
|
||||
response = client.get(generate_sheet_url)
|
||||
assert response.status_code == 302
|
||||
assert response.url == f"{reverse('accounts:login')}?next={generate_sheet_url}"
|
||||
|
||||
def test_get_pdf_sheet(self, client_log, other_user):
|
||||
"""The orga of the grouped models.Order accesses the pdf sheet"""
|
||||
grouped_order = create_grouped_order(
|
||||
days_before_delivery_date=5,
|
||||
days_before_deadline=2,
|
||||
name="gr order test",
|
||||
orga_user=auth.get_user(client_log),
|
||||
)
|
||||
generate_sheet_url = reverse(
|
||||
"order:grouped_order_sheet",
|
||||
kwargs={
|
||||
"pk": grouped_order.pk,
|
||||
},
|
||||
)
|
||||
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["items"].count() == 0
|
||||
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["items"].count() == 2
|
||||
assert response.context["orders_dict"][order] == [3, 2]
|
||||
assert response.context["total_price"] == 24
|
||||
|
|
|
@ -191,36 +191,44 @@ class OrderDetailView(generic.DetailView):
|
|||
|
||||
|
||||
class GroupedOrderSheetMixin:
|
||||
"""Mixin for grouped order info export (pdf sheet and csv)"""
|
||||
|
||||
def get_grouped_order_infos(self, grouped_order_id):
|
||||
grouped_order = get_object_or_404(GroupedOrder, id=grouped_order_id)
|
||||
|
||||
# Get ordered items
|
||||
items = grouped_order.item_set.filter(ordered_nb__gt=0)
|
||||
items = grouped_order.item_set.filter(ordered_nb__gt=0).order_by("name")
|
||||
|
||||
# Get content of orders
|
||||
orders_values = []
|
||||
# Get content of orders as a dict {order : [ordered_nb for item 1, ordered_nb for item 2, ...]}
|
||||
orders_dict = {}
|
||||
for order in grouped_order.order_set.all():
|
||||
for ordered_item in order.ordered_items.all():
|
||||
orders_values[order.id][ordered_item.id] = ordered_item.nb
|
||||
ordered_values = [] # ordered_values list as value of the dict
|
||||
for item in items: # items that has actually been ordered
|
||||
# find the ordered nb of this item in this order
|
||||
# if no item of the type has been ordered in this order, put 0
|
||||
value = order.ordered_items.filter(item=item).first()
|
||||
value = value.nb if value else 0
|
||||
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": orders_dict,
|
||||
"orders_dict": orders_dict,
|
||||
"total_price": grouped_order.total_price,
|
||||
}
|
||||
|
||||
|
||||
class GroupedOrderSheetView(GroupedOrderOverview, GroupedOrderSheetMixin):
|
||||
"""View to get a pdf sheet summing up the grouped order for delivery"""
|
||||
|
||||
template_name = "order/grouped_order_sheet.html"
|
||||
|
||||
def get(self, request, pk):
|
||||
# ferme = Ferme.get_or_404(ferme_id)
|
||||
# ferme.check_access(request.user)
|
||||
|
||||
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
|
||||
# delivery_sheet_info["include_prices"] = should_include_prices - à ajouter plus tard
|
||||
template = get_template(self.template_name)
|
||||
html = template.render(grouped_order_sheet_info)
|
||||
|
||||
|
|
Loading…
Reference in a new issue