Solveur : le malus de chaînage n'est pas limité au même poste
Correction : le malus ajouté précédemment ne se déclenchait que si le bénévole avait tenu le créneau précédent du *même* poste. L'intention était plus générale — limiter les enchaînements de shifts d'un bénévole, quel que soit le poste, pas seulement faire tourner un poste en particulier. - `SolverShift.predecessor_shift_id: str | None` → `predecessor_shift_ids: frozenset[str]` : l'ensemble des créneaux (n'importe quel poste) du même jour dont la fin coïncide avec le début de celui-ci. Peut contenir plusieurs ids (plusieurs postes se terminant à la même heure). - Loader : le calcul du prédécesseur se fait maintenant sur tous les créneaux de l'édition regroupés par jour (comparaison des heures de fin), plus par poste. - Miroir côté mock (`buildPredecessorMap`, `runSolver`). - Nouveau test d'intégration (`test_api_solver.py`) : deux postes différents, confirme que le chaînage s'applique bien d'un poste à l'autre. - CLAUDE.md à jour. Vérifié : 185 tests backend (dont le nouveau), ruff, alembic check ; typecheck/lint/build/smoke frontend. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
64e2f86647
commit
b97b95c606
@@ -71,6 +71,37 @@ def test_avoids_volunteer_whose_wished_artist_would_be_missed(client, edition, s
|
||||
assert suggestion["volunteer_ids"] == [str(indiff.id)]
|
||||
|
||||
|
||||
def test_chain_penalty_applies_across_different_positions(client, edition, session):
|
||||
from app.models import Assignment, PositionCategory
|
||||
|
||||
# Deux postes différents, même jour, repos suffisant (8 h pile) entre les
|
||||
# deux créneaux : seul le chaînage (n'importe quel poste) doit
|
||||
# différencier les deux bénévoles pour le second créneau.
|
||||
bar = make_position(session, edition, name="Bar")
|
||||
entrance = make_position(session, edition, name="Entrée", category=PositionCategory.WELCOME)
|
||||
|
||||
morning_shift = make_shift(
|
||||
session, edition, bar,
|
||||
start=dt_at(10, 8), end=dt_at(10, 12), min_staff=1, ideal_staff=1,
|
||||
)
|
||||
evening_shift = make_shift(
|
||||
session, edition, entrance,
|
||||
start=dt_at(10, 20), end=dt_at(10, 23), min_staff=1, ideal_staff=1,
|
||||
)
|
||||
chained = make_volunteer(session, edition, email="chained@ex.fr")
|
||||
session.add(
|
||||
Assignment(edition_id=edition.id, volunteer_id=chained.id, shift_id=morning_shift.id)
|
||||
)
|
||||
session.commit()
|
||||
fresh = make_volunteer(session, edition, email="fresh@ex.fr")
|
||||
|
||||
resp = client.post(_url(edition, "/suggestions"))
|
||||
suggestion = next(
|
||||
s for s in resp.json()["suggestions"] if s["shift_id"] == str(evening_shift.id)
|
||||
)
|
||||
assert suggestion["volunteer_ids"] == [str(fresh.id)]
|
||||
|
||||
|
||||
def test_unknown_edition_is_404(client):
|
||||
assert client.post(f"/editions/{uuid.uuid4()}/solver/suggestions").status_code == 404
|
||||
|
||||
|
||||
Reference in New Issue
Block a user