src/Controller/DefaultController.php line 40

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