src/Controller/ComptaController.php line 64

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