<?php
namespace App\Controller;
use App\Repository\ContratsRepository;
use DateTime;
use App\Library\Excel;
use App\Entity\Actions;
use App\Entity\Tickets;
use App\Service\Securizer;
use App\Repository\StatusRepository;
use App\Repository\ActionsRepository;
use App\Repository\ClientsRepository;
use App\Repository\TicketsRepository;
use App\Repository\ContactsRepository;
use Doctrine\ORM\EntityManagerInterface;
use PhpOffice\PhpSpreadsheet\Style\Border;
use App\Repository\LigneDeContratRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
class TicketController extends AbstractController
{
/**
* @IsGranted("ROLE_USER")
*/
public function index(TicketsRepository $repoTicket, AccessDecisionManagerInterface $accessDecisionManager, ContactsRepository $repoContact): Response
{
// retourne tickets en fonction des roles de l'utilisateur
$securizer = new Securizer($accessDecisionManager);
// recupere le ou les tickets qu'il est possible d'afficher
$tickets = $repoTicket->findTicketAll($this->getUser(), $securizer, $repoContact);
return $this->json($tickets, 200, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_USER")
*/
public function ticketOpen(TicketsRepository $repoTicket, AccessDecisionManagerInterface $accessDecisionManager, ContactsRepository $repoContact): Response
{
// retourne tickets ouvertes en fonction des roles de l'utilisateur
try {
$securizer = new Securizer($accessDecisionManager);
} catch (\throwable $e) {
return $this->json([
'status' => 400,
'message' => $e->getMessage()
], 400);
}
// recupere le ou les tickets qu'il est possible d'afficher
$tickets = $repoTicket->findTicketStatus($this->getUser(), ["Nouveau", "En Cours", "En Attente"], $securizer, $repoContact);
header('Accept-Encoding: gzip, compress, br');
return $this->json($tickets, 200, [], ['groups' => ['affichageTickets', 'affichageTicketsActions']]);
}
/**
* @IsGranted("ROLE_USER")
*/
public function ticketClose($start, $fin, TicketsRepository $repoTicket, AccessDecisionManagerInterface $accessDecisionManager, ContactsRepository $repoContact): Response
{
$securizer = new Securizer($accessDecisionManager);
$tickets = $repoTicket->getTicketsByDate($start, $fin, $this->getUser(), $securizer, $repoContact);
return $this->json($tickets, 200, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_USER")
*/
public function voir($id, TicketsRepository $repoTicket, ContactsRepository $repoContact, AccessDecisionManagerInterface $accessDecisionManager): Response
{
// retourne les details du ticket par id
$ticket = $repoTicket->find($id);
$securizer = new Securizer($accessDecisionManager);
$tickets = $repoTicket->findTicketAll($this->getUser(), $securizer, $repoContact);
//verifi que le ticket que l'on cherche fait bien partie de la liste de ceux qu'il est possible d'afficher
if (in_array($repoTicket->find($id), $tickets)) {
//le ticket a visualiser
$ticket = $repoTicket->find($id);
} else {
return $this->json([
'status' => 400,
'message' => "Vous ne pouvez pas consulter ce ticket"
], 400);
}
return $this->json($ticket, 200, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_TECH")
*/
public function delete($id, TicketsRepository $repoTicket): Response
{
// retourne les details du ticket par id
$ticket = $repoTicket->find($id);
//verifi que le ticket que l'on cherche fait bien partie de la liste de ceux qu'il est possible d'afficher
if (count($ticket->getActions()) > 0 || $ticket->getIdStatus()->getStatus() != "Nouveau") {
return $this->json([
'status' => 400,
'message' => "Il n'est pas possible de supprimer ce ticket"
], 400);
} else {
$repoTicket->remove($ticket);
}
return $this->json(true, 200);
}
/**
* @IsGranted("ROLE_CLIENT")
*/
public function creer(Request $request, StatusRepository $repoStatus, ValidatorInterface $validator, SerializerInterface $serializer, EntityManagerInterface $manager, ContactsRepository $repoContact, Securizer $securizer): Response
{
// creer un nouveau ticket, seul les role client ou superieur peuvent acceder a cette page
$contacts = $repoContact->findContactActif($this->getUser(), $securizer);
$jsonRecu = $request->getContent();
try {
//transforme le json reçu en entity
$ticket = $serializer->deserialize($jsonRecu, Tickets::class, 'json');
if (in_array($ticket->getBeneficiaire(), $contacts)) {
$ticket->setCreateur($this->getUser())
->setDateCreation(new \DateTime())
->setIdStatus($repoStatus->findOneBy(['status' => 'Nouveau']));
//validation des données reçus
$errors = $validator->validate($ticket);
//si il y a au moins 1 erreur alors il retourne un json avec l'erreur de validation en message
if (count($errors) > 0) {
return $this->json($errors, 400);
}
$manager->persist($ticket);
$manager->flush();
} else {
//retourne un json avec message d'erreur si l'on a pas le droit d'afficher ou si l'id n'existe pas
return $this->json([
'status' => 400,
'message' => "Vous ne pouvez pas lier un ticket à ce contact"
], 400);
}
} catch (\throwable $e) {
//try catch pour les erreurs de syntaxe dans le json
return $this->json([
'status' => 400,
'message' => $e->getMessage()
], 400);
}
return $this->json($ticket, 201, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_TECH")
*/
public function uploadFile(Request $request, EntityManagerInterface $manager, TicketsRepository $repoTicket, AccessDecisionManagerInterface $accessDecisionManager): Response
{
// charger un fichier a un élément de park, seul les roles tech ou supperieur peuvent accer a cette url
$securizer = new Securizer($accessDecisionManager);
if (!$securizer->isGranted($this->getUser(), "ROLE_TECH"))
return $this->json([
'status' => 400,
'message' => "Vous ne pouvez pas consulter cet élément"
], 400);
try {
$file = $request->files->get('myFile');
// ** Vérifier si les dossiers existes et si oui supprimer le contenu
$path = dirname(__DIR__) . '/../documents/tickets/ticket_' . $_POST["ticketId"] . "/";
if (!is_dir($path))
mkdir($path, 0777, true);
// ** Télécharger le fichier
if (!empty($file)) {
$file->move(
$path,
$_FILES["myFile"]["name"]
);
}
$ticket = $repoTicket->find($_POST["ticketId"]);
$ticket->setFile($_FILES["myFile"]["name"]);
$manager->persist($ticket);
$manager->flush();
} catch (\throwable $e) {
return $this->json([
'status' => 400,
'message' => $e->getMessage()
], 400);
}
return $this->json($ticket, 201, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_TECH")
*/
public function getFile($data, AccessDecisionManagerInterface $accessDecisionManager)
{
// télécharger un fichier d'un élément de parc, seul les roles tech ou supperieur peuvent accer a cette url
$securizer = new Securizer($accessDecisionManager);
if (!$securizer->isGranted($this->getUser(), "ROLE_TECH"))
return $this->json([
'status' => 400,
'message' => "Vous ne pouvez pas consulter cet élément"
], 400);
try {
$path = dirname(__DIR__) . "/../documents/tickets/ticket_" . str_replace("::filename", "/", str_replace("::extension", ".", $data));
if (!is_file($path))
return $this->json([
'status' => 400,
'message' => "Aucun fichier de ce type n’a été trouvé"
], 400);
} catch (\throwable $e) {
return $this->json([
'status' => 400,
'message' => $e->getMessage()
], 400);
}
// header('Access-Control-Allow-Origin: ' . "http://localhost:8001");
header('Access-Control-Allow-Origin: ' . "https://extranet.cco-info.fr/");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($path) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
flush(); // Flush system output buffer
echo readfile($path);
}
/**
* @IsGranted("ROLE_TECH")
*/
public function modif($id, Request $request, TicketsRepository $repoTicket, ValidatorInterface $validator, SerializerInterface $serializer, EntityManagerInterface $manager, ContactsRepository $repoContact): Response
{
// le ticket a modifier
$ticket = $repoTicket->find($id);
//si l'id est invalide, retourne un json avec un message d'erreur
if ($ticket == null) {
return $this->json([
'status' => 400,
'message' => "le ticket à modifier n'existe pas"
], 400);
}
// liste des beneficiare qu'il est possible d'affecter a un ticket pour qu'il reste lié au même client
$idClientBeneficiaire = $ticket->getBeneficiaire()->getIdClient()->getId();
$contacts = $repoContact->findBy(['idClient' => $idClientBeneficiaire]);
$jsonRecu = $request->getContent();
try {
$serializer->deserialize($jsonRecu, Tickets::class, 'json', ['object_to_populate' => $ticket]);
if (in_array($ticket->getBeneficiaire(), $contacts) && $idClientBeneficiaire == $ticket->getBeneficiaire()->getIdClient()->getId()) {
$errors = $validator->validate($ticket);
if (count($errors) > 0) {
return $this->json($errors, 400);
}
$manager->persist($ticket);
$manager->flush();
} else {
return $this->json([
'status' => 400,
'message' => "Vous ne pouvez pas lié ce ticket a ce contact"
], 400);
}
} catch (\throwable $e) {
return $this->json([
'status' => 400,
'message' => $e->getMessage()
], 400);
}
return $this->json($ticket, 201, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_TECH")
*/
public function setStatus(Request $request, TicketsRepository $ticketsRepository, StatusRepository $statusRepo, EntityManagerInterface $manager): Response
{
$jsonRecu = json_decode($request->getContent());
if (!isset($jsonRecu->idTicket) || empty($jsonRecu->idTicket))
return $this->json([
'status' => 400,
'message' => "L'id du ticket est manquant"
], 400);
if (!isset($jsonRecu->idStatus) || empty($jsonRecu->idStatus))
return $this->json([
'status' => 400,
'message' => "L'id du status est manquant"
], 400);
$ticket = $ticketsRepository->find($jsonRecu->idTicket);
if (empty($ticket))
return $this->json([
'status' => 400,
'message' => sprintf("l'id %d ne correspond pas à un ticket", $jsonRecu->idTicket)
], 400);
$status = $statusRepo->find($jsonRecu->idStatus);
if (empty($status))
return $this->json([
'status' => 400,
'message' => sprintf("l'id %d ne correspond pas à un status", $jsonRecu->idStatus)
], 400);
try {
$ticket->setIdStatus($status);
// If ticket passe à un statut terminer ou clôturer => incrémenter le champs "hotlineCompteur" du nombre de minute.
if ($status->getStatus() === "Termine") {
$client = $ticket->getBeneficiaire()->getIdClient();
//modifi la durée consomé de la ligne de contrat de l'intervention
$client = $client->setHotlineCompteur($client->getHotlineCompteur() + $ticket->getDureeTotale());
$manager->persist($client);
}
$manager->persist($ticket);
$action = new Actions();
$action->setDateAction(new DateTime());
$action->setMessage($status->getStatus());
$action->setDuree(0);
$action->setIntervenant($this->getUser());
$action->setTicket($ticket);
$action->setStatusChanged(true);
$manager->persist($action);
$manager->flush();
} catch (\throwable $e) {
//try catch pour les erreurs de syntaxe dans le json
return $this->json([
'status' => 400,
'message' => $e->getMessage()
], 400);
}
return $this->json($action, 201, [], ['groups' => 'affichageAction']);
}
/**
* @IsGranted("ROLE_CLIENT")
*/
public function getTicketByClient(int $id, ContactsRepository $repoContact, ClientsRepository $repoClient)
{
$client = $repoClient->find($id);
if (empty($client)) {
return $this->json([
'status' => 400,
'message' => sprintf("Aucun client n'a �t� trouv� avec l'id %d", $id)
], 400);
}
$contacts = $repoContact->findBy(['idClient' => $client]);
$tickets = [];
foreach ($contacts as $contact) {
foreach ($contact->getTicketBeneficiaire() as $t) {
$tickets[] = $t;
}
}
usort($tickets, function ($a, $b) {
if ($a->getDateCreation() < $b->getDateCreation()) {
return 1;
} else if ($a->getDateCreation() > $b->getDateCreation()) {
return -1;
}
return 0;
});
return $this->json($tickets, 201, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_USER")
*/
public function getTicketByContact(int $id, ContactsRepository $repoContact, ClientsRepository $repoClient)
{
$contact = $repoContact->find($id);
if (empty($contact)) {
return $this->json([
'status' => 400,
'message' => sprintf("Aucun contact n'a �t� trouv� avec l'id %d", $id)
], 400);
}
$tickets = [];
foreach ($contact->getTicketBeneficiaire() as $t) {
$tickets[] = $t;
}
return $this->json($tickets, 201, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_COMMERCIAL")
*/
public function stats(Request $request, AccessDecisionManagerInterface $accessDecisionManager, StatusRepository $statusRepo, ActionsRepository $actionsRepo, TicketsRepository $repoTickets, ContactsRepository $repoContact): Response
{
$jsonRecu = json_decode($request->getContent());
$securizer = new Securizer($accessDecisionManager);
$tickets = $repoTickets->getTicketsByDate($jsonRecu->startDate, $jsonRecu->endDate, $this->getUser(), $securizer, $repoContact);
$actions = $actionsRepo->getActionsByDate($jsonRecu->startDate, $jsonRecu->endDate, $this->getUser(), $securizer, $repoContact);
$status = $statusRepo->findAll();
$quantity = [];
foreach ($status as $key => $value) {
if (in_array('ticket', $value->getTypes()))
$quantity[$value->getStatus()] = 0;
}
/** @var Tickets $ticket */
foreach ($tickets as $key => $ticket) {
$quantity[$ticket->getIdStatus()->getStatus()] += 1;
}
$actionsTime = [];
$totalTime = 0;
/** @var Actions $action */
foreach ($actions as $key => $action) {
if ($action->getDuree() > 0) {
if (!isset($actionsTime[$action->getDateAction()->format("d/m/Y")])) $actionsTime[$action->getDateAction()->format("d/m/Y")] = 0;
$actionsTime[$action->getDateAction()->format("d/m/Y")] += $action->getDuree();
$totalTime += $action->getDuree();
}
}
$general = [
"Total tickets" => ["total" => count($tickets) . ' tickets', "moyen" => (count($tickets) > 0 ? round($totalTime / count($tickets)) : 0) . " min", "description" => "moyen par ticket"],
"Total actions" => ["total" => count($actions) . ' actions', "moyen" => (count($tickets) > 0 ? round(count($actions) / count($tickets)) : 0) . " actions", "description" => "moyen par ticket"],
"Temps Passé" => ["total" => $totalTime . " min", "moyen" => (count($actions) > 0 ? round($totalTime / count($actions)) : 0) . " min", "description" => "moyen par action"],
];
return $this->json([$quantity, $actionsTime, $general], 200, [], ['groups' => 'affichageTickets']);
}
/**
* @IsGranted("ROLE_TECH")
*/
public function export(Request $request, TicketsRepository $repoTickets)
{
try {
$jsonRecu = json_decode($request->getContent());
$path = $_SERVER["DOCUMENT_ROOT"] . ($_ENV['APP_ENV'] == "dev" ? '../documents/' : '/ExtranetV2/documents/');
$excel = new Excel($path, 'Export tickets history.xlsx');
$row = 1;
$cols = ["A", "B", "C", "D", "E", "F", "G"];
$heads = ["Ticket N°", "Titre", "Statut", "Date", "Client", "Bénéficiaire", "Temps passe (minutes)"];
for ($i = 0; $i < count($heads); $i++) {
$excel->writeCell($cols[$i] . $row, $heads[$i], Excel::_FORMAT_TEXTE_);
}
$excel->fontBold('A1:G1');
$row++;
/** @var Tickets $ticket */
for ($i = 0; $i < count($jsonRecu->ids); $i++) {
$ticket = $repoTickets->find($jsonRecu->ids[$i]);
$excel->writeCell("A" . $row, $ticket->getId(), Excel::_FORMAT_NUMBER_);
$excel->writeCell("B" . $row, $ticket->getTitre(), Excel::_FORMAT_TEXTE_);
$excel->writeCell("C" . $row, $ticket->getIdStatus()->getStatus(), Excel::_FORMAT_TEXTE_);
$excel->writeCell("D" . $row, date('d/m/Y', $ticket->getDateCreation()), Excel::_FORMAT_DDMMYYYY_);
$excel->writeCell("E" . $row, $ticket->getBeneficiaire()->getIdClient()->getNom(), Excel::_FORMAT_TEXTE_);
$excel->writeCell("F" . $row, $ticket->getBeneficiaire()->getNom() . " " . $ticket->getBeneficiaire()->getPrenom(), Excel::_FORMAT_TEXTE_);
$excel->writeCell("G" . $row, $ticket->getDureeTotale(), Excel::_FORMAT_NUMBER_);
$excel->applyBackgroundColorAndColor('A' . $row . ':G' . $row, ($row % 2 == 1 ? 'f5f5f5' : 'ffffff'), '424242');
$excel->fontBold('G' . $row . ':G' . $row);
$row++;
}
$excel->applyAllBorder(Border::BORDER_THIN, 'A1' . ':G' . ($row - 1));
$excel->autoSizeColumn('A:G');
$excel->saveXlsx();
} catch (\Throwable $th) {
var_dump($th);
}
return $this->json(true, 200, []);
}
public function downloadExport()
{
$path = $_SERVER["DOCUMENT_ROOT"] . ($_ENV['APP_ENV'] == "dev" ? '../documents/' : '/ExtranetV2/documents/');
$path .= 'Export tickets history.xlsx';
// header('Access-Control-Allow-Origin: ' . "http://localhost:8001");
header('Access-Control-Allow-Origin: ' . "https://extranet.cco-info.fr/");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // Type MIME pour les fichiers Excel
header('Content-Disposition: attachment; filename="Export tickets history.xlsx"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
return readfile($path);
}
/**
* @IsGranted("ROLE_COMMERCIAL")
*/
public function showHotline(
Request $request,
ClientsRepository $clientsRepository,
ContratsRepository $contratsRepository,
TicketsRepository $ticketsRepository
): Response {
// $actionsTime = $ticketsRepository->findTimeTicketTelemaintenance();
// $contractsTime = $contratsRepository->findTimeContratTelemaintenance();
// $actionsNotClose = $ticketsRepository->findTimeNotCloseTicketTelemaintenance();
//
// $array = [];
//
// foreach ($actionsTime as $actionTime) {
// $count = 0;
// foreach($actionsNotClose as $actionNotClose) {
// if ($actionTime['id'] === $actionNotClose['id']) {
// $count += $actionNotClose['1'];
// }
// }
//
// $find = false;
// foreach ($contractsTime as $contractTime) {
// if ($actionTime['id'] === $contractTime['id']) {
// $array[] = [
// "nom" => $contractTime['nom'],
// "heureConsommee" => $contractTime['1'],
// "heureNotClosing" => $count,
// "heureTotalTicket" => $actionTime['1'],
// "hotlineCompteur" => $actionTime['hotlineCompteur']
// ];
// $find = true;
// break;
// }
// }
//
// if (!$find) {
// $array[] = [
// "nom" => $actionTime['nom'],
// "heureConsommee" => "Sans contrat",
// "heureNotClosing" => $count,
// "heureTotalTicket" => $actionTime['1'],
// "hotlineCompteur" => $actionTime['hotlineCompteur']
// ];
// }
// }
$array = $this->findDiffTime($ticketsRepository, $contratsRepository);
return $this->render('ticket/index.html.twig', [
"bilanHeures" => $array
]);
}
public function findDiffTime(TicketsRepository $ticketsRepository, ContratsRepository $contratsRepository): array
{
$actionsTime = $ticketsRepository->findTimeTicketTelemaintenance();
$contractsTime = $contratsRepository->findTimeContratTelemaintenance();
$actionsNotClose = $ticketsRepository->findTimeNotCloseTicketTelemaintenance();
$array = [];
foreach ($actionsTime as $actionTime) {
$count = 0;
foreach($actionsNotClose as $actionNotClose) {
if ($actionTime['id'] === $actionNotClose['id']) {
$count += $actionNotClose['1'];
}
}
$find = false;
foreach ($contractsTime as $contractTime) {
if ($actionTime['id'] === $contractTime['id']) {
$array[] = [
"nom" => $contractTime['nom'],
"heureConsommee" => $contractTime['1'],
"heureNotClosing" => $count,
"heureTotalTicket" => $actionTime['1'],
"hotlineCompteur" => $actionTime['hotlineCompteur']
];
$find = true;
break;
}
}
if (!$find) {
$array[] = [
"nom" => $actionTime['nom'],
"heureConsommee" => "Sans contrat",
"heureNotClosing" => $count,
"heureTotalTicket" => $actionTime['1'],
"hotlineCompteur" => $actionTime['hotlineCompteur']
];
}
}
return $array;
}
}