src/Controller/NotificationController.php line 921

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\Routing\Annotation\Route;
  6. use App\Entity\Menu;
  7. use App\Entity\User;
  8. use App\Entity\UserToken;
  9. use App\Entity\NotificationTokens;
  10. use App\Entity\Notification;
  11. use App\Entity\MassiveNotification;
  12. use Symfony\Component\HttpFoundation\JsonResponse;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Doctrine\ORM\EntityManagerInterface;
  15. use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  16. use App\Service\AppApiService;
  17. use App\Service\FirebaseService;
  18. use App\Service\NotificationService;
  19. use App\Entity\AppPersonalAccount;
  20. use App\Entity\MediaObject;
  21. use App\Entity\AppCounterReading;
  22. use App\Entity\DataReception;
  23. use App\Entity\Accounts;
  24. use App\Entity\ServiceOrderHistory;
  25. use Symfony\Component\HttpKernel\KernelInterface
  26. use Psr\Log\LoggerInterface;
  27. use Sentry;
  28. use App\Repository\NotificationRepository;
  29. use App\Message\NotificationMessage;
  30. use Symfony\Component\Messenger\MessageBusInterface;
  31. use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpStamp;
  32. use Symfony\Component\Messenger\Stamp\SentStamp;
  33. use Symfony\Component\Messenger\Exception\TransportExceptionInterface;
  34. use Symfony\Component\Security\Core\Security;
  35. class NotificationController extends AbstractController
  36. {
  37.     public $datetime;
  38.     public $entityManager;
  39.     public $passwordEncoder;
  40.     public $appApiService;
  41.     public $firebaseService;
  42.     public $notificationService;
  43.     public $notifications;
  44.     private $kernel;
  45.     private LoggerInterface $logger;
  46.     private $bus;
  47.     private Security $security;
  48.     public function __construct
  49.         ?\DateTimeInterface $datetime
  50.         EntityManagerInterface $entityManager
  51.         AppApiService $appApiService
  52.         KernelInterface $kernel
  53.         FirebaseService $firebaseService
  54.         NotificationService $notificationService
  55.         LoggerInterface $logger,  
  56.         NotificationRepository $notifications,
  57.         MessageBusInterface $bus,
  58.         Security $security
  59.     ){
  60.         $this->datetime $datetime;
  61.         $this->entityManager $entityManager;
  62.         $this->appApiService $appApiService;
  63.         $this->firebaseService $firebaseService;
  64.         $this->notificationService $notificationService;
  65.         $this->kernel $kernel;
  66.         $this->logger $logger;
  67.         $this->notifications $notifications;
  68.         $this->bus $bus;
  69.         $this->security $security;
  70.     }
  71.     public function valid($requestFilds$requiredFilds){
  72.         $errors '';
  73.         foreach($requiredFilds as $f){
  74.             if(!isset($requestFilds[$f]))
  75.                 $errors .= $f"
  76.         }
  77.         return $errors;
  78.     }
  79.     
  80.     private function customAuth($request){
  81.         $validUser 'loe';
  82.         $validPassword 'GE2666Mh4maRa79iMs5igRPD';
  83.         $login $request->server->get('PHP_AUTH_USER');
  84.         $password $request->server->get('PHP_AUTH_PW');
  85.         if ($login !== $validUser || $password !== $validPassword) {
  86.             return false;
  87.         }
  88.         return true;
  89.     }
  90.     #[Route('/api/create-notfication'name'create_notfication'methods: ['POST'])]
  91.     public function create_notfication(Request $request)
  92.     {
  93.         
  94.         if (!$this->customAuth($request)) {
  95.             return new JsonResponse(['message' => 'Unauthorized'], 401, [
  96.                 'WWW-Authenticate' => 'Basic realm="API Access"',
  97.             ]);
  98.         }
  99.         $data json_decode($request->getContent(), true);
  100.         
  101.         file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log',  "\n\n\n" .  print_r($datatrue) . "\n"FILE_APPEND);
  102.         $valid $this->valid$data, ['user''title''body'] );
  103.         if( empty($valid) ){
  104.             $find $this->entityManager->getRepository(User::class)->findOneBy(['id' => $data['user']]);
  105.             if($find){
  106.                     $notification = new Notification();
  107.                     $notification->setUsers($find);
  108.                     $notification->setTitle$data['title']);
  109.                     $notification->setBody$data['body']);
  110.                     if(!empty($data['type']))
  111.                         $notification->setType$data['type']);
  112.                     else
  113.                         $notification->setType('text');
  114.                     $notification->setDateEntered( new \DateTime() );
  115.                     $notification->setStatus('new');
  116.                     $this->entityManager->persist($notification);
  117.                     $this->entityManager->flush();
  118.                     $rez = ['rez' => true'id' => $notification->getId()];
  119.                  
  120.                 // }else{
  121.                 //     $rez = ['registered' => false, $res];
  122.                 // }
  123.             }else{
  124.                 $rez = ['rez' => false'error' => "Користувача не знайдено"];
  125.             }
  126.         }else{
  127.             $rez = ['rez' => false'error' => "Не задано поля: $valid"];
  128.         }
  129.     
  130.         $response = new JsonResponse();
  131.         $response->setData($rez);
  132.         return $response;
  133.     }
  134.     #[Route('/api/send-notfication'name'send_notfication'methods: ['GET'])]
  135.     public function send_notfication(Request $request)
  136.     {
  137.         $send 0;
  138.         $err 0;
  139.         
  140.         $notifications $this->entityManager->getRepository(Notification::class)->findBy(['status' => 'new']);
  141.         
  142.         if($notifications){
  143.                 file_put_contents('/var/www/symfony_docker/var/log/notification.log',  "NOTIFICATIONS ************************ " .  date('Y-m-d H:i:s') . "\n"FILE_APPEND);
  144.                 // Витягуємо всі ID
  145.                     $notificationIds array_map(fn($n) => $n->getId(), $notifications);
  146.                     // Масове оновлення статусу та дати
  147.                     $this->entityManager->createQuery(
  148.                         'UPDATE App\Entity\Notification n
  149.                         SET n.status = :newStatus, 
  150.                             n.dateSend = :now 
  151.                         WHERE n.id IN (:ids)'
  152.                     )
  153.                     ->setParameter('newStatus''in_progress')
  154.                     ->setParameter('now', new \DateTime())
  155.                     ->setParameter('ids'$notificationIds)
  156.                     ->execute();
  157.                     // file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log',  "2222222222" .  date('H:i:s') . "\n", FILE_APPEND);
  158.                     // Тепер можна знову вибрати тільки оновлені
  159.                     // $notifications = $this->entityManager
  160.                     // ->getRepository(Notification::class)
  161.                     // ->findBy(['id' => $notificationIds]);
  162.                     
  163.                 foreach($notifications as $notification){
  164.                     $send 0;
  165.                     $user $notification->getUsers();
  166.                     $tokensArr = [];
  167.                     if($user){
  168.                         file_put_contents('/var/www/symfony_docker/var/log/notification.log',  "id:" $user->getId() . " phone:" $user->getUsername() .  " notification:" $notification->getId() . "\n"FILE_APPEND);
  169.                         $tokens $user->getUserTokens();
  170.                         if(!empty($tokens) AND count($tokens) > 0){
  171.                             
  172.                         }else{
  173.                             $device_id $user->getDeviceId();
  174.                             $tokens $this->entityManager->getRepository(UserToken::class)->findBy(['device_id' => $device_id'active' => true]);
  175.                         }
  176.                         $search_dublicate_tokens = [];
  177.                         foreach($tokens as $token){
  178.                             if(!$token->isActive())
  179.                                 continue;
  180.                             // if(!isset($search_dublicate_tokens[$token->getTokenFcm()]))
  181.                             //     $search_dublicate_tokens[$token->getTokenFcm()] = true;
  182.                             // else
  183.                             //     continue;
  184.                             if(in_array($token->getTokenFcm(), $tokensArr)){
  185.                                 $token->setDateModified( new \DateTime() );
  186.                                 $token->setErrorDescription"Дублюючий ключ" );
  187.                                 $token->setActive(false);
  188.                                 
  189.                                 $this->entityManager->persist($token);
  190.                                 // $this->entityManager->persist($notification);
  191.                                 $this->entityManager->flush();
  192.                                 continue;
  193.                             }
  194.                             $tokensArr[] = $token->getTokenFcm();
  195.                             $data = [
  196.                                 'id' => $notification->getId(),
  197.                                 'token' => $token->getTokenFcm(),
  198.                                 'title' => $notification->getTitle(),
  199.                                 'body' => $notification->getBody(),
  200.                                 'type' => $notification->getType(),
  201.                             ];
  202.                             // file_put_contents('/var/www/symfony_docker/var/log/notification.log',  print_r($data, true) . "st - " .  date('H:i:s') . "\n", FILE_APPEND);
  203.                             $resultJson $this->firebaseService->sendCurl($data);
  204.                             // file_put_contents('/var/www/symfony_docker/var/log/notification.log',   $resultJson  . "\n", FILE_APPEND);
  205.                             // file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log',   "   - " . date('H:i:s') . "\n", FILE_APPEND);
  206.                             $notification->setDateSend( new \DateTime() );
  207.                             $result json_decode($resultJsontrue);
  208.                             if(!empty( $result['res'] )){
  209.                                 $send 1;
  210.                                 $notification->setStatus('send');
  211.                                 $send++;
  212.                             }elseif(!empty( $result['err'] )){
  213.                                 $send 2;
  214.                                 // $token->setActive(false);
  215.                                 $notification->setStatus('error');
  216.                                 $notification->setError($notification->getError() .  "\n" date('Y-m-d H:i:s') . $token->getTokenFcm() . "\n" $resultJson);
  217.                                 $err++;
  218.                                 if($result['err'] == 'Requested entity was not found.' OR $result['err'] == 'The registration token is not a valid FCM registration token'){
  219.                                     $token->setDateModified( new \DateTime() );
  220.                                     $token->setErrorDescription$result['err'] );
  221.                                     $token->setActive(false);
  222.                                 }
  223.                             }else{
  224.                                 $send 3;
  225.                                 // $token->setActive(false);
  226.                                 $notification->setStatus('error');
  227.                                 $notification->setError($notification->getError() .  "\n" date('Y-m-d H:i:s') . $token->getTokenFcm() . "\n" $resultJson);
  228.                                 $err++;
  229.                             }
  230.                             $this->entityManager->persist($token);
  231.                             $this->entityManager->persist($notification);
  232.                            
  233.                         }
  234.                         
  235.                     }
  236.                     /** Якщо ключа нема */
  237.                     if($send == 0){
  238.                         $notification->setStatus('not_token');
  239.                         $notification->setError($notification->getError() .  "\n" date('Y-m-d H:i:s') .  " Ключ не знайдено \n");
  240.                         $this->entityManager->persist($notification);
  241.                     }
  242.                     $this->entityManager->flush();
  243.                 }
  244.                 file_put_contents('/var/www/symfony_docker/var/log/notification.log',  "***********END************* " .  date('H:i:s') . "\n"FILE_APPEND);
  245.             }else{
  246.                 $rez = ['rez' => false'error' => "Незнайдено нових сповіщень!"];
  247.             }
  248.         $response = new JsonResponse();
  249.         $response->setData(['send' => $send'err' => $err]);
  250.         return $response;
  251.     }
  252.     #[Route('/api/create-notfication-actions'name'create_notfication_account'methods: ['POST'])]
  253.     public function create_notfication_account(Request $request)
  254.     {
  255.         $user $this->security->getUser();
  256.         if(!$user OR !in_array('ROLE_ADMIN'$user->getRoles()) ){
  257.             if (!$this->customAuth($request) ) {
  258.                 return new JsonResponse(['message' => 'Unauthorized'], 401, [
  259.                     'WWW-Authenticate' => 'Basic realm="API Access"',
  260.                 ]);
  261.             }
  262.         }
  263.         
  264.   
  265.         $data json_decode($request->getContent(), true);
  266.         
  267.         $send = [];
  268.         $err '';
  269.         $valid $this->valid$data, ['sender''msg-data'] );
  270.         if( empty($valid) ){
  271.             // $title = $data['msg-data']['title'];
  272.             if(isset($data['msg-data']['receivers']) OR isset($data['msg-data']['content'])){
  273.                 
  274.                 switch ($data['msg-type']) {
  275.                     case 'from-ns':
  276.                         $send $this->notificationService->fromNs($data);
  277.                         break;
  278.                     case 'number-phone':
  279.                         $send $this->notificationService->numberPhone($data);
  280.                         break;
  281.                     case 'notification-yur':
  282.                         $send $this->notificationService->notificationYur($data);
  283.                         break;
  284.                     case 'notification-all':
  285.                         $send $this->notificationService->notificationAll($data);
  286.                         break;
  287.                 
  288.                 }
  289.                 $rez = ['rez' => true'send' => $send 'error' => ""];
  290.             }else{
  291.                 $rez = ['rez' => false'error' => "Не задано поля receivers або content"];
  292.             }
  293.         }else{
  294.             $rez = ['rez' => false'error' => "Не задано поля: $valid"];
  295.         }
  296.         $response = new JsonResponse();
  297.         $response->setData($rez);
  298.         return $response;
  299.     }
  300.     #[Route('/api/create-data-reception'name'create_notfication_data_reception'methods: ['POST'])]
  301.     public function create_notfication_data_reception(Request $request)
  302.     {
  303.         if (!$this->customAuth($request)) {
  304.             return new JsonResponse(['message' => 'Unauthorized'], 401, [
  305.                 'WWW-Authenticate' => 'Basic realm="API Access"',
  306.             ]);
  307.         }
  308.         $data json_decode($request->getContent(), true);
  309.         // file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log',  "\n\n\n" .  print_r($data, true) . "\n", FILE_APPEND);
  310.         $valid $this->valid$data, ['method''data'] );
  311.         if( empty($valid) ){
  312.             
  313.             $DataReception = new DataReception();
  314.             $DataReception->setType$data['method']);
  315.             $DataReception->setData$data['data']);
  316.             $DataReception->setDateEntered( new \DateTime() );
  317.             $DataReception->setStatus('new');
  318.             $this->entityManager->persist($DataReception);
  319.             $this->entityManager->flush();
  320.             $rez = ['rez' => true'id' => $DataReception->getId()];
  321.                  
  322.         }else{
  323.             $rez = ['rez' => false'error' => "Не задано поля: $valid"];
  324.         }
  325.     
  326.         $response = new JsonResponse();
  327.         $response->setData($rez);
  328.         return $response;
  329.     }
  330.     public function updateStatus($inf$name='statusPlanning'$status 'planned'){
  331.         $query $this->entityManager->createQuery(
  332.             'UPDATE App\Entity\Accounts d 
  333.              SET d.'.$name.' = :new_status 
  334.              WHERE d.eic IN (:ids)'
  335.         );
  336.         $query->setParameter('new_status'$status);
  337.         $query->setParameter('ids'$inf); // Масив ID
  338.         $query->execute();
  339.     }
  340.     public function updateClearStatusPlan(){
  341.         $query $this->entityManager->createQuery(
  342.             'UPDATE App\Entity\Accounts d SET d.statusPlanning = :new_status'
  343.         );
  344.         $query->setParameter('new_status''not_pllaned');
  345.        
  346.         $query->execute();
  347.         $this->entityManager->clear();
  348.     }
  349.     #[Route('/cron-get-planned'name'cron_get_pllanned'methods: ['GET'])]
  350.     public function cron_get_pllanned(Request $request)
  351.     {
  352.         /** Дивлюся чи є планові на сьогодні */
  353.         $qb $this->entityManager->createQueryBuilder();
  354.         $qb->select('d.id''d.dateEntered''d.type''d.status')
  355.         ->from(DataReception::class, 'd')
  356.         ->where('d.dateEntered >= :start')
  357.         ->andWhere('d.dateEntered < :end')
  358.         ->setParameter('start', (new \DateTime('today'))->setTime(000))
  359.         ->setParameter('end', (new \DateTime('today'))->setTime(235959));
  360.         $result $qb->getQuery()->getArrayResult();
  361.         /** Якщо плнові на сьогодні відсутні тоді оновлюю всі записи */
  362.         if(count($result) == 0)
  363.             $this->updateClearStatusPlan();
  364.         
  365.         /** Вибираю нові планові дані */
  366.         $DataReception $this->entityManager->getRepository(DataReception::class)->findBy(['type' => 'planned''status' => 'new']);
  367.         /** Якщо відсутні нові дані тоді вихід */
  368.         if(empty($DataReception) AND count($DataReception) == 0)
  369.             die('No data');
  370.         /** Очищаю всі планові статуси щоб задати нові*/
  371.         $this->updateClearStatusPlan();
  372.         $eic = [];
  373.         foreach($DataReception as $data){
  374.             
  375.             $infos json_decode($data->getData(), true);
  376.             
  377.             if(!is_array($infos))
  378.                 continue;
  379.             foreach($infos as $acc_id =>  $inf){
  380.                
  381.                 if(count($inf) > 0)
  382.                     array_push($eic$inf[0]);
  383.                 if(count($eic) == 500){
  384.                     $this->updateStatus($eic);
  385.                     $eic = [];
  386.                 }
  387.             }
  388.             if(count($eic) > 0)
  389.                 $this->updateStatus($eic);
  390.             // $this->entityManager->clear();
  391.             $data->setStatus('complate');
  392.             $this->entityManager->persist($data);
  393.             $this->entityManager->flush();
  394.             // print_r($infos);
  395.         }
  396.         echo count($DataReception); die;
  397.     }
  398.     #[Route('/cron-get-planned-status'name'cron_get_pllanned_status'methods: ['GET'])]
  399.     public function cron_get_pllanned_status(Request $request)
  400.     {
  401.         // $type = $request->query->get('type');
  402.         // $status = $request->query->get('status');
  403.         $query $this->entityManager->createQuery(
  404.             'UPDATE App\Entity\Accounts d SET d.statusLight = :new_status'
  405.         );
  406.         $query->setParameter('new_status''enabled');
  407.         // disabled
  408.         // $query->setParameter('old_status', 'new');
  409.         // echo '<pre>';
  410.         $query->execute();
  411.         $this->entityManager->clear();
  412.         $DataReception $this->entityManager->getRepository(DataReception::class)->findBy(['type' => 'all_acounts_light_data''status' => 'new']);
  413.         $eic = [];
  414.         foreach($DataReception as $data){
  415.             $infos json_decode($data->getData(), true);
  416.             foreach($infos as $acc_id =>  $inf){
  417.                 $code array_keys($inf);
  418.                 print_r($code[0]);
  419.                 var_dump($inf[$code[0]]);
  420.                 print_r($eic);
  421.                 echo "<br>";
  422.                 echo "<br>";
  423.                 echo "<br>";
  424.                 if(count($inf) > 0)
  425.                     if($inf[$code[0]]){
  426.                         array_push($eic$code[0]);
  427.                     }
  428.                 if(count($eic) == 500){
  429.                     $this->updateStatus($eic'statusLight''disabled');
  430.                     $eic = [];
  431.                 }
  432.             }
  433.             if(count($eic) > 0)
  434.                 $this->updateStatus($eic'statusLight''disabled');
  435.             
  436.             $data->setStatus('complate');
  437.             $this->entityManager->persist($data);
  438.             $this->entityManager->flush();
  439.             // print_r($infos);
  440.         }
  441.         echo count($DataReception); die;
  442.     }
  443.     #[Route('/api/get-account-all-data'name'get_account_all_data'methods: ['GET'])]
  444.     public function get_account_all_data(Request $request):Response
  445.     {   
  446.         set_time_limit(0);
  447.         // echo '<pre>';
  448.         $i 0;
  449.         $AppPersonalAccount $this->entityManager->getRepository(AppPersonalAccount::class)->findBy(['counter' => null]);
  450.         foreach($AppPersonalAccount as $account){
  451.             // if(!empty( $account->getEic() ))
  452.             //     continue;
  453.             $i++;
  454.             $data = [
  455.                 'account' => trim$account->getNumber() )
  456.             ];
  457.             // echo $account->getId() . "<br>";
  458.             // echo $account->getNumber() . "<br>";
  459.             $res json_decode$this->appApiService->account_all_data($data) , true );  
  460.             
  461.             // print_r( $res ); 
  462.             
  463.             // if($i > 5)
  464.             //     die;
  465.             if(isset($res['rez']) AND $res['rez'] == AND isset($res['data'][0])){
  466.                 file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log',   print_r($restrue)  . "\n"FILE_APPEND);
  467.                 $account->setEic($res['data'][0]['eic_kod']);  
  468.                 $account->setCounter($res['data'][0]['counter']);  
  469.                 
  470.                 $this->entityManager->persist($account);
  471.                 $this->entityManager->flush();
  472.             }
  473.         }
  474.         return new Response('1');
  475.         
  476.     }
  477.     /** Додавання id crm LOE */
  478.     #[Route('/api/update-service-id'name'update_service_id'methods: ['POST'])]
  479.     public function update_service_id(Request $request)
  480.     {
  481.         if (!$this->customAuth($request)) {
  482.             return new JsonResponse(['message' => 'Unauthorized'], 401, [
  483.                 'WWW-Authenticate' => 'Basic realm="API Access"',
  484.             ]);
  485.         }
  486.         $data json_decode($request->getContent(), true);
  487.         // file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log',  "\n\n\n" .  print_r($data, true) . "\n", FILE_APPEND);
  488.         $valid $this->valid$data, ['id''id_crm'] );
  489.         if( empty($valid) ){
  490.             $ServiceOrderHistory false;
  491.             if(is_int($data['id']))
  492.                 $ServiceOrderHistory $this->entityManager->getRepository(ServiceOrderHistory::class)->findOneBy(['id' => $data['id']]);
  493.             if(!$ServiceOrderHistory AND !empty($data['id_crm']))
  494.                  $ServiceOrderHistory $this->entityManager->getRepository(ServiceOrderHistory::class)->findOneBy(['idCrm' => $data['id_crm']]);
  495.             if($ServiceOrderHistory){
  496.                 $ServiceOrderHistory->setIdCrm$data['id_crm']);
  497.                 if(!empty( $data['status'] ))
  498.                     $ServiceOrderHistory->setStatus(  $data['status'] );
  499.                 else
  500.                     $ServiceOrderHistory->setStatus'in_process' );
  501.                 if(!empty( $data['description'] ))
  502.                     $ServiceOrderHistory->setDescription(  $data['description'] );
  503.                 if(!empty( $data['message'] ))
  504.                     $ServiceOrderHistory->setMessage(  $data['message'] );
  505.     
  506.                 $ServiceOrderHistory->setDateModified( new \DateTime() );
  507.                 // $ServiceOrderHistory->setStatus('new');
  508.     
  509.                 $this->entityManager->persist($ServiceOrderHistory);
  510.                 $this->entityManager->flush();
  511.                 $rez = ['rez' => true'id' => $ServiceOrderHistory->getId()];
  512.             }else{
  513.                 $rez = ['false' => false'error' => "Заявку не знайдено id не вірне"];
  514.             }
  515.                  
  516.         }else{
  517.             $rez = ['rez' => false'error' => "Не задано поля: $valid"];
  518.         }
  519.     
  520.         $response = new JsonResponse();
  521.         $response->setData($rez);
  522.         return $response;
  523.     }
  524.     /** Додавання id crm LOE */
  525.     #[Route('/api/get-service-id'name'get_service_id'methods: ['GET''POST'])]
  526.     public function get_service_id(Request $request)
  527.     {
  528.         if (!$this->customAuth($request)) {
  529.             return new JsonResponse(['message' => 'Unauthorized'], 401, [
  530.                 'WWW-Authenticate' => 'Basic realm="API Access"',
  531.             ]);
  532.         }
  533.         $arr = [];
  534.         $ServiceOrderHistory $this->entityManager->getRepository(ServiceOrderHistory::class)->findBy(['status' => 'in_process']);
  535.         
  536.         foreach($ServiceOrderHistory as $service){
  537.             $arr[] = [
  538.                 'id' => $service->getId(),
  539.                 'id_crm' => $service->getIdCrm(),
  540.             ];
  541.         }
  542.         
  543.         
  544.         $rez = ['rez' => true'data' => $arr];
  545.     
  546.         $response = new JsonResponse();
  547.         $response->setData($rez);
  548.         return $response;
  549.     }
  550.     /** Історія заявок з сторонніх систем */
  551.     #[Route('/api/create-order-history'name'create_order_history'methods: ['POST'])]
  552.     public function create_order_history(Request $request)
  553.     {
  554.         if (!$this->customAuth($request)) {
  555.             return new JsonResponse(['message' => 'Unauthorized'], 401, [
  556.                 'WWW-Authenticate' => 'Basic realm="API Access"',
  557.             ]);
  558.         }
  559.         $data json_decode($request->getContent(), true);
  560.         $valid $this->valid$data, ['phone''account''service_code''status''id_crm'] );
  561.         if( empty($valid) ){
  562.             $find $this->entityManager->getRepository(User::class)->findOneBy(['phone' => $data['phone']]);
  563.             if($find){
  564.                 $arr = [];
  565.                 
  566.                 $orderNames = [
  567.                     =>  "Встановлення зонного лічильника",
  568.                     10 =>  "Лічильник не працює",
  569.                     21 =>  "Неправильний показ",
  570.                     32 =>  "Зміна власника",
  571.                     35 =>  "Підключення електроустановок замовника після виконання ТУ",
  572.                     63 =>  "Звернення щодо підозри на крадіжку",
  573.                     79 =>  "Заміна автоматичного вимикача, який опломбований ОСР",
  574.                     85 =>  "Відсутність пломб на засобі обліку",
  575.                     86 =>  "Закриття особового рахунку",
  576.                     200 =>  "Попередній запис в електронну чергу",
  577.                 ];
  578.                 $account false;
  579.                 foreach($find->getAppPersonalAccounts() as $acc){
  580.                     if(trim$acc->getNumber() ) == $data['account'])
  581.                         $account $acc;
  582.                 }
  583.                 
  584.                 if(!$account AND count($find->getAppPersonalAccounts()) > 0){
  585.                     $account $find->getAppPersonalAccounts()[0];
  586.                 }
  587.                 if($account){
  588.                     $ServiceOrderHistory = new ServiceOrderHistory();
  589.                     $ServiceOrderHistory->setName($orderNames[$data['service_code']]);
  590.                     $ServiceOrderHistory->setDateEntered( new \DateTime() );
  591.                     $ServiceOrderHistory->setType($data['service_code']);
  592.                     $ServiceOrderHistory->setStatus('new');
  593.                     $ServiceOrderHistory->setPersonalAccount($account);
  594.                     if(!empty( $data['id_crm'] ))
  595.                         $ServiceOrderHistory->setIdCrm$data['id_crm']);
  596.                     if(!empty( $data['status'] ))
  597.                         $ServiceOrderHistory->setStatus(  $data['status'] );
  598.                     else
  599.                         $ServiceOrderHistory->setStatus'in_process' );
  600.                     if(!empty( $data['description'] ))
  601.                         $ServiceOrderHistory->setDescription(  $data['description'] );
  602.         
  603.                     if($data['service_code'] == 200){
  604.                         $ServiceOrderHistory->setStatus('-100');
  605.                         $ServiceOrderHistory->setDescription('Виконано');
  606.                     }
  607.                     $ServiceOrderHistory->setPersonalAccount($account);
  608.                     $this->entityManager->persist($ServiceOrderHistory);
  609.                     $this->entityManager->flush();
  610.                     $data["id"] = $ServiceOrderHistory->getId();
  611.                     
  612.                     
  613.                     $rez = ['rez' => true'data' => [
  614.                         'id' => $ServiceOrderHistory->getId()
  615.                     ]];
  616.                 }else{
  617.                     $rez = ['rezult' => false'error' => "Нема жодного особового рахунку"];   
  618.                 }
  619.             }else{
  620.                 $rez = ['rezult' => false'error' => "Користувача не знайдено!"];   
  621.             }
  622.         
  623.         }else{
  624.             $rez = ['rez' => false'error' => "Не задано поля: $valid"];
  625.         }
  626.     
  627.         $response = new JsonResponse();
  628.         $response->setData($rez);
  629.         return $response;
  630.     }
  631.     #[Route('/notifications/health'name'notifications_health'methods: ['GET'])]
  632.     public function notifications_health(): JsonResponse
  633.     {
  634.         $now = new \DateTimeImmutable('now');
  635.         // За поточний день (з 00:00 локального часу сервера)
  636.         $startOfDay $now->setTime(000);
  637.         // За останню годину
  638.         $lastHour $now->modify('-1 hour');
  639.         $dayAgg   $this->notifications->getTotalsFrom($startOfDay);
  640.         $hourAgg  $this->notifications->getTotalsFrom($lastHour);
  641.         $makeCheck = static function (int $totalint $errors): array {
  642.             $errorRate $total $errors $total 0.0;
  643.             return [
  644.                 'total'      => $total,
  645.                 'errors'     => $errors,
  646.                 'errorRate'  => round($errorRate4),          // 0.3142 => 31.42%
  647.                 'over10'     => $total 10,
  648.                 'over30pct'  => $errorRate 0.60,
  649.                 'alert'      => ($total 10) && ($errorRate 0.30),
  650.             ];
  651.         };
  652.         $h $makeCheck($hourAgg['total'], $hourAgg['errors']);
  653.         $d $makeCheck($hourAgg['total'], $hourAgg['errors']);
  654.         // echo $_ENV['WHATSAPP_CHAT_ID']; die;
  655.         if($h['total'] > 10 AND $h['over30pct'] ){
  656.             $time date('Y-m-d H:i:s');
  657.             $from 'instance98373';
  658.             // відправка повідомлення
  659.             $ch curl_init();
  660.             curl_setopt($chCURLOPT_URL'https://bot.inneti.com/whatsapp_group/loe_report_2.php');
  661.             curl_setopt($chCURLOPT_TIMEOUT120);
  662.             curl_setopt($chCURLOPT_BUFFERSIZE128);
  663.             curl_setopt(
  664.                     $ch,
  665.                     CURLOPT_POSTFIELDS,
  666.                     [
  667.                             "msg_text"                  => 'Увага! В базі знайдено більше 30% ненадісланих сповіщень за останню годину! ('.$h['errors'].' з '.$h['total'].')',
  668.                             "from"                      => $from,
  669.                             "whatsapp_chat_id"          => $_ENV['WHATSAPP_CHAT_ID'],
  670.                             "token"                     =>"pg9n1fef6pkesrsl",
  671.                             "time"                      => $time,
  672.                             "hash"                      => hash_hmac('md5'"$from;$time;""$time;asdINNasd;$time"),
  673.                             'mm_type'                   => 'text',
  674.                     ]
  675.             );
  676.             curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  677.             curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  678.             curl_setopt($chCURLOPT_PROXY"");
  679.             $answer curl_exec($ch);
  680.             $error curl_error($ch);
  681.             curl_close($ch);
  682.         }
  683.         $result = [
  684.             'now'  => $now->format(DATE_ATOM),
  685.             'day'  => $d,
  686.             'hour' => $h,
  687.             'thresholds' => [
  688.                 'minTotal'    => 10,
  689.                 'maxErrorRate'=> 0.30,
  690.                 'errorStatuses'=> ['error','failed','warning'],
  691.             ],
  692.         ];
  693.         return $this->json($result);
  694.     }
  695.     #[Route('/notification/test'name'notification_test'methods: ['GET'])]
  696.     public function notification_test(): JsonResponse
  697.     {
  698.         $userIds = [
  699.             // 42,
  700.             // 31,
  701.             // 33,
  702.             // // 34,
  703.             // 35,
  704.             // 37,
  705.             // 38,
  706.         ];
  707.         $h date('H');
  708.         if($h 12){
  709.             $t" Гарного ранку ❤️";
  710.         }elseif($h 15){
  711.             $t" Гарного дня ❤️";
  712.         }elseif($h 22){
  713.             $t" Гарного вечора ❤️";
  714.         }else{
  715.             $t" Спите ? 😊😊😊";
  716.         }
  717.         foreach($userIds as $userId){
  718.             
  719.             $find $this->entityManager->getRepository(User::class)->findOneBy(['id' => $userId]);
  720.             if($find){
  721.                 $notification = new Notification();
  722.                 $notification->setUsers($find);
  723.                 $notification->setTitle('Тестове сповіщення!');
  724.                 $notification->setBodydate('Y-m-d H:i:s') . "\n Тестове сповіщення! \n Система розсилки повідомлень працює коректно. \n Якщо ви це читаєте, значить все добре! \n $t");
  725.         
  726.                 $notification->setType('text');
  727.                 $notification->setDateEntered( new \DateTime() );
  728.                 $notification->setStatus('new');
  729.                 $this->entityManager->persist($notification);
  730.                 $this->entityManager->flush();
  731.             }
  732.         }
  733.         return $this->json(['status' => 'ok']);
  734.     }
  735.     #[Route('/notification/test2'name'notification_test_t'methods: ['GET'])]
  736.     public function notification_test_t(): JsonResponse
  737.     {
  738.         $userIds = [
  739.             31,
  740.             
  741.         ];
  742.         foreach($userIds as $userId){
  743.             
  744.             $find $this->entityManager->getRepository(User::class)->findOneBy(['id' => $userId]);
  745.             if($find){
  746.                 $notification = new Notification();
  747.                 $notification->setUsers($find);
  748.                 $notification->setTitle('Тестове сповіщення!');
  749.                 $notification->setBodydate('Y-m-d H:i:s') . "\n TEST 3 ");
  750.         
  751.                 $notification->setType('text');
  752.                 $notification->setDateEntered( new \DateTime() );
  753.                 $notification->setStatus('new');
  754.                 $this->entityManager->persist($notification);
  755.                 $this->entityManager->flush();
  756.             }
  757.         }
  758.         return $this->json(['status' => 'ok']);
  759.     }
  760.     /** Додавання сповіщень в чергу з статусом "new" */
  761.     #[Route('/api/add-notification-in-queue'name'add_notification_in_queue'methods: ['GET'])]
  762.     public function add_notification_in_queue(Request $request)
  763.     {
  764.         if(file_exists('/var/www/symfony_docker/var/log/notificationCron.log')){
  765.             $logCron file_get_contents('/var/www/symfony_docker/var/log/notificationCron.log');
  766.             if(!empty( $logCron )){
  767.                 $fileContents json_decode($logCrontrue);
  768.                 $lastRunTime = isset($fileContents['start']) ? strtotime($fileContents['start']) : 0;
  769.                 $currentTime time();
  770.                 if( $fileContents['cron'] == 'Start' ){
  771.                 
  772.                     // Якщо останній запуск був менше ніж 5 хвилин тому, завершуємо виконання
  773.                     echo "$currentTime - $lastRunTime = " . ($currentTime $lastRunTime);
  774.                     if (($currentTime $lastRunTime) > 300) {
  775.                         $logCron =  json_encode([
  776.                             'cron' => 'Stop',
  777.                             'stop' => date('Y-m-d H:i:s'),
  778.                             'info' => 'The cron job was run less than 5 minutes ago. Exiting to prevent overlap.'
  779.                         ]);
  780.                         file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log',  $logCron);
  781.                     }
  782.                     var_dump($logCron);
  783.                     die;
  784.                 }
  785.             }
  786.             
  787.         }
  788.         file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log',  json_encode([
  789.             'cron' => 'Start',
  790.             'start' => date('Y-m-d H:i:s'),
  791.             'info' => 'Start notification cron'
  792.         ]));
  793.         
  794.         
  795.         // file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log');
  796.         $send 0;
  797.         $err 0;
  798.         /** Витягую всі ід сповіщень  */
  799.         
  800.         $notifications $this->entityManager->createQuery(
  801.                 'SELECT n.id FROM App\Entity\Notification n WHERE n.status = :status'
  802.             )
  803.             ->setParameter('status''new')
  804.             ->getScalarResult();    
  805.         $ids array_map(fn($r) => (int)$r['id'], $notifications);
  806.      
  807.         if($ids AND count($ids) > 0){
  808.             $dateStart date('Y-m-d H:i:s');
  809.             file_put_contents('/var/www/symfony_docker/var/log/notification.log',  "\n\n\n\nSTART-QUEUE-rabbitmq***************************** " .  $dateStart "\n"FILE_APPEND);
  810.             file_put_contents('/var/www/symfony_docker/var/log/notification.log',  "new ids - " implode(','$ids) . "\n"FILE_APPEND);
  811.             // Масове оновлення статусу та дати
  812.             $this->entityManager->createQuery(
  813.                 'UPDATE App\Entity\Notification n
  814.                 SET n.status = :newStatus, 
  815.                     n.dateSend = :now 
  816.                 WHERE n.id IN (:ids)'
  817.             )
  818.             ->setParameter('newStatus''in_progress')
  819.             ->setParameter('now', new \DateTime())
  820.             ->setParameter('ids'$ids)
  821.             ->execute();
  822.                     
  823.             foreach($ids as $id){
  824.                 $send 0;
  825.                 $priority 1;
  826.                 file_put_contents('/var/www/symfony_docker/var/log/notification.log'"#{$id} add to rabbitmq - " .  date('H:i:s.u') . "\n"FILE_APPEND);
  827.                 $queued false;
  828.                 $error  null;
  829.                 try {
  830.                     $env $this->bus->dispatch(new NotificationMessage($id, [], 'send-notification'$priority));
  831.                     // Якщо повідомлення надіслано у транспорт — з’являться SentStamp-и
  832.                     $sentStamps $env->all(SentStamp::class);
  833.                     if (!empty($sentStamps)) {
  834.                         $send++;
  835.                         file_put_contents('/var/www/symfony_docker/var/log/notification.log'"#{$id} rabbitmq-success " .  date('H:i:s.u') . "\n"FILE_APPEND);
  836.                         $queued true;
  837.                         // для логів можна подивитись куди саме:
  838.                         $targets array_map(fn(SentStamp $s) => $s->getSenderAlias() ?? $s->getTransportName(), $sentStamps);
  839.                         file_put_contents('/var/www/symfony_docker/var/log/notification.log',  'Sent to: '.implode(', '$targets).PHP_EOLFILE_APPEND);
  840.                     } else {
  841.                         $err++;
  842.                         // це означає, що роутінг не відправив у транспорт (наприклад, sync bus)
  843.                         $queued false;
  844.                         $error  'No SentStamp: message was not routed to a transport';
  845.                         file_put_contents('/var/www/symfony_docker/var/log/notification.log'"#{$id} rabbitmq-error " .  date('H:i:s.u') . " - No SentStamp: message was not routed to a transport\n"FILE_APPEND);
  846.                     }
  847.                 } catch (TransportExceptionInterface $e) {
  848.                     // Помилки транспорту/брокера (у т.ч. коли confirm_publish=true і брокер не підтвердив)
  849.                     $queued false;
  850.                     $error  $e->getMessage();
  851.                     $err++;
  852.                     file_put_contents('/var/www/symfony_docker/var/log/notification.log'"#{$id} rabbitmq-TransportExceptionInterface " .  date('H:i:s.u') . " - " $e->getMessage() . "\n"FILE_APPEND);
  853.                 } catch (\Throwable $e) {
  854.                     // будь-яка інша помилка
  855.                     $queued false;
  856.                     $error  $e->getMessage();
  857.                     $err++;
  858.                     file_put_contents('/var/www/symfony_docker/var/log/notification.log'"#{$id} rabbitmq-Throwable " .  date('H:i:s.u') . " - " $e->getMessage() . "\n"FILE_APPEND);
  859.                 }
  860.             }
  861.             file_put_contents('/var/www/symfony_docker/var/log/notification.log',  "END-QUEUE-rabbitmq***************************** start-$dateStart  end-" .  date('Y-m-d H:i:s') . "\n"FILE_APPEND);
  862.             file_put_contents('/var/www/symfony_docker/var/log/notification.log',  "22222222222222222222\n"FILE_APPEND);
  863.         }else{
  864.             $rez = ['rez' => false'error' => "Незнайдено нових сповіщень!"];
  865.         }
  866.         $logCron =  json_encode([
  867.             'cron' => 'Stop',
  868.             'stop' => date('Y-m-d H:i:s'),
  869.             'info' => 'Notification cron complete'
  870.         ]);
  871.         file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log',  $logCron);
  872.         $response = new JsonResponse();
  873.         $response->setData(['send' => $send'err' => $err]);
  874.         return $response;
  875.     }
  876. }