Étape 58 : le présent / absent du référent est enregistré sur
l'affectation (Assignment.attendance + heure, migration 0030,
PUT .../assignments/{id}/attendance) au lieu de disparaître au
rechargement.
Étape 59 : section « Présence » de l'écran Statistiques — créneaux en
cours et créneaux terminés, par poste, rafraîchie toutes les 30 s.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
2.8 KiB
Python
73 lines
2.8 KiB
Python
"""Pointage présent / absent d'un bénévole sur son créneau
|
|
(`PUT .../assignments/{id}/attendance`) : enregistré en base, par le
|
|
référent du poste ou la coordination."""
|
|
|
|
from app.models import Assignment, Role
|
|
from tests.factories import dt_at, make_position, make_shift, make_volunteer
|
|
|
|
|
|
def _assignment(session, edition, lead=None):
|
|
position = make_position(session, edition)
|
|
if lead is not None:
|
|
position.lead_account_id = lead.id
|
|
session.add(position)
|
|
session.commit()
|
|
shift = make_shift(session, edition, position, start=dt_at(10, 18), end=dt_at(10, 22))
|
|
volunteer = make_volunteer(session, edition)
|
|
assignment = Assignment(edition_id=edition.id, volunteer_id=volunteer.id, shift_id=shift.id)
|
|
session.add(assignment)
|
|
session.commit()
|
|
session.refresh(assignment)
|
|
return assignment
|
|
|
|
|
|
def _url(edition, assignment):
|
|
return f"/editions/{edition.id}/assignments/{assignment.id}/attendance"
|
|
|
|
|
|
def test_lead_marks_attendance_and_it_is_kept(edition, session, make_account, as_account):
|
|
lead = make_account(Role.LEAD)
|
|
assignment = _assignment(session, edition, lead)
|
|
client = as_account(lead)
|
|
|
|
resp = client.put(_url(edition, assignment), json={"attendance": "PRESENT"})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["attendance"] == "PRESENT"
|
|
assert resp.json()["attendance_marked_at"] is not None
|
|
|
|
# Relu ensuite (rechargement de l'écran) : le pointage est toujours là.
|
|
(listed,) = client.get(f"/editions/{edition.id}/assignments").json()
|
|
assert listed["attendance"] == "PRESENT"
|
|
|
|
|
|
def test_attendance_can_be_switched_and_cleared(client, edition, session):
|
|
assignment = _assignment(session, edition)
|
|
assert client.put(_url(edition, assignment), json={"attendance": "ABSENT"}).json()[
|
|
"attendance"
|
|
] == "ABSENT"
|
|
cleared = client.put(_url(edition, assignment), json={"attendance": None}).json()
|
|
assert cleared["attendance"] is None
|
|
assert cleared["attendance_marked_at"] is None
|
|
|
|
|
|
def test_lead_of_another_position_cannot_mark(edition, session, make_account, as_account):
|
|
assignment = _assignment(session, edition, make_account(Role.LEAD))
|
|
resp = as_account(make_account(Role.LEAD)).put(
|
|
_url(edition, assignment), json={"attendance": "PRESENT"}
|
|
)
|
|
assert resp.status_code == 403
|
|
|
|
|
|
def test_volunteer_cannot_mark(edition, session, make_account, as_account):
|
|
assignment = _assignment(session, edition)
|
|
resp = as_account(make_account(Role.VOLUNTEER)).put(
|
|
_url(edition, assignment), json={"attendance": "PRESENT"}
|
|
)
|
|
assert resp.status_code == 403
|
|
|
|
|
|
def test_unknown_status_is_rejected(client, edition, session):
|
|
assignment = _assignment(session, edition)
|
|
resp = client.put(_url(edition, assignment), json={"attendance": "LATE"})
|
|
assert resp.status_code == 422
|