✨ feat(devis/contrat): ajoute prestataires et paiements aux devis et améliore la gestion des règlements et statuts
This commit is contained in:
@@ -141,10 +141,15 @@
|
||||
<div>
|
||||
<span class="block text-[9px] font-black uppercase tracking-widest {{ acompteOk ? 'text-emerald-500' : 'text-rose-500' }}">Acompte</span>
|
||||
{% if not acompteOk %}
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'accompte'}) }}"
|
||||
class="mt-3 inline-flex px-4 py-1.5 bg-rose-500/20 hover:bg-rose-500/30 border border-rose-500/30 rounded-lg text-[10px] font-black text-rose-400 uppercase transition-all">
|
||||
Marquer réglé
|
||||
</a>
|
||||
<div class="mt-3 flex flex-wrap justify-center gap-2 max-w-[200px]">
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mt-2 text-[10px] text-emerald-500/60 font-bold uppercase italic">Encaissé</p>
|
||||
{% endif %}
|
||||
@@ -200,10 +205,15 @@
|
||||
|
||||
{# 3. SINON, C'EST QU'ELLE N'EST PAS ENCORE ENREGISTRÉE #}
|
||||
{% else %}
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'caution'}) }}"
|
||||
class="px-4 py-1.5 bg-rose-500/20 hover:bg-rose-500/30 border border-rose-500/30 rounded-lg text-[10px] font-black text-rose-400 uppercase transition-all">
|
||||
Marquer reçue
|
||||
</a>
|
||||
<div class="flex flex-wrap justify-center gap-2 max-w-[200px]">
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -222,10 +232,15 @@
|
||||
<div>
|
||||
<span class="block text-[9px] font-black uppercase tracking-widest {{ soldeOk ? 'text-emerald-500' : 'text-rose-500' }}">Solde Final</span>
|
||||
{% if not soldeOk %}
|
||||
<a data-turbo="false" href="{{ path('app_crm_contrats_view', {id: contrat.id, type: 'solde'}) }}"
|
||||
class="px-4 py-1.5 bg-rose-500/20 hover:bg-rose-500/30 border border-rose-500/30 rounded-lg text-[10px] font-black text-rose-400 uppercase transition-all">
|
||||
Régler le solde
|
||||
</a>
|
||||
<div class="mt-3 flex flex-wrap justify-center gap-2 max-w-[200px]">
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mt-2 text-[10px] text-emerald-500/60 font-bold uppercase italic">Totalité payée</p>
|
||||
{% endif %}
|
||||
|
||||
@@ -107,6 +107,36 @@
|
||||
|
||||
<hr class="border-white/5">
|
||||
|
||||
{# --- BLOC 04.5 : LIVRAISON & PAIEMENT --- #}
|
||||
<div class="mt-8 backdrop-blur-xl bg-slate-900/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl">
|
||||
<h3 class="text-sm font-black text-indigo-500 uppercase tracking-widest mb-8 flex items-center justify-center">
|
||||
<span class="w-6 h-6 bg-indigo-600/20 rounded-lg flex items-center justify-center mr-3 text-[10px]">05</span>
|
||||
Logistique & Paiement
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-4xl mx-auto">
|
||||
<div>
|
||||
<label class="block text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] mb-3 ml-2">Mode de paiement</label>
|
||||
<select name="devis[paymentMethod]" class="w-full bg-slate-900/60 border border-white/10 rounded-2xl px-5 py-4 text-sm text-white outline-none focus:border-indigo-500/50 focus:bg-slate-900/90 transition-all duration-300">
|
||||
<option value="">Sélectionner...</option>
|
||||
{% for type in ['Paiement Via Chorus', 'Paiement En ligne', 'Paiement Après événement', 'Autre mode de paiement'] %}
|
||||
<option value="{{ type }}" {% if devis.paymentMethod == type %}selected{% endif %}>{{ type }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] font-black text-slate-300 uppercase tracking-[0.2em] mb-3 ml-2">Prestataire (Livraison)</label>
|
||||
<select name="devis[prestataire]" class="w-full bg-slate-900/60 border border-white/10 rounded-2xl px-5 py-4 text-sm text-white outline-none focus:border-indigo-500/50 focus:bg-slate-900/90 transition-all duration-300">
|
||||
<option value="">-- Aucun prestataire assigné --</option>
|
||||
{% for p in prestataires %}
|
||||
<option value="{{ p.id }}" {% if devis.prestataire and devis.prestataire.id == p.id %}selected{% endif %}>
|
||||
{{ p.surname }} {{ p.name }} ({{ p.email }})
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# SECTION REPEATER #}
|
||||
<div class="form-repeater" data-component="repeater" is="repeat-line">
|
||||
<div class="flex items-center justify-between mb-6 px-4">
|
||||
|
||||
@@ -178,6 +178,22 @@
|
||||
<p class="text-3xl font-black text-slate-900 italic tracking-tighter">{{ totalTTC|number_format(2, ',', ' ') }}€</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# INFO CAUTION #}
|
||||
{% if totalCaution > 0 %}
|
||||
<div class="bg-amber-50 rounded-[1.5rem] p-6 border border-amber-100 shadow-sm flex items-start gap-4">
|
||||
<div class="p-2 bg-amber-100 rounded-lg text-amber-600 shrink-0">
|
||||
<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="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>
|
||||
<p class="text-[10px] font-black text-amber-500 uppercase tracking-widest mb-1">Information Caution</p>
|
||||
<p class="text-xs font-bold text-slate-600 leading-relaxed">
|
||||
Un chèque de caution vous sera demandé le jour de livraison d'un montant de <span class="text-amber-600 font-black">{{ totalCaution|number_format(2, ',', ' ') }}€</span>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# SOLDE FINAL - Bloc Principal avec saisie du montant #}
|
||||
<div class="bg-slate-900 rounded-[2rem] p-8 text-white shadow-xl shadow-slate-200 relative overflow-hidden">
|
||||
<div class="absolute top-0 right-0 -mt-4 -mr-4 w-24 h-24 bg-blue-600/10 rounded-full blur-2xl"></div>
|
||||
@@ -240,8 +256,9 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# 2. ACOMPTE #}
|
||||
{% if not contratPaymentPay(contrat, 'accompte') %}
|
||||
{% if not (contrat.devis and 'Chorus' in contrat.devis.paymentMethod) %}
|
||||
{# 2. ACOMPTE #}
|
||||
{% if not contratPaymentPay(contrat, 'accompte') %}
|
||||
<div class="bg-white rounded-[2rem] border border-red-100 shadow-xl shadow-red-100/20 overflow-hidden">
|
||||
<div class="bg-red-500 p-6 text-white flex items-center gap-4">
|
||||
<div class="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center"><svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2"></path></svg></div>
|
||||
@@ -284,6 +301,64 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# 3. SOLDE #}
|
||||
{% if solde > 0 %}
|
||||
<div class="bg-white rounded-[2rem] border border-blue-100 shadow-xl shadow-blue-100/20 overflow-hidden">
|
||||
<div class="bg-blue-600 p-6 text-white flex items-center gap-4">
|
||||
<div class="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center"><svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2M12 3v1m0 16v1m-9-9h1.79A2.76 2.76 0 005.255 12h13.49a2.76 2.76 0 002.465-1.79H23"></path></svg></div>
|
||||
<p class="text-sm font-black uppercase italic leading-none">Solde restant</p>
|
||||
</div>
|
||||
<div class="p-6 text-center">
|
||||
<p class="text-3xl font-black text-slate-900 italic mb-4">{{ solde|number_format(2, ',', ' ') }}€</p>
|
||||
|
||||
{% if contrat.signed and contratPaymentPay(contrat, 'accompte') %}
|
||||
<form data-turbo="false" action="{{ path('gestion_contrat_view', {'num': contrat.numReservation}) }}" method="get">
|
||||
<input type="hidden" name="act" value="soldePay">
|
||||
<div class="mb-4">
|
||||
<label for="amountToPay" class="block text-[9px] font-black text-slate-400 uppercase tracking-widest mb-2 text-left">Montant à régler</label>
|
||||
<div class="relative">
|
||||
<input type="number" step="0.01" min="1" max="{{ solde }}" name="amountToPay" id="amountToPay" value="{{ solde }}"
|
||||
class="w-full bg-slate-50 border border-slate-200 rounded-xl px-4 py-3 text-sm font-bold text-slate-800 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all text-center">
|
||||
<div class="absolute right-4 top-3 text-slate-400 font-bold text-sm">€</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="block w-full bg-slate-900 text-white py-4 rounded-xl font-black uppercase text-xs hover:bg-blue-600 transition-all shadow-md">
|
||||
Régler le solde
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="p-3 bg-slate-50 rounded-xl border border-slate-100">
|
||||
<span class="text-[9px] text-slate-400 font-black uppercase tracking-tighter">
|
||||
{% if not contrat.signed %}Attente signature{% else %}Attente acompte{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="bg-white rounded-[2rem] border border-green-100 shadow-xl shadow-green-100/20 overflow-hidden">
|
||||
<div class="bg-green-500 p-6 text-white flex items-center gap-4">
|
||||
<div class="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center"><svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg></div>
|
||||
<p class="text-sm font-black uppercase italic leading-none">Solde Réglé</p>
|
||||
</div>
|
||||
<div class="p-5">
|
||||
{% for payment in paymentCtaList %}
|
||||
<div class="bg-slate-50 p-4 rounded-2xl border border-slate-100 mb-2 last:mb-0">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest">Paiement</p>
|
||||
<p class="text-sm font-black text-slate-900 italic leading-none">{{ payment.amount|number_format(2, ',', ' ') }}€</p>
|
||||
</div>
|
||||
<p class="text-[8px] text-slate-400 font-medium italic uppercase tracking-tighter">Le {{ payment.validateAt|date('d/m/Y') }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="mt-4 p-3 bg-green-50 rounded-xl border border-green-100 text-center">
|
||||
<span class="text-[10px] font-black text-green-600 uppercase tracking-tight">Dossier à jour</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{# ... (Garder tout le code précédent inchangé jusqu'à la fin de la grille 3 colonnes) ... #}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user