Nouvelle entité `Artist` (nom + jour de passage), CRUD
`/editions/{id}/artists` (lecture ouverte à tout compte de l'édition,
écriture COORDINATION), unicité (édition, nom, date).
La fiche bénévole porte deux listes de vœux, sur le modèle de
`skill_codes` (None = inchangé, [] = vider) :
- `artist_ids` : artistes que le bénévole veut voir (`volunteer_artist`) ;
- `wished_position_ids` : postes qu'il voudrait tenir
(`volunteer_position_wish`), distinct de l'affectation.
Un id étranger à l'édition renvoie 422 (`artist.unknown` /
`position.unknown`). Suppression d'un artiste : cascade sur les vœux.
Migration 0006. Jeu de démonstration et frontend inchangés (le front
suivra).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
132 lines
3.3 KiB
Python
132 lines
3.3 KiB
Python
"""Fabriques d'objets du domaine pour les tests (écriture directe en base)."""
|
|
|
|
import datetime as dt
|
|
|
|
from app.models import (
|
|
Artist,
|
|
Availability,
|
|
AvailabilityStatus,
|
|
Position,
|
|
PositionCategory,
|
|
Shift,
|
|
Skill,
|
|
Volunteer,
|
|
VolunteerSkill,
|
|
)
|
|
|
|
|
|
def make_position(session, edition, *, name="Bar", category=PositionCategory.BAR):
|
|
position = Position(edition_id=edition.id, name=name, category=category)
|
|
session.add(position)
|
|
session.commit()
|
|
session.refresh(position)
|
|
return position
|
|
|
|
|
|
def make_artist(
|
|
session, edition, *, name="Chilla", performance_date=dt.date(2026, 7, 10)
|
|
):
|
|
artist = Artist(
|
|
edition_id=edition.id, name=name, performance_date=performance_date
|
|
)
|
|
session.add(artist)
|
|
session.commit()
|
|
session.refresh(artist)
|
|
return artist
|
|
|
|
|
|
def make_shift(
|
|
session, edition, position, *, start, end, min_staff=1, ideal_staff=2, skills=()
|
|
):
|
|
shift = Shift(
|
|
edition_id=edition.id,
|
|
position_id=position.id,
|
|
starts_at=start,
|
|
ends_at=end,
|
|
min_staff=min_staff,
|
|
ideal_staff=ideal_staff,
|
|
)
|
|
session.add(shift)
|
|
session.flush()
|
|
for code in skills:
|
|
_link_skill(session, edition, code=code, shift=shift)
|
|
session.commit()
|
|
session.refresh(shift)
|
|
return shift
|
|
|
|
|
|
def make_volunteer(
|
|
session, edition, *, first_name="Alex", last_name="Martin", email=None, skills=()
|
|
):
|
|
volunteer = Volunteer(
|
|
edition_id=edition.id,
|
|
first_name=first_name,
|
|
last_name=last_name,
|
|
email=email,
|
|
)
|
|
session.add(volunteer)
|
|
session.flush()
|
|
for code in skills:
|
|
_link_skill(session, edition, volunteer=volunteer, code=code)
|
|
session.commit()
|
|
session.refresh(volunteer)
|
|
return volunteer
|
|
|
|
|
|
def make_availability(session, edition, volunteer, day_part, *, date, status):
|
|
row = Availability(
|
|
edition_id=edition.id,
|
|
volunteer_id=volunteer.id,
|
|
day_part_id=day_part.id,
|
|
date=date,
|
|
status=status,
|
|
)
|
|
session.add(row)
|
|
session.commit()
|
|
return row
|
|
|
|
|
|
def declare_available_all_day(session, edition, volunteer, day_parts, date):
|
|
for part in day_parts.values():
|
|
make_availability(
|
|
session,
|
|
edition,
|
|
volunteer,
|
|
part,
|
|
date=date,
|
|
status=AvailabilityStatus.AVAILABLE,
|
|
)
|
|
|
|
|
|
def _get_or_create_skill(session, edition, code) -> Skill:
|
|
from sqlmodel import select
|
|
|
|
skill = session.exec(
|
|
select(Skill)
|
|
.where(Skill.edition_id == edition.id)
|
|
.where(Skill.code == code)
|
|
).first()
|
|
if skill is None:
|
|
skill = Skill(edition_id=edition.id, code=code, label=code)
|
|
session.add(skill)
|
|
session.flush()
|
|
return skill
|
|
|
|
|
|
def _link_skill(session, edition, *, code, volunteer=None, shift=None):
|
|
from app.models import ShiftRequiredSkill
|
|
|
|
skill = _get_or_create_skill(session, edition, code)
|
|
if volunteer is not None:
|
|
session.add(
|
|
VolunteerSkill(volunteer_id=volunteer.id, skill_id=skill.id)
|
|
)
|
|
if shift is not None:
|
|
session.add(
|
|
ShiftRequiredSkill(shift_id=shift.id, skill_id=skill.id)
|
|
)
|
|
|
|
|
|
def dt_at(day: int, hour: int, minute: int = 0) -> dt.datetime:
|
|
return dt.datetime(2026, 7, day, hour, minute)
|