fix: supprimer le calculateur de frais de livraison et la section 7.2 des CGV

Suppression complète du système de calcul de frais de livraison (rayon 30km depuis Danizy) :
- Route /estimer-la-livraison et template estimate_delivery.twig
- Calcul automatique livraison dans FlowController et ReserverController
- Champs distance/prix livraison dans la vue admin flow
- Ligne "Frais de livraison" sur les devis générés
- Section 7.2 (mise en relation + rayon 30km) dans les CGV (twig + PDF contrat/devis)
- Liens navigation "Estimer la livraison" (desktop + mobile)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-03-26 12:03:16 +01:00
parent 31b28e5df2
commit 553d12aac8
9 changed files with 17 additions and 525 deletions

View File

@@ -4,16 +4,9 @@
{% block title_header %}Réservation #{{ session.id }}{% endblock %}
{% block body %}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin="" nonce="{{ csp_nonce('script') }}"></script>
<div class="space-y-8 pb-20">
{% set isActionable = session.deliveryPrice is not null and session.typePaiement %}
{% set isActionable = session.typePaiement %}
<div class="flex items-center gap-3 justify-end">
<a href="{{ path('app_crm_flow') }}"
class="group relative flex items-center gap-2 px-6 py-3 bg-slate-700 hover:bg-slate-600 rounded-2xl text-white text-xs font-bold uppercase tracking-wider transition-all shadow-lg">
@@ -43,26 +36,16 @@
{# BILLING & DELIVERY CONFIG #}
{# BILLING CONFIG #}
<div class="bg-slate-800/40 backdrop-blur-xl border border-slate-700/50 rounded-[2rem] p-8">
<h3 class="text-lg font-bold text-white mb-6 flex items-center gap-3">
<div class="p-2 bg-indigo-500/10 rounded-lg text-indigo-500">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
</div>
Configuration Facturation & Livraison
Configuration Facturation
</h3>
<form action="{{ path('app_crm_flow_update', {id: session.id}) }}" method="post" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1">Distance (km)</label>
<input type="number" step="0.1" name="deliveryDistance" value="{{ session.deliveryDistance }}"
class="w-full bg-slate-900/50 border border-slate-700 rounded-lg px-3 py-2 text-white text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none transition-all">
</div>
<div>
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1">Prix Livraison (€)</label>
<input type="number" step="0.01" name="deliveryPrice" value="{{ session.deliveryPrice }}"
class="w-full bg-slate-900/50 border border-slate-700 rounded-lg px-3 py-2 text-white text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none transition-all">
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1">Mode de paiement</label>
<select name="typePaiement" class="w-full bg-slate-900/50 border border-slate-700 rounded-lg px-3 py-2 text-white text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none transition-all">
@@ -72,17 +55,17 @@
{% endfor %}
</select>
</div>
</div>
<div class="mt-4">
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1">Prestataire (Livraison)</label>
<select name="prestataire" class="w-full bg-slate-900/50 border border-slate-700 rounded-lg px-3 py-2 text-white text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none transition-all">
<option value="">-- Aucun prestataire assigné --</option>
{% for p in prestataires %}
<option value="{{ p.id }}" {% if session.prestataire and session.prestataire.id == p.id %}selected{% endif %}>
{{ p.surname }} {{ p.name }} ({{ p.email }})
</option>
{% endfor %}
</select>
<div>
<label class="block text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-1">Prestataire</label>
<select name="prestataire" class="w-full bg-slate-900/50 border border-slate-700 rounded-lg px-3 py-2 text-white text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none transition-all">
<option value="">-- Aucun prestataire assigné --</option>
{% for p in prestataires %}
<option value="{{ p.id }}" {% if session.prestataire and session.prestataire.id == p.id %}selected{% endif %}>
{{ p.surname }} {{ p.name }} ({{ p.email }})
</option>
{% endfor %}
</select>
</div>
</div>
<div class="flex justify-end mt-4">
<button type="submit" class="py-2 px-6 bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold uppercase tracking-widest rounded-lg transition-all">
@@ -164,49 +147,6 @@
</div>
</div>
{% if session.deliveryDistance is not null %}
<div class="mt-6 border-t border-slate-700/50 pt-6">
<h4 class="text-white font-bold text-sm mb-4">Détails Livraison</h4>
<div class="bg-slate-900/50 rounded-xl border border-slate-700/50 overflow-hidden mb-4">
{# Map #}
{% if session.deliveryGeometry %}
<div class="h-48 w-full relative z-0">
<leaflet-map class="absolute inset-0 w-full h-full"
data-geometry="{{ session.deliveryGeometry|json_encode|e('html_attr') }}">
</leaflet-map>
</div>
{% endif %}
{# Details #}
<div class="p-4 space-y-2 text-xs">
<div class="flex justify-between">
<span class="text-slate-400">Distance réelle (Aller)</span>
<span class="text-white font-bold">{{ session.deliveryDistance|number_format(1, ',', ' ') }} km</span>
</div>
<div class="flex justify-between">
<span class="text-slate-400">Franchise</span>
<span class="text-emerald-400 font-bold">- 10.0 km</span>
</div>
<div class="flex justify-between border-t border-slate-700 pt-2">
<span class="text-slate-400">Distance facturée</span>
<span class="text-white font-bold">{{ max(0, session.deliveryDistance - 10)|number_format(1, ',', ' ') }} km</span>
</div>
<div class="flex justify-between">
<span class="text-slate-400">Trajets</span>
<span class="text-white font-bold">4 (2 A/R)</span>
</div>
<div class="mt-2 p-2 bg-indigo-500/10 border border-indigo-500/20 rounded-lg text-center">
<code class="text-[10px] text-indigo-300 font-mono">
({{ session.deliveryDistance|number_format(1) }} - 10) x 4 x 0.50€ = {{ session.deliveryPrice|number_format(2) }}
</code>
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>

View File

@@ -133,7 +133,6 @@
{{ macros.nav_link('reservation_catalogue', 'nav.catalogue') }}
{{ macros.nav_link('reservation_formules', 'nav.packages') }}
{{ macros.nav_link('/images/Catalogue.pdf', 'nav.pdf', true) }}
{{ macros.nav_link('reservation_estimate_delivery', 'Estimer la livraison') }}
{{ macros.nav_link('reservation_contact', 'nav.contact') }}
<a is="flow-reserve" class="relative p-2 text-gray-600 hover:text-[#f39e36] transition-colors" aria-label="Panier">
@@ -189,7 +188,6 @@
{{ macros.mobile_nav_link('reservation_catalogue', 'Nos structures') }}
{{ macros.mobile_nav_link('reservation_formules', 'Nos Formules') }}
{{ macros.mobile_nav_link('/images/Catalogue.pdf', 'Catalogue', true) }}
{{ macros.mobile_nav_link('reservation_estimate_delivery', 'Estimer la livraison') }}
{{ macros.mobile_nav_link('reservation_search', 'Rechercher') }}
<a is="flow-reserve" class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl flex items-center justify-between">
<span>Panier</span>

View File

@@ -510,14 +510,6 @@
</div>
</div>
{# Frais de déplacement #}
<div class="flex items-center gap-4 p-5 bg-amber-50 rounded-2xl border border-amber-100">
<span class="text-2xl">🌍</span>
<p class="text-xs md:text-sm font-bold text-amber-900 leading-tight">
Livraison incluse dans un rayon de <span class="underline decoration-amber-400 underline-offset-4">30 km depuis Danizy</span>.
Des frais de déplacement s'appliquent au-delà.
</p>
</div>
</div>
</div>

View File

@@ -1,134 +0,0 @@
{% extends 'revervation/base.twig' %}
{% block title %}Estimer les frais de livraison | Ludik Event{% endblock %}
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
{% endblock %}
{% block body %}
<div class="min-h-screen bg-white font-sans antialiased py-20 px-4">
<div class="max-w-3xl mx-auto">
<h1 class="text-4xl md:text-5xl font-black text-slate-900 uppercase italic tracking-tighter mb-8 text-center">
Estimer <span class="text-[#f39e36]">la livraison</span>
</h1>
<div class="bg-slate-50 p-8 rounded-[2.5rem] border border-slate-100 shadow-xl">
<p class="text-center text-slate-500 font-medium mb-8">
Renseignez l'adresse de votre événement pour obtenir une estimation des frais de livraison.
</p>
{{ form_start(form, {'attr': {'class': 'space-y-6', 'data-turbo': 'false'}}) }}
<div>
{{ form_label(form.address, 'Adresse complète', {'label_attr': {'class': 'text-[10px] font-black text-slate-400 uppercase tracking-widest ml-1 mb-2 block'}}) }}
{{ form_widget(form.address, {'attr': {'class': 'w-full bg-white border border-slate-200 rounded-2xl px-5 py-4 text-slate-900 outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 transition-all', 'placeholder': 'Ex: 10 rue de la Paix'}}) }}
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
{{ form_label(form.zipCode, 'Code Postal', {'label_attr': {'class': 'text-[10px] font-black text-slate-400 uppercase tracking-widest ml-1 mb-2 block'}}) }}
{{ form_widget(form.zipCode, {'attr': {'class': 'w-full bg-white border border-slate-200 rounded-2xl px-5 py-4 text-slate-900 outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 transition-all', 'placeholder': '02000'}}) }}
</div>
<div>
{{ form_label(form.city, 'Ville', {'label_attr': {'class': 'text-[10px] font-black text-slate-400 uppercase tracking-widest ml-1 mb-2 block'}}) }}
{{ form_widget(form.city, {'attr': {'class': 'w-full bg-white border border-slate-200 rounded-2xl px-5 py-4 text-slate-900 outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 transition-all', 'placeholder': 'Laon'}}) }}
</div>
</div>
<div class="pt-4">
<button type="submit" class="w-full py-5 bg-slate-900 text-white rounded-2xl font-black uppercase tracking-[0.2em] hover:bg-[#f39e36] transition-all shadow-lg active:scale-95">
Calculer
</button>
</div>
{{ form_end(form) }}
{% if estimation is defined and estimation is not null %}
<div class="mt-10 bg-blue-50 border border-blue-100 rounded-2xl overflow-hidden animate-in fade-in slide-in-from-bottom-4">
<div class="p-6 border-b border-blue-100/50">
<span class="text-[10px] font-black text-blue-400 uppercase tracking-widest block mb-2">Résultat de l'estimation</span>
{% if details.isFree %}
<div class="flex items-center gap-3">
<span class="text-3xl font-black text-emerald-500 italic">Offert !</span>
<span class="px-3 py-1 bg-emerald-100 text-emerald-600 rounded-full text-[10px] font-bold uppercase tracking-wide">Zone gratuite</span>
</div>
<p class="text-xs text-slate-500 mt-2">Votre événement se trouve à moins de 10km de nos locaux.</p>
{% else %}
<p class="text-3xl font-black text-slate-900 italic">
{{ estimation|format_currency('EUR') }}
</p>
{% endif %}
</div>
{% if details is defined %}
<div class="bg-white/50 p-6 space-y-3">
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-4">Détails du calcul</p>
<div class="flex justify-between text-xs">
<span class="text-slate-500">Distance réelle (Aller)</span>
<span class="font-bold text-slate-700">{{ details.distance|number_format(1, ',', ' ') }} km</span>
</div>
<div class="flex justify-between text-xs">
<span class="text-slate-500">Franchise kilométrique</span>
<span class="font-bold text-emerald-500">- 10.0 km (Offerts)</span>
</div>
<div class="border-t border-slate-200/60 my-2"></div>
<div class="flex justify-between text-xs">
<span class="text-slate-500">Distance facturée</span>
<span class="font-bold text-slate-700">{{ details.chargedDistance|number_format(1, ',', ' ') }} km</span>
</div>
<div class="flex justify-between text-xs">
<span class="text-slate-500">Nombre de trajets</span>
<span class="font-bold text-slate-700">{{ details.trips }} (2 A/R)</span>
</div>
<div class="flex justify-between text-xs">
<span class="text-slate-500">Tarif kilométrique</span>
<span class="font-bold text-slate-700">{{ details.rate }} € / km</span>
</div>
{% if not details.isFree %}
<div class="bg-blue-100/50 p-3 rounded-xl mt-4 text-center">
<code class="text-[10px] text-blue-600 font-mono">
({{ details.distance|number_format(1) }} - 10) x {{ details.trips }} x {{ details.rate }}€ = {{ estimation|number_format(2) }}
</code>
</div>
{% endif %}
</div>
{% endif %}
{% if geometry is defined and geometry is not null %}
<leaflet-map class="h-96 w-full block rounded-xl mt-6 z-0 border-t border-blue-100"
data-geometry="{{ geometry|json_encode|e('html_attr') }}">
</leaflet-map>
{% endif %}
<div class="p-4 bg-blue-100/30 text-center">
<p class="text-[10px] text-slate-500 italic">
Cette estimation est donnée à titre indicatif et sera confirmée lors de la validation de votre devis.
</p>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
{% if geometry is defined and geometry is not null %}
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""
nonce="{{ csp_nonce('script') }}"></script>
{% endif %}
{% endblock %}

View File

@@ -273,100 +273,6 @@
</div>
</div>
{# Delivery Estimation #}
{% if delivery is defined and delivery.estimation is not null %}
<div class="bg-white rounded-2xl border border-slate-200 shadow-sm mb-8 overflow-hidden">
<div class="p-6 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50">
<div class="bg-emerald-100 p-2 rounded-lg text-emerald-600">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
</div>
<h3 class="text-lg font-bold text-slate-900">Estimation des frais de livraison</h3>
</div>
<div class="flex flex-col md:flex-row">
{# Details (60%) #}
<div class="w-full md:w-3/5 p-6 border-b md:border-b-0 md:border-r border-slate-100">
{% if delivery.details.isFree %}
<div class="bg-emerald-50 border border-emerald-100 rounded-xl p-4 mb-6">
<div class="flex items-center gap-3">
<span class="text-2xl font-black text-emerald-600 italic">Offert !</span>
<span class="px-3 py-1 bg-white text-emerald-700 rounded-full text-[10px] font-bold uppercase tracking-wide shadow-sm">Zone gratuite</span>
</div>
<p class="text-sm text-emerald-800 mt-2 font-medium">Votre événement se trouve à moins de 10km de nos locaux.</p>
</div>
{% else %}
<div class="mb-6">
<span class="block text-xs font-bold text-slate-400 uppercase tracking-widest mb-1">Coût estimé</span>
<p class="text-4xl font-black text-slate-900 italic">
{{ delivery.estimation|format_currency('EUR') }}
</p>
</div>
{% endif %}
<div class="space-y-3">
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-4">Détails du calcul</p>
<div class="flex justify-between text-sm">
<span class="text-slate-500">Distance réelle (Aller)</span>
<span class="font-bold text-slate-700">{{ delivery.details.distance|number_format(1, ',', ' ') }} km</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-slate-500">Franchise kilométrique</span>
<span class="font-bold text-emerald-500">- 10.0 km (Offerts)</span>
</div>
<div class="border-t border-slate-100 my-2"></div>
<div class="flex justify-between text-sm">
<span class="text-slate-500">Distance facturée</span>
<span class="font-bold text-slate-700">{{ delivery.details.chargedDistance|number_format(1, ',', ' ') }} km</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-slate-500">Nombre de trajets</span>
<span class="font-bold text-slate-700">{{ delivery.details.trips }} (2 A/R)</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-slate-500">Tarif kilométrique</span>
<span class="font-bold text-slate-700">{{ delivery.details.rate }} € / km</span>
</div>
</div>
{% if not delivery.details.isFree %}
<div class="mt-4 p-3 bg-indigo-50 border border-indigo-100 rounded-xl text-center">
<p class="text-[10px] font-bold text-indigo-400 uppercase mb-1">Formule appliquée</p>
<code class="text-xs text-indigo-700 font-mono font-bold">
({{ delivery.details.distance|number_format(1) }} - 10) x {{ delivery.details.trips }} x {{ delivery.details.rate }}€ = {{ delivery.estimation|number_format(2) }}
</code>
</div>
{% endif %}
<div class="mt-4 p-3 bg-slate-50 rounded-xl text-center">
<p class="text-[10px] text-slate-400 italic">
Cette estimation est indicative. Le montant définitif figurera sur votre devis.
</p>
</div>
</div>
{# Map (40%) #}
<div class="w-full md:w-2/5 h-64 md:h-auto min-h-[16rem] bg-slate-100 relative">
{% if delivery.geometry %}
<leaflet-map class="absolute inset-0 z-0"
data-geometry="{{ delivery.geometry|json_encode|e('html_attr') }}">
</leaflet-map>
{% else %}
<div class="absolute inset-0 flex items-center justify-center text-slate-400">
<span class="text-xs font-medium">Carte non disponible</span>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<div class="pt-6 border-t border-slate-100 mt-8 flex flex-col md:flex-row justify-center gap-4">
<a data-turbo="false" href="{{ path('reservation_generate_devis', {sessionId: session.uuid}) }}" class="w-full md:w-auto px-8 py-4 bg-gray-200 text-gray-800 font-bold rounded-2xl shadow-sm hover:shadow-md hover:scale-[1.01] transition-all flex items-center justify-center gap-2 text-lg">