diff --git a/la_chariotte/order/forms.py b/la_chariotte/order/forms.py new file mode 100644 index 0000000..7ab18f0 --- /dev/null +++ b/la_chariotte/order/forms.py @@ -0,0 +1,32 @@ +from django.contrib.auth.models import User +from django.forms import CharField, ModelForm + +from la_chariotte.order.models import GroupedOrder, Item + + +class GroupedOrderForm(ModelForm): + class Meta: + model = GroupedOrder + fields = ["name", "deadline", "delivery_date"] + + def __init__(self, *args, **kwargs): + self.user = kwargs.pop("user") + super().__init__(*args, **kwargs) + + def save(self, commit=True): + self.instance.orga = User.objects.get(id=self.user.pk) + return super().save(commit=commit) + + +class ItemCreateForm(ModelForm): + class Meta: + model = Item + fields = ["name"] + + def __init__(self, *args, **kwargs): + self.grouped_order = kwargs.pop("grouped_order") # type: GroupedOrder + super().__init__(*args, **kwargs) + + def save(self, commit=True): + self.instance.grouped_order = GroupedOrder.objects.get(id=self.grouped_order.pk) + return super().save(commit=commit) diff --git a/la_chariotte/order/models.py b/la_chariotte/order/models.py index 7422571..a2e30b3 100644 --- a/la_chariotte/order/models.py +++ b/la_chariotte/order/models.py @@ -1,5 +1,6 @@ from django.contrib.auth.models import User from django.db import models +from django.urls import reverse from django.utils import timezone @@ -21,6 +22,9 @@ class GroupedOrder(models.Model): """Returns True if the grouped order has not been delivered yet - False if it's old""" return self.delivery_date >= timezone.now().date() + def get_absolute_url(self): + return reverse("order:manage_items", kwargs={"pk": self.pk}) + def __str__(self): # pragma: no cover return ( self.name @@ -48,6 +52,9 @@ class Item(models.Model): ) # à transformer en manytomany quand il y aura un catalogue ordered_nb = models.IntegerField(default=0) + def get_absolute_url(self): + return reverse("order:manage_items", kwargs={"pk": self.grouped_order.pk}) + def __str__(self): # pragma: no cover return f"{self.name} dans la commande groupée {self.grouped_order.pk}" diff --git a/la_chariotte/order/templates/order/grouped_order_add_items.html b/la_chariotte/order/templates/order/grouped_order_add_items.html new file mode 100644 index 0000000..5d6434d --- /dev/null +++ b/la_chariotte/order/templates/order/grouped_order_add_items.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} + +{% block title %}Nouvelle commande groupée{% endblock %} + +{% block content_title %}Ajouter des produits à votre commande groupée{% endblock %} + +{% block content %} + +

Commande groupée "{{ grouped_order.name }}", le {{ grouped_order.delivery_date }}

+

Limite de commande : {{ grouped_order.deadline }}

+

Sur cette page, vous pouvez voir et modifier les produits qui sont inscrits à votre commande groupée.

