src/Controller/BackOffice/AssaysController.php line 196

Open in your IDE?
  1. <?php
  2. namespace App\Controller\BackOffice;
  3. use App\Entity\Assay\AnalysisMethod;
  4. use App\Entity\Assay\Assay;
  5. use App\Entity\Assay\AssayData;
  6. use App\Entity\Assay\AssayReport;
  7. use App\Entity\Assay\Protocol;
  8. use App\Entity\Customer\Customer;
  9. use App\Entity\Customer\CustomerArea;
  10. use App\Entity\QrCode\QrAssayRelation;
  11. use App\Entity\QrCode\QRData;
  12. use App\Entity\Version\APPVersion;
  13. use App\Form\Type\BackOffice\AnalysisMethodSimulationType;
  14. use App\Form\Type\BackOffice\AssayResultType;
  15. use App\Form\Type\BackOffice\AssaySearchFiltersType;
  16. use App\Model\AssayReportStatus;
  17. use App\Model\AssaySearchCriteria;
  18. use App\Model\PaginatedResource;
  19. use App\Model\PaginatedSearchCriteria;
  20. use App\Service\AnalysisService;
  21. use App\Service\AssayReportService;
  22. use App\Service\AssayResultService;
  23. use App\Service\SinaveService;
  24. use App\ViewModel\BackOffice\AssayDataPoints;
  25. use Doctrine\ORM\EntityManagerInterface;
  26. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  27. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  28. use Symfony\Component\Form\FormFactoryInterface;
  29. use Symfony\Component\HttpFoundation\Request;
  30. use Symfony\Component\HttpFoundation\Response;
  31. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  32. use Symfony\Component\Routing\Annotation\Route;
  33. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  34. use Twig\Error\LoaderError;
  35. use Twig\Error\RuntimeError;
  36. use Twig\Error\SyntaxError;
  37. use Psr\Log\LoggerInterface;
  38. /**
  39.  * Class AssaysController
  40.  * @package App\Controller\BackOffice
  41.  * @Route(path="assays")
  42.  */
  43. class AssaysController extends AbstractController
  44. {
  45.     /**
  46.      * @var EntityManagerInterface
  47.      */
  48.     private $entityManager;
  49.     /**
  50.      * @var FormFactoryInterface
  51.      */
  52.     private $formFactory;
  53.     /**
  54.      * @var AnalysisService
  55.      */
  56.     private $analysisService;
  57.     /**
  58.      * @var AssayResultService
  59.      */
  60.     private $assayResultService;
  61.     /**
  62.      * @var SinaveService
  63.      */
  64.     private $sinaveService;
  65.     /**
  66.      * @var AssayReportService
  67.      */
  68.     private $assayReportService;
  69.     /**
  70.      * @var LoggerInterface
  71.      */
  72.     private $logger;
  73.     /**
  74.      * AssaysController constructor.
  75.      * @param EntityManagerInterface $entityManager
  76.      * @param FormFactoryInterface $formFactory
  77.      * @param AnalysisService $analysisService
  78.      * @param AssayResultService $assayResultService
  79.      * @param SinaveService $sinaveService
  80.      * @param AssayReportService $assayReportService
  81.      * @param LoggerInterface $logger
  82.      */
  83.     public function __construct(
  84.         EntityManagerInterface $entityManager,
  85.         FormFactoryInterface $formFactory,
  86.         AnalysisService $analysisService,
  87.         AssayResultService $assayResultService,
  88.         SinaveService $sinaveService,
  89.         AssayReportService $assayReportService,
  90.         LoggerInterface $logger
  91.     ) {
  92.         $this->entityManager $entityManager;
  93.         $this->formFactory $formFactory;
  94.         $this->analysisService $analysisService;
  95.         $this->assayResultService $assayResultService;
  96.         $this->sinaveService $sinaveService;
  97.         $this->assayReportService $assayReportService;
  98.         $this->logger $logger;
  99.     }
  100.     /**
  101.      * @Route(
  102.      *     methods={"GET"},
  103.      *     defaults={"customerProtocols": false}
  104.      * )
  105.      * @Route(
  106.      *     path="/customer",
  107.      *     methods={"GET"},
  108.      *     defaults={"customerProtocols": true},
  109.      *     name="app_backoffice_assays_customer"
  110.      * )
  111.      * @param Request $request
  112.      * @param bool $customerProtocols
  113.      * @return Response
  114.      */
  115.     public function indexAction(Request $requestbool $customerProtocols): Response
  116.     {
  117.         $searchFilterForm $this->formFactory
  118.             ->create(AssaySearchFiltersType::class);
  119.         $searchFilterForm->add("submit"SubmitType::class);
  120.         $searchCriteria = new AssaySearchCriteria($request->query);
  121.         $searchCriteria->setCustomerProtocols($customerProtocols);
  122.         $searchCriteria->setPageSize(PaginatedSearchCriteria::BACKOFFICE_PAGINATION_SIZE);
  123.         $searchFilterForm->handleRequest($request);
  124.         if ($searchFilterForm->isSubmitted() && $searchFilterForm->isValid()) {
  125.             $data $searchFilterForm->getData();
  126.             $searchCriteria->setAssayId($data['assayId']);
  127.             $searchCriteria->setSampleId($data['sampleId']);
  128.             $searchCriteria->setDate($data['date']);
  129.             $searchCriteria->setSku($data['sku']);
  130.             $searchCriteria->setBatch($data['batch']);
  131.             $searchCriteria->setHardwareVersion($data['hardwareVersion']);
  132.             $searchCriteria->setStatus($data['status']);
  133.             $searchCriteria->setResult($data['result']);
  134.         }
  135.         /** @var PaginatedResource $assays */
  136.         $assays $this->entityManager
  137.             ->getRepository(Assay::class)
  138.             ->search($searchCriteria);
  139.         $customer null;
  140.         if ($searchCriteria->getCustomerId() !== null) {
  141.             $customer $this->entityManager
  142.                 ->getRepository(Customer::class)
  143.                 ->find($searchCriteria->getCustomerId());
  144.         }
  145.         $protocol null;
  146.         if ($searchCriteria->getProtocolId() !== null) {
  147.             $protocol $this->entityManager
  148.                 ->getRepository(Protocol::class)
  149.                 ->find($searchCriteria->getProtocolId());
  150.         }
  151.         $qrData null;
  152.         if ($searchCriteria->getQrDataId() !== null) {
  153.             $qrData $this->entityManager
  154.                 ->getRepository(QRData::class)
  155.                 ->find($searchCriteria->getQrDataId());
  156.         }
  157.         return $this->render(
  158.             'backOffice/assays/index.html.twig',
  159.             [
  160.                 'assays' => $assays,
  161.                 'customer' => $customer,
  162.                 'protocol' => $protocol,
  163.                 'qrData' => $qrData,
  164.                 'filterForm' => $searchFilterForm->createView(),
  165.             ]
  166.         );
  167.     }
  168.     /**
  169.      * @param $assayId
  170.      * @return Response
  171.      * @Route(path="/{assayId}", methods={"GET"})
  172.      */
  173.     public function getAction($assayId): Response
  174.     {
  175.         /** @var Assay $assay */
  176.         $assay $this->entityManager
  177.             ->getRepository(Assay::class)
  178.             ->find($assayId);
  179.         if (!$assay) {
  180.             throw $this->createNotFoundException();
  181.         }
  182.         $assayData $this->entityManager
  183.             ->getRepository(AssayData::class)
  184.             ->findByAssay($assay);
  185.         $assayDataPoints AssayDataPoints::create($assayData);
  186.         $assayResultForm $this
  187.             ->createForm(
  188.                 AssayResultType::class,
  189.                 $assay->getResult(),
  190.                 [
  191.                     'action' => $this->generateUrl(
  192.                         'app_backoffice_assayresults_create',
  193.                         ['assayId' => $assay->getAssayId()]
  194.                     ),
  195.                 ]
  196.             )
  197.             ->add('submit'SubmitType::class);
  198.         $analysisMethodSimulationForm $this
  199.             ->createForm(
  200.                 AnalysisMethodSimulationType::class,
  201.                 null,
  202.                 [
  203.                     'analysisMethods' => $assay->getProtocol()->getAnalysisMethods()->toArray(),
  204.                     'action' => $this->generateUrl(
  205.                         'app_backoffice_assays_simulateanalysis',
  206.                         ['assayId' => $assay->getAssayId()]
  207.                     ),
  208.                 ]
  209.             )
  210.             ->add('submit'SubmitType::class);
  211.         $appVersion $this->entityManager
  212.             ->getRepository(APPVersion::class)
  213.             ->findOneBy(["versionCode" => $assay->getSoftwareVersion()]);
  214.         $assayReports $this->entityManager
  215.             ->getRepository(AssayReport::class)
  216.             ->findBy(['assay' => $assay], ['createdAt' => 'desc']);
  217.         return $this->render(
  218.             'backOffice/assays/show.html.twig',
  219.             [
  220.                 'assay' => $assay,
  221.                 'assayData' => $assayData,
  222.                 'assayDataPoints' => $assayDataPoints,
  223.                 'assayResultForm' => $assayResultForm->createView(),
  224.                 'analysisMethodSimulationForm' => $analysisMethodSimulationForm->createView(),
  225.                 'appVersion' => $appVersion $appVersion->getVersionName() : $assay->getSoftwareVersion(),
  226.                 'env' => $this->getParameter('kernel.environment'),
  227.                 'assayReports' => $assayReports,
  228.             ]
  229.         );
  230.     }
  231.     /**
  232.      * @param $assayId
  233.      * @return Response
  234.      * @Route(path="/{assayId}/downloadReport", methods={"GET"})
  235.      */
  236.     public function downloadReport($assayId): Response
  237.     {
  238.         /** @var Assay $assay */
  239.         $assay $this->entityManager
  240.             ->getRepository(Assay::class)
  241.             ->find($assayId);
  242.         if (!$assay) {
  243.             throw $this->createNotFoundException();
  244.         }
  245.         $protocol $assay->getProtocol();
  246.         if (!$protocol || !$protocol->getTest() || !$protocol->getTest()->getCertificateTemplate()) {
  247.             throw $this->createNotFoundException();
  248.         }
  249.         $owner $assay->getUser();
  250.         /** @var CustomerArea $clientArea */
  251.         $clientArea $this->entityManager
  252.             ->getRepository(CustomerArea::class)
  253.             ->getCustomerAreaForUser($owner);
  254.         $customer $this->entityManager
  255.             ->getRepository(Customer::class)
  256.             ->getCustomerForUser($owner);
  257.         /** @var QrAssayRelation $relation */
  258.         $relation $this->entityManager
  259.             ->getRepository(QrAssayRelation::class)
  260.             ->findByAssay($assayId);
  261.         $data null;
  262.         if ($relation) {
  263.             /** @var QRData $data */
  264.             $data $this->entityManager
  265.                 ->getRepository(QRData::class)
  266.                 ->find($relation->getQrDataId());
  267.         }
  268.         try {
  269.             $report $this->assayResultService->renderCertificate($data$assay"en_EN"$customer$clientArea);
  270.             $report->stream();
  271.         } catch (LoaderError|RuntimeError|SyntaxError $e) {
  272.             throw new BadRequestHttpException($e->getMessage());
  273.         }
  274.         return new Response(null200, []);
  275.     }
  276.     /**
  277.      * This is mainly intended for testing purposes.
  278.      * In the long run (when the connection is stable) it should be removed.
  279.      * If applicable, result notification is done automatically when an assay ends.
  280.      * @param $assayId
  281.      * @return Response
  282.      * @throws LoaderError
  283.      * @throws RuntimeError
  284.      * @throws SyntaxError
  285.      * @throws TransportExceptionInterface
  286.      * @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface
  287.      * @Route(
  288.      *     path="/{assayId}/notifySinave",
  289.      *     methods={"GET"}
  290.      * )
  291.      */
  292.     public function notifySinave($assayId): Response
  293.     {
  294.         /** @var Assay $assay */
  295.         $assay $this->entityManager
  296.             ->getRepository(Assay::class)
  297.             ->find($assayId);
  298.         if (!$assay) {
  299.             throw $this->createNotFoundException();
  300.         }
  301.         /** @var QrAssayRelation $relation */
  302.         $relation $this->entityManager
  303.             ->getRepository(QrAssayRelation::class)
  304.             ->findByAssay($assayId);
  305.         if (!$relation) {
  306.             $this->addFlash("warning""Assay not bound to patient data.");
  307.         } else {
  308.             /** @var QRData $data */
  309.             $data $this->entityManager
  310.                 ->getRepository(QRData::class)
  311.                 ->find($relation->getQrDataId());
  312.             $customer $this->entityManager
  313.                 ->getRepository(Customer::class)
  314.                 ->getCustomerForUser($assay->getUser());
  315.             $externalEntityRx $this->sinaveService->submitAssay($assay$customer$data);
  316.             $assay->getResult()->setHealthAuthorityRx($externalEntityRx);
  317.             $this->entityManager->persist($assay);
  318.             $this->entityManager->flush();
  319.         }
  320.         return $this->redirectToRoute(
  321.             'app_backoffice_assays_get',
  322.             [
  323.                 'assayId' => $assay->getAssayId(),
  324.             ]
  325.         );
  326.     }
  327.     /**
  328.      * @param $assayId
  329.      * @return Response
  330.      * @Route(path="/{assayId}/notifyReporter", methods={"POST"})
  331.      */
  332.     public function notifyReporter($assayId): Response
  333.     {
  334.         /** @var Assay $assay */
  335.         $assay $this->entityManager
  336.             ->getRepository(Assay::class)
  337.             ->find($assayId);
  338.         if (!$assay) {
  339.             throw $this->createNotFoundException();
  340.         }
  341.         if (!$assay->getReporter()) {
  342.             $this->addFlash('warning''This assay has no reporter defined');
  343.             return $this->redirectToRoute(
  344.                 'app_backoffice_assays_get',
  345.                 [
  346.                     'assayId' => $assay->getAssayId(),
  347.                 ]
  348.             );
  349.         }
  350.         $report $this->assayReportService->reportAssayAndPersist($assay);
  351.         $reporterName $this->assayReportService->getReporterForIdentifier($assay->getReporter())->getName();
  352.         switch ($report !== null $report->getStatus() : null) {
  353.             case AssayReportStatus::ERROR:
  354.                 $this->addFlash(
  355.                     'danger',
  356.                     sprintf('Assay report to %s failed. Please check below.'$reporterName)
  357.                 );
  358.                 break;
  359.             case AssayReportStatus::UNKNOWN:
  360.                 $this->addFlash(
  361.                     'warning',
  362.                     sprintf('Assay report to %s did not complete. Please check below.'$reporterName)
  363.                 );
  364.                 break;
  365.             case AssayReportStatus::SUCCESS:
  366.                 $this->addFlash(
  367.                     'success',
  368.                     'Assay report to %s completed.'
  369.                 );
  370.                 break;
  371.         }
  372.         return $this->redirectToRoute(
  373.             'app_backoffice_assays_get',
  374.             [
  375.                 'assayId' => $assay->getAssayId(),
  376.             ]
  377.         );
  378.     }
  379.     /**
  380.      * @param Request $request
  381.      * @param $assayId
  382.      * @return Response
  383.      * @Route(path="/{assayId}/simulateAnalysis", methods={"POST"})
  384.      */
  385.     public function simulateAnalysis(Request $request$assayId): Response
  386.     {
  387.         /** @var Assay $assay */
  388.         $assay $this->entityManager
  389.             ->getRepository(Assay::class)
  390.             ->find($assayId);
  391.         if (!$assay) {
  392.             throw $this->createNotFoundException();
  393.         }
  394.         if ($assay->getSkipAnalysis()) {
  395.             throw new BadRequestHttpException("This assay cannot be analyzed");
  396.         }
  397.         $form $this
  398.             ->createForm(
  399.                 AnalysisMethodSimulationType::class,
  400.                 null,
  401.                 [
  402.                     'action' => $this->generateUrl(
  403.                         'app_backoffice_assays_simulateanalysis',
  404.                         ['assayId' => $assay->getAssayId()]
  405.                     ),
  406.                 ]
  407.             )
  408.             ->add('submit'SubmitType::class);
  409.         $form->handleRequest($request);
  410.         if (!$form->isSubmitted() || !$form->isValid()) {
  411.             return $this->forward(
  412.                 AssaysController::class.'::'.'getAction',
  413.                 [
  414.                     'assayId' => $assay->getAssayId(),
  415.                 ]
  416.             );
  417.         }
  418.         /** @var AnalysisMethod $analysisMethod */
  419.         $analysisMethod $form->get('analysisMethod')->getData();
  420.         $assayData $assay->getAssayData();
  421.         $context $this->analysisService->analyzeAssayWithMethod(
  422.             $assay,
  423.             $assayData->toArray(),
  424.             $analysisMethod
  425.         );
  426.         return $this->render(
  427.             'backOffice/assays/simulateAnalysis.html.twig',
  428.             [
  429.                 'assay' => $assay,
  430.                 'assayData' => $assayData,
  431.                 'analysisMethod' => $analysisMethod,
  432.                 'assayResult' => $context->getAssayResult(),
  433.             ]
  434.         );
  435.     }
  436. }