src/Controller/FpsController.php line 423

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Symfony\Component\HttpFoundation\Request;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\HttpFoundation\JsonResponse;
  6. use Symfony\Component\Process\Process;
  7. use FOS\RestBundle\Controller\Annotations\Get;
  8. use FOS\RestBundle\Controller\Annotations\Post;
  9. use FOS\RestBundle\Controller\Annotations\Patch;
  10. use FOS\RestBundle\Controller\Annotations\View;
  11. use FOS\RestBundle\Controller\Annotations\QueryParam;
  12. use FOS\RestBundle\Request\ParamFetcher;
  13. use Symfony\Component\HttpFoundation\StreamedResponse;
  14. use App\Exyzt\JwtAuthentificationBundle\Lib\Util;
  15. use App\Exyzt\JwtAuthentificationBundle\Services\TokenService;
  16. use App\Service\FPS\CouchConnectionService as couchDB;
  17. use App\Service\FPS\PlateValidatorService;
  18. use App\Service\FPS\CalculFpsService;
  19. use App\Service\FPS\FpsService;
  20. use App\Service\FPS\FpsCsvService;
  21. use App\Entity\Fps;
  22. use App\Entity\ActivityFPS;
  23. use App\Entity\Payment;
  24. use App\Entity\Claim;
  25. use App\Entity\FpsComment;
  26. use JsonSchema\Validator;
  27. use JsonSchema\Constraints\Constraint;
  28. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
  29. use App\Exyzt\RESTBundle\Controller\AbstractRESTController;
  30. use App\Repository\FpsRepository;
  31. use App\Repository\ClaimRepository;
  32. use App\Log\CustomLogger;
  33. use Doctrine\Persistence\ManagerRegistry;
  34. class FpsController extends AbstractRESTController
  35. {
  36.     /**
  37.      * Calcul le montant du FPS en POST
  38.      * @Post("/api/{cityId}/fine-values/v1")
  39.      * @Security("is_granted('ROLE_PDA_FPS')")
  40.      *
  41.      */
  42.     public function postCalculFPSAction(Request $requestcouchDB $couchDBCalculFpsService $calculFPSPlateValidatorService $plateValidatorFpsService $serviceFps){
  43.         
  44.         $logFile 'FPS-FINE-VALUES-' $request->get('cityId') . '.log';
  45.         $logger = new CustomLogger('fine-values');
  46.         $logger->setFileOptions($logFile30);
  47.         $data =  Util::getDataRequest($request);
  48.         $logger->info("*** CALCUL DE PRIX "$data);
  49.         
  50.         $user $this->getUser();
  51.         if($user->getCodeVille() != $request->get('cityId')){
  52.             $logger->error("Invalid cityId", ["Request=".$request->get('cityId'), "UserToken=".$user->getCodeVille()]);
  53.             $logger->info("* FIN DU CALCUL");
  54.             $errors[0]=array("code"=>"401","type"=>"Unauthorized");
  55.             return new JsonResponse(array("errors"=>$errors), Response::HTTP_UNAUTHORIZED,array(),false);
  56.         }
  57.         $client $couchDB->getClient("city_".$request->get('cityId')."_ref_fps_metadata");
  58.         if(isset($data['zoneId'])){
  59.             $docName 'ZONE_'.$data['zoneId'];
  60.         }
  61.         elseif(isset($data['parkId'])){
  62.             $docName 'PARK_'.$data['parkId'];
  63.         }
  64.         try {
  65.             $doc $client->getDoc($docName);
  66.         }
  67.         catch(\Exception $e){
  68.             $logger->error("Zone tarifaire ou parc inconnu", [$e]);
  69.             $logger->info("* FIN DU CALCUL");
  70.             $errors[0] = array("code"=>"1004","type"=>"Zone tarifaire inconnue");
  71.             return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  72.         }
  73.         if(substr($docName,0,4) === "ZONE" && property_exists($doc'error')){
  74.             $logger->error("Zone tarifaire inconnue"json_decode($doc->errortrue));
  75.             $logger->info("* FIN DU CALCUL");
  76.             $errors[0]=array("code"=>"1004","type"=>"Zone tarifaire inconnue");
  77.             return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  78.         }
  79.         
  80.         if(substr($docName,0,4) === "PARK" && property_exists($doc'error')){
  81.             $logger->error("Parc inconnu"json_decode($doc->errortrue));
  82.             $logger->info("* FIN DU CALCUL");
  83.             
  84.             $errors[0]=array("code"=>"1014","type"=>"Parc inconnu");
  85.             return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  86.         }
  87.         $prices json_decode(json_encode($doc->prices), true);
  88.         $timeReduced property_exists($doc'timeReduced') ? json_decode(json_encode($doc->timeReduced), true): null;
  89.         $timeValidity json_decode(json_encode($doc->timeValidity), true);
  90.         $timeZone property_exists($doc'timeZone') ? json_decode(json_encode($doc->timeZone), true): 'Europe/Paris';
  91.         date_default_timezone_set($timeZone);
  92.         $freeDay json_decode(json_encode($doc->freeDay), true);
  93.         $week json_decode(json_encode($doc->week), true);
  94.         $gracePeriod property_exists($doc'gracePeriod') ? json_decode(json_encode($doc->gracePeriod), true): 0.00;
  95.         $gracePeriodMax property_exists($doc'gracePeriodMax') ? json_decode(json_encode($doc->gracePeriodMax), true): 0;
  96.         $dataForSchema json_decode(json_encode($data), FALSE);
  97.         $schema $serviceFps->getSchema(realpath(__DIR__.'/../Schemas/calculFps.json'));
  98.         $validator = new Validator;
  99.         $validator->coerce($dataForSchema$schema);
  100.         if ($validator->isValid()) {
  101.             if($data['licensePlate']['plateCountry'] === 'FR'){
  102.                 $plateValid $plateValidator->analysePlate($data['licensePlate']);
  103.                 if (sizeof($plateValid['error']) > 0) {
  104.                     $logger->error("Erreur lors de la validation de plaque d'immatriculation"$plateValid['error']);
  105.                     $logger->info("* FIN DU CALCUL");
  106.                     
  107.                     return new JsonResponse(array("errors"=>$plateValid['error']), 422, array(), false);
  108.                 } else {
  109.                     $data['licensePlate'] = $plateValid['licensePlate'];
  110.                 }
  111.             }
  112.             else{
  113.                 $data['licensePlate']['plate'] =  strtoupper(str_replace(array(' ','-'), ''$data['licensePlate']['plate']));
  114.             }
  115.             $statementDatetimeString=$data['statementDatetime'];
  116.             $statementDatetime=new \DateTime($statementDatetimeString);
  117.             $statementDatetime2 = clone $statementDatetime;
  118.             if($statementDatetime2->sub(new \DateInterval('PT10M')) > new \DateTime('now')){
  119.                 $logger->error("Date de constatation invalide", [$data['statementDatetime']]);
  120.                 $logger->info("* FIN DU CALCUL");
  121.                 $errors[0]=array("code"=>"1005","type"=>"Date de constatation invalide");
  122.                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  123.            }
  124.             $response $calculFPS->getCalculFps($client$data$week$timeValidity$timeZone$freeDay$prices$timeReduced$gracePeriod$gracePeriodMax);
  125.             
  126.             $logger->info("RESPONSE OK"$response);
  127.             $logger->info("* FIN DU CALCUL");
  128.             
  129.             return new JsonResponse($response,Response::HTTP_OK,array(),false);
  130.         }
  131.         else {
  132.             $logger->error("Echec de validation des champs fournis"$validator->getErrors());
  133.             $logger->info("* FIN DU CALCUL");
  134.             
  135.             $errors[0]=array("code"=>"1001","type"=>"Structure de la requête invalide");
  136.             return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  137.         }
  138.     }
  139.     /**
  140.      * Créer un FPS
  141.      * @View()
  142.      * @Post("/api/{cityId}/fines/v1")
  143.      * @Security("is_granted('ROLE_PDA_FPS') or is_granted('ROLE_RAPO_UPDATE') or is_granted('ROLE_SVC_FPS_CREATE')")
  144.      *
  145.     */
  146.     public function postFPSAction(Request $request$cityIdTokenService $tokenPlateValidatorService $plateValidatorFPSservice $serviceFpsManagerRegistry $registry){
  147.         $user $this->getUser();
  148.         if ( $user->getCodeVille() != $request->get('cityId')){
  149.            $errors[0] = array("code"=>"401","type"=>"Unauthorized");
  150.            return new JsonResponse(array("errors"=>$errors), Response::HTTP_UNAUTHORIZED,array(),false);
  151.         }
  152.         $data =  Util::getDataRequest($request);
  153.         if (substr($data['fineLegalId'],0,14) !== $request->get('cityId') ){
  154.             $errors[0] = array("code"=>"401","type"=>"Unauthorized");
  155.             return new JsonResponse(array("errors"=>$errors), Response::HTTP_UNAUTHORIZED,array(),false);
  156.         }
  157.         if ($data['type']==='INITIAL'){
  158.             // INITIAL should not have 'claims', 'surcharge' should not be gretter than 0, 'finePrice' should not be 0 (== instead of === in case of value is passed as string)
  159.             if ( isset($data['claims']) || (isset( $data['surcharge'] ) && $data['surcharge'] > 0) || $data['finePrice'] == 0) {
  160.                 $errors[0] = array( "code" => "1001""type" => "Structure de la requête invalide" );
  161.                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  162.             }
  163.         }
  164.         if ( intval($data['finePrice']) < 0) {
  165.             $errors[0] = array( "code" => "1001""type" => "Structure de la requête invalide" );
  166.             return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  167.         }
  168.         $dataForSchema json_decode(json_encode($data), FALSE);
  169.         $schema $serviceFps->getSchema(realpath(__DIR__.'/../Schemas/fpsCreate.json'));
  170.         $validator = new Validator;
  171.         $validator->validate($dataForSchema$schemaConstraint::CHECK_MODE_COERCE_TYPES);
  172.         if ($validator->isValid()) {
  173.             $em $registry->getManagerself::_PREFIX_EM.$cityId);
  174.             /** @var FpsRepository $repository*/
  175.             $repository $registry->getRepository('App:Fps'self::_PREFIX_EM.$cityId);
  176.             $fpsEntity $repository->findOneBy( ["fineLegalId" => $data['fineLegalId']] );
  177.             if ( $fpsEntity ){
  178.                 $errors[0] = array("code" => "1003","type" => "Numéro de FPS déjà existant");
  179.                 return new JsonResponse( array("errors"=>$errors ), 422 ,array(),false);
  180.             }
  181.             if ( strlen$data['fineLegalId']) != 26 ){
  182.                 $errors[0] = array("code" => "1002","type" => "Numéro de FPS invalide" );
  183.                 return new JsonResponse( array("errors"=>$errors ), 422 ,array(),false);
  184.             }
  185.             if ( isset( $data['fineShortId'] ) ){
  186.                 $exist $repository->fineShortIdAvailable$data['fineShortId'], $data['cityId']);
  187.                 if ( $exist){
  188.                     $errors[0] = array("code"=>"1101","type"=>"Numéro de FineShortId non valide");
  189.                     return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  190.                 }
  191.             }
  192.             $conn $registry->getConnection(self::_PREFIX_CONNECT.$cityId);
  193.             $conn->beginTransaction(); // suspend auto-commit
  194.             try {
  195.                 $fps = new Fps;
  196.                 $fps->setOriginalFpsJson$request->getContent() );
  197.                 $fps->setFineLegalId$data['fineLegalId'] );
  198.                 $dateModified = new \DateTime('now');
  199.                 $dateModifiedRCF3339 $dateModified->format(\DateTime::ATOM);
  200.                 $fps->setDateModified( new \DateTime$dateModifiedRCF3339 ) );
  201.                 $fps->setType($data['type']);
  202.                 $fps->setParent(array_key_exists('parent',$data) ? $data['parent'] : null);
  203.                 $fps->setRootFineLegalId(array_key_exists('rootFineLegalId',$data) ? $data['rootFineLegalId'] : null);
  204.                 $fps->setAuthId($data['authId']);
  205.                 $fps->setAgentId($data['agent']['agentId']);
  206.                 $fps->setCityId($request->get('cityId'));
  207.                 $fps->setZoneId(array_key_exists('zoneId',$data) ? $data['zoneId'] : null);
  208.                 $fps->setParkId(array_key_exists('parkId',$data) ? $data['parkId'] : null);
  209.                 $fps->setNotificationAuthority($data['notificationAuthority']);
  210.                 $fps->setPaymentStatus($data['paymentStatus']);
  211.                 $fps->setName($data['agent']['name']);
  212.                 $fps->setStatementDatetime(new \DateTime($data['statementDatetime']));
  213.                 $fps->setTerminalId($data['terminalId']);
  214.                 if($data['licensePlate']['plateCountry'] === 'FR'){
  215.                     $plateValid $plateValidator->analysePlate$data['licensePlate'] );
  216.                     if (sizeof($plateValid['error']) > 0) {
  217.                         return new JsonResponse(array("errors"=>$plateValid['error']), 422, array(), false);
  218.                     } else {
  219.                         $data['licensePlate'] = $plateValid['licensePlate'];
  220.                     }
  221.                 }
  222.                 else{
  223.                     $data['licensePlate']['plate'] =  strtoupper(str_replace(array(' ','-'), ''$data['licensePlate']['plate']));
  224.                 }
  225.                 $fps->setPlate$data['licensePlate']['plate'] );
  226.                 $fps->setPlateCountry$data['licensePlate']['plateCountry'] );
  227.                 $fps->setBrand($data['vehicle']['brand']);
  228.                 $fps->setModel(array_key_exists('model',$data['vehicle']) ? $data['vehicle']['model'] : null);
  229.                 $fps->setFinePrice($data['finePrice']);
  230.                 $fps->setValidityDatetime(new \DateTime($data['validityDatetime']));
  231.                 $fps->setReducedFinePrice(array_key_exists('reducedFinePrice',$data) ? $data['reducedFinePrice'] : null);
  232.                 $fps->setReducedDatetime(array_key_exists('reducedDatetime',$data) ? new \DateTime($data['reducedDatetime']) : null);
  233.                 $fps->setAuthTransfertDateTime(array_key_exists('authTransfertDateTime',$data) ? new \DateTime($data['authTransfertDateTime']) : null);
  234.                 $fps->setNotificationDatetime(array_key_exists('notificationDatetime',$data) ? new \DateTime($data['notificationDatetime']) : null);
  235.                 $fps->setPricingCategory(array_key_exists('pricingCategory',$data['licensePlate']) ? $data['licensePlate']['pricingCategory'] : null);
  236.                 $fps->setVehiculeCategory(array_key_exists('vehiculeCategory',$data['vehicle']) ? $data['vehicle']['vehiculeCategory'] : null);
  237.                 $fps->setOffender(array_key_exists('offender',$data) ? $data['offender'] : null);
  238.                 $fps->setSurcharge(array_key_exists('surcharge',$data) ? $data['surcharge'] : null);
  239.                 $fps->setTerminalType(array_key_exists('terminalType'$data) ? $data['terminalType'] : null);
  240.                 if(array_key_exists('claims',$data)){
  241.                     foreach($data['claims'] as $c){
  242.                         $claim = new Claim;
  243.                         $claim->setClaimStatus($c['claimStatus']);
  244.                         $claim->setClaimType($c['claimType']);
  245.                         if(isset($c['claimReason'])){
  246.                             $claim->setClaimReason($c['claimReason']);
  247.                         }
  248.                         $claim->setDateModified(new \DateTime($c['dateModified']));
  249.                         $claim->setFps($fps);
  250.                         $fps->addClaim($claim);
  251.                         $em->persist($claim);
  252.                     }
  253.                 }
  254.                 if(!empty($data['comments'])) {
  255.                     foreach($data['comments'] as $com) {
  256.                         // Create comment
  257.                         $comment = new FpsComment;
  258.                         $comment->setAgentId($com['agent']['agentId']);
  259.                         $comment->setName($com['agent']['name']);
  260.                         $comment->setText(trim($com['text']));
  261.                         $comment->setCreationDatetime(new \Datetime($com['creationDatetime']));
  262.                         $comment->setFineId($fps);
  263.                         // Add comment to FPS
  264.                         $fps->addComment($comment);
  265.                         // Persist comment
  266.                         $em->persist($comment);
  267.                     }
  268.                 }
  269.                 if ($fps->getType() === 'CORRECTION' ){
  270.                     $fpsParent $repository->findOneBy(['fineLegalId' => $fps->getParent() ]);
  271.                     if ($fpsParent == null){
  272.                         $errors[0] = array( "code" => "1001""type" => "Structure de la requête invalide" );
  273.                         return new JsonResponse( array( "errors"=>$errors ), 422 , array(), false );
  274.                     }
  275.                     else {
  276.                         $fpsParent->setDateModified(new \Datetime('now'));
  277.                         $em->persist($fpsParent);
  278.                     }
  279.                 }
  280.                 $idUser $token->getUserId$request );
  281.                 $activity = new ActivityFPS;
  282.                 $activity->setIdUser$idUser );
  283.                 $activity->setMethod('POST');
  284.                 $activity->setBody$request->getContent() );
  285.                 $activity->setFps$fps );
  286.                 $em->persist$activity );
  287.                 $em->persist$fps );
  288.                 $em->flush();
  289.                 $fineId $fps->getFineId();
  290.                 if ( isset( $data['fineShortId']) ){
  291.                     $fineShortId $data['fineShortId'];
  292.                 }else {
  293.                     $fineShortId $serviceFps->createShortId($fineId);
  294.                 }
  295.                 $fps->setFineShortId$fineShortId );
  296.                 $em->persist$fps );
  297.                 $em->flush();
  298.                 $em->refresh$fps );
  299.                 $conn->commit();
  300.             } catch (\Throwable $t) {
  301.                 $conn->rollBack();
  302.                 $errorInfo array_values(array_filter$t->getPrevious()->errorInfo, fn($value$key) => str_contains($value'ERROR'), ARRAY_FILTER_USE_BOTH));
  303.                 $message array_values(array_filter(explode("\n"$errorInfo[0]), fn($value$key) => str_contains($value'ERROR'), ARRAY_FILTER_USE_BOTH));
  304.                 $errors[0] = array("code" => "1003""type" => "Numéro de FPS déjà existant""message" => count($message) > $message[0] : "Une erreur est survenue lors de l'enregistrement du FPS");
  305.                 return new JsonResponse( array("errors"=>$errors ), 422 ,array(),false);
  306.             }
  307.             try {
  308.                 $fpsCree $fps->getFormat();
  309.                 $codeWorkSpace $request->get('cityId');
  310.                 $links Util::serialize$fps$codeWorkSpace, array('self'), true$expand "");
  311.                 $jsonResponse = new JsonResponsejson_encode$fpsCree ), Response::HTTP_CREATED, array( "Location" => json_decode$links)->{'_links'}->self->href ), true );
  312.                 $process = new Process(['sh'$_ENV['APP_DIR'].'/scripts/FPS/send-fps.sh']);
  313.                 $process->start();
  314.                 return $jsonResponse;
  315.             } catch (\Exception $e) {
  316.                 return  $e->getMessage();
  317.             }
  318.         }
  319.         else {
  320.             $errors[0] = array( "code" => "1001""type" => "Structure de la requête invalide" );
  321.             return new JsonResponse( array( "errors"=>$errors ), 422 , array(), false );
  322.         }
  323.     }
  324.      /**
  325.      * Récupère une liste de FPS en fonction de criteres en POST
  326.      * @Post("/api/{cityId}/fines-search/v1")
  327.      * @Security("is_granted('ROLE_PC_FPS') or is_granted('ROLE_SVC_FPS_READ')")
  328.      */
  329.     public function postFPSListAction(Request $request$cityIdFPSService $serviceFps){
  330.         
  331.         $maxRecordsDefault 25;
  332.         $pageDefault 1;
  333.         // get and json decode request
  334.         $search = empty(Util::getDataRequest($request)) ? ["maxRecords" => $maxRecordsDefault] : Util::getDataRequest($request);
  335.         $user $this->getUser();
  336.         
  337.         $verifications $serviceFps->verificationsAuthorizationPlateFormatAndFormatJson($user->getCodeVille(),$cityId,$search );  
  338.         if ( sizeof($verifications['error']) > 0) { 
  339.             return new JsonResponse($verifications['error'], 422 ,array(),false);
  340.         }
  341.         else {
  342.             //replace search by search after verifications
  343.             $search $verifications['search'];
  344.             // integral true for a complete FPS json
  345.             $integral = ($user->hasRole('ROLE_FPS_COMPLETE') && $request->get('integral') != null) ? 'complete' false ;
  346.             // find FPSList - filter by search
  347.             /** @var FpsRepository $repositoryFPS */
  348.             $repositoryFPS $this->getDoctrine()->getRepository('App:Fps',  self::_PREFIX_EM.$cityId);   
  349.             
  350.             $fpsResultSearch $repositoryFPS->getFpsFromSearch($search$cityId$integral);
  351.             // for each FPS found, clean and push as json in matches table
  352.             $matches $serviceFps->cleanFpsList($fpsResultSearch);
  353.             // informations pages, total ...
  354.             $currentPage = isset($search['page']) ? intval($search['page']) : $pageDefault;
  355.             $limit = (isset($search['maxRecords']) && $search['maxRecords'] > 0) ? intval($search['maxRecords']) : $maxRecordsDefault;
  356.             // count false if return total is not required 
  357.             $count $request->get('count') != null $request->get('count') : true ;
  358.             $total_records = ( !$count ) ? $repositoryFPS->getCountFps$search'count');
  359.             $total_pages intvalceil$total_records $limit ));
  360.             if ( $currentPage $total_pages ) {
  361.                 $res = array();
  362.             } else {
  363.                 $res = array( "previousPage" => $currentPage 1"nextPage" => $currentPage 1"matches" => $matches"total" => $total_records);
  364.                 if ( $currentPage === ) {
  365.                     unset( $res['previousPage'] );
  366.                 }
  367.                 if ($currentPage === $total_pages || $total_pages === 0) {
  368.                     unset( $res['nextPage'] );
  369.                 }
  370.             }
  371.             return new JsonResponse($res, (sizeof($matches) === 0) ? Response::HTTP_NO_CONTENT Response::HTTP_OK, array(), false);
  372.         }
  373.     }
  374.     /**
  375.      * Récupère un FPS en fonction de son fineId
  376.      * @Get("/api/{cityId}/fines/v1/{fineId}", requirements = {"fineId": "[0-9]+"})
  377.      * @Security("is_granted('ROLE_PC_FPS') or is_granted('ROLE_SVC_FPS_READ')")
  378.      */
  379.     public function getFPSAction(Request $request$cityId$fineIdFPSService $serviceFps){
  380.         
  381.         // User vérifications authorizations
  382.         $user $this->getUser();
  383.         if($user->getCodeVille() != $request->get('cityId') ){
  384.                 $errors[0] = array("code"=>"401","type"=>"Unauthorized");
  385.                 return new JsonResponse(array("errors"=>$errors), Response::HTTP_UNAUTHORIZED,array(),false);
  386.         }
  387.         // fineId format verifications
  388.         if(!is_int((int) $fineId)){
  389.             $errors[0]=['code' => '1','type' => 'Fine Id doit être un entier valide'];
  390.             return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  391.         }
  392.         // integral true for a complete FPS json
  393.         $integral = ($user->hasRole('ROLE_FPS_COMPLETE') && $request->get('integral') != null) ? 'complete' null ;
  394.         // find FPS by fineId
  395.         /** @var FpsRepository $repositoryFPS */
  396.         $repositoryFPS $this->getDoctrine()->getRepository('App:Fps',  self::_PREFIX_EM.$cityId);          
  397.         $fps $repositoryFPS->getFpsFormatedByfineId($fineId$cityId$integral);
  398.         if(empty($fps) ){
  399.             $errors[0] = ['code' => Response::HTTP_NOT_FOUND,'type' => 'Aucun FPS n’a été trouvé'];
  400.             return new JsonResponse(array("errors"=>$errors), Response::HTTP_NOT_FOUND,array(),false);
  401.         }
  402.         if ($fps['cityId'] != $request->get('cityId')){
  403.             $errors[0] = ['code' => Response::HTTP_NOT_FOUND,'type' => 'La ville du FPS ne correspond pas'];
  404.             return new JsonResponse(array("errors"=>$errors), Response::HTTP_NOT_FOUND,array(),false);
  405.         }
  406.         // clean null value
  407.         $fps $serviceFps->cleanFps($fps);
  408.         $response = new JsonResponse(json_encode($fps), Response::HTTP_OK, array(), true);
  409.         $response->setEtag(md5($response->getContent()));
  410.         $response->headers->set('Access-Control-Expose-Headers''ETag');
  411.         return $response;
  412.     }
  413.     /**
  414.      * Modifie un FPS
  415.      * @Patch("/api/{cityId}/fines/v1/{fineId}",
  416.      *         requirements = {
  417.      *             "fineId": "[0-9]+"
  418.      *         })
  419.      * @Security("is_granted('ROLE_PC_FPS') or is_granted('ROLE_PDA_FPS') or is_granted('ROLE_SVC_FPS_UPDATE')")
  420.      *
  421.      */
  422.     public function patchFPSAction(Request $request$cityId,$fineIdTokenService $tokenFPSservice $serviceFps){
  423.         
  424.         /////////////////// header verifications
  425.         $user $this->getUser();
  426.         if ( $user->getCodeVille() != $request->get('cityId') ) {
  427.             $errors[0] = array( "code" => "401""type" => "Unauthorized");
  428.             return new JsonResponse( array( "errors" => $errors ), Response::HTTP_UNAUTHORIZED, array(), false);
  429.         }
  430.         if ( ! is_int((int) $fineId)){
  431.             $errors[0] = [ 'code' => '1''type' => 'Fine Id doit être un entier valide' ];
  432.             return new JsonResponse( array( "errors" => $errors ), 422 , array(), false);
  433.         }
  434.         $ifMatch $request->headers->get('If-Match'); 
  435.         $datas =  Util::getDataRequest($request);
  436.         $dataForSchema json_decode(json_encode($datas), FALSE);
  437.         $schema $serviceFps->getSchemarealpath(__DIR__.'/../Schemas/updateFps.json') );
  438.         $validator = new Validator;
  439.         $validator->coerce($dataForSchema$schema);
  440.         if ( ! $validator->isValid()) {        
  441.             $errors[0] = array( "code" => "1001""type" => "Structure de la requête invalide" );
  442.             return new JsonResponse( array("errors" => $errors"validation" => $validator->getErrors()), 422 , array(), false);
  443.         } 
  444.         else { 
  445.             ///////////////// connected entity manager
  446.             $em $this->getDoctrine()->getManager(self::_PREFIX_EM.$cityId); 
  447.             /** @var FpsRepository $repositoryFPS */
  448.             $repositoryFPS $this->getDoctrine()->getRepository('App:Fps',  self::_PREFIX_EM.$cityId);  
  449.         
  450.             ///////////////// find FPS by fineId for verifications - same format than the last format return for stade       
  451.             $fps $repositoryFPS->getFpsFormatedByfineId($fineId$cityIdnull);
  452.             if(empty($fps) ){
  453.                 $errors[0] = ['code' => Response::HTTP_NOT_FOUND,'type' => 'Aucun FPS n’a été trouvé'];
  454.                 return new JsonResponse(array("errors"=>$errors), Response::HTTP_NOT_FOUND,array(),false);
  455.             }
  456.             if ($fps['cityId'] != $request->get('cityId')){
  457.                 $errors[0] = ['code' => Response::HTTP_NOT_FOUND,'type' => 'La ville du FPS ne correspond pas'];
  458.                 return new JsonResponse(array("errors"=>$errors), Response::HTTP_NOT_FOUND,array(),false);
  459.             }
  460.             // clean null value
  461.             $fps $serviceFps->cleanFps($fps);
  462.             ////////////Vérification if is the same FPS, with no modification /////////////////
  463.             if(substr($ifMatch,1,strlen($ifMatch)-2) !== md5(json_encode($fps))){
  464.                 return new JsonResponse(nullResponse::HTTP_PRECONDITION_FAILED,array(),false);
  465.             }
  466.             ////////////// end verifications
  467.             /////////// begin traitment//////////////
  468.             //// find FPS for modifications //////////
  469.             $fpsEntity $repositoryFPS->find($fineId);        
  470.             foreach ($datas as $data){
  471.                 if (    substr$data['path'], 0) !=="/claims" && 
  472.                         $data['path'] !=="/cancelDatetime" &&
  473.                         $data['path'] !=="/debtCollectionDatetime" && 
  474.                         $data['path'] !=="/paymentStatus" &&
  475.                         substr$data['path'], 0) !== "/payments" && 
  476.                         $data['path'] !=="/notificationDatetime" && 
  477.                         $data['path'] !=="/offender" &&
  478.                         $data['path'] !=="/comments/-" ) {
  479.                     $errors[0] = ['code' => '1012''type' => 'Champs non autorisés à être modifié'];
  480.                     return new JsonResponse( array( "errors" => $errors), 422 , array(), false);
  481.                 }
  482.                 //si claims replace
  483.                 if ( substr$data['path'], 0) === "/claims"  && $data['op'] === "replace" ){
  484.                     //check si claims existe$
  485.                     /** @var ClaimRepository $repository */
  486.                     $repository $this->getDoctrine()->getRepository('App:Claim',  self::_PREFIX_EM.$cityId);  
  487.                     $claims $repository->findBy( ["fps" => $fpsEntity] );
  488.                     if ( !$claims ){
  489.                         $errors[0] = ['code' => '1013''type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  490.                         return new JsonResponse( array( "errors" => $errors), 422 , array(), false);
  491.                     }
  492.                     if(substr$data['path'], 8) !== false && array_key_exists(substr$data['path'], 8), $claims)){
  493.                         $claim $fpsEntity->getClaims()[substr$data['path'], 8)];
  494.                     }
  495.                     else{
  496.                         $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  497.                         return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  498.                     }
  499.                     foreach($data['value'] as $c){
  500.                         if(is_array($c)){
  501.                             if(isset($c['claimStatus'])){
  502.                                 $claim->setClaimStatus($c['claimStatus']);
  503.                                 if($c['claimStatus'] === "ACCEPTED" || $c['claimStatus'] === "TRANSFERRED"){
  504.                                     $fpsEntity->setType("CANCELLED");
  505.                                 }
  506.                             }
  507.                             if(isset($c['dateModified'])){
  508.                                 $claim->setDateModified(new \DateTime($c['dateModified']));
  509.                                 $fpsEntity->setDateModified(new \DateTime('now'));
  510.                             }
  511.                             if(isset($c['claimReason'])){
  512.                                 $claim->setClaimReason($c['claimReason']);
  513.                             }
  514.                             $em->persist($claim);
  515.                         }
  516.                         else{
  517.                             if(isset($data['value']['claimStatus'])){
  518.                                 $claim->setClaimStatus($data['value']['claimStatus']);
  519.                                 if($data['value']['claimStatus'] === "ACCEPTED" || $data['value']['claimStatus'] === "TRANSFERRED"){
  520.                                     $fpsEntity->setType("CANCELLED");
  521.                                 }
  522.                             }
  523.                             if(isset($data['value']['dateModified'])){
  524.                                 $claim->setDateModified(new \DateTime($data['value']['dateModified']));
  525.                                 $fpsEntity->setDateModified(new \DateTime('now'));
  526.                             }
  527.                             if(isset($data['value']['claimReason'])){
  528.                                 $claim->setClaimReason($data['value']['claimReason']);
  529.                             }
  530.                             $em->persist($claim);
  531.                             break;
  532.                         }
  533.                     }
  534.                 }
  535.                 if(substr$data['path'], 0) === "/claims"  && $data['op'] === 'add' ){
  536.                     foreach($data['value'] as $c){
  537.                         if(is_array($c)){
  538.                             if($c['claimStatus'] !== "FILLED"){
  539.                                 $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  540.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  541.                             }
  542.                             if(count($fpsEntity->getClaims())>&& $fpsEntity->getClaims()[0]->getClaimType() === "PRELIMINARY" && $c['claimType'] ==='PRELIMINARY'){
  543.                                 $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  544.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  545.                             }
  546.                             //si claims add
  547.                             if(!isset($c['claimType']) || ($c['claimType'] !== 'PRELIMINARY' && $c['claimType'] !== 'REGULATORY')){
  548.                                 $errors[0]=array("code"=>"1001","type"=>"Structure de la requête invalide");
  549.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  550.                             }
  551.                             if(count($fpsEntity->getClaims())>&& $fpsEntity->getClaims()[count($fpsEntity->getClaims())-1]->getClaimType() === "REGULATORY" && $c['claimType'] ==='REGULATORY'){
  552.                                 $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  553.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  554.                             }
  555.                             $claim = new Claim;
  556.                             $claim->setClaimStatus($c['claimStatus']);
  557.                             $claim->setClaimType($c['claimType']);
  558.                             if(isset($c['claimReason'])){
  559.                                 $claim->setClaimReason($c['claimReason']);
  560.                             }
  561.                             $claim->setDateModified(new \DateTime($c['dateModified']));
  562.                             $fpsEntity->setDateModified(new \DateTime('now'));
  563.                             $claim->setFps($fpsEntity);
  564.                             $fpsEntity->addClaim($claim);
  565.                             $em->persist($claim);
  566.                         }
  567.                         else{
  568.                             if($data['value']['claimStatus'] !== "FILLED"){
  569.                                 $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  570.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  571.                             }
  572.                             if(count($fpsEntity->getClaims())>&& $fpsEntity->getClaims()[0]->getClaimType() === "PRELIMINARY" && $data['value']['claimType'] ==='PRELIMINARY'){
  573.                                 $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  574.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  575.                             }
  576.                             //si claims add
  577.                             if(!isset($data['value']['claimType']) || ($data['value']['claimType'] !== 'PRELIMINARY' && $data['value']['claimType'] !== 'REGULATORY')){
  578.                                 $errors[0]=array("code"=>"1001","type"=>"Structure de la requête invalide");
  579.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  580.                             }
  581.                             if(count($fpsEntity->getClaims())>&& $fpsEntity->getClaims()[count($fpsEntity->getClaims())-1]->getClaimType() === "REGULATORY" && $data['value']['claimType'] === 'REGULATORY'){
  582.                                 $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  583.                                 return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  584.                             }
  585.                             $claim = new Claim;
  586.                             $claim->setClaimStatus($data['value']['claimStatus']);
  587.                             $claim->setClaimType($data['value']['claimType']);
  588.                             if(isset($data['value']['claimReason'])){
  589.                                 $claim->setClaimReason($data['value']['claimReason']);
  590.                             }
  591.                             $claim->setDateModified(new \DateTime($data['value']['dateModified']));
  592.                             $fpsEntity->setDateModified(new \DateTime('now'));
  593.                             $claim->setFps($fpsEntity);
  594.                             $fpsEntity->addClaim($claim);
  595.                             $em->persist($claim);
  596.                             break;
  597.                         }
  598.                     }
  599.                 }
  600.                 if($data['path'] ==="/cancelDatetime" && $data['op'] === 'add'){
  601.                     if($fpsEntity->getCancelDateTime() != null && $fpsEntity->getType() === "CANCELLED"){
  602.                         $errors[0]=['code' => '1012','type' => 'Champs non autorisés à être modifié'];
  603.                         return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  604.                     }
  605.                     $fpsEntity->setCancelDatetime(new \DateTime($data['value']));
  606.                     $fpsEntity->setDateModified(new \DateTime('now'));
  607.                     $fpsEntity->setType("CANCELLED");
  608.                 }
  609.                 if($data['path'] ==="/cancelDatetime" && $data['op'] === 'replace'){
  610.                     $errors[0]=['code' => '1012','type' => 'Champs non autorisés à être modifié'];
  611.                     return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  612.                 }
  613.                 if($data['path'] ==="/debtCollectionDatetime"){
  614.                     $fpsEntity->setDebtCollectionDatetime(new \DateTime($data['value']));
  615.                     $fpsEntity->setDateModified(new \DateTime('now'));
  616.                 }
  617.                 if($data['path'] ==="/paymentStatus" ){
  618.                     if($fpsEntity->getPaymentStatus() === "PENDING" && ($data['value']==="PAID" || $data['value']==="OVERPAID")){
  619.                             if($data['path'] ==="/paymentStatus" ){
  620.                                 $fpsEntity->setPaymentStatus($data['value']);
  621.                                 $fpsEntity->setDateModified(new \DateTime('now'));
  622.                             }
  623.                     }
  624.                     else{
  625.                         $errors[0]=['code' => '1013','type' => 'Incohérence des modifications par rapport au cycle de vie du FPS'];
  626.                         return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  627.                     }
  628.                 }
  629.                 if(substr($data['path'], 09) === "/payments" && $data['op'] === 'add'){
  630.                     foreach($data['value'] as $p){
  631.                         if(is_array($p)){
  632.                             $paymentType = !empty($p['paymentType']) ? $p['paymentType'] : null;
  633.                             
  634.                             $payment= new Payment;
  635.                             $payment->setPaymentDatetime(new \DateTime($p['paymentDatetime']));
  636.                             $payment->setPaymentChannel($p['paymentChannel']);
  637.                             $payment->setPaymentAmount($p['paymentAmount']);
  638.                             $payment->setPaymentType($paymentType);
  639.                             $payment->setFps($fpsEntity);
  640.                             $fpsEntity->addPayment($payment);
  641.                             $fpsEntity->setDateModified(new \DateTime('now'));
  642.                             $em->persist($payment);
  643.                         }
  644.                         else{
  645.                             $paymentType = (
  646.                                 isset($data['value']['paymentType']) && !empty($data['value']['paymentType'])
  647.                                 ) ? $data['value']['paymentType'] : null;
  648.                             
  649.                             $payment= new Payment;
  650.                             $payment->setPaymentDatetime(new \DateTime($data['value']['paymentDatetime']));
  651.                             $payment->setPaymentChannel($data['value']['paymentChannel']);
  652.                             $payment->setPaymentAmount($data['value']['paymentAmount']);
  653.                             $payment->setPaymentType($paymentType);
  654.                             $payment->setFps($fpsEntity);
  655.                             $fpsEntity->addPayment($payment);
  656.                             $fpsEntity->setDateModified(new \DateTime('now'));
  657.                             $em->persist($payment);
  658.                             break;
  659.                         }
  660.                     }
  661.                 }
  662.                 if(substr($data['path'], 09) === "/payments" && $data['op'] === 'replace'){
  663.                     $errors[0]=['code' => '1012','type' => 'Champs non autorisés à être modifié'];
  664.                     return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  665.                 }
  666.                 if($data['path'] ==="/notificationDatetime" ){
  667.                     $fpsEntity->setNotificationDatetime(new \DateTime($data['value']));
  668.                     $fpsEntity->setDateModified(new \DateTime('now'));
  669.                 }
  670.                 if($data['path'] ==="/offender" && $data['op'] === 'add'){
  671.                     if($fpsEntity->getOffender() != null){
  672.                         $errors[0]=['code' => '1012','type' => 'Champs non autorisés à être modifié'];
  673.                         return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  674.                     }
  675.                     $fpsEntity->setOffender($data['value']);
  676.                     $fpsEntity->setDateModified(new \DateTime('now'));
  677.                 }
  678.                 if($data['path'] ==="/offender" && $data['op'] === 'replace'){
  679.                     $errors[0]=['code' => '1012','type' => 'Champs non autorisés à être modifié'];
  680.                     return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  681.                 }
  682.                 if ($data['path'] === "/comments/-") {
  683.                     if ($data['op'] === 'replace') {
  684.                         $errors[0]=['code' => '1012','type' => 'Champs non autorisés à être modifié'];
  685.                         return new JsonResponse(array("errors"=>$errors), 422 ,array(),false);
  686.                     }
  687.                     // Create comment
  688.                     $comment = new FpsComment;
  689.                     $comment->setAgentId($data['value']['agent']['agentId']);
  690.                     $comment->setName($data['value']['agent']['name']);
  691.                     $comment->setText(trim($data['value']['text']));
  692.                     $comment->setCreationDatetime(new \Datetime($data['value']['creationDatetime']));
  693.                     $comment->setFineId($fpsEntity);
  694.                     // Add comment to FPS
  695.                     $fpsEntity->addComment($comment);
  696.                     // Persist comment
  697.                     $em->persist($comment);
  698.                 }
  699.             }
  700.             try {
  701.                 $idUser $token->getUserId($request);
  702.                 $activity = new ActivityFPS;
  703.                 $activity->setIdUser($idUser);
  704.                 $activity->setMethod('PATCH');
  705.                 $activity->setBody($request->getContent());
  706.                 $activity->setFps($fpsEntity);
  707.                 $em->persist($activity);
  708.                 $em->persist($fpsEntity);
  709.                 $em->flush();
  710.                 $em->refresh($fpsEntity);
  711.                 if(isset($claim)){
  712.                     $em->refresh($claim);
  713.                 }
  714.                 if(isset($payment)){
  715.                     $em->refresh($payment);
  716.                 }
  717.                 $fpsUpdate=$fpsEntity->getFormat();
  718.                 $jsonResponse= new JsonResponse(json_encode($fpsUpdate), Response::HTTP_OK, array(), true);
  719.                 return $jsonResponse;
  720.             } catch (\Exception $e) {
  721.                 return  $e->getMessage();
  722.             }
  723.         }
  724.     }
  725.     /**
  726.      * Récupère une liste de FPS en fonction de criteres en GET - csv export
  727.      * @Get("/api/v1/{cityId}/fines-export")
  728.      * @Security("is_granted('ROLE_PC_FPS') or is_granted('ROLE_SVC_FPS_READ')")
  729.      *
  730.      */
  731.     public function exportFPSListAction(Request $request$cityIdFpsService $fpsServiceFpsCsvService $fpsCsvService){
  732.         $maxRecordsDefault 0;
  733.         $pageDefault "1";
  734.         $search json_decode($request->get('search'), true);
  735.         $user $this->getUser();
  736.         $integral $request->get('integral') != null $request->get('integral') === 'true' false ;
  737.         $verifications $fpsService->verificationsAuthorizationPlateFormatAndFormatJson($user->getCodeVille(),$request->get('cityId'),$search );  
  738.         if ( sizeof($verifications['error']) > 0) { 
  739.             return new JsonResponse($verifications['error'], 422 ,array(),false);
  740.         }
  741.         else {   
  742.             if (!isset($search['maxRecords'])) {
  743.                 $search['maxRecords'] = $maxRecordsDefault;
  744.             }
  745.             if( !isset($search['page'])){
  746.                 $search['page'] = $pageDefault;
  747.             }
  748.             if( !isset($search['orderBy']) || count($search['orderBy']) === 0){
  749.                 $search['orderBy'] = [array("field" => "fps.fineId""sort" => "ASC")];
  750.             }
  751.             $complete $user->hasRole('ROLE_FPS_COMPLETE') && $integral === true 'complete' false;
  752.             // find FPSList - filter by search
  753.             /** @var FpsRepository $repositoryFPS */
  754.             $repositoryFPS $this->getDoctrine()->getRepository('App:Fps',  self::_PREFIX_EM.$cityId);   
  755.             $fpsQuery $repositoryFPS->getFpsFromSearch($search$cityId$complete'csv');
  756.             return $fpsCsvService->generateCsv($fpsQuery$cityId);
  757.         }
  758.     }
  759.     /**
  760.      * Récupère une liste de FPS en fonction de criteres en GET - csv export
  761.      * @Get("/api/v1/{cityId}/fpsm")
  762.      * @Security("is_granted('ROLE_PC_FPS') or is_granted('ROLE_SVC_FPS_READ')")
  763.      *
  764.      */
  765.     public function exportFPSMAction(Request $request$cityIdFpsCsvService $fpsCsvServiceManagerRegistry $registry){
  766.         $month explode(","$request->get('months'));
  767.         $year $request->get('year');
  768.         $user $this->getUser();
  769.         // User vérifications authorizations
  770.         if ($user->getCodeVille() != $cityId) {
  771.             return ['error' => ["code" => "401""type" => "Unauthorized"]];
  772.         }
  773.         else {
  774.             // find FPSList - filter by search
  775.             /** @var FpsRepository $repositoryFPS */
  776.             $repositoryFPS $registry->getRepository('App:Fps',  self::_PREFIX_EM.$cityId);
  777.             $fpsQuery $repositoryFPS->getFpsM($month$year);
  778.             return $fpsCsvService->generateCsv($fpsQuery$cityId);
  779.         }
  780.     }
  781.     /**
  782.       * @Get("/api/{cityId}/last-fine")
  783.       * @QueryParam(name="agentId", nullable=false, description="agentId")
  784.       * @QueryParam(name="date", nullable=false, description="date")
  785.       *
  786.     */
  787.     public function getLastFPSIdAction(Request $requestParamFetcher $paramFetcher){
  788.  
  789.         /** @var FpsRepository $repositoryFPS*/
  790.         $repositoryFPS $this->getDoctrine()->getRepository('App:Fps',  self::_PREFIX_EM.$request->get('cityId'));  
  791.         $resId $repositoryFPS->getLastFPSId($request->get('cityId'), $paramFetcher->get('agentId'), $paramFetcher->get('date'));
  792.         $res = ["last" => $resId];
  793.         return new JsonResponse(json_encode($res), Response::HTTP_OK, array(), true);
  794.     }
  795.  }