Files
e-ticket/templates/admin/siret_check.html.twig
Serreau Jovann 100ff96c70 Add SIRET/RNA verification, organizer management, registration flow pages
SIRET/RNA verification:
- Create SiretService with API gouv lookup + JOAFE RNA lookup + cache pool (24h)
- Verification page: declared info vs API data side by side
- Display NAF code + label (from naf.json), nature juridique code + label
- Association/Entreprise/EI badges, ESS badge, RNA, coordonnees lat/long
- JOAFE section: objet, regime, domaine, dates, lieu, PDF download link
- Tranche effectif with readable labels
- Refresh cache button
- Page restricted to non-approved organizers only

Organizer approval flow:
- Approval form with offer (free/basic/custom) and commission rate (default 3%)
- Add commissionRate field to User entity + migration
- Rejection form with required reason textarea, sent in email
- Edit page for approved organizers: all fields modifiable
- Modify button in approved organizers table

Registration flow pages:
- Post-registration success page with email verification message
- Organizer gets additional 48h staff review notice
- Post-email-verification page: confirmed for buyers, 48h notice for organizers

Dashboard:
- Simplified Meilisearch sync to single button

Tests: SiretServiceTest (9), AdminControllerTest (31), RegistrationControllerTest updated, UserTest updated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:25:04 +01:00

262 lines
18 KiB
Twig

