src/Controller/Api/Production/ProductionAnalyticsController.php line 126

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Api\Production;
  3. use App\Entity\User;
  4. use App\Repository\EtatProductionRepository;
  5. use App\Repository\ProductionRepository;
  6. use App\Service\HierarchyService;
  7. use DateTime;
  8. use App\Entity\Production;
  9. use App\Repository\UserRepository;
  10. use App\Repository\PointOfSaleRepository;
  11. use App\Repository\SatisfactionClientRepository;
  12. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  13. use Symfony\Component\HttpFoundation\JsonResponse;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\Routing\Annotation\Route;
  17. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  18. use Symfony\Component\Serializer\SerializerInterface;
  19. use Doctrine\ORM\EntityManagerInterface;
  20. class ProductionAnalyticsController extends AbstractController
  21. {
  22.     public function __invoke(
  23.         Request $request,
  24.         EtatProductionRepository $etatProductionRepository,
  25.         ProductionRepository $productionRepository,
  26.         PointOfSaleRepository $pointOfSaleRepository,
  27.         SatisfactionClientRepository $satisfactionClientRepository,
  28.         UserRepository $userRepository,
  29.         EntityManagerInterface $entityManager,
  30.         HierarchyService $hierarchyService
  31.     ) {
  32.         $pointOfSaleId $request->query->get('pointOfSaleId'null);
  33.         $pointsOfSale = [];
  34.         if ($pointOfSaleId !== null) {
  35.             $organisationId null;
  36.             $pointOfSale $pointOfSaleRepository->findOneBy(["id" => $pointOfSaleId]);
  37.             if ($pointOfSale === null) {
  38.                 throw new BadRequestHttpException('Le point de vente avec cet ID n\'existe pas.');
  39.             }
  40.             $pointsOfSale = [$pointOfSale];
  41.         } else {
  42.             $organisationId $request->query->get('organisationId'null);
  43.             $pointsOfSale $pointOfSaleRepository->findAll();
  44.         }
  45.         $codeCluster $request->query->get('codeCluster'null);
  46.         $codeInsee $request->query->get('codeInsee'null);
  47.         $optionSelect $request->query->get('optionSelect''V');
  48.         $category $request->query->get('categoryId');
  49.         $nbrMonth = (int) $request->query->get('nbrMonth'1);
  50.         $currentYear = (int) date('Y');
  51.         $currentMonth = (int) date('m');
  52.         $queryMonth $request->query->get('month');
  53.         $queryYear $request->query->get('year');
  54.         $perid $request->query->get('perid');
  55.         $sellerId $request->query->get('sellerId');
  56.         $departement $request->query->get('departement');
  57.         $childs = [];
  58.         $user null;
  59.         if ($request->query->get('idUser') != null) {
  60.             $user $entityManager->getRepository(User::class)->find((int)$request->query->get('idUser'));
  61.             if (!$user) {
  62.                 throw new BadRequestHttpException('L\'utilisateur avec cet ID n\'existe pas.');
  63.             }
  64.             // Récupérer l'hierarchie descendante
  65.             if (in_array('ROLE_MANAGER'$user->getRoles()) || in_array('ROLE_DIRECTOR'$user->getRoles())) {
  66.                 $childs array_map(fn($p) => (int) $p['id'], $hierarchyService->getHierarchyDescendante($user->getId()));
  67.             }
  68.         }
  69.         $baseMonth $queryMonth !== null ? (int) $queryMonth $currentMonth;
  70.         $baseYear $queryYear !== null ? (int) $queryYear $currentYear;
  71.         $etatKO $etatProductionRepository->findOneBy(["nom" => 'Racco KO']);
  72.         $etatRaccorde $etatProductionRepository->findOneBy(["nom" => 'Raccorde']);
  73.         $response = [];
  74.         for ($i 0$i $nbrMonth$i++) {
  75.             $date = (new \DateTimeImmutable("$baseYear-$baseMonth-01"))->modify("-$i months");
  76.             $mois = (int) $date->format('m');
  77.             $annee = (int) $date->format('Y');
  78.             // Initialisation des agrégats
  79.             $totalVentes 0;
  80.             $totalSatisfaction 0.0;
  81.             $nombreVendeurs 0;
  82.             $etp 0;
  83.             $totalVentesKO 0;
  84.             $totalObjectif 0;
  85.             $projection 0;
  86.             $jours_restants 0;
  87.             $moyenneJournaliere 0;
  88.             $clients4P 0;
  89.             $clients4PC 0;
  90.             $j30 0;
  91.             $j30_mobile 0;
  92.             $titulaire_mobile 0;
  93.             $titulaire_mobile_chainage 0;
  94.             $clients_hors_mig 0;
  95.             $total_clients_unique 0;
  96.             $total_ventes_raccordes_fixe_conquete 0;
  97.             $total_ventes_raccordes_fixe 0;
  98.             $total_ventes_raccordes_mobile 0;
  99.             $j30_raccorde_fixe_conquete 0;
  100.             $j30_raccorde_fixe 0;
  101.             $j30_raccorde_mobile 0;
  102.             $rio 0;
  103.             $pto_non_saisie 0;
  104.             $pto_saisie 0;
  105.             $pto_non_existante 0;
  106.             $pto_existante 0;
  107.             $total_vente_vla_conquette 0;
  108.             $total_ventes_box_5G 0;
  109.             $mrz = [];
  110.             $clients_4PC_par_semaine = [];
  111.             $clients_4P_par_semaine = [];
  112.             foreach ($pointsOfSale as $pointOfSale) {
  113.                 $satisfactionData $satisfactionClientRepository->getSatisfactionClientAverageForSpecificMonthAndYear(
  114.                     $pointOfSale,
  115.                     $codeCluster,
  116.                     $codeInsee,
  117.                     $mois,
  118.                     $annee,
  119.                     $category,
  120.                     $childs,
  121.                     $organisationId,
  122.                     $perid,
  123.                     $sellerId,
  124.                     $departement
  125.                 );
  126.                 $note = !empty($satisfactionData) && isset($satisfactionData[0]['moyenneSatisfaction'])
  127.                     ? (float) $satisfactionData[0]['moyenneSatisfaction'] : 0.0;
  128.                 $totalSatisfaction += $note;
  129.                 $totalVentes += $productionRepository->getProductionsAnalyticsVentes(
  130.                     $pointOfSale,
  131.                     $codeCluster,
  132.                     $codeInsee,
  133.                     $mois,
  134.                     $annee,
  135.                     $optionSelect,
  136.                     $etatKO,
  137.                     $category,
  138.                     $childs,
  139.                     $organisationId,
  140.                     $perid,
  141.                     $sellerId,
  142.                     $departement
  143.                 )[0]['total_ventes'] ?? 0;
  144.                 $total_ventes_box_5G += $productionRepository->getProductionsAnalyticsVentesBox5G(
  145.                     $pointOfSale,
  146.                     $codeCluster,
  147.                     $codeInsee,
  148.                     $mois,
  149.                     $annee,
  150.                     "V",
  151.                     $etatKO,
  152.                     $category,
  153.                     $childs,
  154.                     $organisationId,
  155.                     $perid,
  156.                     $sellerId,
  157.                     $departement
  158.                 )[0]['total_ventes'] ?? 0;
  159.                 $total_ventes_raccordes_fixe_conquete += $productionRepository->getProductionsAnalyticsVentesForChurn(
  160.                     $pointOfSale,
  161.                     $codeCluster,
  162.                     $codeInsee,
  163.                     $mois,
  164.                     $annee,
  165.                     'B',
  166.                     "Raccorde",
  167.                     null,
  168.                     $childs,
  169.                     $organisationId,
  170.                     $perid,
  171.                     $sellerId,
  172.                     $departement
  173.                 )[0]['total_ventes'] ?? 0;
  174.                  $total_ventes_raccordes_fixe += $productionRepository->getProductionsAnalyticsVentes(
  175.                     $pointOfSale,
  176.                     $codeCluster,
  177.                     $codeInsee,
  178.                     $mois,
  179.                     $annee,
  180.                     'B',
  181.                     "Raccorde",
  182.                     null,
  183.                     $childs,
  184.                     $organisationId,
  185.                     $perid,
  186.                     $sellerId,
  187.                     $departement
  188.                 )[0]['total_ventes'] ?? 0;
  189.                 $total_ventes_raccordes_mobile += $productionRepository->getProductionsAnalyticsVentes(
  190.                     $pointOfSale,
  191.                     $codeCluster,
  192.                     $codeInsee,
  193.                     $mois,
  194.                     $annee,
  195.                     'B',
  196.                     "Raccorde_mobile",
  197.                     "31,32,33",
  198.                     $childs,
  199.                     $organisationId,
  200.                     $perid,
  201.                     $sellerId,
  202.                     $departement
  203.                 )[0]['total_ventes'] ?? 0;
  204.                 $nombreVendeurs += $productionRepository->getProductionsAnalyticsVendeurs(
  205.                     $pointOfSale,
  206.                     $codeCluster,
  207.                     $codeInsee,
  208.                     $mois,
  209.                     $annee,
  210.                     $optionSelect,
  211.                     $etatKO,
  212.                     $category,
  213.                     $childs,
  214.                     $organisationId,
  215.                     $perid,
  216.                     $sellerId,
  217.                     $departement
  218.                 )[0]['nombre_vendeurs'] ?? 0;
  219.                 $etp += (int)($productionRepository->getProductionsAnalyticsETP(
  220.                     $pointOfSale,
  221.                     $codeCluster,
  222.                     $codeInsee,
  223.                     $mois,
  224.                     $annee,
  225.                     $optionSelect,
  226.                     $etatKO,
  227.                     $category,
  228.                     $childs,
  229.                     $organisationId,
  230.                     $perid,
  231.                     $sellerId,
  232.                     $departement
  233.                 )[0]['etp'] ?? 0);
  234.                 $totalVentesKO += $productionRepository->getProductionsAnalyticsKO(
  235.                     $pointOfSale,
  236.                     $codeCluster,
  237.                     $codeInsee,
  238.                     $mois,
  239.                     $annee,
  240.                     $optionSelect,
  241.                     $etatKO,
  242.                     $category,
  243.                     $childs,
  244.                     $organisationId,
  245.                     $perid,
  246.                     $sellerId,
  247.                     $departement
  248.                 )[0]['total_ventes_ko'] ?? 0;
  249.                 $totalObjectif += (int)($productionRepository->getProductionsAnalyticsObjectifs(
  250.                     $pointOfSale,
  251.                     $codeCluster,
  252.                     $mois,
  253.                     $annee,
  254.                     $optionSelect,
  255.                     $etatKO,
  256.                     $category,
  257.                     $childs,
  258.                     $organisationId,
  259.                     $departement
  260.                 )[0]['total_objectif'] ?? 0);
  261.                 $projection += (int)$productionRepository->getProductionsAnalyticsProjection(
  262.                     $pointOfSale,
  263.                     $codeCluster,
  264.                     $codeInsee,
  265.                     $mois,
  266.                     $annee,
  267.                     $optionSelect,
  268.                     $etatKO,
  269.                     $category,
  270.                     $childs,
  271.                     $organisationId,
  272.                     $perid,
  273.                     $sellerId,
  274.                     $departement
  275.                 )['projection_ventes'] ?? 0;
  276.                 $moyenneJournaliere += (float)$productionRepository->getProductionsAnalyticsProjection(
  277.                     $pointOfSale,
  278.                     $codeCluster,
  279.                     $codeInsee,
  280.                     $mois,
  281.                     $annee,
  282.                     $optionSelect,
  283.                     $etatKO,
  284.                     $category,
  285.                     $childs,
  286.                     $organisationId,
  287.                     $perid,
  288.                     $sellerId,
  289.                     $departement
  290.                 )['ventes_par_jour'] ?? 0;
  291.                 $jours_restants += (float)$productionRepository->getProductionsAnalyticsProjection(
  292.                     $pointOfSale,
  293.                     $codeCluster,
  294.                     $codeInsee,
  295.                     $mois,
  296.                     $annee,
  297.                     $optionSelect,
  298.                     $etatKO,
  299.                     $category,
  300.                     $childs,
  301.                     $organisationId,
  302.                     $perid,
  303.                     $sellerId,
  304.                     $departement
  305.                 )['jours_restants'] ?? 0;
  306.                 $clients4P += (int)$productionRepository->getProductionsAnalyticsTotal4P(
  307.                     $pointOfSale,
  308.                     $codeCluster,
  309.                     $codeInsee,
  310.                     $mois,
  311.                     $annee,
  312.                     $optionSelect,
  313.                     $etatKO,
  314.                     "",
  315.                     $childs,
  316.                     $organisationId,
  317.                     $perid,
  318.                     $sellerId,
  319.                     $departement
  320.                 )['total_vente'] ?? 0;
  321.                 $clients4PC += (int)$productionRepository->getProductionsAnalyticsTitulaireVentes(
  322.                     $pointOfSale,
  323.                     $codeCluster,
  324.                     $codeInsee,
  325.                     $mois,
  326.                     $annee,
  327.                     $optionSelect,
  328.                     $etatKO,
  329.                     null,
  330.                     "chainage",
  331.                     false,
  332.                     $childs,
  333.                     $organisationId,
  334.                     $perid,
  335.                     $sellerId,
  336.                     $departement
  337.                 )[0]['nombre_titulaire_email'] ?? 0;
  338.                 $j30 += (int)$productionRepository->getProductionsAnalyticsTotalVentesByDateResiliationInf30(
  339.                     $pointOfSale,
  340.                     $codeCluster,
  341.                     $codeInsee,
  342.                     $mois,
  343.                     $annee,
  344.                     $optionSelect,
  345.                     $etatKO,
  346.                     $category,
  347.                     $childs,
  348.                     $organisationId,
  349.                     $perid,
  350.                     $sellerId,
  351.                     $departement
  352.                 )['total_vente'] ?? 0;
  353.                 $j30_raccorde_fixe += (int)$productionRepository->getProductionsAnalyticsTotalVentesByDateResiliationInf30(
  354.                     $pointOfSale,
  355.                     $codeCluster,
  356.                     $codeInsee,
  357.                     $mois,
  358.                     $annee,
  359.                     "B",
  360.                     $etatKO,
  361.                     "1,3",
  362.                     $childs,
  363.                     $organisationId,
  364.                     $perid,
  365.                     $sellerId,
  366.                     $departement
  367.                 )['total_vente'] ?? 0;
  368.                 $j30_raccorde_fixe_conquete += (int)$productionRepository->getProductionsAnalyticsTotalVentesByDateResiliationInf30ForChurn(
  369.                     $pointOfSale,
  370.                     $codeCluster,
  371.                     $codeInsee,
  372.                     $mois,
  373.                     $annee,
  374.                     "B",
  375.                     $etatKO,
  376.                     "1,3",
  377.                     $childs,
  378.                     $organisationId,
  379.                     $perid,
  380.                     $sellerId,
  381.                     $departement
  382.                 )['total_vente'] ?? 0;
  383.                 $j30_mobile += (int)$productionRepository->getProductionsAnalyticsTotalVentesByDateResiliationInf30Mobile(
  384.                     $pointOfSale,
  385.                     $codeCluster,
  386.                     $codeInsee,
  387.                     $mois,
  388.                     $annee,
  389.                     "B",
  390.                     $etatKO,
  391.                     "31,32,33",
  392.                     $childs,
  393.                     $organisationId,
  394.                     $perid,
  395.                     $sellerId,
  396.                     $departement
  397.                 )['total_vente'] ?? 0;
  398.                 $j30_raccorde_mobile += (int)$productionRepository->getProductionsAnalyticsTotalVentesByDateResiliationInf30Mobile(
  399.                     $pointOfSale,
  400.                     $codeCluster,
  401.                     $codeInsee,
  402.                     $mois,
  403.                     $annee,
  404.                     "B",
  405.                     "Raccorde_mobile",
  406.                     "31,32,33,48",
  407.                     $childs,
  408.                     $organisationId,
  409.                     $perid,
  410.                     $sellerId,
  411.                     $departement
  412.                 )['total_vente'] ?? 0;
  413.                 $titulaire_mobile += (int)$productionRepository->getProductionsAnalyticsTotalMobileV2(
  414.                     $pointOfSale,
  415.                     $codeCluster,
  416.                     $codeInsee,
  417.                     $mois,
  418.                     $annee,
  419.                     $optionSelect,
  420.                     $etatKO,
  421.                     "",
  422.                     $childs,
  423.                     $organisationId,
  424.                     $perid,
  425.                     $sellerId,
  426.                     $departement
  427.                 )['total_vente'] ?? 0;
  428.                 $titulaire_mobile_chainage += (int)$productionRepository->getProductionsAnalyticsTotalMobileChainage(
  429.                     $pointOfSale,
  430.                     $codeCluster,
  431.                     $codeInsee,
  432.                     $mois,
  433.                     $annee,
  434.                     $optionSelect,
  435.                     $etatKO,
  436.                     "chainage",
  437.                     $childs,
  438.                     $organisationId,
  439.                     $perid,
  440.                     $sellerId,
  441.                     $departement
  442.                 )['total_vente'] ?? 0;
  443.                 $clients_hors_mig += (int)$productionRepository->getProductionsAnalyticsTotalClientsHosting(
  444.                     $pointOfSale,
  445.                     $codeCluster,
  446.                     $codeInsee,
  447.                     $mois,
  448.                     $annee,
  449.                     $optionSelect,
  450.                     "",
  451.                     $childs,
  452.                     $organisationId,
  453.                     $perid,
  454.                     $sellerId,
  455.                     $departement
  456.                 )['total_vente'] ?? 0;
  457.                 $mrz[] = $productionRepository->getProductionsAnalyticsTotalByIdentityCtrl(
  458.                     $pointOfSale,
  459.                     $codeCluster,
  460.                     $codeInsee,
  461.                     $mois,
  462.                     $annee,
  463.                     $optionSelect,
  464.                     "",
  465.                     $childs,
  466.                     $organisationId,
  467.                     $perid,
  468.                     $sellerId,
  469.                     $departement
  470.                 );
  471.                 $total_clients_unique += (int)$productionRepository->getProductionsAnalyticsTotalClientsUnique(
  472.                     $pointOfSale,
  473.                     $codeCluster,
  474.                     $codeInsee,
  475.                     $mois,
  476.                     $annee,
  477.                     $optionSelect,
  478.                     $etatKO,
  479.                     $category,
  480.                     "",
  481.                     $childs,
  482.                     $organisationId,
  483.                     $perid,
  484.                     $sellerId,
  485.                     $departement
  486.                 )[0]['total_client_unique'] ?? 0;
  487.                 $clients_4PC_par_semaine[] = $productionRepository->get4PCByWeek(
  488.                     $pointOfSale,
  489.                     $codeCluster,
  490.                     $codeInsee,
  491.                     $mois,
  492.                     $annee,
  493.                     $optionSelect,
  494.                     $etatKO,
  495.                     "31,32,33",
  496.                     "chainage",
  497.                     true,
  498.                     $childs,
  499.                     $organisationId,
  500.                     $perid,
  501.                     $sellerId,
  502.                     $departement
  503.                 );
  504.                 $clients_4P_par_semaine[] = $productionRepository->get4PByWeek(
  505.                     $pointOfSale,
  506.                     $codeCluster,
  507.                     $codeInsee,
  508.                     $mois,
  509.                     $annee,
  510.                     $optionSelect,
  511.                     $etatKO,
  512.                     "",
  513.                     $childs,
  514.                     $organisationId,
  515.                     $perid,
  516.                     $sellerId,
  517.                     $departement
  518.                 );
  519.                 $rio += (int)$productionRepository->getProductionsAnalyticsTotalVenteByOption(
  520.                     $pointOfSale,
  521.                     $codeCluster,
  522.                     $codeInsee,
  523.                     $mois,
  524.                     $annee,
  525.                     $childs,
  526.                     $organisationId,
  527.                     "RIO",
  528.                     $perid,
  529.                     $sellerId,
  530.                     $departement
  531.                 )['total_vente'] ?? 0;
  532.                 $pto_non_saisie += (int)$productionRepository->getProductionsAnalyticsTotalVenteByOption(
  533.                     $pointOfSale,
  534.                     $codeCluster,
  535.                     $codeInsee,
  536.                     $mois,
  537.                     $annee,
  538.                     $childs,
  539.                     $organisationId,
  540.                     "PTO_NON_SAISIE",
  541.                     $perid,
  542.                     $sellerId,
  543.                     $departement
  544.                 )['total_vente'] ?? 0;
  545.                 $pto_saisie += (int)$productionRepository->getProductionsAnalyticsTotalVenteByOption(
  546.                     $pointOfSale,
  547.                     $codeCluster,
  548.                     $codeInsee,
  549.                     $mois,
  550.                     $annee,
  551.                     $childs,
  552.                     $organisationId,
  553.                     "PTO_SAISIE",
  554.                     $perid,
  555.                     $sellerId,
  556.                     $departement
  557.                 )['total_vente'] ?? 0;
  558.                 $pto_non_existante += (int)$productionRepository->getProductionsAnalyticsTotalVenteByOption(
  559.                     $pointOfSale,
  560.                     $codeCluster,
  561.                     $codeInsee,
  562.                     $mois,
  563.                     $annee,
  564.                     $childs,
  565.                     $organisationId,
  566.                     "PTO_NON_EXISTANTE",
  567.                     $perid,
  568.                     $sellerId,
  569.                     $departement
  570.                 )['total_vente'] ?? 0;
  571.                 $pto_existante += (int)$productionRepository->getProductionsAnalyticsTotalVenteByOption(
  572.                     $pointOfSale,
  573.                     $codeCluster,
  574.                     $codeInsee,
  575.                     $mois,
  576.                     $annee,
  577.                     $childs,
  578.                     $organisationId,
  579.                     "PTO_EXISTANTE",
  580.                     $perid,
  581.                     $sellerId,
  582.                     $departement
  583.                 )['total_vente'] ?? 0;
  584.                 $total_vente_vla_conquette += $productionRepository->getProductionsAnalyticsVentesVlaConquete(
  585.                     $pointOfSale,
  586.                     $codeCluster,
  587.                     $codeInsee,
  588.                     $mois,
  589.                     $annee,
  590.                     "B",
  591.                     "1,3",
  592.                     $childs,
  593.                     $organisationId,
  594.                     $perid,
  595.                     $sellerId,
  596.                     $departement
  597.                 )[0]['total_ventes'] ?? 0;
  598.                 $total_churn_fixe 0;
  599.                 $total_churn_mobile 0;
  600.                 $total_rio 0;
  601.                 $total_pto_saisie 0;
  602.                 $total_pto_non_saisie 0;
  603.                 $total_pto_non_existante 0;
  604.                 $total_potentiel 0;
  605.                 $total_pto_existante 0;
  606.                 if ($total_ventes_raccordes_fixe_conquete && $j30_raccorde_fixe_conquete 0) {
  607.                     $ratio_fixe = ($j30_raccorde_fixe_conquete $total_ventes_raccordes_fixe_conquete) * 100;
  608.                     $total_churn_fixe number_format($ratio_fixe1);
  609.                 }
  610.                 if ($total_ventes_raccordes_mobile && $j30_raccorde_mobile 0) {
  611.                     $ratio_mobile = ($j30_raccorde_mobile $total_ventes_raccordes_mobile) * 100;
  612.                     $total_churn_mobile number_format($ratio_mobile1);
  613.                 }
  614.                 if ($total_vente_vla_conquette && $rio 0) {
  615.                     $ratio_rio = ($rio $total_vente_vla_conquette) * 100;
  616.                     $total_rio round($ratio_rio2);
  617.                 }
  618.                 if ($total_vente_vla_conquette && $pto_saisie 0) {
  619.                     $ratio_pto_saisie = ($pto_saisie $total_vente_vla_conquette) * 100;
  620.                     $total_pto_saisie round($ratio_pto_saisie2);
  621.                 }
  622.                 if ($total_vente_vla_conquette && $pto_non_saisie 0) {
  623.                     $ratio_pto_non_saisie = ($pto_non_saisie $total_vente_vla_conquette) * 100;
  624.                     $total_pto_non_saisie round($ratio_pto_non_saisie2);
  625.                 }
  626.                 if ($total_vente_vla_conquette && $pto_non_existante 0) {
  627.                     $ratio_pto_non_existante = ($pto_non_existante $total_vente_vla_conquette) * 100;
  628.                     $total_pto_non_existante round($ratio_pto_non_existante2);
  629.                 }
  630.                 if ($pto_saisie && $pto_existante 0) {
  631.                     $ratio_potentiel = ($pto_saisie $pto_existante) * 100;
  632.                     $total_potentiel round($ratio_potentiel2);
  633.                 }
  634.                 if ($total_vente_vla_conquette && $pto_existante 0) {
  635.                     $ratio_pto_existante = ($pto_existante $total_vente_vla_conquette) * 100;
  636.                     $total_pto_existante round($ratio_pto_existante2);
  637.                 }
  638.             }
  639.             $nbPos count($pointsOfSale);
  640.             $response[$mois] = [
  641.                 'total_ventes' => $totalVentes,
  642.                 'note_satisfaction' => round($nbPos $totalSatisfaction $nbPos 0.02),
  643.                 'nombre_vendeurs' => $nombreVendeurs,
  644.                 'etp' => $etp,
  645.                 'total_ventes_ko' => $totalVentesKO,
  646.                 'total_objectif' => $totalObjectif,
  647.                 'projection' => $projection,
  648.                 'moyenne_journalliere' => round($moyenneJournaliere2),
  649.                 'jours_restants' => $jours_restants,
  650.                 'clients4P' => $clients4P,
  651.                 'clients4PC' => $clients4PC,
  652.                 'j+30' => $j30,
  653.                 'j+30_mobile' => $j30_mobile,
  654.                 'nombre_titulaire_email_mobile' => $titulaire_mobile,
  655.                 'nombre_titulaire_email_mobile_chainage' => $titulaire_mobile_chainage,
  656.                 'clients_hors_mig' => $clients_hors_mig,
  657.                 'mrz' => $this->fixMrzTotals($mrz),
  658.                 'total_client_unique' => $total_clients_unique,
  659.                 'j30_raccorde_fixe' => $j30_raccorde_fixe,
  660.                 'j30_raccorde_mobile' => $j30_raccorde_mobile,
  661.                 'total_ventes_raccordes_fixe' => $total_ventes_raccordes_fixe,
  662.                 'total_ventes_raccordes_mobile' => $total_ventes_raccordes_mobile,
  663.                 'clients_churn_fixe' => $total_churn_fixe,
  664.                 'clients_churn_mobile' => $total_churn_mobile,
  665.                 'clients_4PC_par_semaine' => $this->fixTaux4PCParSemaine($clients_4PC_par_semaine) ?? [],
  666.                 'clients_4P_par_semaine' => $this->fixTaux4PCParSemaine($clients_4P_par_semaine) ?? [],
  667.                 'RIO' => $total_rio "%",
  668.                 'Potentiel' => $total_potentiel "%",
  669.                 'PTO_saisie' => $total_pto_saisie "%",
  670.                 'PTO_non_saisie' => $total_pto_non_saisie "%",
  671.                 'PTO_sans' => $total_pto_non_existante "%",
  672.                 'PTO_existante' => $total_pto_existante "%",
  673.                 'total_ventes_box_5G' => $total_ventes_box_5G
  674.             ];
  675.         }
  676.         return new JsonResponse($nbrMonth $response $response[$baseMonth], 200);
  677.     }
  678.     /**
  679.      * @Route("/api/productions_details_canceled", name="api_get_productions_details_canceled", methods={"GET"})
  680.      */
  681.     public function getProductionsDetailsResilies(
  682.         Request $request,
  683.         EtatProductionRepository $etatProductionRepository,
  684.         ProductionRepository $productionRepository,
  685.         PointOfSaleRepository $pointOfSaleRepository,
  686.         SatisfactionClientRepository $satisfactionClientRepository
  687.     ) {
  688.         $pointOfSale null;
  689.         $pointOfSaleId $request->query->get('pointOfSaleId'null);
  690.         if ($pointOfSaleId) {
  691.             $pointOfSale $pointOfSaleRepository->findOneBy(["id" => $pointOfSaleId]);
  692.         }
  693.         $codeCluster $request->query->get('codeCluster'null);
  694.         // Récupérer les paramètres mois et année
  695.         $currentYear = (int) date('Y');
  696.         $currentMonth = (int) date('m');
  697.         $mois $request->query->get('month'$currentMonth);
  698.         $annee $request->query->get('year'$currentYear);
  699.         $page $request->query->get('page'1);
  700.         $optionSelect $request->query->get('optionSelect''V');
  701.         return $this->json($productionRepository->getProductionsReselies($pointOfSale$codeCluster$mois$annee$optionSelect$page) ?? []);
  702.     }
  703.     /**
  704.      * @Route("/api/productions_details_canceled_mobile", name="api_get_productions_details_canceled_mobile", methods={"GET"})
  705.      */
  706.     public function getProductionsDetailsResiliesMobile(
  707.         Request $request,
  708.         EtatProductionRepository $etatProductionRepository,
  709.         ProductionRepository $productionRepository,
  710.         PointOfSaleRepository $pointOfSaleRepository,
  711.         SatisfactionClientRepository $satisfactionClientRepository
  712.     ) {
  713.         $pointOfSale null;
  714.         $pointOfSaleId $request->query->get('pointOfSaleId'null);
  715.         if ($pointOfSaleId) {
  716.             $pointOfSale $pointOfSaleRepository->findOneBy(["id" => $pointOfSaleId]);
  717.         }
  718.         $codeCluster $request->query->get('codeCluster'null);
  719.         // Récupérer les paramètres mois et année
  720.         $currentYear = (int) date('Y');
  721.         $currentMonth = (int) date('m');
  722.         $mois $request->query->get('month'$currentMonth);
  723.         $annee $request->query->get('year'$currentYear);
  724.         $page $request->query->get('page'1);
  725.         $optionSelect $request->query->get('optionSelect''V');
  726.         return $this->json($productionRepository->getProductionsReseliesMobile($pointOfSale$codeCluster$mois$annee$optionSelect$page) ?? []);
  727.     }
  728.     /**
  729.      * @Route("/api/productions_details_mrz/{pointOfSaleId}", name="api_get_productions_details_mrz", methods={"GET"})
  730.      */
  731.     public function getProductionsDetailsByIdentityCtrl(
  732.         $pointOfSaleId,
  733.         Request $request,
  734.         EtatProductionRepository $etatProductionRepository,
  735.         ProductionRepository $productionRepository,
  736.         PointOfSaleRepository $pointOfSaleRepository,
  737.         SatisfactionClientRepository $satisfactionClientRepository
  738.     ) {
  739.         $pointOfSale $pointOfSaleRepository->findOneBy(["id" => $pointOfSaleId]);
  740.         if ($pointOfSale == null) {
  741.             throw new BadRequestHttpException('Le point de vente avec cet ID n\'existe pas.');
  742.         }
  743.         $codeCluster $request->query->get('codeCluster'null);
  744.         $codeInsee $request->query->get('codeInsee'null);
  745.         // Récupérer les paramètres mois et année
  746.         $currentYear = (int) date('Y');
  747.         $currentMonth = (int) date('m');
  748.         $mois $request->query->get('month'$currentMonth);
  749.         $annee $request->query->get('year'$currentYear);
  750.         $identityCtrl $request->query->get('identityCtrl'null);
  751.         $page $request->query->get('page'1);
  752.         $optionSelect $request->query->get('optionSelect''V');
  753.         return $this->json($productionRepository->getProductionsDetailsByIdentityCtrl($pointOfSale$codeCluster$codeInsee$mois$annee$optionSelect$identityCtrl$page) ?? []);
  754.     }
  755.     public function fixTaux4PcParSemaine($clients_4PC_par_semaine)
  756.     {
  757.         $toclientsParSemaine = [];
  758.         foreach ($clients_4PC_par_semaine as $source) {
  759.             foreach ($source as $item) {
  760.                 if (!isset($item['semaine']) || !isset($item['total'])) {
  761.                     // On ignore les éléments incomplets
  762.                     continue;
  763.                 }
  764.                 $semaine $item['semaine'];
  765.                 $total = (int) $item['total'];
  766.                 if (!isset($toclientsParSemaine[$semaine])) {
  767.                     $toclientsParSemaine[$semaine] = 0;
  768.                 }
  769.                 $toclientsParSemaine[$semaine] += $total;
  770.             }
  771.         }
  772.         $resultat = [];
  773.         foreach ($toclientsParSemaine as $semaine => $total) {
  774.             $resultat[] = [
  775.                 'semaine' => $semaine,
  776.                 'total' => $total
  777.             ];
  778.         }
  779.         // Tri par ordre croissant de semaine (au cas où)
  780.         usort($resultat, fn($a$b) => $a['semaine'] <=> $b['semaine']);
  781.         return $resultat;
  782.     }
  783.     public function fixMrzTotals(array $mrz): array
  784.     {
  785.         $toclientsParType = [];
  786.         foreach ($mrz as $groupe) {
  787.             foreach ($groupe as $item) {
  788.                 if (!isset($item['identity_ctrl']) || !isset($item['total_vente'])) {
  789.                     continue;
  790.                 }
  791.                 $type $item['identity_ctrl'];
  792.                 $vente = (int) $item['total_vente'];
  793.                 if (!isset($toclientsParType[$type])) {
  794.                     $toclientsParType[$type] = 0;
  795.                 }
  796.                 $toclientsParType[$type] += $vente;
  797.             }
  798.         }
  799.         $resultat = [];
  800.         foreach ($toclientsParType as $type => $total) {
  801.             $resultat[] = [
  802.                 'identity_ctrl' => $type,
  803.                 'total_vente' => $total
  804.             ];
  805.         }
  806.         return $resultat;
  807.     }
  808.     public function getAnalyticsByClusters(
  809.         Request $request,
  810.         ProductionRepository $productionRepository,
  811.         PointOfSaleRepository $pointOfSaleRepository,
  812.         EntityManagerInterface $entityManager,
  813.         HierarchyService $hierarchyService,
  814.         EtatProductionRepository $etatProductionRepository,
  815.         SatisfactionClientRepository $satisfactionClientRepository
  816.     ) {
  817.         // -----------------------------------------
  818.         // 🔹 Paramètres
  819.         // -----------------------------------------
  820.         $pointOfSaleId $request->query->get('pointOfSaleId');
  821.         $organisationId $request->query->get('organisationId');
  822.         $pointOfSale null;
  823.         if ($pointOfSaleId) {
  824.             $pointOfSale $pointOfSaleRepository->find($pointOfSaleId);
  825.             if (!$pointOfSale) {
  826.                 throw new BadRequestHttpException("Le point de vente avec cet ID n'existe pas.");
  827.             }
  828.             $organisationId null// Ignorer organisation si point de vente défini
  829.         }
  830.         $codeCluster $request->query->get('codeCluster');
  831.         $codeInsee $request->query->get('codeInsee');
  832.         $departement $request->query->get('departement');
  833.         $mois = (int)($request->query->get('month') ?? date('m'));
  834.         $annee = (int)($request->query->get('year') ?? date('Y'));
  835.         $perid $request->query->get('perid');
  836.         $sellerId $request->query->get('sellerId');
  837.         $category $request->query->get('categoryId');
  838.         $optionSelect $request->query->get('optionSelect''V');
  839.         $etatKO $etatProductionRepository->findOneBy(["nom" => 'Racco KO']);
  840.         // -----------------------------------------
  841.         // 👥 Gestion hiérarchie
  842.         // -----------------------------------------
  843.         $childs = [];
  844.         if ($idUser $request->query->get('idUser')) {
  845.             $user $entityManager->getRepository(User::class)->find((int)$idUser);
  846.             if ($user && (in_array('ROLE_MANAGER'$user->getRoles()) || in_array('ROLE_DIRECTOR'$user->getRoles()))) {
  847.                 $childs array_map(fn($u) => (int)$u['id'], $hierarchyService->getHierarchyDescendante($user->getId()));
  848.             }
  849.         }
  850.         // -----------------------------------------
  851.         // 📊 Récupération des données
  852.         // -----------------------------------------
  853.         $ventesData $productionRepository->getProductionsAnalyticsVentesOptimized(
  854.             $pointOfSale,
  855.             $codeCluster,
  856.             $codeInsee,
  857.             $mois,
  858.             $annee,
  859.             $optionSelect,
  860.             $category,
  861.             $etatKO,
  862.             $childs,
  863.             $organisationId,
  864.             $perid,
  865.             $sellerId,
  866.             $departement
  867.         ); 
  868.        
  869.         $ventesConqVlaData $productionRepository->getTotalVenteCnqVla(
  870.             $pointOfSale,
  871.             $codeCluster,
  872.             $codeInsee,
  873.             $mois,
  874.             $annee,
  875.             "B",
  876.             $childs,
  877.             $organisationId,
  878.             $perid,
  879.             $sellerId,
  880.             $departement
  881.         );
  882.         $objectifsData $productionRepository->getProductionsAnalyticsObjectifsOptimized(
  883.             $pointOfSale,
  884.             $codeCluster,
  885.             $mois,
  886.             $annee,
  887.             $optionSelect,
  888.             null,
  889.             $category,
  890.             $childs,
  891.             $organisationId,
  892.             $departement
  893.         );
  894.         $mrzData $productionRepository->getMrzList(
  895.             $pointOfSale,
  896.             $codeCluster,
  897.             $codeInsee,
  898.             $mois,
  899.             $annee,
  900.             $optionSelect,
  901.             $childs,
  902.             $organisationId,
  903.             $perid,
  904.             $sellerId,
  905.             $departement
  906.         );
  907.         // $fourPData = $productionRepository->get4P(
  908.         //     $pointOfSale,
  909.         //     $codeCluster,
  910.         //     $codeInsee,
  911.         //     $mois,
  912.         //     $annee,
  913.         //     $childs,
  914.         //     $organisationId,
  915.         //     $perid,
  916.         //     $sellerId,
  917.         //     $departement
  918.         // );
  919.         $fourPCData $productionRepository->get4PC(
  920.             $pointOfSale,
  921.             $codeCluster,
  922.             $codeInsee,
  923.             $mois,
  924.             $annee,
  925.             $childs,
  926.             $organisationId,
  927.             $perid,
  928.             $sellerId,
  929.             $departement
  930.         );
  931.         $j30Data $productionRepository->getJ30(
  932.             $pointOfSale,
  933.             $codeCluster,
  934.             $codeInsee,
  935.             $mois,
  936.             $annee,
  937.             $childs,
  938.             $organisationId,
  939.             $perid,
  940.             $sellerId,
  941.             $departement
  942.         );
  943.         $ptoData $productionRepository->getPto(
  944.             $pointOfSale,
  945.             $codeCluster,
  946.             $codeInsee,
  947.             $mois,
  948.             $annee,
  949.             $childs,
  950.             $organisationId,
  951.             $perid,
  952.             $sellerId,
  953.             $departement
  954.         );
  955.         // Appel à la fonction de projection
  956.         $projection $productionRepository->getProjection(
  957.             $pointOfSale,
  958.             $codeCluster,
  959.             $codeInsee,
  960.             $mois,
  961.             $annee,
  962.             $optionSelect,
  963.             $etatKO,
  964.             $category,
  965.             $childs,
  966.             $organisationId,
  967.             $perid,
  968.             $sellerId,
  969.             $departement
  970.         );
  971.         // -----------------------------------------
  972.         // 📊 Satisfaction client par cluster
  973.         // -----------------------------------------
  974.         $satisfactionMap $satisfactionClientRepository->getSatisfaction(
  975.             $pointOfSale,
  976.             $codeCluster,
  977.             $codeInsee,
  978.             $mois,
  979.             $annee,
  980.             $category,
  981.             $childs,
  982.             $organisationId,
  983.             $perid,
  984.             $sellerId,
  985.             $departement
  986.         );
  987.         // -----------------------------------------
  988.         // 📊 Création des maps pour accès rapide
  989.         // -----------------------------------------
  990.         $objectifsMap = [];
  991.         foreach ($objectifsData as $obj) {
  992.             $key $obj['codeCluster'] ?? null;
  993.             if ($key$objectifsMap[$key] = (float)($obj['total_objectif'] ?? 0);
  994.         }
  995.         $mrzMap = [];
  996.         foreach ($mrzData as $obj) {
  997.             $cluster $obj['codeCluster'] ?? null;
  998.             $identity $obj['identity_ctrl'] ?? 'INCONNU';
  999.             $ventes = (float)($obj['total_ventes'] ?? 0);
  1000.             if (!$cluster) continue;
  1001.             if (!isset($mrzMap[$cluster])) $mrzMap[$cluster] = [];
  1002.             if (!isset($mrzMap[$cluster][$identity])) {
  1003.                 $mrzMap[$cluster][$identity] = ['identity_ctrl' => $identity'total_ventes' => 0];
  1004.             }
  1005.             $mrzMap[$cluster][$identity]['total_ventes'] += $ventes;
  1006.         }
  1007.         foreach ($mrzMap as $cluster => $entries$mrzMap[$cluster] = array_values($entries);
  1008.         // $fourPMap = [];
  1009.         // foreach ($fourPData as $f) {
  1010.         //     $key = $f['departement'] ?? null;
  1011.         //     if ($key) $fourPMap[$key] = (float)($f['total_vente'] ?? 0);
  1012.         // }
  1013.         $fourPCMap = [];
  1014.         foreach ($fourPCData as $f) {
  1015.             $key $f['codeCluster'] ?? null;
  1016.             if ($key$fourPCMap[$key] = (float)($f['nombre_titulaire_email'] ?? 0);
  1017.         }
  1018.         $j30Map = [];
  1019.         foreach ($j30Data as $row) {
  1020.             $key $row['codeCluster'] ?? null;
  1021.             if ($key) {
  1022.                 $j30Map[$key] = [
  1023.                     'j30' => (int)($row['total_vente'] ?? 0),
  1024.                     'j30_raccorde_fixe' => (int)($row['total_vente_fixe_raccorde'] ?? 0),
  1025.                     'j30_mobile' => (int)($row['total_vente_mobile'] ?? 0),
  1026.                     'j30_raccorde_mobile' => (int)($row['total_vente_mobile_raccorde'] ?? 0),
  1027.                 ];
  1028.             }
  1029.         }
  1030.         $ventesConqVlaMap = [];
  1031.         foreach ($ventesConqVlaData as $f) {
  1032.             $key $f['codeCluster'] ?? null;
  1033.             if ($key$ventesConqVlaMap[$key] = (int)($f['total_ventes_conq_vla'] ?? 0);
  1034.         }
  1035.         $ptoMap = [];
  1036.         foreach ($ptoData as $ptoRow) {
  1037.             $cluster $ptoRow['codeCluster'] ?? null;
  1038.             if ($cluster) {
  1039.                 $ptoMap[$cluster] = [
  1040.                     'rio' => (int)($ptoRow['total_rio'] ?? 0),
  1041.                     'pto_saisie' => (int)($ptoRow['total_pto_saisie'] ?? 0),
  1042.                     'pto_non_saisie' => (int)($ptoRow['total_pto_non_saisie'] ?? 0),
  1043.                     'pto_existante' => (int)($ptoRow['total_pto_existante'] ?? 0),
  1044.                     'pto_non_existante' => (int)($ptoRow['total_pto_non_existante'] ?? 0),
  1045.                 ];
  1046.             }
  1047.         }
  1048.         // -----------------------------------------
  1049.         // 📈 Calcul des taux + enrichissement
  1050.         // -----------------------------------------
  1051.         foreach ($ventesData as &$row) {
  1052.             $key $row['codeCluster'] ?? null;
  1053.             $key2 $row['departement'] ?? null;
  1054.             $totalObj $objectifsMap[$key] ?? 0;
  1055.             $ventes = (float)($row['total_ventes'] ?? 0);
  1056.             $row['total_objectifs'] = $totalObj;
  1057.             $row['R/O'] = $totalObj round(($ventes $totalObj) * 1002) : 0;
  1058.             $row['taux_ventes_raccordes_fixe'] = $ventes round(($row['total_ventes_raccordes_fixe'] / $ventes) * 1002) : 0;
  1059.             $row['taux_ventes_raccorde_mobile'] = $ventes round(($row['total_ventes_raccorde_mobile'] / $ventes) * 1002) : 0;
  1060.             $row['taux_ventes_box_5G'] = $ventes round(($row['total_ventes_box_5G'] / $ventes) * 1002) : 0;
  1061.             $row['mrz'] = $mrzMap[$key] ?? [];
  1062.             $row['4P'] = 0;
  1063.             $row['4PC'] = $fourPCMap[$key] ?? 0;
  1064.             $row['j30'] = $j30Map[$key]['j30'] ?? 0;
  1065.             $row['j30_raccorde_fixe'] = $j30Map[$key]['j30_raccorde_fixe'] ?? 0;
  1066.             $row['j30_mobile'] = $j30Map[$key]['j30_mobile'] ?? 0;
  1067.             $row['j30_raccorde_mobile'] = $j30Map[$key]['j30_raccorde_mobile'] ?? 0;
  1068.             // Churn
  1069.             $total_ventes_raccordes_fixe $row['total_ventes_raccordes_fixe'] ?? 0;
  1070.             $j30_raccorde_fixe $row['j30_raccorde_fixe'] ?? 0;
  1071.             $row['churn_fixe'] = ($total_ventes_raccordes_fixe && $j30_raccorde_fixe)
  1072.                 ? (float)number_format(($j30_raccorde_fixe $total_ventes_raccordes_fixe) * 1001)
  1073.                 : 0;
  1074.             $total_ventes_raccordes_mobile $row['total_ventes_raccorde_mobile'] ?? 0;
  1075.             $j30_raccorde_mobile $row['j30_raccorde_mobile'] ?? 0;
  1076.             $row['churn_mobile'] = ($total_ventes_raccordes_mobile && $j30_raccorde_mobile)
  1077.                 ? (float)number_format(($j30_raccorde_mobile $total_ventes_raccordes_mobile) * 1001)
  1078.                 : 0;
  1079.             // PTO / RIO
  1080.             $total_vente_vla_conquette $ventesConqVlaMap[$key] ?? 0;
  1081.             $ptoValues $ptoMap[$key] ?? [
  1082.                 'rio' => 0,
  1083.                 'pto_saisie' => 0,
  1084.                 'pto_non_saisie' => 0,
  1085.                 'pto_existante' => 0,
  1086.                 'pto_non_existante' => 0
  1087.             ];
  1088.             $rio $ptoValues['rio'];
  1089.             $pto_saisie $ptoValues['pto_saisie'];
  1090.             $pto_non_saisie $ptoValues['pto_non_saisie'];
  1091.             $pto_existante $ptoValues['pto_existante'];
  1092.             $pto_non_existante $ptoValues['pto_non_existante'];
  1093.             $row['RIO'] = ($total_vente_vla_conquette && $rio) ? round(($rio $total_vente_vla_conquette) * 1002) : 0;
  1094.             $row['PTO_SAISIE'] = ($total_vente_vla_conquette && $pto_saisie) ? round(($pto_saisie $total_vente_vla_conquette) * 1002) : 0;
  1095.             $row['PTO_NON_SAISIE'] = ($total_vente_vla_conquette && $pto_non_saisie) ? round(($pto_non_saisie $total_vente_vla_conquette) * 1002) : 0;
  1096.             $row['PTO_NON_EXISTANTE'] = ($total_vente_vla_conquette && $pto_non_existante) ? round(($pto_non_existante $total_vente_vla_conquette) * 1002) : 0;
  1097.             $row['Potentiel'] = ($pto_saisie && $pto_existante) ? round(($pto_saisie $pto_existante) * 1002) : 0;
  1098.             $row['PTO_EXISTANTE'] = ($total_vente_vla_conquette && $pto_existante) ? round(($pto_existante $total_vente_vla_conquette) * 1002) : 0;
  1099.             $row['satisfaction'] = $satisfactionMap[$key] ?? null;
  1100.             $row['projection'] = $projection[$key];
  1101.         }
  1102.         return $this->json($ventesData200);
  1103.     }
  1104.   
  1105.     
  1106.     /**
  1107.      * @Route("/api/productions-analytics-by-clusters", name="api_get_productions_analytics_by_clusters", methods={"GET"})
  1108.      */
  1109.     public function getAnalyticsByClustersTest(
  1110.         Request $request,
  1111.         ProductionRepository $productionRepository,
  1112.         PointOfSaleRepository $pointOfSaleRepository,
  1113.         EntityManagerInterface $entityManager,
  1114.         HierarchyService $hierarchyService,
  1115.         EtatProductionRepository $etatProductionRepository,
  1116.         SatisfactionClientRepository $satisfactionClientRepository
  1117.     ) {
  1118.         // -----------------------------------------
  1119.         // 🔹 Paramètres
  1120.         // -----------------------------------------
  1121.         $pointOfSaleId $request->query->get('pointOfSaleId');
  1122.         $organisationId $request->query->get('organisationId');
  1123.         $pointOfSale null;
  1124.         if ($pointOfSaleId) {
  1125.             $pointOfSale $pointOfSaleRepository->find($pointOfSaleId);
  1126.             if (!$pointOfSale) {
  1127.                 throw new BadRequestHttpException("Le point de vente avec cet ID n'existe pas.");
  1128.             }
  1129.             $organisationId null// Ignorer organisation si point de vente défini
  1130.         }
  1131.         $codeCluster $request->query->get('codeCluster');
  1132.         $codeInsee $request->query->get('codeInsee');
  1133.         $departement $request->query->get('departement');
  1134.         $mois = (int)($request->query->get('month') ?? date('m'));
  1135.         $annee = (int)($request->query->get('year') ?? date('Y'));
  1136.         $perid $request->query->get('perid');
  1137.         $sellerId $request->query->get('sellerId');
  1138.         $category $request->query->get('categoryId');
  1139.         $optionSelect $request->query->get('optionSelect''V');
  1140.         $etatKO $etatProductionRepository->findOneBy(["nom" => 'Racco KO']);
  1141.         // -----------------------------------------
  1142.         // 👥 Gestion hiérarchie
  1143.         // -----------------------------------------
  1144.         $childs = [];
  1145.         if ($idUser $request->query->get('idUser')) {
  1146.             $user $entityManager->getRepository(User::class)->find((int)$idUser);
  1147.             if ($user && (in_array('ROLE_MANAGER'$user->getRoles()) || in_array('ROLE_DIRECTOR'$user->getRoles()))) {
  1148.                 $childs array_map(fn($u) => (int)$u['id'], $hierarchyService->getHierarchyDescendante($user->getId()));
  1149.             }
  1150.         }
  1151.         // -----------------------------------------
  1152.         // 📊 Récupération des données
  1153.         // -----------------------------------------
  1154.         $ventesData $productionRepository->getProductionsAnalyticsVentesOptimized2(
  1155.             $pointOfSale,
  1156.             $codeCluster,
  1157.             $codeInsee,
  1158.             $mois,
  1159.             $annee,
  1160.             $optionSelect,
  1161.             $category,
  1162.             $etatKO,
  1163.             $childs,
  1164.             $organisationId,
  1165.             $perid,
  1166.             $sellerId,
  1167.             $departement
  1168.         );
  1169.         
  1170.         $ventesMobileData $productionRepository->getProductionsAnalyticsVentesMobileOptimized(
  1171.             $pointOfSale,
  1172.             $codeCluster,
  1173.             $codeInsee,
  1174.             $mois,
  1175.             $annee,
  1176.             "B",
  1177.             $childs,
  1178.             $organisationId,
  1179.             $perid,
  1180.             $sellerId,
  1181.             $departement
  1182.         );
  1183.        
  1184.         $ventesConqVlaData $productionRepository->getTotalVenteCnqVla(
  1185.             $pointOfSale,
  1186.             $codeCluster,
  1187.             $codeInsee,
  1188.             $mois,
  1189.             $annee,
  1190.             "B",
  1191.             $childs,
  1192.             $organisationId,
  1193.             $perid,
  1194.             $sellerId,
  1195.             $departement
  1196.         );
  1197.         $objectifsData $productionRepository->getProductionsAnalyticsObjectifsOptimized(
  1198.             $pointOfSale,
  1199.             $codeCluster,
  1200.             $mois,
  1201.             $annee,
  1202.             $optionSelect,
  1203.             null,
  1204.             $category,
  1205.             $childs,
  1206.             $organisationId,
  1207.             $departement
  1208.         );
  1209.         $mrzData $productionRepository->getMrzList(
  1210.             $pointOfSale,
  1211.             $codeCluster,
  1212.             $codeInsee,
  1213.             $mois,
  1214.             $annee,
  1215.             $optionSelect,
  1216.             $childs,
  1217.             $organisationId,
  1218.             $perid,
  1219.             $sellerId,
  1220.             $departement
  1221.         );
  1222.         $fourPData $productionRepository->get4P(
  1223.             $pointOfSale,
  1224.             $codeCluster,
  1225.             $codeInsee,
  1226.             $mois,
  1227.             $annee,
  1228.             $childs,
  1229.             $organisationId,
  1230.             $perid,
  1231.             $sellerId,
  1232.             $departement
  1233.         );
  1234.         $fourPCData $productionRepository->get4PC(
  1235.             $pointOfSale,
  1236.             $codeCluster,
  1237.             $codeInsee,
  1238.             $mois,
  1239.             $annee,
  1240.             $childs,
  1241.             $organisationId,
  1242.             $perid,
  1243.             $sellerId,
  1244.             $departement
  1245.         );
  1246.         $j30Data $productionRepository->getJ30(
  1247.             $pointOfSale,
  1248.             $codeCluster,
  1249.             $codeInsee,
  1250.             $mois,
  1251.             $annee,
  1252.             $childs,
  1253.             $organisationId,
  1254.             $perid,
  1255.             $sellerId,
  1256.             $departement
  1257.         );
  1258.         $j30MobileData $productionRepository->getJ30Mobile(
  1259.             $pointOfSale,
  1260.             $codeCluster,
  1261.             $codeInsee,
  1262.             $mois,
  1263.             $annee,
  1264.             $childs,
  1265.             $organisationId,
  1266.             $perid,
  1267.             $sellerId,
  1268.             $departement
  1269.         );
  1270.         // dd($ventesMobileData,  $j30MobileData);
  1271.         $ptoData $productionRepository->getPto(
  1272.             $pointOfSale,
  1273.             $codeCluster,
  1274.             $codeInsee,
  1275.             $mois,
  1276.             $annee,
  1277.             $childs,
  1278.             $organisationId,
  1279.             $perid,
  1280.             $sellerId,
  1281.             $departement
  1282.         );
  1283.         // Appel à la fonction de projection
  1284.         $projection $productionRepository->getProjection(
  1285.             $pointOfSale,
  1286.             $codeCluster,
  1287.             $codeInsee,
  1288.             $mois,
  1289.             $annee,
  1290.             $optionSelect,
  1291.             $etatKO,
  1292.             $category,
  1293.             $childs,
  1294.             $organisationId,
  1295.             $perid,
  1296.             $sellerId,
  1297.             $departement
  1298.         );
  1299.         // -----------------------------------------
  1300.         // 📊 Satisfaction client par cluster
  1301.         // -----------------------------------------
  1302.         $satisfactionMap $satisfactionClientRepository->getSatisfaction(
  1303.             $pointOfSale,
  1304.             $codeCluster,
  1305.             $codeInsee,
  1306.             $mois,
  1307.             $annee,
  1308.             $category,
  1309.             $childs,
  1310.             $organisationId,
  1311.             $perid,
  1312.             $sellerId,
  1313.             $departement
  1314.         );
  1315.         // -----------------------------------------
  1316.         // 📊 Création des maps pour accès rapide
  1317.         // -----------------------------------------
  1318.         $ventesMobileMap = [];
  1319.         foreach ($ventesMobileData as $row) {
  1320.             $key $row['departement'] ?? null;
  1321.             if ($key) {
  1322.                 $ventesMobileMap[$key] = [
  1323.                     'total_ventes_box_5G' => (int)($row['total_ventes_box_5G'] ?? 0),
  1324.                     'total_ventes_raccorde_mobile' => (int)($row['total_ventes_raccorde_mobile'] ?? 0),
  1325.                 ];
  1326.             }
  1327.         }
  1328.         $objectifsMap = [];
  1329.         foreach ($objectifsData as $obj) {
  1330.             $key $obj['codeCluster'] ?? null;
  1331.             if ($key$objectifsMap[$key] = (float)($obj['total_objectif'] ?? 0);
  1332.         }
  1333.         $mrzMap = [];
  1334.         foreach ($mrzData as $obj) {
  1335.             $cluster $obj['codeCluster'] ?? null;
  1336.             $identity $obj['identity_ctrl'] ?? 'INCONNU';
  1337.             $ventes = (float)($obj['total_ventes'] ?? 0);
  1338.             if (!$cluster) continue;
  1339.             if (!isset($mrzMap[$cluster])) $mrzMap[$cluster] = [];
  1340.             if (!isset($mrzMap[$cluster][$identity])) {
  1341.                 $mrzMap[$cluster][$identity] = ['identity_ctrl' => $identity'total_ventes' => 0];
  1342.             }
  1343.             $mrzMap[$cluster][$identity]['total_ventes'] += $ventes;
  1344.         }
  1345.         foreach ($mrzMap as $cluster => $entries$mrzMap[$cluster] = array_values($entries);
  1346.         $fourPMap = [];
  1347.         foreach ($fourPData as $f) {
  1348.             $key $f['departement'] ?? null;
  1349.             if ($key$fourPMap[$key] = (float)($f['total_vente'] ?? 0);
  1350.         }
  1351.         $fourPCMap = [];
  1352.         foreach ($fourPCData as $f) {
  1353.             $key $f['departement'] ?? null;
  1354.             if ($key$fourPCMap[$key] = (float)($f['nombre_titulaire_email'] ?? 0);
  1355.         }
  1356.         $j30Map = [];
  1357.         foreach ($j30Data as $row) {
  1358.             $key $row['codeCluster'] ?? null;
  1359.             if ($key) {
  1360.                 $j30Map[$key] = [
  1361.                     'j30' => (int)($row['total_vente'] ?? 0),
  1362.                     'j30_raccorde_fixe' => (int)($row['total_vente_fixe_raccorde'] ?? 0),
  1363.                 ];
  1364.             }
  1365.         }
  1366.         $j30MobileMap = [];
  1367.         foreach ($j30MobileData as $row) {
  1368.             $key $row['departement'] ?? null;
  1369.             if ($key) {
  1370.                 $j30MobileMap[$key] = [
  1371.                     'j30_mobile' => (int)($row['total_vente_mobile'] ?? 0),
  1372.                     'j30_raccorde_mobile' => (int)($row['total_vente_mobile_raccorde'] ?? 0),
  1373.                 ];
  1374.             }
  1375.         }
  1376.       
  1377.         $ventesConqVlaMap = [];
  1378.         foreach ($ventesConqVlaData as $f) {
  1379.             $key $f['codeCluster'] ?? null;
  1380.             if ($key$ventesConqVlaMap[$key] = (int)($f['total_ventes_conq_vla'] ?? 0);
  1381.         }
  1382.         $ptoMap = [];
  1383.         foreach ($ptoData as $ptoRow) {
  1384.             $cluster $ptoRow['codeCluster'] ?? null;
  1385.             if ($cluster) {
  1386.                 $ptoMap[$cluster] = [
  1387.                     'rio' => (int)($ptoRow['total_rio'] ?? 0),
  1388.                     'pto_saisie' => (int)($ptoRow['total_pto_saisie'] ?? 0),
  1389.                     'pto_non_saisie' => (int)($ptoRow['total_pto_non_saisie'] ?? 0),
  1390.                     'pto_existante' => (int)($ptoRow['total_pto_existante'] ?? 0),
  1391.                     'pto_non_existante' => (int)($ptoRow['total_pto_non_existante'] ?? 0),
  1392.                 ];
  1393.             }
  1394.         }
  1395.         // -----------------------------------------
  1396.         // 📈 Calcul des taux + enrichissement
  1397.         // -----------------------------------------
  1398.         foreach ($ventesData as &$row) {
  1399.             $key $row['codeCluster'] ?? null;
  1400.             $key_dep $row['departement'] ?? null;
  1401.             $totalObj $objectifsMap[$key] ?? 0;
  1402.             $ventes = (float)($row['total_ventes'] ?? 0);
  1403.             $row['total_ventes_raccorde_mobile']=$ventesMobileMap[$key_dep]['total_ventes_raccorde_mobile']??0;
  1404.             $row['total_ventes_box_5G']=$ventesMobileMap[$key_dep]['total_ventes_box_5G']??0;
  1405.             $row['total_objectifs'] = $totalObj;
  1406.             $row['R/O'] = $totalObj round(($ventes $totalObj) * 1002) : 0;
  1407.             $row['taux_ventes_raccordes_fixe'] = $ventes round(($row['total_ventes_raccordes_fixe'] / $ventes) * 1002) : 0;
  1408.             $row['mrz'] = $mrzMap[$key] ?? [];
  1409.             $row['4P'] = $fourPMap[$key_dep] ?? 0;
  1410.             $row['4PC'] = $fourPCMap[$key_dep] ?? 0;
  1411.             $row['j30'] = $j30Map[$key]['j30'] ?? 0;
  1412.             $row['j30_raccorde_fixe'] = $j30Map[$key]['j30_raccorde_fixe'] ?? 0;
  1413.             $row['j30_mobile'] = $j30MobileMap[$key_dep]['j30_mobile'] ?? 0;
  1414.             $row['j30_raccorde_mobile'] = $j30MobileMap[$key_dep]['j30_raccorde_mobile'] ?? 0;
  1415.             // Churn
  1416.             $total_ventes_raccordes_fixe $row['total_ventes_raccordes_fixe'] ?? 0;
  1417.             $j30_raccorde_fixe $row['j30_raccorde_fixe'] ?? 0;
  1418.             $row['churn_fixe'] = ($total_ventes_raccordes_fixe && $j30_raccorde_fixe)
  1419.                 ? (float)number_format(($j30_raccorde_fixe $total_ventes_raccordes_fixe) * 1001)
  1420.                 : 0;
  1421.             $total_ventes_raccordes_mobile $row['total_ventes_raccorde_mobile'] ?? 0;
  1422.             $j30_raccorde_mobile $row['j30_raccorde_mobile'] ?? 0;
  1423.             $row['churn_mobile'] = ($total_ventes_raccordes_mobile && $j30_raccorde_mobile)
  1424.                 ? (float)number_format(($j30_raccorde_mobile $total_ventes_raccordes_mobile) * 1001)
  1425.                 : 0;
  1426.             // PTO / RIO
  1427.             $total_vente_vla_conquette $ventesConqVlaMap[$key] ?? 0;
  1428.             $ptoValues $ptoMap[$key] ?? [
  1429.                 'rio' => 0,
  1430.                 'pto_saisie' => 0,
  1431.                 'pto_non_saisie' => 0,
  1432.                 'pto_existante' => 0,
  1433.                 'pto_non_existante' => 0
  1434.             ];
  1435.             $rio $ptoValues['rio'];
  1436.             $pto_saisie $ptoValues['pto_saisie'];
  1437.             $pto_non_saisie $ptoValues['pto_non_saisie'];
  1438.             $pto_existante $ptoValues['pto_existante'];
  1439.             $pto_non_existante $ptoValues['pto_non_existante'];
  1440.             $row['RIO'] = ($total_vente_vla_conquette && $rio) ? round(($rio $total_vente_vla_conquette) * 1002) : 0;
  1441.             $row['PTO_SAISIE'] = ($total_vente_vla_conquette && $pto_saisie) ? round(($pto_saisie $total_vente_vla_conquette) * 1002) : 0;
  1442.             $row['PTO_NON_SAISIE'] = ($total_vente_vla_conquette && $pto_non_saisie) ? round(($pto_non_saisie $total_vente_vla_conquette) * 1002) : 0;
  1443.             $row['PTO_NON_EXISTANTE'] = ($total_vente_vla_conquette && $pto_non_existante) ? round(($pto_non_existante $total_vente_vla_conquette) * 1002) : 0;
  1444.             $row['Potentiel'] = ($pto_saisie && $pto_existante) ? round(($pto_saisie $pto_existante) * 1002) : 0;
  1445.             $row['PTO_EXISTANTE'] = ($total_vente_vla_conquette && $pto_existante) ? round(($pto_existante $total_vente_vla_conquette) * 1002) : 0;
  1446.             // dd($row,$total_vente_vla_conquette,$rio, $row['RIO']);
  1447.             $row['satisfaction'] = $satisfactionMap[$key] ?? null;
  1448.             $row['projection'] = $projection[$key];
  1449.         }
  1450.         return $this->json($ventesData200);
  1451.     }
  1452. }