+// ';
+
+// borrarArchivosPDFWordpress();
+// echo '
+// ';
+// }
+
+// function borrarArchivosPDFWordpress()
+// {
+// $log = PluginLogManager::create(); //Initialize Logger
+// $configManager = PluginConfigManager::create();
+// $config = $configManager->loadConfig();
+
+// // Configuración de conexión FTP
+// $ftp_server = $config['hostServerFTP'];
+// $ftp_username = $config['usernameServerFTP'];
+// $ftp_password = $config['passServerFTP'];
+// $remote_folder = "/public_html/wp/wp-content/uploads/img/";
+
+// // Conexión FTP
+// $ftp_conn = ftp_connect($ftp_server) or die("No se pudo conectar al servidor FTP");
+// $login = ftp_login($ftp_conn, $ftp_username, $ftp_password);
+// ftp_pasv($ftp_conn, true);
+
+// // Verificar conexión y login
+// if ($ftp_conn && $login) {
+// $log->appendLog("Conexión FTP exitosa" . PHP_EOL);
+
+// // Obtener lista de archivos en la carpeta
+// $files = ftp_nlist($ftp_conn, $remote_folder);
+// if (is_array($files)) {
+// // Eliminar la ruta del directorio de los archivos
+// $files = array_map(function($file) use ($remote_folder) {
+// return str_replace($remote_folder, '', $file);
+// }, $files);
+
+// // Obtener fechas de modificación
+// $filesWithTime = [];
+// foreach ($files as $file) {
+// $modifiedTime = ftp_mdtm($ftp_conn, $remote_folder . $file);
+// if ($modifiedTime != -1) {
+// $filesWithTime[$file] = $modifiedTime;
+// }
+// }
+
+// // Ordenar archivos por fecha de modificación, más recientes primero
+// arsort($filesWithTime);
+
+// // Obtener los archivos a eliminar (todos menos los 5 más recientes)
+// $filesToDelete = array_slice(array_keys($filesWithTime), 5);
+
+// // Eliminar archivos antiguos
+// foreach ($filesToDelete as $file) {
+// if (ftp_delete($ftp_conn, $remote_folder . $file)) {
+// echo '
' . $file . '
Archivo borrado
';
+// } else {
+// echo '
' . $file . '
Error al borrar archivo
';
+// }
+// }
+// $log->appendLog("Archivos eliminados" . PHP_EOL);
+// } else {
+// $log->appendLog("No se pudo obtener la lista de archivos de la carpeta FTP" . PHP_EOL);
+// }
+// // Cerrar conexión FTP
+// ftp_close($ftp_conn);
+// } else {
+// $log->appendLog("No se pudo conectar o iniciar sesión en el servidor FTP." . PHP_EOL);
+// }
+// }
+
+// // Verificar si se ha enviado una solicitud POST
+// if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["pintar"])) {
+// // Llamar a la función para imprimir la tabla
+// imprimirTabla();
+
+// }
+
+// // Contenido HTML para el formulario con el botón
+// $html = '
+//
+//
+//
+//
+//
+//
+//
+//
+//
Limpieza de archivos PDF de comprobantes de pago subidos a Wordpress para su envío
+//
+//
+//
+
+//
+//
+// ';
+// echo $html;
diff --git a/archivos_webhook_destino/src/Facade/AbstractMessageNotifierFacade.php b/archivos_webhook_destino/src/Facade/AbstractMessageNotifierFacade.php
new file mode 100755
index 0000000..0e5a4d6
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/AbstractMessageNotifierFacade.php
@@ -0,0 +1,1873 @@
+logger = $logger;
+ $this->messageTextFactory = $messageTextFactory;
+ $this->clientPhoneNumber = $clientPhoneNumber;
+
+ }
+
+ /*
+ * Verify contact type numbers to do notification, update or both
+ */
+ public function verifyPaymentActionToDo(NotificationData $notificationData): void
+ {
+
+ //$this->logger->debug(print_r(json_encode($notificationData),true).PHP_EOL);
+
+ // Obtener los números de teléfono de los contactos
+ $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);
+
+ // Imprimir el array de teléfonos
+ $this->logger->info(json_encode($arrayPhones));
+
+ // Procesar el array de teléfonos y ejecutar la función correspondiente
+ foreach ($arrayPhones as $type => $phones) {
+
+ // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
+ $this->logger->info("Procesando tipo de contacto original: '$type'");
+
+ // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
+ $type = trim(strtolower($type));
+
+ // Registrar el tipo de contacto después de la normalización
+ $this->logger->info("Tipo de contacto normalizado: '$type'");
+
+ // Asegurarse de que $phones es un array y recorrerlo
+ if (is_array($phones)) {
+ foreach ($phones as $phone) {
+ switch ($type) {
+ case 'whatsapp':
+ // Ejecutar función de notificación y actualización
+ $this->notifyAndUpdate($notificationData, $phone);
+ break;
+
+ case 'whatsnotifica':
+ // Ejecutar función de notificación
+ $this->notify($notificationData, $phone);
+ break;
+
+ case 'whatsactualiza':
+ // Ejecutar función de actualización
+ $this->onlyUpdate($notificationData, $phone, false);
+ break;
+
+ default:
+ // Registrar cuando el tipo no es reconocido
+ $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
+ break;
+ }
+ }
+ } else {
+ $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
+ }
+ }
+
+ }
+
+ /*
+ * Verify contact type numbers to do client's data update at CallBell
+ */
+ public function verifyClientActionToDo(NotificationData $notificationData): void
+ {
+ //$this->logger->debug("Verificar contactos" . PHP_EOL);
+
+ $this->logger->debug(print_r(json_encode($notificationData), true) . PHP_EOL);
+
+ $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);
+
+ // Procesar el array de teléfonos y ejecutar la función correspondiente
+ foreach ($arrayPhones as $type => $phones) {
+
+ // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
+ $this->logger->info("Procesando tipo de contacto original: '$type'");
+
+ // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
+ $type = trim(strtolower($type));
+
+ // Registrar el tipo de contacto después de la normalización
+ $this->logger->info("Tipo de contacto normalizado: '$type'");
+
+ // Asegurarse de que $phones es un array y recorrerlo
+ if (is_array($phones)) {
+ foreach ($phones as $phone) {
+ switch ($type) {
+ case 'whatsapp':
+ // Ejecutar función de notificación y actualización
+ $this->onlyUpdate($notificationData, $phone);
+ break;
+
+ case 'whatsactualiza':
+ // Ejecutar función de actualización
+ $this->onlyUpdate($notificationData, $phone);
+ break;
+
+ default:
+ // Registrar cuando el tipo no es reconocido
+ $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
+ break;
+ }
+ }
+ } else {
+ $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
+ }
+ }
+
+ }
+ /*
+ * Verify contact type numbers to do client's data service status at CallBell
+ */
+ public function verifyServiceActionToDo(NotificationData $notificationData): void
+ {
+
+ //$this->logger->debug(print_r(json_encode($notificationData),true).PHP_EOL);
+
+ $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);
+
+ // Procesar el array de teléfonos y ejecutar la función correspondiente
+ foreach ($arrayPhones as $type => $phones) {
+
+ // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
+ $this->logger->info("Procesando tipo de contacto original: '$type'");
+
+ // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
+ $type = trim(strtolower($type));
+
+ // Registrar el tipo de contacto después de la normalización
+ $this->logger->info("Tipo de contacto normalizado: '$type'");
+
+ // Asegurarse de que $phones es un array y recorrerlo
+ if (is_array($phones)) {
+ foreach ($phones as $phone) {
+ switch ($type) {
+ case 'whatsapp':
+ // Ejecutar función de notificación y actualización
+ $this->onlyUpdateService($notificationData, $phone);
+ break;
+
+ case 'whatsactualiza':
+ // Ejecutar función de actualización
+ $this->onlyUpdateService($notificationData, $phone);
+ break;
+
+ default:
+ // Registrar cuando el tipo no es reconocido
+ $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
+ break;
+ }
+ }
+ } else {
+ $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
+ }
+ }
+
+ }
+
+ /*
+ * Verify contact type numbers to do client's
+ */
+ public function verifyJobActionToDo($jsonNotificationData, $reprogramming = null, $changeInstaller = null): void
+ {
+
+ $this->logger->debug('******** INCIO DE LA FUNCIÓN verifyJobActionToDo ******' . PHP_EOL);
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ $IPServer = $config['ipserver'];
+ $UCRMAPIToken = $config['apitoken'];
+ $CallBellAPIToken = $config['tokencallbell'];
+ $IPServer = $config['ipserver'];
+ $installersData = $config['installersDataWhatsApp'];
+
+ $this->logger->debug('Valor de $jsonNotificationData en verifyJobActionToDo: ' . json_encode($jsonNotificationData) . PHP_EOL);
+
+ $clientId = $jsonNotificationData['extraData']['entity']['clientId'];
+ $installerId = $jsonNotificationData['extraData']['entity']['assignedUserId'];
+ $jobId = $jsonNotificationData['entityId'];
+ $jobDescription = $jsonNotificationData['extraData']['entity']['description'] ?? null;
+
+ $reprogrammingValue = var_export($reprogramming, true);
+ $changeInstallerValue = var_export($changeInstaller, true);
+ $this->logger->debug('Valor de $reprogramming en verifyJobActionToDo: ' . $reprogrammingValue . PHP_EOL);
+ $this->logger->debug('Valor de $changeInstaller en verifyJobActionToDo: ' . $changeInstallerValue . PHP_EOL);
+
+ // Obtener la fecha del nodo "entity"
+ $dateString = $jsonNotificationData['extraData']['entity']['date'] ?? null;
+
+ if ($dateString) {
+ // Crear un objeto DateTime a partir de la fecha
+ $date = new DateTime($dateString);
+
+
+ // concaternar emoji de reloj de la hora que más se asemeje a la hora del evento, por ejemplo si la hora es 8:00 am o pm se concatena el emoji de reloj de las 8:00 am o pm como: 🕗
+ $hour = $date->format('h');
+ $clockEmoji = "🕐"; // Emoji por defecto
+ // Determinar el emoji del reloj según la hora
+ // switch ($hour) {
+ // case '01':
+ // $clockEmoji = "🕐";
+ // break;
+ // case '02':
+ // $clockEmoji = "🕑";
+ // break;
+ // case '03':
+ // $clockEmoji = "🕒";
+ // break;
+ // case '04':
+ // $clockEmoji = "🕓";
+ // break;
+ // case '05':
+ // $clockEmoji = "🕔";
+ // break;
+ // case '06':
+ // $clockEmoji = "🕕";
+ // break;
+ // case '07':
+ // $clockEmoji = "🕖";
+ // break;
+ // case '08':
+ // $clockEmoji = "🕗";
+ // break;
+ // case '09':
+ // $clockEmoji = "🕘";
+ // break;
+ // case '10':
+ // $clockEmoji = "🕙";
+ // break;
+ // case '11':
+ // $clockEmoji = "🕚";
+ // break;
+ // case '12':
+ // $clockEmoji = "🕛";
+ // break;
+ // }
+
+ // Formatear la fecha al formato deseado: día/mes/año a las hora:minuto am/pm aproximadamente
+ // $formattedDate = "*" . $date->format('d/m/Y') . "* a las $clockEmoji *" . $date->format('h:i A') . "* aproximadamente";
+ $formattedDate = sprintf("*%s*", $date->format('d/m/Y'));
+
+
+ // $this->logger->debug('Valor de $formattedDate en verifyJobActionToDo: ' . $formattedDate . PHP_EOL);
+ } else {
+ $this->logger->error('La fecha no está disponible en el JSON' . PHP_EOL);
+ }
+
+ $this->logger->debug('Valor de $installersData en verifyJobActionToDo: ' . $installersData . PHP_EOL);
+
+ $this->ucrmApi = UcrmApi::create();
+ $usersInstallers = $this->ucrmApi->get('users/admins/' . $installerId, []);
+ $this->logger->debug('Valor de $usersInstallers en verifyJobActionToDo: ' . json_encode($usersInstallers) . PHP_EOL);
+
+ // Inicializar la variable para el nombre completo
+ $installerFullName = '';
+
+ $jsonInstallersData = json_decode($installersData, true);
+
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ $this->logger->error('Error al decodificar el JSON de instaladores: ' . json_last_error_msg());
+ return;
+ }
+
+ // Verificar si el nodo "instaladores" existe
+ if (!isset($jsonInstallersData['instaladores'])) {
+ $this->logger->error('El nodo "instaladores" no existe en el JSON');
+ return;
+ }
+
+ // Buscar el número de WhatsApp en el JSON
+ $installerWhatsApp = '';
+ foreach ($jsonInstallersData['instaladores'] as $installer) {
+ if ($installer['id'] === $installerId) {
+ $installerWhatsApp = $installer['whatsapp'];
+ break;
+ }
+ }
+ //$this->logger->debug('tipo de dato de installerWhatsApp: ' . gettype($installerWhatsApp) . PHP_EOL);
+
+ // Validar si se encontró el WhatsApp
+ if (empty($installerWhatsApp)) {
+ $this->logger->warning('No se encontró un número de WhatsApp para el instalador con ID 1019');
+ } else {
+ $this->logger->debug('Número de WhatsApp del Instalador: ' . $installerWhatsApp . PHP_EOL);
+ }
+
+ $this->ucrmApi = UcrmApi::create();
+ $usersInstallers = $this->ucrmApi->get('users/admins/' . $installerId, []);
+ //$this->logger->debug('Valor de $usersInstallers ' . json_encode($usersInstallers) . PHP_EOL);
+
+ $firstName = $usersInstallers['firstName'] ?? '';
+ $lastName = $usersInstallers['lastName'] ?? '';
+ $installerFullName = trim("$firstName $lastName");
+ $this->logger->debug('Valor de $installerFullName: ' . $installerFullName . PHP_EOL);
+
+ $baseUri = 'https://' . $IPServer . '/crm/api/v1.0/';
+
+ $clientGuzzleHttp = new Client([
+ 'base_uri' => $baseUri,
+ 'headers' => [
+ 'X-Auth-App-Key' => $UCRMAPIToken,
+ 'Accept' => 'application/json',
+ ],
+ 'verify' => false,
+ ]);
+
+ $responseClients = $clientGuzzleHttp->request('GET', "clients/" . $clientId);
+ $arrayClientCRM = json_decode($responseClients->getBody()->getContents(), true);
+ // $this->logger->debug('Valor de $arrayClientCRM en verifyJobActionToDo: ' . json_encode($arrayClientCRM) . PHP_EOL);
+ //ejemplo de $arrayClientCRM: {"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Chiapas 31","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente espacial, el m\u00e1s chido","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":false,"types":[]},{"id":170,"clientId":2,"email":null,"phone":"5214181148783","name":null,"isBilling":false,"isContact":false,"types":[{"id":1000,"name":"WhatsApp"}]}],"attributes":[{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false},{"id":200,"clientId":2,"customAttributeId":14,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https","clientZoneVisible":false},{"id":202,"clientId":2,"customAttributeId":17,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"gYAIEK:Be}SK*01z5+\/V","clientZoneVisible":false}],"accountBalance":-200,"accountCredit":100,"accountOutstanding":300,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564414,"addressGpsLon":-100.9383654,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}
+
+ //buscar en los attributes del cliente el atributo de con la key "passwordAntenaCliente" y almacenar su valor en la variable $passwordAntenaClienteCRM
+ $passwordAntenaClienteCRM = '';
+ foreach ($arrayClientCRM['attributes'] as $attribute) {
+ if ($attribute['key'] === 'passwordAntenaCliente') {
+ $passwordAntenaClienteCRM = $attribute['value'];
+ $this->logger->debug('Valor de $passwordAntenaClienteCRM en verifyJobActionToDo: ' . $passwordAntenaClienteCRM . PHP_EOL);
+ break;
+ }
+ }
+
+ $clientFullName = sprintf("%s %s", $arrayClientCRM['firstName'], $arrayClientCRM['lastName']);
+
+ // Extraer la dirección completa
+ $fullAddress = $arrayClientCRM['fullAddress'] ?? null;
+
+ // Validar si la dirección completa está disponible
+ if ($fullAddress) {
+ // Convertir la dirección a HTML seguro
+ $safeAddress = htmlspecialchars($fullAddress, ENT_QUOTES, 'UTF-8');
+ // $this->logger->debug('Dirección completa: ' . $safeAddress . PHP_EOL);
+ } else {
+ $this->logger->error('La dirección completa no está disponible en el JSON' . PHP_EOL);
+ }
+
+ // Extraer las coordenadas del nodo "entity"
+ $gpsLat = $arrayClientCRM['addressGpsLat'] ?? null;
+ $gpsLon = $arrayClientCRM['addressGpsLon'] ?? null;
+
+ // Validar si las coordenadas están disponibles
+ if ($gpsLat && $gpsLon) {
+ // Construir la URL de Google Maps
+ $googleMapsUrl = sprintf('https://www.google.com/maps?q=%s,%s', $gpsLat, $gpsLon);
+ // $this->logger->debug('URL de Google Maps: ' . $googleMapsUrl . PHP_EOL);
+ } else {
+ $googleMapsUrl = 'Las coordenadas no están disponibles en este cliente.';
+ $this->logger->error('Las coordenadas no están disponibles en el JSON' . PHP_EOL);
+ }
+
+ $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers(null, $arrayClientCRM);
+ // $this->logger->debug('Valor de $arrayPhones en verifyJobActionToDo: ' . json_encode($arrayPhones) . PHP_EOL);
+
+ $arrayAllPhones = $this->clientPhoneNumber->getAllUcrmClientNumbers($arrayClientCRM);
+
+ // Convertir el array de teléfonos en una cadena separada por comas
+ $clientAllPhonesString = implode(',', $arrayAllPhones);
+ $this->logger->debug('Valor de $clientAllPhonesString en verifyJobActionToDo: ' . $clientAllPhonesString . PHP_EOL);
+
+ // Dividir los números en un array
+ $arrayNumeros = explode(',', $clientAllPhonesString);
+ $this->logger->debug('Valor de $arrayNumeros en verifyJobActionToDo: ' . json_encode($arrayNumeros) . PHP_EOL);
+
+ // Procesar cada número
+ $resultados = [];
+ foreach ($arrayNumeros as $numero) {
+ $numero = trim($numero);
+ $numeroValidado = $this->validarNumeroTelefono($numero);
+
+ // Asegurar que solo quedan números
+ $numeroValidado = preg_replace('/\D/', '', $numeroValidado);
+
+ // Si empieza con 521 y tiene más de 12 dígitos, lo quitamos
+ if (substr($numeroValidado, 0, 3) === "521") {
+ $resultados[] = substr($numeroValidado, 3);
+ } else {
+ $resultados[] = $numeroValidado;
+ }
+ }
+ $this->logger->debug('Valor de $resultados en verifyJobActionToDo: ' . json_encode($resultados) . PHP_EOL);
+
+ // Convertir el array de resultados en una cadena separada por comas
+ $resultadoFinalNumerosCliente = implode(', ', $resultados);
+ $this->logger->debug('Valor de $resultadoFinalNumerosCliente en verifyJobActionToDo: ' . $resultadoFinalNumerosCliente . PHP_EOL);
+
+ $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
+
+ // Construir el array asociativo con los datos de la notificación para el cliente
+ $jsonClientJobNotificationData = [
+ "clientFullName" => $clientFullName,
+ "jobId" => $jobId,
+ "date" => $formattedDate,
+ "installerName" => $installerFullName,
+ ];
+
+ $clientWhatsApp = '';
+
+ //Parte de la notificación al cliente
+ // Procesar el array de teléfonos y ejecutar la función correspondiente
+ foreach ($arrayPhones as $type => $phones) {
+
+ // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
+ $type = trim(strtolower($type));
+
+ switch ($type) {
+ case 'whatsapp':
+ case 'whatsnotifica':
+ $this->logger->debug("Se encontró un tipo de contacto $type" . PHP_EOL);
+
+ // Verificar si el valor es un array de teléfonos
+ if (is_array($phones)) {
+ $attempts = 0;
+ $maxAttempts = 3;
+ $result = false;
+ foreach ($phones as $phone) {
+
+ //Aquí se enviará la notificación al cliente
+ // Reintentar hasta 3 veces si la función retorna false
+ while ($attempts < $maxAttempts && $result === false) {
+ $attempts++;
+ $result = $client_callbell_api->sendJobNotificationWhatsAppToClient(
+ $this->validarNumeroTelefono($phone), // Validar número de teléfono
+ $jsonClientJobNotificationData, // Datos de notificación
+ $reprogramming, // Reprogramación
+ $changeInstaller // Cambio de instalador
+ );
+
+ if ($result === false) {
+ sleep(1); // Esperar 1 segundo antes de reintentar
+ $this->logger->warning("Intento $attempts fallido en el envío de notificación a $phone. Reintentando..." . PHP_EOL);
+ }
+ }
+
+ // Verificar el resultado final
+ if ($result === true) {
+ $this->logger->info("Notificación enviada correctamente al cliente con teléfono $phone después de $attempts intento(s)." . PHP_EOL);
+ $title = $jsonNotificationData['extraData']['entity']['title'];
+ $this->logger->debug('Valor de $title en verifyJobActionToDo: ' . $title . PHP_EOL);
+ //la variable $title contiene el título del trabajo con un prefijo "[NOTIFICACION-PENDIENTE]" aquí hay que quitarlo
+
+ // $this->ucrmApi = UcrmApi::create();
+ // $responsePatch = $this->ucrmApi->patch('scheduling/jobs/' . $jsonNotificationData['entityId'], [
+ // 'title' => $title,
+ // ]);
+ if (strpos($title, '[NOTIFICACION-PENDIENTE]') !== false) { //si el título contiene el prefijo [NOTIFICACION-PENDIENTE] entonces se quita
+ $title = str_replace('[NOTIFICACION-PENDIENTE]', '', $title); // Quitar el prefijo
+ $responseClients = $clientGuzzleHttp->request('PATCH', "scheduling/jobs/" . $jsonNotificationData['entityId'], [
+ 'json' => [
+ 'title' => $title,
+ ],
+ ]);
+ $this->logger->debug('Valor de $title después de quitar el prefijo en verifyJobActionToDo: ' . $title . PHP_EOL);
+ break;
+
+ } else {
+ $this->logger->debug('El título no contiene el prefijo [NOTIFICACION-PENDIENTE] en verifyJobActionToDo: ' . $title . PHP_EOL);
+ }
+
+ } else {
+ $this->logger->error("No se pudo enviar la notificación al cliente con teléfono $phone después de $maxAttempts intentos." . PHP_EOL);
+ }
+ }
+ } else {
+ $this->logger->warning("No se encontraron números de teléfono para el tipo de contacto $type." . PHP_EOL);
+ }
+
+ break;
+
+ default:
+ $this->logger->info("Tipo de contacto no reconocido: $type" . PHP_EOL);
+ break;
+ }
+ }
+
+ // --- ¡AÑADE ESTAS LÍNEAS PARA CONVERTIR A BOOLEANO REAL! ---
+ $reprogramming = filter_var($reprogramming, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ $changeInstaller = filter_var($changeInstaller, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ // -----------------------------------------------------------
+
+ // Puedes volver a loggear los valores para confirmar la conversión (opcional)
+ $this->logger->debug("DEBUG: Valores después de conversión para mensaje instalador - Reprogramming: " . var_export($reprogramming, true) . ", ChangeInstaller: " . var_export($changeInstaller, true) . PHP_EOL);
+
+
+ if ($changeInstaller) { //Si se cambió el instalador
+ $this->logger->debug('Se cambió el instalador, por lo tanto se procede a enviarle mensaje al que se le desasignó' . PHP_EOL);
+
+ // Construir el array asociativo con los datos de la notificación
+
+ //Enviar notificación al instalador anterior
+
+ $previousinstallerInstallerId = $installerId = $jsonNotificationData['extraData']['entityBeforeEdit']['assignedUserId'];
+ $usersInstallers = $this->ucrmApi->get('users/admins/' . $previousinstallerInstallerId, []);
+ $firstNamePreviousInstaller = $usersInstallers['firstName'] ?? ''; //Obtener el nombre del instalador anterior
+ $lastNamePreviousInstaller = $usersInstallers['lastName'] ?? ''; //Obtener el apellido del instalador anterior
+ $previousInstallerFullName = trim("$firstNamePreviousInstaller $lastNamePreviousInstaller");
+ $attempts = 0;
+ $maxAttempts = 3;
+ $result = false;
+
+ $jsonPreviousInstallerJobNotificationData = [
+ "installerName" => "👷🏻♂️" . $previousInstallerFullName,
+ "subjectOfChange" => self::SUBJECT_OF_INSTALLER_CHANGE[1],
+ "jobId" => $jobId,
+ "clientFullName" => sprintf("[%s] %s", $arrayClientCRM['id'], $clientFullName),
+ "additionalChangeData" => self::ADDITIONAL_CHANGE_DATA[1] . ' *' . $installerFullName . '*',
+
+ ];
+
+ // Buscar el número de WhatsApp en el JSON del instalador anterior
+ $previousInstallerWhatsApp = '';
+ foreach ($jsonInstallersData['instaladores'] as $installer) {
+ if ($installer['id'] === $previousinstallerInstallerId) {
+ $previousInstallerWhatsApp = $installer['whatsapp'];
+ $this->logger->debug('Se encontró el Whatsapp del instalador anterior en el JSON y es: ' . $previousInstallerWhatsApp . PHP_EOL);
+ break;
+ }
+ }
+
+ //Enviar mensaje al instalador anterior
+ // Reintentar hasta 3 veces si la función retorna false
+ while ($attempts < $maxAttempts && $result === false) {
+ $attempts++;
+ $result = $client_callbell_api->sendJobNotificationWhatsAppToInstaller(
+ $this->validarNumeroTelefono((string) $previousInstallerWhatsApp),
+ $jsonPreviousInstallerJobNotificationData,
+ $reprogramming,
+ $changeInstaller,
+ ''
+
+ );
+
+ if ($result === false) {
+ sleep(1);
+ $this->logger->warning("Intento $attempts fallido para enviar notificación a $phone. Reintentando..." . PHP_EOL);
+ }
+ }
+
+ sleep(4);
+
+ // Construir el array asociativo con los datos de la notificación para el instalador nuevo
+ $jsonInstallerJobNotificationData = [
+ "installerName" => $installerFullName,
+ "clientFullName" => sprintf("%s [ID:%s]", $clientFullName, $arrayClientCRM['id']),
+ "jobId" => $jobId,
+ "clientAddress" => $safeAddress,
+ "clientWhatsApp" => $resultadoFinalNumerosCliente,
+ "date" => $formattedDate,
+ "jobDescription" => $jobDescription,
+ "gmapsLocation" => $googleMapsUrl,
+ "passwordAntenaCliente" => ''
+
+ ];
+
+ //obtener la contraseña de la antena con el método getVaultCredentialsByClientId y compararlo con el campo de la contraseña de la antena en el CRM
+ $passwordVault = $this->getVaultCredentialsByClientId($arrayClientCRM['id']);
+
+ //Comparar las contraseñas y obtener la que se enviará al instalador
+ $jsonInstallerJobNotificationData['passwordAntenaCliente'] = $this->comparePasswords($passwordAntenaClienteCRM, $passwordVault);
+
+
+
+ //Enviar notificación al instalador nuevo
+
+ $attempts = 0;
+ $maxAttempts = 3;
+ $result = false;
+
+ // Reintentar hasta 3 veces si la función retorna false
+ while ($attempts < $maxAttempts && $result === false) {
+ $attempts++;
+ $result = $client_callbell_api->sendJobNotificationWhatsAppToInstaller(
+ $this->validarNumeroTelefono((string) $installerWhatsApp),
+ $jsonInstallerJobNotificationData,
+ false,
+ false,
+
+ );
+
+ if ($result === false) {
+ sleep(1);
+ $this->logger->warning("Intento $attempts fallido para enviar notificación a $phone. Reintentando..." . PHP_EOL);
+ }
+ }
+
+ } else { //si el instalador no cambió
+ $this->logger->debug('No se cambió el instalador' . PHP_EOL);
+
+ // Construir el array asociativo con los datos de la notificación
+ $jsonInstallerJobNotificationData = [
+ "installerName" => $installerFullName,
+ "clientFullName" => sprintf("%s [ID:%s]", $clientFullName, $arrayClientCRM['id']),
+ "jobId" => $jobId,
+ "clientAddress" => $safeAddress,
+ "clientWhatsApp" => $resultadoFinalNumerosCliente,
+ "date" => $formattedDate,
+ "jobDescription" => $jobDescription,
+ "gmapsLocation" => $googleMapsUrl,
+ "passwordAntenaCliente" => ''
+
+ ];
+
+ //obtener la contraseña de la antena con el método getVaultCredentialsByClientId y compararlo con el campo de la contraseña de la antena en el CRM
+ $passwordVault = $this->getVaultCredentialsByClientId($arrayClientCRM['id']);
+
+ //Comparar las contraseñas y obtener la que se enviará al instalador
+ $jsonInstallerJobNotificationData['passwordAntenaCliente'] = $this->comparePasswords($passwordAntenaClienteCRM, $passwordVault);
+
+
+
+
+ $attempts = 0;
+ $maxAttempts = 3;
+ $result = false;
+
+ // // Reintentar hasta 3 veces si la función retorna false
+ while ($attempts < $maxAttempts && $result === false) {
+ $attempts++;
+ $result = $client_callbell_api->sendJobNotificationWhatsAppToInstaller(
+ $this->validarNumeroTelefono((string) $installerWhatsApp),
+ $jsonInstallerJobNotificationData,
+ $reprogramming,
+ $changeInstaller,
+
+ );
+
+ if ($result === false) {
+ sleep(1);
+ $this->logger->warning("Intento $attempts fallido para enviar notificación a $phone. Reintentando..." . PHP_EOL);
+ }
+ }
+
+ }
+
+ }
+
+ /*
+ * Verify contact type numbers to do client's data update at CallBell by invoice add or edit
+ */
+ public function verifyInvoiceActionToDo(NotificationData $notificationData): void
+ {
+
+ $accountBalance = $notificationData->clientData['accountBalance'];
+ $this->logger->debug(print_r(json_encode($notificationData), true) . PHP_EOL);
+
+ $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);
+
+ // Procesar el array de teléfonos y ejecutar la función correspondiente
+ foreach ($arrayPhones as $type => $phones) {
+
+ // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
+ $this->logger->info("Procesando tipo de contacto original: '$type'");
+
+ // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
+ $type = trim(strtolower($type));
+
+ // Registrar el tipo de contacto después de la normalización
+ $this->logger->info("Tipo de contacto normalizado: '$type'");
+
+ // Asegurarse de que $phones es un array y recorrerlo
+ if (is_array($phones)) {
+ foreach ($phones as $phone) {
+ switch ($type) {
+ case 'whatsapp':
+ // Ejec vb bbnbbnbvnutar función de notificación y actualización
+ $this->onlyUpdate($notificationData, $phone, false);
+ break;
+
+ case 'whatsactualiza':
+ // Ejecutar función de actualización
+ $this->onlyUpdate($notificationData, $phone, false);
+ break;
+
+ default:
+ // Registrar cuando el tipo no es reconocido
+ $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
+ break;
+ }
+ }
+ } else {
+ $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
+ }
+ }
+ }
+
+ /*
+ * Notify to client with the payment receipt via WhatsApp
+ */
+ public function notify(NotificationData $notificationData, $phoneToNotify = null): void
+ {
+
+ // $notification_client_data = $notificationData->clientData; //array con los datos del cliente
+
+ // $notification_client_data_export = json_encode($notification_client_data);
+ // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ // the "exportFormat" key must be defined in plugin's manifest file, see the link above
+ $IPServer = $config['ipserver'];
+ $UCRMAPIToken = $config['apitoken'];
+ $CallBellAPIToken = $config['tokencallbell'];
+ $notificationTypeText = $config['notificationTypeText'];
+
+ $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
+
+ //$clientPhoneNumber = $this->clientPhoneNumber->getUcrmClientNumber($notificationData);
+ $clientPhoneNumber = $this->validarNumeroTelefono($phoneToNotify); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"
+
+ //$this->logger->debug("Numero de cel obtenido " . $clientPhoneNumber . PHP_EOL);
+
+ if (empty($clientPhoneNumber)) {
+ $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
+ return;
+ } else {
+
+ if ($notificationTypeText) {
+ try {
+ $attempts = 0;
+ $maxAttempts = 3;
+ $result = false;
+
+ while ($attempts < $maxAttempts && !$result) {
+ $attempts++;
+ $result = $client_callbell_api->sendTextPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData);
+
+ if (!$result) {
+ $this->logger->warning("Intento $attempts fallido para enviar notificación de texto al cliente con número $clientPhoneNumber." . PHP_EOL);
+ }
+ }
+
+ if ($result) {
+ $this->logger->info("Notificación de texto enviada correctamente al cliente con número $clientPhoneNumber después de $attempts intento(s)." . PHP_EOL);
+ } else {
+ $this->logger->error("No se pudo enviar la notificación de texto al cliente con número $clientPhoneNumber después de $maxAttempts intentos." . PHP_EOL);
+ }
+ } catch (HttpException $httpException) {
+ $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
+ }
+
+ } else {
+ try {
+ $attempts = 0;
+ $maxAttempts = 3;
+ $result = false;
+
+ while ($attempts < $maxAttempts && !$result) {
+ $attempts++;
+ $result = $client_callbell_api->sendPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData);
+
+ if (!$result) {
+ $this->logger->warning("Intento $attempts fallido para enviar notificación al cliente con número $clientPhoneNumber." . PHP_EOL);
+ }
+ }
+
+ if ($result) {
+ $this->logger->info("Notificación enviada correctamente al cliente con número $clientPhoneNumber después de $attempts intento(s)." . PHP_EOL);
+ } else {
+ $this->logger->error("No se pudo enviar la notificación al cliente con número $clientPhoneNumber después de $maxAttempts intentos." . PHP_EOL);
+ }
+ } catch (HttpException $httpException) {
+ $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
+ }
+
+ }
+
+ }
+
+ // $messageBody = $this->messageTextFactory->createBody($notificationData);
+ // if (! $messageBody) {
+ // $this->logger->info('No text configured for event: ' . $notificationData->eventName);
+ // return;
+ // }
+
+ }
+
+ /*
+ * Notify to client with the payment receipt via WhatsApp and Update the client's data at CallBell
+ */
+ public function notifyAndUpdate(NotificationData $notificationData, $phoneToNotifyAndUpdate = null): void
+ {
+ $this->logger->debug("***Se notifica y actualiza al cliente sobre su pago***" . PHP_EOL);
+
+ // $notification_client_data = $notificationData->clientData; //array con los datos del cliente
+
+ // $notification_client_data_export = json_encode($notification_client_data);
+ // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);
+ //$this->logger->debug("Creando instancia callbell ".PHP_EOL);
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ // the "exportFormat" key must be defined in plugin's manifest file, see the link above
+ $IPServer = $config['ipserver'];
+ $UCRMAPIToken = $config['apitoken'];
+ $CallBellAPIToken = $config['tokencallbell'];
+ $notificationTypeText = $config['notificationTypeText'];
+
+ $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
+ //$this->logger->debug(" instancia callbell creada".PHP_EOL);
+ //$clientPhoneNumber = $this->validarNumeroTelefono($this->clientPhoneNumber->getUcrmClientNumber($notificationData));
+
+ //$clientPhoneNumber = $this->clientPhoneNumber->getUcrmClientNumber($notificationData);
+ //$clientPhoneNumber = $this->validarNumeroTelefono($this->clientPhoneNumber->getUcrmClientNumber($notificationData)); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"
+
+ $clientPhoneNumber = $this->validarNumeroTelefono($phoneToNotifyAndUpdate);
+
+ if (empty($clientPhoneNumber)) {
+ $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
+ return;
+ } else {
+
+ //$this->logger->debug(sprintf('llego al llamado de sendPaymentNotificationWhatsApp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));
+
+ if ($notificationTypeText) {
+ $this->logger->debug("Activado el check de mensajes de texto: " . $notificationTypeText . PHP_EOL);
+ }
+
+ if ($notificationTypeText) {
+ try {
+
+ if ($client_callbell_api->sendTextPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData)) {
+ $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
+ $client_callbell_api->patchWhatsapp($response_getContactCallBell, $notificationData);
+ } else {
+ $this->logger->warning("No se pudo enviar el comprobante para este cliente" . PHP_EOL);
+ }
+ } catch (\Exception $Exception) {
+ $this->logger->error($Exception->getCode() . ' ' . $Exception->getMessage());
+ }
+
+ } else {
+
+ try {
+ if ($client_callbell_api->sendPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData)) {
+ $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
+ $client_callbell_api->patchWhatsapp($response_getContactCallBell, $notificationData);
+ } else {
+ $this->logger->warning("No se pudo enviar el comprobante para este cliente" . PHP_EOL);
+ }
+
+ } catch (\Exception $Exception) {
+ $this->logger->error($Exception->getCode() . ' ' . $Exception->getMessage());
+ }
+ }
+
+ }
+
+ // $messageBody = $this->messageTextFactory->createBody($notificationData);
+ // if (! $messageBody) {
+ // $this->logger->info('No text configured for event: ' . $notificationData->eventName);
+ // return;
+ // }
+
+ }
+
+ /*
+ * Notify to client about Invoice Overdue
+ */
+ public function notifyOverDue(NotificationData $notificationData): void
+ {
+ $this->logger->debug("***Se notifica al cliente que la factura de su servicio está vencida***" . PHP_EOL);
+
+ // $notification_client_data = $notificationData->clientData; //array con los datos del cliente
+
+ // $notification_client_data_export = json_encode($notification_client_data);
+ // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);
+ //$this->logger->debug("Creando instancia callbell ".PHP_EOL);
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ // the "exportFormat" key must be defined in plugin's manifest file, see the link above
+ $IPServer = $config['ipserver'];
+ $UCRMAPIToken = $config['apitoken'];
+ $CallBellAPIToken = $config['tokencallbell'];
+
+ $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
+ //$this->logger->debug(" instancia callbell creada".PHP_EOL);
+ //$clientPhoneNumber = $this->validarNumeroTelefono($this->clientPhoneNumber->getUcrmClientNumber($notificationData));
+ $clientPhoneNumber = $this->clientPhoneNumber->getUcrmClientNumber($notificationData);
+ $this->logger->debug("Numero de cel obtenido " . $clientPhoneNumber . PHP_EOL);
+
+ if (empty($clientPhoneNumber)) {
+ $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
+ return;
+ } else {
+
+ try {
+ //$this->logger->debug(sprintf('llego al llamado de sendPaymentNotificationWhatsApp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));
+ //$this->sendMessage($notificationData, $clientSmsNumber, $messageBody);
+ //$this->sendWhatsApp($notificationData, $clientSmsNumber);
+
+ $client_callbell_api->sendOverdueNotificationWhatsApp($clientPhoneNumber, $notificationData);
+
+ } catch (HttpException $httpException) {
+ //$this->logger->debug('Ocurrio un error en el try catch');
+ $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
+ }
+ }
+
+ // $messageBody = $this->messageTextFactory->createBody($notificationData);
+ // if (! $messageBody) {
+ // $this->logger->info('No text configured for event: ' . $notificationData->eventName);
+ // return;
+ // }
+
+ }
+
+ /*
+ * Update the client's data at CallBell
+ */
+ public function onlyUpdate(NotificationData $notificationData, $phoneToUpdate = null, $updateEmail = false): void
+ {
+ //$this->logger->info("Se enviará una actualización a Callbell " . PHP_EOL);
+
+ $notification_client_data = $notificationData->clientData; //array con los datos del cliente
+
+ // $notification_client_data_export = json_encode($notification_client_data);
+ // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);
+
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ // the "exportFormat" key must be defined in plugin's manifest file, see the link above
+ $IPServer = $config['ipserver'];
+ $UCRMAPIToken = $config['apitoken'];
+ $CallBellAPIToken = $config['tokencallbell'];
+ $StripeToken = $config['tokenstripe'];
+
+ $attributes = $notificationData->clientData['attributes']; //Obtener los atributos del cliente
+ // Variable para almacenar los valores de los atributos que comienzan con "clabe"
+
+ // Iterar sobre los atributoss
+ foreach ($attributes as $attribute) {
+ // Verificar si la "key" comienza con "stripe"
+ if (strpos($attribute['key'], 'stripe') === 0) {
+ // Agregar el valor al array $clabeValues
+ $customerStripeID = $attribute['value'];
+ } else if (strpos($attribute['key'], 'clabe') === 0) { // Verificar si la "key" comienza con "clabe"
+ // Agregar el valor al array $clabeValues
+ $clabeInterbancaria = $attribute['value'];
+ }
+
+ }
+
+ if ($updateEmail) {
+ $contacts = $notificationData->clientData['contacts'] ?? []; //Obtener los contactos que tiene el cliente para buscar el email
+
+ foreach ($contacts as $contact) {
+
+ $types = $contact['types'] ?? []; //Obtener los tipos de contactos del cliente
+ foreach ($types as $type) {
+
+ if ($type['name'] == 'WhatsApp') { //Si el tipo de contacto es Whatsapp
+
+ $client_email = $contact['email']; //Asignar el correo del cliente a la variable
+ break;
+ }
+ }
+
+ }
+ $this->logger->info("Se procesaron los contactos para revisar el o los email" . PHP_EOL);
+
+ $stripe = new \Stripe\StripeClient($StripeToken); //Instancia de la clase manejadora de clientes para la API de Stripe
+
+ if ($client_email !== null && $customerStripeID !== null) {
+ $this->logger->info("Se actualizara el correo del cliente en Stripe: " . $client_email . PHP_EOL);
+ $stripe->customers->update($customerStripeID, ['email' => $client_email]); //Actualiza el correo electrónico del cliente en la plataforma de Stripe en su correspondiente "customer Stripe ID"
+ }
+ }
+
+ $clientPhoneNumber = $this->validarNumeroTelefono($phoneToUpdate); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"
+
+ if (empty($clientPhoneNumber)) {
+ $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
+ return;
+ } else {
+
+ try {
+ //$this->logger->debug(sprintf('llego al llamado de sendwhatsapp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));
+ //$this->sendMessage($notificationData, $clientSmsNumber, $messageBody);
+ //$this->sendWhatsApp($notificationData, $clientSmsNumber);
+
+ //$client_callbell_api->sendMessageWhatsApp($clientPhoneNumber, $notificationData);
+ $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
+ $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
+ //$this->logger->debug('Se hizo la petición al callbell para obtener el uuid' . PHP_EOL);
+ $client_callbell_api->patchWhatsapp($response_getContactCallBell, $notificationData, $clabeInterbancaria);
+
+ } catch (HttpException $httpException) {
+ //$this->logger->debug('Ocurrio un error en el try catch');
+ $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
+ }
+ }
+
+ // $notificationData_export = var_export($notificationData, true);
+ // $this->logger->debug('valor de notificationdata: ' . $notificationData_export);
+
+ // $messageBody = $this->messageTextFactory->createBody($notificationData);
+ // if (! $messageBody) {
+ // $this->logger->info('No text configured for event: ' . $notificationData->eventName);
+ // return;
+ // }
+
+ }
+
+ /*
+ * Update de status of service at CallBell
+ */
+ public function onlyUpdateService(NotificationData $notificationData, $phoneToUpdate): void
+ {
+ //$this->logger->info("Se enviará una actualización del estado del servicio a Callbell, estado del servicio: ".$notificationData->serviceData['status'] . PHP_EOL);
+ $this->logger->info(json_encode($notificationData) . PHP_EOL);
+
+ //$clientID = $notificationData->extraData['entity']['clientId'];
+
+ //$this->logger->info("client id " .$clientID. PHP_EOL);
+
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ // the "exportFormat" key must be defined in plugin's manifest file, see the link above
+ $IPServer = $config['ipserver'];
+ $UCRMAPIToken = $config['apitoken'];
+ $CallBellAPIToken = $config['tokencallbell'];
+
+ $clientPhoneNumber = $this->validarNumeroTelefono($phoneToUpdate); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"
+ //$this->logger->info("Número de telefono obtenido para actualizar:" .$clientPhoneNumber. PHP_EOL);
+
+ if (empty($clientPhoneNumber)) {
+ $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
+ return;
+ } else {
+
+ try {
+ //$this->logger->debug(sprintf('llego al llamado de sendwhatsapp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));
+ //$this->sendMessage($notificationData, $clientSmsNumber, $messageBody);
+ //$this->sendWhatsApp($notificationData, $clientSmsNumber);
+
+ $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
+ $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
+ $client_callbell_api->patchServiceStatusWhatsApp($response_getContactCallBell, $notificationData);
+
+ } catch (HttpException $httpException) {
+ //$this->logger->debug('Ocurrio un error en el try catch');
+ $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
+ }
+ }
+
+ }
+
+ /**
+ * implement in subclass with the specific messaging provider
+ * @see TwilioNotifierFacade::sendMessage()
+ */
+ abstract protected function sendMessage(
+ NotificationData $notificationData,
+ string $clientSmsNumber,
+ string $messageBody
+ ): void;
+
+ // /**
+ // * implement in subclass with the specific messaging provider
+ // * @see TwilioNotifierFacade::sendWhatsApp()
+ // */
+ // abstract protected function sendWhatsApp(
+ // NotificationData $notificationData,
+ // string $clientSmsNumber
+ // ): void;
+
+ function validarNumeroTelefono($telefono)
+ {
+ // Eliminar espacios y guiones
+ $telefono = preg_replace('/\s+|-/', '', $telefono);
+
+ // Eliminar caracteres no numéricos, excepto el '+' si está al principio
+ $telefono = preg_replace('/(?!^\+)[^0-9]/', '', $telefono);
+
+ // Verificar si el número comienza con "+1" o "1" y tiene 11 dígitos en total
+ if (
+ (substr($telefono, 0, 2) === "+1" && strlen($telefono) === 12) ||
+ (substr($telefono, 0, 1) === "1" && strlen($telefono) === 11)
+ ) {
+ return $telefono;
+ }
+
+ // Si el número tiene exactamente 10 dígitos, agregar el prefijo "521"
+ if (strlen($telefono) === 10) {
+ return "521" . $telefono;
+ }
+
+ // Si el número tiene más de 10 dígitos, verificar que comience con "521"
+ if (strlen($telefono) > 10) {
+ if (substr($telefono, 0, 2) === "521" && strlen($telefono) === 12) {
+ return $telefono;
+ } else {
+ // Si no comienza con "52", tomar los últimos 10 dígitos y agregar el prefijo "52"
+ return "521" . substr($telefono, -10);
+ }
+ }
+
+ // Si no cumple con ninguna de las condiciones anteriores, retornar cadena vacía
+ return '';
+ }
+
+ function patchClientCustomAttribute($clientId, $attributeId, $value): bool
+ {
+ $logger = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ $ucrmBaseUri = $config['ipserver'];
+ $authToken = $config['apitoken'];
+
+ $ucrmBaseUri = 'https://' . $ucrmBaseUri . '/crm/api/v1.0/';
+ $clientguzz = new Client(); //instancia de cliente GuzzleHttp para consumir API UISP CRM
+
+ $json_data_patch = '{
+ "attributes": [
+ {
+ "value": "' . $value . '",
+ "customAttributeId":' . $attributeId . '
+ }
+ ]
+
+ }'; //JSON para hacer patch de los custom fields del cliente en el UISCP CRM
+
+ try {
+ //aquí se contruye la petición para hacer patch hacia el cliente en sus custom fields con la API del UISP UCRM
+ $responseCRM = $clientguzz->patch(
+ $ucrmBaseUri . 'clients/' . $clientId,
+ [
+ 'headers' => [
+ 'X-Auth-Token' => $authToken,
+ 'Content-Type' => 'application/json',
+ ],
+ 'body' => $json_data_patch,
+ 'verify' => false, // Deshabilitar la verificación del certificado SSL
+ ],
+
+ );
+ //evaluar el código de respuesta HTTP y si es 200 se retorna true
+ if ($responseCRM->getStatusCode() === 200) {
+ $this->logger->info("Se actualizó el custom attribute del cliente " . $clientId . PHP_EOL);
+ return true; // Return true if patch is successful
+ } else {
+ $this->logger->info("Error al hacer el patch al CRM: " . $responseCRM->getStatusCode() . PHP_EOL);
+ return false; // Return false if patch fails
+ }
+
+
+ } catch (\GuzzleHttp\Exception\GuzzleException $error) {
+ $this->logger->info("Error al hacer el patch al CRM: " . $error->getMessage() . PHP_EOL);
+ return false; // Return false if patch fails
+ }
+
+ }
+ function getVaultCredentials($dataToSearch): string
+ {
+
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ $ucrmBaseUri = $config['ipserver'];
+ $crmAuthToken = $config['apitoken'];
+ $unmsAuthToken = $config['unmsApiToken'];
+
+ if ($ucrmBaseUri === '172.16.5.134') { //opción solo para el servidor de pruebas
+ return 'gYAIEK:Be}SK*01z5+/V';
+ }
+
+ $unmsBaseUri = 'https://' . $ucrmBaseUri . '/nms/api/v2.1/';
+ $ucrmBaseUri = 'https://' . $ucrmBaseUri . '/crm/api/v1.0/';
+ //$authToken = '7adc9198-50b1-41d0-9bfa-d4946902ed89';
+
+ // Crear una instancia del cliente Guzzle
+ $clientUnms = new Client([
+ 'base_uri' => $unmsBaseUri,
+ 'verify' => false, // Deshabilitar la verificación del certificado SSL
+ ]);
+
+ $clientUcrm = new Client([
+ 'base_uri' => $ucrmBaseUri,
+ 'verify' => false, // Deshabilitar la verificación del certificado SSL
+ ]);
+
+ //validar si dataToSearch es una dirección IP o una dirección MAC
+ if (filter_var($dataToSearch, FILTER_VALIDATE_IP)) {
+
+ // La variable es una dirección IP válida
+ //$logger->appendLog('Consulta por dirección IP: ' . $dataToSearch);
+ $this->logger->info('Consulta por dirección IP: ' . $dataToSearch . PHP_EOL);
+
+
+ if ($ucrmBaseUri === '172.16.5.134') { //opción solo para el servidor de pruebas
+ return 'gYAIEK:Be}SK*01z5+/V';
+ }
+
+ $IpAddressClientId = filter_var($dataToSearch, FILTER_VALIDATE_IP);
+
+ try {
+ $responseSitesByIP = $clientUnms->request('GET', 'sites/search?query=' . $dataToSearch . '&count=1&page=1', [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+
+ if ($responseSitesByIP->getStatusCode() === 200) {
+
+ $datasSitesByIP = json_decode((string) $responseSitesByIP->getBody(), true);
+ $jsonDevicesBySite = json_encode($datasSitesByIP, JSON_PRETTY_PRINT);
+ //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
+
+ if (isset($datasSitesByIP[0])) {
+ $siteId = $datasSitesByIP[0]['id'];
+ // print_r('ID DEL SITIO: ' . $siteId . PHP_EOL); // ID del sitio
+ } else {
+
+ $this->logger->error('No se encontró ningún sitio para la IP proporcionada: ' . $dataToSearch . PHP_EOL);
+ return 'Error: No se encontró ningún sitio para la IP proporcionada: ' . $dataToSearch; // Return early if no site is found
+ }
+
+ } else {
+
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseSitesByIP->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responseSitesByIP->getStatusCode(); // Return early if the request fails
+ }
+
+ $devicesBySiteId = $clientUnms->request('GET', 'devices?siteId=' . $siteId, [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+
+ if ($devicesBySiteId->getStatusCode() === 200) {
+ $dataDevicesBySite = json_decode((string) $devicesBySiteId->getBody(), true);
+ $jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
+ //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
+ $deviceID = null;
+
+ foreach ($dataDevicesBySite as $device) {
+ if (isset($device['ipAddress'])) {
+ $ipAddress = explode('/', $device['ipAddress'])[0]; // Obtener solo la IP sin la máscara
+ if ($ipAddress === $IpAddressClientId) {
+ $deviceID = $device['identification']['id'];
+ break; // Salir del ciclo si se encuentra la IP
+ }
+ } else {
+ $this->logger->error('No se encontró la IP del dispositivo en la respuesta de la API.' . PHP_EOL);
+ return 'Error: No se encontró la IP del dispositivo en la respuesta de la API.'; // Return early if the IP is not found
+ }
+ }
+
+ if ($deviceID == null) {
+ $this->logger->error('No se encontró el dispositivo con la IP proporcionada: ' . $IpAddressClientId . PHP_EOL);
+ return 'Error: No se encontró el dispositivo con la IP proporcionada: ' . $IpAddressClientId; // Return early if no device is found
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $devicesBySiteId->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $devicesBySiteId->getStatusCode(); // Return early if the request fails
+ }
+
+ $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $deviceID . '/credentials', [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+
+ if ($responsePasswordVault->getStatusCode() === 200) {
+ $dataPasswordVault = json_decode((string) $responsePasswordVault->getBody(), true);
+ // $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
+ //print_r($jsonPasswordVault . PHP_EOL); //Credenciales del dispositivo
+
+ if (isset($dataPasswordVault['credentials'][0]['password'])) {
+ $dataPasswordVault = $dataPasswordVault['credentials'][0]['password'];
+ } else {
+ $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
+ return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
+ }
+ return $dataPasswordVault;
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
+ }
+
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud, si hay error 404 entonces responder que no se encontró niguna IP asociada a alguna antena o dispositivo de red
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el cliente con la dirección IP proporcionada: ' . $IpAddressClientId . PHP_EOL);
+ return 'Error: No se encontró el cliente con la dirección IP proporcionada: ' . $IpAddressClientId; // Return early if the client is not found
+ }
+ return 'Error: ' . $reason; // Return early if the request fails
+ } else {
+ $this->logger->error('Error al realizar la solicitud: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ } else if (preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $dataToSearch)) {
+ // La variable es una dirección MAC válida
+
+ $this->logger->info('Consulta por dirección MAC: ' . $dataToSearch . PHP_EOL);
+
+ if ($ucrmBaseUri === '172.16.5.134') { //opción solo para el servidor de pruebas
+ return 'gYAIEK:Be}SK*01z5+/V';
+ }
+
+ try {
+ // //para mandarla al endpoint de dispositivos por MAC se necesita convertir la cadena de la direccion mac en un formato como el siguiente ejemplo: para la dirección mac 60:22:32:c8:b2:c3 quedaría como 60%3A22%3A32%3Ac8%3Ab2%3Ac3
+ // $dataToSearch = str_replace(':', '%3A', $dataToSearch);
+ // $logger->appendLog('Consulta por dirección MAC: ' . $dataToSearch );
+ $responseDeviceByMAC = $clientUnms->request('GET', 'devices/mac/' . $dataToSearch, [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+
+ if ($responseDeviceByMAC->getStatusCode() === 200) {
+
+ $dataDeviceByMAC = json_decode((string) $responseDeviceByMAC->getBody(), true);
+ $jsonDeviceByMac = json_encode($dataDeviceByMAC, JSON_PRETTY_PRINT);
+ // print_r($jsonDeviceByMac . PHP_EOL); //Devices por ID del sitio
+ //$logger->appendLog($jsonDeviceByMac.PHP_EOL);
+
+ //Ejemplo de $responseDeviceByMac en json: {"id":"84c8a581-154c-41db-81d5-a1b1c9ede411","type":"airMax","series":"AC"}
+ //obtener el id del dispositivo y si no existe el id del dispositivo entonces devolver un mensaje de error
+ if (isset($dataDeviceByMAC['id'])) {
+ $deviceId = $dataDeviceByMAC['id'];
+ // print_r('ID DEL DISPOSITIVO: ' . $deviceId . PHP_EOL); // ID del dispositivo
+ } else {
+ $this->logger->error('No se encontró el dispositivo con la dirección MAC proporcionada: ' . $dataToSearch . PHP_EOL);
+ return 'Error: No se encontró el dispositivo con la dirección MAC proporcionada: ' . $dataToSearch; // Return early if no device is found
+ }
+
+ }
+
+ $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $deviceId . '/credentials', [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+
+ if ($responsePasswordVault->getStatusCode() === 200) {
+ $dataPasswordVault = json_decode((string) $responsePasswordVault->getBody(), true);
+
+ if (isset($dataPasswordVault['credentials'][0]['password'])) {
+ $dataPasswordVault = $dataPasswordVault['credentials'][0]['password'];
+ } else {
+ $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
+ return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
+ }
+ return $dataPasswordVault;
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
+ }
+
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud, si hay error 404 entonces responder que no se encontró niguna MAC asociada a alguna antena o dispositivo de red
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró ninguna antena de cliente o dispositivo en la red con la dirección MAC proporcionada: ' . $dataToSearch . PHP_EOL);
+ return 'Error: No se encontró ninguna antena de cliente o dispositivo en la red con la dirección MAC proporcionada: ' . $dataToSearch; // Return early if the client is not found
+ }
+ $this->logger->error('Error: ' . $reason . PHP_EOL);
+ return 'Error: ' . $reason; // Return early if the request fails
+ } else {
+ $this->logger->error('Error al realizar la solicitud: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ } else {
+ // La variable no es una dirección IP válida, se asume que es un ID
+ $IpAddressClientId = filter_var($dataToSearch, FILTER_SANITIZE_NUMBER_INT);
+ //print ('Consulta por ID: ' . $dataToSearch . PHP_EOL);
+ $this->logger->info('Consulta por ID: ' . $dataToSearch . PHP_EOL);
+
+
+ try {
+ //Obtener id del sitio por medio del servicio
+ $responseServices = $clientUcrm->get('clients/services?clientId=' . $IpAddressClientId, [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ 'Content-Type: application/json',
+ ],
+ ]);
+
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el cliente con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
+ return 'Error: No se encontró el cliente con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
+ }
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ if ($responseServices->getStatusCode() === 200) {
+
+ $dataServices = json_decode($responseServices->getBody()->getContents(), true);
+
+ if (isset($dataServices[0])) {
+ $unmsSiteID = $dataServices[0]['unmsClientSiteId']; // Example: 9c6798f3-0254-4e5b-bc3b-9da82fe16e46
+ } else {
+ $this->logger->error('No se encontraron servicios para el cliente proporcionado: ' . $IpAddressClientId . PHP_EOL);
+ return "Error: No se encontraron servicios para el cliente proporcionado: " . $IpAddressClientId; // Return early if no services are found
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseServices->getStatusCode() . PHP_EOL);
+ return "Error: En la solicitud. Código de estado HTTP: " . $responseServices->getStatusCode();
+ }
+
+ try {
+ $responseDevicesBySite = $clientUnms->request('GET', 'devices?siteId=' . $unmsSiteID, [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el devicie con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
+ return 'Error: No se encontró el devicie con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
+ }
+ $this->logger->error('Error: ' . $reason . PHP_EOL);
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ if ($responseDevicesBySite->getStatusCode() === 200) {
+
+ $dataDevicesBySite = json_decode($responseDevicesBySite->getBody()->getContents(), true);
+ $jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
+ //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
+
+ //id del device al que está conectado el cliente
+ if (isset($dataDevicesBySite[0])) {
+ //verificar con iiset si existe la clave 'identification' y 'apDevice' en el primer elemento del array
+ if (isset($dataDevicesBySite[0]['identification']) && isset($dataDevicesBySite[0]['attributes']['apDevice'])) {
+ $idClientDevice = $dataDevicesBySite[0]['identification']['id'];
+ $deviceID = $dataDevicesBySite[0]['attributes']['apDevice']['id'];
+ } else {
+ $this->logger->error('No se encontró el dispositivo con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
+ return "Este cliente es un repetidor."; // Return early if the key is not found
+ }
+
+ } else {
+ $this->logger->error('No se encontraron dispositivos para el sitio proporcionado: ' . $unmsSiteID . PHP_EOL);
+ return "Error: No se encontraron dispositivos para el sitio proporcionado."; // Return early if no devices are found
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
+ return "Error: Falla en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode();
+ }
+
+ try {
+ $responseDevicesBySite = $clientUnms->request('GET', 'devices/' . $deviceID, [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el device con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
+ return 'Error: No se encontró el device con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
+ }
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ if ($responseDevicesBySite->getStatusCode() === 200) {
+
+ $dataDevices = json_decode($responseDevicesBySite->getBody()->getContents(), true);
+ $jsonDevices = json_encode($dataDevices, JSON_PRETTY_PRINT);
+ //print_r($jsonDevices . PHP_EOL);
+
+ try {
+ //print_r('ID del device al que está conectado el cliente: ' . $idDevice . PHP_EOL);
+ $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $idClientDevice . '/credentials', [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el device con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
+ return 'Error: No se encontró el device con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
+ }
+ $this->logger->error('Error: ' . $reason . PHP_EOL);
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+ }
+
+ if ($responsePasswordVault->getStatusCode() === 200) {
+ $dataPasswordVault = json_decode($responsePasswordVault->getBody()->getContents(), true);
+ $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
+ if (isset($dataPasswordVault['credentials'][0]['password'])) {
+ $passwordVault = $dataPasswordVault['credentials'][0]['password'];
+ return $passwordVault;
+ } else {
+ $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
+ return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode(); // Return early if the request fails
+
+ }
+
+ }
+
+ }
+ function getVaultCredentialsByClientId($clientId): string
+ {
+
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ $ipServer = $config['ipserver'];
+ $crmAuthToken = $config['apitoken'];
+ $unmsAuthToken = $config['unmsApiToken'];
+
+ if ($ipServer === '172.16.5.134') { //opción solo para el servidor de pruebas
+ return 'gYAIEK:Be}SK*01z5+/V';
+ }
+
+ $unmsBaseUri = 'https://' . $ipServer . '/nms/api/v2.1/';
+ $ucrmBaseUri = 'https://' . $ipServer . '/crm/api/v1.0/';
+ //$authToken = '7adc9198-50b1-41d0-9bfa-d4946902ed89';
+
+ // Crear una instancia del cliente Guzzle
+ $clientUnms = new Client([
+ 'base_uri' => $unmsBaseUri,
+ 'verify' => false, // Deshabilitar la verificación del certificado SSL
+ ]);
+
+ $clientUcrm = new Client([
+ 'base_uri' => $ucrmBaseUri,
+ 'verify' => false, // Deshabilitar la verificación del certificado SSL
+ ]);
+
+
+ $this->logger->debug('Consulta por ID: ' . $clientId . PHP_EOL);
+
+
+ try {
+ //Obtener id del sitio por medio del servicio
+ $responseServices = $clientUcrm->get('clients/services?clientId=' . $clientId, [
+ 'headers' => [
+ 'X-Auth-Token' => $crmAuthToken,
+ 'Content-Type: application/json',
+ ],
+ ]);
+
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el cliente con el ID proporcionado: ' . $clientId . PHP_EOL);
+ return 'No se encontró el cliente con el ID proporcionado: ' . $clientId; // Return early if the client is not found
+ }
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ if ($responseServices->getStatusCode() === 200) {
+
+ $dataServices = json_decode($responseServices->getBody()->getContents(), true);
+
+ if (isset($dataServices[0])) {
+ $unmsSiteID = $dataServices[0]['unmsClientSiteId']; // Example: 9c6798f3-0254-4e5b-bc3b-9da82fe16e46
+ } else {
+ $this->logger->error('No se encontraron servicios para el cliente proporcionado: ' . $clientId . PHP_EOL);
+ return "No se encontraron servicios para el cliente proporcionado: " . $clientId; // Return early if no services are found
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseServices->getStatusCode() . PHP_EOL);
+ return "Error: En la solicitud. Código de estado HTTP: " . $responseServices->getStatusCode();
+ }
+
+ try {
+ $responseDevicesBySite = $clientUnms->request('GET', 'devices?siteId=' . $unmsSiteID, [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el device con el ID proporcionado: ' . $clientId . PHP_EOL);
+ return 'No se encontró el device con el ID proporcionado: ' . $clientId; // Return early if the client is not found
+ }
+ $this->logger->error('Error: ' . $reason . PHP_EOL);
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ if ($responseDevicesBySite->getStatusCode() === 200) {
+
+ $dataDevicesBySite = json_decode($responseDevicesBySite->getBody()->getContents(), true);
+ $jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
+ //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
+
+ //id del device al que está conectado el cliente
+ if (isset($dataDevicesBySite[0])) {
+ //verificar con iiset si existe la clave 'identification' y 'apDevice' en el primer elemento del array
+ if (isset($dataDevicesBySite[0]['identification']) && isset($dataDevicesBySite[0]['attributes']['apDevice'])) {
+ $idClientDevice = $dataDevicesBySite[0]['identification']['id'];
+ $deviceID = $dataDevicesBySite[0]['attributes']['apDevice']['id'];
+ } else {
+ $this->logger->error('No se encontró el dispositivo con el ID proporcionado: ' . $clientId . PHP_EOL);
+ return "Este cliente es un repetidor."; // Return early if the key is not found
+ }
+
+ } else {
+ $this->logger->error('No se encontraron dispositivos para el sitio proporcionado: ' . $unmsSiteID . PHP_EOL);
+ return "No se encontraron dispositivos para el sitio proporcionado."; // Return early if no devices are found
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
+ return "Error: Falla en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode();
+ }
+
+ try {
+ $responseDevicesBySite = $clientUnms->request('GET', 'devices/' . $deviceID, [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el device con el ID proporcionado: ' . $clientId . PHP_EOL);
+ return 'No se encontró el dispositivo de red con el ID proporcionado: ' . $clientId; // Return early if the client is not found
+ }
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+
+ }
+
+ if ($responseDevicesBySite->getStatusCode() === 200) {
+
+ $dataDevices = json_decode($responseDevicesBySite->getBody()->getContents(), true);
+ $jsonDevices = json_encode($dataDevices, JSON_PRETTY_PRINT);
+ //print_r($jsonDevices . PHP_EOL);
+
+ try {
+ //print_r('ID del device al que está conectado el cliente: ' . $idDevice . PHP_EOL);
+ $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $idClientDevice . '/credentials', [
+ 'headers' => [
+ 'X-Auth-Token' => $unmsAuthToken,
+ ],
+ ]);
+ } catch (RequestException $requestException) {
+ // Manejar errores de la solicitud
+ if ($requestException->hasResponse()) {
+ $response = $requestException->getResponse();
+ $statusCode = $response->getStatusCode();
+ $reason = $response->getReasonPhrase();
+ //si el statusCode es 404 significa que no se encontró el cliente
+ if ($statusCode == 404) {
+ $this->logger->error('No se encontró el device con el ID proporcionado: ' . $clientId . PHP_EOL);
+ return 'No se encontró el dispositivo de red con el ID proporcionado: ' . $clientId; // Return early if the client is not found
+ }
+ $this->logger->error('Error: ' . $reason . PHP_EOL);
+ return 'Error: ' . $reason; // Return early if the request fails
+
+ } else {
+ $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
+ return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
+ }
+ }
+
+ if ($responsePasswordVault->getStatusCode() === 200) {
+ $dataPasswordVault = json_decode($responsePasswordVault->getBody()->getContents(), true);
+ $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
+ if (isset($dataPasswordVault['credentials'][0]['password'])) {
+ $passwordVault = $dataPasswordVault['credentials'][0]['password'];
+ return $passwordVault;
+ } else {
+ $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
+ return "No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
+ }
+
+ } else {
+ $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
+ return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode(); // Return early if the request fails
+
+ }
+
+
+
+ }
+
+ function comparePasswords($passwordVault, $passwordAntenaClienteCRM): string
+ {
+ $erroresVaultPrefix = [
+ 'Error:',
+ 'No se encon',
+ 'Falla en',
+ ];
+
+ // Validar si la contraseña de la antena del cliente en el CRM es igual a la contraseña de la antena del cliente en el Vault y de ser iguales devolver la contraseña del vault
+ if ($passwordAntenaClienteCRM === $passwordVault) {
+ $this->logger->debug('La contraseña de la antena del cliente en el CRM
+ es igual a la contraseña de la antena del cliente en el Vault.' . PHP_EOL);
+ return $passwordVault;
+ } else {
+ //si no son iguales entonces validar si alguna de las contraseñas no contiene un prefijo de error para decidir cuál devolver; si
+
+
+ if (!empty($passwordAntenaClienteCRM) && !array_filter($erroresVaultPrefix, fn($prefix) => str_starts_with($passwordAntenaClienteCRM, $prefix))) { //verificar que la contraseña del CRM no comience con ninguno de los prefijos de error o esté vacía
+ $this->logger->debug('La contraseña de la antena del cliente en el CRM será la que se envíe al instalador.' . PHP_EOL);
+ return $passwordAntenaClienteCRM;
+ } elseif (!empty($passwordVault) && !array_filter($erroresVaultPrefix, fn($prefix) => str_starts_with($passwordVault, $prefix))) { //verificar que la contraseña del vault no comience con ninguno de los prefijos de error o esté vacía
+ $this->logger->debug('La contraseña de la antena del cliente en el Vault será la que se envíe al instalador.' . PHP_EOL);
+ return $passwordVault;
+ } else {
+ //asignar la variable con un texto de advertencia sobre que ninguna de las contraseñas es válida para ser enviada al instalador
+ $this->logger->debug('Ninguna de las contraseñas de la antena es válida para ser enviada al instalador.' . PHP_EOL);
+ return '⚠️ Probar una contraseña conocida como Siip.567 etc. ya que no se encontró una contraseña en el UISP Vault ni en el CRM.';
+ }
+ }
+ }
+
+}
diff --git a/archivos_webhook_destino/src/Facade/AbstractOxxoOperationsFacade.php b/archivos_webhook_destino/src/Facade/AbstractOxxoOperationsFacade.php
new file mode 100755
index 0000000..0e237e2
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/AbstractOxxoOperationsFacade.php
@@ -0,0 +1,738 @@
+logger = $logger;
+ $this->messageTextFactory = $messageTextFactory;
+ $this->clientPhoneNumber = $clientPhoneNumber;
+ }
+
+ /*
+ * Creates a PaymentIntent for OXXO in Stripe for a Customer
+ * @param array $event_json
+ * @param int|null $amount
+ * @return array
+ * @throws \GuzzleHttp\Exception\GuzzleException
+ * @throws \Stripe\Exception\ApiErrorException
+ * @throws Exception
+ */
+ public function createOxxoPaymentIntent($event_json, $amount = null): array
+ {
+ //declarar un array asociativo de strings pero no asignarle nada aun
+ $arrayOxxoPayment = array();
+ $integerAmount = $amount;
+
+ $this->logger->info("Creando referencia del cliente para OXXO: " . PHP_EOL);
+ $configManager = PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ $StripeToken = $config['tokenstripe'];
+ $IPServer = $config['ipserver'];
+ $tokenCRM = $config['apitoken'];
+ $ipPuppeteer = $config['ipPuppeteer'];
+ $portPuppeteer = $config['portPuppeteer'];
+
+ $baseUri = 'https://' . $IPServer . '/crm/api/v1.0/';
+ $this->ucrmApi = UcrmApi::create();
+ $currentUserAdmin = $this->ucrmApi->get('users/admins', []);
+ $clientID = $event_json['client_id'];
+
+ $stripeCustomerId = null;
+ $clientEmail = '';
+ $clientFullName = '';
+
+ $clientGuzzleHttp = new Client([
+ 'base_uri' => $baseUri,
+ 'headers' => [
+ 'X-Auth-App-Key' => $tokenCRM,
+ 'Accept' => 'application/json',
+ ],
+ 'verify' => false,
+ 'timeout' => 5, // Timeout de 5 segundos
+ ]);
+
+ try {
+ $response = $clientGuzzleHttp->request('GET', "clients/" . $clientID);
+ $arrayClientCRM = json_decode($response->getBody()->getContents(), true);
+ //$this->logger->info("Valor de arrayClientCRM: " . print_r($arrayClientCRM, true) . PHP_EOL);
+ $clientFullName = $arrayClientCRM['firstName'] . ' ' . $arrayClientCRM['lastName'];
+ } catch (RequestException $e) {
+ if ($e->getCode() === 404) {
+ $this->logger->error("Cliente no encontrado en CRM: " . $clientID . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID, clientFullName y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorGetClientNotFound';
+ $arrayOxxoPayment['failDescription'] = 'Cliente no encontrado en CRM: ' . $clientID;
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $integerAmount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+
+
+ }
+ //timeout
+ if ($e->getCode() === 408) {
+ $this->logger->error("Timeout al obtener el cliente en CRM: " . $clientID . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorTimeoutGetClient';
+ $arrayOxxoPayment['failDescription'] = 'Timeout al obtener el cliente en CRM: ' . $clientID;
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $integerAmount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+ }
+ $this->logger->error("Error al obtener el cliente en CRM (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorGetClient';
+ $arrayOxxoPayment['failDescription'] = 'Error al obtener el cliente en CRM: ' . $clientID;
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $integerAmount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+
+ }
+
+ // Obtener email del cliente
+ foreach ($arrayClientCRM['contacts'] as $contact) {
+ if (!empty($contact['email'])) {
+ $clientEmail = $contact['email'];
+ break;
+ } else {
+ $clientEmail = 'siip8873@gmail.com'; // Default
+ }
+ }
+
+ try {
+ // Obtener stripeCustomerId
+ foreach ($arrayClientCRM['attributes'] as $attribute) {
+ if ($attribute['key'] === 'stripeCustomerId') {
+ $stripeCustomerId = $attribute['value'];
+ break;
+ }
+ }
+
+ $this->logger->info("Stripe Customer ID obtenido: " . $stripeCustomerId . PHP_EOL);
+ } catch (Exception $e) {
+ $this->logger->error("Error al obtener el Customer ID de Stripe (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['error'] = 'errorGetCustomerStripe';
+ $arrayOxxoPayment['failDescription'] = 'Error al obtener el Customer ID de Stripe: ' . $clientID;
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $integerAmount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+ }
+
+ if ($amount === null) {
+ $amount = abs($arrayClientCRM['accountOutstanding']); //Monto adeudado del cliente
+ } else {
+ //la variable $amount debe ser numérica pero en ocasiones la solicitud puede traer signos o alguna letra ingresada mal por el cliente, se debe analizar para limpiar cualquier caracter que no sea numérico
+ if(!is_numeric($amount)) {
+ $amount = preg_replace('/[^\d.]/', '', $amount); // Eliminar todo lo que no sea dígito o punto decimal
+ }
+ $this->logger->debug("Monto proporcionado directamente: $amount " . PHP_EOL);
+ }
+
+ if ($amount > 10) {
+ $amountInCents = intval($amount * 100); // Convertir a centavos
+
+ try {
+ $this->logger->debug("Creando referencia en Stripe por $amount para el cliente $stripeCustomerId" . PHP_EOL);
+ $guzzleClient = new Client([
+ 'timeout' => 5, // Timeout de 5 segundos
+ ]);
+
+ $response = $guzzleClient->post('https://api.stripe.com/v1/payment_intents', [
+ 'auth' => [$StripeToken, ''],
+ 'form_params' => [
+ 'amount' => $amountInCents,
+ 'currency' => 'mxn',
+ 'payment_method_types' => ['customer_balance', 'card', 'oxxo'],
+ 'description' => 'Pago de servicio de SIIP Internet',
+ 'customer' => $stripeCustomerId,
+ 'metadata' => [
+ 'clientId' => $clientID,
+ 'createdBy' => 'UCRM',
+ 'paymentType' => 'card.one_time',
+ 'signedInAdminId' => $currentUserAdmin[1]['id'],
+ 'tipoPago' => 'OXXO',
+ ],
+ 'payment_method_options' => [
+ 'oxxo' => [
+ 'expires_after_days' => 3,
+ ],
+ ],
+ ]
+ ]);
+
+ $paymentIntent = json_decode($response->getBody()->getContents(), true);
+
+ } catch (\Stripe\Exception\ApiConnectionException $e) {
+ $this->logger->error("Error de conexión con Stripe (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorConnectionStripe';
+ $arrayOxxoPayment['failDescription'] = 'Error de conexión con Stripe: ' . $clientID;
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+
+ } catch (\Stripe\Exception\ApiErrorException $e) {
+ $this->logger->error("Error de la API de Stripe: " . $e->getMessage() . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorApiStripe';
+ $arrayOxxoPayment['failDescription'] = 'Error de la API de Stripe: ' . $clientID;
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+
+ } catch (Exception $e) {
+ $this->logger->error("Error inesperado al crear PaymentIntent (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
+ //si e->getMessage incluye el mensaje: You must provide a customer when creating or updating a PaymentIntent with a `customer_ba (truncated...) declarar una variable y ahi poner "Este cliente no tiene cuenta de Stripe"
+ if ($e->getMessage() == 'You must provide a customer when creating or updating a PaymentIntent with a `customer_ba (truncated...)') {
+ $this->logger->error("Este cliente no tiene cuenta de Stripe" . PHP_EOL);
+ $arrayOxxoPayment['failDescription'] = 'Este cliente no tiene cuenta de Stripe: ' . $clientID;
+ } else {
+ $this->logger->error("Error inesperado al crear PaymentIntent: " . $e->getMessage() . PHP_EOL);
+ $arrayOxxoPayment['failDescription'] = 'Error inesperado al crear PaymentIntent: ' . $clientID;
+ }
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorCreatePaymentIntent';
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+
+ }
+
+ try {
+ $firstName = isset($arrayClientCRM['firstName']) ? trim($arrayClientCRM['firstName']) : '';
+ $lastName = isset($arrayClientCRM['lastName']) ? trim($arrayClientCRM['lastName']) : '';
+
+ if (strlen($firstName) < 2 || strlen($lastName) < 2) {
+ $this->logger->error("Nombre/apellido inválido: ' . $firstName . ' ' . $lastName" . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorNombreApellidoInvalido';
+ $arrayOxxoPayment['failDescription'] = "Nombre/apellido inválido: ' . $firstName . ' ' . $lastName";
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+
+ }
+
+ $responsePaymentMethod = $guzzleClient->post('https://api.stripe.com/v1/payment_methods', [
+ 'auth' => [$StripeToken, ''],
+ 'form_params' => [
+ 'type' => 'oxxo',
+ 'billing_details' => [
+ 'name' => "$firstName $lastName",
+ 'email' => $clientEmail,
+ ],
+ ]
+ ]);
+
+ $paymentMethod = json_decode($responsePaymentMethod->getBody()->getContents(), true);
+
+ $responseConfirmPaymentIntent = $guzzleClient->post('https://api.stripe.com/v1/payment_intents/' . $paymentIntent['id'] . '/confirm', [
+ 'auth' => [$StripeToken, ''],
+ 'form_params' => [
+ 'payment_method' => $paymentMethod['id'],
+ ]
+ ]);
+
+ $paymentIntentConfirm = json_decode($responseConfirmPaymentIntent->getBody()->getContents(), true);
+
+ } catch (Exception $e) {
+ $this->logger->error("Error al confirmar PaymentIntent: " . $e->getMessage() . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorConfirmPaymentIntent';
+ $arrayOxxoPayment['failDescription'] = 'Error al confirmar PaymentIntent: ' . $e->getMessage();
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+ }
+
+ if (!empty($paymentIntentConfirm['next_action']) && isset($paymentIntentConfirm['next_action']['oxxo_display_details'])) {
+ $oxxoPayment = $paymentIntentConfirm['next_action']['oxxo_display_details'];
+ $oxxo_reference = $oxxoPayment['number'];
+ $oxxo_receipt_url = $oxxoPayment['hosted_voucher_url'];
+
+ $this->logger->info("Referencia OXXO: " . $oxxo_reference . PHP_EOL);
+ $this->logger->info("URL del recibo: " . $oxxo_receipt_url . PHP_EOL);
+ //$this->captureScreenshot($oxxo_receipt_url);
+ //devolver un array con los campos de url de oxxo, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = $oxxo_reference;
+ $arrayOxxoPayment['url'] = $oxxo_receipt_url;
+ $arrayOxxoPayment['error'] = '';
+ $arrayOxxoPayment['failDescription'] = '';
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $this->logger->info("Referencia OXXO creada correctamente." . PHP_EOL);
+
+
+ // Configuración de la API de tu servicio Docker de Puppeteer
+ $api_url = 'http://'.$ipPuppeteer.':'.$portPuppeteer.'/screenshot'; // Asegúrate que esta URL sea accesible
+
+ // --- Datos para la petición ---
+ $request_data = [
+ 'url' => $oxxo_receipt_url, // URL del recibo de OXXO
+ // Opcional: Si quieres recortar la imagen, descomenta y ajusta el 'clip'
+
+ 'clip' => [
+ 'x' => 325,
+ 'y' => 30,
+ 'width' => 550,
+ 'height' => 550
+ ]
+
+ ];
+
+ // Nombre del archivo donde se guardará la imagen
+ $clientFullNameWithoutSpaces = str_replace(' ', '_', $clientFullName); // Reemplazar espacios por guiones bajos
+ $voucherFileName = 'voucher_'.$clientFullNameWithoutSpaces.'_' . time() . '.jpeg'; // Usamos .jpeg por defecto
+ $output_filename = __DIR__ . '/../../vouchers_oxxo/' . $voucherFileName; // Usamos .jpeg por defecto
+ $output_filename = realpath(__DIR__ . '/../../vouchers_oxxo') . '/'. $voucherFileName; // Mejor: ruta absoluta y verifica que el directorio exista
+ //$output_filename = '/path/to/vouchers_oxxo/voucher_' . time() . '.jpeg'; // Mejor aún: ruta absoluta y fija, si es posible
+
+ $guzzleClient = new Client([
+ 'timeout' => 5, // Timeout de 5 segundos
+ ]);
+ // Descargar el recibo de OXXO
+ try {
+ // --- Realizar la petición POST ---
+ $response = $guzzleClient->post($api_url, [
+ 'json' => $request_data, // Guzzle codifica automáticamente el array a JSON y establece Content-Type: application/json
+ 'headers' => [
+ 'Accept' => 'image/jpeg, image/png', // Indicar que esperamos una imagen
+ ],
+ // Opcional: para depuración si necesitas ver el cuerpo de la respuesta en caso de error
+ // 'http_errors' => false // Desactiva las excepciones para códigos de estado 4xx/5xx y maneja la respuesta manualmente
+ ]);
+
+ // --- Procesar la respuesta ---
+ $statusCode = $response->getStatusCode();
+ $contentType = $response->getHeaderLine('Content-Type');
+
+ $this->logger->debug("Status Code: " . $statusCode);
+ $this->logger->debug("Content Type: " . $contentType);
+
+ if ($statusCode === 200 && str_contains($contentType, 'image/')) {
+ // La respuesta es una imagen y el código de estado es 200 OK
+ $image_content = $response->getBody()->getContents();
+
+ // *** VERIFICACIÓN IMPORTANTE: ***
+ if (file_put_contents($output_filename, $image_content)) {
+ $this->logger->debug("¡Imagen guardada exitosamente en: " . $output_filename);
+ $url_file = $this->UploadVoucherToWordpressByImageFileName($voucherFileName); //Carga del comprobante PDF a Wordpress para su posterior envío
+ $arrayOxxoPayment['voucher_image_url'] = $url_file; // Agregar la URL del archivo de imagen al array
+ } else {
+ $this->logger->error("Error: No se pudo guardar la imagen en " . $output_filename);
+ $this->logger->error("Ruta del archivo: " . $output_filename); // Agregado para depuración
+ $this->logger->error("Directorio del script: " . __DIR__); // Agregado para depuración
+ $this->logger->error("Error de PHP: " . error_get_last()['message']); // Agregado para depuración
+ }
+ } else {
+ // No es una imagen o hubo un error en el servicio
+ $this->logger->debug("Error: La respuesta no es una imagen o el código de estado no es 200 OK.");
+ $this->logger->debug("Cuerpo de la respuesta: " . $response->getBody()->getContents());
+ }
+
+ } catch (RequestException $e) {
+ // Manejo de errores de red o del servidor (ej. timeouts, 4xx, 5xx si http_errors no es false)
+ $this->logger->error("Error en la petición: " . $e->getMessage());
+ if ($e->hasResponse()) {
+ $this->logger->error("Cuerpo de la respuesta de error: " . $e->getResponse()->getBody()->getContents());
+ $this->logger->error("Código de estado HTTP de error: " . $e->getResponse()->getStatusCode());
+ }
+ } catch (Exception $e) {
+ // Otros errores inesperados
+ $this->logger->error("Error inesperado: " . $e->getMessage());
+ }
+
+
+
+
+ return $arrayOxxoPayment;
+ } else {
+ $this->logger->info("El PaymentIntent no tiene detalles de OXXO disponibles. Estado: " . $paymentIntentConfirm['status'] . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorPaymentIntentWithoutOxxoDetails';
+ $arrayOxxoPayment['failDescription'] = 'El PaymentIntent no tiene detalles de OXXO disponibles. Estado: ' . $paymentIntentConfirm['status'];
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+
+ }
+
+ } else {
+ $this->logger->info("Este cliente no tiene adeudos." . PHP_EOL);
+ //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
+ $arrayOxxoPayment['oxxo_reference'] = '';
+ $arrayOxxoPayment['url'] = '';
+ $arrayOxxoPayment['error'] = 'errorsinadeudo';
+ $arrayOxxoPayment['failDescription'] = 'Este cliente no tiene adeudos.';
+ $arrayOxxoPayment['clientID'] = $clientID;
+ $arrayOxxoPayment['clientFullName'] = $clientFullName;
+ $arrayOxxoPayment['amount'] = $amount;
+ $arrayOxxoPayment['voucher_image_url'] = '';
+ return $arrayOxxoPayment;
+ }
+ }
+
+
+
+
+
+
+ // /**
+ // * implement in subclass with the specific messaging provider
+ // * @see TwilioNotifierFacade::sendWhatsApp()
+ // */
+ abstract protected function sendWhatsApp(
+ string $message
+ ): void;
+
+
+
+
+ function validarEmail($email)
+ {
+ $this->logger->debug('SE VALIDA EL EMAIL!!! ' . PHP_EOL);
+ // Utilizar la función filter_var con el filtro FILTER_VALIDATE_EMAIL para validar el email
+ if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ // Si el email es válido, devolver el email
+ return $email;
+ } else {
+ // Si el email no es válido, devolver una cadena vacía
+ return '';
+ }
+ }
+
+
+ function UploadReceiptToWordpressByImageFileName($imageFileName): string
+ {
+
+ // $log = PluginLogManager::create(); //Initialize Logger
+ // $configManager = PluginConfigManager::create();
+ // $config = $configManager->loadConfig();
+
+ // // Configuración de conexión FTP
+ // $ftp_server = $config['hostServerFTP'];
+ // $ftp_username = $config['usernameServerFTP'];
+ // $ftp_password = $config['passServerFTP'];
+
+ $remote_folder = "/public_html/wp/wp-content/uploads/img/";
+
+
+ // Configuración de conexión FTP
+ $ftp_server = "siip.mx";
+ $ftp_username = "siip0001";
+ $ftp_password = '$spGiT,[wa)n';
+ $remote_file = "/public_html/wp/wp-content/uploads/img/" . $imageFileName;
+ $file_to_upload = __DIR__ . '/' . $imageFileName;
+ $url = 'https://siip.mx/wp/wp-content/uploads/img/' . $imageFileName;
+
+
+
+ // Conexión FTP
+ $ftp_conn = ftp_connect($ftp_server) or die("No se pudo conectar al servidor FTP");
+ $login = ftp_login($ftp_conn, $ftp_username, $ftp_password);
+ ftp_pasv($ftp_conn, true);
+ // Verificar conexión y login
+ if ($ftp_conn && $login) {
+ print_r("Conexión FTP exitosa" . PHP_EOL);
+ // $log->appendLog("Conexión FTP exitosa" . PHP_EOL);
+
+ // Cargar archivo
+ if (ftp_put($ftp_conn, $remote_file, $file_to_upload, FTP_BINARY)) {
+ print_r("El archivo ha sido cargado exitosamente." . PHP_EOL);
+ print_r("La URL es: " . $url . PHP_EOL);
+ // $log->appendLog("El archivo ha sido cargado exitosamente." . PHP_EOL);
+ // $log->appendLog("La URL es: " . $url . PHP_EOL);
+ // Cerrar conexión FTP
+ //ftp_close($ftp_conn);
+ //return $url;
+
+ } else {
+ //$log->appendLog("Error al cargar el archivo " . PHP_EOL);
+ print_r("Error al cargar el archivo " . PHP_EOL);
+ ftp_close($ftp_conn);
+ return '';
+ }
+
+ // Obtener lista de archivos en la carpeta
+ $files = ftp_nlist($ftp_conn, $remote_folder);
+ if (is_array($files)) {
+ // Eliminar la ruta del directorio de los archivos
+ $files = array_map(function ($file) use ($remote_folder) {
+ return str_replace($remote_folder, '', $file);
+ }, $files);
+
+ // Obtener fechas de modificación
+ $filesWithTime = [];
+ foreach ($files as $file) {
+ $modifiedTime = ftp_mdtm($ftp_conn, $remote_folder . $file);
+ if ($modifiedTime != -1) {
+ $filesWithTime[$file] = $modifiedTime;
+ }
+ }
+
+ // Ordenar archivos por fecha de modificación, más recientes primero
+ arsort($filesWithTime);
+
+ // Obtener los archivos a eliminar (todos menos los 5 más recientes)
+ $filesToDelete = array_slice(array_keys($filesWithTime), 5);
+
+ // Eliminar archivos antiguos
+ foreach ($filesToDelete as $file) {
+ if (ftp_delete($ftp_conn, $remote_folder . $file)) {
+ print_r("Comprobante eliminado de Wordpress: " . $file . PHP_EOL);
+ // $log->appendLog("Comprobante eliminado de Wordpress: " . $file . PHP_EOL);
+ } else {
+ print_r('Error al borrar comprobante' . $file . PHP_EOL);
+ // $log->appendLog('Error al borrar comprobante' . $file . PHP_EOL);
+ }
+ }
+ print_r("Archivos eliminados" . PHP_EOL);
+ // $log->appendLog("Archivos eliminados" . PHP_EOL);
+ ftp_close($ftp_conn);
+ return $url;
+ } else {
+ print_r("No se pudo obtener la lista de archivos de la carpeta FTP" . PHP_EOL);
+ // $log->appendLog("No se pudo obtener la lista de archivos de la carpeta FTP" . PHP_EOL);
+ ftp_close($ftp_conn);
+ return $url;
+ }
+
+ // Cerrar conexión FTP
+ //ftp_close($ftp_conn);
+ //return '';
+ } else {
+ print_r("No se pudo conectar o iniciar sesión en el servidor FTP." . PHP_EOL);
+ // $log->appendLog("No se pudo conectar o iniciar sesión en el servidor FTP." . PHP_EOL);
+ return '';
+ }
+
+ }
+
+
+
+ function UploadVoucherToWordpressByImageFileName($imageFileName): string
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+ $configManager = PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+
+ // Configuración de conexión FTP
+ $ftp_server = $config['hostServerFTP'];
+ $ftp_username = $config['usernameServerFTP'];
+ $ftp_password = $config['passServerFTP'];
+ $remote_folder = "/public_html/wp/wp-content/uploads/vouchers_oxxo/";
+
+ $log->appendLog("Subiendo voucher a worpdpress " . PHP_EOL);
+ // Configuración de conexión FTP
+ // $ftp_server = "siip.mx";
+ // $ftp_username = "siip0001";
+ // $ftp_password = '$spGiT,[wa)n';
+ $remote_file = "/public_html/wp/wp-content/uploads/vouchers_oxxo/" . $imageFileName;
+ $file_to_upload = __DIR__ . '/../../vouchers_oxxo/' . $imageFileName;
+ $url = 'https://siip.mx/wp/wp-content/uploads/vouchers_oxxo/' . $imageFileName;
+
+ $log->appendLog("file_to_upload: " . $file_to_upload . PHP_EOL);
+
+ // Conexión FTP
+ $ftp_conn = ftp_connect($ftp_server) or die("No se pudo conectar al servidor FTP");
+ $login = ftp_login($ftp_conn, $ftp_username, $ftp_password);
+ ftp_pasv($ftp_conn, true);
+ // Verificar conexión y login
+ if ($ftp_conn && $login) {
+ $log->appendLog("Conexión FTP exitosa" . PHP_EOL);
+
+ // Cargar archivo
+ if (ftp_put($ftp_conn, $remote_file, $file_to_upload, FTP_BINARY)) {
+ $log->appendLog("El archivo ha sido cargado exitosamente." . PHP_EOL);
+ $log->appendLog("La URL es: " . $url . PHP_EOL);
+
+ $this->deleteFilesWordpressExceptLastHundred($log, $ftp_conn, $remote_file);
+ // Cerrar conexión FTP
+ ftp_close($ftp_conn); //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
+ return $url; //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
+
+ } else {
+ $log->appendLog("Error al cargar el archivo " . PHP_EOL);
+ ftp_close($ftp_conn);
+ return '';
+ }
+
+ //SI SE DECIDE VOLVER A ELIMINAR LOS COMPROBANTES ENTONCES DESCOMENTAR ESTA PARTE DE ABAJO Y COMENTAR LA SECCIÓN DE ARRIBA
+
+ // Obtener lista de archivos en la carpeta
+ // $files = ftp_nlist($ftp_conn, $remote_folder);
+ // if (is_array($files)) {
+ // // Eliminar la ruta del directorio de los archivos
+ // $files = array_map(function ($file) use ($remote_folder) {
+ // return str_replace($remote_folder, '', $file);
+ // }, $files);
+
+ // // Obtener fechas de modificación
+ // $filesWithTime = [];
+ // foreach ($files as $file) {
+ // $modifiedTime = ftp_mdtm($ftp_conn, $remote_folder . $file);
+ // if ($modifiedTime != -1) {
+ // $filesWithTime[$file] = $modifiedTime;
+ // }
+ // }
+
+ // // Ordenar archivos por fecha de modificación, más recientes primero
+ // arsort($filesWithTime);
+
+ // // Obtener los archivos a eliminar (todos menos los 50 más recientes)
+ // $filesToDelete = array_slice(array_keys($filesWithTime), 50);
+
+ // // Eliminar archivos antiguos
+ // foreach ($filesToDelete as $file) {
+ // if (ftp_delete($ftp_conn, $remote_folder . $file)) {
+ // $log->appendLog("Comprobante eliminado de Wordpress: " . $file . PHP_EOL);
+ // } else {
+ // $log->appendLog('Error al borrar comprobante' . $file . PHP_EOL);
+ // }
+ // }
+ // $log->appendLog("Archivos eliminados" . PHP_EOL);
+ // ftp_close($ftp_conn);
+ // return $url;
+ // } else {
+ // $log->appendLog("No se pudo obtener la lista de archivos de la carpeta FTP" . PHP_EOL);
+ // ftp_close($ftp_conn);
+ // return $url;
+ // }
+
+ } else {
+ $log->appendLog("No se pudo conectar o iniciar sesión en el servidor FTP." . PHP_EOL);
+ return '';
+ }
+ }
+
+ function deleteFilesWordpressExceptLastHundred($log, $ftp_conn, $remote_folder): bool
+ {
+
+ // Obtener lista de archivos en la carpeta
+ $files = ftp_nlist($ftp_conn, $remote_folder);
+ if (is_array($files)) {
+ // Eliminar la ruta del directorio de los archivos
+ $files = array_map(function ($file) use ($remote_folder) {
+ return str_replace($remote_folder, '', $file);
+ }, $files);
+
+ // Obtener fechas de modificación
+ $filesWithTime = [];
+ foreach ($files as $file) {
+ $modifiedTime = ftp_mdtm($ftp_conn, $remote_folder . $file);
+ if ($modifiedTime != -1) {
+ $filesWithTime[$file] = $modifiedTime;
+ }
+ }
+
+ // Ordenar archivos por fecha de modificación, más recientes primero
+ arsort($filesWithTime);
+
+ // Obtener los archivos a eliminar (todos menos los 50 más recientes)
+ $filesToDelete = array_slice(array_keys($filesWithTime), 50);
+
+ // Eliminar archivos antiguos
+ foreach ($filesToDelete as $file) {
+ if (ftp_delete($ftp_conn, $remote_folder . $file)) {
+ $log->appendLog("Voucher eliminado de Wordpress: " . $file . PHP_EOL);
+ } else {
+ $log->appendLog('Error al borrar voucher' . $file . PHP_EOL);
+ }
+ }
+ $log->appendLog("Archivos eliminados" . PHP_EOL);
+ ftp_close($ftp_conn);
+ return true;
+ } else {
+ $log->appendLog("No se pudo obtener la lista de archivos de la carpeta FTP" . PHP_EOL);
+ ftp_close($ftp_conn);
+ return false;
+ }
+ }
+
+}
diff --git a/archivos_webhook_destino/src/Facade/AbstractStripeOperationsFacade.php b/archivos_webhook_destino/src/Facade/AbstractStripeOperationsFacade.php
new file mode 100755
index 0000000..e83882d
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/AbstractStripeOperationsFacade.php
@@ -0,0 +1,489 @@
+logger = $logger;
+ $this->messageTextFactory = $messageTextFactory;
+ $this->clientPhoneNumber = $clientPhoneNumber;
+ }
+
+ /*
+ * Creates a PaymentIntent in Stripe for a Customer
+ */
+ public function createPaymentIntent($event_json)
+ {
+ $this->logger->info("Iniciando creación de PaymentIntent en Stripe." . PHP_EOL);
+
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ $StripeToken = $config['tokenstripe'];
+ $idPaymentAdmin = $config['idPaymentAdminCRM']; //ID del administrador que crea el PaymentIntent
+ $stripe = new \Stripe\StripeClient($StripeToken); //Token de clave privada para la API de Stripe
+
+ // Asegurarse de que 'customer' esté presente en la estructura del evento
+ if (!isset($event_json['data']['object']['customer'])) {
+ $this->logger->info("Error: Invalid event structure. Customer ID not found." . PHP_EOL);
+ return;
+ }
+
+ $customerId = $event_json['data']['object']['customer'];
+ if (is_null($customerId)) {
+ $this->logger->info("Error: Customer ID is null." . PHP_EOL);
+ return;
+ }
+
+ // Validar que net_amount está presente
+ if (!isset($event_json['data']['object']['net_amount'])) {
+ $this->logger->info("Error: net_amount not found in event data." . PHP_EOL);
+ return;
+ }
+
+ $amount = $event_json['data']['object']['net_amount'];
+ //convertir en positivo
+ if ($event_json['data']['object']['net_amount'] < 0) {
+ $this->logger->warning("Error: net_amount es negativo." . PHP_EOL);
+ return;
+
+ }
+
+
+ //imprimir la cantidad del PaymentIntent
+ $this->logger->info("Cantidad del PaymentIntent: " . $amount . PHP_EOL);
+
+ try {
+ // Obtener información del cliente desde Stripe
+ $stripeQuery = $stripe->customers->retrieve($customerId, []);
+ $UCRM_clientID = $stripeQuery['metadata']['ucrm_client_id']; // ID del cliente en Ubiquiti UISP
+
+ // Obtener información del administrador actual
+ $this->ucrmApi = UcrmApi::create();
+ $currentUserAdmin = $this->ucrmApi->get('users/admins', []);
+
+ // Crear PaymentIntent
+ $paymentIntent = $stripe->paymentIntents->create([
+ 'amount' => $amount,
+ 'currency' => 'mxn',
+ 'customer' => $customerId,
+ 'payment_method_types' => ['customer_balance'],
+ 'payment_method_data' => ['type' => 'customer_balance'],
+ 'confirm' => true,
+ 'payment_method_options' => [
+ 'customer_balance' => [
+ 'funding_type' => 'bank_transfer',
+ 'bank_transfer' => ['type' => 'mx_bank_transfer']
+ ],
+ ],
+ 'metadata' => [
+ 'clientId' => $UCRM_clientID, // ID del cliente en Ubiquiti
+ 'createdBy' => 'UCRM',
+ 'paymentType' => 'card.one_time',
+ 'signedInAdminId' => $idPaymentAdmin, // ID del administrador que crea el PaymentIntent
+ 'tipoPago' => 'Transferencia Bancaria'
+ ],
+ ]);
+
+ $this->logger->info("PaymentIntent creado: " . $paymentIntent->id . PHP_EOL);
+
+ } catch (\Stripe\Exception\ApiErrorException $e) {
+ $this->logger->info("Error creando PaymentIntent: " . $e->getMessage() . PHP_EOL);
+ }
+ }
+
+
+ /*
+ * Creates the Stripe Customer
+ */
+ public function createStripeClient(NotificationData $notificationData, $tagStripe = false): void
+ {
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ // the "exportFormat" key must be defined in plugin's manifest file, see the link above
+ $IPServer = $config['ipserver'];
+ $UCRMAPIToken = $config['apitoken'];
+ $StripeToken = $config['tokenstripe'];
+ $baseUri = 'https://' . $IPServer . '/crm/api/v1.0/'; //endpoint de la API REST del CRM
+ $this->ucrmApi = UcrmApi::create();
+
+ $stripe = new \Stripe\StripeClient($StripeToken); //Token de clave privada en modo prueba para la API de Stripe
+ //$stripe = new \Stripe\StripeClient('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'); //Token de clave privada en modo prodcucción para la API de Stripe
+
+ //valor de $notificationData en json
+ $this->logger->info("Valor de notificationData: " . json_encode($notificationData) . PHP_EOL);
+
+ //ejemplo de notificationData: {"uuid":"0be6fee6-db1d-4ab5-a52c-2ee87b04315e","changeType":"edit","entity":"client","entityId":170,"message":null,"clientId":170,"eventName":"client.edit","clientData":{"id":170,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"San Luis 34","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"San Luis 34, Dolores Hidalgo, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-03-24T00:00:00-0600","leadConvertedAt":"2025-03-24T15:01:22-0600","companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Charicuas","lastName":"Quinero","username":null,"contacts":[{"id":176,"clientId":170,"email":null,"phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[{"id":192,"clientId":170,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_S0T9BJ4dO0p0A3","clientZoneVisible":true},{"id":193,"clientId":170,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"124180302040274015","clientZoneVisible":true}],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[{"id":5,"name":"CREARCLABESTRIPE","colorBackground":"#e30000","colorText":"#fff"}],"invitationEmailSentDate":null,"avatarColor":"#ef5350","addressGpsLat":22.00854045,"addressGpsLon":-99.0272544,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"serviceData":null,"invoiceData":null,"paymentData":null}
+
+ //obtener el id del cliente
+ $clientId = $notificationData->clientData['id'];
+
+ //si en attributes del cliente encuentra el custom field de Stripe Customer ID entonces no se vuelve a crear el cliente en Stripe
+ $attributes = $notificationData->clientData['attributes'];
+ $this->logger->info("Valor de attributes: " . json_encode($attributes) . PHP_EOL);
+ $stripeCustomerId = null;
+ foreach ($attributes as $attribute) {
+ if ($attribute['key'] === 'stripeCustomerId') {
+ $stripeCustomerId = $attribute['value'];
+ break;
+ }
+ }
+
+ $customAttributes = $this->ucrmApi->get('custom-attributes/', ['attributeType' => 'client']);//Obtener los atributos del sistema que estén vinculados a la entidad "cliente"
+ //$this->logger->info("result del custom Attributes: " . json_encode($customAttributes) . PHP_EOL);
+
+
+ // Verificar si se obtuvieron los atributos
+ if ($customAttributes && is_array($customAttributes)) {
+ foreach ($customAttributes as $attribute) {
+ // Verificar si 'name' contiene la palabra 'Stripe' sin distinguir mayúsculas y minúsculas
+ if (isset($attribute['name']) && stripos($attribute['name'], 'Stripe') !== false) {
+ $this->logger->info("ID correspondiente a 'Customer Stripe ID': " . $attribute['id'] . PHP_EOL);
+ $this->stripeCustomAttributeID = $attribute['id'];
+ } else if (isset($attribute['name']) && stripos($attribute['name'], 'Clabe') !== false) {
+ //$this->logger->info("ID correspondiente a 'Clabe Interbancaria Banamex': " . $attribute['id'] .PHP_EOL);
+ $this->clabeInterbancariaBanamexID = $attribute['id'];
+ }
+
+
+ }
+ } else {
+ $this->logger->info("Error al obtener los atributos personalizados." . PHP_EOL);
+ }
+
+ if ($stripeCustomerId) {
+ $this->logger->info("El cliente ya tiene un Stripe Customer ID: " . $stripeCustomerId . PHP_EOL);
+ if ($tagStripe) {
+ $tagsIds = $this->ucrmApi->get('client-tags', []);
+ //ejemplo de respuesta $tagsIds: [{"id":4,"name":"EQUIPO A CREDITO","colorBackground":"#fed74a","colorText":"#444"},{"id":5,"name":"CREARCLABESTRIPE","colorBackground":"#e30000","colorText":"#fff"}]
+
+ //obtener el ID de la etiqueta o tag llamada "CREAR CLABE STRIPE" y asiganarla a una variable $tagCrearClabeStripe basandose en el ejemplo de respuesta anterior
+ $tagCrearClabeStripe = null;
+ foreach ($tagsIds as $tag) {
+ if ($tag['name'] === 'CREAR CLABE STRIPE') {
+ $tagCrearClabeStripe = $tag['id'];
+ // $this->logger->info("ID de la etiqueta 'CREAR CLABE STRIPE': " . $tagCrearClabeStripe . PHP_EOL);
+ break;
+ }
+ }
+ if (!$tagCrearClabeStripe) {
+ $this->logger->info("No se encontró la etiqueta 'CREAR CLABE STRIPE'." . PHP_EOL);
+ return;
+ }
+
+ $this->ucrmApi->patch("clients/$clientId/remove-tag/" . $tagCrearClabeStripe);
+ $this->logger->info("Se eliminó la etiqueta 'CREAR CLABE STRIPE' del cliente." . PHP_EOL);
+
+ }
+ return;
+ }
+
+ //$this->logger->info("Ya dentro del metodo Create Stripe Client " . PHP_EOL);
+ //$this->sendWhatsApp('Hola Dany');
+
+
+ if ($tagStripe) {
+ $tagsIds = $this->ucrmApi->get('client-tags', []);
+ //ejemplo de respuesta $tagsIds: [{"id":4,"name":"EQUIPO A CREDITO","colorBackground":"#fed74a","colorText":"#444"},{"id":5,"name":"CREARCLABESTRIPE","colorBackground":"#e30000","colorText":"#fff"}]
+
+ //obtener el ID de la etiqueta o tag llamada "CREARCLABESTRIPE" y asiganarla a una variable $tagCrearClabeStripe basandose en el ejemplo de respuesta anterior
+ $tagCrearClabeStripe = null;
+ foreach ($tagsIds as $tag) { //revisamos los tags del cliente y si encuentra el tag de "CREARCLABESTRIPE" entonces lo asigna a la variable $tagCrearClabeStripe el valor de id
+ if ($tag['name'] === 'CREAR CLABE STRIPE') {
+ $tagCrearClabeStripe = $tag['id'];
+ // $this->logger->info("ID de la etiqueta 'CREAR CLABE STRIPE': " . $tagCrearClabeStripe . PHP_EOL);
+ break;
+ }
+ }
+ if (!$tagCrearClabeStripe) {
+ $this->logger->info("No se encontró la etiqueta 'CREAR CLABE STRIPE'." . PHP_EOL);
+ return;
+ }
+ $this->createCustomerStripe($notificationData, $stripe, $baseUri, $UCRMAPIToken);
+ $this->ucrmApi->patch("clients/$clientId/remove-tag/" . $tagCrearClabeStripe);
+ $this->logger->info("Se eliminó la etiqueta 'CREAR CLABE STRIPE' del cliente." . PHP_EOL);
+ return;
+ }
+
+
+
+
+
+
+ // Verificar si la solicitud fue exitosa (código de estado 200)
+ //https://172.16.5.120/crm/api/v1.0/payments?limit=1&clientId=1992&order=createdDate&direction=DESC
+
+ $notification_client_data = $notificationData->clientData; //array con los datos del cliente
+
+ // Asegúrate de trabajar con un objeto PHP
+ $dataObject = json_decode(json_encode($notification_client_data)); // Convertir a JSON y luego decodificar como objeto
+
+ if (!is_object($dataObject)) {
+ $this->logger->info("Error: Los datos del cliente no pudieron ser procesados." . PHP_EOL);
+ return;
+ }
+
+ $this->createCustomerStripe($notificationData, $stripe, $baseUri, $UCRMAPIToken);
+ }
+
+ // /**
+ // * implement in subclass with the specific messaging provider
+ // * @see TwilioNotifierFacade::sendWhatsApp()
+ // */
+ abstract protected function sendWhatsApp(
+ string $message
+ ): void;
+
+
+ function createCustomerStripe($notificationData, $stripe, $baseUri, $token): bool
+ {
+ $this->ucrmApi = UcrmApi::create();
+ $this->logger->info("Creando el Customer Stripe" . PHP_EOL);
+
+
+
+ $ucrm_client_id = $notificationData->clientData['id'];
+ $clientCRMContacts = $notificationData->clientData['contacts'];
+
+ $firstName = $notificationData->clientData['firstName']; //obtenemos nombre del cliente y lo almacenamos en una variable
+ $lastName = $notificationData->clientData['lastName']; //obtenemos apellidos del cliente y lo almacenamos en una variable
+ $this->logger->info('El cliente a procesar es : ' . $firstName . ' ' . $lastName . PHP_EOL); //impresión de control para ver el nombre del cliente a procesar en consola
+
+ $cadenaNotificationData = json_encode($notificationData);
+ $this->logger->info("Datos notificationData: " . $cadenaNotificationData . PHP_EOL);
+ foreach ($clientCRMContacts as $contact) { //aquí revisamos los datos de contacto del cliente, como pueden ser uno o varios se hace uso del foreach
+ $this->logger->info('Ya dentro del FOREACH!!! ' . PHP_EOL);
+
+ $phone = ''; //variable para almacenar el número de teléfono del cliente que se mandará a su cuenta de Stripe
+
+ foreach ($contact['types'] as $type) { //revisamos el tipo de contacto
+
+ $this->logger->info('REVISANDO EL PRIMER CONTACTO!!! ' . PHP_EOL);
+ if ($type['name'] === "WhatsApp") { //si es de tipo whatsapp..
+ //print_r("Encontré un tipo de Contacto para WhatsAapp" . PHP_EOL);
+ $phone = $contact['phone']; //se asigna como número de teléfono
+ break;
+ } else {
+ $phone = $contact['phone']; //Si no encuentra un tipo de contacto como Whatsapp entonces el último número de celular obtenido es el que se envía
+ }
+ }
+ $email = $this->validarEmail($contact['email']); //validamos el email del cliente mediante la función validarEmail para que en caso de que no esté bien formado lo ponga en blanco
+
+
+
+ }
+
+ $this->logger->info('ahora se procede a validar el teléfono!!! ' . PHP_EOL);
+
+ //si la variable $phone no esta vacia o null se valida con la funcion validarNumeroTelefono
+ if ($phone == '') {
+ $this->logger->info('El número de teléfono está vacío o no es válido.' . PHP_EOL);
+ //se manda a crear pero sin numero de teléfono
+ $this->logger->info('AHORA SE MANDA A CREAR EL CLIENTE A STRIPE!!! ' . PHP_EOL);
+ $result = $stripe->customers->create([
+ "description" => "Cliente SIIP CRM con client_id: " . $ucrm_client_id,
+ "name" => $firstName . ' ' . $lastName,
+ "email" => $email,
+ 'preferred_locales' => ['es-419']
+ ]); //aquí se contruye la petición de creación de un customer en Stripe y se consume la API
+
+ } else {
+ $phone = $this->validarNumeroTelefono($phone); //validamos y procesamos el número de celular del cliente para que se vaya a 10 dígitos ya que Stripe por si mismo les agrega el +52
+ $this->logger->info('AHORA SE MANDA A CREAR EL CLIENTE A STRIPE!!! ' . PHP_EOL);
+ $result = $stripe->customers->create([
+ "description" => "Cliente SIIP CRM con client_id: " . $ucrm_client_id,
+ "name" => $firstName . ' ' . $lastName,
+ "phone" => $phone,
+ "email" => $email,
+ 'preferred_locales' => ['es-419']
+ ]); //aquí se contruye la petición de creación de un customer en Stripe y se consume la API
+
+ }
+
+ $this->logger->info(json_encode($result) . PHP_EOL); //imprimir respuesta de creación del cliente
+ //ejemplo de respuesta de stripe cuando se crea el cliente: {"id":"cus_Rkh9CoRTpjlZUu","object":"customer","address":null,"balance":0,"created":1739250682,"currency":null,"default_source":null,"delinquent":false,"description":"Cliente SIIP CRM con client_id: 167","discount":null,"email":null,"invoice_prefix":"5017E9D3","invoice_settings":{"custom_fields":null,"default_payment_method":null,"footer":null,"rendering_options":null},"livemode":false,"metadata":[],"name":"Javier Alatorre","next_invoice_sequence":1,"phone":"4181878106","preferred_locales":["es-419"],"shipping":null,"tax_exempt":"none","test_clock":null}
+
+ //validar si se creo el cliente con la API de Stripe $stripe->customers->create
+ if (!isset($result['id'])) { //si no existe el ID del cliente en la respuesta de Stripe entonces se manda un mensaje de error
+ $this->logger->info('Error al crear el cliente en Stripe: ' . json_encode($result) . PHP_EOL);
+
+ }
+
+
+
+ $stripe_customer_id = $result['id']; //obtenemos el customer id de Stripe recibido por medio del consumo del API y lo asignamos a una variable $stripe_customer_id
+ sleep(2);
+ $result2 = $stripe->customers->update(
+ $stripe_customer_id,
+ ['metadata' => ['ucrm_client_id' => '' . $ucrm_client_id]]
+ );//aquí se contruye la petición de actualización de un customer en Stripe para agregarle los metadatos y se consume la API, requiere el ID del Customer, por eso antes lo almacenamos en la variable $stripe_customer_id
+
+ $this->logger->info(json_encode($result2) . PHP_EOL); // imprimir respuesta de actualización del metadata del cliente
+ sleep(2);
+ $result3 = $stripe->customers->createFundingInstructions(
+ $stripe_customer_id,
+ [
+ 'currency' => 'mxn',
+ 'funding_type' => 'bank_transfer',
+ 'bank_transfer' => ['type' => 'mx_bank_transfer'],
+ ]
+ ); //aquí se contruye la petición de creación de Instrucciones de Fondeo de un customer en Stripe (O su metodo de pago como cuenta bancaria para transferencias) y se consume la API
+
+ $this->logger->info(json_encode($result3) . PHP_EOL); //imprimir respuesta de asignación de cuenta bancaria de transferencia
+
+ // Acceder al valor de "clabe" para BANORTE
+ $clabeInterbancaria = $result3['bank_transfer']['financial_addresses'][0]['spei']['clabe']; //Asignamos la clabe obtenida con la API de Stripe con la solicitud anterior a la variable $clabe
+ $stripeID = $this->stripeCustomAttributeID;
+ $clabeInterbancariaID = $this->clabeInterbancariaBanamexID;
+
+ $customer = $stripe->customers->update(
+ $stripe_customer_id,
+ [
+ 'metadata' => [
+ 'clabe' => $clabeInterbancaria, // Nueva clabe
+ ],
+ ]
+ );
+
+ $this->logger->info("CLABE guardada en metadata: " . $customer->metadata->clabe . PHP_EOL);
+
+
+ $json_data_patch = '{
+ "attributes": [
+ {
+ "value": "' . $stripe_customer_id . '",
+ "customAttributeId":' . $stripeID . '
+ },
+ {
+ "value": "' . $clabeInterbancaria . '",
+ "customAttributeId":' . $clabeInterbancariaID . '
+ }
+ ]
+
+ }'; //JSON para hacer patch de los custom fields del cliente en el UISCP CRM, Campo para el Stripe Customer ID y la Clabe interbancaria
+
+ //valor de $json_data_patch en json
+ //$this->logger->info("Valor de json_data_patch: " . $json_data_patch . PHP_EOL);
+ // try{
+ // $responsepatchCRM= $this->ucrmApi->patch("clients/$ucrm_client_id", [
+ // "attributes" => [
+ // [
+ // "value" => $stripe_customer_id,
+ // "customAttributeId" => $stripeID
+ // ],
+ // [
+ // "value" => $clabeInterbancaria,
+ // "customAttributeId" => $clabeInterbancariaID
+ // ]
+ // ]
+ // ]); //aquí se contruye la petición para hacer patch hacia el cliente en sus custom fields con la API del UISP UCRM
+ // $this->logger->info("Se actualizó el cliente en UCRM con el Stripe Customer ID y la Clabe Interbancaria." . PHP_EOL);
+ // $this->logger->info(json_encode($responsepatchCRM) . PHP_EOL); //imprimir respuesta del patch de CRM con la clabe y Customer ID Stripe
+ // }catch (GuzzleException $e) {
+ // $this->logger->info("Error al hacer el patch al cliente en UCRM: " . $e->getMessage() . PHP_EOL);
+ // return false; // Return false if patch fails
+ // }
+
+
+ $clientguzz = new Client(); //instancia de cliente GuzzleHttp para consumir API UISP CRM
+ try {
+ //aquí se contruye la petición para hacer patch hacia el cliente en sus custom fields con la API del UISP UCRM
+ $responseCRM = $clientguzz->patch($baseUri . 'clients/' . $ucrm_client_id, [
+ 'json' => json_decode($json_data_patch, true),
+ 'headers' => [
+ 'X-Auth-App-Key' => $token, // Cambia el nombre de la cabecera de autorización
+ 'Accept' => 'application/json', // Indica que esperamos una respuesta en formato JSON
+ ],
+ 'verify' => false,
+ ]);
+
+
+ } catch (GuzzleException $error) {
+ $this->logger->info("Error al hacer el patch al CRM: " . $error->getMessage() . PHP_EOL);
+ return false; // Return false if patch fails
+ }
+ $this->logger->info(json_encode($responseCRM) . PHP_EOL); //imprimir respuesta del patch de CRM con la clabe y Customer ID Stripe
+
+ return true; // Return true if all operations succeed
+ }
+
+ function validarNumeroTelefono($telefono)
+ {
+ // Eliminar espacios y guiones
+ $telefono = preg_replace('/\s+|-/', '', $telefono);
+
+ // Eliminar caracteres no numéricos
+ $telefono = preg_replace('/\D/', '', $telefono);
+
+ // Verificar si quedan exactamente 10 dígitos
+ if (strlen($telefono) === 10) {
+ // Retornar el número de teléfono correctamente formateado
+ return $telefono;
+ } elseif (strlen($telefono) > 10) {
+ // Si el número tiene más de 10 dígitos, quitar los primeros
+ return substr($telefono, -10);
+ } else {
+ // Si el número tiene menos de 10 dígitos, retornar cadena vacía
+ return '';
+ }
+ }
+
+ function validarEmail($email)
+ {
+ $this->logger->info('SE VALIDA EL EMAIL!!! ' . PHP_EOL);
+ // Utilizar la función filter_var con el filtro FILTER_VALIDATE_EMAIL para validar el email
+ if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ // Si el email es válido, devolver el email
+ return $email;
+ } else {
+ // Si el email no es válido, devolver una cadena vacía
+ return '';
+ }
+ }
+
+
+
+}
diff --git a/archivos_webhook_destino/src/Facade/AbstractUpdateClientFacade.php b/archivos_webhook_destino/src/Facade/AbstractUpdateClientFacade.php
new file mode 100755
index 0000000..54ab925
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/AbstractUpdateClientFacade.php
@@ -0,0 +1,98 @@
+logger = $logger;
+ $this->messageTextFactory = $messageTextFactory;
+ $this->smsNumberProvider = $smsNumberProvider;
+ }
+
+ /*
+ * sets up the body and uses the implementation's sendMessage() to send
+ */
+ public function notify(NotificationData $notificationData): void
+ {
+ $clientSmsNumber = $this->smsNumberProvider->getUcrmClientNumber($notificationData); //renombrar variables
+
+ if (empty($clientSmsNumber)) {
+ $this->logger->warning('No SMS number found for client: ' . $notificationData->clientId);
+ return;
+ }
+ // $messageBody = $this->messageTextFactory->createBody($notificationData);
+ // if (! $messageBody) {
+ // $this->logger->info('No text configured for event: ' . $notificationData->eventName);
+ // return;
+ // }
+
+
+ try {
+ $this->logger->debug(sprintf('llego al llamado de sendwhatsapp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientSmsNumber));
+ //$this->sendMessage($notificationData, $clientSmsNumber, $messageBody);
+ //$this->sendWhatsApp($notificationData, $clientSmsNumber);
+
+ $client_callbell_api = new ClientCallBellAPI();
+ $client_callbell_api->sendMessageWhatsApp($clientSmsNumber, $notificationData);
+ $response_getContactCallBell=json_decode($client_callbell_api->getContactWhatsapp($clientSmsNumber));
+ $client_callbell_api->patchWhatsapp($response_getContactCallBell->contact->uuid,$notificationData);
+
+ } catch (HttpException $httpException) {
+ //$this->logger->debug('Ocurrio un error en el try catch');
+ $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
+ }
+ }
+
+ /**
+ * implement in subclass with the specific messaging provider
+ * @see TwilioNotifierFacade::sendMessage()
+ */
+ abstract protected function sendMessage(
+ NotificationData $notificationData,
+ string $clientSmsNumber,
+ string $messageBody
+ ): void;
+
+ // /**
+ // * implement in subclass with the specific messaging provider
+ // * @see TwilioNotifierFacade::sendWhatsApp()
+ // */
+ // abstract protected function sendWhatsApp(
+ // NotificationData $notificationData,
+ // string $clientSmsNumber
+ // ): void;
+}
diff --git a/archivos_webhook_destino/src/Facade/ClientCallBellAPI.php b/archivos_webhook_destino/src/Facade/ClientCallBellAPI.php
new file mode 100755
index 0000000..f9bbbdb
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/ClientCallBellAPI.php
@@ -0,0 +1,1346 @@
+UCRMAPIToken = $UCRMAPIToken;
+ $this->IPServer = $IPServer;
+ $this->CallBellAPIToken = $CallBellAPIToken;
+ }
+
+ public function updateContact($client_uuid)
+ {
+ }
+
+ public function printPrueba($clientWhatsAppNumber, $notificationData)
+ {
+ $log = PluginLogManager::create(); //Initialize Logger
+ $log->appendLog("Ejecutando metodo print prueba: " . $clientWhatsAppNumber);
+ // $logger = new Logger();
+ // $logger->debug('Ejecutando metodo print prueba con Logger');
+ }
+
+ public function sendMessageWhatsApp($clientWhatsAppNumber, $notificationData)
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+ $log->appendLog("Entrando al metodo sendMessageWhatsApp" . PHP_EOL);
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, 'https://api.callbell.eu/v1/messages/send');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer g8thcZkXGd3xBj2g3TtYNYFMH1fuesbJ.b6a940ea7d78cf6c9e42f067b21c8ddf96e9fa2a9e307bfd0c7c7c4d7fa38f79',
+ 'Content-Type: application/json',
+ ]);
+
+ // $jsonString = json_encode($notificationData);
+ // $log->appendLog($jsonString);
+
+ $campo1 = sprintf("😀 *%s %s*", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']);
+ $log->appendLog("Valor del campo1: " . $campo1);
+ $estado_service = ($notificationData->clientData['hasSuspendedService']) ? 'Suspendido 🔴' : 'Activo 🟢';
+ $log->appendLog("Valor del estado_service: " . $estado_service);
+ $domicilio = ($notificationData->clientData['fullAddress'] == null) ? 'Sin domicilio' : $notificationData->clientData['fullAddress'];
+ $log->appendLog("Valor del domicilio: " . $domicilio);
+ $campo2 = sprintf("📡 Su servicio está: %s 📍Su dirección es: *%s* ", $estado_service, $domicilio);
+ $log->appendLog("Valor del campo2 " . $campo2);
+
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\"],\n \"template_uuid\": \"55705f1fe4e24bab80104dc2643fe11c\",\n \"optin_contact\": true\n }";
+ $log->appendLog("La cadena CURL que se envia es: " . $curl_string);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $curl_string);
+
+ $response = curl_exec($ch);
+ $log->appendLog("Response del CallBell: " . $response);
+
+ curl_close($ch);
+ }
+
+ public function sendJobNotificationWhatsAppToClient($clientWhatsAppNumber, $jobNotificationData, $reprogramming, $changeInstaller): bool
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+ $log->appendLog("Enviando mensaje de trabajo para el cliente" . PHP_EOL);
+ $jsonJobNotificationData = json_encode($jobNotificationData, true);
+ $log->appendLog("Datos de la notificación de trabajo: " . $jsonJobNotificationData . PHP_EOL);
+
+ // --- ¡AÑADE ESTAS LÍNEAS PARA CONVERTIR A BOOLEANO REAL! ---
+ $reprogramming = filter_var($reprogramming, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ $changeInstaller = filter_var($changeInstaller, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ // -----------------------------------------------------------
+
+ // Puedes volver a loggear los valores para confirmar la conversión (opcional)
+ $log->appendLog("DEBUG: Valores después de conversión - Reprogramming: " . var_export($reprogramming, true) . ", ChangeInstaller: " . var_export($changeInstaller, true) . PHP_EOL);
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, 'https://api.callbell.eu/v1/messages/send');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+
+ $campo1 = '👤 ' . sprintf(' *%s*', $jobNotificationData['clientFullName']);
+ if ($changeInstaller && !$reprogramming) {
+ $campo2 = sprintf('se ha hecho un cambio de técnico 👷🏻♂️🔄 para su visita con el folio *#️⃣%s*', $jobNotificationData['jobId']);
+ } else {
+ $campo2 = sprintf('*#️⃣%s*', $jobNotificationData['jobId']);
+ }
+ $campo3 = '🗓️ ' . sprintf('%s', $jobNotificationData['date']);
+ if ($changeInstaller && $reprogramming) {
+ $campo4 = 'Además se ha hecho un cambio de técnico por el siguiente 👷🏻♂️➡️ ' . sprintf('*%s*', $jobNotificationData['installerName']);
+ } else {
+ $campo4 = '👷🏻♂️➡️ ' . sprintf('*%s*', $jobNotificationData['installerName']);
+ }
+
+ $campo5 = "asegúrese de que alguien esté presente en el domicilio 🏠 para permitir el acceso y confirme su disponibilidad.";
+
+ $log->appendLog("DEBUG: Valores antes de la estructura IF - Reprogramming: " . var_export($reprogramming, true) . ", ChangeInstaller: " . var_export($changeInstaller, true) . PHP_EOL);
+
+ if ($reprogramming && !$changeInstaller) {
+ //{{1}}, se ha reprogramado su visita técnica con el folio {{2}}
+
+ $campo3 = '🗓️➡️ ' . sprintf('%s', $jobNotificationData['date']);
+ $campo1_combinado = "Estimado cliente $campo1 se ha reprogramado su visita técnica con folio $campo2";
+
+ // Case: true, false
+ //Enviar notificación de reprogramación al cliente
+ $log->appendLog("Enviando notificación de reprogramación al cliente, valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1_combinado\", \"$campo3\", \"$campo4\", \"$campo5\"],\n \"template_uuid\": \"715eed9d6f2d4d90853f25e296202e00\",\n \"optin_contact\": true\n }";
+ } else if (!$reprogramming && $changeInstaller) {
+ // Case: false, true
+ //Enviar notificación de cambio de instalador
+ $log->appendLog("Enviando notificación de cambio de instalador al cliente, valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\", \"$campo3\", \"$campo4\", \"$campo5\"],\n \"template_uuid\": \"d684e6fa2ba24593a86c98be1815831d\",\n \"optin_contact\": true\n }";
+ } else if (!$reprogramming && !$changeInstaller) { // <--- Ahora este else if está correctamente encadenado
+ // Case: false, false
+ //Enviar notificación normal de visita técnica al cliente
+ $log->appendLog("Enviando notificación normal de visita técnica al cliente, valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\", \"$campo3\", \"$campo4\", \"$campo5\"],\n \"template_uuid\": \"07cfbc6e394044608485b530a27177d0\",\n \"optin_contact\": true\n }";
+ } else if ($reprogramming && $changeInstaller) { // <--- Ahora este else if está correctamente encadenado
+ // Case: true, true
+ //Enviar notificación de cambio de instalador y reprogramación al cliente
+ $log->appendLog("Enviando notificación de cambio de instalador y reprogramación al cliente, valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\", \"$campo3\", \"$campo4\", \"$campo5\"],\n \"template_uuid\": \"145885d15323414f978f1e3f249c2ae1\",\n \"optin_contact\": true\n }";
+ } else {
+ // Case: true, true (la única combinación restante con booleanos)
+ $log->appendLog("No se encontró una opción válida para enviar la notificación (reprogramming y changeInstaller son true)." . PHP_EOL);
+ // Decide qué hacer aquí, ¿Quizás devolver false? ¿O manejar esta combinación?
+ return false; // O el manejo adecuado para true/true
+ }
+
+ $log->appendLog("La cadena CURL que se envia es: " . $curl_string);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $curl_string);
+
+ $response = curl_exec($ch);
+ $log->appendLog("Response del CallBell: " . $response);
+
+ curl_close($ch);
+
+ // Validar la respuesta de Callbell
+ $jsonResponse = json_decode($response, true);
+
+ if (json_last_error() === JSON_ERROR_NONE) {
+ // Evaluar si contiene "message" con "status": "enqueued"
+ if (isset($jsonResponse['message']) && $jsonResponse['message']['status'] === 'enqueued') {
+ $log->appendLog("La notificación fue enviada correctamente con estado: enqueued" . PHP_EOL);
+ return true;
+ }
+
+ // Evaluar si contiene "error"
+ if (isset($jsonResponse['error'])) {
+ $log->appendLog("Error al enviar la notificación: " . json_encode($jsonResponse['error']) . PHP_EOL);
+ return false;
+ }
+ } else {
+ // Manejo de error en caso de que la respuesta no sea un JSON válido
+ $log->appendLog("La respuesta no es un JSON válido." . PHP_EOL);
+ return false;
+ }
+
+ // Valor de retorno predeterminado en caso de que ninguna condición se cumpla
+ $log->appendLog("Ruta no prevista en la función." . PHP_EOL);
+ return false;
+ }
+
+ public function sendJobNotificationWhatsAppToInstaller($installerWhatsAppNumber, $jobInstallerNotificationData, $reprogramming, $changeInstaller): bool
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+ $log->appendLog("Enviando mensaje de tarea al instalador" . PHP_EOL);
+ $jsonJobNotificationData = json_encode($jobInstallerNotificationData, true);
+ $log->appendLog("Datos de la notificación de tarea: " . $jsonJobNotificationData . PHP_EOL);
+
+ // --- ¡AÑADE ESTAS LÍNEAS PARA CONVERTIR A BOOLEANO REAL! ---
+ $reprogramming = filter_var($reprogramming, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ $changeInstaller = filter_var($changeInstaller, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ // -----------------------------------------------------------
+
+ // Puedes volver a loggear los valores para confirmar la conversión (opcional)
+ $log->appendLog("DEBUG: Valores después de conversión - Reprogramming: " . var_export($reprogramming, true) . ", ChangeInstaller: " . var_export($changeInstaller, true) . PHP_EOL);
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, 'https://api.callbell.eu/v1/messages/send');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+
+
+ if (!$reprogramming && $changeInstaller) {
+ $campo1 = $jobInstallerNotificationData['installerName'];
+ $campo2 = $jobInstallerNotificationData['subjectOfChange'];
+ $campo3 = sprintf("#️⃣%s", $jobInstallerNotificationData['jobId']);
+ $campo4 = sprintf('*👤%s* ', $jobInstallerNotificationData['clientFullName']);
+ $campo5 = $jobInstallerNotificationData['additionalChangeData'];
+ } else {
+ $campo1 = '👷🏻♂️ ' . $jobInstallerNotificationData['installerName'];
+ $campo2 = sprintf("#️⃣%s", $jobInstallerNotificationData['jobId']);
+ $campo3 = '👤 *' . $jobInstallerNotificationData['clientFullName'] . '*';
+ // $campo4 = $jobInstallerNotificationData['clientAddress'];
+ $campo4 = '☎️ ' . $jobInstallerNotificationData['clientWhatsApp'];
+ $campo5 = '🗓️ ' . $jobInstallerNotificationData['date'];
+ // $campo6 = '🛠️ ' . $jobInstallerNotificationData['jobDescription'];
+ // $campo7 = '📌 ' . $jobInstallerNotificationData['gmapsLocation'];
+ // $campo8 = '🔐 ' . $passwordAntenaCliente;
+ }
+
+ if ($reprogramming && !$changeInstaller) {
+ $jobId = sprintf("#️⃣ *%s*", $jobInstallerNotificationData['jobId']);
+ $clientFullName = sprintf("👤 *%s*", $jobInstallerNotificationData['clientFullName']);
+ $date = sprintf("🗓️➡️ %s", $jobInstallerNotificationData['date']);
+ $installerName = sprintf("👷🏻♂️ *%s*", $jobInstallerNotificationData['installerName']);
+
+ $campo1_combinado = "$installerName se reprogramó una tarea con el folio $jobId para el cliente $clientFullName, la nueva fecha será el $date";
+ $campo2 = $jobInstallerNotificationData['clientWhatsApp'];
+ $campo3 = $jobInstallerNotificationData['gmapsLocation'];
+ $campo4 = $jobInstallerNotificationData['passwordAntenaCliente'];
+
+ //Enviar notificación de reprogramación
+ $log->appendLog("Enviando notificación de reprogramación al instalador, valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$installerWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1_combinado\", \"$campo2\", \"$campo3\", \"$campo4\"],\n \"template_uuid\": \"88eeb6420a214fd8870dd28d741021c4\",\n \"optin_contact\": true\n }";
+ } else if (!$reprogramming && $changeInstaller) {
+ //Enviar notificación de cambio de instalador
+ $log->appendLog("Enviando notificación de cambio de instalador al instalador anterior (desasignación), valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$installerWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\", \"$campo3\", \"$campo4\", \"$campo5\"],\n \"template_uuid\": \"e1aa2b0fd3884595918f4ac2676acd29\",\n \"optin_contact\": true\n }";
+ } else if ($reprogramming && $changeInstaller) {
+ //Enviar notificación de cambio de instalador
+ $log->appendLog("Enviando notificación de cambio de instalador al instalador y notificación de reprogramación al instalador, valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$installerWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\", \"$campo3\", \"$campo4\", \"$campo5\"],\n \"template_uuid\": \"e1aa2b0fd3884595918f4ac2676acd29\",\n \"optin_contact\": true\n }";
+ } else if (!$reprogramming && !$changeInstaller) {
+
+ //combinar el campo3, campo4, campo5, campo6, campo7 y campo8 en un solo campo con saltos de línea
+ $jobId = sprintf("#️⃣ *%s*", $jobInstallerNotificationData['jobId']);
+ $clientFullName = sprintf("👤 *%s*", $jobInstallerNotificationData['clientFullName']);
+ $date = sprintf("🗓️ %s", $jobInstallerNotificationData['date']);
+ $installerName = sprintf("👷🏻♂️ *%s*", $jobInstallerNotificationData['installerName']);
+
+ $campo1_combinado = "$installerName se te ha asignado una tarea con folio $jobId, del cliente $clientFullName, para el $date";
+ $campo2 = $jobInstallerNotificationData['clientWhatsApp'];
+ $campo3 = $jobInstallerNotificationData['gmapsLocation'];
+ $campo4 = $jobInstallerNotificationData['passwordAntenaCliente'];
+
+ $log->appendLog("Enviando notificación normal de tarea al instalador, valor de reprogramming $reprogramming y valor de changeInstaller $changeInstaller " . PHP_EOL);
+ $curl_string = "{\n \"to\": \"$installerWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1_combinado\", \"$campo2\", \"$campo3\", \"$campo4\"],\n \"template_uuid\": \"88eeb6420a214fd8870dd28d741021c4\",\n \"optin_contact\": true\n }";
+ }
+
+ $log->appendLog("La cadena CURL que se envia es: " . $curl_string);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $curl_string);
+
+ $response = curl_exec($ch);
+ $log->appendLog("Response del CallBell: " . $response);
+
+ curl_close($ch);
+
+
+
+
+ // Validar la respuesta de Callbell
+ $jsonResponse = json_decode($response, true);
+
+ if (json_last_error() === JSON_ERROR_NONE) {
+ // Evaluar si contiene "message" con "status": "enqueued"
+ if (isset($jsonResponse['message']) && $jsonResponse['message']['status'] === 'enqueued') {
+ $log->appendLog("La notificación fue enviada correctamente con estado: enqueued" . PHP_EOL);
+ return true;
+ }
+
+ // Evaluar si contiene "error"
+ if (isset($jsonResponse['error'])) {
+ $log->appendLog("Error al enviar la notificación: " . json_encode($jsonResponse['error']) . PHP_EOL);
+ return false;
+ }
+ } else {
+ // Manejo de error en caso de que la respuesta no sea un JSON válido
+ $log->appendLog("La respuesta no es un JSON válido." . PHP_EOL);
+ return false;
+ }
+
+ // Valor de retorno predeterminado en caso de que ninguna condición se cumpla
+ $log->appendLog("Ruta no prevista en la función." . PHP_EOL);
+ return false;
+ }
+
+ public function sendPaymentNotificationWhatsApp($clientWhatsAppNumber, $notificationData): bool
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+
+ $log->appendLog("Eviando comprobante de pago al cliente: " . $notificationData->clientData['id'] . ' con número: ' . $clientWhatsAppNumber . PHP_EOL);
+
+ // URL base de la API
+ $baseUri = 'https://' . $this->IPServer . '/crm/api/v1.0/';
+ // Token de autenticación
+ $token = $this->UCRMAPIToken;
+ //Path base del comprobante de pago
+ $pdf_payment_path = '';
+
+ $this->ucrmApi = UcrmApi::create();
+ $payments = $this->ucrmApi->get(
+ 'payments/',
+ [
+ 'clientId' => $notificationData->clientData['id'],
+ 'limit' => 1,
+ 'direction' => 'DESC',
+
+ ]
+ );
+
+ $payment_id = $payments[0]['id'];
+ $payment_amount = '$' . $payments[0]['amount'];
+ //$saldo = '$' . $notificationData->clientData['accountBalance'];
+ $nombre_cliente = sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']);
+
+ $accountBalance = $notificationData->clientData['accountBalance'];
+ $saldoTexto = '';
+
+ if ($accountBalance < 0) {
+ // Si el saldo es negativo, quitar el signo y poner "Pendientes"
+ $saldoTexto = '$' . abs($accountBalance) . ' pendientes';
+ } elseif ($accountBalance > 0) {
+ // Si el saldo es positivo, poner "a favor"
+ $saldoTexto = '$' . $accountBalance . ' a favor';
+ } else {
+ // Si el saldo es 0, poner "está al corriente"
+ $saldoTexto = '$' . $accountBalance . ' está al corriente';
+ }
+
+ // Configuración del cliente GuzzleHttp
+ $clientGuzzleHttp = new Client([
+ 'base_uri' => $baseUri,
+ 'headers' => [
+ 'X-Auth-App-Key' => $token, // Cambia el nombre de la cabecera de autorización
+ 'Accept' => 'application/pdf', // Indica que esperamos una respuesta en formato JSON
+ ],
+ 'verify' => false,
+ ]);
+
+ try {
+ // Hacer la solicitud GET para obtener el PDF
+ $response = $clientGuzzleHttp->request('GET', "payments/$payment_id/pdf");
+
+ // Leer el contenido del PDF de la respuesta
+ $contenidoArchivo = $response->getBody()->getContents();
+
+ // Construir el nombre del archivo PDF basado en el cliente
+ $fileNameComprobante = 'Comprobante_' . str_replace(' ', '_', $nombre_cliente) . '.pdf';
+ $rutaArchivo = __DIR__ . '/../../comprobantes/' . $fileNameComprobante;
+
+ // Guardar el contenido del PDF en un archivo local
+ if (file_put_contents($rutaArchivo, $contenidoArchivo) !== false) {
+ $log->appendLog("El archivo PDF se ha descargado y guardado correctamente en: $rutaArchivo" . PHP_EOL);
+ } else {
+ $log->appendLog("Error al guardar el archivo PDF en la ruta: $rutaArchivo" . PHP_EOL);
+ return false;
+ }
+
+ if (!file_exists($rutaArchivo)) {
+ $log->appendLog("El archivo PDF no existe: $rutaArchivo" . PHP_EOL);
+ return false;
+ }
+
+ if (filesize($rutaArchivo) === 0) {
+ $log->appendLog("El archivo PDF está vacío: $rutaArchivo" . PHP_EOL);
+ return false;
+ }
+
+ $log->appendLog("El archivo PDF es válido y tiene contenido: $rutaArchivo" . PHP_EOL);
+ $rutaImagen = __DIR__ . '/../../comprobantes/' . str_replace('.pdf', '.png', $fileNameComprobante);
+ } catch (\Exception $e) {
+ $log->appendLog("Error al manejar el comprobante de pago: " . $e->getMessage() . PHP_EOL);
+ return false;
+ }
+
+ try {
+ $image = new Imagick();
+ $image->setResolution(300, 300);
+ $image->readImage($rutaArchivo); // Aquí podría ocurrir un error
+ $image->setImageFormat('png');
+ $rutaImagen = str_replace('.pdf', '.png', $rutaArchivo);
+ $image->writeImage($rutaImagen);
+ $image->destroy();
+
+ $log->appendLog("El archivo PNG se ha generado correctamente en: $rutaImagen" . PHP_EOL);
+ } catch (ImagickException $e) {
+ $log->appendLog("Error al convertir el PDF a PNG con Imagick: " . $e->getMessage() . PHP_EOL);
+ return false;
+ }
+
+ $fileNameComprobanteImage = str_replace('.pdf', '.png', $fileNameComprobante);
+ $url_file = $this->UploadReceiptToWordpressByImageFileName($fileNameComprobanteImage); //Carga del comprobante PDF a Wordpress para su posterior envío
+ // $url_file = $this->UploadReceiptToWordpressByImageFileName($fileNameComprobante);//Carga del comprobante PDF a Wordpress para su posterior envío
+
+ $log->appendLog("Se terminó de subir comprobante a wordpress " . PHP_EOL);
+
+ //$log->appendLog("Entrando al metodo sendPaymentNotificationWhatsAp" . PHP_EOL);
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, 'https://api.callbell.eu/v1/messages/send');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"document\",\n \"content\": {\n \"text\": \"S/M\",\n \"url\": \"$url_file\"\n },\n \"template_values\": [\"$nombre_cliente\", \"$payment_amount\", \"$saldoTexto\"],\n \"template_uuid\": \"57ead79cebd14902921477922403093b\",\n \"optin_contact\": true\n }";
+ $log->appendLog("La cadena CURL que se envia es: " . $curl_string);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $curl_string);
+
+ $response = curl_exec($ch);
+ $log->appendLog("Response del CallBell: " . $response);
+
+ //Enviar notificación adicional si es transferencia
+ // if($transferNotify){
+ // curl_setopt($ch, CURLOPT_POSTFIELDS, "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"John Doe\"\n },\n \"template_uuid\": \"41783c020cd84881bc27cb9e7e1da348\",\n \"optin_contact\": true\n }");
+ // $response2 = curl_exec($ch);
+ // $log->appendLog("Response del CallBell aviso adicional: " . $response2);
+ // }
+
+ curl_close($ch);
+ $this->deleteFilesExceptLastHundred();
+ //return $fileNameComprobante;
+
+ // Validar la respuesta de Callbell
+ $jsonResponse = json_decode($response, true);
+
+ if (json_last_error() === JSON_ERROR_NONE) {
+ // Evaluar si contiene "message" con "status": "enqueued"
+ if (isset($jsonResponse['message']) && $jsonResponse['message']['status'] === 'enqueued') {
+ $log->appendLog("La notificación fue enviada correctamente con estado: enqueued" . PHP_EOL);
+ return true;
+ }
+
+ // Evaluar si contiene "error"
+ if (isset($jsonResponse['error'])) {
+ $log->appendLog("Error al enviar la notificación: " . json_encode($jsonResponse['error']) . PHP_EOL);
+ return false;
+ }
+ } else {
+ // Manejo de error en caso de que la respuesta no sea un JSON válido
+ $log->appendLog("La respuesta no es un JSON válido." . PHP_EOL);
+ return false;
+ }
+
+ // Valor de retorno predeterminado en caso de que ninguna condición se cumpla
+ $log->appendLog("Ruta no prevista en la función." . PHP_EOL);
+ return false;
+ }
+ public function sendTextPaymentNotificationWhatsApp($clientWhatsAppNumber, $notificationData): bool
+ {
+
+ $nombre_cliente = sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']);
+ $folio = $notificationData->paymentData['id'];
+ $client_id = $notificationData->clientData['id'];
+ $fecha_pago = '';
+ $cantidad_pagada = $notificationData->paymentData['amount'];
+ $metodo_pago = '';
+ //$invoice_id= null;
+ $total_factura = null;
+ $pago_factura = $notificationData->paymentData['amount'];
+ // $saldoTexto= null;
+ $creditoPorPago = $notificationData->paymentData['creditAmount'];
+ $texto_credito = null;
+ $creditoClienteBase = $notificationData->clientData['accountCredit'];
+
+ switch ($notificationData->paymentData['methodId']) {
+ case '11721cdf-a498-48be-903e-daa67552e4f6':
+ $metodo_pago = 'Cheque 📄';
+ break;
+ case '6efe0fa8-36b2-4dd1-b049-427bffc7d369':
+ $metodo_pago = 'Efectivo 💵';
+ break;
+ case '4145b5f5-3bbc-45e3-8fc5-9cda970c62fb':
+ $metodo_pago = 'Transferencia bancaria 📱🏦';
+ break;
+ case '78e84000-9b5b-44a4-8367-da43df86ce34':
+ $metodo_pago = 'PayPal 🌐💳';
+ break;
+ case '6da98bb9-6df7-4c41-8608-5cdd7fde7d5d':
+ $metodo_pago = 'Tarjeta de crédito PayPal 💳';
+ break;
+ case '1dd098fa-5d63-4c8d-88b7-3c27ffbbb6ae':
+ $metodo_pago = 'Tarjeta de crédito Stripe 💳';
+ break;
+ case 'b9e1e9d1-5c7b-41d2-b6b2-3e568d700290':
+ $metodo_pago = 'Suscripción de Stripe (tarjeta de crédito) 🌐💳';
+ break;
+ case '939f7701-00b7-4676-9b1e-17afb268c8ba':
+ $metodo_pago = 'Suscripción de PayPal 🌐💳';
+ break;
+ case '1c963e35-df24-444d-95d2-12592d5107e8':
+ $metodo_pago = 'MercadoPago 🌐💳';
+ break;
+ case 'd8c1eae9-d41d-479f-aeaf-38497975d7b3':
+ $metodo_pago = 'Personalizado 📝💸';
+ break;
+ default:
+ $metodo_pago = 'Desconocido, revisar metodos de pago no contemplados';
+ break;
+ }
+
+ $log = PluginLogManager::create(); //Initialize Logger
+
+ $log->appendLog("Eviando comprobante de pago al cliente: " . $notificationData->clientData['id'] . ' con número: ' . $clientWhatsAppNumber . PHP_EOL);
+
+ // URL base de la API
+ $baseUri = 'https://' . $this->IPServer . '/crm/api/v1.0/';
+ // Token de autenticación
+ $token = $this->UCRMAPIToken;
+ //Path base del comprobante de pago
+ $pdf_payment_path = '';
+
+ $this->ucrmApi = UcrmApi::create();
+ $payments = $this->ucrmApi->get(
+ 'payments/',
+ [
+ 'clientId' => $notificationData->clientData['id'],
+ 'limit' => 1,
+ 'direction' => 'DESC',
+
+ ]
+ );
+
+ //$datos_payment_array = json_decode($response->getBody()->getContents(), true);
+ $datos_paymentJsonText = json_encode($payments, true);
+ $log->appendLog("Datos traidos con payment api: " . $datos_paymentJsonText . PHP_EOL);
+
+ // $log->appendLog("Check 1" . PHP_EOL);
+ $paymentDate = new DateTime($fecha_pago);
+
+ // Restar 6 horas
+ $paymentDate->modify('-6 hours');
+
+ // Formatear la fecha como "d/m/Y g:ia" (día/mes/año hora:minutos am/pm)
+ $fecha_pago = $paymentDate->format('d/m/Y g:ia');
+
+ $accountBalance = $notificationData->clientData['accountBalance'];
+ $saldoTexto = '';
+
+ if ($accountBalance < 0) {
+ // Si el saldo es negativo, quitar el signo y poner "Pendientes"
+ $saldoTexto = '$' . abs($accountBalance) . ' pendientes';
+ } elseif ($accountBalance > 0) {
+ // Si el saldo es positivo, poner "a favor"
+ $saldoTexto = '$' . $accountBalance . ' a favor';
+ } else {
+ // Si el saldo es 0, poner "está al corriente"
+ $saldoTexto = '$' . $accountBalance . ' está al corriente';
+ }
+
+ $log->appendLog("Datos client data credit amount: " . $notificationData->paymentData['creditAmount'] . PHP_EOL);
+
+ $cantidad_pagadaFormateada = '$' . number_format($cantidad_pagada, 2, ',', '.') . ' MXN';
+ $creditoPorPagoFormateado = '$' . number_format($creditoPorPago, 2, ',', '.') . ' MXN';
+
+ if ($creditoClienteBase > 0 && empty($notificationData->paymentData['paymentCovers'])) {
+
+ $texto_credito = "La cantidad que sobra de $creditoPorPagoFormateado se ha convertido a crédito";
+ $log->appendLog("La cantidad que sobra de $creditoPorPagoFormateado se ha convertido a crédito" . PHP_EOL);
+
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"John Doe\"\n },\n \"template_values\": [\"$nombre_cliente\", \"$folio\", \"$client_id\", \"$fecha_pago\", \"$cantidad_pagadaFormateada\", \"$metodo_pago\", \"$saldoTexto\", \"$texto_credito\"],\n \"template_uuid\": \"4ac9dc060cf746b6ad7f2e8acad355e0\",\n \"optin_contact\": true\n }";
+ } else {
+
+ if ($creditoPorPago > 0) {
+ $texto_credito = "La cantidad que sobra de $creditoPorPagoFormateado se ha convertido a crédito";
+ $log->appendLog("La cantidad que sobra de $creditoPorPagoFormateado se ha convertido a crédito" . PHP_EOL);
+ } else {
+ $texto_credito = '_________________________';
+ }
+
+ // Configuración del cliente GuzzleHttp
+ $clientGuzzleHttp = new Client([
+ 'base_uri' => $baseUri,
+ 'headers' => [
+ 'X-Auth-App-Key' => $token, // Cambia el nombre de la cabecera de autorización
+ 'Accept' => 'application/pdf', // Indica que esperamos una respuesta en formato JSON
+ ],
+ 'verify' => false,
+ ]);
+
+ $log->appendLog("Verificar paymentCovers " . PHP_EOL);
+
+ $log->appendLog("payment covers" . json_encode($notificationData->paymentData['paymentCovers']) . PHP_EOL);
+
+ if (!empty($notificationData->paymentData['paymentCovers'])) {
+ $log->appendLog('Datos del payment covers:' . PHP_EOL);
+
+ $invoiceIds = ''; // Variable para almacenar los invoiceId
+ $amounts = ''; // Variable para almacenar los amounts formateados
+
+ foreach ($notificationData->paymentData['paymentCovers'] as $paymentCover) {
+ $log->appendLog('Invoice ID pagado: ' . $paymentCover['invoiceId'] . ' de esta cantidad: ' . $paymentCover['amount'] . PHP_EOL);
+
+ // Concatenar cada invoiceId seguido de una coma
+ $invoiceIds .= $paymentCover['invoiceId'] . ', ';
+
+ // Formatear el amount con punto para miles y coma para decimales
+ $formattedAmount = number_format($paymentCover['amount'], 2, ',', '.');
+
+ // Concatenar el amount formateado seguido de una coma
+ $amounts .= $formattedAmount . ', ';
+ }
+
+ // Eliminar la última coma y el espacio extra usando substr
+ $invoiceIds = substr($invoiceIds, 0, -2); // Elimina los últimos dos caracteres (coma y espacio)
+ $amounts = substr($amounts, 0, -2); // Elimina los últimos dos caracteres (coma y espacio)
+
+ // Mostrar las cadenas finales
+ $log->appendLog('Todos los Invoice IDs: ' . $invoiceIds . PHP_EOL);
+ $log->appendLog('Todas las cantidades: ' . $amounts . PHP_EOL);
+
+ try {
+
+ // Hacer la solicitud GET
+ $response = $clientGuzzleHttp->request('GET', "invoices/$invoiceIds");
+
+ // Realizar la solicitud a la API y guardar el contenido en un archivo local
+ $responseInvoices = $response->getBody()->getContents();
+ $responseInvoicesJSON = json_decode($responseInvoices, true);
+ $log->appendLog('Numero de factura: ' . $responseInvoicesJSON['number'] . PHP_EOL);
+ $log->appendLog('TOTAL de factura: ' . $responseInvoicesJSON['total'] . PHP_EOL);
+ $total_factura = $responseInvoicesJSON['total'];
+ } catch (\Exception $e) {
+ $log->appendLog("Error con un problema al obtener alguna factura del cliente: " . $e->getMessage() . PHP_EOL);
+ return false;
+ }
+ } else {
+ $log->appendLog("no hay datos en payment covers" . PHP_EOL);
+ $invoiceIds = $notificationData->paymentData['id'];
+ $amounts = $notificationData->paymentData['amount'];
+ $total_factura = 0;
+ }
+ //$cantidad_pagadaFormateada = '$' . number_format($cantidad_pagada, 2, ',', '.') . ' MXN';
+ $log->appendLog("Se terminó de verificar payment covers" . PHP_EOL);
+ $total_facturaFormateada = '$' . number_format($total_factura, 2, ',', '.') . ' MXN';
+ $pagoFacturaFormateado = '$' . $amounts . ' MXN';
+
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"John Doe\"\n },\n \"template_values\": [\"$nombre_cliente\", \"$folio\", \"$client_id\", \"$fecha_pago\", \"$cantidad_pagadaFormateada\", \"$metodo_pago\", \"$invoiceIds\", \"$total_facturaFormateada\", \"$pagoFacturaFormateado\", \"$saldoTexto\", \"$texto_credito\"],\n \"template_uuid\": \"c1396a6ad3cb4192916d4ac2bfb782a5\",\n \"optin_contact\": true\n }";
+ }
+
+ //$log->appendLog("Entrando al metodo sendPaymentNotificationWhatsAp" . PHP_EOL);
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, 'https://api.callbell.eu/v1/messages/send');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+
+ //$curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"document\",\n \"content\": {\n \"text\": \"S/M\",\n \"url\": \"$url_file\"\n },\n \"template_values\": [\"$nombre_cliente\", \"$payment_amount\", \"$saldo\"],\n \"template_uuid\": \"6c0df98317b44f7b8666375a6cc8454c\",\n \"optin_contact\": true\n }";
+
+ // $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\"],\n \"template_uuid\": \"55705f1fe4e24bab80104dc2643fe11c\",\n \"optin_contact\": true\n }";
+ $log->appendLog("La cadena CURL que se envia es: " . $curl_string);
+ //curl_setopt($ch, CURLOPT_POSTFIELDS, $curl_string);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $curl_string);
+ $response = curl_exec($ch);
+ $log->appendLog("Response del CallBell: " . $response);
+
+ //Enviar notificación adicional si es transferencia
+ // if($transferNotify){
+ // curl_setopt($ch, CURLOPT_POSTFIELDS, "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"John Doe\"\n },\n \"template_uuid\": \"41783c020cd84881bc27cb9e7e1da348\",\n \"optin_contact\": true\n }");
+ // $response2 = curl_exec($ch);
+ // $log->appendLog("Response del CallBell aviso adicional: " . $response2);
+ // }
+
+ curl_close($ch);
+ //$this->deleteFilesExceptLastFifty();
+ //return $fileNameComprobante;
+ // Validar la respuesta de Callbell
+ $jsonResponse = json_decode($response, true);
+
+ if (json_last_error() === JSON_ERROR_NONE) {
+ // Evaluar si contiene "message" con "status": "enqueued"
+ if (isset($jsonResponse['message']) && $jsonResponse['message']['status'] === 'enqueued') {
+ $log->appendLog("La notificación fue enviada correctamente con estado: enqueued" . PHP_EOL);
+ return true;
+ }
+
+ // Evaluar si contiene "error"
+ if (isset($jsonResponse['error'])) {
+ $log->appendLog("Error al enviar la notificación: " . json_encode($jsonResponse['error']) . PHP_EOL);
+ return false;
+ }
+ } else {
+ // Manejo de error en caso de que la respuesta no sea un JSON válido
+ $log->appendLog("La respuesta no es un JSON válido." . PHP_EOL);
+ return false;
+ }
+
+ // Valor de retorno predeterminado en caso de que ninguna condición se cumpla
+ $log->appendLog("Ruta no prevista en la función." . PHP_EOL);
+ return false;
+ }
+
+ public function sendOverdueNotificationWhatsApp($clientWhatsAppNumber, $notificationData): void
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+
+ // URL base de la API
+ //$baseUri = 'https://' . $this->IPServer . '/crm/api/v1.0/';
+ // Token de autenticación
+ //$token = $this->UCRMAPIToken;
+ //Path base del comprobante de pago
+ //$pdf_payment_path = '';
+
+ // $this->ucrmApi = UcrmApi::create();
+ // $invoices = $this->ucrmApi->get(
+ // 'invoices/',
+ // [
+ // 'clientId' => $notificationData->clientData['id'],
+ // 'limit' => 1,
+ // 'direction' => 'DESC'
+
+ // ]
+ // );
+
+ //$datos_payment_array = json_decode($payments,true);
+ //$datos_invoices = json_encode($invoices);
+
+ //$log->appendLog("Datos traidos con invoices api: " . $datos_invoices . PHP_EOL);
+ //$log->appendLog("Esto es lo que trae la fecha mas reciente de los pagos: " . $notificationData->paymentData[0]['createdDate']. PHP_EOL);
+ // $log->appendLog("Esto es lo que trae la fecha mas reciente de los pagos opcion 2: " . $payments[0]['createdDate'] . PHP_EOL);
+
+ // $invoice_id = $invoices[0]['id'];
+ // $invoices_amount = '$' . $invoices[0]['amount'];
+ $saldo = '$' . $notificationData->clientData['accountBalance'];
+ $nombre_cliente = sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']);
+
+ // Configuración del cliente GuzzleHttp
+ // $clientGuzzleHttp = new Client([
+ // 'base_uri' => $baseUri,
+ // 'headers' => [
+ // 'X-Auth-App-Key' => $token, // Cambia el nombre de la cabecera de autorización
+ // 'Accept' => 'application/pdf', // Indica que esperamos una respuesta en formato JSON
+ // ],
+ // 'verify' => false,
+ // ]);
+
+ // if (empty($notificationData->clientData['contacts'][0]['email'])) {
+ // $log->appendLog("El cliente no tiene correo" . PHP_EOL);
+ // } else {
+ // // $log->appendLog("El cliente SI tiene correo y es: ".$notificationData->clientData['contacts'][0]['email'] . PHP_EOL);
+ // // Hacer la solicitud PATCH para enviar correo electronico con el comprobante de pago
+ // $response = $clientGuzzleHttp->request('PATCH', "invoices/$invoice_id/send");
+
+ // }
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, 'https://api.callbell.eu/v1/messages/send');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+
+ // Verificar si la ruta es válida
+ // if ($realPath = realpath('/data/ucrm/data/plugins/siip-whatsapp-notifications/src/Facade/Comprobante.pdf')) {
+ // $log->appendLog("La ruta es válida: $realPath" . PHP_EOL);
+ // $log->appendLog(var_export($realPath,true) . PHP_EOL);
+
+ // } else {
+ // $log->appendLog("La ruta no es válida o no existe" . PHP_EOL);
+ // }
+
+ $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"SIIP INTERNET\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\",\n },\n \"template_values\": [\"$nombre_cliente\", \"$saldo\"],\n \"template_uuid\": \"9e7024c0a61a4c49b382150d26888dc2\",\n \"optin_contact\": true\n }";
+ //$curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"document\",\n \"content\": {\n \"text\": \"S/M\",\n \"url\": \"$url_file\"\n },\n \"template_values\": [\"$nombre_cliente\", \"$payment_amount\", \"$saldo\"],\n \"template_uuid\": \"57ead79cebd14902921477922403093b\",\n \"optin_contact\": true\n }";
+ //$curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"document\",\n \"content\": {\n \"text\": \"S/M\",\n \"url\": \"$url_file\"\n },\n \"template_values\": [\"$nombre_cliente\", \"$payment_amount\", \"$saldo\"],\n \"template_uuid\": \"6c0df98317b44f7b8666375a6cc8454c\",\n \"optin_contact\": true\n }";
+
+ // $curl_string = "{\n \"to\": \"$clientWhatsAppNumber\",\n \"from\": \"whatsapp\",\n \"type\": \"text\",\n \"content\": {\n \"text\": \"S/M\"\n },\n \"template_values\": [\"$campo1\", \"$campo2\"],\n \"template_uuid\": \"55705f1fe4e24bab80104dc2643fe11c\",\n \"optin_contact\": true\n }";
+ $log->appendLog("La cadena CURL que se envia es: " . $curl_string);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $curl_string);
+
+ $response = curl_exec($ch);
+ $log->appendLog("Response del CallBell: " . $response);
+
+ curl_close($ch);
+ }
+
+ public function getContactWhatsapp($cellphone_number): string
+ {
+ // URL de la API REST
+ $apiUrl = 'https://api.callbell.eu/v1/contacts/phone/' . $cellphone_number;
+
+ // Inicializar cURL
+ $ch = curl_init();
+
+ // Configurar las opciones de cURL
+ curl_setopt($ch, CURLOPT_URL, $apiUrl);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+
+ // Ejecutar la solicitud y obtener la respuesta
+ $response = curl_exec($ch);
+
+ // Verificar si hay errores en la solicitud cURL
+ if (curl_errno($ch)) {
+ return 'Error al realizar la solicitud cURL: ' . curl_error($ch);
+ } else {
+ // Cerrar la sesión cURL
+ curl_close($ch);
+ return $response;
+ }
+ }
+
+ public function patchWhatsapp($response_getContactCallBell, $notificationData, $clabeInterbancaria = null)
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+ //imprimir notificacionData
+ $log->appendLog("Notificacion data: " . json_encode($notificationData) . PHP_EOL);
+ //ejemplo de $notificationData: {"uuid":"cad4fa25-176e-4823-9f4c-1421d05d2a31","changeType":"edit","entity":"client","entityId":2,"message":null,"clientId":2,"eventName":"client.edit","clientData":{"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"31 Chiapas","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Centro, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente espacial, el m\u00e1s chido","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas Pollerias2","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":"Personal","isBilling":false,"isContact":false,"types":[{"id":1000,"name":"WhatsApp"}]},{"id":170,"clientId":2,"email":null,"phone":"5214181817609","name":"Bussiness","isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false}],"accountBalance":1553.33,"accountCredit":1553.33,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[{"id":2,"name":"NS EXENTO","colorBackground":"#42a3df","colorText":"#fff"}],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564209,"addressGpsLon":-100.9384185,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"serviceData":null,"invoiceData":null,"paymentData":null}
+
+ //buscar el attribute con el key site y antenaSectorial
+ $attributes = $notificationData->clientData['attributes']; //Obtener los atributos del cliente
+ $site = '';
+ $antenaSectorial = '';
+
+ // Iterar sobre los atributos
+ foreach ($attributes as $attribute) {
+ // Verificar si el key es "site"
+ if ($attribute['key'] === 'site') {
+ $site = $attribute['value'];
+ }
+ // Verificar si el key es "antenaSectorial"
+ if ($attribute['key'] === 'antenaSectorial') {
+ $antenaSectorial = $attribute['value'];
+ }
+ }
+
+ $log->appendLog("Dentro del proceso del patch: " . PHP_EOL);
+ $this->ucrmApi = UcrmApi::create();
+ $payments = $this->ucrmApi->get(
+ 'payments/',
+ [
+ 'clientId' => $notificationData->clientData['id'],
+ 'limit' => 1,
+ 'direction' => 'DESC',
+
+ ]
+ );
+
+ //$datos_payment_array = json_decode($payments,true);
+ $datos_payment = json_encode($payments);
+
+ $log->appendLog("Datos traidos con payment api: " . $datos_payment . PHP_EOL);
+ //$log->appendLog("Esto es lo que trae la fecha mas reciente de los pagos: " . $notificationData->paymentData[0]['createdDate']. PHP_EOL);
+ // $log->appendLog("Esto es lo que trae la fecha mas reciente de los pagos opcion 2: " . $payments[0]['createdDate'] . PHP_EOL);
+
+ $uuid = $response_getContactCallBell['contact']['uuid'];
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+
+ $ch2 = curl_init();
+ curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch2, CURLOPT_CUSTOMREQUEST, 'PATCH');
+ curl_setopt($ch2, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+ $UrlChatCallBell = 'https://api.callbell.eu/v1/contacts/' . $uuid;
+ curl_setopt($ch, CURLOPT_URL, $UrlChatCallBell);
+ curl_setopt($ch2, CURLOPT_URL, $UrlChatCallBell);
+ $nombre_cliente = sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']);
+ $log->appendLog("Nombre del cliente que se va a actualizar: " . $nombre_cliente . PHP_EOL);
+ $log->appendLog("UUID: " . $uuid . PHP_EOL);
+
+ $payment_method_id = $payments[0]['methodId'];
+ $payment_method = '';
+
+ switch ($payment_method_id) {
+ case '11721cdf-a498-48be-903e-daa67552e4f6':
+ $payment_method = 'Cheque 📄';
+ break;
+ case '6efe0fa8-36b2-4dd1-b049-427bffc7d369':
+ $payment_method = 'Efectivo 💵';
+ break;
+ case '4145b5f5-3bbc-45e3-8fc5-9cda970c62fb':
+ $payment_method = 'Transferencia bancaria 📱🏦';
+ break;
+ case '78e84000-9b5b-44a4-8367-da43df86ce34':
+ $payment_method = 'PayPal 🌐💳';
+ break;
+ case '6da98bb9-6df7-4c41-8608-5cdd7fde7d5d':
+ $payment_method = 'Tarjeta de crédito PayPal 💳';
+ break;
+ case '1dd098fa-5d63-4c8d-88b7-3c27ffbbb6ae':
+ $payment_method = 'Tarjeta de crédito Stripe 💳';
+ break;
+ case 'b9e1e9d1-5c7b-41d2-b6b2-3e568d700290':
+ $payment_method = 'Suscripción de Stripe (tarjeta de crédito) 🌐💳';
+ break;
+ case '939f7701-00b7-4676-9b1e-17afb268c8ba':
+ $payment_method = 'Suscripción de PayPal 🌐💳';
+ break;
+ case '1c963e35-df24-444d-95d2-12592d5107e8':
+ $payment_method = 'MercadoPago 🌐💳';
+ break;
+ case 'd8c1eae9-d41d-479f-aeaf-38497975d7b3':
+ $payment_method = 'Personalizado 📝💸';
+ break;
+ default:
+ $payment_method = 'Desconocido, revisar metodos de pago no contemplados';
+ break;
+ }
+
+ $fecha_actual = new DateTime();
+ $fecha_actual->modify('-6 hours');
+ $fecha_actual_ajustada = $fecha_actual->format("d/m/Y H:i");
+
+ $fecha_ultimoPago = new DateTime($payments[0]['createdDate']);
+ //$fecha_ultimoPago = $fecha_ultimoPago->modify('-6 hours');
+ $fecha_ultimoPago_ajustada = $fecha_ultimoPago->format("d/m/Y H:i");
+
+ //$log->appendLog("las dos fechas ajustadas : " . $fecha_actual_ajustada.' aqui la otra: '.$fecha_ultimoPago_ajustada. PHP_EOL);
+
+ // $attributes = $notificationData->clientData['attributes']; //Obtener los atributos del cliente
+
+ // // Variable para almacenar los valores de los atributos que comienzan con "clabe"
+ // $clabeInterbancaria = '';
+
+ // // Iterar sobre los atributoss
+ // foreach ($attributes as $attribute) {
+ // // Verificar si la "key" comienza con "clabe"
+ // if (strpos($attribute['key'], 'clabe') === 0) {
+ // // Agregar el valor al array $clabeValues
+ // $clabeInterbancaria = $attribute['value'];
+ // }
+ // }
+
+ $accountBalance = $notificationData->clientData['accountBalance'];
+ $saldoTexto = '';
+
+ if ($accountBalance < 0) {
+ // Si el saldo es negativo, quitar el signo y poner "Pendientes"
+ $saldoTexto = '💲' . abs($accountBalance) . ' pendientes';
+ } elseif ($accountBalance > 0) {
+ // Si el saldo es positivo, poner "a favor"
+ $saldoTexto = '💲' . $accountBalance . ' a favor';
+ } else {
+ // Si el saldo es 0, poner "está al corriente"
+ $saldoTexto = '💲' . $accountBalance . ' está al corriente';
+ }
+
+ $resumenClienteJSON = '{' .
+ '"Cliente": "' . $notificationData->clientData['id'] . '",' .
+ '"Domicilio": "' .
+ //(($notificationData->clientData['fullAddress'] == null) ? 'Sin domicilio' : '' . $notificationData->clientData['fullAddress']) . '",' .
+ '"Nombre": "' . sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']) . '",' .
+ '"URL": "https://sistema.siip.mx/crm/client/' . $notificationData->clientId . '",' .
+ '"Saldo Actual": "' . $saldoTexto . '",' .
+ '"Monto Ultimo Pago": "$ ' . $payments[0]['amount'] . '",' .
+ '"Estado": "' .
+ (($notificationData->clientData['hasSuspendedService']) ? 'Suspendido' : 'Activo') . '",' .
+ '"Fecha Ultimo Pago": " ' . $fecha_ultimoPago_ajustada . ' con ' . $payment_method . '",' .
+ '"Fecha Ultima Actualizacion": "' . $fecha_actual_ajustada . '",' .
+ '"Clabe Interbancaria": "' . $clabeInterbancaria . '",' .
+ '"Site": "' . $site . '",' .
+ '"Antena/Sectorial": "' . $antenaSectorial . '"' .
+ '}';
+
+ $data_CRM = [
+ //"uuid" => $json_responseAPI->contact->uuid,
+ "name" => sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']),
+
+ "custom_fields" => [
+ "Cliente" => $notificationData->clientData['id'],
+ "Domicilio" => ($notificationData->clientData['fullAddress'] == null) ? '📍❌ Sin domicilio' : '📍 ' . $notificationData->clientData['fullAddress'],
+ "Nombre" => sprintf("👤 %s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']),
+ "URL" => '🌐 https://sistema.siip.mx/crm/client/' . $notificationData->clientId,
+ "Saldo Actual" => $saldoTexto,
+ "Monto Ultimo Pago" => '💲 ' . $payments[0]['amount'],
+ "Estado" => ($notificationData->clientData['hasSuspendedService']) ? '🔴 Suspendido' : '🟢 Activo ',
+ "Resumen" => $resumenClienteJSON,
+ "Fecha Ultimo Pago" => '📆💸 ' . $fecha_ultimoPago_ajustada . ' con ' . $payment_method,
+ "Fecha Ultima Actualizacion" => '📆🔄️ ' . $fecha_actual_ajustada,
+ "Clabe Interbancaria" => $clabeInterbancaria,
+ "Site" => $site,
+ "Antena/Sectorial" => $antenaSectorial,
+ ],
+ ];
+
+ $log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL);
+
+ $data_CRM2 = [
+ "custom_fields" => [
+ "Resumen" => $resumenClienteJSON,
+ ],
+ ];
+
+ $log->appendLog("JSON con los datos a actualizar del resumen: " . $resumenClienteJSON . PHP_EOL);
+
+ if (
+ $response_getContactCallBell['custom_fields']['Cliente'] != $data_CRM['custom_fields']['Cliente']
+ || $response_getContactCallBell['custom_fields']['Domicilio'] != $data_CRM['custom_fields']['Domicilio']
+ || $response_getContactCallBell['custom_fields']['Nombre'] != $data_CRM['custom_fields']['Nombre']
+ || $response_getContactCallBell['custom_fields']['URL'] != $data_CRM['custom_fields']['URL']
+ || $response_getContactCallBell['custom_fields']['Saldo'] != $data_CRM['custom_fields']['Saldo']
+ || $response_getContactCallBell['custom_fields']['Estado'] != $data_CRM['custom_fields']['Estado']
+ || $response_getContactCallBell['custom_fields']['Fecha Ultimo Pago'] != $data_CRM['custom_fields']['Fecha Ultimo Pago']
+ || $response_getContactCallBell['custom_fields']['Monto Ultimo Pago'] != $data_CRM['custom_fields']['Monto Ultimo Pago']
+ || $response_getContactCallBell['name'] != $data_CRM['name']
+
+ ) {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data_CRM));
+ curl_setopt($ch2, CURLOPT_POSTFIELDS, json_encode($data_CRM2));
+ $response = curl_exec($ch);
+ $log->appendLog("Response Patch CallBell: " . $response . PHP_EOL);
+ $response2 = curl_exec($ch2);
+ $log->appendLog("Response 2 Patch CallBell: " . $response2 . PHP_EOL);
+ curl_close($ch);
+ curl_close($ch2);
+
+ // if($fileNameComprobante != null){
+ // sleep(3);
+ // $this->deleteFileWordPressAndLocal($fileNameComprobante);
+ // }
+
+ // $json_data_patch = '{
+ // "attributes": [
+ // {
+ // "value": "' . $UrlChatCallBell . '",
+ // "customAttributeId": 21
+ // }
+ // ]
+
+ // }'; //JSON para hacer patch de los custom fields del cliente en el UISCP CRM, Campo para el Stripe Customer ID y la Clabe interbancaria
+
+ // $clientguzz = new Client(); //instancia de cliente GuzzleHttp para consumir API UISP CRM
+ // try {
+ // $responseCRM = $clientguzz->patch($baseUri . 'clients/' . $notificationData->clientData['id'], [
+ // 'json' => json_decode($json_data_patch, true),
+ // 'headers' => [
+ // 'X-Auth-App-Key' => $token, // Cambia el nombre de la cabecera de autorización
+ // 'Accept' => 'application/json', // Indica que esperamos una respuesta en formato JSON
+ // ],
+ // 'verify' => false,
+ // ]); //aquí se contruye la petición para hacer patch hacia el cliente en sus custom fields con la API del UISP UCRM
+
+ // } catch (GuzzleException $error) {
+ // echo "Error al hacer el patch al CRM: " . $error->getMessage() . PHP_EOL;
+ // //exit();
+ // }
+ // $log->appendLog(json_encode($responseCRM) . PHP_EOL); //imprimir respuesta del patch de CRM con la clabe y Customer ID Stripe
+
+ } else {
+ $log->appendLog("No hay cambios que actualizar " . PHP_EOL);
+ }
+ }
+
+ public function patchServiceStatusWhatsApp($response_getContactCallBell, $notificationData)
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+
+ $log->appendLog("Actualizando estado del servicio " . PHP_EOL);
+
+ $uuid = $response_getContactCallBell['contact']['uuid'];
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Authorization: Bearer ' . $this->CallBellAPIToken,
+ 'Content-Type: application/json',
+ ]);
+ $UrlChatCallBell = 'https://api.callbell.eu/v1/contacts/' . $uuid;
+ curl_setopt($ch, CURLOPT_URL, $UrlChatCallBell);
+ $nombre_cliente = sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']);
+ $log->appendLog("Nombre del cliente al que se va a actualizar el estado del servicio: " . $nombre_cliente . PHP_EOL);
+ $log->appendLog("UUID: " . $uuid . PHP_EOL);
+
+ $fecha_actual = new DateTime();
+ $fecha_actual->modify('-6 hours');
+ $fecha_actual_ajustada = $fecha_actual->format("d/m/Y H:i");
+
+ $data_CRM = [
+ "name" => $nombre_cliente,
+ "custom_fields" => [
+ "Estado" => (
+ isset($notificationData->serviceData['status'])
+ && $notificationData->serviceData['status'] == 3
+ ) ? '🟠 Suspendido' : (
+ (isset($notificationData->serviceData['status'])
+ && $notificationData->serviceData['status'] == 1)
+ ? '🟢 Activo' : '🚫 Finalizado'),
+ "Fecha Ultima Actualizacion" => '📆🔄️ ' . $fecha_actual_ajustada,
+ ],
+ ];
+
+ $log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL);
+
+ if ($response_getContactCallBell['custom_fields']['Estado'] != $data_CRM['custom_fields']['Estado']) {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data_CRM));
+ $response = curl_exec($ch);
+ $log->appendLog("Response Patch CallBell: " . $response . PHP_EOL);
+ curl_close($ch);
+ } else {
+ $log->appendLog("No hay cambios en el estado del servicio que actualizar " . PHP_EOL);
+ }
+ }
+
+ function UploadReceiptToWordpressByImageFileName($imageFileName): string
+ {
+
+ $log = PluginLogManager::create(); //Initialize Logger
+ $configManager = PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+
+ // Configuración de conexión FTP
+ $ftp_server = $config['hostServerFTP'];
+ $ftp_username = $config['usernameServerFTP'];
+ $ftp_password = $config['passServerFTP'];
+ $remote_folder = "/public_html/wp/wp-content/uploads/img/";
+
+ $log->appendLog("Subiendo comprobante a worpdpress " . PHP_EOL);
+ // Configuración de conexión FTP
+ // $ftp_server = "siip.mx";
+ // $ftp_username = "siip0001";
+ // $ftp_password = '$spGiT,[wa)n';
+ $remote_file = "/public_html/wp/wp-content/uploads/img/" . $imageFileName;
+ $file_to_upload = __DIR__ . '/../../comprobantes/' . $imageFileName;
+ $url = 'https://siip.mx/wp/wp-content/uploads/img/' . $imageFileName;
+
+ $log->appendLog("file_to_upload: " . $file_to_upload . PHP_EOL);
+
+ // Conexión FTP
+ $ftp_conn = ftp_connect($ftp_server) or die("No se pudo conectar al servidor FTP");
+ $login = ftp_login($ftp_conn, $ftp_username, $ftp_password);
+ ftp_pasv($ftp_conn, true);
+ // Verificar conexión y login
+ if ($ftp_conn && $login) {
+ $log->appendLog("Conexión FTP exitosa" . PHP_EOL);
+
+ // Cargar archivo
+ if (ftp_put($ftp_conn, $remote_file, $file_to_upload, FTP_BINARY)) {
+ $log->appendLog("El archivo ha sido cargado exitosamente." . PHP_EOL);
+ $log->appendLog("La URL es: " . $url . PHP_EOL);
+
+ $this->deleteFilesWordpressExceptLastHundred($log, $ftp_conn, $remote_file);
+ // Cerrar conexión FTP
+ ftp_close($ftp_conn); //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
+ return $url; //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
+
+ } else {
+ $log->appendLog("Error al cargar el archivo " . PHP_EOL);
+ ftp_close($ftp_conn);
+ return '';
+ }
+
+ //SI SE DECIDE VOLVER A ELIMINAR LOS COMPROBANTES ENTONCES DESCOMENTAR ESTA PARTE DE ABAJO Y COMENTAR LA SECCIÓN DE ARRIBA
+
+ // Obtener lista de archivos en la carpeta
+ // $files = ftp_nlist($ftp_conn, $remote_folder);
+ // if (is_array($files)) {
+ // // Eliminar la ruta del directorio de los archivos
+ // $files = array_map(function ($file) use ($remote_folder) {
+ // return str_replace($remote_folder, '', $file);
+ // }, $files);
+
+ // // Obtener fechas de modificación
+ // $filesWithTime = [];
+ // foreach ($files as $file) {
+ // $modifiedTime = ftp_mdtm($ftp_conn, $remote_folder . $file);
+ // if ($modifiedTime != -1) {
+ // $filesWithTime[$file] = $modifiedTime;
+ // }
+ // }
+
+ // // Ordenar archivos por fecha de modificación, más recientes primero
+ // arsort($filesWithTime);
+
+ // // Obtener los archivos a eliminar (todos menos los 50 más recientes)
+ // $filesToDelete = array_slice(array_keys($filesWithTime), 50);
+
+ // // Eliminar archivos antiguos
+ // foreach ($filesToDelete as $file) {
+ // if (ftp_delete($ftp_conn, $remote_folder . $file)) {
+ // $log->appendLog("Comprobante eliminado de Wordpress: " . $file . PHP_EOL);
+ // } else {
+ // $log->appendLog('Error al borrar comprobante' . $file . PHP_EOL);
+ // }
+ // }
+ // $log->appendLog("Archivos eliminados" . PHP_EOL);
+ // ftp_close($ftp_conn);
+ // return $url;
+ // } else {
+ // $log->appendLog("No se pudo obtener la lista de archivos de la carpeta FTP" . PHP_EOL);
+ // ftp_close($ftp_conn);
+ // return $url;
+ // }
+
+ } else {
+ $log->appendLog("No se pudo conectar o iniciar sesión en el servidor FTP." . PHP_EOL);
+ return '';
+ }
+ }
+
+ function deleteFilesWordpressExceptLastHundred($log, $ftp_conn, $remote_folder): bool
+ {
+
+ // Obtener lista de archivos en la carpeta
+ $files = ftp_nlist($ftp_conn, $remote_folder);
+ if (is_array($files)) {
+ // Eliminar la ruta del directorio de los archivos
+ $files = array_map(function ($file) use ($remote_folder) {
+ return str_replace($remote_folder, '', $file);
+ }, $files);
+
+ // Obtener fechas de modificación
+ $filesWithTime = [];
+ foreach ($files as $file) {
+ $modifiedTime = ftp_mdtm($ftp_conn, $remote_folder . $file);
+ if ($modifiedTime != -1) {
+ $filesWithTime[$file] = $modifiedTime;
+ }
+ }
+
+ // Ordenar archivos por fecha de modificación, más recientes primero
+ arsort($filesWithTime);
+
+ // Obtener los archivos a eliminar (todos menos los 50 más recientes)
+ $filesToDelete = array_slice(array_keys($filesWithTime), 50);
+
+ // Eliminar archivos antiguos
+ foreach ($filesToDelete as $file) {
+ if (ftp_delete($ftp_conn, $remote_folder . $file)) {
+ $log->appendLog("Comprobante eliminado de Wordpress: " . $file . PHP_EOL);
+ } else {
+ $log->appendLog('Error al borrar comprobante' . $file . PHP_EOL);
+ }
+ }
+ $log->appendLog("Archivos eliminados" . PHP_EOL);
+ ftp_close($ftp_conn);
+ return true;
+ } else {
+ $log->appendLog("No se pudo obtener la lista de archivos de la carpeta FTP" . PHP_EOL);
+ ftp_close($ftp_conn);
+ return false;
+ }
+ }
+
+ /**
+ * /Elimina los archivos del directorio de comprobantes de pago a excepción de los últimos 100 para evitar errores de envío
+ * @return void
+ */
+ function deleteFilesExceptLastHundred()
+ {
+ $log = PluginLogManager::create(); //Initialize Logger
+ $directory = __DIR__ . '/../../comprobantes/';
+ // Verificar si el directorio existe
+ if (!is_dir($directory)) {
+ $log->appendLog('El directorio no existe.');
+ die("El directorio no existe.");
+ }
+
+ // Obtener la lista de archivos en el directorio
+ $files = glob($directory . '/*');
+
+ // Ordenar los archivos por fecha de modificación, de más reciente a más antiguo
+ usort($files, function ($a, $b) {
+ return filemtime($b) - filemtime($a);
+ });
+
+ // Verificar que haya más de 100 archivos
+ if (count($files) > 100) {
+ // Obtener los archivos que deben ser eliminados (todos menos los 100 más recientes)
+ $filesToDelete = array_slice($files, 100);
+
+ // Eliminar los archivos
+ foreach ($filesToDelete as $file) {
+ if (is_file($file)) {
+ unlink($file);
+ $log->appendLog("Archivo eliminado: $file" . PHP_EOL);
+ }
+ }
+ } else {
+ $log->appendLog("Hay menos de 100 archivos en el directorio. No se eliminarán archivos." . PHP_EOL);
+ }
+ }
+}
diff --git a/archivos_webhook_destino/src/Facade/PluginNotifierFacade.php b/archivos_webhook_destino/src/Facade/PluginNotifierFacade.php
new file mode 100755
index 0000000..22d259e
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/PluginNotifierFacade.php
@@ -0,0 +1,58 @@
+pluginData = $optionsManager->load();
+ }
+
+
+ /*
+ * Send WhatsApp through the CallBell API
+ */
+ protected function sendWhatsApp(
+ string $message,
+ ): void {
+ $this->logger->debug('Enviando mensaje desde twilio notifier facade: '.$message);
+
+
+ }
+
+ /*
+ * Phone number of sender - required by Twilio. In this plugin, we only load it from config.
+ */
+ private function getSenderNumber(): string
+ {
+ return $this->pluginData->twilioSmsNumber;
+ }
+}
diff --git a/archivos_webhook_destino/src/Facade/PluginOxxoNotifierFacade.php b/archivos_webhook_destino/src/Facade/PluginOxxoNotifierFacade.php
new file mode 100755
index 0000000..9f54026
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/PluginOxxoNotifierFacade.php
@@ -0,0 +1,58 @@
+pluginData = $optionsManager->load();
+ }
+
+
+ /*
+ * Send WhatsApp through the CallBell API
+ */
+ protected function sendWhatsApp(
+ string $message,
+ ): void {
+ $this->logger->debug('Enviando mensaje desde twilio notifier facade: '.$message);
+
+
+ }
+
+ /*
+ * Phone number of sender - required by Twilio. In this plugin, we only load it from config.
+ */
+ private function getSenderNumber(): string
+ {
+ return $this->pluginData->twilioSmsNumber;
+ }
+}
diff --git a/archivos_webhook_destino/src/Facade/TwilioNotifierFacade.php b/archivos_webhook_destino/src/Facade/TwilioNotifierFacade.php
new file mode 100755
index 0000000..0c7abfe
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/TwilioNotifierFacade.php
@@ -0,0 +1,93 @@
+pluginData = $optionsManager->load();
+ }
+
+ /*
+ * Get Twilio SMS API object (unless it's already initialized)
+ */
+ public function getTwilioClient(): Client
+ {
+ if (!$this->twilioClient) {
+ $this->twilioClient = new Client(
+ $this->pluginData->token_callbell
+ );
+ }
+ return $this->twilioClient;
+ }
+ /*
+ * Send WhatsApp through the CallBell API
+ */
+ protected function sendWhatsApp(
+ string $message,
+ ): void {
+ $this->logger->debug('Enviando mensaje desde twilio notifier facade: '.$message);
+
+
+ }
+ /*
+ * Send message through the Twilio client
+ */
+ protected function sendMessage(
+ NotificationData $notificationData,
+ string $clientSmsNumber,
+ string $messageBody
+ ): void {
+ $this->logger->debug(sprintf('Sending: %s', $messageBody));
+
+ $messageInstance = $this->getTwilioClient()->messages->create(
+ $clientSmsNumber,
+ [
+ 'from' => $this->getSenderNumber(),
+ 'body' => $messageBody,
+ ]
+ );
+
+ $this->logger->debug((string) $messageInstance);
+ $this->logger->info(sprintf('Twilio status: %s, message id: %s', $messageInstance->status, $messageInstance->sid));
+ if ($messageInstance->errorCode) {
+ $this->logger->warning(sprintf('Twilio error: %s %s', $messageInstance->errorCode, $messageInstance->errorMessage));
+ }
+ }
+
+ /*
+ * Phone number of sender - required by Twilio. In this plugin, we only load it from config.
+ */
+ private function getSenderNumber(): string
+ {
+ return $this->pluginData->twilioSmsNumber;
+ }
+}
diff --git a/archivos_webhook_destino/src/Facade/pruebas_ucrm_api.php b/archivos_webhook_destino/src/Facade/pruebas_ucrm_api.php
new file mode 100755
index 0000000..71d04a0
--- /dev/null
+++ b/archivos_webhook_destino/src/Facade/pruebas_ucrm_api.php
@@ -0,0 +1,5 @@
+logger = $logger;
+ $this->optionsManager = $optionsManager;
+ $this->pluginDataValidator = $pluginDataValidator;
+ $this->notifierFacade = $notifierFacade;
+ $this->pluginNotifierFacade = $pluginNotifierFacade;
+ $this->pluginOxxoNotifierFacade = $pluginOxxoNotifierFacade;
+ $this->notificationDataFactory = $notificationDataFactory;
+ }
+
+ public function run(): void
+ {
+ // $hola = PHP_SAPI;
+ // $this->logger->info('valor de PHP_SAPI: ' . $hola);
+ if (PHP_SAPI === 'fpm-fcgi') {
+ // $this->logger->debug('Whatsapp over HTTP started');
+ $this->processHttpRequest();
+ // $this->logger->debug('HTTP request processing ended.');
+ } elseif (PHP_SAPI === 'cli') {
+ // $this->logger->debug('Whatsapp over CLI started');
+ $this->processCli();
+ // $this->logger->debug('CLI process ended.');
+ } else {
+ throw new \UnexpectedValueException('Unknown PHP_SAPI type: ' . PHP_SAPI);
+ }
+
+ }
+
+ private function processCli(): void
+ {
+ if ($this->pluginDataValidator->validate()) {
+ $this->logger->info('Validating config');
+ $this->optionsManager->load();
+ }
+ }
+
+ private function processHttpRequest(): void
+ {
+ $pluginData = $this->optionsManager->load();
+ if ($pluginData->logging_level) {
+ $this->logger->setLogLevelThreshold(LogLevel::DEBUG);
+ }
+
+ $userInput = file_get_contents('php://input'); //se recibe el json del webhook
+ //imprimir el json del webhook
+ $this->logger->debug('valor del webhook: ' . $userInput . PHP_EOL);
+
+ if (! $userInput) {
+ $this->logger->warning('no input');
+
+ return;
+ }
+
+ $jsonData = @json_decode($userInput, true, 50);
+
+ if (! isset($jsonData['uuid'])) {
+ $this->logger->info('No UUID found in the webhook data');
+ //$this->logger->error('JSON error: ' . json_last_error_msg());
+
+ //return;
+
+ // Maneja el evento del webhook externo
+ if ($jsonData) {
+ switch ($jsonData['type']) {
+ case 'customer_cash_balance_transaction.created':
+ if ($jsonData['data']['object']['type'] === 'funded') {
+ $this->logger->info('Evento de transferencia de un cliente recibido: ' . json_encode($jsonData) . PHP_EOL);
+ $this->pluginNotifierFacade->createPaymentIntent($jsonData);
+
+ }
+
+ if ($jsonData['data']['object']['type'] === 'applied_to_payment') {
+ $this->logger->info('Se aplicó el saldo en Stripe de un pago: ' . json_encode($jsonData) . PHP_EOL);
+
+ }elseif ($jsonData['data']['object']['type'] === 'unapplied_from_payment'){
+ //ejemplo de json para transferencia de dinero cancelada: {"id":"evt_1RlEGgEFY1WEUtgR6Bp2DzDP","object":"event","api_version":"2023-10-16","created":1752606717,"data":{"object":{"id":"ccsbtxn_1RlEGfEFY1WEUtgRv8jAUGmE","object":"customer_cash_balance_transaction","created":1752606717,"currency":"mxn","customer":"cus_PetN1dhr4rx0kX","ending_balance":18000,"livemode":false,"net_amount":18000,"type":"unapplied_from_payment","unapplied_from_payment":{"payment_intent":"pi_3RlDPdEFY1WEUtgR1JBgNhTQ"}}},"livemode":false,"pending_webhooks":2,"request":{"id":"req_954mskVBfAI0jn","idempotency_key":"749518f6-baa0-4ae9-99e4-8029a35719aa"},"type":"customer_cash_balance_transaction.created"}
+ $paymentIntentId = $jsonData['data']['object']['unapplied_from_payment']['payment_intent'];
+ //Se canceló una transferencia de dinero, imprimir que se canceló y además el monto neto
+ $this->logger->warning('Evento de transferencia cancelada para el pago: ' . $paymentIntentId . PHP_EOL);
+ $this->logger->warning('Monto neto de la transferencia cancelada: ' . $jsonData['data']['object']['net_amount'] . PHP_EOL);
+
+ }
+ break;
+ case 'payout.failed':
+ $this->logger->info('Evento de transferencia fallida encontrado: ' . json_encode($jsonData) . PHP_EOL);
+ //imprimir detalles del fallo
+ $this->logger->info('Detalles del fallo: ' . json_encode($jsonData));
+ break;
+ case 'payment_intent.partially_funded':
+ $this->logger->info('Evento de pago parcialmente financiado encontrado: ' . json_encode($jsonData) . PHP_EOL);
+ //imprimir detalles del evento o pago
+ $this->logger->info('Detalles del evento: ' . json_encode($jsonData));
+ break;
+ case 'inbound_payment.payment_attempt':
+ //$this->logger->info('Evento de Pago de OXXO recibido: ' . json_encode($jsonData) . PHP_EOL);
+ break;
+ case 'cash_balance.funds_available':
+ $this->logger->info('Evento de Pago de fondos disponibles recibido: ' . json_encode($jsonData) . PHP_EOL);
+ break;
+ case 'energy.alert':
+ $this->logger->info('Evento de Energía recibido: ' . $jsonData['message'] . PHP_EOL);
+ break;
+ case 'oxxo.request':
+ $this->logger->info('Evento de solicitud de referencia de oxxo recibido' . PHP_EOL);
+
+ // Construir la URL basada en el "client_id"
+ // $url = "https://siip.mx/wp/wp-content/uploads/img/voucher.png";
+ if (! empty($jsonData['amount'])) {
+ $this->logger->info('Referencia personalizada, Valor del monto: ' . $jsonData['amount'] . PHP_EOL);
+ $intentos = 0;
+ do {
+ // if ($intentos > 1) {
+ // sleep(2);
+ // }
+ $responseOxxo = $this->pluginOxxoNotifierFacade->createOxxoPaymentIntent($jsonData, $jsonData['amount']);
+ $this->logger->info('Referencia personalizada, Valor de la respuesta: ' . json_encode($responseOxxo) . PHP_EOL);
+ //El array asociativo $responseOxxo es un array asosiativo con los siguientes campos: oxxo_reference, error, failDescription, clientID, amount
+ $intentos++;
+ } while (strpos($responseOxxo['url'], 'https') !== 0 && $intentos < 3); //Mientras la url no contenga https y el número de intentos sea menor a 3
+ } else {
+ $intentos = 0;
+ do {
+ // if ($intentos > 1) {
+ // sleep(2);
+ // }
+ $responseOxxo = $this->pluginOxxoNotifierFacade->createOxxoPaymentIntent($jsonData);
+ //El array asociativo $responseOxxo es un array asosiativo con los siguientes campos: oxxo_reference, error, failDescription, clientID, amount
+ $intentos++;
+ } while (strpos($responseOxxo['url'], 'https') !== 0 && $intentos < 3); //Mientras la url no contenga https y el número de intentos sea menor a 3
+ }
+
+ //El array asociativo $responseOxxo es un array asosiativo con los siguientes campos: oxxo_reference, error, failDescription, clientID, amount
+ //Si la respuesta no contiene https, se genera un error
+ if (strpos($responseOxxo['url'], 'https') !== 0) {
+ //this->logger->error('Error al crear la referencia de OXXO: ' . $responseOxxo);
+ //crear un json con variable $response que contenga las claves y valores del array $responseOxxo los cuales son: oxxo_reference, error, failDescription, clientID, clientFullName amount
+ $response = '{' .
+ '"url": "' . $responseOxxo['url'] . '",' .
+ '"oxxo_reference": "' . $responseOxxo['oxxo_reference'] . '",' .
+ '"voucher_image_url": "' . $responseOxxo['voucher_image_url'] . '",' .
+ '"error": "' . $responseOxxo['error'] . '",' .
+ '"failDescription": "' . $responseOxxo['failDescription'] . '",' .
+ '"clientID": "' . $responseOxxo['clientID'] . '",' .
+ '"clientFullName": "' . $responseOxxo['clientFullName'] . '",' .
+ '"amount": "' . $responseOxxo['amount'] . '"' .
+ '}';
+
+ header('Content-Type: application/json');
+ echo $response;
+ break;
+ } else {
+ //crear un json con variable $response que contenga las claves y valores del array $responseOxxo los cuales son: oxxo_reference, error, failDescription, clientID, clientFullName, amount
+
+ $response = '{' .
+ '"url": "' . $responseOxxo['url'] . '",' .
+ '"oxxo_reference": "' . $responseOxxo['oxxo_reference'] . '",' .
+ '"voucher_image_url": "' . $responseOxxo['voucher_image_url'] . '",' .
+ '"error": "' . $responseOxxo['error'] . '",' .
+ '"failDescription": "' . $responseOxxo['failDescription'] . '",' .
+ '"clientID": "' . $responseOxxo['clientID'] . '",' .
+ '"clientFullName": "' . $responseOxxo['clientFullName'] . '",' .
+ '"amount": "' . $responseOxxo['amount'] . '"' .
+ '}';
+
+ $this->logger->debug('Reponse que se envía a CallBell: ' . $response);
+ // Enviar el encabezado de respuesta como JSON
+ header('Content-Type: application/json');
+
+ // Enviar la respuesta en formato JSON
+ //echo json_encode($response);
+ echo $response;
+
+ break;
+
+ }
+
+ }
+ }
+ return;
+ }
+
+ // $event_json = json_decode($userInput);
+ // $webhook_string = json_encode($event_json);
+ // $this->logger->debug("El valor de webhook_string: " . $webhook_string . PHP_EOL);
+
+ $notification = $this->notificationDataFactory->getObject($jsonData);
+ $this->logger->debug('valor el evento recibido por webhook: ' . $notification->eventName . PHP_EOL);
+ $this->logger->debug('Valor de JSON: ' . json_encode($jsonData) . PHP_EOL);
+
+ if ($notification->changeType === 'test') {
+
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+
+ $this->logger->info('Webhook test successful.');
+
+ return;
+ } else if ($notification->changeType === 'paperless.update') {
+ //imprimir el webhook json
+ $this->logger->info('Webhook de paperless update: ' . json_encode($jsonData) . PHP_EOL);
+ }
+ // if (!$notification->clientId) {
+ // $this->logger->warning('No client specified, cannot notify them.');
+
+ // return;
+ // }
+
+ $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
+ $config = $configManager->loadConfig();
+ // the "exportFormat" key must be defined in plugin's manifest file, see the link above
+
+ try {
+
+ if ($notification->eventName === 'payment.add') {
+
+ $result = json_encode($notification);
+ $this->logger->debug('Notification encodificado en JSON:' . $result . PHP_EOL);
+
+ $datos_payment = $notification->paymentData;
+ $this->logger->debug('valor del payment data: ' . json_encode($datos_payment) . PHP_EOL);
+ $payment_method_id = $notification->paymentData['methodId'];
+ //$this->logger->debug('Metodo de pago: ' . $notification->paymentData['methodId'] . PHP_EOL);
+
+ $payment_method = '';
+
+ switch ($payment_method_id) {
+
+ case '11721cdf-a498-48be-903e-daa67552e4f6':
+ $payment_method = 'Cheque';
+ if ($config['checkPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '6efe0fa8-36b2-4dd1-b049-427bffc7d369':
+ $payment_method = 'Efectivo';
+ if ($config['cashPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '4145b5f5-3bbc-45e3-8fc5-9cda970c62fb':
+ $payment_method = 'Transferencia bancaria';
+ if ($config['bankTransferPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '78e84000-9b5b-44a4-8367-da43df86ce34':
+ $payment_method = 'PayPal';
+ if ($config['paypalPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '6da98bb9-6df7-4c41-8608-5cdd7fde7d5d':
+ $payment_method = 'Tarjeta de crédito PayPal';
+ if ($config['creditCardPaypalPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '1dd098fa-5d63-4c8d-88b7-3c27ffbbb6ae':
+ $payment_method = 'Tarjeta de crédito Stripe';
+ if ($config['creditCardStripePaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case 'b9e1e9d1-5c7b-41d2-b6b2-3e568d700290':
+ $payment_method = 'Suscripción de Stripe (tarjeta de crédito)';
+ if ($config['stripeSubscriptionCreditCardPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '939f7701-00b7-4676-9b1e-17afb268c8ba':
+ $payment_method = 'Suscripción de PayPal';
+ if ($config['paypalSubscriptionPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '1c963e35-df24-444d-95d2-12592d5107e8':
+ $payment_method = 'MercadoPago';
+ if ($config['mercadopagoPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case 'd8c1eae9-d41d-479f-aeaf-38497975d7b3':
+ $payment_method = 'Personalizado';
+ if ($config['customPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ case '72271b72-5c0a-45e2-94d1-cdf4d7cf10e2':
+ $payment_method = 'Cortesía';
+ if ($config['courtesyPaymentMethodId']) {
+ $this->notifierFacade->verifyPaymentActionToDo($notification);
+ }
+ break;
+ default:
+ $payment_method = 'Desconocido, revisar metodos de pago no contemplados';
+ break;
+
+ }
+
+ } else if ($notification->eventName === 'client.edit') {
+ $this->logger->debug('Se actualiza a un cliente');
+ $this->logger->debug('Valor de json_data: ' . json_encode($jsonData));
+ //ejemplo de json_data: {"uuid":"aacaf5c5-2bf4-44ea-864f-a24121b453bb","changeType":"edit","entity":"client","entityId":"171","eventName":"client.edit","extraData":{"entity":{"id":171,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Campeche 56","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Campeche 56, Dolores Hidalgo, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-05-21T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Archi","lastName":"Isalas","username":"mainstreamm2@gmail.com","contacts":[{"id":177,"clientId":171,"email":"mainstreamm2@gmail.com","phone":"4181878106","name":null,"isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":198,"clientId":171,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_SM2zH6IsjTz6ol","clientZoneVisible":true},{"id":199,"clientId":171,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"124180950530868794","clientZoneVisible":true}],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1572461,"addressGpsLon":-100.9377137,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"entityBeforeEdit":{"id":171,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Campeche 56","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Campeche 56, Dolores Hidalgo, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-05-21T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Archi","lastName":"Isalas","username":"mainstreamm2@gmail.com","contacts":[{"id":177,"clientId":171,"email":"mainstreamm2@gmail.com","phone":"4181878106","name":null,"isBilling":false,"isContact":false,"types":[{"id":1003,"name":"WhatsNotifica"}]}],"attributes":[{"id":198,"clientId":171,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_SM2zH6IsjTz6ol","clientZoneVisible":true},{"id":199,"clientId":171,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"124180950530868794","clientZoneVisible":true}],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1572461,"addressGpsLon":-100.9377137,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}}}
+
+
+ $clientID = $jsonData['entityId'];
+ $this->ucrmApi = UcrmApi::create();
+ $customAttributes = $this->ucrmApi->get('custom-attributes/', ['attributeType' => 'client']); //Obtener los atributos del sistema que estén vinculados a la entidad "cliente"
+ //$this->logger->info("result del custom Attributes: " . json_encode($customAttributes) . PHP_EOL);
+
+ $idPasswordAntenaCliente = null;
+ $passwordAntenaValue = null;
+
+ //ejemplo de $customAttributes: [{"id":1,"name":"ip","key":"ip","attributeType":"client","type":"string","clientZoneVisible":false},{"id":2,"name":"ubntpass","key":"ubntpass","attributeType":"client","type":"string","clientZoneVisible":false},{"id":3,"name":"adminpass","key":"adminpass","attributeType":"client","type":"string","clientZoneVisible":true},{"id":4,"name":"ssid","key":"ssid","attributeType":"client","type":"string","clientZoneVisible":true},{"id":5,"name":"clavessid","key":"clavessid","attributeType":"client","type":"string","clientZoneVisible":true},{"id":6,"name":"clave","key":"clave","attributeType":"client","type":"string","clientZoneVisible":true},{"id":11,"name":"latitud","key":"latitud","attributeType":"client","type":"string","clientZoneVisible":true},{"id":12,"name":"longitud","key":"longitud","attributeType":"client","type":"string","clientZoneVisible":true},{"id":16,"name":"instalador","key":"instalador","attributeType":"client","type":"string","clientZoneVisible":true},{"id":17,"name":"creado por","key":"creadoPor","attributeType":"client","type":"string","clientZoneVisible":true},{"id":21,"name":"Chat de CallBell","key":"chatDeCallbell","attributeType":"client","type":"string","clientZoneVisible":false},{"id":22,"name":"uuid","key":"uuid","attributeType":"client","type":"string","clientZoneVisible":false},{"id":23,"name":"zona","key":"zona","attributeType":"client","type":"enum","clientZoneVisible":true},{"id":29,"name":"Stripe Customer ID","key":"stripeCustomerId","attributeType":"client","type":"string","clientZoneVisible":true},{"id":30,"name":"Clabe Interbancaria","key":"clabeInterbancaria","attributeType":"client","type":"string","clientZoneVisible":true},{"id":31,"name":"RUTA DE COBRANZA","key":"rutaDeCobranza","attributeType":"client","type":"enum","clientZoneVisible":true},{"id":35,"name":"Site","key":"site","attributeType":"client","type":"string","clientZoneVisible":true},{"id":36,"name":"Antena/Sectorial","key":"antenaSectorial","attributeType":"client","type":"string","clientZoneVisible":true},{"id":37,"name":"Password Antena Cliente","key":"passwordAntenaCliente","attributeType":"client","type":"string","clientZoneVisible":false}]
+
+ // Verificar si se obtuvieron los atributos
+ if ($customAttributes && is_array($customAttributes)) {
+ foreach ($customAttributes as $attribute) {
+ // Verificar si 'name' contiene la palabra 'passwordAntenaCliente' sin distinguir mayúsculas y minúsculas
+ if (isset($attribute['key']) && stripos($attribute['key'], 'passwordAntenaCliente') !== false) {
+ $this->logger->info("ID correspondiente a 'passwordAntenaCliente': " . $attribute['id'] . PHP_EOL);
+ $idPasswordAntenaCliente = $attribute['id'];
+ }
+
+ }
+ } else {
+ $this->logger->info("Error al obtener los atributos personalizados." . PHP_EOL);
+ }
+
+ //buscar en los attributes ($jsonData) del cliente el id del atributo personalizado 'passwordAntenaCliente' si no está o si está pero está en blanco se manda llamar la función $this->notifierFacade->getVaultCredentials($clientID);
+
+ foreach ($jsonData['extraData']['entity']['attributes'] as $attribute) {
+ if ($attribute['customAttributeId'] === $idPasswordAntenaCliente) {
+ $this->logger->info("El valor de passwordAntenaValue es: " . $attribute['value'] . PHP_EOL);
+ $passwordAntenaValue = $attribute['value'];
+ }
+ }
+
+ //si el value de passwordAntenaValue es igual a null o cadena vacía se manda llamar la función $this->notifierFacade->getVaultCredentials($clientID);
+ if ($passwordAntenaValue === null || $passwordAntenaValue === '') {
+ $password = $this->notifierFacade->getVaultCredentials($clientID);
+ $this->logger->info("El valor de passwordAntenaValue es null o cadena vacía, se manda llamar la función getVaultCredentials" . PHP_EOL);
+ $this->logger->info("El valor de password es: " . $password . PHP_EOL);
+
+ if ($this->notifierFacade->patchClientCustomAttribute($clientID, $idPasswordAntenaCliente, $password)) {
+ $this->logger->info("Se actualizó el atributo personalizado passwordAntenaCliente con el valor: " . $password . PHP_EOL);
+ } else {
+ $this->logger->info("No se pudo actualizar el atributo personalizado passwordAntenaCliente" . PHP_EOL);
+ }
+ } else {
+ $this->logger->info("Ya existe un valor de passwordAntenaValue: " . $passwordAntenaValue . PHP_EOL);
+ }
+
+ //ejemplo de json_data: {"uuid":"17e043a7-03b5-4312-ab81-a7818124a77e","changeType":"edit","entity":"client","entityId":"158","eventName":"client.edit","extraData":{"entity":{"id":158,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"23 San Luis","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37804","fullAddress":"San Luis 23, Guadalupe, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-01-06T00:00:00-0600","leadConvertedAt":"2025-02-09T03:15:49-0600","companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Luis","lastName":"Guti\u00e9rrez","username":null,"contacts":[{"id":162,"clientId":158,"email":null,"phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#2196f3","addressGpsLat":21.153272,"addressGpsLon":-100.9134508,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"entityBeforeEdit":{"id":158,"userIdent":null,"previousIsp":null,"isLead":true,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"23 San Luis","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37804","fullAddress":"San Luis 23, Guadalupe, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-01-06T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Luis","lastName":"Guti\u00e9rrez","username":null,"contacts":[{"id":162,"clientId":158,"email":null,"phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#2196f3","addressGpsLat":21.153272,"addressGpsLon":-100.9134508,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}}}
+
+ // Validar que 'extraData' existe y contiene las claves necesarias
+ if (
+ isset($jsonData['extraData']['entityBeforeEdit']) &&
+ isset($jsonData['extraData']['entity'])
+ ) {
+ $entityBeforeEdit = $jsonData['extraData']['entityBeforeEdit'];
+ $entity = $jsonData['extraData']['entity'];
+
+ //$this->logger->debug('Validando claves dentro de entityBeforeEdit y entity');
+
+ // Validar si 'isLead' esta en true en entityBeforeEdit y en false en entity
+ if (array_key_exists('isLead', $entityBeforeEdit) && array_key_exists('isLead', $entity)) {
+ //$this->logger->debug('Los datos entityBeforeEdit y entity contienen el campo isLead');
+
+ $isLeadBefore = $entityBeforeEdit['isLead'];
+ $isLeadAfter = $entity['isLead'];
+
+ // Comprobar si 'isLead' cambió de true a false
+ if ($isLeadBefore === true && $isLeadAfter === false) {
+ $this->logger->debug('El cliente cambió de potencial a cliente');
+ //$this->pluginNotifierFacade->createStripeClient($notification); //Se comenta esta línea para que no se cree el cliente en Stripe al convertir el lead a cliente, ya que se hará al agregar la etiqueta 'CREAR CLABE STRIPE'
+ } else {
+ $this->logger->debug('El cliente no cambió de potencial a cliente');
+ }
+ } else {
+ $this->logger->warning('El campo isLead no existe en entityBeforeEdit o entity');
+ }
+
+ // buscar si existe la etiqueta 'STRIPE' en entity pero no en entityBeforeEdit
+ $tags = $jsonData['extraData']['entity']['tags'];
+ $tagsBefore = $jsonData['extraData']['entityBeforeEdit']['tags'];
+
+ $this->logger->debug('Validando claves dentro de entity y entityBeforeEdit');
+
+ // Validar que 'tags' existe en ambas entidades
+ if (array_key_exists('tags', $jsonData['extraData']['entity']) && array_key_exists('tags', $jsonData['extraData']['entityBeforeEdit'])) {
+ $this->logger->debug('Los datos entity y entityBeforeEdit contienen el campo tags');
+
+ $tags = $jsonData['extraData']['entity']['tags'];
+ $tagsBefore = $jsonData['extraData']['entityBeforeEdit']['tags'];
+
+ $this->logger->debug('Validando si la etiqueta STRIPE existe en entity pero no en entityBeforeEdit');
+
+ // Comprobar si la etiqueta 'CREAR CLABE STRIPE' existe en 'tags' pero no en 'tagsBefore'
+ $stripeTagExists = false;
+ $stripeTagExistsBefore = false;
+ foreach ($tags as $tag) {
+ if ($tag['name'] === 'CREAR CLABE STRIPE') {
+ $stripeTagExists = true;
+ break;
+ }
+ }
+ foreach ($tagsBefore as $tag) {
+ if ($tag['name'] === 'CREAR CLABE STRIPE') {
+ $stripeTagExistsBefore = true;
+ break;
+ }
+ }
+
+ // Comprobar si la etiqueta 'STRIPE' existe en 'tags' pero no en 'tagsBefore'
+ if ($stripeTagExists && ! $stripeTagExistsBefore) {
+ $this->logger->debug('La etiqueta CREAR CLABE STRIPE se agregará al cliente');
+ $this->pluginNotifierFacade->createStripeClient($notification, true);
+ }
+ } else {
+ $this->logger->warning('El campo tags no existe en entity o entityBeforeEdit');
+ }
+
+ } else {
+ $this->logger->warning('Los datos entityBeforeEdit o entity no están presentes en extraData');
+ }
+
+ $this->notifierFacade->verifyClientActionToDo($notification);
+
+ } else if ($notification->eventName === 'client.add') {
+ $this->logger->debug('Se agregó un nuevo cliente' . PHP_EOL);
+ $this->logger->debug('Valor de json_data: ' . json_encode($jsonData));
+
+ // Verificar que existen tanto 'entityBeforeEdit' como 'entity'
+ // if (isset($jsonData['extraData']['entity']['isLead'])) {
+ // $this->logger->debug('El campo isLead existe en los datos del evento');
+ // $isLead = $jsonData['extraData']['entity']['isLead'];
+
+ // // Comprobar si 'isLead' es true
+ // if ($isLead === true) {
+ // $this->logger->debug('El cliente es potencial');
+ // $this->pluginNotifierFacade->createStripeClient($notification);
+ // } else {
+ // $this->logger->debug('El cliente no es potencial');
+ // $this->pluginNotifierFacade->createStripeClient($notification);
+ // }
+ // } else {
+ // $this->logger->warning('El campo isLead no existe en los datos del evento');
+ // }
+
+ } else if ($notification->eventName === 'service.edit') {
+ $this->logger->debug('Se editó el servicio a un cliente' . PHP_EOL);
+ $this->notifierFacade->verifyServiceActionToDo($notification);
+ //ejemplo de json_data: {"uuid":"06d281ca-d78e-4f0a-a282-3a6b77d25da0","changeType":"edit","entity":"service","entityId":"155","eventName":"service.edit","extraData":{"entity":{"id":155,"prepaid":false,"clientId":171,"status":1,"name":"Basico 300","fullAddress":"Campeche 56, Dolores Hidalgo, 37800","street1":"Campeche 56","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","note":null,"addressGpsLat":21.1572461,"addressGpsLon":-100.9377137,"servicePlanId":6,"servicePlanPeriodId":26,"price":300,"hasIndividualPrice":false,"totalPrice":300,"currencyCode":"MXN","invoiceLabel":null,"contractId":null,"contractLengthType":1,"minimumContractLengthMonths":null,"activeFrom":"2025-05-21T00:00:00-0600","activeTo":null,"contractEndDate":null,"discountType":0,"discountValue":null,"discountInvoiceLabel":"Descuento","discountFrom":null,"discountTo":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"invoicingStart":"2025-05-21T00:00:00-0600","invoicingPeriodType":1,"invoicingPeriodStartDay":1,"nextInvoicingDayAdjustment":10,"invoicingProratedSeparately":true,"invoicingSeparately":false,"sendEmailsAutomatically":null,"useCreditAutomatically":true,"servicePlanName":"Basico 300","servicePlanPrice":300,"servicePlanPeriod":1,"servicePlanType":"Internet","downloadSpeed":8,"uploadSpeed":8,"hasOutage":false,"unmsClientSiteStatus":null,"fccBlockId":null,"lastInvoicedDate":null,"unmsClientSiteId":"359cb58d-e64f-453a-890e-23d5abb4f116","attributes":[],"addressData":null,"suspensionReasonId":null,"serviceChangeRequestId":null,"setupFeePrice":null,"earlyTerminationFeePrice":null,"downloadSpeedOverride":null,"uploadSpeedOverride":null,"trafficShapingOverrideEnd":null,"trafficShapingOverrideEnabled":false,"servicePlanGroupId":null,"suspensionPeriods":[],"surcharges":[]},"entityBeforeEdit":{"id":155,"prepaid":false,"clientId":171,"status":1,"name":"Basico 300","fullAddress":"Campeche 56, Dolores Hidalgo, 37800","street1":"Campeche 56","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","note":null,"addressGpsLat":21.1572461,"addressGpsLon":-100.9377137,"servicePlanId":6,"servicePlanPeriodId":26,"price":300,"hasIndividualPrice":false,"totalPrice":300,"currencyCode":"MXN","invoiceLabel":null,"contractId":null,"contractLengthType":1,"minimumContractLengthMonths":null,"activeFrom":"2025-05-21T00:00:00-0600","activeTo":null,"contractEndDate":null,"discountType":0,"discountValue":null,"discountInvoiceLabel":"Descuento","discountFrom":null,"discountTo":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"invoicingStart":"2025-05-21T00:00:00-0600","invoicingPeriodType":1,"invoicingPeriodStartDay":1,"nextInvoicingDayAdjustment":10,"invoicingProratedSeparately":true,"invoicingSeparately":false,"sendEmailsAutomatically":null,"useCreditAutomatically":true,"servicePlanName":"Basico 300","servicePlanPrice":300,"servicePlanPeriod":1,"servicePlanType":"Internet","downloadSpeed":8,"uploadSpeed":8,"hasOutage":false,"unmsClientSiteStatus":null,"fccBlockId":null,"lastInvoicedDate":null,"unmsClientSiteId":"359cb58d-e64f-453a-890e-23d5abb4f116","attributes":[],"addressData":null,"suspensionReasonId":null,"serviceChangeRequestId":null,"setupFeePrice":null,"earlyTerminationFeePrice":null,"downloadSpeedOverride":null,"uploadSpeedOverride":null,"trafficShapingOverrideEnd":null,"trafficShapingOverrideEnabled":false,"servicePlanGroupId":null,"suspensionPeriods":[],"surcharges":[]}}}
+ //obtener el clientID y asginarlo a la variable $clientID
+ $clientID = $jsonData['extraData']['entity']['clientId'];
+ $this->ucrmApi = UcrmApi::create();
+ $customAttributes = $this->ucrmApi->get('custom-attributes/', ['attributeType' => 'client']); //Obtener los atributos del sistema que estén vinculados a la entidad "cliente"
+ //$this->logger->info("result del custom Attributes: " . json_encode($customAttributes) . PHP_EOL);
+
+ $idPasswordAntenaCliente = null;
+ $passwordAntenaValue = null;
+
+ //ejemplo de $customAttributes: [{"id":1,"name":"ip","key":"ip","attributeType":"client","type":"string","clientZoneVisible":false},{"id":2,"name":"ubntpass","key":"ubntpass","attributeType":"client","type":"string","clientZoneVisible":false},{"id":3,"name":"adminpass","key":"adminpass","attributeType":"client","type":"string","clientZoneVisible":true},{"id":4,"name":"ssid","key":"ssid","attributeType":"client","type":"string","clientZoneVisible":true},{"id":5,"name":"clavessid","key":"clavessid","attributeType":"client","type":"string","clientZoneVisible":true},{"id":6,"name":"clave","key":"clave","attributeType":"client","type":"string","clientZoneVisible":true},{"id":11,"name":"latitud","key":"latitud","attributeType":"client","type":"string","clientZoneVisible":true},{"id":12,"name":"longitud","key":"longitud","attributeType":"client","type":"string","clientZoneVisible":true},{"id":16,"name":"instalador","key":"instalador","attributeType":"client","type":"string","clientZoneVisible":true},{"id":17,"name":"creado por","key":"creadoPor","attributeType":"client","type":"string","clientZoneVisible":true},{"id":21,"name":"Chat de CallBell","key":"chatDeCallbell","attributeType":"client","type":"string","clientZoneVisible":false},{"id":22,"name":"uuid","key":"uuid","attributeType":"client","type":"string","clientZoneVisible":false},{"id":23,"name":"zona","key":"zona","attributeType":"client","type":"enum","clientZoneVisible":true},{"id":29,"name":"Stripe Customer ID","key":"stripeCustomerId","attributeType":"client","type":"string","clientZoneVisible":true},{"id":30,"name":"Clabe Interbancaria","key":"clabeInterbancaria","attributeType":"client","type":"string","clientZoneVisible":true},{"id":31,"name":"RUTA DE COBRANZA","key":"rutaDeCobranza","attributeType":"client","type":"enum","clientZoneVisible":true},{"id":35,"name":"Site","key":"site","attributeType":"client","type":"string","clientZoneVisible":true},{"id":36,"name":"Antena/Sectorial","key":"antenaSectorial","attributeType":"client","type":"string","clientZoneVisible":true},{"id":37,"name":"Password Antena Cliente","key":"passwordAntenaCliente","attributeType":"client","type":"string","clientZoneVisible":false}]
+
+ // Verificar si se obtuvieron los atributos
+ if ($customAttributes && is_array($customAttributes)) {
+ foreach ($customAttributes as $attribute) {
+ // Verificar si 'name' contiene la palabra 'passwordAntenaCliente' sin distinguir mayúsculas y minúsculas
+ if (isset($attribute['key']) && stripos($attribute['key'], 'passwordAntenaCliente') !== false) {
+ $this->logger->info("ID correspondiente a 'passwordAntenaCliente': " . $attribute['id'] . PHP_EOL);
+ $idPasswordAntenaCliente = $attribute['id'];
+ }
+
+ }
+ } else {
+ $this->logger->info("Error al obtener los atributos personalizados." . PHP_EOL);
+ }
+
+ //buscar en los attributes ($jsonData) del cliente el id del atributo personalizado 'passwordAntenaCliente' si no está o si está pero está en blanco se manda llamar la función $this->notifierFacade->getVaultCredentials($clientID);
+
+ foreach ($jsonData['extraData']['entity']['attributes'] as $attribute) {
+ if ($attribute['customAttributeId'] === $idPasswordAntenaCliente) {
+ $this->logger->info("El valor de passwordAntenaValue es: " . $attribute['value'] . PHP_EOL);
+ $passwordAntenaValue = $attribute['value'];
+ }
+ }
+
+ //si el value de passwordAntenaValue es igual a null o cadena vacía se manda llamar la función $this->notifierFacade->getVaultCredentials($clientID);
+ if ($passwordAntenaValue === null || $passwordAntenaValue === '') {
+ $password = $this->notifierFacade->getVaultCredentials($clientID);
+ $this->logger->info("El valor de passwordAntenaValue es null o cadena vacía, se manda llamar la función getVaultCredentials" . PHP_EOL);
+ $this->logger->info("El valor de password es: " . $password . PHP_EOL);
+
+ if ($this->notifierFacade->patchClientCustomAttribute($clientID, $idPasswordAntenaCliente, $password)) {
+ $this->logger->info("Se actualizó el atributo personalizado passwordAntenaCliente con el valor: " . $password . PHP_EOL);
+ } else {
+ $this->logger->info("No se pudo actualizar el atributo personalizado passwordAntenaCliente" . PHP_EOL);
+ }
+ } else {
+ $this->logger->info("Ya existe un valor de passwordAntenaValue: " . $passwordAntenaValue . PHP_EOL);
+ }
+
+ } else if ($notification->eventName === 'service.suspend') {
+ $this->logger->debug('Se suspendió el servicio a un cliente' . PHP_EOL);
+ $this->notifierFacade->verifyServiceActionToDo($notification);
+ } else if ($notification->eventName === 'service.suspend_cancel') {
+ $this->logger->debug('Se reactivó el servicio a un cliente' . PHP_EOL);
+ $this->notifierFacade->verifyServiceActionToDo($notification);
+ } else if ($notification->eventName === 'service.postpone') {
+ $this->logger->debug('Se pospuso la suspención del servicio a un cliente' . PHP_EOL);
+ $this->notifierFacade->verifyServiceActionToDo($notification);
+ } else if ($notification->eventName === 'invoice.near_due') {
+ $this->logger->debug('Factura casi por vencer' . PHP_EOL);
+ $this->notifierFacade->notifyOverDue($notification);
+ } else if ($notification->eventName === 'invoice.overdue') {
+ $this->logger->debug('Factura vencida' . PHP_EOL);
+ $result = json_encode($notification);
+ $this->logger->debug('datos del notification para el invoice overdue:' . $result . PHP_EOL);
+ $this->notifierFacade->notifyOverDue($notification);
+ } else if ($notification->eventName === 'invoice.add') {
+ $this->logger->debug('Adición de Factura' . PHP_EOL);
+ $result = json_encode($notification);
+ $this->logger->debug('datos del notification para el invoice add:' . $result . PHP_EOL);
+
+ $accountBalance = $notification->clientData['accountBalance'];
+ //$invoiceAmountPaid = $notification->invoiceData['amountPaid'];
+ $this->logger->debug("Account Balance: " . $accountBalance . PHP_EOL);
+ // $this->logger->debug("Pago hecho con la factura: " . $invoiceAmountPaid . PHP_EOL);
+ $this->notifierFacade->verifyInvoiceActionToDo($notification);
+ } else if ($notification->eventName === 'invoice.edit') {
+ $this->logger->debug('Edición de Factura' . PHP_EOL);
+ $this->notifierFacade->verifyInvoiceActionToDo($notification);
+ } else if ($notification->eventName === 'invoice.add_draft') {
+ $this->logger->debug('Adición de borrador de Factura' . PHP_EOL);
+ $this->notifierFacade->verifyInvoiceActionToDo($notification);
+ } else if ($notification->eventName === 'invoice.draft_approved') {
+ $this->logger->debug('Aprobación de Factura' . PHP_EOL);
+ $this->notifierFacade->verifyInvoiceActionToDo($notification);
+ } else if ($notification->eventName === 'invoice.delete') {
+ $this->logger->debug('Eliminación de Factura' . PHP_EOL);
+ $this->notifierFacade->verifyInvoiceActionToDo($notification);
+ } else if ($notification->eventName === 'job.add') {
+ $this->logger->debug('Se ha agregado un nuevo trabajo' . PHP_EOL);
+ $this->logger->debug('Valor de json_data: ' . json_encode($jsonData));
+ //Ejemplo de json_data: {"uuid":"434b3da0-984a-4358-a1b6-2a4418bacc49","changeType":"insert","entity":"job","entityId":"38","eventName":"job.add","extraData":{"entity":{"id":38,"title":"Servicio","description":"Revisar Router","assignedUserId":null,"clientId":2,"date":null,"duration":60,"status":0,"address":"31 Chiapas, Dolores Hidalgo Cuna de la Independencia Nacional, 37800, Mexico","gpsLat":null,"gpsLon":null,"attachments":[],"tasks":[]},"entityBeforeEdit":null}}
+ //Extraer el valor de title en una variable y concatenarle como prefijo la cadena "[SINENVIONOTIFICACION]" por ejemplo: "[NOTIFICACION-PENDIENTE]Servicio"
+ $title = $jsonData['extraData']['entity']['title'];
+ $title = '[NOTIFICACION-PENDIENTE]' . $title;
+ $this->ucrmApi = UcrmApi::create();
+ $responsePatch = $this->ucrmApi->patch('scheduling/jobs/' . $jsonData['entityId'], [
+ 'title' => $title,
+ ]);
+
+ $this->logger->debug('Respuesta de la API al agregar el trabajo: ' . json_encode($responsePatch) . PHP_EOL);
+
+ } else if ($notification->eventName === 'job.edit') {
+ $this->logger->debug('Se actualiza un trabajo' . PHP_EOL);
+ // $this->logger->debug('Valor de json_data: ' . json_encode($jsonData));
+
+ // Validar que 'extraData' existe y contiene las claves necesarias
+ if (
+ isset($jsonData['extraData']['entityBeforeEdit']) &&
+ isset($jsonData['extraData']['entity'])
+ ) {
+ $entityBeforeEdit = $jsonData['extraData']['entityBeforeEdit'];
+ $entity = $jsonData['extraData']['entity'];
+
+ $this->logger->debug('Validando claves dentro de entityBeforeEdit y entity');
+
+ // Validar que 'assignedUserId' existe en ambas entidades
+ if (array_key_exists('assignedUserId', $entityBeforeEdit) && array_key_exists('assignedUserId', $entity)) {
+ // $this->logger->debug('Los datos entityBeforeEdit y entity contienen el campo assignedUserId');
+
+ $assignedUserIdBefore = $entityBeforeEdit['assignedUserId'];
+ $assignedUserIdAfter = $entity['assignedUserId'];
+ $dateBefore = $entityBeforeEdit['date'];
+ $dateAfter = $entity['date'];
+ $statusBefore = $entityBeforeEdit['status'];
+ $statusAfter = $entity['status'];
+ $title = $entityBeforeEdit['title'];
+ $pendingPrefix = '[NOTIFICACION-PENDIENTE]'; // Prefijo para trabajos pendientes de notificación
+ $currentTitle = $entity['title'] ?? ''; // Obtener el título actual
+
+ //Valores de status y su significado: 0 = abierto, 1= En curso, 2 = Cerrado
+
+ if ($statusAfter == 1) {
+ // Comprobar si 'assignedUserId' cambió
+ // if (($assignedUserIdBefore === null && $assignedUserIdAfter != null) || ($statusBefore == 0 && $statusAfter == 1)) { //Si el campo "assignedUserId" cambió de null a un valor
+ // $this->logger->debug('El instalador cambió de null a un valor');
+
+ // $this->notifierFacade->verifyJobActionToDo($jsonData); // Se envía notificación de trabajo asignado
+ // }
+
+ //Si el campo status cambió de 0 a 1 y title comienza con el prefijo [NOTIFICACION-PENDIENTE]
+ if (($statusBefore == 0 && $statusAfter == 1) && strpos($currentTitle, $pendingPrefix) !== false) { // Se envía notificación de trabajo asignado
+ $this->logger->debug('El instalador cambió de null a un valor');
+ $this->notifierFacade->verifyJobActionToDo($jsonData, false, false);
+ } else if (($assignedUserIdBefore != null && $assignedUserIdAfter != $assignedUserIdBefore) && ($dateBefore === $dateAfter)) { //Si el campo "assignedUserId" cambió de un valor a otro y la fecha no cambió
+ $this->logger->debug('No hay reprogramación de trabajo pero si hay cambio de instalador');
+ $this->notifierFacade->verifyJobActionToDo($jsonData, false, true); // Se envía notificación de trabajo reasignado
+ } else if (($assignedUserIdBefore != null && $assignedUserIdBefore === $assignedUserIdAfter) && ($dateBefore != $dateAfter)) { //Si el campo "assignedUserId" no cambió y la fecha cambió
+ $this->logger->debug('Se reprogramó el trabajo pero no hubo cambio de instalador');
+ $this->notifierFacade->verifyJobActionToDo($jsonData, true, false); // Se envía notificación de reprogramación de trabajo
+ } else if (($assignedUserIdBefore != null && $assignedUserIdAfter != $assignedUserIdBefore) && ($dateBefore != $dateAfter)) {
+ $this->logger->debug('Se reprogramó el trabajo y hubo cambio de instalador');
+ $this->notifierFacade->verifyJobActionToDo($jsonData, true, true); // Se envía notificación de trabajo reasignado
+ } else if ($assignedUserIdBefore != null && $assignedUserIdAfter === null) { //Si el campo "assignedUserId" cambió de un valor a null
+ $this->logger->debug('El instalador cambió de un valor a null');
+ $this->notifierFacade->verifyJobActionToDo($jsonData, null, true); // Se envía notificación de trabajo desasignado
+ } else {
+ $this->logger->debug('No hubo cambio en el instalador ni en la fecha');
+ //$this->notifierFacade->verifyJobActionToDo($jsonData); // Se envía notificación de trabajo asignado
+ }
+ }
+
+ } else {
+ $this->logger->warning('El campo assignedUserId no existe en entityBeforeEdit o entity');
+ }
+ } else {
+ $this->logger->warning('Los datos entityBeforeEdit o entity no están presentes en extraData');
+ }
+
+ }
+
+ //$this->notifierFacade->update($notification);
+ } catch (TwilioException $exception) {
+ $this->logger->error($exception->getMessage());
+ } catch (\Exception $ex) {
+ $this->logger->error($ex->getMessage());
+ $this->logger->info($ex->getTraceAsString());
+ }
+ }
+}
diff --git a/composer.json b/composer.json
old mode 100644
new mode 100755
diff --git a/composer.lock b/composer.lock
old mode 100644
new mode 100755
diff --git a/data/config.json b/data/config.json
old mode 100644
new mode 100755
index 58c8267..47dccd2
--- a/data/config.json
+++ b/data/config.json
@@ -1 +1 @@
-{"ipserver":"sistema.siip.mx","apitoken":"NftJK4BllFalBa1iCCjAww6T/opqDMhyCVyMoBLkq4CPHHUjLEoIsHyEaPwflMz1","debugMode":true,"logging_level":true,"ipServer":"sistema.siip.mx","apiTokenUcrm":"NftJK4BllFalBa1iCCjAww6T/opqDMhyCVyMoBLkq4CPHHUjLEoIsHyEaPwflMz1","apiTokenStripe":"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"}
\ No newline at end of file
+{"ipServer":"venus.siip.mx","apiTokenUcrm":"35lAikF7l9ua8KxmkXhekByNP0vj8Yc3o65bsfl08oN55VN2bdarTu1y3pP4tAXj","apiTokenStripe":"sk_test_51OkG0REFY1WEUtgRH6UxBK5pu80Aq5Iy8EcdPnf0cOWzuVLQTpyLCd7CbPzqMsWMafZOHElCxhEHF7g8boURjWlJ00tBwE0W1M","debugMode":true,"logging_level":true}
\ No newline at end of file
diff --git a/data/plugin.log b/data/plugin.log
old mode 100644
new mode 100755
index daf33c5..76a4129
--- a/data/plugin.log
+++ b/data/plugin.log
@@ -2,3 +2,23 @@ Create Intent Result: {"success":true,"id":"pi_3Sf48SEFY1WEUtgR0s5i4ole","status
Create Intent Result: {"success":true,"id":"pi_3Sf4IyEFY1WEUtgR1jQ2r4pM","status":"requires_action","amount":100,"currency":"mxn"}
Create Intent Result: {"success":true,"id":"pi_3Sf5DMEFY1WEUtgR06kkTXuo","status":"requires_action","amount":200,"currency":"mxn"}
Create Intent Result: {"success":true,"id":"pi_3Sf5EpEFY1WEUtgR1D1YsgLF","status":"requires_action","amount":150,"currency":"mxn"}
+Create Intent Result: {"success":true,"id":"pi_3SfSt1EFY1WEUtgR1isPFtsV","status":"succeeded","amount":500,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":false,"error":"No such customer: 'contrase\u00f1a obtenida 2'"}
+Create Intent Result: {"success":false,"error":"No such customer: 'contrase\u00f1a obtenida 2'"}
+Create Intent Result: {"success":true,"id":"pi_3SfTCOEFY1WEUtgR1UdBNVDk","status":"requires_action","amount":600,"currency":"mxn","next_action":{"display_bank_transfer_instructions":{"amount_remaining":60000,"currency":"mxn","financial_addresses":[{"spei":{"account_holder_address":{"city":"Ciudad de M\u00e9xico","country":"MX","line1":"Av Paseo de la Reforma 180 piso 29 col Juarez","line2":null,"postal_code":"06600","state":"Ciudad de M\u00e9xico"},"account_holder_name":"SIIP INTERNET","bank_address":{"city":"Naucalpan","country":"MX","line1":"Blvd. Manuel Avila Camacho 1902","line2":"Planta Baja, Cd. Satelite","postal_code":"C.P. 53100","state":"Estado de Mexico"},"bank_code":"124","bank_name":"CITI","clabe":"124180257395215094"},"supported_networks":["spei"],"type":"spei"}],"hosted_instructions_url":"https:\/\/payments.stripe.com\/bank_transfers\/instructions\/test_YWNjdF8xT2tHMFJFRlkxV0VVdGdSLF9UY2lkNTgzSmNzV01iMWV1WWhnb2k4V3B6dVR5Y1NI0100Vwpk0GNP","reference":"836126","type":"mx_bank_transfer"},"type":"display_bank_transfer_instructions"}}
+Create Intent Result: {"success":true,"id":"pi_3SfTEsEFY1WEUtgR0sUbrbKn","status":"requires_action","amount":600,"currency":"mxn","next_action":{"display_bank_transfer_instructions":{"amount_remaining":7000,"currency":"mxn","financial_addresses":[{"spei":{"account_holder_address":{"city":"Ciudad de M\u00e9xico","country":"MX","line1":"Av Paseo de la Reforma 180 piso 29 col Juarez","line2":null,"postal_code":"06600","state":"Ciudad de M\u00e9xico"},"account_holder_name":"SIIP INTERNET","bank_address":{"city":"Naucalpan","country":"MX","line1":"Blvd. Manuel Avila Camacho 1902","line2":"Planta Baja, Cd. Satelite","postal_code":"C.P. 53100","state":"Estado de Mexico"},"bank_code":"124","bank_name":"CITI MEXICO","clabe":"124180464584143838"},"supported_networks":["spei"],"type":"spei"}],"hosted_instructions_url":"https:\/\/payments.stripe.com\/bank_transfers\/instructions\/test_YWNjdF8xT2tHMFJFRlkxV0VVdGdSLF9UY2lnZHBDdzdXaVA0dlk1eGpnTDhXUW90dG43UXJJ01005zNS9IqA","reference":"891006","type":"mx_bank_transfer"},"type":"display_bank_transfer_instructions"}}
+Create Intent Result: {"success":true,"id":"pi_3SfTFNEFY1WEUtgR0ARP09wI","status":"requires_action","amount":600,"currency":"mxn","next_action":{"display_bank_transfer_instructions":{"amount_remaining":60000,"currency":"mxn","financial_addresses":[{"spei":{"account_holder_address":{"city":"Ciudad de M\u00e9xico","country":"MX","line1":"Av Paseo de la Reforma 180 piso 29 col Juarez","line2":null,"postal_code":"06600","state":"Ciudad de M\u00e9xico"},"account_holder_name":"SIIP INTERNET","bank_address":{"city":"Naucalpan","country":"MX","line1":"Blvd. Manuel Avila Camacho 1902","line2":"Planta Baja, Cd. Satelite","postal_code":"C.P. 53100","state":"Estado de Mexico"},"bank_code":"124","bank_name":"CITI","clabe":"124180257395215094"},"supported_networks":["spei"],"type":"spei"}],"hosted_instructions_url":"https:\/\/payments.stripe.com\/bank_transfers\/instructions\/test_YWNjdF8xT2tHMFJFRlkxV0VVdGdSLF9UY2lnSUZJYzBqaUM2RlQzUHZNNXhMSDBia0NyQ0RG0100aPJCIE4P","reference":"287441","type":"mx_bank_transfer"},"type":"display_bank_transfer_instructions"}}
+Create Intent Result: {"success":true,"id":"pi_3SfnSmEFY1WEUtgR0F4shJOv","status":"requires_action","amount":600,"currency":"mxn","next_action":{"display_bank_transfer_instructions":{"amount_remaining":60000,"currency":"mxn","financial_addresses":[{"spei":{"account_holder_address":{"city":"Ciudad de M\u00e9xico","country":"MX","line1":"Av Paseo de la Reforma 180 piso 29 col Juarez","line2":null,"postal_code":"06600","state":"Ciudad de M\u00e9xico"},"account_holder_name":"SIIP INTERNET","bank_address":{"city":"Naucalpan","country":"MX","line1":"Blvd. Manuel Avila Camacho 1902","line2":"Planta Baja, Cd. Satelite","postal_code":"C.P. 53100","state":"Estado de Mexico"},"bank_code":"124","bank_name":"CITI","clabe":"124180257395215094"},"supported_networks":["spei"],"type":"spei"}],"hosted_instructions_url":"https:\/\/payments.stripe.com\/bank_transfers\/instructions\/test_YWNjdF8xT2tHMFJFRlkxV0VVdGdSLF9UZDNabm04VGE5QjVRV0tCdkNvNnI2R0ZyeW5BY21y0100Cek337H9","reference":"723997","type":"mx_bank_transfer"},"type":"display_bank_transfer_instructions"}}
+Create Intent Result: {"success":true,"id":"pi_3SfnwDEFY1WEUtgR1PKgbJlo","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sfo8lEFY1WEUtgR1cTsq4mZ","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sfpe1EFY1WEUtgR0eLGPAYb","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":false,"error":"Could not connect to Stripe (https:\/\/api.stripe.com\/v1\/payment_intents). Please check your internet connection and try again. If this problem persists, you should check Stripe's service status at https:\/\/twitter.com\/stripestatus, or let us know at support@stripe.com.\n\n(Network error [errno 28]: Operation timed out after 80001 milliseconds with 0 bytes received)"}
+Create Intent Result: {"success":true,"id":"pi_3SfqxqEFY1WEUtgR19zL9aNr","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sfr6AEFY1WEUtgR1dhC2Ffj","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3SfrAkEFY1WEUtgR01zLxB4v","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sg6SCEFY1WEUtgR1NqBNPcb","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sg7rzEFY1WEUtgR0rGdMrvv","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sg9DQEFY1WEUtgR1Ye5k6G3","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sg9PLEFY1WEUtgR1iAOyHlS","status":"succeeded","amount":600,"currency":"mxn","next_action":null}
+Create Intent Result: {"success":true,"id":"pi_3Sg9kHEFY1WEUtgR0UDlXu7T","status":"requires_action","amount":250,"currency":"mxn","next_action":{"display_bank_transfer_instructions":{"amount_remaining":25000,"currency":"mxn","financial_addresses":[{"spei":{"account_holder_address":{"city":"Ciudad de M\u00e9xico","country":"MX","line1":"Av Paseo de la Reforma 180 piso 29 col Juarez","line2":null,"postal_code":"06600","state":"Ciudad de M\u00e9xico"},"account_holder_name":"SIIP INTERNET","bank_address":{"city":"Naucalpan","country":"MX","line1":"Blvd. Manuel Avila Camacho 1902","line2":"Planta Baja, Cd. Satelite","postal_code":"C.P. 53100","state":"Estado de Mexico"},"bank_code":"124","bank_name":"CITI","clabe":"124180257395215094"},"supported_networks":["spei"],"type":"spei"}],"hosted_instructions_url":"https:\/\/payments.stripe.com\/bank_transfers\/instructions\/test_YWNjdF8xT2tHMFJFRlkxV0VVdGdSLF9UZFFiajNxbDd6bE9PNmgxOXNXSXZIRzlaaVAzd1pm0100rOmKqech","reference":"779272","type":"mx_bank_transfer"},"type":"display_bank_transfer_instructions"}}
+Create Intent Result: {"success":true,"id":"pi_3Shc8dEFY1WEUtgR123bgp1n","status":"succeeded","amount":750,"currency":"mxn","next_action":null}
diff --git a/img/vista-general.png b/img/vista-general.png
old mode 100644
new mode 100755
diff --git a/main.php b/main.php
old mode 100644
new mode 100755
diff --git a/manifest.json b/manifest.json
old mode 100644
new mode 100755
diff --git a/public.php b/public.php
old mode 100644
new mode 100755
index 301ec7b..9f159d7
--- a/public.php
+++ b/public.php
@@ -96,6 +96,59 @@ if ($action === 'create_intent') {
exit;
}
+// 5. Webhook Handler
+if ($action === 'webhook') {
+ $payload = @file_get_contents('php://input');
+ $event = null;
+
+ try {
+ $event = \Stripe\Event::constructFrom(
+ json_decode($payload, true)
+ );
+ } catch(\UnexpectedValueException $e) {
+ http_response_code(400);
+ exit();
+ }
+
+ $log->appendLog("Webhook Received: " . $event->type);
+
+ if ($event->type == 'payment_intent.succeeded') {
+ $paymentIntent = $event->data->object;
+ $clientId = $paymentIntent->metadata->clientId ?? null;
+ $amount = $paymentIntent->amount / 100;
+ $currency = $paymentIntent->currency;
+
+ if ($clientId) {
+ $notes = "Pago procesado via Stripe PaymentIntent: " . $paymentIntent->id;
+ $res = $service->registerPayment($clientId, $amount, $currency, $notes);
+ $log->appendLog("Payment Register UCRM ($clientId): " . ($res ? 'Success' : 'Fail'));
+ }
+ }
+ elseif ($event->type == 'customer_cash_balance_transaction.created') {
+ $txn = $event->data->object;
+ // Check if money was applied to a payment object
+ if (isset($txn->applied_to_payment) && isset($txn->applied_to_payment->payment_intent)) {
+ $piId = $txn->applied_to_payment->payment_intent;
+ $paymentIntent = $service->getPaymentIntent($piId);
+
+ if ($paymentIntent) {
+ $clientId = $paymentIntent->metadata->clientId ?? null;
+ $amount = abs($txn->net_amount) / 100;
+ $currency = $txn->currency;
+
+ if ($clientId) {
+ $notes = "Pago via Transferencia (Cash Balance) aplicado a Intent: " . $piId;
+ $res = $service->registerPayment($clientId, $amount, $currency, $notes);
+ $log->appendLog("Cash Balance Payment Register UCRM ($clientId): " . ($res ? 'Success' : 'Fail'));
+ }
+ }
+ }
+ }
+
+ http_response_code(200);
+ exit;
+}
+
// --- VIEW (HTML) ---
?>
@@ -596,6 +649,41 @@ if ($action === 'create_intent') {
+
+
+
+
Instrucciones de Pago
+
Realiza la transferencia con los siguientes datos: