From 68a4e7103f358c14ab06cc6a51d20fabcdf0009a Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Mon, 9 Aug 2021 19:59:29 +0200
Subject: [PATCH] Fix bulk_update in delete_personal_note action

This includes tests to reproduce the error.
---
 CHANGELOG.rst                              |  8 ++
 aleksis/apps/alsijil/actions.py            |  4 +-
 aleksis/apps/alsijil/tests/test_actions.py | 96 ++++++++++++++++++++++
 3 files changed, 107 insertions(+), 1 deletion(-)
 create mode 100644 aleksis/apps/alsijil/tests/test_actions.py

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 5d702b571..5f4e9ef13 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,14 @@ All notable changes to this project will be documented in this file.
 The format is based on `Keep a Changelog`_,
 and this project adheres to `Semantic Versioning`_.
 
+Unreleased
+----------
+
+Fixed
+~~~~~
+
+* The _Delete personal note_ action didn't work due to wrong usage of ``bulk_update``.
+
 `2.0rc4`_ - 2021-08-01
 ----------------------
 
diff --git a/aleksis/apps/alsijil/actions.py b/aleksis/apps/alsijil/actions.py
index 2d42d6134..9c307017e 100644
--- a/aleksis/apps/alsijil/actions.py
+++ b/aleksis/apps/alsijil/actions.py
@@ -40,7 +40,9 @@ def delete_personal_note(modeladmin, request, queryset):
     for personal_note in queryset:
         personal_note.reset_values()
         notes.append(personal_note)
-    PersonalNote.objects.bulk_update(notes)
+    PersonalNote.objects.bulk_update(
+        notes, fields=["absent", "excused", "late", "excuse_type", "remarks"]
+    )
 
 
 delete_personal_note.short_description = _("Delete")
diff --git a/aleksis/apps/alsijil/tests/test_actions.py b/aleksis/apps/alsijil/tests/test_actions.py
new file mode 100644
index 000000000..6f1bd6ef4
--- /dev/null
+++ b/aleksis/apps/alsijil/tests/test_actions.py
@@ -0,0 +1,96 @@
+from datetime import date, time
+
+import pytest
+
+from aleksis.apps.alsijil.actions import (
+    delete_personal_note,
+    mark_as_excuse_type_generator,
+    mark_as_excused,
+    mark_as_unexcused,
+)
+from aleksis.apps.alsijil.models import ExcuseType, PersonalNote
+from aleksis.apps.chronos.models import Event, TimePeriod
+from aleksis.core.models import Person
+
+pytestmark = pytest.mark.django_db
+
+
+def _generate_event(day: date):
+    period_from = TimePeriod.objects.create(
+        weekday=0, period=1, time_start=time(10, 00), time_end=time(11, 00)
+    )
+    period_to = TimePeriod.objects.create(
+        weekday=0, period=2, time_start=time(11, 00), time_end=time(12, 00)
+    )
+
+    event = Event.objects.create(
+        date_start=day, date_end=day, period_from=period_from, period_to=period_to
+    )
+    return event
+
+
+def _prepare_notes():
+    """Create some minimal personal notes."""
+    person, __ = Person.objects.get_or_create(first_name="Jane", last_name="Doe")
+
+    excuse_type, __ = ExcuseType.objects.get_or_create(short_name="Foo", name="Fooooooooooooo")
+    notes = [
+        PersonalNote(
+            person=person,
+            event=_generate_event(date(2021, 10, 1)),
+            absent=True,
+            remarks="This is baz.",
+        ),
+        PersonalNote(person=person, event=_generate_event(date(2021, 11, 1)), absent=True),
+        PersonalNote(
+            person=person, event=_generate_event(date(2022, 10, 1)), absent=True, excused=True
+        ),
+        PersonalNote(
+            person=person,
+            event=_generate_event(date(2021, 3, 1)),
+            absent=True,
+            excused=True,
+            excuse_type=excuse_type,
+        ),
+        PersonalNote(person=person, event=_generate_event(date(2021, 10, 4)), late=10),
+        PersonalNote(
+            person=person, event=_generate_event(date(2032, 10, 11)), remarks="Good work!"
+        ),
+        PersonalNote(person=person, event=_generate_event(date(2032, 10, 11))),
+    ]
+    PersonalNote.objects.bulk_create(notes)
+    return notes
+
+
+def test_mark_as_excused_action():
+    notes = _prepare_notes()
+    assert PersonalNote.objects.filter(excused=True).count() == 2
+    mark_as_excused(None, None, PersonalNote.objects.all())
+    assert PersonalNote.objects.filter(excused=True).count() == 4
+    assert PersonalNote.objects.filter(excuse_type=None, excused=True).count() == 4
+
+
+def test_mark_as_unexcused_action():
+    notes = _prepare_notes()
+    assert PersonalNote.objects.filter(excused=True).count() == 2
+    mark_as_unexcused(None, None, PersonalNote.objects.all())
+    assert PersonalNote.objects.filter(excused=True).count() == 0
+    assert PersonalNote.objects.filter(excuse_type=None, excused=True).count() == 0
+
+
+def test_mark_as_excuse_type_generator_action():
+    excuse_type, __ = ExcuseType.objects.get_or_create(short_name="Foo", name="Fooooooooooooo")
+    notes = _prepare_notes()
+    assert PersonalNote.objects.filter(excused=True).count() == 2
+    assert PersonalNote.objects.filter(excused=True, excuse_type=excuse_type).count() == 1
+    mark_as_foo = mark_as_excuse_type_generator(excuse_type=excuse_type)
+    mark_as_foo(None, None, PersonalNote.objects.all())
+    assert PersonalNote.objects.filter(excused=True).count() == 4
+    assert PersonalNote.objects.filter(excuse_type=excuse_type, excused=True).count() == 4
+
+
+def test_delete_personal_note_action():
+    notes = _prepare_notes()
+    assert PersonalNote.objects.not_empty().count() == 6
+    delete_personal_note(None, None, PersonalNote.objects.all())
+    assert PersonalNote.objects.not_empty().count() == 0
-- 
GitLab