Formulaire public : paiement de la cotisation via l'API SumUp (remplace Yapla)
Remplace le simple lien Yapla statique par une vraie intégration API SumUp : checkout hébergé créé à la soumission du formulaire, statut de paiement (PENDING/PAID/FAILED/EXPIRED) tenu à jour par un webhook SumUp et visible sur la fiche du bénévole. La cotisation n'est plus un montant unique : la coordination configure autant de types de paiement qu'elle veut (libellé + montant, ex. « Cotisation classique », « Mécénat »), et le bénévole en choisit un à l'inscription — le libellé et le montant choisis sont figés sur le bénévole, indépendamment d'une modification ultérieure de la config. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0be5daa89c
commit
0bd38a6465
@@ -9,6 +9,7 @@ from app.models import (
|
||||
AssignmentSource,
|
||||
BadgeAlign,
|
||||
BadgeFieldType,
|
||||
FeePaymentStatus,
|
||||
FormFieldType,
|
||||
PositionCategory,
|
||||
Role,
|
||||
@@ -92,6 +93,15 @@ class VolunteerRead(ApiModel):
|
||||
companion_wish_note: str | None
|
||||
self_declared_available: bool
|
||||
willing_to_pay_fee: bool
|
||||
# Paiement de la cotisation via SumUp (voir CLAUDE.md § 2, `Volunteer`) —
|
||||
# `fee_payment_label`/`fee_amount` : copie figée du type de paiement
|
||||
# choisi (pas la config actuelle, qui peut avoir changé depuis).
|
||||
# `fee_payment_status` reste `None` tant qu'aucun checkout n'a jamais été
|
||||
# créé pour ce bénévole.
|
||||
fee_payment_label: str | None
|
||||
fee_amount: float | None
|
||||
fee_payment_status: FeePaymentStatus | None
|
||||
fee_paid_at: dt.datetime | None
|
||||
created_at: dt.datetime
|
||||
updated_at: dt.datetime
|
||||
|
||||
@@ -493,16 +503,43 @@ class FormTemplateRead(ApiModel):
|
||||
fields: list[FormFieldType]
|
||||
has_logo: bool
|
||||
description: str | None
|
||||
yapla_url: str | None
|
||||
sumup_merchant_code: str | None
|
||||
# `sumup_api_key` (secret) n'est jamais renvoyé — seulement s'il est
|
||||
# défini, comme `has_logo` pour le logo.
|
||||
sumup_api_key_set: bool
|
||||
|
||||
|
||||
class FormTemplateUpdate(ApiModel):
|
||||
"""`None`/absent = inchangé pour chaque champ (`exclude_unset`) — permet
|
||||
de changer `is_open` sans toucher `description`/`yapla_url`, etc."""
|
||||
de changer `is_open` sans toucher `description`/`sumup_*`, etc. Chaîne
|
||||
vide sur `sumup_api_key` = efface le secret enregistré."""
|
||||
|
||||
is_open: bool | None = None
|
||||
description: str | None = None
|
||||
yapla_url: str | None = None
|
||||
sumup_merchant_code: str | None = None
|
||||
sumup_api_key: str | None = None
|
||||
|
||||
|
||||
class FormPaymentOptionRead(ApiModel):
|
||||
id: uuid.UUID
|
||||
edition_id: uuid.UUID
|
||||
label: str
|
||||
amount: float
|
||||
order: int
|
||||
created_at: dt.datetime
|
||||
updated_at: dt.datetime
|
||||
|
||||
|
||||
class FormPaymentOptionCreate(ApiModel):
|
||||
label: str
|
||||
amount: float
|
||||
order: int = 0
|
||||
|
||||
|
||||
class FormPaymentOptionUpdate(ApiModel):
|
||||
label: str | None = None
|
||||
amount: float | None = None
|
||||
order: int | None = None
|
||||
|
||||
|
||||
class PublicPositionOption(ApiModel):
|
||||
@@ -516,6 +553,15 @@ class PublicArtistOption(ApiModel):
|
||||
performance_date: dt.date
|
||||
|
||||
|
||||
class PublicPaymentOption(ApiModel):
|
||||
"""Type de paiement proposé au bénévole sur le formulaire public — un
|
||||
montant n'est pas un secret, contrairement aux identifiants SumUp."""
|
||||
|
||||
id: uuid.UUID
|
||||
label: str
|
||||
amount: float
|
||||
|
||||
|
||||
class PublicFormConfig(ApiModel):
|
||||
"""Tout ce qu'il faut pour afficher le formulaire public — jamais plus :
|
||||
ni les bénévoles déjà inscrits, ni les créneaux/affectations de
|
||||
@@ -527,8 +573,26 @@ class PublicFormConfig(ApiModel):
|
||||
artists: list[PublicArtistOption]
|
||||
has_logo: bool
|
||||
description: str | None
|
||||
yapla_url: str | None
|
||||
# `True` si l'édition a configuré SumUp (identifiants marchand + au
|
||||
# moins un type de paiement) — utilisé par le front-end pour afficher le
|
||||
# choix de paiement près de `WILLING_TO_PAY_FEE`, sans jamais exposer les
|
||||
# identifiants eux-mêmes.
|
||||
sumup_enabled: bool
|
||||
payment_options: list[PublicPaymentOption]
|
||||
|
||||
|
||||
class FormSubmissionResult(ApiModel):
|
||||
volunteer_id: uuid.UUID
|
||||
# Lien de paiement hébergé SumUp, si un checkout a pu être créé (voir
|
||||
# `app/api/forms.py:submit_public_form`) — `None` si le bénévole n'a
|
||||
# choisi aucun type de paiement, si SumUp n'est pas configuré, ou en cas
|
||||
# d'échec de l'appel API (best effort, l'inscription reste valide).
|
||||
sumup_checkout_url: str | None = None
|
||||
|
||||
|
||||
class SumUpWebhookPayload(ApiModel):
|
||||
"""Corps envoyé par SumUp à `return_url` — voir la doc SumUp sur les
|
||||
webhooks. Le seul événement existant à ce jour."""
|
||||
|
||||
event_type: str
|
||||
id: str
|
||||
|
||||
Reference in New Issue
Block a user