'use client'; import React, { useState, useEffect, useRef } from 'react'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Button } from 'primereact/button'; import { InputText } from 'primereact/inputtext'; import { Card } from 'primereact/card'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { Tag } from 'primereact/tag'; import { Dialog } from 'primereact/dialog'; import { Calendar } from 'primereact/calendar'; import { InputTextarea } from 'primereact/inputtextarea'; import { Dropdown } from 'primereact/dropdown'; import { devisService } from '../../../../services/api'; import { formatDate, formatCurrency } from '../../../../utils/formatters'; import type { Devis } from '../../../../types/btp'; import devisActionsService from '../../../../services/devisActionsService'; const DevisAcceptesPage = () => { const [devis, setDevis] = useState([]); const [loading, setLoading] = useState(true); const [globalFilter, setGlobalFilter] = useState(''); const [selectedDevis, setSelectedDevis] = useState([]); const [actionDialog, setActionDialog] = useState(false); const [selectedDevisItem, setSelectedDevisItem] = useState(null); const [actionType, setActionType] = useState<'create_chantier' | 'create_facture' | 'contract'>('create_chantier'); const [chantierData, setChantierData] = useState({ nom: '', dateDebut: new Date(), dateFinPrevue: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), description: '' }); const toast = useRef(null); const dt = useRef>(null); useEffect(() => { loadDevis(); }, []); const loadDevis = async () => { try { setLoading(true); const data = await devisService.getAll(); // Filtrer les devis acceptés const devisAcceptes = data.filter(devis => devis.statut === 'ACCEPTE'); setDevis(devisAcceptes); } catch (error) { console.error('Erreur lors du chargement des devis:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les devis acceptés', life: 3000 }); } finally { setLoading(false); } }; const getDaysSinceAcceptance = (dateEmission: string | Date) => { const today = new Date(); const acceptanceDate = new Date(dateEmission); // Approximation const diffTime = today.getTime() - acceptanceDate.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); return diffDays; }; const needsAction = (dateEmission: string | Date) => { const days = getDaysSinceAcceptance(dateEmission); return days > 7; // Plus de 7 jours sans action }; const createChantier = (devisItem: Devis) => { setSelectedDevisItem(devisItem); setActionType('create_chantier'); setChantierData({ nom: `Chantier - ${devisItem.objet}`, dateDebut: new Date(), dateFinPrevue: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), description: devisItem.description || '' }); setActionDialog(true); }; const createFacture = (devisItem: Devis) => { setSelectedDevisItem(devisItem); setActionType('create_facture'); setActionDialog(true); }; const generateContract = (devisItem: Devis) => { setSelectedDevisItem(devisItem); setActionType('contract'); setActionDialog(true); }; const handleAction = async () => { if (!selectedDevisItem) return; try { let message = ''; switch (actionType) { case 'create_chantier': await devisActionsService.createChantierFromDevis({ devisId: selectedDevisItem.id, dateDebutSouhaitee: chantierData.dateDebut.toISOString(), notes: chantierData.notes }); message = 'Chantier créé avec succès'; break; case 'create_facture': await devisActionsService.createFactureFromDevis({ devisId: selectedDevisItem.id, type: 'FACTURE' }); message = 'Facture créée avec succès'; break; case 'contract': // Générer un contrat PDF (simulation) generateContractPDF(selectedDevisItem); message = 'Contrat généré avec succès'; break; } setActionDialog(false); toast.current?.show({ severity: 'success', summary: 'Succès', detail: `${message} (simulation)`, life: 3000 }); } catch (error) { console.error('Erreur lors de l\'action:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible d\'effectuer l\'action', life: 3000 }); } }; const generateContractPDF = (devisItem: Devis) => { // Simulation de génération de contrat const contractContent = ` === CONTRAT DE TRAVAUX === DEVIS DE RÉFÉRENCE: ${devisItem.numero} DATE: ${new Date().toLocaleDateString('fr-FR')} CLIENT: ${devisItem.client ? `${devisItem.client.prenom} ${devisItem.client.nom}` : 'N/A'} ${devisItem.client?.entreprise || ''} ${devisItem.client?.adresse || ''} ${devisItem.client?.codePostal || ''} ${devisItem.client?.ville || ''} PRESTATAIRE: [Votre entreprise] OBJET DES TRAVAUX: ${devisItem.objet} DESCRIPTION: ${devisItem.description || 'Voir devis en annexe'} MONTANT: Montant HT: ${formatCurrency(devisItem.montantHT || 0)} TVA (${devisItem.tauxTVA}%): ${formatCurrency((devisItem.montantTVA || 0))} Montant TTC: ${formatCurrency(devisItem.montantTTC || 0)} CONDITIONS: - Délai d'exécution: ${devisItem.delaiExecution || 30} jours - Conditions de paiement: ${devisItem.conditionsPaiement || 'À définir'} - Validité du contrat: À partir de la signature Date et signature du client: Date et signature du prestataire: `; const blob = new Blob([contractContent], { type: 'text/plain;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `contrat_${devisItem.numero}_${new Date().toISOString().split('T')[0]}.txt`; link.click(); }; const exportCSV = () => { dt.current?.exportCSV(); }; const generateAcceptanceReport = () => { const totalValue = devis.reduce((sum, d) => sum + (d.montantTTC || 0), 0); const avgValue = totalValue / (devis.length || 1); const needingAction = devis.filter(d => needsAction(d.dateEmission)); const report = ` === RAPPORT DEVIS ACCEPTÉS === Période: ${new Date().toLocaleDateString('fr-FR')} STATISTIQUES GÉNÉRALES: - Nombre total de devis acceptés: ${devis.length} - Valeur totale des devis: ${formatCurrency(totalValue)} - Valeur moyenne par devis: ${formatCurrency(avgValue)} - Devis nécessitant une action: ${needingAction.length} DEVIS NÉCESSITANT UNE ACTION (${needingAction.length}): ${needingAction.map(d => ` - ${d.numero} - ${d.objet} Client: ${d.client ? `${d.client.prenom} ${d.client.nom}` : 'N/A'} Montant: ${formatCurrency(d.montantTTC || 0)} Accepté depuis: ${getDaysSinceAcceptance(d.dateEmission)} jours `).join('')} RÉPARTITION PAR MOIS: ${getMonthlyBreakdown()} RECOMMANDATIONS: - Créer les chantiers pour les devis acceptés depuis plus de 7 jours - Établir les factures d'acompte si prévues - Générer les contrats pour formaliser les accords `; const blob = new Blob([report], { type: 'text/plain;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `rapport_devis_acceptes_${new Date().toISOString().split('T')[0]}.txt`; link.click(); toast.current?.show({ severity: 'success', summary: 'Rapport généré', detail: 'Le rapport a été téléchargé', life: 3000 }); }; const getMonthlyBreakdown = () => { const months = {}; devis.forEach(d => { const month = new Date(d.dateEmission).toLocaleDateString('fr-FR', { year: 'numeric', month: 'long' }); if (!months[month]) { months[month] = { count: 0, value: 0 }; } months[month].count++; months[month].value += d.montantTTC || 0; }); return Object.entries(months) .map(([month, data]: [string, any]) => `- ${month}: ${data.count} devis, ${formatCurrency(data.value)}`) .join('\n'); }; const leftToolbarTemplate = () => { return (
Devis acceptés ({devis.length})
); }; const rightToolbarTemplate = () => { return (