Files
benevoles/backend/app/migrations/versions/0026_badge_editor_v2.py
T
AdamThomasandClaude Opus 5.5 ced0855d47
ci-cd / build-backend (push) Successful in 30s
ci-cd / deploy (push) Successful in 13s
ci-cd / build-frontend (push) Successful in 22s
Refonte du créateur de badges et nombre de badges par bénévole
Créateur de badges refait d'après la maquette : champs sur le recto et le
verso (BadgeField.face, verso placé en miroir dans le PDF pour le
recto-verso), fond de zone, réduction automatique du texte, photo ovale,
initiales sans photo, nom sur deux lignes (migration 0026) ; éditeur en
trois colonnes (champs, aperçu recto/verso avec de vrais bénévoles,
inspecteur), formats prédéfinis, annuler, flèches, zoom, repères de
découpe, dépôt d'image sur l'aperçu, contrôle de tous les badges avant
génération.

Nombre de badges par bénévole (Volunteer.badge_count, 1 par défaut,
migration 0027) : champ sur la fiche, autant d'exemplaires sur les
planches, total affiché à la génération, colonne dans l'export Excel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 19:20:42 +01:00

63 lines
2.3 KiB
Python

"""Éditeur de badges v2 (verso, fond de zone, auto-ajustement, photo ovale)
Revision ID: 0026_badge_editor_v2
Revises: 0025_badge_field_text
Create Date: 2026-10-27
`badge_field.face` : face du badge (`FRONT`/`BACK`) — les champs existants
deviennent des champs du recto. La contrainte d'unicité passe de
(`edition_id`, `field_type`) à (`edition_id`, `face`, `field_type`) : un même
champ peut figurer sur les deux faces. `bg_color` (fond de la zone,
transparent si `NULL`), `auto_fit` (réduction automatique du texte) et
`photo_shape` (`RECT`/`OVAL`, champ `PHOTO`).
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
revision: str = "0026_badge_editor_v2"
down_revision: str | None = "0025_badge_field_text"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
_FACE = sa.Enum("FRONT", "BACK", name="badgeface", native_enum=False)
_PHOTO_SHAPE = sa.Enum("RECT", "OVAL", name="badgephotoshape", native_enum=False)
def upgrade() -> None:
op.add_column(
"badge_field",
sa.Column("face", _FACE, server_default="FRONT", nullable=False),
)
op.add_column("badge_field", sa.Column("bg_color", sa.String(), nullable=True))
op.add_column(
"badge_field",
sa.Column("auto_fit", sa.Boolean(), server_default="false", nullable=False),
)
op.add_column(
"badge_field",
sa.Column("photo_shape", _PHOTO_SHAPE, server_default="RECT", nullable=False),
)
op.drop_constraint("uq_badge_field_edition_type", "badge_field", type_="unique")
op.create_unique_constraint(
"uq_badge_field_edition_face_type",
"badge_field",
["edition_id", "face", "field_type"],
)
def downgrade() -> None:
# Le verso n'existait pas : ses champs sont perdus (sinon l'ancienne
# contrainte d'unicité échouerait sur un champ présent sur les deux faces).
op.execute("DELETE FROM badge_field WHERE face = 'BACK'")
op.drop_constraint("uq_badge_field_edition_face_type", "badge_field", type_="unique")
op.create_unique_constraint(
"uq_badge_field_edition_type", "badge_field", ["edition_id", "field_type"]
)
op.drop_column("badge_field", "photo_shape")
op.drop_column("badge_field", "auto_fit")
op.drop_column("badge_field", "bg_color")
op.drop_column("badge_field", "face")