src/Controller/Admin/DashboardController.php line 483

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Admin;
  3. use App\Entity\Activity;
  4. use App\Repository\ActivityRepository;
  5. use App\Repository\CommentRepository;
  6. use App\Repository\ProduitDeclinationValueRepository;
  7. use App\Repository\ProduitRepository;
  8. use App\Repository\ReclamationRepository;
  9. use App\Repository\SocialConversationRepository;
  10. use App\Repository\UserRepository;
  11. use App\Repository\DocumentRepository;
  12. use Doctrine\ORM\EntityManagerInterface;
  13. use PDO;
  14. use Psr\Log\LoggerInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\HttpFoundation\JsonResponse;
  17. use Symfony\Component\HttpFoundation\Response;
  18. use Symfony\Component\Routing\Annotation\Route;
  19. use App\Service\GlobalVariables;
  20. use App\Entity\User;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Doctrine\DBAL\Types\Types;
  23. use Symfony\Component\ExpressionLanguage\Expression;
  24. use Symfony\Component\Security\Http\Attribute\IsGranted;
  25. #[IsGranted(new Expression("is_granted('ROLE_ADMIN') or is_granted('ROLE_RESELLER')"))]
  26. class DashboardController extends AbstractController {
  27.     private $produitRepository;
  28.     public function __construct(
  29.             ProduitRepository $produitRepository,
  30.             ActivityRepository  $activityRepository,
  31.             CommentRepository $commentRepository,
  32.             UserRepository $userRepository,
  33.             ProduitDeclinationValueRepository $produitDeclinationValueRepository,
  34.             DocumentRepository $documentRepository,
  35.             GlobalVariables $globalVariables
  36.     ) {
  37.         $this->produitRepository $produitRepository;
  38.         $this->activityRepository $activityRepository;
  39.         $this->commentRepository $commentRepository;
  40.         $this->userRepository $userRepository;
  41.         $this->produitDeclinationValueRepository $produitDeclinationValueRepository;
  42.         $this->produitRepository $produitRepository;
  43.         $this->documentRepository $documentRepository;
  44.         $this->globalVariables $globalVariables;
  45.     }
  46.     private function isResellerUser(): bool
  47.     {
  48.         $user $this->getUser();
  49.         return $user instanceof User
  50.             && in_array('ROLE_RESELLER'$user->getRoles(), true)
  51.             && !in_array('ROLE_SUPER_ADMIN'$user->getRoles(), true);
  52.     }
  53.     private function getCurrentResellerUser(): ?User
  54.     {
  55.         $user $this->getUser();
  56.         return $this->isResellerUser() && $user instanceof User $user null;
  57.     }
  58.     private function canAccessReclamations(): bool
  59.     {
  60.         $user $this->getUser();
  61.         if ($user instanceof User && in_array('ROLE_SUPER_ADMIN'$user->getRoles(), true)) {
  62.             return true;
  63.         }
  64.         return $user instanceof User && in_array('RECLAMATION', (array) $user->getArrayRight(), true);
  65.     }
  66.     /**
  67.      * @Route("/index", name="index")
  68.      */
  69.     public function index(EntityManagerInterface $em): Response {
  70.         $user $this->getUser();
  71.         if ($user instanceof User && in_array('ROLE_RESELLER'$user->getRoles(), true) && !in_array('ROLE_SUPER_ADMIN'$user->getRoles(), true)) {
  72.             $kpisToday $this->documentRepository->getDashboardKpisTodayClientOrders($user);
  73.             return $this->render('@admin/dashboard/dashboard.html.twig', [
  74.                 'todayActivities' => [],
  75.                 'weekActivities' => [],
  76.                 'customActivities' => [],
  77.                 'activeTab' => 'today',
  78.                 'lastDayActivities' => [],
  79.                 'logEventsActivities' => [],
  80.                 'log_start' => null,
  81.                 'log_end' => null,
  82.                 'totalVente' => (float) ($kpisToday['totalVenteAvecFrais'] ?? 0),
  83.                 'totalVenteAvecFrais' => (float) ($kpisToday['totalVenteAvecFrais'] ?? 0),
  84.                 'totalVenteSansFrais' => (float) ($kpisToday['totalVenteSansFrais'] ?? 0),
  85.                 'comments' => [],
  86.                 'latestClients' => [],
  87.                 'countProduitDec' => $this->produitDeclinationValueRepository->countProduitDeclinations(nullnullnullnullnull, [], nulltruenullnullnullnullnull),
  88.                 'countProduit' => $this->produitRepository->countProduits(nullnullnullnulltruenull),
  89.                 'countClient' => 0,
  90.                 'nbCommandeJour' => (int) ($kpisToday['nbCommandeJour'] ?? 0),
  91.                 'nbEchangeJour' => (int) ($kpisToday['nbEchangeJour'] ?? 0),
  92.                 'nbUsersConnectes' => 0,
  93.                 'log_user' => 'all',
  94.                 'users' => [],
  95.                 'isResellerView' => true,
  96.             ]);
  97.         }
  98.         $this->denyAccessUnlessGranted('ROLE_ADMIN');
  99.         $now = new \DateTime("now");
  100.         $todayActivities       = [];
  101.         $lastDayActivities     = [];
  102.         $weekActivities        = [];
  103.         $customActivities      = [];
  104.         $logEventsActivities   = [];
  105.         $totalVenteAvecFrais   0.0// somme TTC
  106.         $totalVenteSansFrais   0.0// somme TTC - frais livraison
  107.         $totalVente            0.0;
  108.         $nbCommandeJour        0;
  109.         $nbEchangeJour         0;
  110.         if ($user && in_array("ROLE_SUPER_ADMIN"$user->getRoles())) {
  111.             $todayActivities $this->activityRepository->findByCreatedAtField($now100);
  112.             $kpisToday $this->documentRepository->getDashboardKpisTodayClientOrders();
  113.             $totalVenteAvecFrais = (float) ($kpisToday['totalVenteAvecFrais'] ?? 0);
  114.             $totalVenteSansFrais = (float) ($kpisToday['totalVenteSansFrais'] ?? 0);
  115.             $totalVente          $totalVenteAvecFrais;
  116.             $nbCommandeJour = (int) ($kpisToday['nbCommandeJour'] ?? 0);
  117.             $nbEchangeJour  = (int) ($kpisToday['nbEchangeJour'] ?? 0);
  118.             $lastDayActivities $this->activityRepository->findByCreatedAtField(new \DateTime("-1 day"), 100);
  119.             //$lastDaylogEventsActivities = $this->activityRepository->LoginEvent(new \DateTime("-1 day"), 100);
  120.         } else {
  121.         }
  122.         $comments      $this->commentRepository->findLatestComments(20);
  123.         $latestClients $this->userRepository->findLatestUsers(10'client');
  124.         $countProduitDec $this->produitDeclinationValueRepository->countProduitDeclinations(nullnullnullnullnull, [], nulltruenullnullnullnullnull);
  125.         $countProduit  $this->produitRepository->countProduits(nullnullnullnulltruenull);
  126.         $countClient   $this->userRepository->countUsers(nullnull'client');
  127.         //$nbCommandeJour = $this->documentRepository->countCommandesForToday();
  128.         $nbUsersConnectes $this->activityRepository->countTodayLogins(); // à créer
  129.         $startOfWeek   = (new \DateTime())->modify('monday this week')->setTime(000);
  130.         $endOfWeek     = (new \DateTime())->modify('sunday this week')->setTime(235959);
  131.         $weekActivities $this->activityRepository->findBetweenDates($startOfWeek$endOfWeek);
  132.         $customActivities = [];
  133.         $startStr $_GET['start'] ?? null;
  134.         $endStr   $_GET['end'] ?? null;
  135.         if ($startStr && $endStr) {
  136.             try {
  137.                 $startDate = new \DateTime($startStr);
  138.                 $endDate   = new \DateTime($endStr);
  139.                 $customActivities $this->activityRepository->findBetweenDates($startDate$endDate);
  140.             } catch (\Exception $e) {
  141.                 // Gérer une erreur de date invalide si besoin
  142.             }
  143.         }
  144.         $activeTab 'today'// onglet par défaut
  145.         if ($startStr && $endStr) {
  146.             $activeTab 'custom'// si période personnalisée
  147.         }
  148.         $selectedUserId $_GET['log_user'] ?? 'all';
  149.         if ($selectedUserId !== 'all') {
  150.             $selectedUserId = (int) $selectedUserId;
  151.         }
  152.         $logEventsActivities = [];
  153.         $startLog $_GET['log_start'] ?? (new \DateTime())->modify('monday this week')->format('Y-m-d');
  154.         $endLog   $_GET['log_end']   ?? (new \DateTime())->modify('sunday this week')->format('Y-m-d');
  155.         try {
  156.             $startDate = new \DateTime($startLog);
  157.             $endDate   = new \DateTime($endLog);
  158.             if ($selectedUserId === 'all') {
  159.                 $logEventsActivities $this->activityRepository->LoginEventRange($startDate$endDate);
  160.             } else {
  161.                 $logEventsActivities $this->activityRepository->LoginEventRangeByUser($startDate$endDate$selectedUserId);
  162.             }
  163.         } catch (\Exception $e) {
  164.             $logEventsActivities = [];
  165.         }
  166.         return $this->render('@admin/dashboard/dashboard.html.twig', [
  167.             'todayActivities' => $todayActivities,
  168.             'weekActivities' => $weekActivities,
  169.             'customActivities' => $customActivities,
  170.             'activeTab' => $activeTab,
  171.             'lastDayActivities' => $lastDayActivities,
  172.             'logEventsActivities' => $logEventsActivities ?? null,
  173.             'log_start' => $startLog,
  174.             'log_end' => $endLog,
  175.             //'lastDaylogEventsActivities' => $lastDaylogEventsActivities ?? null,
  176.             // *** sorties totaux
  177.             'totalVente' => $totalVente,                         // legacy (avec frais)
  178.             'totalVenteAvecFrais' => $totalVenteAvecFrais,       // nouveau
  179.             'totalVenteSansFrais' => $totalVenteSansFrais,       // nouveau
  180.             'comments' => $comments,
  181.             'latestClients' => $latestClients,
  182.             'countProduitDec' => $countProduitDec,
  183.             'countProduit' => $countProduit,
  184.             'countClient' => $countClient,
  185.             'nbCommandeJour' => $nbCommandeJour,
  186.             'nbUsersConnectes' => $nbUsersConnectes,
  187.             'log_user' => $selectedUserId,
  188.             'users' => $this->userRepository->findLightUsers(),
  189.             'isResellerView' => false,
  190.         ]);
  191.     }
  192.     /**
  193.      * @Route("/dashboard/activities", name="dashboard_activities_timeline", methods={"GET"})
  194.      * @Route("/admin/dashboard/activities", name="dashboard_activities_timeline_legacy", methods={"GET"})
  195.      */
  196.     public function activitiesTimeline(Request $requestEntityManagerInterface $em): Response
  197.     {
  198.         if ($this->isResellerUser()) {
  199.             return new Response($this->renderView('@admin/dashboard/_activities_timeline.html.twig', [
  200.                 'activities' => [],
  201.             ]), 200, ['Content-Type' => 'text/html; charset=UTF-8']);
  202.         }
  203.         // Accès (même logique que ton écran) : SUPER_ADMIN ou droit STATISTIQUE si dispo.
  204.         $user $this->getUser();
  205.         $can  $user && in_array('ROLE_SUPER_ADMIN', (array)$user->getRoles(), true);
  206.         if (!$can && $user && method_exists($user'getArrayRight')) {
  207.             $can in_array('STATISTIQUE', (array)$user->getArrayRight(), true);
  208.         }
  209.         if (!$can) {
  210.             return new Response('Forbidden'403);
  211.         }
  212.         $tz     = new \DateTimeZone('Africa/Tunis');
  213.         $now    = new \DateTimeImmutable('now'$tz);
  214.         $period = (string) $request->query->get('period''today');
  215.         // défaut : aujourd’hui
  216.         $start $now->setTime(000);
  217.         $end   $now->setTime(235959);
  218.         switch ($period) {
  219.             case '3days':
  220.                 $end   $now->setTime(23,59,59);
  221.                 $start $end->sub(new \DateInterval('P2D'))->setTime(0,0,0);
  222.                 break;
  223.             case '7days':
  224.                 $end   $now->setTime(23,59,59);
  225.                 $start $end->sub(new \DateInterval('P6D'))->setTime(0,0,0);
  226.                 break;
  227.             case '30days':
  228.                 $end   $now->setTime(23,59,59);
  229.                 $start $end->sub(new \DateInterval('P29D'))->setTime(0,0,0);
  230.                 break;
  231.             case 'week':
  232.                 $start = (new \DateTimeImmutable('monday this week'$tz))->setTime(0,0,0);
  233.                 $end   $now->setTime(23,59,59);
  234.                 break;
  235.             case 'last_week':
  236.                 $start = (new \DateTimeImmutable('monday last week'$tz))->setTime(0,0,0);
  237.                 $end   = (new \DateTimeImmutable('sunday last week'$tz))->setTime(23,59,59);
  238.                 break;
  239.             case 'month':
  240.                 $start = (new \DateTimeImmutable('first day of this month'$tz))->setTime(0,0,0);
  241.                 $end   $now->setTime(23,59,59);
  242.                 break;
  243.             case 'last_month':
  244.                 $start = (new \DateTimeImmutable('first day of last month'$tz))->setTime(0,0,0);
  245.                 $end   = (new \DateTimeImmutable('last day of last month'$tz))->setTime(23,59,59);
  246.                 break;
  247.             case 'year':
  248.                 $start = (new \DateTimeImmutable('first day of january'$tz))->setTime(0,0,0);
  249.                 $end   $now->setTime(23,59,59);
  250.                 break;
  251.             case 'last_year':
  252.                 $start = (new \DateTimeImmutable('first day of january last year'$tz))->setTime(0,0,0);
  253.                 $end   = (new \DateTimeImmutable('last day of december last year'$tz))->setTime(23,59,59);
  254.                 break;
  255.             case 'custom': {
  256.                 $s $request->query->get('start');
  257.                 $e $request->query->get('end');
  258.                 if ($s && $e) {
  259.                     try {
  260.                         $start = (new \DateTimeImmutable($s$tz))->setTime(0,0,0);
  261.                         $end   = (new \DateTimeImmutable($e$tz))->setTime(23,59,59);
  262.                         if ($end $start) { [$start$end] = [$end$start]; }
  263.                     } catch (\Throwable $ex) { /* on garde today */ }
  264.                 }
  265.                 break;
  266.             }
  267.             // today => défaut
  268.         }
  269.         // Requête explicite, bornes inclusives, SANS limite cachée
  270.         $qb $em->createQueryBuilder()
  271.             ->select('a','u','p','d')
  272.             ->from(Activity::class, 'a')
  273.             ->leftJoin('a.currentUser''u')
  274.             ->leftJoin('a.produit''p')
  275.             ->leftJoin('a.document''d')
  276.             ->andWhere('a.createdAt >= :start')
  277.             ->andWhere('a.createdAt <= :end')
  278.             ->setParameter('start'\DateTime::createFromImmutable($start))
  279.             ->setParameter('end',   \DateTime::createFromImmutable($end))
  280.             ->orderBy('a.createdAt''DESC');
  281.         $qb->setMaxResults(null); // safety: pas de cap
  282.         $activities $qb->getQuery()->getResult();
  283.         $html $this->renderView('@admin/dashboard/_activities_timeline.html.twig', [
  284.             'activities' => $activities,
  285.         ]);
  286.         return new Response($html200, ['Content-Type' => 'text/html; charset=UTF-8']);
  287.     }
  288.     /**
  289.      * @Route("/dashboard/login-history", name="dashboard_login_history", methods={"GET"})
  290.      * @Route("/admin/dashboard/login-history", name="dashboard_login_history_legacy", methods={"GET"})
  291.      */
  292.     public function loginHistory(Request $request): Response
  293.     {
  294.         if ($this->isResellerUser()) {
  295.             return new Response($this->renderView('@admin/dashboard/_login_events_list.html.twig', [
  296.                 'events' => [],
  297.             ]));
  298.         }
  299.         // Accès : SUPER_ADMIN ou droit 'STATISTIQUE' dans arrayRight
  300.         $user $this->getUser();
  301.         $can  $user && in_array('ROLE_SUPER_ADMIN', (array)$user->getRoles(), true);
  302.         if (!$can && $user && method_exists($user'getArrayRight')) {
  303.             $can in_array('STATISTIQUE', (array)$user->getArrayRight(), true);
  304.         }
  305.         if (!$can) {
  306.             return new Response('Forbidden'403);
  307.         }
  308.         $tz     = new \DateTimeZone('Africa/Tunis');
  309.         $now    = new \DateTimeImmutable('now'$tz);
  310.         $period = (string) $request->query->get('period''today');
  311.         $logUser $request->query->get('log_user''all');
  312.         // Par défaut : aujourd’hui (00:00 → 23:59:59)
  313.         $start $now->setTime(000);
  314.         $end   $now->setTime(235959);
  315.         switch ($period) {
  316.             case '3days':
  317.                 $end   $now->setTime(23,59,59);
  318.                 $start $end->sub(new \DateInterval('P2D'))->setTime(0,0,0);
  319.                 break;
  320.             case '7days':
  321.                 $end   $now->setTime(23,59,59);
  322.                 $start $end->sub(new \DateInterval('P6D'))->setTime(0,0,0);
  323.                 break;
  324.             case '30days':
  325.                 $end   $now->setTime(23,59,59);
  326.                 $start $end->sub(new \DateInterval('P29D'))->setTime(0,0,0);
  327.                 break;
  328.             case 'week':
  329.                 $start = (new \DateTimeImmutable('monday this week'$tz))->setTime(0,0,0);
  330.                 $end   $now->setTime(23,59,59);
  331.                 break;
  332.             case 'last_week':
  333.                 $start = (new \DateTimeImmutable('monday last week'$tz))->setTime(0,0,0);
  334.                 $end   = (new \DateTimeImmutable('sunday last week'$tz))->setTime(23,59,59);
  335.                 break;
  336.             case 'month':
  337.                 $start = (new \DateTimeImmutable('first day of this month'$tz))->setTime(0,0,0);
  338.                 $end   $now->setTime(23,59,59);
  339.                 break;
  340.             case 'last_month':
  341.                 $start = (new \DateTimeImmutable('first day of last month'$tz))->setTime(0,0,0);
  342.                 $end   = (new \DateTimeImmutable('last day of last month'$tz))->setTime(23,59,59);
  343.                 break;
  344.             case 'year':
  345.                 $start = (new \DateTimeImmutable('first day of january'$tz))->setTime(0,0,0);
  346.                 $end   $now->setTime(23,59,59);
  347.                 break;
  348.             case 'last_year':
  349.                 $start = (new \DateTimeImmutable('first day of january last year'$tz))->setTime(0,0,0);
  350.                 $end   = (new \DateTimeImmutable('last day of december last year'$tz))->setTime(23,59,59);
  351.                 break;
  352.             case 'custom':
  353.                 $s $request->query->get('start');
  354.                 $e $request->query->get('end');
  355.                 if ($s && $e) {
  356.                     try {
  357.                         $start = (new \DateTimeImmutable($s$tz))->setTime(0,0,0);
  358.                         $end   = (new \DateTimeImmutable($e$tz))->setTime(23,59,59);
  359.                         if ($end $start) { [$start$end] = [$end$start]; }
  360.                     } catch (\Throwable $ex) { /* on conserve today */ }
  361.                 }
  362.                 break;
  363.             // today => défaut
  364.         }
  365.         // Utilise tes méthodes existantes du repository
  366.         if ($logUser === 'all') {
  367.             $events $this->activityRepository->LoginEventRange(
  368.                 \DateTime::createFromImmutable($start),
  369.                 \DateTime::createFromImmutable($end)
  370.             );
  371.         } else {
  372.             $events $this->activityRepository->LoginEventRangeByUser(
  373.                 \DateTime::createFromImmutable($start),
  374.                 \DateTime::createFromImmutable($end),
  375.                 (int) $logUser
  376.             );
  377.         }
  378.         $html $this->renderView('@admin/dashboard/_login_events_list.html.twig', [
  379.             'events' => $events
  380.         ]);
  381.         return new Response($html);
  382.     }
  383.     /**
  384.      * @Route("/page", name="page")
  385.      */
  386.     public function page(): Response {
  387.         $produits $this->produitRepository->findWithImage();
  388.         return $this->render('@admin/front/page.html.twig', [
  389.                     'produits' => $produits
  390.         ]);
  391.     }
  392.     public static function ddQuery($sql,EntityManagerInterface $em)
  393.     {
  394.         //$sql = " select @@sql_mode";
  395.         $stmt $em->getConnection()->prepare($sql);
  396.         $result $stmt->executeQuery()->fetchAllAssociative();
  397.     }
  398.     /**
  399.      * @Route("/count-document/{type}/{status}", name="count-document", methods={"GET","POST"}, options={"expose"=true})
  400.      */
  401.     public function countDocument($type="commande",$status="en-attente"): Response {
  402.         return new JsonResponse(array(
  403.             'result' => 1,
  404.             'message' => "{type:'$type',status:'$status'}",
  405.             'count' =>  $this->globalVariables->getCountDocumentByType($type,$status)['count']));
  406.     }
  407.     /**
  408.      * @Route("/time-server", name="timeServer", methods={"GET","POST"}, options={"expose"=true})
  409.      */
  410.     public function getTimeServer(): Response {
  411.         return new JsonResponse(array(
  412.             'result' => 1,
  413.             'message' => 'ok',
  414.             'data' => (new \DateTime('now'))->format("Y-m-d\\TH:i:s")));
  415.     }
  416.     /**
  417.      * @Route("/copy-db", name="copydatabase")
  418.      */
  419.     public function copyDBLoggerInterface $logger): Response{
  420.         $sourceDbName 'sunshiladmin';
  421.         $destinationDbName 'sunshiladmindemo';
  422.         $connectionSource = new PDO('mysql:host=sunshiladmin.mysql.db;dbname=sunshiladmin''sunshiladmin''SunshineElegance192510185');
  423.         $connectionDestination = new PDO('mysql:host=sunshiladmindemo.mysql.db;dbname=sunshiladmindemo' 'sunshiladmindemo''adminDemo2022');
  424.         $tables $connectionSource->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN);
  425.         $connectionDestination->exec("USE {$destinationDbName}");
  426.         foreach ($tables as $tableName) {
  427.             $createCommand $connectionSource->query("SHOW CREATE TABLE `{$sourceDbName}`.`{$tableName}`")->fetchColumn(1);
  428.             $carefulCreateCommand str_replace("CREATE TABLE""CREATE TABLE IF NOT EXISTS"$createCommand);
  429.             $connectionDestination->exec($carefulCreateCommand);
  430.             $logger->info("Table `{$tableName}` created" PHP_EOL);
  431.             $connectionDestination->exec("INSERT INTO `{$destinationDbName}`.`{$tableName}` SELECT * FROM `{$sourceDbName}`.`{$tableName}`");
  432.             $logger->info("Data for table `{$tableName}` copied" PHP_EOL);
  433.         }
  434.         return new Response("<html><head></head><body>done</body></html>");
  435.     }
  436.     #[Route('/topnav/status-counts'name'admin_topnav_status_counts'methods: ['GET'])]
  437.     public function topnavStatusCounts(DocumentRepository $documentRepositoryReclamationRepository $reclamationRepositorySocialConversationRepository $socialConversationRepository\App\Repository\DraftOrderRepository $draftOrderRepository\App\Repository\DocumentCallRepository $documentCallRepository): JsonResponse
  438.     {
  439.         if ($this->isResellerUser()) {
  440.             $data $documentRepository->getTopnavStatusCounts($this->getCurrentResellerUser());
  441.             $data['reclamation'] = ['open' => 0];
  442.             $data['social_inbox'] = ['unread' => 0];
  443.             $data['draft_order'] = ['open' => 0];
  444.             $data['call_reminder'] = ['due' => 0];
  445.             return new JsonResponse([
  446.                 'commande' => $data['commande'],
  447.                 'echange' => $data['echange'],
  448.                 'reclamation' => $data['reclamation'],
  449.                 'social_inbox' => $data['social_inbox'],
  450.                 'draft_order' => $data['draft_order'],
  451.                 'call_reminder' => $data['call_reminder'],
  452.             ], 200, [
  453.                 'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
  454.                 'Pragma' => 'no-cache',
  455.             ]);
  456.         }
  457.         $this->denyAccessUnlessGranted('ROLE_ADMIN');
  458.         $data $documentRepository->getTopnavStatusCounts();
  459.         $data['reclamation'] = [
  460.             'open' => $this->canAccessReclamations() ? $reclamationRepository->countUnresolved() : 0,
  461.         ];
  462.         $data['social_inbox'] = [
  463.             'unread' => $socialConversationRepository->countUnreadInbox(),
  464.         ];
  465.         $data['draft_order'] = [
  466.             'open' => $draftOrderRepository->countOpen(),
  467.         ];
  468.         $data['call_reminder'] = [
  469.             'due' => $documentCallRepository->countDueUnresolvedScheduledCalls(),
  470.         ];
  471.         $response = new JsonResponse($data);
  472.         $response->headers->set('Cache-Control''no-store, no-cache, must-revalidate, max-age=0');
  473.         $response->headers->set('Pragma''no-cache');
  474.         return $response;
  475.     }
  476.     #[Route('/topnav/call-reminders'name'admin_topnav_call_reminders'methods: ['GET'])]
  477.     public function topnavCallReminders(\App\Repository\DocumentCallRepository $documentCallRepository): JsonResponse
  478.     {
  479.         if ($this->isResellerUser()) {
  480.             return new JsonResponse([
  481.                 'count' => 0,
  482.                 'items' => [],
  483.             ], 200, [
  484.                 'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
  485.                 'Pragma' => 'no-cache',
  486.             ]);
  487.         }
  488.         $this->denyAccessUnlessGranted('ROLE_ADMIN');
  489.         $items = [];
  490.         foreach ($documentCallRepository->findDueUnresolvedScheduledCalls(12) as $call) {
  491.             $document $call->getDocument();
  492.             if (!$document) {
  493.                 continue;
  494.             }
  495.             $client $document->getClient();
  496.             $items[] = [
  497.                 'id' => $call->getId(),
  498.                 'documentId' => $document->getId(),
  499.                 'documentRef' => $document->getInternalNbr() ?: ('#' $document->getId()),
  500.                 'client' => $client trim((string) $client->getFirstName()) : '-',
  501.                 'phone' => $client ? ($client->getPhone() ?: $client->getSecondPhone()) : null,
  502.                 'scheduledAt' => $call->getScheduledAt() ? $call->getScheduledAt()->format('d/m/Y H:i') : null,
  503.                 'note' => $call->getNote(),
  504.                 'url' => $this->generateUrl('document_show', ['id' => $document->getId()]),
  505.             ];
  506.         }
  507.         return new JsonResponse([
  508.             'count' => count($items),
  509.             'items' => $items,
  510.         ], 200, [
  511.             'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
  512.             'Pragma' => 'no-cache',
  513.         ]);
  514.     }
  515.     #[Route('/dashboard/kpis-today'name'admin_dashboard_kpis_today'methods: ['GET'])]
  516.     #[Route('/admin/dashboard/kpis-today'name'admin_dashboard_kpis_today_legacy'methods: ['GET'])]
  517.     public function kpisToday(DocumentRepository $documentRepository): JsonResponse
  518.     {
  519.         if ($this->isResellerUser()) {
  520.             return new JsonResponse(
  521.                 $documentRepository->getDashboardKpisTodayClientOrders($this->getCurrentResellerUser()),
  522.                 200,
  523.                 [
  524.                 'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
  525.                 'Pragma' => 'no-cache',
  526.                 ]
  527.             );
  528.         }
  529.         $this->denyAccessUnlessGranted('ROLE_ADMIN');
  530.         $kpis $documentRepository->getDashboardKpisTodayClientOrders();
  531.         return new JsonResponse($kpis200, [
  532.             'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
  533.             'Pragma' => 'no-cache',
  534.         ]);
  535.     }
  536. }