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
diff --git a/kfet/templates/kfet/inventory_read.html b/kfet/templates/kfet/inventory_read.html
index 964e81b0..9a9275f8 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 %}
+
+
+
+
+ {% endif %}
+
@@ -64,4 +75,29 @@
+
+
{% endblock %}
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/"
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
# -----
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
# -----