src/Controller/UploadProcessController.php line 296

Open in your IDE?
  1. <?php
  2. // src/Controller/UploadProcessController.php
  3. namespace App\Controller;
  4. use App\Entity\DeclarationConducteur;
  5. use App\Entity\DeclarationLigne;
  6. use App\Entity\UploadBatch;
  7. use App\Service\Project2ApiClient;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  10. use Symfony\Component\HttpFoundation\JsonResponse;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Routing\Annotation\Route;
  14. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  15. class UploadProcessController extends AbstractController
  16. {
  17.     private EntityManagerInterface $em;
  18.     private string $projectDir;
  19.     private Project2ApiClient $apiClient;
  20.     public function __construct(
  21.         EntityManagerInterface $em
  22.         ParameterBagInterface $parameterBag,
  23.         Project2ApiClient $apiClient
  24.     ) {
  25.         $this->em $em;
  26.         $this->projectDir $parameterBag->get('kernel.project_dir');
  27.         $this->apiClient $apiClient;
  28.     }
  29.     /**
  30.      * @Route("/upload/process/{id}", name="upload_process", methods={"POST"})
  31.      */
  32.     public function process(UploadBatch $batch): JsonResponse
  33.     {
  34.         try {
  35.             if (!in_array($batch->getStatus(), ['uploaded''error'])) {
  36.                 return $this->json(['error' => 'Document déjà traité'], 400);
  37.             }
  38.             $batch->setStatus('processing');
  39.             $this->em->flush();
  40.             $filePath $this->projectDir '/public/uploads/' $batch->getStoredFilename();
  41.             
  42.             if (!file_exists($filePath)) {
  43.                 throw new \Exception('Fichier non trouvé: ' $filePath);
  44.             }
  45.             // Créer un objet UploadedFile simulé pour l'API
  46.             $file = new \Symfony\Component\HttpFoundation\File\File($filePath);
  47.             $uploadedFile = new \Symfony\Component\HttpFoundation\File\UploadedFile(
  48.                 $filePath,
  49.                 $batch->getOriginalFilename(),
  50.                 $batch->getMimeType(),
  51.                 null,
  52.                 true
  53.             );
  54.             // Appeler l'API
  55.             $extractedData $this->apiClient->extractDataFromFile(
  56.                 $uploadedFile,
  57.                 $batch->getOriginalFilename()
  58.             );
  59.             // Vérifier que les données sont valides
  60.             if (empty($extractedData) || !isset($extractedData['lignes'])) {
  61.                 throw new \Exception('Données extraites invalides depuis l\'API');
  62.             }
  63.             // Stocker en session
  64.             $this->get('session')->set('extracted_data_' $batch->getId(), [
  65.                 'raw_data' => $extractedData,
  66.                 'batch_id' => $batch->getId(),
  67.                 'timestamp' => time(),
  68.                 'source' => 'project2_api'
  69.             ]);
  70.             // Créer la déclaration
  71.             $declaration $this->createDeclarationFromExtractedData($batch$extractedData);
  72.             $this->em->persist($declaration);
  73.             $this->em->flush();
  74.             $batch->setStatus('processed');
  75.             $this->em->flush();
  76.             return $this->json([
  77.                 'success' => true,
  78.                 'message' => 'Extraction réussie via API. ' count($extractedData['lignes']) . ' lignes détectées.',
  79.                 'redirect' => $this->generateUrl('upload_review', ['id' => $batch->getId()]),
  80.                 'stats' => [
  81.                     'tables' => count($extractedData['lignes']),
  82.                     'lines' => count($extractedData['lignes']),
  83.                     'confidence' => $extractedData['confidence'] ?? 0
  84.                 ]
  85.             ]);
  86.         } catch (\Exception $e) {
  87.             $batch->setStatus('error');
  88.             $this->em->flush();
  89.             
  90.             error_log('Erreur traitement via API: ' $e->getMessage());
  91.             
  92.             return $this->json([
  93.                 'success' => false,
  94.                 'error' => 'Erreur: ' $e->getMessage(),
  95.                 'details' => $this->getParameter('kernel.debug') ? $e->getTraceAsString() : null
  96.             ], 500);
  97.         }
  98.     }
  99.     /**
  100.      * Crée une déclaration à partir des données extraites
  101.      */
  102.     private function createDeclarationFromExtractedData(UploadBatch $batch, array $extractedData): DeclarationConducteur
  103.     {
  104.         $declaration = new DeclarationConducteur();
  105.         $declaration->setUploadBatch($batch);
  106.         $declaration->setStatus('draft');
  107.         $declaration->setAgence($extractedData['agence'] ?? null);
  108.         $declaration->setImmatriculation($extractedData['immatriculation'] ?? null);
  109.         $declaration->setNumeroLicence($extractedData['numero_licence'] ?? null);
  110.         $declaration->setNomClient($extractedData['nom_client'] ?? null);
  111.         
  112.         if (isset($extractedData['date_debut']) && $extractedData['date_debut']) {
  113.             $declaration->setDateDebut($this->parseDate($extractedData['date_debut']));
  114.         }
  115.         if (isset($extractedData['date_fin']) && $extractedData['date_fin']) {
  116.             $declaration->setDateFin($this->parseDate($extractedData['date_fin']));
  117.         }
  118.         // Ajouter les lignes
  119.         foreach ($extractedData['lignes'] ?? [] as $ligneData) {
  120.             $ligne $this->createLigneFromData($declaration$ligneData);
  121.             $declaration->addLigne($ligne);
  122.         }
  123.         return $declaration;
  124.     }
  125.     /**
  126.      * Crée une ligne à partir des données
  127.      */
  128.     private function createLigneFromData(DeclarationConducteur $declaration, array $ligneData): DeclarationLigne
  129.     {
  130.         $ligne = new DeclarationLigne();
  131.         $ligne->setDeclaration($declaration);
  132.         $ligne->setAgence($declaration->getAgence());
  133.         $ligne->setImmatriculation($declaration->getImmatriculation());
  134.         $ligne->setNomClient($declaration->getNomClient());
  135.         
  136.         if (isset($ligneData['date']) && $ligneData['date']) {
  137.             $parsedDate $this->parseDate($ligneData['date']);
  138.             if ($parsedDate) {
  139.                 $ligne->setDateJour($parsedDate);
  140.             }
  141.         }
  142.         
  143.         $ligne->setLieuDepart($ligneData['lieu_depart'] ?? null);
  144.         $ligne->setKmDepart($ligneData['km_depart'] ?? null);
  145.         $ligne->setTranche1MatinDebut($ligneData['tranche_1_matin_debut'] ?? $ligneData['matin_debut'] ?? null);
  146.         $ligne->setTranche1MatinFin($ligneData['tranche_1_matin_fin'] ?? $ligneData['matin_fin'] ?? null);
  147.         $ligne->setTranche2MidiDebut($ligneData['tranche_2_midi_debut'] ?? $ligneData['midi_debut'] ?? null);
  148.         $ligne->setTranche2MidiFin($ligneData['tranche_2_midi_fin'] ?? $ligneData['midi_fin'] ?? null);
  149.         $ligne->setTranche3SoirDebut($ligneData['tranche_3_soir_debut'] ?? $ligneData['soir_debut'] ?? null);
  150.         $ligne->setTranche3SoirFin($ligneData['tranche_3_soir_fin'] ?? $ligneData['soir_fin'] ?? null);
  151.         $ligne->setTranche4AutreDebut($ligneData['tranche_4_autre_debut'] ?? null);
  152.         $ligne->setTranche4AutreFin($ligneData['tranche_4_autre_fin'] ?? null);
  153.         $ligne->setLieuArrivee($ligneData['lieu_arrivee'] ?? null);
  154.         $ligne->setKmArrivee($ligneData['km_arrivee'] ?? null);
  155.         $ligne->setTempsAnnexes($ligneData['temps_annexes'] ?? null);
  156.         $ligne->setTempsTotal($ligneData['temps_total'] ?? null);
  157.         $ligne->setCommentaires($ligneData['commentaires'] ?? null);
  158.         return $ligne;
  159.     }
  160.     /**
  161.      * @Route("/upload/test-api-connection", name="test_api_connection", methods={"GET"})
  162.      */
  163.     public function testApiConnection(): JsonResponse
  164.     {
  165.         try {
  166.             $isConnected $this->apiClient->testConnection();
  167.             $stats $this->apiClient->getStats();
  168.             return $this->json([
  169.                 'success' => true,
  170.                 'connected' => $isConnected,
  171.                 'stats' => $stats,
  172.                 'api_url' => $_ENV['PROJECT2_API_URL'] ?? 'non configuré'
  173.             ]);
  174.         } catch (\Exception $e) {
  175.             return $this->json([
  176.                 'success' => false,
  177.                 'error' => $e->getMessage()
  178.             ], 500);
  179.         }
  180.     }
  181.     /**
  182.      * Parse une date
  183.      */
  184.     private function parseDate(string $dateString): ?\DateTimeInterface
  185.     {
  186.         try {
  187.             $formats = ['d/m/Y''d-m-Y''Y-m-d''d/m/y''d-m-y'];
  188.             
  189.             foreach ($formats as $format) {
  190.                 $date \DateTime::createFromFormat($format$dateString);
  191.                 if ($date !== false) {
  192.                     return $date;
  193.                 }
  194.             }
  195.             
  196.             return new \DateTime($dateString);
  197.         } catch (\Exception $e) {
  198.             return null;
  199.         }
  200.     }
  201.     private function cleanupTempDir(string $tempDir): void
  202.     {
  203.         if (is_dir($tempDir)) {
  204.             $files = @scandir($tempDir);
  205.             if ($files) {
  206.                 foreach ($files as $file) {
  207.                     if ($file != '.' && $file != '..') {
  208.                         @unlink($tempDir '\\' $file);
  209.                     }
  210.                 }
  211.             }
  212.             @rmdir($tempDir);
  213.         }
  214.     }
  215.     /**
  216.      * @Route("/upload/review/{id}", name="upload_review", methods={"GET", "POST"})
  217.      */
  218.     public function review(Request $requestUploadBatch $batch): Response
  219.     {
  220.         $declaration $batch->getDeclaration();
  221.         if (!$declaration) {
  222.             throw $this->createNotFoundException();
  223.         }
  224.         // Gérer l'ajout d'une nouvelle ligne
  225.         if ($request->isMethod('POST') && $request->request->has('add_line')) {
  226.             $ligne = new DeclarationLigne();
  227.             $ligne->setDeclaration($declaration);
  228.             $ligne->setAgence($declaration->getAgence());
  229.             $ligne->setImmatriculation($declaration->getImmatriculation());
  230.             $ligne->setNomClient($declaration->getNomClient());
  231.             $ligne->setDateJour(new \DateTime());
  232.             
  233.             $declaration->addLigne($ligne);
  234.             $this->em->persist($ligne);
  235.             $this->em->flush();
  236.             $this->addFlash('success''Nouvelle ligne ajoutée');
  237.             return $this->redirectToRoute('upload_review', ['id' => $batch->getId()]);
  238.         }
  239.         // Gérer la suppression d'une ligne
  240.         if ($request->isMethod('POST') && $request->request->has('delete_line')) {
  241.             $lineId $request->request->get('delete_line');
  242.             foreach ($declaration->getLignes() as $ligne) {
  243.                 if ($ligne->getId() == $lineId) {
  244.                     $declaration->removeLigne($ligne);
  245.                     $this->em->remove($ligne);
  246.                     break;
  247.                 }
  248.             }
  249.             $this->em->flush();
  250.             $this->addFlash('success''Ligne supprimée');
  251.             return $this->redirectToRoute('upload_review', ['id' => $batch->getId()]);
  252.         }
  253.         // Gérer la validation complète
  254.         if ($request->isMethod('POST') && $request->request->has('validate_all')) {
  255.             return $this->validateDeclaration($request$batch$declaration);
  256.         }
  257.         // Gérer la sauvegarde brouillon
  258.         if ($request->isMethod('POST') && $request->request->has('save_draft')) {
  259.             return $this->saveDraft($request$batch$declaration);
  260.         }
  261.         // Récupérer les données brutes extraites pour information
  262.         $sessionData $this->get('session')->get('extracted_data_' $batch->getId());
  263.         $rawData $sessionData['raw_data'] ?? null;
  264.         return $this->render('upload/review.html.twig', [
  265.             'batch' => $batch,
  266.             'declaration' => $declaration,
  267.             'rawData' => $rawData,
  268.             'ligneCount' => $declaration->getLignes()->count()
  269.         ]);
  270.     }
  271.     // private function validateDeclaration(Request $request, UploadBatch $batch, DeclarationConducteur $declaration): Response
  272.     // {
  273.     //     $data = $request->request->all();
  274.     //     // Mettre à jour l'en-tête
  275.     //     $declaration->setNomClient($data['nom_client'] ?? $declaration->getNomClient());
  276.     //     $declaration->setImmatriculation($data['immatriculation'] ?? $declaration->getImmatriculation());
  277.     //     $declaration->setAgence($data['agence'] ?? $declaration->getAgence());
  278.     //     $declaration->setNumeroLicence($data['numero_licence'] ?? $declaration->getNumeroLicence());
  279.         
  280.     //     // Dates de période
  281.     //     if (isset($data['date_debut']) && $data['date_debut']) {
  282.     //         $declaration->setDateDebut(new \DateTime($data['date_debut']));
  283.     //     }
  284.     //     if (isset($data['date_fin']) && $data['date_fin']) {
  285.     //         $declaration->setDateFin(new \DateTime($data['date_fin']));
  286.     //     }
  287.         
  288.     //     // Mettre à jour les lignes existantes
  289.     //     if (isset($data['lignes']) && is_array($data['lignes'])) {
  290.     //         foreach ($data['lignes'] as $index => $ligneData) {
  291.     //             $lignes = $declaration->getLignes()->toArray();
  292.     //             if (isset($lignes[$index])) {
  293.     //                 $ligne = $lignes[$index];
  294.                     
  295.     //                 if (isset($ligneData['date']) && $ligneData['date']) {
  296.     //                     $ligne->setDateJour(new \DateTime($ligneData['date']));
  297.     //                 }
  298.                     
  299.     //                 $ligne->setLieuDepart($ligneData['lieu_depart'] ?? null);
  300.     //                 $ligne->setKmDepart($ligneData['km_depart'] ?? null);
  301.     //                 $ligne->setTranche1MatinDebut($ligneData['tranche_1_matin_debut'] ?? null);
  302.     //                 $ligne->setTranche1MatinFin($ligneData['tranche_1_matin_fin'] ?? null);
  303.     //                 $ligne->setTranche2MidiDebut($ligneData['tranche_2_midi_debut'] ?? null);
  304.     //                 $ligne->setTranche2MidiFin($ligneData['tranche_2_midi_fin'] ?? null);
  305.     //                 $ligne->setTranche3SoirDebut($ligneData['tranche_3_soir_debut'] ?? null);
  306.     //                 $ligne->setTranche3SoirFin($ligneData['tranche_3_soir_fin'] ?? null);
  307.     //                 $ligne->setTranche4AutreDebut($ligneData['tranche_4_autre_debut'] ?? null);
  308.     //                 $ligne->setTranche4AutreFin($ligneData['tranche_4_autre_fin'] ?? null);
  309.     //                 $ligne->setLieuArrivee($ligneData['lieu_arrivee'] ?? null);
  310.     //                 $ligne->setKmArrivee($ligneData['km_arrivee'] ?? null);
  311.     //                 $ligne->setTempsAnnexes($ligneData['temps_annexes'] ?? null);
  312.     //                 $ligne->setTempsTotal($ligneData['temps_total'] ?? null);
  313.     //                 $ligne->setCommentaires($ligneData['commentaires'] ?? null);
  314.                     
  315.     //                 $ligne->setIsCorrected(true);
  316.     //                 $ligne->setCorrectedAt(new \DateTimeImmutable());
  317.     //             }
  318.     //         }
  319.     //     }
  320.     //     $declaration->setProcessedAt(new \DateTimeImmutable());
  321.     //     $declaration->setStatus('validated');
  322.     //     $batch->setStatus('processed');
  323.         
  324.     //     $this->em->flush();
  325.     //     // Nettoyer la session
  326.     //     $this->get('session')->remove('extracted_data_' . $batch->getId());
  327.     //     $this->addFlash('success', 'Déclaration validée et enregistrée avec succès !');
  328.         
  329.     //     return $this->redirectToRoute('upload_list');
  330.     // }
  331.     // private function saveDraft(Request $request, UploadBatch $batch, DeclarationConducteur $declaration): Response
  332.     // {
  333.     //     $data = $request->request->all();
  334.     //     // Mettre à jour l'en-tête
  335.     //     $declaration->setNomClient($data['nom_client'] ?? $declaration->getNomClient());
  336.     //     $declaration->setImmatriculation($data['immatriculation'] ?? $declaration->getImmatriculation());
  337.     //     $declaration->setAgence($data['agence'] ?? $declaration->getAgence());
  338.     //     $declaration->setNumeroLicence($data['numero_licence'] ?? $declaration->getNumeroLicence());
  339.         
  340.     //     // Dates de période
  341.     //     if (isset($data['date_debut']) && $data['date_debut']) {
  342.     //         $declaration->setDateDebut(new \DateTime($data['date_debut']));
  343.     //     }
  344.     //     if (isset($data['date_fin']) && $data['date_fin']) {
  345.     //         $declaration->setDateFin(new \DateTime($data['date_fin']));
  346.     //     }
  347.         
  348.     //     // Mettre à jour les lignes existantes
  349.     //     if (isset($data['lignes']) && is_array($data['lignes'])) {
  350.     //         foreach ($data['lignes'] as $index => $ligneData) {
  351.     //             $lignes = $declaration->getLignes()->toArray();
  352.     //             if (isset($lignes[$index])) {
  353.     //                 $ligne = $lignes[$index];
  354.                     
  355.     //                 if (isset($ligneData['date']) && $ligneData['date']) {
  356.     //                     $ligne->setDateJour(new \DateTime($ligneData['date']));
  357.     //                 }
  358.                     
  359.     //                 $ligne->setLieuDepart($ligneData['lieu_depart'] ?? null);
  360.     //                 $ligne->setKmDepart($ligneData['km_depart'] ?? null);
  361.     //                 $ligne->setTranche1MatinDebut($ligneData['tranche_1_matin_debut'] ?? null);
  362.     //                 $ligne->setTranche1MatinFin($ligneData['tranche_1_matin_fin'] ?? null);
  363.     //                 $ligne->setTranche2MidiDebut($ligneData['tranche_2_midi_debut'] ?? null);
  364.     //                 $ligne->setTranche2MidiFin($ligneData['tranche_2_midi_fin'] ?? null);
  365.     //                 $ligne->setTranche3SoirDebut($ligneData['tranche_3_soir_debut'] ?? null);
  366.     //                 $ligne->setTranche3SoirFin($ligneData['tranche_3_soir_fin'] ?? null);
  367.     //                 $ligne->setTranche4AutreDebut($ligneData['tranche_4_autre_debut'] ?? null);
  368.     //                 $ligne->setTranche4AutreFin($ligneData['tranche_4_autre_fin'] ?? null);
  369.     //                 $ligne->setLieuArrivee($ligneData['lieu_arrivee'] ?? null);
  370.     //                 $ligne->setKmArrivee($ligneData['km_arrivee'] ?? null);
  371.     //                 $ligne->setTempsAnnexes($ligneData['temps_annexes'] ?? null);
  372.     //                 $ligne->setTempsTotal($ligneData['temps_total'] ?? null);
  373.     //                 $ligne->setCommentaires($ligneData['commentaires'] ?? null);
  374.                     
  375.     //                 $ligne->setIsCorrected(true);
  376.     //                 $ligne->setCorrectedAt(new \DateTimeImmutable());
  377.     //             }
  378.     //         }
  379.     //     }
  380.     //     $declaration->setStatus('draft');
  381.     //     $this->em->flush();
  382.     //     $this->addFlash('success', 'Brouillon sauvegardé avec succès');
  383.     //     return $this->redirectToRoute('upload_review', ['id' => $batch->getId()]);
  384.     // }
  385.     private function validateDeclaration(Request $requestUploadBatch $batchDeclarationConducteur $declaration): Response
  386. {
  387.     $data $request->request->all();
  388.     // Mettre à jour l'en-tête
  389.     $declaration->setNomClient($data['nom_client'] ?? $declaration->getNomClient());
  390.     $declaration->setImmatriculation($data['immatriculation'] ?? $declaration->getImmatriculation());
  391.     $declaration->setAgence($data['agence'] ?? $declaration->getAgence());
  392.     $declaration->setNumeroLicence($data['numero_licence'] ?? $declaration->getNumeroLicence());
  393.     
  394.     // Dates de période
  395.     if (isset($data['date_debut']) && $data['date_debut']) {
  396.         $declaration->setDateDebut(new \DateTime($data['date_debut']));
  397.     }
  398.     if (isset($data['date_fin']) && $data['date_fin']) {
  399.         $declaration->setDateFin(new \DateTime($data['date_fin']));
  400.     }
  401.     
  402.     // Mettre à jour les lignes existantes AVEC les champs de l'entête
  403.     if (isset($data['lignes']) && is_array($data['lignes'])) {
  404.         foreach ($data['lignes'] as $index => $ligneData) {
  405.             $lignes $declaration->getLignes()->toArray();
  406.             if (isset($lignes[$index])) {
  407.                 $ligne $lignes[$index];
  408.                 
  409.                 // Mettre à jour les champs de l'entête dans la ligne
  410.                 $ligne->setNomClient($declaration->getNomClient());
  411.                 $ligne->setImmatriculation($declaration->getImmatriculation());
  412.                 $ligne->setAgence($declaration->getAgence());
  413.                 
  414.                 if (isset($ligneData['date']) && $ligneData['date']) {
  415.                     $ligne->setDateJour(new \DateTime($ligneData['date']));
  416.                 }
  417.                 
  418.                 $ligne->setLieuDepart($ligneData['lieu_depart'] ?? null);
  419.                 $ligne->setKmDepart($ligneData['km_depart'] ?? null);
  420.                 $ligne->setTranche1MatinDebut($ligneData['tranche_1_matin_debut'] ?? null);
  421.                 $ligne->setTranche1MatinFin($ligneData['tranche_1_matin_fin'] ?? null);
  422.                 $ligne->setTranche2MidiDebut($ligneData['tranche_2_midi_debut'] ?? null);
  423.                 $ligne->setTranche2MidiFin($ligneData['tranche_2_midi_fin'] ?? null);
  424.                 $ligne->setTranche3SoirDebut($ligneData['tranche_3_soir_debut'] ?? null);
  425.                 $ligne->setTranche3SoirFin($ligneData['tranche_3_soir_fin'] ?? null);
  426.                 $ligne->setTranche4AutreDebut($ligneData['tranche_4_autre_debut'] ?? null);
  427.                 $ligne->setTranche4AutreFin($ligneData['tranche_4_autre_fin'] ?? null);
  428.                 $ligne->setLieuArrivee($ligneData['lieu_arrivee'] ?? null);
  429.                 $ligne->setKmArrivee($ligneData['km_arrivee'] ?? null);
  430.                 $ligne->setTempsAnnexes($ligneData['temps_annexes'] ?? null);
  431.                 $ligne->setTempsTotal($ligneData['temps_total'] ?? null);
  432.                 $ligne->setCommentaires($ligneData['commentaires'] ?? null);
  433.                 
  434.                 $ligne->setIsCorrected(true);
  435.                 $ligne->setCorrectedAt(new \DateTimeImmutable());
  436.             }
  437.         }
  438.     } else {
  439.         // Si pas de données de lignes dans la requête, mettre à jour quand même les champs d'entête
  440.         foreach ($declaration->getLignes() as $ligne) {
  441.             $ligne->setNomClient($declaration->getNomClient());
  442.             $ligne->setImmatriculation($declaration->getImmatriculation());
  443.             $ligne->setAgence($declaration->getAgence());
  444.         }
  445.     }
  446.     $declaration->setProcessedAt(new \DateTimeImmutable());
  447.     $declaration->setStatus('validated');
  448.     $batch->setStatus('processed');
  449.     
  450.     $this->em->flush();
  451.     // Nettoyer la session
  452.     $this->get('session')->remove('extracted_data_' $batch->getId());
  453.     $this->addFlash('success''Déclaration validée et enregistrée avec succès !');
  454.     
  455.     return $this->redirectToRoute('upload_list');
  456. }
  457. private function saveDraft(Request $requestUploadBatch $batchDeclarationConducteur $declaration): Response
  458. {
  459.     $data $request->request->all();
  460.     // Mettre à jour l'en-tête
  461.     $declaration->setNomClient($data['nom_client'] ?? $declaration->getNomClient());
  462.     $declaration->setImmatriculation($data['immatriculation'] ?? $declaration->getImmatriculation());
  463.     $declaration->setAgence($data['agence'] ?? $declaration->getAgence());
  464.     $declaration->setNumeroLicence($data['numero_licence'] ?? $declaration->getNumeroLicence());
  465.     
  466.     // Dates de période
  467.     if (isset($data['date_debut']) && $data['date_debut']) {
  468.         $declaration->setDateDebut(new \DateTime($data['date_debut']));
  469.     }
  470.     if (isset($data['date_fin']) && $data['date_fin']) {
  471.         $declaration->setDateFin(new \DateTime($data['date_fin']));
  472.     }
  473.     
  474.     // Mettre à jour les lignes existantes AVEC les champs de l'entête
  475.     if (isset($data['lignes']) && is_array($data['lignes'])) {
  476.         foreach ($data['lignes'] as $index => $ligneData) {
  477.             $lignes $declaration->getLignes()->toArray();
  478.             if (isset($lignes[$index])) {
  479.                 $ligne $lignes[$index];
  480.                 
  481.                 // Mettre à jour les champs de l'entête dans la ligne
  482.                 $ligne->setNomClient($declaration->getNomClient());
  483.                 $ligne->setImmatriculation($declaration->getImmatriculation());
  484.                 $ligne->setAgence($declaration->getAgence());
  485.                 
  486.                 if (isset($ligneData['date']) && $ligneData['date']) {
  487.                     $ligne->setDateJour(new \DateTime($ligneData['date']));
  488.                 }
  489.                 
  490.                 $ligne->setLieuDepart($ligneData['lieu_depart'] ?? null);
  491.                 $ligne->setKmDepart($ligneData['km_depart'] ?? null);
  492.                 $ligne->setTranche1MatinDebut($ligneData['tranche_1_matin_debut'] ?? null);
  493.                 $ligne->setTranche1MatinFin($ligneData['tranche_1_matin_fin'] ?? null);
  494.                 $ligne->setTranche2MidiDebut($ligneData['tranche_2_midi_debut'] ?? null);
  495.                 $ligne->setTranche2MidiFin($ligneData['tranche_2_midi_fin'] ?? null);
  496.                 $ligne->setTranche3SoirDebut($ligneData['tranche_3_soir_debut'] ?? null);
  497.                 $ligne->setTranche3SoirFin($ligneData['tranche_3_soir_fin'] ?? null);
  498.                 $ligne->setTranche4AutreDebut($ligneData['tranche_4_autre_debut'] ?? null);
  499.                 $ligne->setTranche4AutreFin($ligneData['tranche_4_autre_fin'] ?? null);
  500.                 $ligne->setLieuArrivee($ligneData['lieu_arrivee'] ?? null);
  501.                 $ligne->setKmArrivee($ligneData['km_arrivee'] ?? null);
  502.                 $ligne->setTempsAnnexes($ligneData['temps_annexes'] ?? null);
  503.                 $ligne->setTempsTotal($ligneData['temps_total'] ?? null);
  504.                 $ligne->setCommentaires($ligneData['commentaires'] ?? null);
  505.                 
  506.                 $ligne->setIsCorrected(true);
  507.                 $ligne->setCorrectedAt(new \DateTimeImmutable());
  508.             }
  509.         }
  510.     } else {
  511.         // Si pas de données de lignes dans la requête, mettre à jour quand même les champs d'entête
  512.         foreach ($declaration->getLignes() as $ligne) {
  513.             $ligne->setNomClient($declaration->getNomClient());
  514.             $ligne->setImmatriculation($declaration->getImmatriculation());
  515.             $ligne->setAgence($declaration->getAgence());
  516.         }
  517.     }
  518.     $declaration->setStatus('draft');
  519.     $this->em->flush();
  520.     $this->addFlash('success''Brouillon sauvegardé avec succès');
  521.     return $this->redirectToRoute('upload_review', ['id' => $batch->getId()]);
  522. }
  523.     // /**
  524.     //  * @Route("/upload/test-conversion/{id}", name="test_conversion", methods={"GET"})
  525.     //  */
  526.     // public function testConversion(UploadBatch $batch): Response
  527.     // {
  528.     //     $filePath = $this->projectDir . '/public/uploads/' . $batch->getStoredFilename();
  529.         
  530.     //     $html = '<h1>Test de conversion PDF en images</h1>';
  531.     //     $html .= '<p>Fichier: ' . basename($filePath) . '</p>';
  532.         
  533.     //     if (!file_exists($filePath)) {
  534.     //         return new Response($html . '<p style="color: red;">❌ Fichier non trouvé</p>');
  535.     //     }
  536.         
  537.     //     // Tester Ghostscript
  538.     //     $html .= '<h2>Test Ghostscript</h2>';
  539.     //     $html .= '<p>Chemin: ' . htmlspecialchars($this->ghostscriptPath) . '</p>';
  540.         
  541.     //     $tempDir = sys_get_temp_dir() . '\\test_gs_' . uniqid();
  542.     //     mkdir($tempDir, 0777, true);
  543.         
  544.     //     $testImage = $tempDir . '\\test.jpg';
  545.     //     $command = sprintf('"%s" -sDEVICE=jpeg -dFirstPage=1 -dLastPage=1 -r150 -dJPEGQ=90 -dNOPAUSE -dBATCH -dQUIET -sOutputFile="%s" "%s"',
  546.     //         $this->ghostscriptPath, $testImage, $filePath);
  547.         
  548.     //     exec($command . ' 2>&1', $output, $returnCode);
  549.         
  550.     //     $html .= '<p>Commande: <code>' . htmlspecialchars($command) . '</code></p>';
  551.     //     $html .= '<p>Code retour: ' . $returnCode . '</p>';
  552.     //     $html .= '<p>Sortie: <pre>' . htmlspecialchars(implode("\n", $output)) . '</pre></p>';
  553.         
  554.     //     if (file_exists($testImage) && filesize($testImage) > 0) {
  555.     //         $imageData = base64_encode(file_get_contents($testImage));
  556.     //         $html .= '<p>✅ Image générée (' . filesize($testImage) . ' octets)</p>';
  557.     //         $html .= '<img src="data:image/jpeg;base64,' . $imageData . '" style="max-width: 800px; border: 1px solid #ccc;">';
  558.             
  559.     //         // Tester la préparation du contenu
  560.     //         $html .= '<h2>Test préparation pour OpenAI</h2>';
  561.     //         try {
  562.     //             $messages = $this->prepareContentForOpenAI($filePath, $batch->getExtension());
  563.     //             $html .= '<p>✅ Préparation réussie</p>';
  564.     //             $html .= '<pre>' . htmlspecialchars(json_encode($messages, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . '</pre>';
  565.     //         } catch (\Exception $e) {
  566.     //             $html .= '<p style="color: red;">❌ Erreur: ' . htmlspecialchars($e->getMessage()) . '</p>';
  567.     //         }
  568.             
  569.     //         unlink($testImage);
  570.     //     } else {
  571.     //         $html .= '<p style="color: red;">❌ Aucune image générée</p>';
  572.             
  573.     //         // Tester pdftoppm
  574.     //         $html .= '<h2>Test pdftoppm</h2>';
  575.     //         if ($this->tryPdfToPpmConversion($filePath, $tempDir)) {
  576.     //             $html .= '<p>✅ pdftoppm fonctionne</p>';
  577.     //             $images = glob($tempDir . '\\alt_page*.jpg');
  578.     //             foreach ($images as $image) {
  579.     //                 if (file_exists($image)) {
  580.     //                     $imageData = base64_encode(file_get_contents($image));
  581.     //                     $html .= '<img src="data:image/jpeg;base64,' . $imageData . '" style="max-width: 800px; border: 1px solid #ccc; margin-bottom: 10px;">';
  582.     //                     unlink($image);
  583.     //                 }
  584.     //             }
  585.     //         } else {
  586.     //             $html .= '<p style="color: red;">❌ pdftoppm ne fonctionne pas</p>';
  587.     //         }
  588.     //     }
  589.         
  590.     //     @rmdir($tempDir);
  591.         
  592.     //     return new Response($html);
  593.     // }
  594. }