logger = $logger; $this->messageTextFactory = $messageTextFactory; $this->clientPhoneNumber = $clientPhoneNumber; $this->ucrmApi = UcrmApi::create(); } public function verifyPaymentActionToDo(NotificationData $notificationData): void { $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null); foreach ($arrayPhones as $type => $phones) { $type = trim(strtolower($type)); if (!is_array($phones)) continue; foreach ($phones as $phone) { switch ($type) { case 'whatsapp': $this->notifyAndUpdate($notificationData, $phone); break; case 'whatsnotifica': $this->notify($notificationData, $phone); break; case 'whatsactualiza': $this->onlyUpdate($notificationData, $phone); break; } } } } public function verifyClientActionToDo(NotificationData $notificationData): void { $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null); foreach ($arrayPhones as $type => $phones) { $type = trim(strtolower($type)); if (!is_array($phones)) continue; foreach ($phones as $phone) { if ($type === 'whatsapp' || $type === 'whatsactualiza') $this->onlyUpdate($notificationData, $phone); } } } public function verifyServiceActionToDo(NotificationData $notificationData): void { $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null); foreach ($arrayPhones as $type => $phones) { $type = trim(strtolower($type)); if (!is_array($phones)) continue; foreach ($phones as $phone) { if ($type === 'whatsapp' || $type === 'whatsactualiza') $this->onlyUpdateService($notificationData, $phone); } } } public function verifyJobActionToDo($jsonNotificationData, $reprogramming = null, $changeInstaller = null): void { $this->logger->info('Iniciando verifyJobActionToDo'); $clientId = $jsonNotificationData['extraData']['entity']['clientId']; $installerId = $jsonNotificationData['extraData']['entity']['assignedUserId']; $jobId = $jsonNotificationData['entityId']; $dateString = $jsonNotificationData['extraData']['entity']['date'] ?? null; $formattedDate = $dateString ? sprintf("*%s*", (new DateTime($dateString))->format('d/m/Y')) : ''; $config = PluginConfigManager::create()->loadConfig(); $admin = $this->ucrmApi->get("users/admins/$installerId", []); $installerName = trim(($admin['firstName'] ?? '') . ' ' . ($admin['lastName'] ?? '')); $installerWhatsApp = ''; $installers = json_decode($config['installersDataWhatsApp'] ?? '{"instaladores":[]}', true); foreach ($installers['instaladores'] as $inst) { if ($inst['id'] == $installerId) { $installerWhatsApp = $inst['whatsapp']; break; } } if (empty($installerWhatsApp)) { $this->logger->warning("No se encontró número de WhatsApp para el instalador ID: $installerId"); } $clientCRM = $this->ucrmApi->get("clients/$clientId", []); $clientName = trim(($clientCRM['firstName'] ?? '') . ' ' . ($clientCRM['lastName'] ?? '')); $passCRM = ''; foreach ($clientCRM['attributes'] as $attr) { if ($attr['key'] === 'passwordAntenaCliente') { $passCRM = $attr['value']; break; } } $allPhones = $this->clientPhoneNumber->getAllUcrmClientNumbers($clientCRM); $phonesStr = implode(', ', array_map(fn($n) => $this->validarNumeroTelefono($n), $allPhones)); $api = new ClientCallBellAPI($config['apitoken'], $config['ipserver'], $config['tokencallbell']); // --- Nueva Lógica de Prefijos --- $title = $jsonNotificationData['extraData']['entity']['title'] ?? ''; $isPending = (stripos($title, '[NOTIFICACION-PENDIENTE]') !== false); $isNoWhatsApp = (stripos($title, '[CLIENTE-SIN-WHATSAPP]') !== false); $reprogramming = filter_var($reprogramming, FILTER_VALIDATE_BOOLEAN); $changeInstaller = filter_var($changeInstaller, FILTER_VALIDATE_BOOLEAN); $clientPhones = $this->clientPhoneNumber->getUcrmClientNumbers(null, $clientCRM); $hasClientWhatsApp = false; foreach ($clientPhones as $type => $phones) { $type = trim(strtolower($type)); if (($type === 'whatsapp' || $type === 'whatsnotifica') && !empty($phones)) { $hasClientWhatsApp = true; break; } } $shouldNotifyTech = ($isPending || $reprogramming || $changeInstaller); $shouldNotifyClient = ($isPending || $isNoWhatsApp || $reprogramming || $changeInstaller); $this->logger->debug("Estado de notificación - Pending: " . ($isPending?'SI':'NO') . ", NoWhatsApp: " . ($isNoWhatsApp?'SI':'NO') . ", HasWA: " . ($hasClientWhatsApp?'SI':'NO')); // 1. Notificar al Instalador Anterior (Desasignación) if ($changeInstaller) { $prevId = $jsonNotificationData['extraData']['entityBeforeEdit']['assignedUserId']; $prevAdmin = $this->ucrmApi->get("users/admins/$prevId", []); $prevWhatsApp = ''; foreach ($installers['instaladores'] as $inst) { if ($inst['id'] == $prevId) { $prevWhatsApp = $inst['whatsapp']; break; } } if ($prevWhatsApp) { $api->sendJobNotificationWhatsAppToInstaller($this->validarNumeroTelefono($prevWhatsApp), [ "installerName" => "👷🏻‍♂️" . trim(($prevAdmin['firstName'] ?? '') . ' ' . ($prevAdmin['lastName'] ?? '')), "subjectOfChange" => self::SUBJECT_OF_INSTALLER_CHANGE[1], "jobId" => $jobId, "clientFullName" => "[$clientId] $clientName", "additionalChangeData" => self::ADDITIONAL_CHANGE_DATA[1] . ' *' . $installerName . '*', ], $reprogramming, $changeInstaller); sleep(1); } } // 2. Notificar al Cliente (si aplica) $clientNotified = false; if ($shouldNotifyClient && $hasClientWhatsApp) { foreach ($clientPhones as $type => $phones) { $type = trim(strtolower($type)); if (!is_array($phones) || ($type !== 'whatsapp' && $type !== 'whatsnotifica')) continue; foreach ($phones as $phone) { if ($api->sendJobNotificationWhatsAppToClient($this->validarNumeroTelefono($phone), ["clientFullName" => $clientName, "jobId" => $jobId, "date" => $formattedDate, "installerName" => $installerName], $reprogramming, $changeInstaller)) { $clientNotified = true; } } } } // 2. Notificar al Técnico (si aplica) if ($shouldNotifyTech) { $passVault = $this->getVaultCredentialsByClientId($clientId); $api->sendJobNotificationWhatsAppToInstaller($this->validarNumeroTelefono($installerWhatsApp), [ "installerName" => $installerName, "clientFullName" => "$clientName [ID:$clientId]", "jobId" => $jobId, "clientAddress" => $clientCRM['fullAddress'] ?? 'N/A', "clientWhatsApp" => !empty($phonesStr) ? $phonesStr : 'Sin WhatsApp', "date" => $formattedDate, "jobDescription" => $jsonNotificationData['extraData']['entity']['description'] ?? 'S/D', "gmapsLocation" => ($clientCRM['addressGpsLat'] && $clientCRM['addressGpsLon']) ? "https://www.google.com/maps?q={$clientCRM['addressGpsLat']},{$clientCRM['addressGpsLon']}" : 'N/A', "passwordAntenaCliente" => $this->comparePasswords($passCRM, $passVault) ], $reprogramming, $changeInstaller); } // 3. Gestión del Título / Prefijos if ($isPending) { if ($clientNotified || $reprogramming || $changeInstaller) { // Si el cliente fue notificado o es un cambio, quitamos el prefijo $newTitle = str_ireplace('[NOTIFICACION-PENDIENTE]', '', $title); $this->ucrmApi->patch("scheduling/jobs/$jobId", ['title' => trim($newTitle)]); } else if (!$hasClientWhatsApp) { // Si no tiene WhatsApp, cambiamos a estado "SIN-WHATSAPP" para no volver a notificar al técnico $newTitle = str_ireplace('[NOTIFICACION-PENDIENTE]', '[CLIENTE-SIN-WHATSAPP]', $title); $this->ucrmApi->patch("scheduling/jobs/$jobId", ['title' => trim($newTitle)]); } } else if ($isNoWhatsApp && ($clientNotified || $reprogramming || $changeInstaller)) { // Si estaba marcado como sin whatsapp y ahora sí pudimos notificarlo $newTitle = str_ireplace('[CLIENTE-SIN-WHATSAPP]', '', $title); $this->ucrmApi->patch("scheduling/jobs/$jobId", ['title' => trim($newTitle)]); } } public function verifyInvoiceActionToDo(NotificationData $notificationData): void { $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null); foreach ($arrayPhones as $type => $phones) { $type = trim(strtolower($type)); if (!is_array($phones)) continue; foreach ($phones as $phone) { if ($type === 'whatsapp' || $type === 'whatsactualiza') $this->onlyUpdate($notificationData, $phone, false); } } } public function notify(NotificationData $notificationData, $phoneToNotify = null): void { $config = PluginConfigManager::create()->loadConfig(); $api = new ClientCallBellAPI($config['apitoken'], $config['ipserver'], $config['tokencallbell']); $phone = $this->validarNumeroTelefono($phoneToNotify); if (!$phone) return; if ($config['notificationTypeText'] ?? false) $api->sendTextPaymentNotificationWhatsApp($phone, $notificationData); else $api->sendPaymentNotificationWhatsApp($phone, $notificationData); } public function notifyAndUpdate(NotificationData $notificationData, $phoneToNotifyAndUpdate = null): void { $config = PluginConfigManager::create()->loadConfig(); $api = new ClientCallBellAPI($config['apitoken'], $config['ipserver'], $config['tokencallbell']); $phone = $this->validarNumeroTelefono($phoneToNotifyAndUpdate); if (!$phone) return; if ($config['notificationTypeText'] ?? false) { if ($api->sendTextPaymentNotificationWhatsApp($phone, $notificationData)) { $contact = json_decode($api->getContactWhatsapp($phone), true); $api->patchWhatsapp($contact, $notificationData); } } else { if ($api->sendPaymentNotificationWhatsApp($phone, $notificationData)) { $contact = json_decode($api->getContactWhatsapp($phone), true); $api->patchWhatsapp($contact, $notificationData); } } } public function notifyOverDue(NotificationData $notificationData): void { $config = PluginConfigManager::create()->loadConfig(); $api = new ClientCallBellAPI($config['apitoken'], $config['ipserver'], $config['tokencallbell']); $phone = $this->clientPhoneNumber->getUcrmClientNumber($notificationData); if ($phone) $api->sendOverdueNotificationWhatsApp($phone, $notificationData); } public function onlyUpdate(NotificationData $notificationData, $phoneToUpdate): void { $config = PluginConfigManager::create()->loadConfig(); $api = new ClientCallBellAPI($config['apitoken'], $config['ipserver'], $config['tokencallbell']); $phone = $this->validarNumeroTelefono($phoneToUpdate); $contact = json_decode($api->getContactWhatsapp($phone), true); if ($contact) $api->patchWhatsapp($contact, $notificationData); } public function onlyUpdateService(NotificationData $notificationData, $phoneToUpdate): void { $config = PluginConfigManager::create()->loadConfig(); $api = new ClientCallBellAPI($config['apitoken'], $config['ipserver'], $config['tokencallbell']); $phone = $this->validarNumeroTelefono($phoneToUpdate); $contact = json_decode($api->getContactWhatsapp($phone), true); if ($contact) $api->patchServiceStatusWhatsApp($contact, $notificationData); } protected function getVaultCredentialsByClientId($clientId): string { $config = PluginConfigManager::create()->loadConfig(); if ($config['ipserver'] === '172.16.5.134') return 'gYAIEK:Be}SK*01z5+/V'; $unms = new Client(['base_uri' => "https://{$config['ipserver']}/nms/api/v2.1/", 'verify' => false]); $crm = new Client(['base_uri' => "https://{$config['ipserver']}/crm/api/v1.0/", 'verify' => false]); try { $respSvc = $crm->get('clients/services?clientId=' . $clientId, ['headers' => ['X-Auth-Token' => $config['apitoken']]]); $svcs = json_decode($respSvc->getBody()->getContents(), true); if (!isset($svcs[0]['unmsClientSiteId'])) return 'Error: Sin sitio'; $respDev = $unms->get("devices?siteId={$svcs[0]['unmsClientSiteId']}", ['headers' => ['X-Auth-Token' => $config['unmsApiToken']]]); $devs = json_decode($respDev->getBody()->getContents(), true); if (!isset($devs[0]['identification']['id'])) return 'Error: Sin equipo'; $respVault = $unms->get("vault/{$devs[0]['identification']['id']}/credentials", ['headers' => ['X-Auth-Token' => $config['unmsApiToken']]]); $vault = json_decode($respVault->getBody()->getContents(), true); return $vault['credentials'][0]['password'] ?? 'Error: Sin pass'; } catch (\Exception $e) { return 'Error: ' . $e->getMessage(); } } protected function comparePasswords(?string $crm, ?string $vault): string { if ($crm && strpos($crm, 'Error') !== 0) return $crm; if ($vault && strpos($vault, 'Error') !== 0) return $vault; return '⚠️ Probar pass conocida.'; } protected function validarNumeroTelefono($n): string { if (!$n) return ''; $n = preg_replace('/\D/', '', (string)$n); return (strlen($n) === 10) ? '52' . $n : $n; } abstract protected function sendWhatsApp(NotificationData $notificationData, string $clientSmsNumber): void; }