✨ feat(etat-des-lieux): Finalise les EDL de retour et enrichit leur gestion et affichage dans le CRM.
This commit is contained in:
@@ -42,25 +42,69 @@
|
||||
{% set cautionEncaisser = contratPaymentPay(contrat, 'caution_recup') %}
|
||||
|
||||
<div class="contrat-card relative overflow-hidden group">
|
||||
|
||||
{# --- BANNIÈRE DE LITIGE (Si signature refusée) --- #}
|
||||
{% if contrat.etatLieux and contrat.etatLieux.status == 'edl_return_refused' %}
|
||||
<div class="bg-red-600/20 border-b border-red-500/30 px-8 py-3 flex items-center justify-between gap-3 backdrop-blur-md">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="relative flex h-3 w-3">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
|
||||
<span class="relative inline-flex rounded-full h-3 w-3 bg-red-500"></span>
|
||||
</span>
|
||||
<div>
|
||||
<p class="text-[10px] font-black text-red-400 uppercase tracking-widest leading-none">⚠️ Litige : Signature refusée par le client</p>
|
||||
<p class="text-xs text-red-100/80 mt-1 font-medium italic">
|
||||
Motif : "{{ contrat.etatLieux.raisonRefus|default('Non renseigné') }}"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-3 py-1 bg-red-500 text-white rounded-lg text-[9px] font-black uppercase shadow-lg shadow-red-500/20">
|
||||
Action Requise
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="absolute -inset-px bg-gradient-to-r from-transparent via-white/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500 rounded-[2rem]"></div>
|
||||
|
||||
<div class="relative bg-white/[0.03] border border-white/10 backdrop-blur-md rounded-[2rem] transition-all duration-300 group-hover:bg-white/[0.06] group-hover:translate-y-[-2px] group-hover:shadow-2xl group-hover:shadow-blue-500/10">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-12 items-center">
|
||||
|
||||
{# 1. REF & STATUS #}
|
||||
{# 1. RÉFÉRENCE & STATUTS #}
|
||||
<div class="lg:col-span-2 p-8 border-b lg:border-b-0 lg:border-r border-white/5 text-center lg:text-left">
|
||||
<span class="text-[10px] font-bold text-blue-400 uppercase tracking-[0.2em] mb-1 block">Contrat</span>
|
||||
<span class="text-[10px] font-bold text-blue-400 uppercase tracking-[0.2em] mb-1 block">Réservation</span>
|
||||
<h3 class="text-white font-black text-xl tracking-tighter mb-3">{{ contrat.numReservation }}</h3>
|
||||
|
||||
{% if contrat.isSigned %}
|
||||
<div class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-[9px] font-bold uppercase tracking-wider">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span> Signé
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-400 text-[9px] font-bold uppercase tracking-wider">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-amber-500"></span> Attente
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex flex-col gap-2 items-center lg:items-start">
|
||||
{# Status Contrat #}
|
||||
{% if contrat.isSigned %}
|
||||
<div class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-[9px] font-bold uppercase tracking-wider">
|
||||
<span class="w-1 h-1 rounded-full bg-emerald-500"></span> Contrat Signé
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-400 text-[9px] font-bold uppercase tracking-wider">
|
||||
<span class="w-1 h-1 rounded-full bg-amber-500"></span> Attente Signature
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Status État des Lieux avec Traductions et Couleurs #}
|
||||
{% if contrat.etatLieux %}
|
||||
{% set status_config = {
|
||||
'delivery_progress': { 'color': 'bg-blue-500/10 text-blue-400 border-blue-500/20', 'label': '🚚 Livraison en cours' },
|
||||
'delivery_done': { 'color': 'bg-cyan-500/10 text-cyan-400 border-cyan-500/20', 'label': '📍 Livré' },
|
||||
'edl_progress': { 'color': 'bg-indigo-500/10 text-indigo-400 border-indigo-500/20', 'label': '📝 EDL Installation...' },
|
||||
'edl_validated': { 'color': 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30', 'label': '✅ EDL Validé' },
|
||||
'return_edl_progress': { 'color': 'bg-orange-500/10 text-orange-400 border-orange-500/20', 'label': '🔍 EDL Retour...' },
|
||||
'edl_return_done': { 'color': 'bg-purple-500/10 text-purple-400 border-purple-500/20', 'label': '📦 Retour Effectué' },
|
||||
'edl_return_refused': { 'color': 'bg-red-600 text-white border-red-500', 'label': '❌ Signature Refusée' }
|
||||
} %}
|
||||
|
||||
{% set current_status = status_config[contrat.etatLieux.status] ?? { 'color': 'bg-slate-500/10 text-slate-400 border-white/5', 'label': contrat.etatLieux.status } %}
|
||||
|
||||
<div class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full border {{ current_status.color }} text-[9px] font-black uppercase tracking-wider shadow-sm">
|
||||
{{ current_status.label }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# 2. CLIENT #}
|
||||
@@ -79,93 +123,78 @@
|
||||
{# 3. LIEU #}
|
||||
<div class="lg:col-span-2 p-8 border-b lg:border-b-0 lg:border-r border-white/5">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-[10px] font-bold text-slate-300 uppercase tracking-widest mb-1">Destination</span>
|
||||
<span class="text-[10px] font-bold text-slate-300 uppercase tracking-widest mb-1">Ville / CP</span>
|
||||
<p class="text-slate-200 font-bold text-sm">{{ contrat.townEvent }}</p>
|
||||
<p class="text-blue-500 font-black text-[11px]">{{ contrat.zipCodeEvent }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# 4. PAIEMENTS & DETAILS #}
|
||||
{# 4. PAIEMENTS & FINANCES #}
|
||||
<div class="lg:col-span-4 p-4 bg-black/10 lg:bg-transparent border-b lg:border-b-0 lg:border-r border-white/5">
|
||||
<div class="flex items-center justify-between gap-4 h-full">
|
||||
{# INFO PRIX & FORMULE #}
|
||||
<div class="flex flex-col justify-center min-w-[120px]">
|
||||
{% if contrat.devis %}
|
||||
{% if contrat.devis.orderSession and contrat.devis.orderSession.promotion %}
|
||||
<span class="text-sm font-black text-white">
|
||||
{{ (contrat.devis|totalQuotoHT)|number_format(2, ',', ' ') }}€
|
||||
</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-[10px] text-slate-500 line-through font-bold">
|
||||
{{ (contrat.devis|totalQuotoBeforeDiscount)|number_format(2, ',', ' ') }}€
|
||||
</span>
|
||||
<span class="text-[9px] text-emerald-400 font-bold uppercase tracking-wider">
|
||||
-{{ contrat.devis.orderSession.promotion.percentage }}%
|
||||
</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-sm font-black text-white">
|
||||
{{ (contrat.devis|totalQuotoHT)|number_format(2, ',', ' ') }}€
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if contrat.devis %}
|
||||
<span class="text-sm font-black text-white">
|
||||
{{ (contrat.devis|totalQuotoHT)|number_format(2, ',', ' ') }}€ HT
|
||||
</span>
|
||||
|
||||
{% if contrat.devis.formule %}
|
||||
<span class="text-[9px] text-blue-400 font-bold uppercase tracking-widest mt-1 truncate max-w-[150px]" title="{{ contrat.devis.formule.name }}">
|
||||
{{ contrat.devis.formule.name }}
|
||||
</span>
|
||||
<span class="text-[9px] text-blue-400 font-bold uppercase tracking-widest mt-1 truncate max-w-[150px]">
|
||||
{{ contrat.devis.formule.name }}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<span class="text-[9px] text-slate-500 font-bold mt-1">
|
||||
Caution: {{ (contrat.devis|totalCaution)|number_format(2, ',', ' ') }}€
|
||||
</span>
|
||||
Caution : {{ (contrat.devis|totalCaution)|number_format(2, ',', ' ') }}€
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-xs text-slate-500 italic">No Devis</span>
|
||||
<span class="text-xs text-slate-500 italic">Pas de devis</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# STATUTS PAIEMENTS (Icons) #}
|
||||
{# BADGES DE PAIEMENT #}
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
{# ACOMPTE #}
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center transition-all duration-300
|
||||
{{ acompteOk ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-rose-500/10 text-rose-500 border border-rose-500/20' }}">
|
||||
{{ acompteOk ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-red-500/10 text-red-500 border border-red-500/20' }}">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="{{ acompteOk ? 'M5 13l4 4L19 7' : 'M6 18L18 6M6 6l12 12' }}"></path></svg>
|
||||
</div>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter {{ acompteOk ? 'text-emerald-500' : 'text-rose-500' }}">Acompte</span>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter {{ acompteOk ? 'text-emerald-500' : 'text-red-500' }}">Acompte</span>
|
||||
</div>
|
||||
|
||||
{# CAUTION #}
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
{% if cautionEncaisser %}
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-rose-600/30 text-rose-400 border border-rose-500/50" title="Encaissée">
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-red-600/30 text-red-400 border border-red-500/50">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path></svg>
|
||||
</div>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter text-rose-400">Encaissée</span>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter text-red-400">Encaissée</span>
|
||||
{% elseif cautionRelase %}
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-blue-500/20 text-blue-400 border border-blue-500/30" title="Libérée">
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-blue-500/20 text-blue-400 border border-blue-500/30">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M8 11V7a4 4 0 118 0m-4 8v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2z"></path></svg>
|
||||
</div>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter text-blue-400">Libérée</span>
|
||||
{% elseif cautionOk %}
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-emerald-500/20 text-emerald-400 border border-emerald-500/30" title="Détenue">
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-emerald-500/20 text-emerald-400 border border-emerald-500/30">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg>
|
||||
</div>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter text-emerald-500">Détenue</span>
|
||||
{% else %}
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-rose-500/10 text-rose-500 border border-rose-500/20 animate-pulse" title="Requise">
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-red-500/10 text-red-500 border border-red-500/20 animate-pulse">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>
|
||||
</div>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter text-rose-500">Requise</span>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter text-red-500">Requise</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# SOLDE #}
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center transition-all duration-300
|
||||
{{ soldeOk ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-rose-500/10 text-rose-500 border border-rose-500/20' }}">
|
||||
{{ soldeOk ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-red-500/10 text-red-500 border border-red-500/20' }}">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="{{ soldeOk ? 'M5 13l4 4L19 7' : 'M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z' }}"></path></svg>
|
||||
</div>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter {{ soldeOk ? 'text-emerald-500' : 'text-rose-500' }}">Solde</span>
|
||||
<span class="text-[7px] font-black uppercase tracking-tighter {{ soldeOk ? 'text-emerald-500' : 'text-red-500' }}">Solde</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,12 +203,12 @@
|
||||
{# 5. ACTIONS #}
|
||||
<div class="lg:col-span-2 p-6 flex lg:flex-col items-center justify-center gap-3">
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id}) }}"
|
||||
class="w-full lg:w-12 h-12 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-blue-600 hover:border-blue-400 transition-all group/btn" title="Voir">
|
||||
class="w-full lg:w-12 h-12 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-blue-600 hover:border-blue-400 transition-all group/btn" title="Consulter">
|
||||
<svg class="w-5 h-5 group-hover/btn:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path></svg>
|
||||
</a>
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats', {idSend: contrat.id}) }}"
|
||||
onclick="return confirm('Envoyer à {{ contrat.customer.email }} ?')"
|
||||
class="w-full lg:w-12 h-12 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-indigo-600 hover:border-indigo-400 transition-all group/btn" title="Envoyer">
|
||||
onclick="return confirm('Renvoyer les documents à {{ contrat.customer.email }} ?')"
|
||||
class="w-full lg:w-12 h-12 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-indigo-600 hover:border-indigo-400 transition-all group/btn" title="Renvoyer Mail">
|
||||
<svg class="w-5 h-5 group-hover/btn:translate-x-1 group-hover/btn:-translate-y-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path></svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
{# Définition des états de paiement #}
|
||||
{% set acompteOk = contratPaymentPay(contrat, 'accompte') %}
|
||||
{% set cautionOk = contratPaymentPay(contrat, 'caution') %}
|
||||
|
||||
{% set soldeOk = (solde <= 0.05) %}
|
||||
|
||||
<div class="space-y-8 pb-20">
|
||||
@@ -53,60 +52,34 @@
|
||||
<div class="p-4 rounded-[1.5rem] bg-white/5 border border-white/10 backdrop-blur-md flex items-center justify-between">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-[10px] font-black uppercase text-slate-300 tracking-widest block">Total Contrat</span>
|
||||
{% if contrat.devis and contrat.devis.orderSession and contrat.devis.orderSession.promotion %}
|
||||
<div class="flex items-center gap-2 mt-0.5">
|
||||
<span class="text-[9px] text-slate-500 line-through font-bold">
|
||||
{{ (contrat.devis|totalQuotoBeforeDiscount)|number_format(2, ',', ' ') }} €
|
||||
</span>
|
||||
<span class="text-[9px] text-emerald-400 font-bold uppercase tracking-wider">
|
||||
-{{ contrat.devis.orderSession.promotion.percentage }}%
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if contrat.devis and contrat.devis.formule %}
|
||||
<span class="text-[9px] text-blue-400 font-bold uppercase tracking-widest mt-0.5">
|
||||
{{ contrat.devis.formule.name }}
|
||||
</span>
|
||||
{% endif %}
|
||||
<span class="text-[8px] text-slate-500 italic mt-1" title="Pour les cartes standard de l'Espace économique européen">Com. Stripe (EEE) : ~ {{ ((totalHT * 0.015) + 0.25)|number_format(2, ',', ' ') }} €</span>
|
||||
<span class="text-[8px] text-slate-500 italic mt-1">HT / Jour</span>
|
||||
</div>
|
||||
<span class="text-xs font-black text-white italic">
|
||||
{% if contrat.devis %}
|
||||
{{ (contrat.devis|totalQuotoHT)|number_format(2, ',', ' ') }} €
|
||||
{% else %}
|
||||
{{ totalHT|number_format(2, ',', ' ') }} €
|
||||
{% endif %}
|
||||
{{ (contrat.devis ? (contrat.devis|totalQuotoHT) : totalHT)|number_format(2, ',', ' ') }} €
|
||||
</span>
|
||||
</div>
|
||||
<div class="p-4 rounded-[1.5rem] bg-white/5 border border-white/10 backdrop-blur-md flex items-center justify-between">
|
||||
<div>
|
||||
<span class="text-[10px] font-black uppercasetext-slate-300 tracking-widest block">Reste à percevoir</span>
|
||||
{% if not soldeOk %}
|
||||
<span class="text-[8px] text-slate-500 italic" title="Pour les cartes standard de l'Espace économique européen">Com. Stripe (EEE) : ~ {{ ((solde * 0.015) + 0.25)|number_format(2, ',', ' ') }} €</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<span class="text-[10px] font-black uppercase text-slate-300 tracking-widest block">Reste à percevoir</span>
|
||||
<span class="text-xs font-black {{ soldeOk ? 'text-emerald-400' : 'text-rose-500' }} italic">
|
||||
{% set totalAmount = (contrat.devis ? (contrat.devis|totalQuotoHT) : totalHT) %}
|
||||
{% set totalPaid = 0 %}
|
||||
{% for payment in contrat.contratsPayments %}
|
||||
{% if payment.type in ['accompte', 'solde'] %}
|
||||
{% set totalPaid = totalPaid + payment.amount %}
|
||||
{% endif %}
|
||||
{% if payment.type in ['accompte', 'solde', 'etl_payment'] %}
|
||||
{% set totalPaid = totalPaid + payment.amount %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set remaining = totalAmount - totalPaid %}
|
||||
|
||||
{{ remaining <= 0.05 ? 'CONTRAT SOLDÉ' : (remaining|number_format(2, ',', ' ') ~ ' €') }}
|
||||
{{ remaining <= 0.05 ? 'SOLDÉ' : (remaining|number_format(2, ',', ' ') ~ ' €') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="p-4 rounded-[1.5rem] bg-white/5 border border-white/10 backdrop-blur-md flex items-center justify-between">
|
||||
<span class="text-[10px] font-black uppercasetext-slate-300 tracking-widest">Référence</span>
|
||||
<span class="text-[10px] font-black uppercase text-slate-300 tracking-widest">Référence</span>
|
||||
<span class="text-xs font-black text-blue-400 italic">#{{ contrat.numReservation }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- 2. INFOS CLIENT & ÉVÉNEMENT --- #}
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{# CARTE CLIENT #}
|
||||
<div class="relative group">
|
||||
<div class="absolute -inset-0.5 bg-gradient-to-br from-blue-500/20 to-purple-500/20 rounded-[2.5rem] blur opacity-50"></div>
|
||||
<div class="relative h-full p-8 bg-slate-900/40 border border-white/10 backdrop-blur-xl rounded-[2.5rem]">
|
||||
@@ -116,23 +89,16 @@
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xl font-black text-white italic tracking-tighter uppercase">{{ contrat.customer.surname }} {{ contrat.customer.name }}</h2>
|
||||
<p class="text-slate-500 font-bold text-[10px] uppercase tracking-widest">Informations Locataire</p>
|
||||
<p class="text-slate-500 font-bold text-[10px] uppercase tracking-widest">Locataire</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center gap-3 p-4 rounded-2xl bg-white/[0.02] border border-white/5 text-slate-300 text-sm">
|
||||
<svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" stroke-width="2"/></svg>
|
||||
{{ contrat.customer.email }}
|
||||
</div>
|
||||
<div class="flex items-center gap-3 p-4 rounded-2xl bg-white/[0.02] border border-white/5 text-slate-300 text-sm">
|
||||
<svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" stroke-width="2"/></svg>
|
||||
{{ contrat.customer.phone }}
|
||||
</div>
|
||||
<div class="flex items-center gap-3 p-4 rounded-2xl bg-white/[0.02] border border-white/5 text-slate-300 text-sm italic font-bold">{{ contrat.customer.email }}</div>
|
||||
<div class="flex items-center gap-3 p-4 rounded-2xl bg-white/[0.02] border border-white/5 text-slate-300 text-sm font-black">{{ contrat.customer.phone }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# CARTE ÉVÉNEMENT #}
|
||||
<div class="relative group">
|
||||
<div class="absolute -inset-0.5 bg-gradient-to-br from-emerald-500/20 to-teal-500/20 rounded-[2.5rem] blur opacity-50"></div>
|
||||
<div class="relative h-full p-8 bg-slate-900/40 border border-white/10 backdrop-blur-xl rounded-[2.5rem]">
|
||||
@@ -142,11 +108,10 @@
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xl font-black text-white italic tracking-tighter uppercase">Lieu de l'événement</h2>
|
||||
<p class="text-slate-500 font-bold text-[10px] uppercase tracking-widest">{{ contrat.dateAt|date('d/m/Y') }} - {{ contrat.endAt|date('d/m/Y') }}</p>
|
||||
<p class="text-slate-500 font-bold text-[10px] uppercase tracking-widest">{{ contrat.dateAt|date('d/m/Y') }} — {{ contrat.endAt|date('d/m/Y') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-5 rounded-2xl bg-white/[0.02] border border-white/5">
|
||||
<span class="text-[9px] font-black text-slate-300 uppercase tracking-widest block mb-1">Adresse de livraison</span>
|
||||
<p class="text-white text-base font-bold">{{ contrat.addressEvent }}</p>
|
||||
<p class="text-emerald-400 font-black text-sm uppercase italic">{{ contrat.zipCodeEvent }} {{ contrat.townEvent }}</p>
|
||||
</div>
|
||||
@@ -154,14 +119,107 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- 3. ÉTAT DES PAIEMENTS AVEC ACTIONS DE GESTION --- #}
|
||||
<div class="p-8 bg-white/[0.02] border border-white/10 rounded-[2.5rem] backdrop-blur-md shadow-2xl">
|
||||
<div class="flex flex-col md:flex-row gap-8 justify-around items-start">
|
||||
{# --- 3. SECTION LOGISTIQUE & ÉTAT DES LIEUX --- #}
|
||||
{% if contrat.etatLieux %}
|
||||
<div class="space-y-4">
|
||||
<h3 class="px-2 text-sm font-black text-slate-400 uppercase tracking-[0.3em]">Logistique & État des lieux</h3>
|
||||
|
||||
{# --- ACOMPTE --- #}
|
||||
{% if contrat.etatLieux.status == 'edl_return_refused' %}
|
||||
<div class="p-6 bg-red-500/10 border border-red-500/20 rounded-[2rem] flex items-center justify-between backdrop-blur-md">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-red-500/20 rounded-xl flex items-center justify-center border border-red-500/30">
|
||||
<svg class="w-6 h-6 text-red-500 animate-pulse" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-red-500 font-black uppercase italic text-sm tracking-tight">Signature Refusée au Retour</h4>
|
||||
<p class="text-red-200/60 text-xs font-bold mt-0.5 italic">Motif : {{ contrat.etatLieux.raisonRefused|default('Non spécifié') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<span class="px-4 py-1.5 bg-red-500 text-white text-[10px] font-black rounded-xl uppercase shadow-lg shadow-red-500/20">Litige à traiter</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{# EDL INSTALLATION #}
|
||||
<div class="p-6 bg-white/[0.02] border border-white/10 rounded-[2.5rem] backdrop-blur-md">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h4 class="text-xs font-black text-white uppercase tracking-widest italic">📝 État des lieux Installation</h4>
|
||||
<span class="px-3 py-1 bg-emerald-500/10 text-emerald-400 text-[9px] font-black rounded-lg border border-emerald-500/20">
|
||||
{{ contrat.etatLieux.status in ['edl_validated','edl_return_done', 'edl_return_refused','edl_return_finised'] ? 'VALIDÉ' : 'EN COURS' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
{% if contrat.etatLieux.etatLieuxSignFileName %}
|
||||
<a href="{{ vich_uploader_asset(contrat.etatLieux, 'etatLieuxSignFile') }}" target="_blank" class="flex items-center justify-center gap-3 p-4 bg-emerald-500/10 hover:bg-emerald-500/20 border border-emerald-500/20 rounded-2xl text-emerald-400 text-[10px] font-black uppercase transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke-width="2.5"/></svg>
|
||||
Voir le PV signé (Installation)
|
||||
</a>
|
||||
<a href="{{ path('app_crm_contrats_view',{id:contrat.id,act:'downloadFilePv'})}}" class="flex items-center justify-center gap-3 p-4 bg-purple-500/10 hover:bg-purple-500/20 border border-purple-500/20 rounded-2xl text-purple-400 text-[10px] font-black uppercase transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 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" stroke-width="2.5"/></svg>
|
||||
Télécharger tout ses photos le PV
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="grid grid-cols-2 gap-3 text-center">
|
||||
<div class="p-3 bg-white/5 rounded-2xl border border-white/5">
|
||||
<span class="block text-white font-black text-lg">{{ contrat.etatLieux.files|length }}</span>
|
||||
<span class="text-[8px] text-slate-500 font-bold uppercase tracking-widest">Médias Photos/Vid.</span>
|
||||
</div>
|
||||
<div class="p-3 bg-white/5 rounded-2xl border border-white/5">
|
||||
<span class="block text-white font-black text-lg">{{ contrat.etatLieux.pointControls|length }}</span>
|
||||
<span class="text-[8px] text-slate-500 font-bold uppercase tracking-widest">Points d'inspection</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# EDL RETOUR #}
|
||||
<div class="p-6 bg-white/[0.02] border border-white/10 rounded-[2.5rem] backdrop-blur-md">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h4 class="text-xs font-black text-white uppercase tracking-widest italic">📦 État des lieux Retour</h4>
|
||||
{% if contrat.etatLieux.status in ['edl_return_done', 'edl_return_refused','edl_return_finised'] %}
|
||||
<span class="px-3 py-1 bg-purple-500/10 text-purple-400 text-[9px] font-black rounded-lg border border-purple-500/20">EFFECTUÉ</span>
|
||||
{% else %}
|
||||
<span class="px-3 py-1 bg-white/5 text-slate-500 text-[9px] font-black rounded-lg">EN ATTENTE</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
{% if contrat.etatLieux.etatLieuxSignReturnFileName %}
|
||||
<a href="{{ vich_uploader_asset(contrat.etatLieux, 'etatLieuxSignReturnFile') }}" target="_blank" class="flex items-center justify-center gap-3 p-4 bg-purple-500/10 hover:bg-purple-500/20 border border-purple-500/20 rounded-2xl text-purple-400 text-[10px] font-black uppercase transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 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" stroke-width="2.5"/></svg>
|
||||
Voir le PV signé (Retour)
|
||||
</a>
|
||||
<a href="{{ path('app_crm_contrats_view',{id:contrat.id,act:'downloadFileReturnPv'})}}" class="flex items-center justify-center gap-3 p-4 bg-purple-500/10 hover:bg-purple-500/20 border border-purple-500/20 rounded-2xl text-purple-400 text-[10px] font-black uppercase transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 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" stroke-width="2.5"/></svg>
|
||||
Télécharger tout ses photos le PV
|
||||
</a>
|
||||
{% elseif contrat.etatLieux.status == 'edl_return_refused' %}
|
||||
<div class="p-4 bg-red-500/5 border border-red-500/20 rounded-2xl text-center">
|
||||
<span class="text-[9px] font-black text-red-400 uppercase italic tracking-widest">PV non signé (Refus client)</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="grid grid-cols-2 gap-3 text-center">
|
||||
<div class="p-3 bg-white/5 rounded-2xl border border-white/5">
|
||||
<span class="block text-white font-black text-lg">{{ contrat.etatLieux.fileReturn|length }}</span>
|
||||
<span class="text-[8px] text-slate-500 font-bold uppercase tracking-widest">Médias Retour</span>
|
||||
</div>
|
||||
<div class="p-3 bg-white/5 rounded-2xl border border-white/5">
|
||||
<span class="block text-white font-black text-lg">{{ contrat.etatLieux.pointControlsReturn|length }}</span>
|
||||
<span class="text-[8px] text-slate-500 font-bold uppercase tracking-widest">Points Vérifiés</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# --- 4. ÉTAT DES PAIEMENTS --- #}
|
||||
<div class="p-8 bg-white/[0.02] border border-white/10 rounded-[2.5rem] backdrop-blur-md">
|
||||
<div class="flex flex-col md:flex-row gap-8 justify-around items-start">
|
||||
{# ACOMPTE #}
|
||||
<div class="flex flex-col items-center gap-4 text-center w-full">
|
||||
<div class="w-16 h-16 rounded-2xl flex items-center justify-center border transition-all duration-500
|
||||
{{ acompteOk ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30 shadow-[0_0_20px_rgba(16,185,129,0.1)]' : 'bg-rose-500/10 text-rose-500 border-rose-500/20' }}">
|
||||
<div class="w-16 h-16 rounded-2xl flex items-center justify-center border {{ acompteOk ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30' : 'bg-rose-500/10 text-rose-500 border-rose-500/20' }}">
|
||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
{% if acompteOk %}<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 13l4 4L19 7"/>{% else %}<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>{% endif %}
|
||||
</svg>
|
||||
@@ -169,77 +227,43 @@
|
||||
<div>
|
||||
<span class="block text-[9px] font-black uppercase tracking-widest {{ acompteOk ? 'text-emerald-500' : 'text-rose-500' }}">Acompte</span>
|
||||
{% if not acompteOk %}
|
||||
<div class="mt-3 flex flex-wrap justify-center gap-2 max-w-[200px]">
|
||||
<div class="mt-3 flex flex-wrap justify-center gap-2">
|
||||
{% for method in ['Carte Bancaire', 'Chèque', 'Espèces', 'Virement'] %}
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'accompte', method: method}) }}"
|
||||
class="px-2 py-1.5 bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/20 rounded-lg text-[9px] font-bold text-rose-500 uppercase transition-all"
|
||||
title="Régler par {{ method }}">
|
||||
{{ method|slice(0, 4) }}.
|
||||
</a>
|
||||
<a href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'accompte', method: method}) }}" class="px-2 py-1 bg-rose-500/10 border border-rose-500/20 rounded-lg text-[8px] font-black text-rose-500 uppercase">{{ method|slice(0, 4) }}.</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mt-2 text-[10px] text-emerald-500/60 font-bold uppercase italic">Encaissé</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden md:block w-px h-20 bg-white/5 self-center"></div>
|
||||
|
||||
{# --- CAUTION --- #}
|
||||
{# CAUTION #}
|
||||
<div class="flex flex-col items-center gap-4 text-center w-full">
|
||||
<div class="w-16 h-16 rounded-2xl flex items-center justify-center border transition-all duration-500
|
||||
{{ cautionOk ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30 shadow-[0_0_20px_rgba(16,185,129,0.1)]' : 'bg-rose-500/20 text-rose-500 border-rose-500/30 animate-pulse' }}">
|
||||
<div class="w-16 h-16 rounded-2xl flex items-center justify-center border {{ cautionOk ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30' : 'bg-rose-500/20 text-rose-500 border-rose-500/30 animate-pulse' }}">
|
||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
{% if cautionOk %}<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>{% else %}<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>{% endif %}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-[9px] font-black uppercase tracking-widest {{ cautionOk ? 'text-emerald-500' : 'text-rose-500' }}">Caution</span>
|
||||
<div class="flex flex-col gap-2 mt-3">
|
||||
<div class="mt-3">
|
||||
{% set cautionRelase = contratPaymentPay(contrat, 'caution_free') %}
|
||||
{% set cautionEncaisser = contratPaymentPay(contrat, 'caution_recup') %}
|
||||
|
||||
{# 1. ON TESTE D'ABORD LES ÉTATS FINAUX #}
|
||||
{% if cautionRelase %}
|
||||
<div class="flex items-center gap-1.5 px-3 py-1.5 bg-emerald-500/10 border border-emerald-500/20 rounded-lg">
|
||||
<svg class="w-3 h-3 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
<span class="text-[9px] font-black text-emerald-500 uppercase italic">Caution Libérée</span>
|
||||
</div>
|
||||
|
||||
<span class="text-[9px] font-black text-emerald-500 uppercase italic">Libérée</span>
|
||||
{% elseif cautionEncaisser %}
|
||||
<div class="flex items-center gap-1.5 px-3 py-1.5 bg-amber-500/10 border border-amber-500/20 rounded-lg">
|
||||
<svg class="w-3 h-3 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||
</svg>
|
||||
<span class="text-[9px] font-black text-amber-500 uppercase italic">Caution Encaissée</span>
|
||||
</div>
|
||||
|
||||
{# 2. SI PAS DE STATUT FINAL, ON REGARDE SI ELLE EST AU MOINS REÇUE #}
|
||||
<span class="text-[9px] font-black text-amber-500 uppercase italic">Encaissée</span>
|
||||
{% elseif cautionOk %}
|
||||
<div class="flex gap-2">
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, action: 'encaisser'}) }}"
|
||||
onclick="return confirm('CONFIRMATION : Voulez-vous vraiment ENCAISSER la caution ?')"
|
||||
class="px-3 py-1.5 bg-amber-500/20 hover:bg-amber-500/40 border border-amber-500/30 rounded-lg text-[9px] font-black text-amber-500 uppercase transition-all shadow-lg shadow-amber-900/10">
|
||||
Encaisser
|
||||
</a>
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, action: 'liberer'}) }}"
|
||||
class="px-3 py-1.5 bg-emerald-500/20 hover:bg-emerald-500/40 border border-emerald-500/30 rounded-lg text-[9px] font-black text-emerald-400 uppercase transition-all shadow-lg shadow-emerald-900/10">
|
||||
Libérer
|
||||
</a>
|
||||
<a href="{{ path('app_crm_contrats_view', {id: contrat.id, action: 'encaisser'}) }}" class="px-3 py-1 bg-amber-500/20 border border-amber-500/30 rounded-lg text-[9px] font-black text-amber-500 uppercase">Encaisser</a>
|
||||
<a href="{{ path('app_crm_contrats_view', {id: contrat.id, action: 'liberer'}) }}" class="px-3 py-1 bg-emerald-500/20 border border-emerald-500/30 rounded-lg text-[9px] font-black text-emerald-400 uppercase">Libérer</a>
|
||||
</div>
|
||||
|
||||
{# 3. SINON, C'EST QU'ELLE N'EST PAS ENCORE ENREGISTRÉE #}
|
||||
{% else %}
|
||||
<div class="flex flex-wrap justify-center gap-2 max-w-[200px]">
|
||||
<div class="flex flex-wrap justify-center gap-2">
|
||||
{% for method in ['Carte Bancaire', 'Chèque', 'Espèces', 'Virement'] %}
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'caution', method: method}) }}"
|
||||
class="px-2 py-1.5 bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/20 rounded-lg text-[9px] font-bold text-rose-500 uppercase transition-all"
|
||||
title="Caution par {{ method }}">
|
||||
{{ method|slice(0, 4) }}.
|
||||
</a>
|
||||
<a href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'caution', method: method}) }}" class="px-2 py-1 bg-rose-500/10 border border-rose-500/20 rounded-lg text-[8px] font-black text-rose-500 uppercase">{{ method|slice(0, 4) }}.</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -249,10 +273,9 @@
|
||||
|
||||
<div class="hidden md:block w-px h-20 bg-white/5 self-center"></div>
|
||||
|
||||
{# --- SOLDE --- #}
|
||||
{# SOLDE #}
|
||||
<div class="flex flex-col items-center gap-4 text-center w-full">
|
||||
<div class="w-16 h-16 rounded-2xl flex items-center justify-center border transition-all duration-500
|
||||
{{ soldeOk ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30 shadow-[0_0_20px_rgba(16,185,129,0.1)]' : 'bg-rose-500/10 text-rose-500 border-rose-500/20' }}">
|
||||
<div class="w-16 h-16 rounded-2xl flex items-center justify-center border {{ soldeOk ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30' : 'bg-rose-500/10 text-rose-500 border-rose-500/20' }}">
|
||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
{% if soldeOk %}<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>{% else %}<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z"/>{% endif %}
|
||||
</svg>
|
||||
@@ -260,82 +283,44 @@
|
||||
<div>
|
||||
<span class="block text-[9px] font-black uppercase tracking-widest {{ soldeOk ? 'text-emerald-500' : 'text-rose-500' }}">Solde Final</span>
|
||||
{% if not soldeOk %}
|
||||
<div class="mt-3 flex flex-wrap justify-center gap-2 max-w-[200px]">
|
||||
<div class="mt-3 flex flex-wrap justify-center gap-2">
|
||||
{% for method in ['Carte Bancaire', 'Chèque', 'Espèces', 'Virement'] %}
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'solde', method: method}) }}"
|
||||
class="px-2 py-1.5 bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/20 rounded-lg text-[9px] font-bold text-rose-500 uppercase transition-all"
|
||||
title="Solde par {{ method }}">
|
||||
{{ method|slice(0, 4) }}.
|
||||
</a>
|
||||
<a href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'solde', method: method}) }}" class="px-2 py-1 bg-rose-500/10 border border-rose-500/20 rounded-lg text-[8px] font-black text-rose-500 uppercase">{{ method|slice(0, 4) }}.</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mt-2 text-[10px] text-emerald-500/60 font-bold uppercase italic">Totalité payée</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{# --- 4. PRODUITS ET OPTIONS --- #}
|
||||
|
||||
{# --- 5. PRODUITS ET OPTIONS --- #}
|
||||
<div class="grid grid-cols-1 xl:grid-cols-2 gap-8">
|
||||
{# PRODUITS #}
|
||||
<div class="space-y-4">
|
||||
<h3 class="px-2 text-sm font-black text-slate-400 uppercase tracking-[0.3em]">Équipements loués</h3>
|
||||
<div class="bg-white/[0.02] border border-white/10 rounded-[2rem] divide-y divide-white/5 overflow-hidden">
|
||||
{% if contrat.devis and contrat.devis.formule %}
|
||||
{# BLOC FORMULE #}
|
||||
<div class="p-6 bg-blue-500/5 hover:bg-blue-500/10 transition-colors border-l-2 border-blue-500">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h4 class="text-blue-400 font-black text-base uppercase italic tracking-wider">FORMULE : {{ contrat.devis.formule.name }}</h4>
|
||||
<p class="text-[10px] text-slate-400 font-bold uppercase mt-1">Caution Globale : {{ contrat.devis.formule.caution }}€</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span class="text-white font-black italic">Package</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for product in contrat.contratsLines %}
|
||||
<div class="p-6 hover:bg-white/[0.03] transition-colors">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h4 class="text-white font-bold text-base uppercase italic">{{ product.name }}</h4>
|
||||
{% if not (contrat.devis and contrat.devis.formule) %}
|
||||
<p class="text-[10px] text-slate-300 font-bold uppercase mt-1">Caution : {{ product.caution }}€</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
{% if contrat.devis and contrat.devis.formule %}
|
||||
<span class="text-emerald-400 font-black italic text-xs uppercase tracking-widest">Inclus</span>
|
||||
{% else %}
|
||||
<span class="text-blue-400 font-black italic">{{ product.price1DayHt }}€</span>
|
||||
<span class="block text-[8px] text-slate-300 uppercase font-black">HT / Jour</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="p-6 hover:bg-white/[0.03] transition-colors flex justify-between items-start">
|
||||
<div>
|
||||
<h4 class="text-white font-bold text-base uppercase italic tracking-wide">{{ product.name }}</h4>
|
||||
<p class="text-[10px] text-slate-400 font-bold uppercase mt-1">Caution : {{ product.caution }}€</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span class="text-blue-400 font-black italic">{{ product.price1DayHt }}€</span>
|
||||
<span class="block text-[8px] text-slate-500 uppercase font-black">HT / J</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# OPTIONS #}
|
||||
<div class="space-y-4">
|
||||
<h3 class="px-2 text-sm font-black text-slate-400 uppercase tracking-[0.3em]">Options & Services</h3>
|
||||
<div class="bg-white/[0.02] border border-white/10 rounded-[2rem] divide-y divide-white/5 overflow-hidden">
|
||||
{% for product in contrat.contratsOptions %}
|
||||
<div class="p-6 hover:bg-white/[0.03] transition-colors">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="max-w-[70%]">
|
||||
<h4 class="text-white font-bold text-sm uppercase">{{ product.name }}</h4>
|
||||
<p class="text-slate-500 text-[10px] italic mt-1">{{ product.details }}</p>
|
||||
</div>
|
||||
<div class="bg-purple-500/10 border border-purple-500/20 px-3 py-1 rounded-xl">
|
||||
<span class="text-purple-400 font-black text-xs italic">{{ product.price }}€</span>
|
||||
</div>
|
||||
</div>
|
||||
{% for opt in contrat.contratsOptions %}
|
||||
<div class="p-6 hover:bg-white/[0.03] transition-colors flex justify-between items-center">
|
||||
<h4 class="text-white font-bold text-sm uppercase">{{ opt.name }}</h4>
|
||||
<span class="text-purple-400 font-black text-xs italic">{{ opt.price }}€ HT</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="p-10 text-center text-slate-600 text-[10px] font-black uppercase tracking-widest opacity-30">Aucun supplément</div>
|
||||
@@ -344,14 +329,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- 5. HISTORIQUE DES PAIEMENTS --- #}
|
||||
{# --- 6. HISTORIQUE FINANCIER --- #}
|
||||
<div class="space-y-4">
|
||||
<h3 class="px-2 text-sm font-black text-slate-400 uppercase tracking-[0.3em]">Historique Financier</h3>
|
||||
<div class="bg-white/[0.02] border border-white/10 rounded-[2rem] overflow-hidden">
|
||||
<h3 class="px-2 text-sm font-black text-slate-400 uppercase tracking-[0.3em]">Historique des transactions</h3>
|
||||
<div class="bg-white/[0.02] border border-white/10 rounded-[2.5rem] overflow-hidden">
|
||||
<table class="w-full text-left">
|
||||
<thead>
|
||||
<tr class="border-b border-white/5 bg-white/[0.03]">
|
||||
<th class="px-8 py-4 text-[9px] font-black text-slate-300 uppercase tracking-widest">Transaction</th>
|
||||
<th class="px-8 py-4 text-[9px] font-black text-slate-300 uppercase tracking-widest">Date</th>
|
||||
<th class="px-8 py-4 text-[9px] font-black text-slate-300 uppercase tracking-widest">Type</th>
|
||||
<th class="px-8 py-4 text-[9px] font-black text-slate-300 uppercase tracking-widest">Montant</th>
|
||||
<th class="px-8 py-4 text-[9px] font-black text-slate-300 uppercase tracking-widest text-right">Justificatif</th>
|
||||
@@ -362,24 +347,23 @@
|
||||
<tr class="group hover:bg-white/[0.02] transition-colors">
|
||||
<td class="px-8 py-5 text-xs text-white font-bold tracking-tight">{{ payment.paymentAt|date('d/m/Y H:i') }}</td>
|
||||
<td class="px-8 py-5">
|
||||
<span class="px-2 py-1 rounded-lg text-[8px] font-black uppercase italic
|
||||
{% if payment.type == 'caution' %}bg-purple-500/10 text-purple-400 border border-purple-500/20
|
||||
{% elseif payment.type == 'accompte' %}bg-blue-500/10 text-blue-400 border border-blue-500/20
|
||||
{% else %}bg-emerald-500/10 text-emerald-400 border border-emerald-500/20{% endif %}">
|
||||
{{ payment.type|replace({'_': ' '}) }}
|
||||
</span>
|
||||
<span class="px-2 py-1 rounded-lg text-[8px] font-black uppercase italic
|
||||
{% if payment.type == 'caution' %}bg-purple-500/10 text-purple-400
|
||||
{% elseif payment.type == 'accompte' %}bg-blue-500/10 text-blue-400
|
||||
{% else %}bg-emerald-500/10 text-emerald-400{% endif %}">
|
||||
{{ payment.type|replace({'_': ' '}) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-8 py-5 text-sm text-white font-black italic">{{ payment.amount|number_format(2, ',', ' ') }}€</td>
|
||||
<td class="px-8 py-5 text-right">
|
||||
<a href="{{ path('app_crm_contrats_view', {id: contrat.id, idPaymentPdf: payment.id}) }}" target="_blank"
|
||||
class="inline-flex items-center gap-2 text-[9px] font-black uppercase text-slate-400 hover:text-white transition-all">
|
||||
<a href="{{ path('app_crm_contrats_view', {id: contrat.id, idPaymentPdf: payment.id}) }}" target="_blank" class="inline-flex items-center gap-2 text-[9px] font-black uppercase text-slate-400 hover:text-white transition-all">
|
||||
<svg class="w-4 h-4 text-rose-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" stroke-width="2"/></svg>
|
||||
REÇU PDF
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="4" class="py-12 text-center text-slate-600 text-[10px] font-black uppercase opacity-40">Aucun paiement effectué</td></tr>
|
||||
<tr><td colspan="4" class="py-12 text-center text-slate-600 text-[10px] font-black uppercase opacity-40 italic">Aucun règlement</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<p class="text-xs font-bold text-slate-900">Mes Missions</p>
|
||||
<p class="text-[9px] text-slate-400 font-medium mt-0.5">Planning & Détails</p>
|
||||
</a>
|
||||
|
||||
|
||||
<a href="{{ path('etl_contrats') }}" class="bg-white p-5 rounded-[1.5rem] border border-slate-100 shadow-sm hover:border-blue-100 transition-all group active:scale-95">
|
||||
<div class="w-10 h-10 bg-emerald-50 rounded-xl flex items-center justify-center text-emerald-600 mb-3 group-hover:bg-emerald-600 group-hover:text-white transition-colors">
|
||||
<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 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
@@ -46,11 +46,11 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{# UPCOMING LIST #}
|
||||
<div class="space-y-4">
|
||||
<h3 class="px-2 text-xs font-black text-slate-400 uppercase tracking-widest">Prochainement</h3>
|
||||
|
||||
|
||||
{% if missions|length > 0 %}
|
||||
<div class="space-y-3">
|
||||
{% for mission in missions %}
|
||||
@@ -59,9 +59,12 @@
|
||||
<p class="text-[9px] font-black uppercase text-blue-500 mb-0.5">
|
||||
{{ mission.dateAt|date('d/m H:i') }} <span class="text-slate-300 mx-1">➜</span> {{ mission.endAt|date('d/m H:i') }}
|
||||
</p>
|
||||
<p class="text-xs font-bold text-slate-900">{{ mission.townEvent }}</p>
|
||||
<p class="text-xs font-bold text-slate-900">{{ mission.numReservation }} - {{ mission.townEvent }}</p>
|
||||
<p class="text-xs font-bold text-slate-900"> {{ mission.customer.name }} {{ mission.customer.surname }}</p>
|
||||
{% if mission.etatLieux is not null and mission.etatLieux.status == "edl_validated" %}
|
||||
<p class="text-xs font-bold text-slate-900">En attends de l'état de retour</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<span class="text-xs text-slate-400 font-mono">{{ mission.zipCodeEvent }}</span>
|
||||
</a>
|
||||
{% endfor %} </div>
|
||||
{% else %} <div class="bg-white rounded-[2rem] border border-slate-100 p-8 text-center">
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{# ACTION LIVRAISON #}
|
||||
{% if not mission.etatLieux or mission.etatLieux.status == 'delivery_ready' %}
|
||||
<form action="{{ path('etl_mission_start', {id: mission.id}) }}" method="post">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<mj-text>
|
||||
L'état des lieux d'installation pour la réservation <strong>#{{ datas.contrat.numReservation }}</strong> a été validé et signé par les deux parties.
|
||||
</mj-text>
|
||||
|
||||
|
||||
<mj-text font-weight="bold" font-size="14px" padding-top="20px">
|
||||
Détails de l'intervention :
|
||||
</mj-text>
|
||||
|
||||
@@ -43,12 +43,4 @@
|
||||
</mj-text>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<mj-button href="{{ system.path }}{{ path('etl_contrat_view', {id: datas.contrat.id}) }}" background-color="#3b82f6" border-radius="8px" font-weight="bold" padding-top="30px">
|
||||
Consulter le dossier complet
|
||||
</mj-button>
|
||||
|
||||
<mj-text padding-top="30px" font-size="12px" color="#64748b" align="center">
|
||||
L'état des lieux a été marqué avec le statut <strong>"Refusé"</strong>. Veuillez vérifier les fichiers médias joints pour constater d'éventuels dommages.
|
||||
</mj-text>
|
||||
{% endblock %}
|
||||
|
||||
57
templates/mails/etl/edl_retour_confirmation.twig
Normal file
57
templates/mails/etl/edl_retour_confirmation.twig
Normal file
@@ -0,0 +1,57 @@
|
||||
{% extends 'mails/base.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<mj-text>
|
||||
Bonjour,
|
||||
</mj-text>
|
||||
|
||||
<mj-text>
|
||||
L'état des lieux pour la réservation <strong>#{{ datas.contrat.numReservation }}</strong> a été validé et signé par les deux parties.
|
||||
</mj-text>
|
||||
|
||||
<mj-text font-weight="bold" font-size="14px" padding-top="20px">
|
||||
Détails de l'intervention :
|
||||
</mj-text>
|
||||
<mj-text>
|
||||
<strong>Client :</strong> {{ datas.contrat.customer.surname }} {{ datas.contrat.customer.name }}<br>
|
||||
<strong>Lieu :</strong> {{ datas.contrat.addressEvent }} {{ datas.contrat.zipCodeEvent }} {{ datas.contrat.townEvent }}
|
||||
</mj-text>
|
||||
|
||||
{# Section Observations (Entrant ou Sortant selon le contexte) #}
|
||||
{% set comments = datas.etatLieux.status == 'edl_validated' ? datas.etatLieux.comments : datas.etatLieux.commentsReturn %}
|
||||
|
||||
{% if comments|length > 0 %}
|
||||
<mj-text font-weight="bold" font-size="14px" padding-top="20px">
|
||||
Observations / Commentaires :
|
||||
</mj-text>
|
||||
{% for comment in comments %}
|
||||
<mj-text padding-bottom="0">
|
||||
- [{{ comment.createdAt|date('d/m H:i') }}] {{ comment.content }}
|
||||
</mj-text>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{# Section Médias #}
|
||||
{% set files = datas.etatLieux.status == 'edl_validated' ? datas.etatLieux.files : datas.etatLieux.filesReturn %}
|
||||
|
||||
{% if files|length > 0 %}
|
||||
<mj-text font-weight="bold" font-size="14px" padding-top="20px">
|
||||
Médias joints au dossier ({{ files|length }}) :
|
||||
</mj-text>
|
||||
{% for file in files %}
|
||||
<mj-text padding-bottom="2px">
|
||||
- <a href="{{ system.path }}{{ vich_uploader_asset(file, 'file') }}" target="_blank" style="color:#3b82f6; text-decoration:underline;">
|
||||
Voir le fichier {{ loop.index }} ({{ file.type|capitalize }})
|
||||
</a>
|
||||
</mj-text>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<mj-text padding-top="20px" font-weight="bold" color="#10b981">
|
||||
L'exemplaire signé de votre état des lieux est joint à cet e-mail en version PDF.
|
||||
</mj-text>
|
||||
|
||||
<mj-button href="{{ system.path }}{{ path('etl_contrat_view', {id: datas.contrat.id}) }}" background-color="#3b82f6" border-radius="8px" font-weight="bold" padding-top="20px">
|
||||
Accéder à mon dossier
|
||||
</mj-button>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user