+ +{% url 'order:item_create' pk=grouped_order.pk as create_item_url %} + + + + + + + + + + + + {% csrf_token %} + + + + {% for item in item_list %} + + + + + {% endfor %} + +
NomAction
{{ item.name }}Supprimer (pas possible pour l'instant)
+ +
+ Valider +
+{% endblock %} diff --git a/la_chariotte/order/templates/order/grouped_order_create.html b/la_chariotte/order/templates/order/grouped_order_create.html new file mode 100644 index 0000000..b361f50 --- /dev/null +++ b/la_chariotte/order/templates/order/grouped_order_create.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block title %}Nouvelle commande groupée{% endblock %} + +{% block content_title %}Créer une commande groupée{% endblock %} + +{% block content %} +{% csrf_token %} + {{ form.as_p }} + + +{% endblock %} \ No newline at end of file diff --git a/la_chariotte/order/tests/test_views.py b/la_chariotte/order/tests/test_views.py index 82d7e4f..9c548c3 100644 --- a/la_chariotte/order/tests/test_views.py +++ b/la_chariotte/order/tests/test_views.py @@ -298,11 +298,157 @@ class TestGroupedOrderOrgaView: "pk": grouped_order.pk, }, ) - detail_view_url = reverse( - "order:grouped_order_detail", + response = client_log.get(orga_view_url) + assert response.status_code == 403 + + +class TestGroupedOrderCreateView: + def test_create_grouped_order(self, client_log): + """ + 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 + create_gorder_url = reverse("order:create_grouped_order") + response = client_log.get(create_gorder_url) + assert response.status_code == 200 + date = timezone.now().date() + datetime.timedelta(days=42) + deadline = timezone.now() + datetime.timedelta(days=32) + response = client_log.post( + create_gorder_url, + {"name": "titre test", "deadline": deadline, "delivery_date": date}, + ) + assert response.status_code == 302 + assert response.url.endswith("gerer-produits") + assert GroupedOrder.objects.count() == 1 + + def test_create_grouped_order__anonymous_user(self, client): + create_gorder_url = reverse("order:create_grouped_order") + response = client.get(create_gorder_url) + assert response.status_code == 302 + assert response.url.startswith(reverse("accounts:login")) + assert response.url.endswith( + reverse( + "order:create_grouped_order", + ) + ) + + +class TestGroupedOrderAddItemsView: + def test_get_manage_items__user_not_orga(self, client_log, other_user): + """ + A user that is not orga cannot see the GroupedOrderAddItemsView. + They get a 403 forbidden error + """ + grouped_order = create_grouped_order( + days_before_delivery_date=5, + days_before_deadline=2, + name="gr order test", + orga_user=other_user, + ) + add_items_view_url = reverse( + "order:manage_items", kwargs={ "pk": grouped_order.pk, }, ) - response = client_log.get(orga_view_url) + response = client_log.get(add_items_view_url) + assert response.status_code == 403 + + def test_get_manage_items__anonymous_user(self, client, other_user): + """ + A user that is not logged cannot see the GroupedOrderOrgaView. They get redirected to the login view + """ + grouped_order = create_grouped_order( + days_before_delivery_date=5, + days_before_deadline=2, + name="gr order test", + orga_user=other_user, + ) + add_items_view_url = reverse( + "order:manage_items", + kwargs={ + "pk": grouped_order.pk, + }, + ) + assert auth.get_user(client).is_anonymous + response = client.get(add_items_view_url) + assert response.status_code == 302 + assert response.url.startswith(reverse("accounts:login")) + assert response.url.endswith( + reverse( + "order:manage_items", + kwargs={ + "pk": grouped_order.pk, + }, + ) + ) + + +class TestItemCreateView: + def test_create_item(self, client_log): + """A user that has created a grouped order adds an item to it.""" + 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), + ) + create_item_view_url = reverse( + "order:item_create", + kwargs={ + "pk": grouped_order.pk, + }, + ) + response = client_log.post(create_item_view_url, {"name": "titre item"}) + assert response.status_code == 302 + assert response.url == reverse( + "order:manage_items", + kwargs={ + "pk": grouped_order.pk, + }, + ) + assert Item.objects.first().name == "titre item" + response = client_log.get(response.url) + assert "titre item" in response.content.decode() + + def test_create_item__anonymous_user(self, client, other_user): + """ + A user that is not logged cannot create an item. They get a redirected to loginview. + """ + grouped_order = create_grouped_order( + days_before_delivery_date=5, + days_before_deadline=2, + name="gr order test", + orga_user=other_user, + ) + create_item_view_url = reverse( + "order:item_create", + kwargs={ + "pk": grouped_order.pk, + }, + ) + response = client.post(create_item_view_url, {"name": "titre item"}) + assert response.status_code == 302 + assert ( + response.url == f"{reverse('accounts:login')}?next={create_item_view_url}" + ) + + def test_create_item__not_orga(self, client_log, other_user): + """ + A user that is not orga cannot create an item. 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, + ) + create_item_view_url = reverse( + "order:item_create", + kwargs={ + "pk": grouped_order.pk, + }, + ) + response = client_log.post(create_item_view_url, {"name": "titre item"}) assert response.status_code == 403 diff --git a/la_chariotte/order/urls.py b/la_chariotte/order/urls.py index 56d4ad7..45aa7ae 100644 --- a/la_chariotte/order/urls.py +++ b/la_chariotte/order/urls.py @@ -14,4 +14,15 @@ urlpatterns = [ name="grouped_order_overview", ), path("/commander/", views.order, name="order"), + path("creer", views.GroupedOrderCreateView.as_view(), name="create_grouped_order"), + path( + "/gerer-produits", + views.GroupedOrderAddItemsView.as_view(), + name="manage_items", + ), + path( + "/gerer-produits/nouveau", + views.ItemCreateView.as_view(), + name="item_create", + ), ] diff --git a/la_chariotte/order/views.py b/la_chariotte/order/views.py index b117980..d83c71d 100644 --- a/la_chariotte/order/views.py +++ b/la_chariotte/order/views.py @@ -5,6 +5,7 @@ from django.urls import reverse, reverse_lazy from django.utils import timezone from django.views import generic +from .forms import GroupedOrderForm, ItemCreateForm from .models import GroupedOrder, Item, Order, OrderedItem @@ -70,6 +71,59 @@ class GroupedOrderOrgaView(UserPassesTestMixin, generic.DetailView): return self.get_object().orga == self.request.user +class GroupedOrderCreateView(LoginRequiredMixin, generic.CreateView): + """View for creating a new grouped order""" + + model = GroupedOrder + form_class = GroupedOrderForm + template_name = "order/grouped_order_create.html" + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs["user"] = self.request.user + return kwargs + + +class GroupedOrderAddItemsView(UserPassesTestMixin, generic.ListView): + """After creating grouped order, view for adding items to it""" + + model = Item + template_name = "order/grouped_order_add_items.html" + queryset = Item.objects.all() + + def get_queryset(self): + items = super().get_queryset() + items = items.filter(grouped_order__id=self.kwargs.get("pk")) + return items + + def get_context_data(self, **kwargs): + context = super(GroupedOrderAddItemsView, self).get_context_data(**kwargs) + context["grouped_order"] = GroupedOrder.objects.get(id=self.kwargs.get("pk")) + return context + + def test_func(self): + """Accessible only if the requesting user is the grouped order organizer""" + grouped_order_id = self.kwargs.get("pk") + return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user + + +class ItemCreateView(UserPassesTestMixin, generic.CreateView): + """CreateView for an item""" + + model = Item + form_class = ItemCreateForm + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs["grouped_order"] = GroupedOrder.objects.get(id=self.kwargs.get("pk")) + return kwargs + + def test_func(self): + """Accessible only if the requesting user is the grouped order organizer""" + grouped_order_id = self.kwargs.get("pk") + return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user + + def order( request, grouped_order_id ): # crée une commande (order) pour cette commande groupée, avec l'item selectionné dedans diff --git a/la_chariotte/templates/base.html b/la_chariotte/templates/base.html index 6785e1f..f4cea2a 100644 --- a/la_chariotte/templates/base.html +++ b/la_chariotte/templates/base.html @@ -81,7 +81,7 @@ Mes commandes - + Créer une commande groupée