From 59dacda37d0d3b672cc213407eaee5aad795b78d Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 11 Sep 2020 15:21:29 +0200 Subject: [PATCH 1/5] Inventory deletion view --- kfet/views.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/kfet/views.py b/kfet/views.py index a9dd1945..d42c6338 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -13,7 +13,7 @@ from django.contrib.auth.models import Permission, User from django.contrib.messages.views import SuccessMessageMixin from django.core.exceptions import SuspiciousOperation from django.db import transaction -from django.db.models import Count, F, Prefetch, Q, Sum +from django.db.models import Count, F, Max, OuterRef, Prefetch, Q, Subquery, Sum from django.forms import formset_factory from django.http import Http404, HttpResponseBadRequest, JsonResponse from django.shortcuts import get_object_or_404, redirect, render @@ -1909,6 +1909,32 @@ class InventoryRead(DetailView): return context +class InventoryDelete(PermissionRequiredMixin, DeleteView): + model = Inventory + success_url = reverse_lazy("kfet.inventory") + success_message = "Inventaire annulé avec succès !" + permission_required = "kfet.delete_inventory" + + def get(self, request, *args, **kwargs): + return redirect("kfet.inventory.read", self.kwargs.get(self.pk_url_kwarg)) + + def delete(self, request, *args, **kwargs): + inv = self.get_object() + # On met à jour les articles dont c'est le dernier inventaire + # .get() ne marche pas avec OuterRef, donc on utilise .filter() avec [:1] + update_subquery = InventoryArticle.objects.filter( + inventory=inv, article=OuterRef("pk") + ).values("stock_old")[:1] + + Article.objects.annotate(last_env=Max("inventories__at")).filter( + last_env=inv.at + ).update(stock=Subquery(update_subquery)) + + # On a tout mis à jour, on peut delete (avec un message) + messages.success(request, self.success_message) + return super().delete(request, *args, **kwargs) + + # ----- # Order views # ----- From f3701d91fc672cda6f9dae9200717cd908854714 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 11 Sep 2020 15:22:02 +0200 Subject: [PATCH 2/5] Url and template for InventoryDeleteView --- kfet/templates/kfet/inventory_read.html | 34 +++++++++++++++++++++++++ kfet/urls.py | 5 ++++ 2 files changed, 39 insertions(+) diff --git a/kfet/templates/kfet/inventory_read.html b/kfet/templates/kfet/inventory_read.html index 964e81b0..143449f7 100644 --- a/kfet/templates/kfet/inventory_read.html +++ b/kfet/templates/kfet/inventory_read.html @@ -19,6 +19,17 @@ {% endif %} + {% if perms.kfet.delete_inventory %} +
+
+ +
+ {% csrf_token %} +
+ {% endif %} +
@@ -64,4 +75,27 @@ + + {% endblock %} diff --git a/kfet/urls.py b/kfet/urls.py index 2548e77e..7a9498ed 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -270,6 +270,11 @@ urlpatterns = [ teamkfet_required(views.InventoryRead.as_view()), name="kfet.inventory.read", ), + path( + "inventaires//delete", + views.InventoryDelete.as_view(), + name="kfet.inventory.delete", + ), # ----- # Order urls # ----- From 521be6db85da2646f2dde598fddd9eb8b833173f Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 11 Sep 2020 15:22:07 +0200 Subject: [PATCH 3/5] Tests --- kfet/tests/test_views.py | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/kfet/tests/test_views.py b/kfet/tests/test_views.py index 47382aa1..ecd7131e 100644 --- a/kfet/tests/test_views.py +++ b/kfet/tests/test_views.py @@ -4579,6 +4579,87 @@ class InventoryReadViewTests(ViewTestCaseMixin, TestCase): self.assertEqual(r.status_code, 200) +class InventoryDeleteViewTests(ViewTestCaseMixin, TestCase): + url_name = "kfet.inventory.delete" + + auth_user = "team1" + auth_forbidden = [None, "user", "team"] + + def get_users_extra(self): + return { + "user1": create_user("user1", "001"), + "team1": create_team("team1", "101", perms=["kfet.delete_inventory"]), + } + + @property + def url_kwargs(self): + return {"pk": self.inventory1.pk} + + @property + def url_expected(self): + return "/k-fet/inventaires/{}/delete".format(self.inventory1.pk) + + def setUp(self): + super().setUp() + # Deux inventaires : un avec article 1 + 2, l'autre avec 1 + 3 + self.inventory1 = Inventory.objects.create( + by=self.accounts["team"], at=self.now + ) + self.inventory2 = Inventory.objects.create( + by=self.accounts["team"], at=self.now + timedelta(days=1) + ) + category = ArticleCategory.objects.create(name="Category") + # Le stock des articles correspond à leur dernier inventaire + self.article1 = Article.objects.create( + name="Article1", category=category, stock=51 + ) + self.article2 = Article.objects.create( + name="Article2", category=category, stock=42 + ) + self.article3 = Article.objects.create( + name="Article3", category=category, stock=42 + ) + + InventoryArticle.objects.create( + inventory=self.inventory1, + article=self.article1, + stock_old=23, + stock_new=42, + ) + InventoryArticle.objects.create( + inventory=self.inventory1, + article=self.article2, + stock_old=23, + stock_new=42, + ) + InventoryArticle.objects.create( + inventory=self.inventory2, + article=self.article1, + stock_old=42, + stock_new=51, + ) + InventoryArticle.objects.create( + inventory=self.inventory2, + article=self.article3, + stock_old=23, + stock_new=42, + ) + + def test_ok(self): + r = self.client.post(self.url) + self.assertRedirects(r, reverse("kfet.inventory")) + + # On vérifie que l'inventaire n'existe plus + self.assertFalse(Inventory.objects.filter(pk=self.inventory1.pk).exists()) + # On check les stocks + self.article1.refresh_from_db() + self.article2.refresh_from_db() + self.article3.refresh_from_db() + self.assertEqual(self.article1.stock, 51) + self.assertEqual(self.article2.stock, 23) + self.assertEqual(self.article3.stock, 42) + + class OrderListViewTests(ViewTestCaseMixin, TestCase): url_name = "kfet.order" url_expected = "/k-fet/orders/" From b9699637aa77b8ffe2eab38656de4044dee4b996 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 21 Oct 2020 15:52:50 +0200 Subject: [PATCH 4/5] Message de confirmation plus clair --- kfet/templates/kfet/inventory_read.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kfet/templates/kfet/inventory_read.html b/kfet/templates/kfet/inventory_read.html index 143449f7..9a9275f8 100644 --- a/kfet/templates/kfet/inventory_read.html +++ b/kfet/templates/kfet/inventory_read.html @@ -84,6 +84,8 @@ $( function() { content: `
Cette opération est irréversible ! +
+ N.B. : seuls les articles dont c'est le dernier inventaire en date seront affectés.
`, backgroundDismiss: true, From a7cbd2d45165902d304f4e2c3b4f1506cc8674bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 4 Dec 2020 17:02:36 +0100 Subject: [PATCH 5/5] CHANGELOG --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b35d8e73..8a87eccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,9 +21,12 @@ Liste des changements notables dans GestioCOF depuis la version 0.1 (septembre Uniquement un modèle simple de clubs avec des respos. Aucune gestion des adhérents ni des cotisations. -## Version ??? - le futur +## Version ??? - dans un futur proche -... +### K-Fêt + +- On peut supprimer un inventaire. Seuls les articles dont c'est le dernier + inventaire sont affectés. ## Version 0.8 - 03/12/2020