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>
107 lines
4.4 KiB
Python
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")
|