{% extends 'admin/base.html.twig' %}
{% block title %}Verification Entreprise / Association - {{ siret }}{% endblock %}
{% block body %}
<div style="margin-bottom:2rem;">
<h1 class="text-3xl font-black uppercase tracking-tighter italic" style="border-bottom:4px solid #111827;display:inline-block;margin-bottom:0.5rem;">Verification Entreprise / Association</h1>
<p class="font-bold text-gray-500 italic">{{ user.firstName }} {{ user.lastName }}{{ siret }}</p>
</div>
<div style="display:flex;flex-wrap:wrap;gap:1.5rem;">
<div style="flex:1;min-width:300px;">
<div style="border:4px solid #111827;box-shadow:6px 6px 0 rgba(0,0,0,1);background:white;padding:1.5rem;">
<h2 class="text-sm font-black uppercase tracking-widest" style="margin-bottom:1rem;">Informations declarees</h2>
<table style="width:100%;border-collapse:collapse;">
<tbody>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Nom</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ user.firstName }} {{ user.lastName }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Raison sociale</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ user.companyName }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">SIRET</td>
<td style="padding:0.5rem 0;" class="text-sm font-mono">{{ user.siret }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Adresse</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ user.address }}, {{ user.postalCode }} {{ user.city }}</td>
</tr>
<tr>
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Telephone</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ user.phone }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div style="flex:1;min-width:300px;">
<div style="border:4px solid #111827;box-shadow:6px 6px 0 rgba(0,0,0,1);background:white;padding:1.5rem;">
<h2 class="text-sm font-black uppercase tracking-widest" style="margin-bottom:1rem;">Donnees API Gouvernement</h2>
{% if data %}
<div style="margin-bottom:1rem;display:flex;gap:0.5rem;flex-wrap:wrap;">
{% if data.complements is defined and data.complements.est_association is defined and data.complements.est_association %}
<span style="background:#dbeafe;border:2px solid #111827;padding:0.15rem 0.75rem;" class="text-xs font-black uppercase">Association</span>
{% elseif data.complements is defined and data.complements.est_entrepreneur_individuel is defined and data.complements.est_entrepreneur_individuel %}
<span style="background:#fef3c7;border:2px solid #111827;padding:0.15rem 0.75rem;" class="text-xs font-black uppercase">Entrepreneur individuel</span>
{% else %}
<span style="background:#e0e7ff;border:2px solid #111827;padding:0.15rem 0.75rem;" class="text-xs font-black uppercase">Entreprise</span>
{% endif %}
{% if data.complements is defined and data.complements.est_ess is defined and data.complements.est_ess %}
<span style="background:#d1fae5;border:2px solid #111827;padding:0.15rem 0.75rem;" class="text-xs font-black uppercase">ESS</span>
{% endif %}
</div>
<table style="width:100%;border-collapse:collapse;">
<tbody>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Denomination</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ data.nom_complet ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">SIREN</td>
<td style="padding:0.5rem 0;" class="text-sm font-mono">{{ data.siren ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Nature juridique</td>
<td style="padding:0.5rem 0;" class="text-sm">
{% if data.nature_juridique is defined and data.nature_juridique %}
<span class="font-mono">{{ data.nature_juridique }}</span> — {{ data.libelle_nature_juridique ?? '' }}
{% else %}
{% endif %}
</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Siege</td>
<td style="padding:0.5rem 0;" class="text-sm">
{% if data.siege is defined and data.siege %}
{{ data.siege.adresse ?? '' }}, {{ data.siege.code_postal ?? '' }} {{ data.siege.libelle_commune ?? '' }}
{% else %}
{% endif %}
</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Activite (NAF)</td>
<td style="padding:0.5rem 0;" class="text-sm">
{% if data.activite_principale is defined and data.activite_principale %}
<span class="font-mono">{{ data.activite_principale }}</span> — {{ data.libelle_activite_principale ?? '' }}
{% else %}
{% endif %}
</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Tranche effectif</td>
<td style="padding:0.5rem 0;" class="text-sm">
{% set te = data.tranche_effectif_salarie ?? 'NN' %}
{% set te_labels = {
'NN': 'Non renseigne',
'00': '0 salarie',
'01': '1 ou 2 salaries',
'02': '3 a 5 salaries',
'03': '6 a 9 salaries',
'11': '10 a 19 salaries',
'12': '20 a 49 salaries',
'21': '50 a 99 salaries',
'22': '100 a 199 salaries',
'31': '200 a 249 salaries',
'32': '250 a 499 salaries',
'41': '500 a 999 salaries',
'42': '1 000 a 1 999 salaries',
'51': '2 000 a 4 999 salaries',
'52': '5 000 a 9 999 salaries',
'53': '10 000 salaries et plus'
} %}
{{ te_labels[te] ?? te }}
</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Date creation</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ data.date_creation ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Statut</td>
<td style="padding:0.5rem 0;">
{% if data.etat_administratif is defined and data.etat_administratif == 'A' %}
<span style="background:#d1fae5;border:2px solid #111827;padding:0.15rem 0.5rem;" class="text-xs font-black uppercase">Active</span>
{% else %}
<span style="background:#fee2e2;border:2px solid #111827;padding:0.15rem 0.5rem;" class="text-xs font-black uppercase">Fermee</span>
{% endif %}
</td>
</tr>
{% if data.complements is defined and data.complements.est_association is defined and data.complements.est_association %}
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">RNA</td>
<td style="padding:0.5rem 0;" class="text-sm font-mono">{{ data.complements.identifiant_association ?? '—' }}</td>
</tr>
{% endif %}
<tr>
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Coordonnees</td>
<td style="padding:0.5rem 0;" class="text-sm">
{% if data.siege is defined and data.siege.latitude is defined and data.siege.longitude is defined and data.siege.latitude and data.siege.longitude %}
<span class="font-mono">{{ data.siege.latitude }}, {{ data.siege.longitude }}</span>
{% else %}
{% endif %}
</td>
</tr>
</tbody>
</table>
{% else %}
<div style="padding:2rem;text-align:center;">
<span style="background:#fee2e2;border:2px solid #111827;padding:0.25rem 0.75rem;" class="text-xs font-black uppercase">SIRET non trouve</span>
<p class="text-gray-400 text-sm font-bold" style="margin-top:0.5rem;">Aucun resultat retourne par l'API pour ce SIRET.</p>
</div>
{% endif %}
</div>
</div>
</div>
{% if rnaData %}
<div style="margin-top:1.5rem;">
<div style="border:4px solid #111827;box-shadow:6px 6px 0 rgba(0,0,0,1);background:white;padding:1.5rem;">
<h2 class="text-sm font-black uppercase tracking-widest" style="margin-bottom:1rem;">Journal Officiel (JOAFE)</h2>
<table style="width:100%;border-collapse:collapse;">
<tbody>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;width:180px;" class="font-bold text-sm text-gray-400">RNA</td>
<td style="padding:0.5rem 0;" class="text-sm font-mono">{{ rnaData.numero_rna ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Regime</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ rnaData.association_type_libelle ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;vertical-align:top;" class="font-bold text-sm text-gray-400">Objet</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ rnaData.objet ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Domaine d'activite</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ rnaData.domaine_activite_libelle_categorise ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Date declaration</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ rnaData.datedeclaration ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Date parution JOAFE</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ rnaData.dateparution ?? '—' }}</td>
</tr>
<tr style="border-bottom:1px solid #e5e7eb;">
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">Lieu declaration</td>
<td style="padding:0.5rem 0;" class="text-sm">{{ rnaData.lieupref ?? '—' }}</td>
</tr>
<tr>
<td style="padding:0.5rem 0;" class="font-bold text-sm text-gray-400">PDF JOAFE</td>
<td style="padding:0.5rem 0;">
{% if rnaData.url_pdf is defined and rnaData.url_pdf %}
<a href="{{ rnaData.url_pdf }}" target="_blank" style="border:2px solid #111827;padding:0.15rem 0.5rem;background:#fabf04;display:inline-block;" class="text-xs font-black uppercase hover:bg-indigo-600 hover:text-black transition-all">Telecharger</a>
{% else %}
{% endif %}
</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endif %}
<div style="margin-top:2rem;display:flex;gap:0.75rem;flex-wrap:wrap;">
<form method="post" action="{{ path('app_admin_siret_refresh', {id: user.id}) }}" style="display:inline;">
<button type="submit" style="padding:0.5rem 1rem;border:3px solid #111827;background:white;cursor:pointer;" class="font-black uppercase text-xs tracking-widest hover:bg-indigo-600 hover:text-black transition-all">Rafraichir SIRET</button>
</form>
<a href="{{ path('app_admin_organizers') }}" style="padding:0.5rem 1rem;border:3px solid #111827;background:white;display:inline-block;" class="font-black uppercase text-xs tracking-widest hover:bg-gray-100 transition-all">Retour</a>
</div>
<div style="display:flex;flex-wrap:wrap;gap:1.5rem;margin-top:2rem;">
<div style="flex:1;min-width:300px;">
<div style="border:4px solid #111827;box-shadow:6px 6px 0 rgba(0,0,0,1);background:white;padding:1.5rem;">
<h2 class="text-sm font-black uppercase tracking-widest" style="margin-bottom:1rem;color:#16a34a;">Approuver l'organisateur</h2>
<form method="post" action="{{ path('app_admin_approve_organizer', {id: user.id}) }}" style="display:flex;flex-direction:column;gap:1rem;">
<div>
<label for="approve_offer" style="font-size:10px;letter-spacing:0.1em;display:block;margin-bottom:0.5rem;" class="font-black uppercase text-gray-400">Offre</label>
<select id="approve_offer" name="offer" style="width:100%;padding:0.5rem 0.75rem;border:3px solid #111827;font-weight:700;outline:none;cursor:pointer;">
<option value="free">Gratuit</option>
<option value="basic">Basique</option>
<option value="custom">Sur-mesure</option>
</select>
</div>
<div>
<label for="approve_commission" style="font-size:10px;letter-spacing:0.1em;display:block;margin-bottom:0.5rem;" class="font-black uppercase text-gray-400">Taux de commission (%)</label>
<input type="number" id="approve_commission" name="commission_rate" value="3" step="0.1" min="0" max="100"
style="width:100%;padding:0.5rem 0.75rem;border:3px solid #111827;font-weight:700;outline:none;">
</div>
<button type="submit" style="padding:0.5rem 1rem;border:3px solid #111827;box-shadow:4px 4px 0 rgba(0,0,0,1);background:#fabf04;cursor:pointer;" class="font-black uppercase text-xs tracking-widest hover:bg-green-500 hover:text-black transition-all">Approuver l'organisateur</button>
</form>
</div>
</div>
<div style="flex:1;min-width:300px;">
<div style="border:4px solid #991b1b;box-shadow:6px 6px 0 rgba(0,0,0,1);background:white;padding:1.5rem;">
<h2 class="text-sm font-black uppercase tracking-widest" style="margin-bottom:1rem;color:#991b1b;">Refuser la demande</h2>
<form method="post" action="{{ path('app_admin_reject_organizer', {id: user.id}) }}" data-confirm="Etes-vous sur de vouloir refuser et supprimer le compte de {{ user.firstName }} {{ user.lastName }} ? Cette action est irreversible." style="display:flex;flex-direction:column;gap:1rem;">
<div>
<label for="reject_reason" style="font-size:10px;letter-spacing:0.1em;display:block;margin-bottom:0.5rem;" class="font-black uppercase text-gray-400">Motif du refus</label>
<textarea id="reject_reason" name="reason" required rows="4"
style="width:100%;padding:0.75rem 1rem;border:3px solid #111827;font-weight:700;outline:none;resize:vertical;"
placeholder="Expliquez la raison du refus..."></textarea>
</div>
<button type="submit" style="padding:0.5rem 1rem;border:3px solid #991b1b;box-shadow:4px 4px 0 rgba(0,0,0,1);background:#dc2626;color:white;cursor:pointer;" class="font-black uppercase text-xs tracking-widest hover:bg-red-800 transition-all">Refuser et supprimer le compte</button>
</form>
</div>
</div>
</div>
{% endblock %}