Files
benevoles/backend/app/migrations/versions/0018_pending_submissions_mecenat.py
T
AdamThomasandClaude Sonnet 5 a2b748566b
ci-cd / build-backend (push) Successful in 30s
ci-cd / build-frontend (push) Successful in 18s
ci-cd / deploy (push) Successful in 12s
Inscription en deux temps, emails de confirmation et export Excel des bénévoles
Formulaire public — paiement en ligne :
- Le bénévole n'est plus compté en base tant qu'un paiement en ligne choisi
  n'est pas confirmé (PendingFormSubmission, promu en Volunteer à la
  confirmation, webhook ou vérification en direct).
- Type de paiement « mécénat » : étape d'adresse postale avant le paiement,
  conservée sur le bénévole pour un reçu fiscal (cerfa) ultérieur.
- Page de confirmation au retour de SumUp, avec relance possible après
  échec/expiration sans ressaisir le formulaire.
- « Je paierai sur place » remplace « je ne participe pas » ; tous les
  champs activés par la coordination sont désormais obligatoires.
- La fiche bénévole n'affiche plus l'état des cases à cocher, seulement le
  résultat réel du paiement (libellé, montant, statut).

Emails :
- Email de confirmation d'inscription à la création du bénévole (tient lieu
  de reçu de paiement quand une cotisation est payée en ligne).
- Mise en forme HTML au thème de l'application (logo de l'édition en
  en-tête) pour tous les emails envoyés, texte brut conservé en repli.

Export Excel des bénévoles (COORDINATION) : coordonnées, vœux résolus en
noms lisibles, cotisation et mécénat.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 07:41:58 +02:00

107 lines
4.4 KiB
Python

"""Inscription en deux temps + mécénat (cerfa)
Revision ID: 0018_pending_submissions_mecenat
Revises: 0017_form_payment_options
Create Date: 2026-09-29
Un bénévole qui choisit un paiement en ligne n'est plus créé en base tant que
le paiement n'est pas confirmé : `pending_form_submission` retient le
formulaire (et l'état du checkout SumUp) jusqu'à la promotion en `Volunteer`
(`app/api/forms.py:_promote_pending`) ou jusqu'à purge si jamais payé.
`form_payment_option.requires_mecenat_info` distingue un type de paiement
« mécénat » (étape d'adresse postale avant paiement, cerfa) ; les coordonnées
correspondantes vivent sur `volunteer.mecenat_*` une fois le bénévole promu.
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
revision: str = "0018_pending_submissions_mecenat"
down_revision: str | None = "0017_form_payment_options"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
_FEE_STATUS_ENUM = sa.Enum(
"PENDING", "PAID", "FAILED", "EXPIRED",
name="feepaymentstatus", native_enum=False,
)
def upgrade() -> None:
op.add_column(
"form_payment_option",
sa.Column(
"requires_mecenat_info", sa.Boolean(), server_default="false", nullable=False
),
)
op.add_column("volunteer", sa.Column("mecenat_address", sa.String(), nullable=True))
op.add_column("volunteer", sa.Column("mecenat_city", sa.String(), nullable=True))
op.add_column("volunteer", sa.Column("mecenat_postal_code", sa.String(), nullable=True))
op.add_column("volunteer", sa.Column("mecenat_country", sa.String(), nullable=True))
op.create_table(
"pending_form_submission",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("edition_id", sa.Uuid(), nullable=False),
sa.Column("first_name", sa.String(), nullable=True),
sa.Column("last_name", sa.String(), nullable=True),
sa.Column("email", sa.String(), nullable=True),
sa.Column("phone", sa.String(), nullable=True),
sa.Column("comment", sa.String(), nullable=True),
sa.Column("companion_wish_note", sa.String(), nullable=True),
sa.Column("available", sa.Boolean(), server_default="false", nullable=False),
sa.Column("position_wish_ids_json", sa.String(), nullable=True),
sa.Column("artist_wish_ids_json", sa.String(), nullable=True),
sa.Column("photo", sa.LargeBinary(), nullable=True),
sa.Column("photo_content_type", sa.String(), nullable=True),
sa.Column("payment_label", sa.String(), nullable=False),
sa.Column("payment_amount", sa.Float(), nullable=False),
sa.Column(
"requires_mecenat_info", sa.Boolean(), server_default="false", nullable=False
),
sa.Column("mecenat_address", sa.String(), nullable=True),
sa.Column("mecenat_city", sa.String(), nullable=True),
sa.Column("mecenat_postal_code", sa.String(), nullable=True),
sa.Column("mecenat_country", sa.String(), nullable=True),
sa.Column("checkout_id", sa.String(), nullable=True),
sa.Column("checkout_status", _FEE_STATUS_ENUM, nullable=True),
sa.Column("promoted_volunteer_id", sa.Uuid(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["edition_id"], ["edition.id"], ondelete="CASCADE"),
sa.ForeignKeyConstraint(
["promoted_volunteer_id"], ["volunteer.id"], ondelete="SET NULL"
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
"ix_pending_form_submission_edition_id",
"pending_form_submission",
["edition_id"],
)
op.create_index(
"ix_pending_form_submission_checkout_id",
"pending_form_submission",
["checkout_id"],
)
def downgrade() -> None:
op.drop_index(
"ix_pending_form_submission_checkout_id", table_name="pending_form_submission"
)
op.drop_index(
"ix_pending_form_submission_edition_id", table_name="pending_form_submission"
)
op.drop_table("pending_form_submission")
op.drop_column("volunteer", "mecenat_country")
op.drop_column("volunteer", "mecenat_postal_code")
op.drop_column("volunteer", "mecenat_city")
op.drop_column("volunteer", "mecenat_address")
op.drop_column("form_payment_option", "requires_mecenat_info")