feat(Product.php): Ajoute ProductDoc pour gérer les documents.
 feat(Contrats.php): Gère les fichiers du contrat via VichUploader.
 feat(templates): Crée template mail signature contrat.
 feat(SignatureController): Ajoute la signature du contrat.
 feat(ContratsController): Crée contrat depuis devis et liste contrats.
 feat(Client): Crée soumission contrat Docuseal.
 feat(DevisPdfService): Corrige l'assurance RC Pro.
 feat(.env): Ajoute CONTRAT_BASEURL.
 feat(ProductDocType): Crée formulaire pour les documents produit.
 feat(contrats/list.twig): Liste et actions pour les contrats.
 feat(UtmEvent.js): Track click document produit.
 feat(ContratEvent.php): Crée event pour envoi contrat.
 feat(admin.js): Initialise la recherche dynamique des contrats.
 feat(ContratPdfService): Génère le PDF du contrat DocuSeal.
 feat(products/add.twig): Ajoute gestion des documents produits.
 feat(ContratController): Crée controlleur contrat.
 feat(ContratSubscriber.php): Envoi du contrat par email.
 feat(reservation/produit.twig): Affiche les documents produit.
 feat(ProductController.php): Refactorisation et ajout des documents.
```
This commit is contained in:
Serreau Jovann
2026-01-22 15:58:57 +01:00
parent 9eafbbe2d9
commit afa6133907
32 changed files with 2263 additions and 286 deletions

View File

@@ -3,6 +3,25 @@
{% block title %}Fiche Produit{% endblock %}
{% block title_header %}Gestion du <span class="text-blue-500">Matériel</span>{% endblock %}
{% block actions %}
<div class="flex items-center gap-4">
<a target="_blank" rel="nofollow"
href="https://reservation.ludikevent.fr{{ path('reservation_product_show', {id: product.slug}) }}"
class="flex items-center px-6 py-3 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-blue-500/50 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-2xl transition-all group shadow-xl backdrop-blur-md">
<svg class="w-4 h-4 mr-2.5 text-blue-500 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="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
<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"/>
</svg>
Voir sur le site
<svg class="w-3 h-3 ml-2 text-slate-500 group-hover:translate-x-1 group-hover:-translate-y-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
</svg>
</a>
</div>
{% endblock %}
{% block body %}
<div class="max-w-6xl mx-auto animate-in fade-in slide-in-from-bottom-4 duration-700">
{{ form_start(form) }}
@@ -143,11 +162,6 @@
{# FOOTER ACTIONS #}
<div class="mt-12 mb-20 flex items-center justify-between backdrop-blur-xl bg-slate-900/40 p-6 rounded-[2rem] border border-white/5 shadow-xl">
<a href="{{ path('app_crm_product') }}" class="px-8 py-3 text-[10px] font-black text-slate-400 hover:text-white uppercase tracking-widest transition-colors flex items-center group">
<svg class="w-4 h-4 mr-2 transform group-hover:-translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" /></svg>
Retour au catalogue
</a>
<button type="submit" class="relative overflow-hidden group px-12 py-4 bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black uppercase tracking-[0.2em] rounded-2xl transition-all shadow-lg shadow-blue-600/30">
<span class="relative z-10 flex items-center">
<svg class="w-4 h-4 mr-2" 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>
@@ -158,5 +172,87 @@
</div>
{{ form_end(form) }}
{# 03. DOCUMENTS TECHNIQUES (PDF) #}
{% if formDoc is defined %}
<div class="backdrop-blur-xl bg-[#1e293b]/40 border border-white/5 rounded-[2.5rem] p-8 shadow-2xl mt-8">
<h3 class="text-lg font-bold text-white mb-6 flex items-center">
<span class="w-8 h-8 bg-amber-600/20 text-amber-500 rounded-lg flex items-center justify-center mr-3 text-[10px] font-black">03</span>
Documents & Notices
</h3>
{# LISTE DES DOCUMENTS EXISTANTS #}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-10">
{% for doc in product.productDocs %}
<div class="flex items-center justify-between p-4 bg-white/5 border border-white/5 rounded-2xl group hover:bg-white/10 transition-all">
<div class="flex items-center">
<div class="w-10 h-10 bg-red-500/20 text-red-500 rounded-xl flex items-center justify-center mr-4">
<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="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"/></svg>
</div>
<div>
<div class="text-xs font-black text-white uppercase tracking-wider">{{ doc.name }}</div>
<div class="text-[9px] font-bold {{ doc.isPublic ? 'text-emerald-500' : 'text-slate-500' }} uppercase tracking-tighter">
{{ doc.isPublic ? '● Public' : '○ Privé (Interne)' }}
</div>
</div>
</div>
<div class="flex gap-2">
<a href="{{ vich_uploader_asset(doc, 'docProduct') }}" target="_blank" class="p-2 text-slate-400 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="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
</a>
<form data-turbo="false" method="post" action="{{ path('app_crm_product_edit', {'id': product.id,act:'deleted',idDoc:doc.id}) }}"
onsubmit="return confirm('Confirmer la suppression de ce document ?');"
class="inline-block">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ doc.id) }}">
<button type="submit" class="p-2 text-slate-400 hover:text-rose-500 transition-colors" title="Supprimer">
<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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
</form>
{# Ici tu pourrais ajouter un lien de suppression #}
</div>
</div>
{% else %}
<div class="md:col-span-2 py-8 text-center border-2 border-dashed border-white/5 rounded-3xl">
<p class="text-[10px] font-black text-slate-600 uppercase tracking-[0.2em]">Aucun document attaché</p>
</div>
{% endfor %}
</div>
<div class="h-px bg-white/5 w-full mb-10"></div>
{# FORMULAIRE D'AJOUT #}
{{ form_start(formDoc) }}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-end">
<div>
{{ form_label(formDoc.name, 'Nom du document', {'label_attr': {'class': 'text-[10px] font-black text-slate-500 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(formDoc.name, {'attr': {'placeholder': 'Ex: Notice technique PDF', 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-amber-500/20 focus:border-amber-500 transition-all py-4 px-5 font-bold text-sm'}}) }}
</div>
<div>
{{ form_label(formDoc.isPublic, 'Visibilité Client', {'label_attr': {'class': 'text-[10px] font-black text-slate-500 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }}
{{ form_widget(formDoc.isPublic, {'attr': {'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-4 px-5 font-bold text-sm cursor-pointer'}}) }}
</div>
<div class="md:col-span-2 bg-slate-950/40 p-6 rounded-[2rem] border border-dashed border-white/10 group hover:border-amber-500/30 transition-all">
{{ form_label(formDoc.docProduct, 'Fichier PDF (Notice, Certificat...)', {'label_attr': {'class': 'text-[10px] font-black text-slate-500 uppercase tracking-widest mb-4 block text-center'}}) }}
{{ form_widget(formDoc.docProduct, {
'attr': {
'class': 'block w-full text-xs text-slate-400 file:mr-4 file:py-3 file:px-6 file:rounded-xl file:border-0 file:text-[10px] file:font-black file:uppercase file:tracking-widest file:bg-amber-600 file:text-white hover:file:bg-amber-500 transition-all cursor-pointer'
}
}) }}
</div>
</div>
<div class="mt-8 flex justify-end">
<button type="submit" class="group px-8 py-4 bg-amber-600/10 hover:bg-amber-600 text-amber-500 hover:text-white text-[10px] font-black uppercase tracking-widest rounded-2xl transition-all border border-amber-500/20 flex items-center">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 4v16m8-8H4"/></svg>
Ajouter au dossier
</button>
</div>
{{ form_end(formDoc) }}
</div>
{% endif %}
</div>
{% endblock %}