vendor/uvdesk/core-framework/Controller/Dash.php line 291

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\CoreFrameworkBundle\Controller;
  3. use Webkul\UVDesk\CoreFrameworkBundle\Entity;
  4. use Webkul\UVDesk\CoreFrameworkBundle\Form;
  5. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use Symfony\Component\HttpFoundation\Response;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportGroup;
  10. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportTeam;
  11. use Webkul\UVDesk\CoreFrameworkBundle\Entity\UserInstance;
  12. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  13. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Services\UVDeskService;
  15. use Webkul\UVDesk\CoreFrameworkBundle\Services\ReportService;
  16. use Symfony\Contracts\Translation\TranslatorInterface;
  17. use Knp\Component\Pager\PaginatorInterface;
  18. use Doctrine\ORM\Query;
  19. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  20. use Symfony\Component\DependencyInjection\ContainerInterface;
  21. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketRating;
  22. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket;
  23. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  24. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  25. use Symfony\Component\HttpFoundation\JsonResponse;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. class Dash extends AbstractController
  28. {
  29.     private $userService;
  30.     private $reportService;
  31.     private $uvdeskService;
  32.     private $paginator;
  33.     private $translator;
  34.     private $entityManager;
  35.     public function __construct(UserService $userServiceUVDeskService $uvdeskService,ReportService $reportServicePaginatorInterface $paginatorTranslatorInterface $translatorEntityManagerInterface $entityManager)
  36.     {
  37.         $this->userService $userService;
  38.         $this->reportService $reportService;
  39.         $this->uvdeskService $uvdeskService;
  40.         $this->paginator $paginator;
  41.         $this->translator $translator;
  42.         $this->entityManager $entityManager;
  43.     }
  44.     public function listDashActivity(Request $request)
  45.     {
  46.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_AGENT_ACTIVITY')){
  47.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  48.         }
  49.         // Determine date param (single date, format YYYY-MM-DD)
  50.         $dateParam $request->query->get('date') ?: (new \DateTimeImmutable('today'))->format('Y-m-d');
  51.         // Prepare initial activity payload for the view (agentDashData expects Request)
  52.         $clonedRequest $request->duplicate(nullnull, ['_route_params' => []]);
  53.         $clonedRequest->query->set('date'$dateParam);
  54.         try {
  55.             $agentActivity $this->agentDashData($clonedRequest);
  56.         } catch (\Exception $e) {
  57.             $agentActivity = ['data' => [], 'dueDatesByDate' => [], 'dueTickets' => []];
  58.         }
  59.         // Compute bucket counts server-side so template can render initial numbers immediately
  60.         $dueCounts = [
  61.             'today' => 0,
  62.             'tomorrow' => 0,
  63.             'in7' => 0,
  64.             'od7' => 0,
  65.             'odgt7' => 0,
  66.         ];
  67.         $baseDate = new \DateTimeImmutable($dateParam);
  68.         // Prefer computing counts from dueTickets if available
  69.         $dueTicketRows $agentActivity['dueTickets'] ?? [];
  70.         if (!empty($dueTicketRows) && is_array($dueTicketRows)) {
  71.             foreach ($dueTicketRows as $r) {
  72.                 if (empty($r['dueDate'])) continue;
  73.                 try {
  74.                     $d = new \DateTimeImmutable($r['dueDate']);
  75.                 } catch (\Exception $e) { continue; }
  76.                 $diff = (int) $d->diff($baseDate)->format('%r%a');
  77.                 if ($diff === 0$dueCounts['today']++;
  78.                 elseif ($diff === 1$dueCounts['tomorrow']++;
  79.                 elseif ($diff && $diff <= 7$dueCounts['in7']++;
  80.                 elseif ($diff && $diff >= -7$dueCounts['od7']++;
  81.                 elseif ($diff < -7$dueCounts['odgt7']++;
  82.             }
  83.         } else {
  84.             // Fallback: compute from dueDatesByDate
  85.             if (!empty($agentActivity['dueDatesByDate']) && is_array($agentActivity['dueDatesByDate'])) {
  86.                 foreach ($agentActivity['dueDatesByDate'] as $dueDateKey => $ticketIds) {
  87.                     try { $d = new \DateTimeImmutable($dueDateKey); } catch (\Exception $e) { continue; }
  88.                     $diff = (int) $d->diff($baseDate)->format('%r%a');
  89.                     $count is_array($ticketIds) ? count($ticketIds) : 0;
  90.                     if ($diff === 0$dueCounts['today'] += $count;
  91.                     elseif ($diff === 1$dueCounts['tomorrow'] += $count;
  92.                     elseif ($diff && $diff <= 7$dueCounts['in7'] += $count;
  93.                     elseif ($diff && $diff >= -7$dueCounts['od7'] += $count;
  94.                     elseif ($diff < -7$dueCounts['odgt7'] += $count;
  95.                 }
  96.             }
  97.         }
  98.         return $this->render('@UVDeskCoreFramework/Reports/listDash.html.twig', [
  99.             'agents' => $this->userService->getAgentsPartialDetails(),
  100.             'agentActivity' => $agentActivity,
  101.             'date' => $dateParam,
  102.             'dueCounts' => $dueCounts,
  103.         ]);
  104.     }
  105.     public function agentDashData(Request $request)
  106.     {
  107.         // Check access permissions
  108.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_AGENT_ACTIVITY')) {
  109.             throw new \Exception('Access Denied'403);
  110.         }
  111.         // Prepare sensible empty return structure
  112.         $result = [
  113.             'data' => [],
  114.             'dueDatesByDate' => [],
  115.             'dueTickets' => [],
  116.         ];
  117.         try {
  118.             $connection $this->entityManager->getConnection();  // ✅ Injected EntityManager
  119.             // Query tickets with their status
  120.             $query "
  121.                 SELECT 
  122.                     t.id AS ticket_id, 
  123.                     t.due_date, 
  124.                     s.code AS status_code, 
  125.                     s.description AS status_description
  126.                 FROM uv_ticket t
  127.                 JOIN uv_ticket_status s ON t.status_id = s.id
  128.             ";
  129.             $tickets $connection->fetchAllAssociative($query);
  130.         } catch (\Throwable $e) {
  131.             // If DB isn't accessible (tests, cache warmup, etc.) return empty structures
  132.             return $result;
  133.         }
  134.         // Build normalized structures expected by listDashActivity and templates
  135.         $rows = [];
  136.         $dueTickets = [];
  137.         $dueDatesByDate = [];
  138.         foreach ($tickets as $ticket) {
  139.             if (empty($ticket['due_date'])) {
  140.                 continue;
  141.             }
  142.             try {
  143.                 // Use fully-qualified DateTimeImmutable
  144.                 $dt \DateTimeImmutable::createFromFormat('Y-m-d H:i:s'$ticket['due_date']) ?: new \DateTimeImmutable($ticket['due_date']);
  145.             } catch (\Exception $e) {
  146.                 // skip unparseable dates
  147.                 continue;
  148.             }
  149.             $dueDateNormalized $dt->format('Y-m-d');
  150.             $row = [
  151.                 'ticketId' => $ticket['ticket_id'],
  152.                 'dueDate' => $dueDateNormalized,
  153.                 'statusCode' => $ticket['status_code'] ?? null,
  154.                 'statusDescription' => $ticket['status_description'] ?? null,
  155.             ];
  156.             $rows[] = $row;
  157.             $dueTickets[] = $row;
  158.             $dueDatesByDate[$dueDateNormalized][] = $ticket['ticket_id'];
  159.         }
  160.         $result['data'] = $rows;
  161.         $result['dueDatesByDate'] = $dueDatesByDate;
  162.         $result['dueTickets'] = $dueTickets;
  163.         return $result;
  164.     }
  165.     /**
  166.  * Returns To-Do items for tabs: today | upcoming | completed.
  167.  * - today:     due_date = today
  168.  * - upcoming:  due_date in next 15 days (excluding today)
  169.  * - completed: due_date within last 7 days up to today AND status = closed
  170.  *
  171.  * @Route("/agent/dashboard/todo", name="helpdesk_member_dash_todo", methods={"GET"})
  172.  */
  173. public function todoData(Request $request): JsonResponse
  174. {
  175.     if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_AGENT_ACTIVITY')) {
  176.         return new JsonResponse(['error' => 'Access denied'], 403);
  177.     }
  178.     $tab $request->query->get('tab''today'); // today | upcoming | completed
  179.     // Use your server TZ (or set a specific one like 'Asia/Kolkata')
  180.     $tz = new \DateTimeZone(date_default_timezone_get());
  181.     $today = (new \DateTimeImmutable('today'$tz));
  182.     // Dates we’ll need
  183.     $fromUpcoming $today->modify('+1 day')->format('Y-m-d');
  184.     $toUpcoming   $today->modify('+15 days')->format('Y-m-d');
  185.     $fromCompleted$today->modify('-7 days')->format('Y-m-d');
  186.     $todayStr     $today->format('Y-m-d');
  187.     // Base SQL (your join), + filter by tab
  188.     // NOTE: We DON’T hardcode status_id=5; instead we treat any status whose code is 'closed' (case-insensitive) as completed.
  189.     $sql "
  190.         SELECT 
  191.             t.id AS ticket_id,
  192.             t.subject,
  193.             DATE(t.due_date) AS due_date,
  194.             t.agent_id,
  195.             t.status_id,
  196.             u.first_name AS agent_first_name,
  197.             u.last_name  AS agent_last_name,
  198.             s.code       AS status_code
  199.         FROM uv_ticket t
  200.         LEFT JOIN uv_user u          ON t.agent_id = u.id
  201.         LEFT JOIN uv_ticket_status s ON t.status_id = s.id
  202.         WHERE t.due_date IS NOT NULL
  203.     ";
  204.     $params = [];
  205.     switch ($tab) {
  206.         case 'today':
  207.             $sql .= " AND DATE(t.due_date) = :today";
  208.             $params['today'] = $todayStr;
  209.             break;
  210.         case 'upcoming':
  211.             $sql .= " AND DATE(t.due_date) BETWEEN :from AND :to";
  212.             $params['from'] = $fromUpcoming;
  213.             $params['to']   = $toUpcoming;
  214.             break;
  215.         case 'completed':
  216.             // last 7 days up to today, and closed status
  217.             // if you must use a numeric id, swap the status filter line for: AND t.status_id = :closedId
  218.             $sql .= " AND DATE(t.due_date) BETWEEN :from AND :to
  219.                       AND LOWER(s.code) = 'closed'";
  220.             $params['from'] = $fromCompleted;
  221.             $params['to']   = $todayStr;
  222.             break;
  223.         default:
  224.             // default to today
  225.             $sql .= " AND DATE(t.due_date) = :today";
  226.             $params['today'] = $todayStr;
  227.             break;
  228.     }
  229.     $sql .= " ORDER BY t.due_date ASC, t.id ASC";
  230.     $conn  $this->entityManager->getConnection();
  231.     $rows  $conn->fetchAllAssociative($sql$params);
  232.     // Normalize response for UI
  233.     $items array_map(function ($r) {
  234.         $agent trim(($r['agent_first_name'] ?? '') . ' ' . ($r['agent_last_name'] ?? ''));
  235.         return [
  236.             'ticket_id'   => (int) $r['ticket_id'],
  237.             'subject'     => $r['subject'] ?? '',
  238.             'due_date'    => $r['due_date'] ?? null// Y-m-d
  239.             'agent_name'  => $agent !== '' $agent null,
  240.             'status_code' => $r['status_code'] ?? null,
  241.             'status_id'   => isset($r['status_id']) ? (int)$r['status_id'] : null,
  242.         ];
  243.     }, $rows);
  244.     return new JsonResponse(['items' => $items]);
  245. }
  246. /**
  247.  * @Route("/agent/dashboard/tasks", name="helpdesk_member_dash_tasks", methods={"GET"})
  248.  */
  249. public function tasksData(Request $request): JsonResponse
  250. {
  251.     if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_AGENT_ACTIVITY')) {
  252.         return new JsonResponse(['error' => 'Access denied'], 403);
  253.     }
  254.     $tab $request->query->get('tab''pending'); // pending | hold | inprogress | completed
  255.     // Map UI tabs to status_id
  256.     $map = [
  257.         'pending'    => 2// Pending
  258.         'hold'       => 4// Hold / Resolved (as per your mapping)
  259.         'inprogress' => 1// Open
  260.         'completed'  => 5// Closed
  261.     ];
  262.     $statusId $map[$tab] ?? 2;
  263.     $conn $this->entityManager->getConnection();
  264.     $sql "
  265.         SELECT 
  266.             t.id AS ticket_id,
  267.             t.subject,
  268.             DATE(t.due_date) AS due_date,
  269.             t.agent_id,
  270.             t.status_id,
  271.             u.first_name AS agent_first_name,
  272.             u.last_name  AS agent_last_name,
  273.             s.code       AS status_code
  274.         FROM uv_ticket t
  275.         LEFT JOIN uv_user u          ON t.agent_id = u.id
  276.         LEFT JOIN uv_ticket_status s ON t.status_id = s.id
  277.         WHERE t.status_id = :sid
  278.         ORDER BY t.due_date IS NULL, t.due_date ASC, t.id ASC
  279.     ";
  280.     $rows $conn->fetchAllAssociative($sql, ['sid' => $statusId]);
  281.     $items array_map(function ($r) {
  282.         $agent trim(($r['agent_first_name'] ?? '') . ' ' . ($r['agent_last_name'] ?? ''));
  283.         return [
  284.             'ticket_id'   => (int) $r['ticket_id'],
  285.             'subject'     => $r['subject'] ?? '',
  286.             'due_date'    => $r['due_date'] ?? null// Y-m-d or null
  287.             'agent_name'  => $agent !== '' $agent null,
  288.             'status_code' => $r['status_code'] ?? null,
  289.             'status_id'   => isset($r['status_id']) ? (int)$r['status_id'] : null,
  290.         ];
  291.     }, $rows);
  292.     return new JsonResponse(['items' => $items]);
  293. }
  294.    
  295. }