Type de paiement à montant libre (pensé pour le mécénat)
FormPaymentOption.free_amount (migration 0021) : case « Montant libre » sur l'écran Inscriptions ; le montant configuré devient le minimum et le bénévole saisit le sien sur le formulaire public (payment_amount, virgule ou point, 2 décimales max, plafond 10 000 € contre une faute de frappe — 422 form.invalid_free_amount sinon). Validé côté client avant l'envoi, le serveur restant seul juge. Le montant choisi est celui du checkout SumUp, recopié sur la fiche, l'email de confirmation et le cerfa. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ccd769d04e
commit
c49ce520e3
@@ -116,6 +116,16 @@ const imageSizeMm = async (file: File): Promise<{ width_mm: number; height_mm: n
|
||||
|
||||
// Approche de `str.title()` (Python) utilisé côté back-end à la soumission
|
||||
// du formulaire public — capitalise chaque mot (« - » compris).
|
||||
/** Miroir de `app/api/forms.py:_free_amount` (montant libre). */
|
||||
const freeAmount = (raw: string | undefined, minimum: number): number => {
|
||||
const text = (raw ?? '').trim().replace(',', '.');
|
||||
const value = Number(text);
|
||||
if (!/^\d+(\.\d{1,2})?$/.test(text) || value < minimum || value > 10000) {
|
||||
throw new ApiError(422, 'form.invalid_free_amount');
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const titleCase = (s: string): string =>
|
||||
s.toLowerCase().replace(/\b\p{L}/gu, (c) => c.toUpperCase());
|
||||
|
||||
@@ -1647,6 +1657,7 @@ export function createMockApi(): PlanningApi {
|
||||
label: o.label,
|
||||
amount: o.amount,
|
||||
requires_mecenat_info: o.requires_mecenat_info,
|
||||
free_amount: o.free_amount,
|
||||
})),
|
||||
});
|
||||
},
|
||||
@@ -1666,6 +1677,7 @@ export function createMockApi(): PlanningApi {
|
||||
amount: body.amount,
|
||||
order: body.order ?? 0,
|
||||
requires_mecenat_info: body.requires_mecenat_info ?? false,
|
||||
free_amount: body.free_amount ?? false,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
};
|
||||
@@ -1691,6 +1703,7 @@ export function createMockApi(): PlanningApi {
|
||||
...(body.requires_mecenat_info !== undefined
|
||||
? { requires_mecenat_info: body.requires_mecenat_info }
|
||||
: {}),
|
||||
...(body.free_amount !== undefined ? { free_amount: body.free_amount } : {}),
|
||||
updated_at: touch(),
|
||||
});
|
||||
return delay<FormPaymentOptionRead>(option);
|
||||
@@ -1802,7 +1815,9 @@ export function createMockApi(): PlanningApi {
|
||||
artistIds,
|
||||
photo,
|
||||
paymentLabel: paymentOption.label,
|
||||
paymentAmount: paymentOption.amount,
|
||||
paymentAmount: paymentOption.free_amount
|
||||
? freeAmount(body.payment_amount, paymentOption.amount)
|
||||
: paymentOption.amount,
|
||||
requiresMecenatInfo: paymentOption.requires_mecenat_info,
|
||||
mecenatAddress: null,
|
||||
mecenatCity: null,
|
||||
|
||||
Reference in New Issue
Block a user