Commit 5d028ecd authored by Thom Wiggers's avatar Thom Wiggers 📐
Browse files

Merge branch 'feature/revert-registration-status' into 'master'

Make it possible to correct an acception or rejection in registrations

Closes #679

See merge request !952
parents 4d0d865b 91e22847
...@@ -84,10 +84,12 @@ class RegistrationAdmin(admin.ModelAdmin): ...@@ -84,10 +84,12 @@ class RegistrationAdmin(admin.ModelAdmin):
obj = None obj = None
can_review = False can_review = False
can_resend = False can_resend = False
can_revert = False
if (object_id is not None and if (object_id is not None and
request.user.has_perm('registrations.review_entries')): request.user.has_perm('registrations.review_entries')):
obj = Entry.objects.get(id=object_id) obj = Entry.objects.get(id=object_id)
can_review = obj.status == Entry.STATUS_REVIEW can_review = obj.status == Entry.STATUS_REVIEW
can_revert = obj.status in [Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]
try: try:
can_resend = obj.registration.status == Entry.STATUS_CONFIRM can_resend = obj.registration.status == Entry.STATUS_CONFIRM
except Registration.DoesNotExist: except Registration.DoesNotExist:
...@@ -97,6 +99,7 @@ class RegistrationAdmin(admin.ModelAdmin): ...@@ -97,6 +99,7 @@ class RegistrationAdmin(admin.ModelAdmin):
'entry': obj, 'entry': obj,
'can_review': can_review, 'can_review': can_review,
'can_resend': can_resend, 'can_resend': can_resend,
'can_revert': can_revert,
}) })
def get_actions(self, request): def get_actions(self, request):
......
...@@ -7,8 +7,8 @@ msgid "" ...@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-03 19:39+0200\n" "POT-Creation-Date: 2018-10-03 19:55+0200\n"
"PO-Revision-Date: 2018-10-03 19:40+0200\n" "PO-Revision-Date: 2018-10-03 19:56+0200\n"
"Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n" "Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: nl\n" "Language: nl\n"
...@@ -316,6 +316,10 @@ msgstr "verlenging" ...@@ -316,6 +316,10 @@ msgstr "verlenging"
msgid "Resend confirmation email" msgid "Resend confirmation email"
msgstr "Verstuur bevestigingsmail opnieuw" msgstr "Verstuur bevestigingsmail opnieuw"
#: templates/admin/registrations/change_form.html
msgid "Revert review"
msgstr "Opnieuw beoordelen"
#: templates/admin/registrations/change_form.html #: templates/admin/registrations/change_form.html
msgid "Accept" msgid "Accept"
msgstr "Goedkeuren" msgstr "Goedkeuren"
......
...@@ -144,6 +144,22 @@ def accept_entries(queryset): ...@@ -144,6 +144,22 @@ def accept_entries(queryset):
return len(updated_entries) return len(updated_entries)
def revert_entry(entry):
"""
Revert status of entry to review so that it can be corrected
:param entry: Entry that should be reverted
"""
if not (entry.status in [Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]):
return
entry.status = Entry.STATUS_REVIEW
entry.updated_at = timezone.now()
entry.save()
if entry.payment is not None:
entry.payment.delete()
def _create_payment_for_entry(entry): def _create_payment_for_entry(entry):
""" """
Create payment model for entry Create payment model for entry
......
...@@ -12,11 +12,14 @@ ...@@ -12,11 +12,14 @@
{% endblock %} {% endblock %}
{% block submit_buttons_bottom %} {% block submit_buttons_bottom %}
{% if can_resend or can_review %} {% if can_resend or can_review or can_revert %}
<div class="submit-row registrations-row"> <div class="submit-row registrations-row">
{% if can_resend %} {% if can_resend %}
<a data-href="{% url 'registrations:admin-process' pk=entry.pk %}" class="button" data-action="resend">{% trans "Resend confirmation email" %}</a> <a data-href="{% url 'registrations:admin-process' pk=entry.pk %}" class="button" data-action="resend">{% trans "Resend confirmation email" %}</a>
{% endif %} {% endif %}
{% if can_revert %}
<a data-href="{% url 'registrations:admin-process' pk=entry.pk %}" class="button" data-action="revert">{% trans "Revert review" %}</a>
{% endif %}
{% if can_review %} {% if can_review %}
<a data-href="{% url 'registrations:admin-process' pk=entry.pk %}" class="button accept" data-action="accept">{% trans "Accept" %}</a> <a data-href="{% url 'registrations:admin-process' pk=entry.pk %}" class="button accept" data-action="accept">{% trans "Accept" %}</a>
<a data-href="{% url 'registrations:admin-process' pk=entry.pk %}" class="button reject" data-action="reject">{% trans "Reject" %}</a> <a data-href="{% url 'registrations:admin-process' pk=entry.pk %}" class="button reject" data-action="reject">{% trans "Reject" %}</a>
......
...@@ -73,6 +73,7 @@ class RegistrationAdminTest(TestCase): ...@@ -73,6 +73,7 @@ class RegistrationAdminTest(TestCase):
'entry': None, 'entry': None,
'can_review': False, 'can_review': False,
'can_resend': False, 'can_resend': False,
'can_revert': False,
}) })
super_method.reset_mock() super_method.reset_mock()
...@@ -85,6 +86,7 @@ class RegistrationAdminTest(TestCase): ...@@ -85,6 +86,7 @@ class RegistrationAdminTest(TestCase):
'entry': None, 'entry': None,
'can_review': False, 'can_review': False,
'can_resend': False, 'can_resend': False,
'can_revert': False,
}) })
super_method.reset_mock() super_method.reset_mock()
...@@ -97,6 +99,7 @@ class RegistrationAdminTest(TestCase): ...@@ -97,6 +99,7 @@ class RegistrationAdminTest(TestCase):
'entry': entry, 'entry': entry,
'can_review': True, 'can_review': True,
'can_resend': False, 'can_resend': False,
'can_revert': False,
}) })
super_method.reset_mock() super_method.reset_mock()
...@@ -112,6 +115,7 @@ class RegistrationAdminTest(TestCase): ...@@ -112,6 +115,7 @@ class RegistrationAdminTest(TestCase):
'entry': entry, 'entry': entry,
'can_review': False, 'can_review': False,
'can_resend': True, 'can_resend': True,
'can_revert': False,
}) })
super_method.reset_mock() super_method.reset_mock()
...@@ -127,6 +131,7 @@ class RegistrationAdminTest(TestCase): ...@@ -127,6 +131,7 @@ class RegistrationAdminTest(TestCase):
'entry': entry, 'entry': entry,
'can_review': False, 'can_review': False,
'can_resend': False, 'can_resend': False,
'can_revert': True,
}) })
super_method.reset_mock() super_method.reset_mock()
...@@ -144,6 +149,7 @@ class RegistrationAdminTest(TestCase): ...@@ -144,6 +149,7 @@ class RegistrationAdminTest(TestCase):
'entry': entry, 'entry': entry,
'can_review': True, 'can_review': True,
'can_resend': False, 'can_resend': False,
'can_revert': False,
}) })
@mock.patch('registrations.services.accept_entries') @mock.patch('registrations.services.accept_entries')
......
...@@ -228,6 +228,41 @@ class ServicesTest(TestCase): ...@@ -228,6 +228,41 @@ class ServicesTest(TestCase):
status=Entry.STATUS_ACCEPTED).count(), 2) status=Entry.STATUS_ACCEPTED).count(), 2)
self.assertEqual(len(mail.outbox), 0) self.assertEqual(len(mail.outbox), 0)
def test_revert_entry(self):
with self.subTest("Revert accepted entry"):
self.e2.status = Entry.STATUS_ACCEPTED
self.e2.payment = services._create_payment_for_entry(self.e2)
self.e2.save()
services.revert_entry(self.e2)
self.e2.refresh_from_db()
self.assertEqual(self.e2.status, Entry.STATUS_REVIEW)
self.assertIsNone(self.e2.payment)
with self.subTest("Revert rejected entry"):
self.e2.status = Entry.STATUS_REJECTED
self.e2.save()
services.revert_entry(self.e2)
self.e2.refresh_from_db()
self.assertEqual(self.e2.status, Entry.STATUS_REVIEW)
with self.subTest("Does not revert completed entry"):
self.e2.status = Entry.STATUS_COMPLETED
self.e2.payment = services._create_payment_for_entry(self.e2)
self.e2.save()
services.revert_entry(self.e2)
self.e2.refresh_from_db()
self.assertEqual(self.e2.status, Entry.STATUS_COMPLETED)
self.assertIsNotNone(self.e2.payment)
def test_create_payment_for_entry(self): def test_create_payment_for_entry(self):
self.e1.username = 'jdoe' self.e1.username = 'jdoe'
self.e1.save() self.e1.save()
......
...@@ -236,6 +236,34 @@ class EntryAdminViewTest(TestCase): ...@@ -236,6 +236,34 @@ class EntryAdminViewTest(TestCase):
elif type == 'renewal': elif type == 'renewal':
send_email.assert_not_called() send_email.assert_not_called()
@mock.patch('registrations.services.revert_entry')
def test_post_revert(self, revert):
self.view.action = 'revert'
for type, entry in {
'registration': self.entry1,
'renewal': self.entry2
}.items():
entry_qs = Entry.objects.filter(pk=entry.pk)
revert.reset_mock()
revert.return_value = None
with mock.patch('registrations.models.Entry.objects.filter') as qs_mock:
qs_mock.return_value = entry_qs
qs_mock.get = Mock(return_value=entry_qs.get())
request = _get_mock_request()
request.POST = {
'action': 'revert',
}
response = self.view.post(request, pk=entry.pk)
self.assertEqual(response.status_code, 302)
self.assertEqual(
response.url,
'/admin/registrations/%s/%s/change/' % (type, entry.pk)
)
revert.assert_called_once_with(entry.entry_ptr)
@mock.patch('registrations.models.Entry.objects.filter') @mock.patch('registrations.models.Entry.objects.filter')
def test_post_not_exists(self, qs_mock): def test_post_not_exists(self, qs_mock):
qs_mock.return_value = MagicMock( qs_mock.return_value = MagicMock(
......
...@@ -74,6 +74,8 @@ class EntryAdminView(View): ...@@ -74,6 +74,8 @@ class EntryAdminView(View):
emails.send_registration_email_confirmation(entry.registration) emails.send_registration_email_confirmation(entry.registration)
except Registration.DoesNotExist: except Registration.DoesNotExist:
pass pass
elif action == 'revert':
services.revert_entry(entry)
if entry_qs.filter(renewal=None).exists(): if entry_qs.filter(renewal=None).exists():
content_type = ContentType.objects.get_for_model(Registration) content_type = ContentType.objects.get_for_model(Registration)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment