src/Controller/DefaultController.php line 39

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\AssignedBadge;
  4. use App\Entity\Badge;
  5. use App\Entity\CompanyOrder;
  6. use App\Entity\ErrorStamped;
  7. use App\Entity\Operator;
  8. use App\Entity\Stamped;
  9. use App\Form\StampedInOutType;
  10. use App\Form\StampedMensaType;
  11. use App\Repository\StampedRepository;
  12. use App\Utils\DateTimeUtils;
  13. use Doctrine\Persistence\ManagerRegistry;
  14. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  15. use Symfony\Component\Config\Definition\Exception\Exception;
  16. use Symfony\Component\HttpFoundation\JsonResponse;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpFoundation\Response;
  19. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  20. use Symfony\Component\Routing\Annotation\Route;
  21. class DefaultController extends AbstractController
  22. {
  23. private $doctrine;
  24. public function __construct(ManagerRegistry $doctrine)
  25. {
  26. $this->doctrine = $doctrine;
  27. }
  28. /**
  29. * @Route("/", name="home", methods={"GET","POST"})
  30. * @param StampedRepository $stampedRepository
  31. * @return Response
  32. * @throws \Exception
  33. */
  34. public function index(StampedRepository $stampedRepository): Response
  35. {
  36. if ($this->isGranted("ROLE_ADMIN_EMZA")) {
  37. return $this->redirectToRoute('stamped_index', ['page' => '1', 'companyOrderType' => CompanyOrder::TYPE_EMZA]);
  38. } elseif ($this->isGranted("ROLE_ADMIN")) {
  39. return $this->redirectToRoute('stamped_index', ['page' => '1', 'companyOrderType' => CompanyOrder::TYPE_CANTIERE]);
  40. }elseif ($this->isGranted("ROLE_ADMIN_MENSA")) {
  41. return $this->redirectToRoute('stamped_index', ['page' => '1', 'companyOrderType' => CompanyOrder::TYPE_MENSA]);
  42. }elseif ($this->isGranted("ROLE_ADMIN_CANTIERE")) {
  43. return $this->redirectToRoute('stamped_index', ['page' => '1', 'companyOrderType' => CompanyOrder::TYPE_CANTIERE]);
  44. } elseif ($this->isGranted("ROLE_MENSA")) {
  45. $form = $this->createForm(StampedMensaType::class);
  46. $userCompanyOrder = $this->get('security.token_storage')->getToken()->getUser()->getCompanyOrder();
  47. return $this->render('default/home-mensa.html.twig', [
  48. 'form' => $form->createView(),
  49. 'userCompany' => $userCompanyOrder,
  50. ]);
  51. } else {
  52. $form = $this->createForm(StampedInOutType::class);
  53. $userCompanyOrder = $this->get('security.token_storage')->getToken()->getUser()->getCompanyOrder();
  54. return $this->render('default/home.html.twig', [
  55. 'form' => $form->createView(),
  56. 'userCompany' => $userCompanyOrder,
  57. ]);
  58. }
  59. }
  60. /**
  61. * @Route("/ajax/timbra", name="timbra_ajax", methods={"POST"})
  62. * @param Request $request
  63. * @return Response
  64. * @throws \Exception
  65. */
  66. public function timbraAjax(Request $request): Response
  67. {
  68. $datas = $request->request->get('data');
  69. $result = new JsonResponse(['Inizializzo il result'], Response::HTTP_BAD_REQUEST);
  70. try {
  71. if (array_key_exists('type', $datas)) {
  72. $typeForm = StampedMensaType::class;
  73. $data = [
  74. 'stamped_in_out[Badge' => $datas['stamped_mensa[Badge'],
  75. 'stamped_in_out[InOut' => $datas['stamped_mensa[InOut'],
  76. 'stamped_in_out[date' => DateTimeUtils::getNow(),
  77. ];
  78. $result = $this->saveTimbrate($data, $typeForm, 'Mensa');
  79. } else {
  80. $typeForm = StampedInOutType::class;
  81. foreach ($datas as $data) {
  82. $result = $this->saveTimbrate($data, $typeForm, 'Cantiere');
  83. }
  84. }
  85. } catch (\Exception $ex) {
  86. $result = new JsonResponse(['Non ci sono dati da processare'], Response::HTTP_BAD_REQUEST);
  87. }
  88. return $result;
  89. }
  90. /**
  91. * Salva una nuova timbrata (entrata o uscita) per un operatore.
  92. *
  93. * FUNZIONAMENTO MULTI-CANTIERE - CHIAVE DEL SISTEMA:
  94. * La timbrata viene associata al cantiere del TIMBRATORE ($userCompanyOrder), NON al cantiere di appartenenza dell'operatore.
  95. * Questo permette ad un operatore registrato su un cantiere di timbrare liberamente su qualsiasi altro timbratore.
  96. *
  97. * FLUSSO OPERATIVO:
  98. * 1. Identifica l'operatore tramite il badge scansionato
  99. * 2. Recupera il cantiere del timbratore corrente ($userCompanyOrder = cantiere dove si trova fisicamente il timbratore)
  100. * 3. Verifica duplicati SOLO per la coppia (operatore + cantiere timbratore) nelle ultime 4 ore
  101. * 4. Salva la timbrata associandola al cantiere del timbratore
  102. *
  103. * ESEMPIO PRATICO MULTI-CANTIERE:
  104. * Operatore "Mario Rossi" registrato su Sovere:
  105. * - Scenario A: Timbra su timbratore di Sovere
  106. * → $userCompanyOrder = Sovere
  107. * → Controllo duplicati su (Mario + Sovere)
  108. * → Timbrata salvata con companyOrder = Sovere
  109. *
  110. * - Scenario B: Timbra su timbratore di Brescia
  111. * → $userCompanyOrder = Brescia
  112. * → Controllo duplicati su (Mario + Brescia) - cantiere diverso, nessun problema!
  113. * → Timbrata salvata con companyOrder = Brescia
  114. *
  115. * - Scenario C: Ritorna su timbratore di Sovere dopo 30 minuti
  116. * → $userCompanyOrder = Sovere
  117. * → Controllo duplicati su (Mario + Sovere) - trova timbrata precedente in 4h!
  118. * → Timbrata BLOCCATA (duplicato)
  119. *
  120. * LOGICA ANTI-DUPLICATO:
  121. * - Per ENTRATE: chiama getStampedWithinFourHoursEntry($userCompanyOrder, $operatorId)
  122. * - Per USCITE: chiama getStampedWithinFourHoursRelease($userCompanyOrder, $operatorId)
  123. * - Se trova duplicato E operatore non è isMulti → blocca la timbrata
  124. * - Se NON trova duplicato OPPURE operatore è isMulti (mensa) → salva la timbrata
  125. *
  126. * GESTIONE ERRORI:
  127. * - Badge non trovato → salva in ErrorStamped
  128. * - Badge non assegnato → salva in ErrorStamped
  129. * - Form non valido → ritorna errore 400
  130. *
  131. * @param array $data Dati form con badge, tipo timbrata (in/out), data
  132. * @param string $typeForm Tipo form (StampedInOutType o StampedMensaType)
  133. * @param string $t Tipo timbrata ('Cantiere' o 'Mensa')
  134. * @return JsonResponse Risposta JSON con esito operazione
  135. * @throws \Exception
  136. */
  137. public function saveTimbrate($data, $typeForm, $t): JsonResponse
  138. {
  139. $form = $this->createForm($typeForm);
  140. $form->submit($data);
  141. if ($form->isSubmitted() && $form->isValid()) {
  142. $actionForm = $data['stamped_in_out[InOut'];
  143. $badgeForm = $data['stamped_in_out[Badge'];
  144. $entityManager = $this->doctrine->getManager();
  145. // PUNTO CHIAVE MULTI-CANTIERE: il companyOrder è del TIMBRATORE, non dell'operatore
  146. // Questo permette di salvare la timbrata sul cantiere dove si trova fisicamente il timbratore
  147. $userCompanyOrder = $this->get('security.token_storage')->getToken()->getUser()->getCompanyOrder();
  148. $assignedBadgeRepository = $entityManager->getRepository(AssignedBadge::class);
  149. $badgeRepository = $entityManager->getRepository(Badge::class);
  150. $stampedRepository = $entityManager->getRepository(Stamped::class);
  151. $errorStamped = new ErrorStamped();
  152. $errorStamped->setCompanyOrder($userCompanyOrder);
  153. $errorStamped->setCodBadge($badgeForm);
  154. $stamped = new Stamped();
  155. /** @var Badge $badge */
  156. $badge = $badgeRepository->findOneBy(['codBadge' => $badgeForm]);
  157. $dataIn = DateTimeUtils::getNow();
  158. $dataOut = DateTimeUtils::getNow();
  159. try {
  160. if ($data['stamped_in_out[date']) {
  161. if ($actionForm === 'in') {
  162. $dataIn = $t === 'Cantiere' ? new \DateTime($data['stamped_in_out[date']) : DateTimeUtils::getNow();
  163. } elseif ($actionForm === 'out') {
  164. $dataOut = $t === 'Cantiere' ? new \DateTime($data['stamped_in_out[date']) : DateTimeUtils::getNow();;
  165. }
  166. }
  167. } catch (Exception $e) {
  168. return new JsonResponse(['error' => 'Non ci sono settate le date di timbrata'], Response::HTTP_BAD_REQUEST);
  169. }
  170. if ($badge) {
  171. $idBadge = $badge->getId();
  172. /** @var AssignedBadge $assignedBadge */
  173. $assignedBadge = $assignedBadgeRepository->findOneBy(['badge' => $idBadge]);
  174. if ($assignedBadge) {
  175. $operatorBadge = $assignedBadge->getOperator()->getId();
  176. $operatorRepository = $entityManager->getRepository(Operator::class);
  177. /** @var Operator $op */
  178. $op = $operatorRepository->findOneBy(['id' => $operatorBadge]);
  179. if ($actionForm === 'out') {
  180. /** @var Stamped $stamped */
  181. $stamped = $stampedRepository->getStamped($userCompanyOrder, $operatorBadge);
  182. if ($stamped) {
  183. // CONTROLLO MULTI-CANTIERE: verifica duplicati solo su questo specifico cantiere
  184. $stampedRecent = $stampedRepository->getStampedWithinFourHoursRelease($userCompanyOrder, $operatorBadge);
  185. if (!$stampedRecent) {
  186. $stamped->setReleaseDate($dataOut);
  187. }
  188. // Non salviamo se esiste un duplicato, ma non bloccamo l'esecuzione
  189. } else {
  190. /** @var Stamped $stampedWithinFourHours */
  191. $stampedWithinFourHours = $stampedRepository->getStampedWithinFourHoursRelease($userCompanyOrder, $operatorBadge);
  192. if ($stampedWithinFourHours and $op->getIsMulti() === false and $this->isGranted("ROLE_MENSA")) {
  193. return new JsonResponse(['Non puoi mangiare in mensa piu volte nel giro di poco'], Response::HTTP_BAD_REQUEST);
  194. }
  195. // Crea una nuova timbrata se non esiste duplicato nelle 4 ore precedenti OPPURE se operatore è multi per mensa
  196. if (!$stampedWithinFourHours || ($op->getIsMulti() === true && $this->isGranted("ROLE_MENSA"))) {
  197. $stamped = new Stamped();
  198. $stamped->setCompanyOrder($userCompanyOrder);
  199. $stamped->setOperator($op);
  200. $stamped->setReleaseDate($dataOut);
  201. $stamped->setStatus(Stamped::STATUS_ERROR);
  202. } else {
  203. // Se esiste un duplicato e non è multi, non creiamo un nuovo record
  204. $stamped = null;
  205. }
  206. }
  207. } elseif ($actionForm === 'in') {
  208. // CONTROLLO MULTI-CANTIERE: verifica duplicati solo su questo specifico cantiere
  209. /** @var Stamped $stampedWithinFourHours */
  210. $stampedWithinFourHours = $stampedRepository->getStampedWithinFourHoursEntry($userCompanyOrder, $operatorBadge);
  211. if ($stampedWithinFourHours and $op->getIsMulti() === false and $this->isGranted("ROLE_MENSA")) {
  212. return new JsonResponse(['Non puoi mangiare in mensa piu volte nel giro di poco'], Response::HTTP_BAD_REQUEST);
  213. }
  214. // Crea una timbrata se non esiste duplicato nelle 4 ore precedenti OPPURE se operatore è multi per mensa
  215. if (!$stampedWithinFourHours || ($op->getIsMulti() === true && $this->isGranted("ROLE_MENSA"))) {
  216. $stamped->setEntryDate($dataIn);
  217. $stamped->setCompanyOrder($userCompanyOrder);
  218. $stamped->setOperator($op);
  219. if ($this->isGranted("ROLE_MENSA")) {
  220. $stamped->setReleaseDate($dataIn);
  221. }
  222. } else {
  223. // Se esiste un duplicato e non è multi, non creiamo un nuovo record
  224. $stamped = null;
  225. }
  226. }
  227. // Salvo solo se stamped non è null (non è un duplicato)
  228. if ($stamped !== null) {
  229. $entityManager->persist($stamped);
  230. $entityManager->flush();
  231. }
  232. } else {
  233. $errorStamped->setNBadge($badge->getNBadge());
  234. if ($actionForm === 'out') {
  235. $errorStamped->setReleaseDate($dataOut);
  236. } elseif ($actionForm === 'in') {
  237. $errorStamped->setEntryDate($dataIn);
  238. if ($this->isGranted("ROLE_MENSA")) {
  239. return new JsonResponse(['Non sei registrato, richiedere al responsabile l inserimento a sistema'], Response::HTTP_BAD_REQUEST);
  240. }
  241. }
  242. $errorStamped->setType(ErrorStamped::TYPE_ERROR_ASSIGNED);
  243. $entityManager->persist($errorStamped);
  244. $entityManager->flush();
  245. }
  246. } else {
  247. if ($actionForm === 'out') {
  248. $errorStamped->setReleaseDate($dataOut);
  249. } elseif ($actionForm === 'in') {
  250. $errorStamped->setEntryDate($dataIn);
  251. if ($this->isGranted("ROLE_MENSA")) {
  252. return new JsonResponse(['Non sei registrato, richiedere al responsabile l inserimento a sistema'], Response::HTTP_BAD_REQUEST);
  253. }
  254. }
  255. $errorStamped->setType(ErrorStamped::TYPE_ERROR_ASSIGNED);
  256. $entityManager->persist($errorStamped);
  257. $entityManager->flush();
  258. }
  259. } else {
  260. return new JsonResponse(['Il form non è valido contattare l amministratore'], Response::HTTP_BAD_REQUEST);
  261. }
  262. if ($stamped && $badge && $this->isGranted("ROLE_MENSA") && $stamped->getId()) {
  263. return new JsonResponse([
  264. 'ok',
  265. 'stampedId' => $stamped->getId(),
  266. 'badgeStamped' => $badge->getNBadge(),
  267. 'codOperator' => $stamped->getOperator()->getId(),
  268. 'dataStamped' => $stamped->getCreatedAt()->format('d-m-Y H:i:s')
  269. ], Response::HTTP_OK);
  270. } else {
  271. return new JsonResponse(['ok'], Response::HTTP_OK);
  272. }
  273. }
  274. /**
  275. * @Route("/delete-multiple-ids", name="delete_multiple_ids", methods={"DELETE"})
  276. * @IsGranted ("ROLE_ADMIN")
  277. *
  278. * @param Request $request
  279. * @return Response
  280. */
  281. public function deleteAjax(Request $request): Response
  282. {
  283. if (!$request->request->get('type')) {
  284. return new JsonResponse(['Error, missing type parameter'], Response::HTTP_BAD_REQUEST);
  285. }
  286. $ids = $request->request->get('ids');
  287. if (!$ids || !is_array($request->request->get('ids'))) {
  288. return new JsonResponse(['Error ids not valid'], Response::HTTP_BAD_REQUEST);
  289. }
  290. switch ($request->request->get('type')) {
  291. case 'stamped':
  292. $result = $this->deleteMultipleIds($ids, Stamped::class);
  293. break;
  294. default:
  295. return new JsonResponse(['Error, this type is not registered'], Response::HTTP_BAD_REQUEST);
  296. }
  297. return $result ? new JsonResponse(['ok'], Response::HTTP_OK) : new JsonResponse(['Error while deleting records'], Response::HTTP_BAD_REQUEST);
  298. }
  299. private function deleteMultipleIds(array $ids, $className)
  300. {
  301. try {
  302. $qb = $this->doctrine->getManager()->createQueryBuilder();
  303. $qb->delete($className, 'e')
  304. ->andWhere('e.id IN (:id)')
  305. ->setParameter('id', $ids);
  306. return $qb->getQuery()->execute();
  307. } catch (Exception $e) {
  308. return false;
  309. }
  310. }
  311. }