Skip to content

Commit

Permalink
employee_record.admin: Use transitions instead of a freehand input
Browse files Browse the repository at this point in the history
  • Loading branch information
rsebille committed Feb 10, 2025
1 parent eaf6dde commit 644e58e
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 2 deletions.
34 changes: 34 additions & 0 deletions itou/employee_record/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import itertools

import xworkflows
from django import forms
from django.contrib import admin, messages
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils import timezone
from django.utils.html import format_html
Expand Down Expand Up @@ -161,6 +163,7 @@ def schedule_approval_update_notification(self, request, queryset):

readonly_fields = (
"pk",
"status",
"created_at",
"updated_at",
"processed_at",
Expand Down Expand Up @@ -234,6 +237,8 @@ def schedule_approval_update_notification(self, request, queryset):
),
)

change_form_template = "admin/employee_records/employeerecord_change_form.html"

@admin.display(description="numéro d'agrément")
def approval_number_link(self, obj):
if approval_number := obj.approval_number:
Expand Down Expand Up @@ -269,6 +274,35 @@ def get_deleted_objects(self, objs, request):
perms_needed.discard(EmployeeRecordUpdateNotification._meta.verbose_name)
return deleted_objects, model_count, perms_needed, protected

def response_change(self, request, obj):
for transition in obj.status.transitions():
if f"transition_{transition.name}" in request.POST:
try:
getattr(obj, transition.name)(user=request.user)
except xworkflows.AbortTransition as e:
self.message_user(request, e, messages.ERROR)
return HttpResponseRedirect(request.get_full_path())

return super().response_change(request, obj)

def render_change_form(self, request, context, *, obj=None, **kwargs):
if obj:
system_transitions = {
models.EmployeeRecordTransition.WAIT_FOR_ASP_RESPONSE,
models.EmployeeRecordTransition.REJECT,
models.EmployeeRecordTransition.PROCESS,
}
context.update(
{
"available_transitions": [
transition
for transition in obj.status.transitions()
if getattr(obj, transition.name).is_available() and transition.name not in system_transitions
]
}
)
return super().render_change_form(request, context, **kwargs)


@admin.register(models.EmployeeRecordUpdateNotification)
class EmployeeRecordUpdateNotificationAdmin(ReadonlyMixin, ASPExchangeInformationAdminMixin, ItouModelAdmin):
Expand Down
2 changes: 1 addition & 1 deletion itou/employee_record/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def check_archive(self):
return not self.job_application.approval.is_valid() and not self.job_application.approval.can_be_prolonged

@xwf_models.transition()
def archive(self):
def archive(self, *, user=None):
# Remove proof of processing after delay
self.archived_json = None

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% extends 'admin/change_form.html' %}

{% block submit_buttons_top %}

{{ block.super }}

{% if perms.employee_record.change_employeerecord and available_transitions %}
<div class="submit-row" id="employee-record-transitions">
<p>Changer l'état de la fiche salarié :</p>
{% for transition in available_transitions %}
<input type='submit' class="danger js-with-confirm" name="transition_{{ transition.name }}" value="{{ transition.target.title }}">
{% endfor %}
</div>

<script nonce="{{ CSP_NONCE }}">
var buttons = document.getElementsByClassName("js-with-confirm");
Array.prototype.forEach.call(buttons, function(button) {
button.addEventListener("click", function(event) {
if (!confirm("Êtes vous certain de vouloir changer l'état à **" + event.target.value.toUpperCase() + '** ?')) {
event.preventDefault();
}
});
});
</script>
{% endif %}
{% endblock %}
57 changes: 57 additions & 0 deletions tests/employee_record/__snapshots__/test_admin.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# serializer version: 1
# name: test_available_transitions[ARCHIVED][actions]
'''
<div class="submit-row" id="employee-record-transitions">
<p>Changer l'état de la fiche salarié :</p>

<input class="danger js-with-confirm" name="transition_unarchive_new" type="submit" value="Nouvelle"/>

</div>
'''
# ---
# name: test_available_transitions[DISABLED][actions]
'''
<div class="submit-row" id="employee-record-transitions">
<p>Changer l'état de la fiche salarié :</p>

<input class="danger js-with-confirm" name="transition_ready" type="submit" value="Complétée"/>

<input class="danger js-with-confirm" name="transition_enable" type="submit" value="Nouvelle"/>

</div>
'''
# ---
# name: test_available_transitions[NEW][actions]
'''
<div class="submit-row" id="employee-record-transitions">
<p>Changer l'état de la fiche salarié :</p>

<input class="danger js-with-confirm" name="transition_ready" type="submit" value="Complétée"/>

<input class="danger js-with-confirm" name="transition_disable" type="submit" value="Désactivée"/>

</div>
'''
# ---
# name: test_available_transitions[PROCESSED][actions]
'''
<div class="submit-row" id="employee-record-transitions">
<p>Changer l'état de la fiche salarié :</p>

<input class="danger js-with-confirm" name="transition_disable" type="submit" value="Désactivée"/>

</div>
'''
# ---
# name: test_available_transitions[REJECTED][actions]
'''
<div class="submit-row" id="employee-record-transitions">
<p>Changer l'état de la fiche salarié :</p>

<input class="danger js-with-confirm" name="transition_ready" type="submit" value="Complétée"/>

<input class="danger js-with-confirm" name="transition_disable" type="submit" value="Désactivée"/>

</div>
'''
# ---
31 changes: 30 additions & 1 deletion tests/employee_record/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import pytest
from django.contrib import messages
from django.contrib.admin import helpers
from django.contrib.auth.models import Permission
from django.urls import reverse
from pytest_django.asserts import assertContains, assertMessages, assertRedirects
from pytest_django.asserts import assertContains, assertMessages, assertNotContains, assertRedirects

from itou.approvals.models import Approval
from itou.employee_record import models
from itou.employee_record.enums import Status
from itou.employee_record.models import EmployeeRecord
from tests.employee_record import factories
from tests.employee_record.factories import EmployeeRecordFactory
from tests.users.factories import ItouStaffFactory
from tests.utils.test import parse_response_to_soup


def test_schedule_approval_update_notification_when_notification_do_not_exists(admin_client):
Expand Down Expand Up @@ -104,3 +109,27 @@ def test_employee_record_deletion_with_notification(admin_client):
response = admin_client.post(delete_url, {"post": "yes"})
assertRedirects(response, reverse("admin:employee_record_employeerecord_changelist"))
assert EmployeeRecord.objects.filter(pk=ern.employee_record.pk).count() == 0


@pytest.mark.parametrize("status", Status)
def test_available_transitions(snapshot, client, status):
superuser = ItouStaffFactory(is_superuser=True)
rw_user = ItouStaffFactory(is_superuser=False)
rw_user.user_permissions.add(Permission.objects.get(codename="change_employeerecord"))
ro_user = ItouStaffFactory(is_superuser=False)
ro_user.user_permissions.add(Permission.objects.get(codename="view_employeerecord"))

employee_record = EmployeeRecordFactory(status=status)
url = reverse("admin:employee_record_employeerecord_change", args=[employee_record.pk])

for user in [superuser, rw_user]:
client.force_login(user)
response = client.get(url)
if status not in {Status.READY, Status.SENT}:
assert str(parse_response_to_soup(response, "#employee-record-transitions")) == snapshot(name="actions")
else:
assertNotContains(response, '<div class="submit-row" id="employee-record-transitions">')

client.force_login(ro_user)
response = client.get(url)
assertNotContains(response, '<div class="submit-row" id="employee-record-transitions">')

0 comments on commit 644e58e

Please sign in to comment.