src\Controller\SolicitacaoController.php line 163

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Solicitacao;
  4. use App\Form\SolicitacaoType;
  5. use App\Entity\User;
  6. use App\Repository\SolicitacaoRepository;
  7. use App\Utils\FormSolicitacaoUtil;
  8. use App\Utils\VerificaRole;
  9. use App\Service\FileUploader;
  10. use App\Service\Watermark;
  11. use App\Service\Mailer;
  12. use App\Service\SpreadsheetGenerator;
  13. use Knp\Component\Pager\PaginatorInterface;
  14. use Psr\Log\LoggerInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\HttpFoundation\RedirectResponse;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpFoundation\Response;
  19. use Symfony\Component\Routing\Annotation\Route;
  20. #[Route('/solicitacao')]
  21. class SolicitacaoController extends AbstractController
  22. {
  23.     #[Route('/pendentes'name'app_solicitacao_pendentes'methods: ['GET'])]
  24.     public function solicitacaoPendentes(
  25.         SolicitacaoRepository $solicitacaoRepository,
  26.         Request $request,
  27.         PaginatorInterface $paginator
  28.     ): Response {
  29.         $qb $solicitacaoRepository->qbSolicitacaoByUserStatus($this->getUser(), Solicitacao::STATUS_PENDENTE);
  30.         $pagination $paginator->paginate($qb$request->query->getInt('page'1), 10);
  31.         return $this->render('solicitacao/index.html.twig', [
  32.             'solicitacoes' => $pagination,
  33.             'nav_active'   => 'Solicitação',
  34.         ]);
  35.     }
  36.     #[Route('/pre-aprovados'name'app_solicitacao_pre_aprovados'methods: ['GET'])]
  37.     public function solicitacaoPreAprovadas(
  38.         SolicitacaoRepository $solicitacaoRepository,
  39.         Request $request,
  40.         PaginatorInterface $paginator
  41.     ): Response {
  42.         $qb $solicitacaoRepository->qbSolicitacaoByUserStatus($this->getUser(), Solicitacao::STATUS_APROVADOR_OK);
  43.         $pagination $paginator->paginate($qb$request->query->getInt('page'1), 10);
  44.         return $this->render('solicitacao/index.html.twig', [
  45.             'solicitacoes' => $pagination,
  46.             'nav_active'   => 'Solicitação',
  47.         ]);
  48.     }
  49.     #[Route('/aprovados'name'app_solicitacao_aprovados'methods: ['GET'])]
  50.     public function solicitacaoAprovadas(
  51.         SolicitacaoRepository $solicitacaoRepository,
  52.         Request $request,
  53.         PaginatorInterface $paginator
  54.     ): Response {
  55.         $qb $solicitacaoRepository->qbSolicitacaoByUserStatus($this->getUser(), Solicitacao::STATUS_ADMINISTRADOR_OK);
  56.         $pagination $paginator->paginate($qb$request->query->getInt('page'1), 10);
  57.         return $this->render('solicitacao/index.html.twig', [
  58.             'solicitacoes' => $pagination,
  59.             'nav_active'   => 'Solicitação',
  60.         ]);
  61.     }
  62.     #[Route('/todos'name'app_solicitacao_todos'methods: ['GET'])]
  63.     public function solicitacaoTodas(
  64.         SolicitacaoRepository $solicitacaoRepository,
  65.         Request $request,
  66.         PaginatorInterface $paginator
  67.     ): Response {
  68.         $qb $solicitacaoRepository->qbSolicitacaoByUser($this->getUser());
  69.         $pagination $paginator->paginate($qb$request->query->getInt('page'1), 10);
  70.         return $this->render('solicitacao/index.html.twig', [
  71.             'solicitacoes' => $pagination,
  72.             'nav_active'   => 'Solicitação',
  73.         ]);
  74.     }
  75.     #[Route('/recusados'name'app_solicitacao_recusados'methods: ['GET'])]
  76.     public function solicitacaoRecusados(
  77.         SolicitacaoRepository $solicitacaoRepository,
  78.         Request $request,
  79.         PaginatorInterface $paginator
  80.     ): Response {
  81.         $qb $solicitacaoRepository->qbRecusados($this->getUser());
  82.         $pagination $paginator->paginate($qb$request->query->getInt('page'1), 10);
  83.         return $this->render('solicitacao/index.html.twig', [
  84.             'solicitacoes' => $pagination,
  85.             'nav_active'   => 'Solicitação',
  86.         ]);
  87.     }
  88.     #[Route('/new'name'app_solicitacao_new'methods: ['GET''POST'])]
  89.     public function new(
  90.         Request $request,
  91.         FormSolicitacaoUtil $formSolicitacaoUtil,
  92.         VerificaRole $verificiaRole,
  93.         SolicitacaoRepository $solicitacaoRepository,
  94.         FileUploader $fileUploader,
  95.         Watermark $watermark,
  96.         Mailer $mailer
  97.     ): Response {
  98.         $solicitacao = new Solicitacao();
  99.         $form $this->createForm(SolicitacaoType::class, $solicitacao);
  100.         $form->handleRequest($request);
  101.         /** @var User $user */
  102.         $user $this->getUser();
  103.         $isSuperUser $this->isGranted('ROLE_SUPER');
  104.         $empresasUsuario $user->getEmpresas();
  105.         if (!$empresasUsuario) {
  106.             throw new \Exception('Usuário sem empresa vinculada.');
  107.         }
  108.         if ($form->isSubmitted() && $form->isValid()) {
  109.             $solicitacao $formSolicitacaoUtil->formatter($solicitacao);
  110.             if ($form->getClickedButton() && 'salvar' === $form->getClickedButton()->getName()) {
  111.                 $solicitacaoRepository->add($solicitacaotrue$this->getUser());
  112.                 if ($isSuperUser) {
  113.                     $watermark->addWatermark($solicitacao$this->getParameter('kernel.project_dir'), $this->getUser());
  114.                 }
  115.                 $mailer->sendMail($solicitacao);
  116.                 $this->addFlash('success''Solicitação adicionada com sucesso.');
  117.                 return $this->redirectToRoute('app_solicitacao_pendentes', [], Response::HTTP_SEE_OTHER);
  118.             }
  119.             if ($form->getClickedButton() && 'recorrente' === $form->getClickedButton()->getName()) {
  120.                 $solicitacaoRepository->add($solicitacaotrue$this->getUser());
  121.                 if ($isSuperUser) {
  122.                     $watermark->addWatermark($solicitacao$this->getParameter('kernel.project_dir'), $this->getUser());
  123.                 } else {
  124.                     $solicitacao->setAprovador($this->getUser());
  125.                     $mailer->sendMail($solicitacao);
  126.                 }
  127.                 $this->addFlash('success''Solicitação adicionada com sucesso.');
  128.             }
  129.         }
  130.         return $this->renderForm('solicitacao/new.html.twig', [
  131.             'solicitacao' => $solicitacao,
  132.             'form'        => $form,
  133.             'nav_active'  => 'Solicitação',
  134.         ]);
  135.     }
  136.     #[Route('/checker'name'app_solicitacao_recorrente'methods: ['POST'])]
  137.     public function checker(Request $requestSolicitacaoRepository $solicitacaoRepository): Response
  138.     {
  139.         $post_data json_decode($request->getContent(), true) ?? [];
  140.         $numeroLancamento $post_data['numeroLancamento'] ?? null;
  141.         if ($numeroLancamento === null) {
  142.             return $this->json(false);
  143.         }
  144.         $isChecked $solicitacaoRepository->findBy(['numeroLancamento' => $numeroLancamento]);
  145.         return $this->json(count($isChecked) > 0);
  146.     }
  147.     #[Route('/empresa/{empresaId}/subempresa/{subEmpresaId}/solicitacao/{id}'name'app_solicitacao_show'methods: ['GET'])]
  148.     public function show(
  149.         SolicitacaoRepository $solicitacaoRepository,
  150.         Solicitacao $solicitacao,
  151.         int $empresaId,
  152.         int $subEmpresaId
  153.     ): Response {
  154.         /** @var User $user */
  155.         $user $this->getUser();
  156.         $hasAccess false;
  157.         if ($this->isGranted('ROLE_SUPER')) {
  158.             $hasAccess true;
  159.         } else {
  160.             foreach ($user->getSubEmpresas() as $subEmpresa) {
  161.                 if ($subEmpresa->getId() === $subEmpresaId) {
  162.                     $hasAccess true;
  163.                     break;
  164.                 }
  165.             }
  166.         }
  167.         if ($solicitacao->getUsuario() === $user) {
  168.             $hasAccess true;
  169.         }
  170.         if (!$hasAccess) {
  171.             throw $this->createAccessDeniedException('Você não tem permissão para acessar as solicitações desta empresa.');
  172.         }
  173.         $duplicidadeList $solicitacaoRepository->findBy([
  174.             'numeroLancamento' => $solicitacao->getNumeroLancamento(),
  175.         ]);
  176.         $duplicidade count($duplicidadeList) > 1;
  177.         return $this->render('solicitacao/show.html.twig', [
  178.             'solicitacao' => $solicitacao,
  179.             'nav_active'  => 'Solicitação',
  180.             'duplicidade' => $duplicidade,
  181.         ]);
  182.     }
  183.     #[Route('/{id}/edit'name'app_solicitacao_edit'methods: ['GET''POST'])]
  184.     public function edit(
  185.         Request $request,
  186.         Solicitacao $solicitacao,
  187.         SolicitacaoRepository $solicitacaoRepository
  188.     ): Response {
  189.         if (
  190.             $solicitacao->getStatus() !== Solicitacao::STATUS_PENDENTE
  191.             || $solicitacao->getUsuario() !== $this->getUser()
  192.         ) {
  193.             return $this->redirectToRoute('app_solicitacao_redirect');
  194.         }
  195.         $form $this->createForm(SolicitacaoType::class, $solicitacao);
  196.         $form->handleRequest($request);
  197.         if ($form->isSubmitted() && $form->isValid()) {
  198.             $solicitacaoRepository->add($solicitacaotrue$this->getUser());
  199.             return $this->redirectToRoute('app_solicitacao_pendentes', [], Response::HTTP_SEE_OTHER);
  200.         }
  201.         return $this->renderForm('solicitacao/edit.html.twig', [
  202.             'solicitacao' => $solicitacao,
  203.             'form'        => $form,
  204.             'nav_active'  => 'Solicitação',
  205.         ]);
  206.     }
  207.     #[Route('/aprovar/{id}'name'app_solicitacao_aprovar'methods: ['POST'])]
  208.     public function aprovar(
  209.         Request $request,
  210.         Solicitacao $solicitacao,
  211.         SolicitacaoRepository $solicitacaoRepository,
  212.         Watermark $watermark,
  213.         Mailer $mailer,
  214.         LoggerInterface $logger
  215.     ): Response {
  216.         $isSuperUser $this->isGranted('ROLE_SUPER');
  217.         $status $isSuperUser Solicitacao::STATUS_ADMINISTRADOR_OK Solicitacao::STATUS_APROVADOR_OK;
  218.         // calculo os redirects de saída (e referer) logo no início
  219.         $empresaId   $solicitacao->getEmpresa()?->getId();
  220.         $subEmpresaId $solicitacao->getSubEmpresa()?->getId();
  221.         $referer     = (string) $request->headers->get('referer');
  222.         try {
  223.             if ($this->isCsrfTokenValid('aprovar' $solicitacao->getId(), (string) $request->request->get('_token'))) {
  224.                 $now = new \DateTimeImmutable('now');
  225.                 $solicitacao->setStatus($status);
  226.                 $solicitacao->setUpdatedAt($now);
  227.                 $solicitacao->setApprovedAt($now);
  228.                 $comentario $request->request->get('comentario');
  229.                 if (is_string($comentario) && trim($comentario) !== '') {
  230.                     $solicitacao->setComentario(trim($comentario));
  231.                 }
  232.                 if ($isSuperUser) {
  233.                     $solicitacao->setAdministrador($this->getUser());
  234.                 } else {
  235.                     $solicitacao->setAprovador($this->getUser());
  236.                 }
  237.                 // 1) persiste primeiro (minimiza risco de 500 por side-effects depois)
  238.                 $solicitacaoRepository->update($solicitacaotrue);
  239.                 // 2) watermark (só se SUPER) – isolado
  240.                 if ($isSuperUser) {
  241.                     try {
  242.                         $watermark->addWatermark($solicitacao$this->getParameter('kernel.project_dir'), $this->getUser());
  243.                     } catch (\Throwable $e) {
  244.                         $logger->error('Erro ao gerar watermark da solicitacao ' $solicitacao->getId() . ': ' $e->getMessage(), ['exception' => $e]);
  245.                         $this->addFlash('error''Aprovado, mas ocorreu um erro ao gerar o carimbo d’água.');
  246.                     }
  247.                 }
  248.                 // 3) e-mail – isolado
  249.                 try {
  250.                     $mailer->sendMail($solicitacao);
  251.                 } catch (\Throwable $e) {
  252.                     $logger->error('Erro ao enviar e-mail da solicitacao ' $solicitacao->getId() . ': ' $e->getMessage(), ['exception' => $e]);
  253.                     $this->addFlash('error''Aprovado, mas ocorreu um erro ao enviar as notificações.');
  254.                 }
  255.                 $this->addFlash('success'$isSuperUser 'Solicitação Aprovada com sucesso.' 'Solicitação Pré-Aprovada com sucesso.');
  256.             } else {
  257.                 $this->addFlash('error''Token inválido. Recarregue a página e tente novamente.');
  258.             }
  259.         } catch (\Throwable $e) {
  260.             // Qualquer erro inesperado vira flash + log, sem 500
  261.             $logger->error('Falha no fluxo de aprovação da solicitacao ' $solicitacao->getId() . ': ' $e->getMessage(), ['exception' => $e]);
  262.             $this->addFlash('error''Não foi possível concluir a aprovação: ' $e->getMessage());
  263.         }
  264.         // Redirect final (SUPER → empresa; aprovador → subempresa). Fallback: referer.
  265.         if ($isSuperUser && $empresaId) {
  266.             return $this->redirect(sprintf('/aprovador/empresa/%d'$empresaId));
  267.         }
  268.         if (!$isSuperUser && $subEmpresaId) {
  269.             return $this->redirectToRoute(
  270.                 'app_aprovador_subempresa_status',
  271.                 ['subEmpresaId' => $subEmpresaId],
  272.                 Response::HTTP_SEE_OTHER
  273.             );
  274.         }
  275.         // fallback absoluto
  276.         return $referer ? new RedirectResponse($referer) : $this->redirectToRoute('app_solicitacao_pendentes');
  277.     }
  278.     #[Route('/recusar/{id}'name'app_solicitacao_recusar'methods: ['POST'])]
  279.     public function recusar(
  280.         Request $request,
  281.         Solicitacao $solicitacao,
  282.         SolicitacaoRepository $solicitacaoRepository,
  283.         LoggerInterface $logger
  284.     ): Response {
  285.         $isSuperUser $this->isGranted('ROLE_SUPER');
  286.         $empresaId    $solicitacao->getEmpresa()?->getId();
  287.         $subEmpresaId $solicitacao->getSubEmpresa()?->getId();
  288.         $referer      = (string) $request->headers->get('referer');
  289.         try {
  290.             if ($this->isCsrfTokenValid('recusar' $solicitacao->getId(), (string) $request->request->get('_token'))) {
  291.                 $now = new \DateTimeImmutable('now');
  292.                 $solicitacao->setUpdatedAt($now);
  293.                 $solicitacao->setRecusedAt($now);
  294.                 $solicitacao->setRecusador($this->getUser());
  295.                 $solicitacao->setStatus(
  296.                     $isSuperUser Solicitacao::STATUS_ADMINISTRADOR_RECUSADO Solicitacao::STATUS_APROVADOR_RECUSADO
  297.                 );
  298.                 $solicitacao->setRecusa((string) $request->request->get('recusa'));
  299.                 $solicitacaoRepository->update($solicitacaotrue);
  300.                 $this->addFlash('success''Solicitação recusada com sucesso.');
  301.             } else {
  302.                 $this->addFlash('error''Token inválido. Recarregue a página e tente novamente.');
  303.             }
  304.         } catch (\Throwable $e) {
  305.             $logger->error('Falha ao recusar solicitacao ' $solicitacao->getId() . ': ' $e->getMessage(), ['exception' => $e]);
  306.             $this->addFlash('error''Não foi possível recusar: ' $e->getMessage());
  307.         }
  308.         if ($isSuperUser && $empresaId) {
  309.             return $this->redirect(sprintf('/aprovador/empresa/%d'$empresaId));
  310.         }
  311.         if (!$isSuperUser && $subEmpresaId) {
  312.             return $this->redirectToRoute(
  313.                 'app_aprovador_subempresa_status',
  314.                 ['subEmpresaId' => $subEmpresaId],
  315.                 Response::HTTP_SEE_OTHER
  316.             );
  317.         }
  318.         return $referer ? new RedirectResponse($referer) : $this->redirectToRoute('app_solicitacao_pendentes');
  319.     }
  320.     #[Route('/{id}'name'app_solicitacao_delete'methods: ['POST'])]
  321.     public function delete(
  322.         Request $request,
  323.         Solicitacao $solicitacao,
  324.         SolicitacaoRepository $solicitacaoRepository
  325.     ): Response {
  326.         if ($this->isCsrfTokenValid('delete' $solicitacao->getId(), (string) $request->request->get('_token'))) {
  327.             $solicitacaoRepository->remove($solicitacaotrue);
  328.         }
  329.         return $this->redirectToRoute('app_solicitacao_pendentes', [], Response::HTTP_SEE_OTHER);
  330.     }
  331.     #[Route('/pendentes-count/{empresa}/{status}/{tipo}'methods: ['GET'], defaults: ['empresa' => 'any''tipo' => 'any'])]
  332.     public function pendentsCount(
  333.         Request $request,
  334.         SolicitacaoRepository $solicitacaoRepository,
  335.         $empresa,
  336.         $status,
  337.         $tipo
  338.     ): Response {
  339.         if ($empresa !== 'any' && $status !== 'any' && $tipo !== 'any') {
  340.             return $this->json($solicitacaoRepository->count(['empresa' => $empresa'status' => $status'tipo' => $tipo]));
  341.         }
  342.         if ($empresa !== 'any' && $status !== 'any') {
  343.             return $this->json($solicitacaoRepository->count(['empresa' => $empresa'status' => $status]));
  344.         }
  345.         if ($empresa === 'any' && $tipo !== 'any') {
  346.             return $this->json($solicitacaoRepository->count(['status' => $status'tipo' => $tipo]));
  347.         }
  348.         return $this->json(['error' => 'Invalid parameters'], Response::HTTP_BAD_REQUEST);
  349.     }
  350.     /**
  351.      * @Route("/report/spreadsheet", name="app_solicitacao_report", methods={"GET"})
  352.      */
  353.     public function report(Request $requestSpreadsheetGenerator $spreadsheetGenerator): Response
  354.     {
  355.         $startDate  $request->query->get('start_date');
  356.         $endDate    $request->query->get('end_date');
  357.         $reportType $request->query->get('report_type');
  358.         try {
  359.             $response $spreadsheetGenerator->generateExcel($startDate$endDate$reportType);
  360.         } catch (\Exception $e) {
  361.             $this->addFlash('error''Ocorreu um erro ao gerar o relatório: ' $e->getMessage());
  362.             return new RedirectResponse((string) $request->headers->get('referer'));
  363.         }
  364.         return $response;
  365.     }
  366. }