Files
ludikevent_crm/templates/dashboard/contrats/facture.twig

308 lines
21 KiB
Twig

{% extends 'dashboard/base.twig' %}
{% block title %}Facturation & Paiements{% endblock %}
{% block title_header %}Gestion <span class="text-blue-500">Financière</span>{% endblock %}
{% block body %}
<div class="w-full max-w-full mx-auto space-y-8 animate-in fade-in duration-700">
{# NAVIGATION DES ONGLETS #}
<div class="flex flex-col lg:flex-row items-center justify-between gap-6 mb-8">
<div class="inline-flex p-1.5 bg-[#1e293b]/60 backdrop-blur-xl border border-white/5 rounded-[2rem] shadow-2xl">
<a data-turbo="false" href="{{ path('app_crm_facture', {active: 'facture'}) }}"
class="flex items-center px-8 py-3.5 rounded-[1.5rem] transition-all duration-500 group {{ active == 'facture' ? 'bg-blue-600 shadow-lg shadow-blue-600/20' : 'hover:bg-white/5' }}">
<svg class="w-4 h-4 mr-3 {{ active == 'facture' ? 'text-white' : 'text-slate-500 group-hover:text-blue-400' }}" 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"/>
</svg>
<span class="text-[10px] font-black uppercase tracking-[0.2em] {{ active == 'facture' ? 'text-white' : 'text-slate-400 group-hover:text-white' }}">
Factures Émises
</span>
</a>
<a data-turbo="false" href="{{ path('app_crm_facture', {active: 'confirmed_paiement'}) }}"
class="flex items-center px-8 py-3.5 rounded-[1.5rem] transition-all duration-500 group {{ active == 'confirmed_paiement' ? 'bg-emerald-600 shadow-lg shadow-emerald-600/20' : 'hover:bg-white/5' }}">
<svg class="w-4 h-4 mr-3 {{ active == 'confirmed_paiement' ? 'text-white' : 'text-slate-500 group-hover:text-emerald-400' }}" 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>
<span class="text-[10px] font-black uppercase tracking-[0.2em] {{ active == 'confirmed_paiement' ? 'text-white' : 'text-slate-400 group-hover:text-white' }}">
Confirmations de paiement
</span>
</a>
</div>
{# ACTIONS RAPIDES #}
<div class="flex items-center gap-3">
{% if active == 'confirmed_paiement' %}
<a data-turbo="false" href="{{ path('app_crm_facture',{active:active,'extract':true, 'startDate': startDate, 'endDate': endDate, 'q': searchTerm}) }}"
class="px-6 py-3.5 bg-emerald-500/10 hover:bg-emerald-500 text-emerald-500 hover:text-white rounded-2xl border border-emerald-500/20 flex items-center transition-all duration-500 group shadow-xl shadow-emerald-500/5">
<svg class="w-4 h-4 mr-2.5 opacity-80 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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"/>
</svg>
<span class="text-[10px] font-black uppercase tracking-widest">Exporter .XLSX</span>
</a>
{% endif %}
<button onclick="window.location.reload()" class="px-6 py-3.5 bg-slate-800/80 hover:bg-slate-700 text-slate-300 rounded-2xl border border-white/5 flex items-center transition-all group">
<svg class="w-4 h-4 mr-2 opacity-50 group-hover:rotate-180 transition-transform duration-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
<span class="text-[10px] font-black uppercase tracking-widest">Actualiser</span>
</button>
</div>
</div>
{# MOTEUR DE RECHERCHE ET FILTRES #}
<div class="bg-[#1e293b]/40 backdrop-blur-xl border border-white/5 rounded-[2rem] p-6 shadow-xl mb-6">
<form method="GET" action="{{ path('app_crm_facture') }}" class="flex flex-col md:flex-row items-end gap-4">
<input type="hidden" name="active" value="{{ active }}">
<div class="flex-1 w-full space-y-2">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-2">Recherche globale</label>
<div class="relative">
<svg class="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4text-slate-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
<input type="text" name="q" value="{{ searchTerm }}"
placeholder="Nom, Réservation, Email..."
class="w-full bg-slate-900/50 border border-white/5 rounded-xl py-3 pl-11 pr-4 text-xs text-white placeholder:text-slate-600 focus:border-blue-500/50 focus:ring-0 transition-all">
</div>
</div>
<div class="w-full md:w-44 space-y-2">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-2">Date début</label>
<input type="date" name="startDate" value="{{ startDate }}"
class="w-full bg-slate-900/50 border border-white/5 rounded-xl py-3 px-4 text-xs text-white focus:border-blue-500/50 focus:ring-0 transition-all">
</div>
<div class="w-full md:w-44 space-y-2">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-2">Date fin</label>
<input type="date" name="endDate" value="{{ endDate }}"
class="w-full bg-slate-900/50 border border-white/5 rounded-xl py-3 px-4 text-xs text-white focus:border-blue-500/50 focus:ring-0 transition-all">
</div>
<button type="submit" class="bg-blue-600 hover:bg-blue-500 text-white p-3.5 rounded-xl transition-all shadow-lg shadow-blue-600/20 group">
<svg class="w-4 h-4 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</button>
{% if searchTerm or startDate or endDate %}
<a href="{{ path('app_crm_facture', {active: active}) }}" class="bg-slate-800 hover:bg-slate-700 text-slate-400 p-3.5 rounded-xl transition-all border border-white/5">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</a>
{% endif %}
</form>
</div>
{# CONTENU DYNAMIQUE #}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl">
{% if active == 'facture' %}
{# VUE FACTURES #}
<div class="flex items-center space-x-4 mb-10">
<span class="w-8 h-px bg-blue-500/30"></span>
<span class="text-[10px] font-black text-blue-500 uppercase tracking-[0.3em]">Flux de facturation en cours</span>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left">
<thead>
<tr class="border-b border-white/5">
<th class="pb-6 text-[10px] font-black text-slate-300 uppercase tracking-widest">Date</th>
<th class="pb-6 text-[10px] font-black text-slate-300 uppercase tracking-widest">Client</th>
<th class="pb-6 text-[10px] font-black text-slate-300 uppercase tracking-widest text-center">Statut</th>
</tr>
</thead>
<tbody class="divide-y divide-white/5 text-slate-400 italic text-xs">
{% for confirmedPaiement in pagination2 %}
<tr class="group bg-white/[0.02] hover:bg-white/[0.05] transition-all duration-300">
<td class="py-5 pl-6 rounded-l-2xl border-y border-l border-white/5">
<div class="flex flex-col">
<span class="text-xs font-bold text-white">{{ confirmedPaiement.createAt|date('d/m/Y') }}</span>
<span class="text-[9px] text-slate-300 font-medium">Encaissé</span>
</div>
</td>
<td class="py-5 border-y border-white/5">
<div class="flex flex-col">
<span class="text-xs font-bold text-slate-200 uppercase tracking-tight">
{{ confirmedPaiement.contrat.customer.name }} {{ confirmedPaiement.contrat.customer.surname }}
</span>
<span class="text-[10px text-slate-300 lowercase">{{ confirmedPaiement.contrat.customer.email }}</span>
</div>
</td>
<td class="py-5 border-y border-white/5">
<span class="px-3 py-1.5 bg-slate-900/50 rounded-lg border border-white/5 text-[10px] font-mono font-bold text-blue-400">
{{ confirmedPaiement.contrat.numReservation }}
</span>
</td>
<td class="py-5 pr-6 rounded-r-2xl border-y border-r border-white/5 text-right">
{% if confirmedPaiement.factureFileName !="" %}
<a href="{{ vich_uploader_asset(confirmedPaiement, 'factureFile') }}"
download
class="inline-flex p-2.5 bg-emerald-500/10 hover:bg-emerald-500 text-emerald-500 hover:text-white rounded-xl transition-all duration-300 border border-emerald-500/20 group/btn"
title="Télécharger le justificatif">
<svg class="w-4 h-4 transform 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="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
</svg>
</a>
{% else %}
<span class="text-[9px] font-black text-slate-600 uppercase tracking-tighter italic">Aucun fichier</span>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="py-20 text-center border-2 border-dashed border-white/5 rounded-[2rem]">
<div class="flex flex-col items-center">
<svg class="w-10 h-10 text-slate-600 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
</svg>
<p class="text-slate-500 text-[10px] font-black uppercase tracking-[0.3em]">Aucune donnée trouvée pour cette recherche</p>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
{# VUE PAIEMENTS CONFIRMÉS #}
<div class="flex items-center space-x-4 mb-10">
<span class="w-8 h-px bg-emerald-500/30"></span>
<span class="text-[10px] font-black text-emerald-500 uppercase tracking-[0.3em]">Historique des encaissements</span>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-separate border-spacing-y-3">
<thead>
<tr class="text-slate-500 uppercase">
<th class="pb-4 pl-6 text-[10px] font-black tracking-[0.2em]">Date</th>
<th class="pb-4 text-[10px] font-black tracking-[0.2em]">Client</th>
<th class="pb-4 text-[10px] font-black tracking-[0.2em]">N° Réservation</th>
<th class="pb-4 text-[10px] font-black tracking-[0.2em]">Méthode</th>
<th class="pb-4 text-[10px] font-black tracking-[0.2em]">État</th>
<th class="pb-4 pr-6 text-[10px] font-black tracking-[0.2em] text-right">Preuve</th>
</tr>
</thead>
<tbody class="space-y-4">
{% for confirmedPaiement in pagination %}
<tr class="group bg-white/[0.02] hover:bg-white/[0.05] transition-all duration-300">
<td class="py-5 pl-6 rounded-l-2xl border-y border-l border-white/5">
<div class="flex flex-col">
<span class="text-xs font-bold text-white">{{ confirmedPaiement.paymentAt|date('d/m/Y') }}</span>
<span class="text-[9px] text-slate-300 font-medium">Encaissé</span>
</div>
</td>
<td class="py-5 border-y border-white/5">
<div class="flex flex-col">
<span class="text-xs font-bold text-slate-200 uppercase tracking-tight">
{{ confirmedPaiement.contrat.customer.name }} {{ confirmedPaiement.contrat.customer.surname }}
</span>
<span class="text-[10px text-slate-300 lowercase">{{ confirmedPaiement.contrat.customer.email }}</span>
</div>
</td>
<td class="py-5 border-y border-white/5">
<span class="px-3 py-1.5 bg-slate-900/50 rounded-lg border border-white/5 text-[10px] font-mono font-bold text-blue-400">
{{ confirmedPaiement.contrat.numReservation }}
</span>
</td>
<td class="py-5 border-y border-white/5">
<div class="inline-flex items-center px-2.5 py-1 rounded-md bg-white/5 border border-white/10">
<span class="text-[9px] font-black text-slate-400 uppercase tracking-widest">{{ confirmedPaiement.type }}</span>
</div>
</td>
<td class="py-5 border-y border-white/5">
<div class="flex items-center space-x-2">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.6)]"></span>
<span class="text-[10px] font-black text-emerald-500 uppercase tracking-widest">{{ confirmedPaiement.state }}</span>
</div>
</td>
<td class="py-5 pr-6 rounded-r-2xl border-y border-r border-white/5 text-right">
{% if confirmedPaiement.paymentFileName !="" %}
<a href="{{ vich_uploader_asset(confirmedPaiement, 'paymentFile') }}"
download
class="inline-flex p-2.5 bg-emerald-500/10 hover:bg-emerald-500 text-emerald-500 hover:text-white rounded-xl transition-all duration-300 border border-emerald-500/20 group/btn"
title="Télécharger le justificatif">
<svg class="w-4 h-4 transform 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="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
</svg>
</a>
{% else %}
<span class="text-[9px] font-black text-slate-600 uppercase tracking-tighter italic">Aucun fichier</span>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="py-20 text-center border-2 border-dashed border-white/5 rounded-[2rem]">
<div class="flex flex-col items-center">
<svg class="w-10 h-10 text-slate-600 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
</svg>
<p class="text-slate-500 text-[10px] font-black uppercase tracking-[0.3em]">Aucune donnée trouvée pour cette recherche</p>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{# PAGINATION KNP BUNDLE #}
<div class="mt-8 flex justify-center">
<div class="knp-pagination-wrapper">
{{ knp_pagination_render(pagination) }}
</div>
</div>
{% endif %}
</div>
</div>
{# Style personnalisé pour la pagination KNP afin de correspondre au thème sombre #}
<style>
.knp-pagination-wrapper .pagination {
display: flex;
gap: 0.5rem;
align-items: center;
}
.knp-pagination-wrapper .page-item .page-link {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
color: #94a3b8;
padding: 0.5rem 1rem;
border-radius: 0.75rem;
font-size: 11px;
font-weight: 800;
text-transform: uppercase;
transition: all 0.3s ease;
}
.knp-pagination-wrapper .page-item.active .page-link {
background: #10b981;
color: white;
border-color: #10b981;
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.2);
}
.knp-pagination-wrapper .page-item:hover:not(.active) .page-link {
background: rgba(255, 255, 255, 0.1);
color: white;
}
/* Style spécifique pour les inputs de date (chrome/safari) */
input[type="date"]::-webkit-calendar-picker-indicator {
filter: invert(1);
opacity: 0.5;
cursor: pointer;
}
</style>
{% endblock %}