src/Controller/ComptaController.php line 111

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Facture;
  4. use App\Form\FactureType;
  5. use App\Repository\FactureRepository;
  6. use App\Repository\EntrepriseRepository;
  7. use App\Repository\ContratRepository;
  8. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpFoundation\Response;
  11. use Symfony\Component\Routing\Annotation\Route;
  12. use App\Repository\ElectricMeterRepository;
  13. use App\Repository\GasMeterRepository;
  14. use App\Repository\UserRepository;
  15. use App\Repository\ChargeRepository;
  16. use App\Entity\Entreprise;
  17. use App\Entity\ElectricMeter;
  18. use App\Entity\GasMeter;
  19. use App\Entity\User;
  20. use App\Entity\Contrat;
  21. use App\Entity\Charge;
  22. use App\Form\ContratType;
  23. use App\Form\ChargeType;
  24. use App\Service\PricingService;
  25. use Doctrine\ORM\EntityManagerInterface;
  26. use Symfony\Component\HttpFoundation\JsonResponse;
  27. /**
  28.  * @Route("/compta")
  29.  */
  30. class ComptaController extends AbstractController
  31. {
  32.     private $pricingService;
  33.     public function __construct(PricingService $pricingService)
  34.     {
  35.         $this->pricingService $pricingService;
  36.     }
  37.     /**
  38.      * @Route("/", name="app_compta")
  39.      */
  40.     public function index(EntrepriseRepository $entrepriseRepository): Response
  41.     {
  42.         $entreprises $entrepriseRepository->findAll();
  43.         $totalEntreprises count($entreprises);
  44.         $elecricMeters $this->getDoctrine()->getRepository(ElectricMeter::class)->findAll();
  45.         $gasMeters $this->getDoctrine()->getRepository(GasMeter::class)->findAll();
  46.         $totalElectricMeters count($elecricMeters);
  47.         $totalGasMeters count($gasMeters);
  48.         return $this->render('compta/index.html.twig', [
  49.             'total_entreprises' => $totalEntreprises,
  50.             'total_electric_meters' => $totalElectricMeters,
  51.             'total_gas_meters' => $totalGasMeters,
  52.         ]);
  53.     }
  54.     /**
  55.      * @Route("/charges", name="app_compta_charge")
  56.      */
  57.     public function charges(Request $requestChargeRepository $chargeRepositoryUserRepository $userRepository): Response
  58.     {
  59.         $session $request->getSession();
  60.         
  61.         // Récupérer les dates de la session ou utiliser null par défaut
  62.         $dateDebut $session->get('charges_date_debut');
  63.         $dateFin $session->get('charges_date_fin');
  64.         
  65.         $charges $chargeRepository->findAll();
  66.         
  67.         // Filter users to only get those with ROLE_TEAM
  68.         $agents $userRepository->createQueryBuilder('u')
  69.             ->where('u.roles LIKE :role')
  70.             ->setParameter('role''%ROLE_TEAM%')
  71.             ->orderBy('u.username''ASC')
  72.             ->getQuery()
  73.             ->getResult();
  74.         // Calculate totals
  75.         $totalHT 0;
  76.         $totalTVA 0;
  77.         $totalTTC 0;
  78.         // Get unique categories
  79.         $categories = [];
  80.         foreach ($charges as $charge) {
  81.             if ($charge->getCategoriePersonnalisee()) {
  82.                 $categories[$charge->getCategoriePersonnalisee()] = $charge->getCategoriePersonnalisee();
  83.             }
  84.             $totalHT += floatval($charge->getMontantHT());
  85.             $totalTVA += floatval($charge->getMontantTVA());
  86.             $totalTTC += floatval($charge->getMontantTTC());
  87.         }
  88.         // Sort categories alphabetically
  89.         sort($categories);
  90.         // Vérifier les charges mensuelles manquantes
  91.         $missingCharges $chargeRepository->checkMissingMonthlyCharges();
  92.         return $this->render('compta/charges.html.twig', [
  93.             'charges' => $charges,
  94.             'agents' => $agents,
  95.             'categories' => $categories,
  96.             'totalHT' => $totalHT,
  97.             'totalTVA' => $totalTVA,
  98.             'totalTTC' => $totalTTC,
  99.             'missingCharges' => $missingCharges,
  100.         ]);
  101.     }
  102.     /**
  103.      * @Route("/charge/new", name="app_compta_charge_new", methods={"GET","POST"})
  104.      */
  105.     public function newCharge(Request $requestEntityManagerInterface $entityManagerChargeRepository $chargeRepository): Response
  106.     {
  107.         $charge = new Charge();
  108.         
  109.         // If this is a monthly charge being added from the missing charges list
  110.         if ($request->query->has('monthly_charge_id')) {
  111.             $originalCharge $chargeRepository->find($request->query->get('monthly_charge_id'));
  112.             if ($originalCharge) {
  113.                 $charge->setAgent($originalCharge->getAgent());
  114.                 $charge->setDesignation($originalCharge->getDesignation());
  115.                 $charge->setCategorieDesignation($originalCharge->getCategorieDesignation());
  116.                 $charge->setCategoriePersonnalisee($originalCharge->getCategoriePersonnalisee());
  117.                 $charge->setMontantHT($originalCharge->getMontantHT());
  118.                 $charge->setTauxTVA($originalCharge->getTauxTVA());
  119.                 $charge->setMontantTVA($originalCharge->getMontantTVA());
  120.                 $charge->setMontantTTC($originalCharge->getMontantTTC());
  121.                 $charge->setIsEntrepriseCharge($originalCharge->getIsEntrepriseCharge());
  122.                 $charge->setIsMensuel($originalCharge->getIsMensuel());
  123.                 
  124.                 // Set the expected date from the query parameter if provided
  125.                 if ($request->query->has('expected_date')) {
  126.                     $expectedDate = new \DateTime($request->query->get('expected_date'));
  127.                     $charge->setDate($expectedDate);
  128.                 }
  129.             }
  130.         }
  131.         $form $this->createForm(ChargeType::class, $charge);
  132.         $form->handleRequest($request);
  133.         if ($form->isSubmitted() && $form->isValid()) {
  134.             try {
  135.                 // Ensure proper number formatting
  136.                 $montantHT floatval(str_replace(',''.'$charge->getMontantHT()));
  137.                 $montantTVA floatval(str_replace(',''.'$charge->getMontantTVA()));
  138.                 $montantTTC floatval(str_replace(',''.'$charge->getMontantTTC()));
  139.                 
  140.                 $charge->setMontantHT(number_format($montantHT2'.'''));
  141.                 $charge->setMontantTVA(number_format($montantTVA2'.'''));
  142.                 $charge->setMontantTTC(number_format($montantTTC2'.'''));
  143.                 $entityManager->persist($charge);
  144.                 $entityManager->flush();
  145.                 $this->addFlash('success''La charge a été créée avec succès.');
  146.                 return $this->redirectToRoute('app_compta_charge');
  147.             } catch (\Exception $e) {
  148.                 $this->addFlash('error''Une erreur est survenue lors de la création de la charge : ' $e->getMessage());
  149.             }
  150.         }
  151.         return $this->render('compta/charge/new.html.twig', [
  152.             'charge' => $charge,
  153.             'form' => $form->createView(),
  154.         ]);
  155.     }
  156.     /**
  157.      * @Route("/charge/{id}/edit", name="app_compta_charge_edit", methods={"GET","POST"})
  158.      */
  159.     public function editCharge(Request $requestCharge $chargeEntityManagerInterface $entityManager): Response
  160.     {
  161.         $form $this->createForm(ChargeType::class, $charge);
  162.         $form->handleRequest($request);
  163.         if ($form->isSubmitted() && $form->isValid()) {
  164.             try {
  165.                 // Ensure proper number formatting
  166.                 $montantHT floatval(str_replace(',''.'$charge->getMontantHT()));
  167.                 $montantTVA floatval(str_replace(',''.'$charge->getMontantTVA()));
  168.                 $montantTTC floatval(str_replace(',''.'$charge->getMontantTTC()));
  169.                 
  170.                 $charge->setMontantHT(number_format($montantHT2'.'''));
  171.                 $charge->setMontantTVA(number_format($montantTVA2'.'''));
  172.                 $charge->setMontantTTC(number_format($montantTTC2'.'''));
  173.                 $entityManager->flush();
  174.                 $this->addFlash('success''La charge a été modifiée avec succès.');
  175.                 return $this->redirectToRoute('app_compta_charge');
  176.             } catch (\Exception $e) {
  177.                 $this->addFlash('error''Une erreur est survenue lors de la modification de la charge : ' $e->getMessage());
  178.             }
  179.         }
  180.         return $this->render('compta/charge/edit.html.twig', [
  181.             'charge' => $charge,
  182.             'form' => $form->createView(),
  183.         ]);
  184.     }
  185.     /**
  186.      * @Route("/charge/{id}/duplicate", name="app_compta_charge_duplicate", methods={"GET"})
  187.      */
  188.     public function duplicateCharge(Charge $charge): Response
  189.     {
  190.         return $this->redirectToRoute('app_compta_charge_new', [
  191.             'monthly_charge_id' => $charge->getId()
  192.         ]);
  193.     }
  194.     /**
  195.      * @Route("/charge/{id}", name="app_compta_charge_delete", methods={"POST"})
  196.      */
  197.     public function deleteCharge(Request $requestCharge $chargeEntityManagerInterface $entityManager): Response
  198.     {
  199.         if ($this->isCsrfTokenValid('delete'.$charge->getId(), $request->request->get('_token'))) {
  200.             try {
  201.                 $entityManager->remove($charge);
  202.                 $entityManager->flush();
  203.                 $this->addFlash('success''La charge a été supprimée avec succès.');
  204.             } catch (\Exception $e) {
  205.                 $this->addFlash('error''Une erreur est survenue lors de la suppression de la charge : ' $e->getMessage());
  206.             }
  207.         }
  208.         return $this->redirectToRoute('app_compta_charge');
  209.     }
  210.     /**
  211.      * @Route("/contrats", name="app_compta_contrat")
  212.      */
  213.     public function contrats(ContratRepository $contratRepositoryElectricMeterRepository $electricMeterRepositoryGasMeterRepository $gasMeterRepository): Response
  214.     {
  215.         $contrats $contratRepository->findAll();
  216.         
  217.         // Get meters for type determination
  218.         $meters = [];
  219.         foreach ($electricMeterRepository->findAll() as $meter) {
  220.             $meters[$meter->getPDL()] = ['type' => 'Elec''profil' => $meter->getProfil()];
  221.         }
  222.         foreach ($gasMeterRepository->findAll() as $meter) {
  223.             $meters[$meter->getPDL()] = ['type' => 'Gaz''profil' => $meter->getProfil()];
  224.         }
  225.         return $this->render('compta/contrats.html.twig', [
  226.             'contrats' => $contrats,
  227.             'meters' => $meters,
  228.         ]);
  229.     }
  230.     /**
  231.      * @Route("/contrat/new", name="app_compta_contrat_new", methods={"GET","POST"})
  232.      */
  233.     public function newContrat(Request $requestEntityManagerInterface $entityManager): Response
  234.     {
  235.         $contrat = new Contrat();
  236.         $pdlChoices $this->getPDLChoicesForForm($entityManager);
  237.         $form $this->createForm(ContratType::class, $contrat, [
  238.             'pdl_choices' => $pdlChoices
  239.         ]);
  240.         $form->handleRequest($request);
  241.         if ($form->isSubmitted() && $form->isValid()) {
  242.             if (!$contrat->getDuree()) {
  243.                 $duration $this->calculateDurationInMonths($contrat->getDateDebut(), $contrat->getDateFin());
  244.                 $contrat->setDuree($duration);
  245.             }
  246.             // Use PricingService to calculate the contract value
  247.             $contratValue $this->pricingService->calculateContractValue($contrat);
  248.             $contrat->setValeur($contratValue);
  249.             if ($contrat->getEntreprise() && $contrat->getEntreprise()->getUtilisateur()) {
  250.                 $user $entityManager->getRepository(User::class)->find($contrat->getEntreprise()->getUtilisateur());
  251.                 if ($user) {
  252.                     $contrat->setCollaborateur($user);
  253.                 }
  254.             }
  255.             $entityManager->persist($contrat);
  256.             $entityManager->flush();
  257.             // Return JSON response for AJAX handling
  258.             if ($request->isXmlHttpRequest()) {
  259.                 return new JsonResponse([
  260.                     'success' => true,
  261.                     'contractId' => $contrat->getId(),
  262.                     'message' => 'Le contrat a été créé avec succès.'
  263.                 ]);
  264.             }
  265.             $this->addFlash('success''Le contrat a été créé avec succès.');
  266.             return $this->redirectToRoute('app_compta_contrat');
  267.         }
  268.         return $this->render('compta/new_contrat.html.twig', [
  269.             'contrat' => $contrat,
  270.             'form' => $form->createView(),
  271.         ]);
  272.     }
  273.     /**
  274.      * @Route("/contrat/{id}/edit", name="app_compta_contrat_edit", methods={"GET","POST"})
  275.      */
  276.     public function editContrat(Request $requestContrat $contratEntityManagerInterface $entityManager): Response
  277.     {
  278.         $pdlChoices $this->getPDLChoicesForForm($entityManager);
  279.         $form $this->createForm(ContratType::class, $contrat, [
  280.             'pdl_choices' => $pdlChoices
  281.         ]);
  282.         $form->handleRequest($request);
  283.         if ($form->isSubmitted() && $form->isValid()) {
  284.             if (!$contrat->getDuree()) {
  285.                 $duration $this->calculateDurationInMonths($contrat->getDateDebut(), $contrat->getDateFin());
  286.                 $contrat->setDuree($duration);
  287.             }
  288.             // Use PricingService to calculate the contract value
  289.             $contratValue $this->pricingService->calculateContractValue($contrat);
  290.             $contrat->setValeur($contratValue);
  291.             if ($contrat->getEntreprise() && $contrat->getEntreprise()->getUtilisateur()) {
  292.                 $user $entityManager->getRepository(User::class)->find($contrat->getEntreprise()->getUtilisateur());
  293.                 if ($user) {
  294.                     $contrat->setCollaborateur($user);
  295.                 }
  296.             }
  297.             $entityManager->flush();
  298.             return $this->redirectToRoute('app_compta_contrat');
  299.         }
  300.         return $this->render('compta/edit_contrat.html.twig', [
  301.             'contrat' => $contrat,
  302.             'form' => $form->createView(),
  303.         ]);
  304.     }
  305.     /**
  306.      * @Route("/contrat/{id}", name="app_compta_contrat_delete", methods={"POST"})
  307.      */
  308.     public function deleteContrat(Request $requestContrat $contratEntityManagerInterface $entityManager): Response
  309.     {
  310.         if ($this->isCsrfTokenValid('delete'.$contrat->getId(), $request->request->get('_token'))) {
  311.             $entityManager->remove($contrat);
  312.             $entityManager->flush();
  313.         }
  314.         return $this->redirectToRoute('app_compta_contrat');
  315.     }
  316.     /**
  317.      * @Route("/suivi_commercial", name="app_compta_suivit_commercial")
  318.      */
  319.     public function suivi_commercial(Request $requestUserRepository $userRepositoryContratRepository $contratRepository): Response
  320.     {
  321.         // Récupérer uniquement les utilisateurs avec ROLE_TEAM
  322.         $collaborators $userRepository->createQueryBuilder('u')
  323.             ->where('u.roles LIKE :role')
  324.             ->setParameter('role''%ROLE_TEAM%')
  325.             ->orderBy('u.username''ASC')
  326.             ->getQuery()
  327.             ->getResult();
  328.         // Récupérer les dates de la période
  329.         $dateDebut $request->query->get('date_debut') ? new \DateTime($request->query->get('date_debut')) : new \DateTime();
  330.         $dateFin $request->query->get('date_fin') ? new \DateTime($request->query->get('date_fin')) : new \DateTime();
  331.         // Périodes pour la durée des contrats
  332.         $contractPeriods = [122436];
  333.         $selectedContractPeriod = (int)$request->query->get('contract_period'12);
  334.         // Calculer les données commerciales
  335.         $commercialData $this->calculateCommercialData(
  336.             $collaborators
  337.             $contratRepository
  338.             $selectedContractPeriod,
  339.             $dateDebut,
  340.             $dateFin
  341.         );
  342.         return $this->render('compta/suivi_commercial.html.twig', [
  343.             'commercial_data' => $commercialData,
  344.             'contract_periods' => $contractPeriods,
  345.             'selected_contract_period' => $selectedContractPeriod,
  346.             'date_debut' => $dateDebut,
  347.             'date_fin' => $dateFin
  348.         ]);
  349.     }
  350.     private function calculateCommercialData($collaboratorsContratRepository $contratRepository$contractPeriod, \DateTime $dateDebut, \DateTime $dateFin): array
  351.     {
  352.         $data = [];
  353.         foreach ($collaborators as $collaborator) {
  354.             $totalPrestations 0;
  355.             // Utiliser la méthode du repository avec les dates spécifiques
  356.             $contrats $contratRepository->findContratsByPeriod($collaborator$dateDebut$dateFin);
  357.             foreach ($contrats as $contrat) {
  358.                 if (!$contrat->getDateSignature()) {
  359.                     continue;
  360.                 }
  361.                 // La valeur du contrat est maintenant annuelle
  362.                 $valeurAnnuelle $contrat->getValeur();
  363.                 
  364.                 // Calculer la date de fin en ajoutant la durée à la date de signature
  365.                 $dateFinContrat = clone $contrat->getDateSignature();
  366.                 $dateFinContrat->modify('+' $contrat->getDuree() . ' months');
  367.                 
  368.                 // Calculer le nombre d'années à prendre en compte
  369.                 $annees $contractPeriod 12;
  370.                 
  371.                 // Si la durée du contrat est inférieure à la période demandée,
  372.                 // on ajuste la valeur proportionnellement
  373.                 if ($contrat->getDuree() < $contractPeriod) {
  374.                     $annees $contrat->getDuree() / 12;
  375.                 }
  376.                 
  377.                 // Ajouter le montant total des prestations pour la période demandée
  378.                 $totalPrestations += $valeurAnnuelle $annees;
  379.             }
  380.             $data[] = [
  381.                 'name' => $collaborator->getUsername(),
  382.                 'total_prestations' => $totalPrestations
  383.             ];
  384.         }
  385.         return $data;
  386.     }
  387.     /**
  388.      * @Route("/suivi_comptable", name="app_compta_suivit_compta")
  389.      */
  390.     public function suivi_comptable(Request $request): Response
  391.     {
  392.         return $this->forward('App\Controller\ComptabiliteController::suivi', [
  393.             'request' => $request
  394.         ]);
  395.     }
  396.     private function calculateDurationInMonths(?\DateTimeInterface $dateDebut, ?\DateTimeInterface $dateFin): ?int
  397.     {
  398.         if (!$dateDebut || !$dateFin) {
  399.             return null;
  400.         }
  401.         $interval $dateDebut->diff($dateFin);
  402.         return $interval->12 $interval->m;
  403.     }
  404.     /**
  405.      * @Route("/get-pdl-options/{entreprise}", name="app_compta_get_pdl_options", methods={"GET"})
  406.      */
  407.     public function getPdlOptions(
  408.         Entreprise $entreprise,
  409.         ElectricMeterRepository $electricMeterRepository,
  410.         GasMeterRepository $gasMeterRepository
  411.     ): JsonResponse
  412.     {
  413.         $pdlOptions = [];
  414.         
  415.         // Fetch electric meters
  416.         $electricMeters $electricMeterRepository->findBy(['entreprise_id' => $entreprise->getId()]);
  417.         foreach ($electricMeters as $meter) {
  418.             $pdlOptions[] = [
  419.                 'pdl' => $meter->getPDL(),
  420.                 'type' => 'electric',
  421.                 'car' => $meter->getCAR(),
  422.                 'prix_moyen' => $meter->getPrix(),
  423.                 'fournisseur' => $meter->getFournisseur(),
  424.                 'date_debut' => $meter->getDateDebut() ? $meter->getDateDebut()->format('d/m/Y') : null,
  425.                 'date_fin' => $meter->getDateFin() ? $meter->getDateFin()->format('d/m/Y') : null,
  426.             ];
  427.         }
  428.         
  429.         // Fetch gas meters
  430.         $gasMeters $gasMeterRepository->findBy(['entreprise_id' => $entreprise->getId()]);
  431.         foreach ($gasMeters as $meter) {
  432.             $pdlOptions[] = [
  433.                 'pdl' => $meter->getPDL(),
  434.                 'type' => 'gas',
  435.                 'car' => $meter->getCAR(),
  436.                 'prix_moyen' => $meter->getPrix(),
  437.                 'fournisseur' => $meter->getFournisseur(),
  438.                 'date_debut' => $meter->getDateDebut() ? $meter->getDateDebut()->format('d/m/Y') : null,
  439.                 'date_fin' => $meter->getDateFin() ? $meter->getDateFin()->format('d/m/Y') : null,
  440.             ];
  441.         }
  442.         return new JsonResponse($pdlOptions);
  443.     }
  444.     /**
  445.      * @Route("/charges/save-dates", name="app_compta_save_dates", methods={"POST"})
  446.      */
  447.     public function saveDates(Request $request): JsonResponse
  448.     {
  449.         $session $request->getSession();
  450.         
  451.         // Sauvegarder les dates dans la session
  452.         $session->set('charges_date_debut'$request->request->get('dateDebut'));
  453.         $session->set('charges_date_fin'$request->request->get('dateFin'));
  454.         
  455.         return new JsonResponse(['success' => true]);
  456.     }
  457.     private function getPDLChoicesForForm(EntityManagerInterface $entityManager): array
  458.     {
  459.         $pdlChoices = [];
  460.         
  461.         $electricMeters $entityManager->getRepository(ElectricMeter::class)->findAll();
  462.         foreach ($electricMeters as $meter) {
  463.             $pdlChoices[$meter->getPDL()] = $meter->getPDL();
  464.         }
  465.         
  466.         $gasMeters $entityManager->getRepository(GasMeter::class)->findAll();
  467.         foreach ($gasMeters as $meter) {
  468.             $pdlChoices[$meter->getPDL()] = $meter->getPDL();
  469.         }
  470.         return $pdlChoices;
  471.     }
  472.     /**
  473.      * @Route("/get-contrats/{entreprise}", name="app_compta_get_contrats", methods={"GET"})
  474.      */
  475.     public function getContrats(Entreprise $entrepriseContratRepository $contratRepository): JsonResponse
  476.     {
  477.         $contrats $contratRepository->findBy(['entreprise' => $entreprise]);
  478.         $data = [];
  479.         
  480.         foreach ($contrats as $contrat) {
  481.             $data[] = [
  482.                 'id' => $contrat->getId(),
  483.                 'pdl' => $contrat->getPdl() ?? 'PDL non défini',
  484.                 'fournisseur' => $contrat->getFournisseur() ?? 'Fournisseur non défini',
  485.                 'car' => $contrat->getCar() ? number_format($contrat->getCar(), 0','' ') : '0',
  486.                 'dateDebut' => $contrat->getDateDebut() ? $contrat->getDateDebut()->format('d/m/Y') : 'N/A',
  487.                 'dateFin' => $contrat->getDateFin() ? $contrat->getDateFin()->format('d/m/Y') : 'N/A'
  488.             ];
  489.         }
  490.         return new JsonResponse($data);
  491.     }
  492.     /**
  493.      * @Route("/factures", name="app_compta_facture")
  494.      */
  495.     public function factures(Request $requestFactureRepository $factureRepositoryEntrepriseRepository $entrepriseRepositoryContratRepository $contratRepository): Response
  496.     {
  497.         $filters = [
  498.             'dateDebut' => $request->query->get('dateDebut') ? \DateTime::createFromFormat('d/m/Y'$request->query->get('dateDebut')) : null,
  499.             'dateFin' => $request->query->get('dateFin') ? \DateTime::createFromFormat('d/m/Y'$request->query->get('dateFin')) : null,
  500.             'entreprise' => $request->query->get('entreprise'),
  501.             'contrat' => $request->query->get('contrat'),
  502.             'statut' => $request->query->get('statut'),
  503.             'sort' => $request->query->get('sort''dateEmission'),
  504.             'direction' => $request->query->get('direction''DESC')
  505.         ];
  506.         return $this->render('compta/factures.html.twig', [
  507.             'factures' => $factureRepository->findByFilters($filters),
  508.             'entreprises' => $entrepriseRepository->findAll(),
  509.             'contrats' => $contratRepository->findAll(),
  510.         ]);
  511.     }
  512.     /**
  513.      * @Route("/facture/new", name="app_compta_facture_new", methods={"GET","POST"})
  514.      */
  515.     public function newFacture(Request $requestEntityManagerInterface $entityManager): Response
  516.     {
  517.         $facture = new Facture();
  518.         $form $this->createForm(FactureType::class, $facture);
  519.         $form->handleRequest($request);
  520.         if ($form->isSubmitted() && $form->isValid()) {
  521.             try {
  522.                 $entityManager->persist($facture);
  523.                 $entityManager->flush();
  524.                 $this->addFlash('success''La facture a été créée avec succès.');
  525.                 return $this->redirectToRoute('app_compta_facture');
  526.             } catch (\Exception $e) {
  527.                 $this->addFlash('error''Une erreur est survenue lors de la création de la facture : ' $e->getMessage());
  528.             }
  529.         }
  530.         return $this->render('compta/facture/new.html.twig', [
  531.             'facture' => $facture,
  532.             'form' => $form->createView(),
  533.         ]);
  534.     }
  535.     /**
  536.      * @Route("/facture/{id}", name="app_compta_facture_show", methods={"GET"})
  537.      */
  538.     public function showFacture(Facture $facture): Response
  539.     {
  540.         return $this->render('compta/facture/show.html.twig', [
  541.             'facture' => $facture,
  542.         ]);
  543.     }
  544.     /**
  545.      * @Route("/facture/{id}/edit", name="app_compta_facture_edit", methods={"GET","POST"})
  546.      */
  547.     public function editFacture(Request $requestFacture $factureEntityManagerInterface $entityManager): Response
  548.     {
  549.         $form $this->createForm(FactureType::class, $facture);
  550.         $form->handleRequest($request);
  551.         if ($form->isSubmitted() && $form->isValid()) {
  552.             $entityManager->flush();
  553.             $this->addFlash('success''La facture a été modifiée avec succès.');
  554.             return $this->redirectToRoute('app_compta_facture');
  555.         }
  556.         return $this->render('compta/facture/edit.html.twig', [
  557.             'facture' => $facture,
  558.             'form' => $form->createView(),
  559.         ]);
  560.     }
  561.     /**
  562.      * @Route("/facture/{id}", name="app_compta_facture_delete", methods={"POST"})
  563.      */
  564.     public function deleteFacture(Request $requestFacture $factureEntityManagerInterface $entityManager): Response
  565.     {
  566.         if ($this->isCsrfTokenValid('delete'.$facture->getId(), $request->request->get('_token'))) {
  567.             $entityManager->remove($facture);
  568.             $entityManager->flush();
  569.             $this->addFlash('success''La facture a été supprimée avec succès.');
  570.         }
  571.         return $this->redirectToRoute('app_compta_facture');
  572.     }
  573.     /**
  574.      * @Route("/facture/new-from-contract/{id}", name="app_compta_facture_new_from_contract", methods={"GET","POST"})
  575.      */
  576.     public function newFactureFromContract(Request $requestContrat $contratEntityManagerInterface $entityManager): Response
  577.     {
  578.         $facture = new Facture();
  579.         
  580.         // Pre-fill invoice data from contract
  581.         $facture->setEntreprise($contrat->getEntreprise());
  582.         $facture->setContrat($contrat);
  583.         $facture->setDateEmission(new \DateTime());
  584.         
  585.         // Set due date to 30 days after emission
  586.         $dueDate = new \DateTime();
  587.         $dueDate->modify('+30 days');
  588.         $facture->setDateEcheance($dueDate);
  589.         // Calculate monthly amount (annual value divided by 12)
  590.         $montantHT $contrat->getValeur() / 12;
  591.         $montantTVA $montantHT 0.20// 20% TVA
  592.         $montantTTC $montantHT $montantTVA;
  593.         $facture->setMontantHT(number_format($montantHT2'.'''));
  594.         $facture->setMontantTVA(number_format($montantTVA2'.'''));
  595.         $facture->setMontantTTC(number_format($montantTTC2'.'''));
  596.         // Generate invoice number (YYYYMM-XXX)
  597.         $numero date('Ym') . '-' sprintf('%03d'rand(1999));
  598.         $facture->setNumero($numero);
  599.         // Set initial status
  600.         $facture->setStatut('En attente');
  601.         $form $this->createForm(FactureType::class, $facture);
  602.         $form->handleRequest($request);
  603.         if ($form->isSubmitted() && $form->isValid()) {
  604.             $entityManager->persist($facture);
  605.             $entityManager->flush();
  606.             $this->addFlash('success''La facture a été créée avec succès.');
  607.             return $this->redirectToRoute('app_compta_facture');
  608.         }
  609.         return $this->render('compta/facture/new.html.twig', [
  610.             'facture' => $facture,
  611.             'form' => $form->createView(),
  612.             'from_contract' => true
  613.         ]);
  614.     }
  615. }