src/Controller/PlanityWebSocketController.php line 356

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Exception;
  4. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  5. use Symfony\Component\HttpFoundation\JsonResponse;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Symfony\Component\Routing\Annotation\Route;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use GuzzleHttp\Client;
  10. class PlanityWebSocketController extends AbstractController
  11. {
  12.     private $firebaseConfig = [
  13.         'apiKey' => "AIzaSyDrSE1PzMwLKyhEvh2x8eV7s1NYwKGRC5Q",
  14.         'authDomain' => "planity-production.firebaseapp.com",
  15.         'projectId' => "planity-production",
  16.         'storageBucket' => "planity-production.appspot.com",
  17.         'messagingSenderId' => "1025269755978",
  18.         'appId' => "1:1025269755978:web:26e77f72a3cbd599",
  19.         'databaseURL' => "https://planity-production-fr-13.europe-west1.firebasedatabase.app"
  20.     ];
  21.     private $client;
  22.     private $authToken;
  23.     public function __construct()
  24.     {
  25.         $this->client = new Client();
  26.     }
  27.     /**
  28.      * Initialise la connexion Firebase et récupère le token d'authentification
  29.      */
  30.     private function initialize(): void
  31.     {
  32.         // Vérifier si le token d'authentification existe déjà
  33.         if ($this->authToken !== null) {
  34.             // Déjà authentifié, ne rien faire
  35.             return;
  36.         }
  37.         try {
  38.             $response $this->client->post(
  39.                 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword',
  40.                 [
  41.                     'json' => [
  42.                         'email' => $_ENV['FIREBASE_EMAIL'] ?? 'contact@immybeauty.fr',
  43.                         'password' => $_ENV['FIREBASE_PASSWORD'] ?? 'Adamjamel93',
  44.                         'returnSecureToken' => true
  45.                     ],
  46.                     'query' => [
  47.                         'key' => $this->firebaseConfig['apiKey']
  48.                     ]
  49.                 ]
  50.             );
  51.             $data json_decode((string) $response->getBody(), true);
  52.             $this->authToken $data['idToken'];
  53.         } catch (\Exception $e) {
  54.             throw new \Exception('Erreur d\'authentification Firebase: ' $e->getMessage());
  55.         }
  56.     }
  57.     /**
  58.      * Récupère le planning pour une date donnée
  59.      */
  60.     public function getPlanning(string $date null): JsonResponse
  61.     {
  62.         try {
  63.             $this->initialize();
  64.             $date $date ?? date('Y-m-d');
  65.             $planningData $this->fetchPlanningData($date);
  66.             $validAppointments $this->filterValidAppointments($planningData);
  67.             $formattedAppointments $this->formatAppointments($validAppointments);
  68.             return new JsonResponse([
  69.                 'date' => $date,
  70.                 'appointments' => $formattedAppointments
  71.             ]);
  72.         } catch (\Exception $e) {
  73.             return new JsonResponse([
  74.                 'error' => 'Erreur lors de la récupération du planning',
  75.                 'message' => $e->getMessage()
  76.             ], 500);
  77.         }
  78.     }
  79.     /**
  80.      * Récupère les données du planning depuis Firebase
  81.      */
  82.     private function fetchPlanningData(string $date): array
  83.     {
  84.         $queryParams = [
  85.             'orderBy' => '"s"',
  86.             'startAt' => '"' $date ' 00:00:00"',
  87.             'endAt' => '"' $date ' 23:59:59"',
  88.             'auth' => $this->authToken
  89.         ];
  90.         $response $this->client->get(
  91.             $this->firebaseConfig['databaseURL'] . '/calendar_vevents/-NpLfj6VkVASdkJk886Q.json',
  92.             ['query' => $queryParams]
  93.         );
  94.         return json_decode((string) $response->getBody(), true) ?? [];
  95.     }
  96.     /**
  97.      * Filtre les rendez-vous valides (non supprimés)
  98.      */
  99.     private function filterValidAppointments(array $planningData): array
  100.     {
  101.         $validAppointments = [];
  102.         foreach ($planningData as $key => $event) {
  103.             if (!isset($event['dat'])) {
  104.                 $validAppointments[$key] = $event;
  105.             }
  106.         }
  107.         uasort($validAppointments, function($a$b) {
  108.             return strtotime($a['s']) - strtotime($b['s']);
  109.         });
  110.         return $validAppointments;
  111.     }
  112.     /**
  113.      * Formate les rendez-vous pour l'affichage
  114.      */
  115.     private function formatAppointments(array $appointments): array
  116.     {
  117.         $formattedAppointments = [];
  118.         $processedEmails = []; // Pour tracker les emails déjà traités
  119.         foreach ($appointments as $key => $event) {
  120.             $formattedAppointment $this->formatAppointment($key$event);
  121.             // Si l'appointment est valide (contient un email)
  122.             if ($formattedAppointment !== null) {
  123.                 $clientEmail $formattedAppointment['appointment']['client']['email'];
  124.                 // Vérifier si cet email n'a pas déjà été traité
  125.                 if (!in_array($clientEmail$processedEmails)) {
  126.                     $processedEmails[] = $clientEmail;
  127.                     $formattedAppointments[] = $formattedAppointment;
  128.                 }
  129.             }
  130.         }
  131.         return $formattedAppointments;
  132.     }
  133.     /**
  134.      * Récupère l'email d'un client via l'API Algolia si nécessaire
  135.      */
  136.     private function fetchClientEmail(string $clientId): string
  137.     {
  138.         try {
  139.             $httpClient = new Client();
  140.             $response $httpClient->post(
  141.                 'https://day79mubw3-dsn.algolia.net/1/indexes/business_customers/query',
  142.                 [
  143.                     'headers' => [
  144.                         'accept' => 'application/json',
  145.                         'content-type' => 'application/x-www-form-urlencoded',
  146.                         'x-algolia-agent' => 'Algolia for JavaScript (3.35.1); Browser',
  147.                         'x-algolia-application-id' => 'DAY79MUBW3',
  148.                         'x-algolia-api-key' => 'YjE0OWQzYWNkYzNkNThjMDM1MTk1MTMzZmM0NzQ5YzdkYmI0YjAzNDhiZThhM2RhNGEzNjA5NWJhZjdkNjQ1NGZpbHRlcnM9YnVzaW5lc3NJZCUzQS1Oak1aem5iVnBHZmpwR2M2aDho'
  149.                     ],
  150.                     'body' => json_encode([
  151.                         'params' => 'filters=id:"' $clientId '"&attributesToRetrieve=["email"]'
  152.                     ])
  153.                 ]
  154.             );
  155.             $result json_decode((string) $response->getBody(), true);
  156.             return $result['hits'][0]['email'] ?? '';
  157.         } catch (\Exception $e) {
  158.             error_log("Erreur lors de la récupération de l'email pour le client $clientId: " $e->getMessage());
  159.             return '';
  160.         }
  161.     }
  162.     /**
  163.      * Récupère l'email du client selon différentes sources
  164.      */
  165.     private function getClientEmail(array $event, array $clientstring $clientId): string
  166.     {
  167.         // Priorité 1: Email dans les données de l'événement
  168.         if (isset($event['t']) && $event['t'] === 'd' && isset($event['d']['b']['d']['email'])) {
  169.             return $event['d']['b']['d']['email'];
  170.         }
  171.         // Priorité 2: Email dans les données du client
  172.         if (isset($client['email'])) {
  173.             return $client['email'];
  174.         }
  175.         // Priorité 3: Recherche via Algolia
  176.         if ($clientId !== 'Non renseigné') {
  177.             try {
  178.                 return $this->fetchClientEmail($clientId);
  179.             } catch (\Exception $e) {
  180.                 error_log("Erreur lors de la récupération de l'email pour le client $clientId: " $e->getMessage());
  181.             }
  182.         }
  183.         return '';
  184.     }
  185.     /**
  186.      * Formate un rendez-vous individuel
  187.      */
  188.     private function formatAppointment($key$event): ?array
  189.     {
  190.         try {
  191.             $timestamp = isset($event['cat']) ? $event['cat'] : time();
  192.             // Préparation des données
  193.             $dateHeure = isset($event['s']) ? $event['s'] : 'Non renseigné';
  194.             $duree = isset($event['d']) ? $event['d'] : '0';
  195.             $modifieLe = isset($event['uat']) ? date('d/m/Y H:i:s'$event['uat']) : 'Non modifié';
  196.             // Client
  197.             // Client
  198.             $client = isset($event['cu']) ? $event['cu'] : array();
  199.             $clientNom = isset($client['name']) ? $client['name'] : 'Non renseigné';
  200.             $clientPhone = isset($client['phone']) ? $client['phone'] : 'Non renseigné';
  201.             $clientId = isset($client['id']) ? $client['id'] : 'Non renseigné';
  202.             // Tentative de récupération de l'email
  203.             $clientEmail $this->getClientEmail($event$client$clientId);
  204.             $clientId = isset($client['id']) ? $client['id'] : 'Non renseigné';
  205.             $clientSupprime = isset($client['d']) ? 'Oui' 'Non';
  206.             $nouveauClient = isset($event['nc']) && $event['nc'] === true 'Oui' 'Non';
  207.             // Prestation
  208.             $prestationNom = isset($event['t']) ? $event['t'] : 'Non renseigné';
  209.             $prestationPrix = isset($event['seop']) ? $event['seop'] : '0';
  210.             $prestationId = isset($event['se']) ? $event['se'] : 'Non renseigné';
  211.             $prestationOption = isset($event['seo']) ? $event['seo'] : 'Non renseigné';
  212.             $prestationIndex = isset($event['seoi']) ? $event['seoi'] : 'Non renseigné';
  213.             // Paiement
  214.             $paiementStatut = isset($event['opd']) ? $event['opd'] : 'Non renseigné';
  215.             $paiementMontant = isset($event['p']) ? $event['p'] : (isset($event['seop']) ? $event['seop'] : '0');
  216.             $paiementTransaction = isset($event['opcid']) ? $event['opcid'] : 'Non renseigné';
  217.             $paiementMethode = isset($event['oppm']) ? $event['oppm'] : 'Non renseigné';
  218.             $paiementReduction = isset($event['opcr']) ? $event['opcr'] : '0';
  219.             $paiementCarte = isset($event['opl4']) ? $event['opl4'] : 'Non renseigné';
  220.             // Source
  221.             $source = isset($event['cby']) ? $event['cby'] : 'Non renseigné';
  222.             $plateforme = isset($event['fo']) ? $event['fo'] : 'web';
  223.             $calendrierId = isset($event['ca']) ? $event['ca'] : 'Non renseigné';
  224.             $sequence = isset($event['sq']) ? $event['sq'] : 'Non renseigné';
  225. //            echo "
  226. //        <div style='margin: 20px; padding: 20px; border: 1px solid #ddd; border-radius: 8px; font-family: Arial;'>
  227. //            <h2 style='color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px;'>
  228. //                🕒 Rendez-vous #{$key}
  229. //            </h2>
  230. //
  231. //            <div style='display: grid; grid-template-columns: 1fr 1fr; gap: 20px;'>
  232. //                <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
  233. //                    <h3 style='color: #2980b9;'>⏰ Informations Horaires</h3>
  234. //                    <ul style='list-style: none; padding: 0;'>
  235. //                        <li><strong>Date/Heure:</strong> {$dateHeure}</li>
  236. //                        <li><strong>Durée:</strong> {$duree} minutes</li>
  237. //                        <li><strong>Créé le:</strong> " . date('d/m/Y H:i:s', $timestamp) . "</li>
  238. //                        <li><strong>Modifié le:</strong> {$modifieLe}</li>
  239. //                    </ul>
  240. //                </div>
  241. //
  242. //                <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
  243. //                    <h3 style='color: #2980b9;'>👤 Client</h3>
  244. //                    <ul style='list-style: none; padding: 0;'>
  245. //                        <li><strong>Nom:</strong> {$clientNom}</li>
  246. //                        <li><strong>Téléphone:</strong> {$clientPhone}</li>
  247. //                        <li><strong>Email:</strong> {$clientEmail}</li>
  248. //                        <li><strong>ID Client:</strong> {$clientId}</li>
  249. //                        <li><strong>Nouveau client:</strong> {$nouveauClient}</li>
  250. //                        <li><strong>Supprimé:</strong> {$clientSupprime}</li>
  251. //                    </ul>
  252. //                </div>
  253. //
  254. //                <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
  255. //                    <h3 style='color: #2980b9;'>💇 Prestation</h3>
  256. //                    <ul style='list-style: none; padding: 0;'>
  257. //                        <li><strong>Nom:</strong> {$prestationNom}</li>
  258. //                        <li><strong>Prix:</strong> {$prestationPrix}€</li>
  259. //                        <li><strong>ID Service:</strong> {$prestationId}</li>
  260. //                        <li><strong>Option Service:</strong> {$prestationOption}</li>
  261. //                        <li><strong>Index Option:</strong> {$prestationIndex}</li>
  262. //                    </ul>
  263. //                </div>
  264. //
  265. //                <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
  266. //                    <h3 style='color: #2980b9;'>💳 Paiement</h3>
  267. //                    <ul style='list-style: none; padding: 0;'>
  268. //                        <li><strong>Statut:</strong> {$paiementStatut}</li>
  269. //                        <li><strong>Montant:</strong> {$paiementMontant}€</li>
  270. //                        <li><strong>ID Transaction:</strong> {$paiementTransaction}</li>
  271. //                        <li><strong>Méthode:</strong> {$paiementMethode}</li>
  272. //                        <li><strong>Réduction:</strong> {$paiementReduction}%</li>
  273. //                        <li><strong>Derniers chiffres carte:</strong> {$paiementCarte}</li>
  274. //                    </ul>
  275. //                </div>
  276. //
  277. //                <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
  278. //                    <h3 style='color: #2980b9;'>📝 Métadonnées</h3>
  279. //                    <ul style='list-style: none; padding: 0;'>
  280. //                        <li><strong>Source:</strong> {$source}</li>
  281. //                        <li><strong>Plateforme:</strong> {$plateforme}</li>
  282. //                        <li><strong>ID Calendrier:</strong> {$calendrierId}</li>
  283. //                        <li><strong>Séquence:</strong> {$sequence}</li>
  284. //                    </ul>
  285. //                </div>
  286. //
  287. //                                <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
  288. //                    <h3 style='color: #2980b9;'>🔍 Données Brutes</h3>
  289. //                    <pre style='background: #eee; padding: 10px; overflow: auto; max-height: 200px;'>" .
  290. //                json_encode($event, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) .
  291. //                "</pre>
  292. //                </div>
  293. //            </div>
  294. //        </div>";
  295.             if (!empty($clientEmail)) {
  296.                 return [
  297.                     'appointment' => [
  298.                         'date' => $dateHeure,
  299.                         'client' => [
  300.                             'name' => $clientNom,
  301.                             'email' => $clientEmail
  302.                         ]
  303.                     ]
  304.                 ];
  305.             }
  306. // Si pas d'email, retourner null ou un tableau vide
  307.             return null// ou return [];
  308.         } catch (Exception $e) {
  309.             error_log("Erreur de formatage pour le rendez-vous $key: " json_encode($event));
  310.             throw $e;
  311.         }
  312.     }
  313.     #[Route('/admin/search-clients-planity'name'search_clients'methods: ['GET'])]
  314.     public function searchClientsFromPlanity(Request $request): JsonResponse
  315.     {
  316.         try {
  317.             $searchTerm $request->query->get('q');
  318.             $client = new Client();
  319.             $response $client->post(
  320.                 'https://day79mubw3-dsn.algolia.net/1/indexes/business_customers/query',
  321.                 [
  322.                     'headers' => [
  323.                         'accept' => 'application/json',
  324.                         'content-type' => 'application/x-www-form-urlencoded',
  325.                         'x-algolia-agent' => 'Algolia for JavaScript (3.35.1); Browser',
  326.                         'x-algolia-application-id' => 'DAY79MUBW3',
  327.                         'x-algolia-api-key' => 'YjE0OWQzYWNkYzNkNThjMDM1MTk1MTMzZmM0NzQ5YzdkYmI0YjAzNDhiZThhM2RhNGEzNjA5NWJhZjdkNjQ1NGZpbHRlcnM9YnVzaW5lc3NJZCUzQS1Oak1aem5iVnBHZmpwR2M2aDho'
  328.                     ],
  329.                     'body' => json_encode([
  330.                         'params' => "query={$searchTerm}&hitsPerPage=5"
  331.                     ])
  332.                 ]
  333.             );
  334.             $data json_decode((string) $response->getBody(), true);
  335.             return new JsonResponse($data);
  336.         } catch (\Exception $e) {
  337.             return new JsonResponse(['error' => $e->getMessage()], 500);
  338.         }
  339.     }
  340. }