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 = ''; $config = PluginConfigManager::create()->loadConfig(); $gClient = new Client(['base_uri' => "https://{$this->IPServer}/crm/api/v1.0/", 'verify' => false]); $this->ucrmApi = new UcrmApi($gClient, $this->UCRMAPIToken ?? ''); $payment_id = $notificationData->paymentData['id']; $payment_amount = '$' . $notificationData->paymentData['amount']; // We already have the payment data in $notificationData, no need to fetch 'payments/' again to get the ID. // However, if we need the 'note' field for the overlay which might not be in notificationData (depending on richness), // we should try to use what we have or fetch SPECIFICALLY this payment. // Let's verify if 'note' is in paymentData. Usually UCRM webhook payload has it. // But to be safe and consistent with previous logic, if we need 'note', we can fetch THIS payment. // $payments = $this->ucrmApi->get('payments/'.$payment_id); // This would be better if we need details. // The previous code did: // $payments = $this->ucrmApi->get('payments/', ['clientId' => ..., 'limit' => 1 ...]); // $payment_id = $payments[0]['id']; <-- THIS WAS THE BUG. Always getting latest. // Fix: Use the ID passed in notificationData. // If we need the NOTE for the Overlay (OXXO/Transfer check later in code), we should ensure we have it. // $notificationData->paymentData usually contains 'note'. $note = $notificationData->paymentData['note'] ?? ''; // Let's keep $payments array structure if downstream code expects it, OR refactor downstream. // Downstream uses $payments[0]['note']. // Let's just mock $payments[0] with our data OR fetch the correct single payment. // Fetching single payment is safer to ensure we have the Note. try { $fetchedPayment = $this->ucrmApi->get('payments/' . $payment_id); $payments = [$fetchedPayment]; } catch (\Exception $e) { // Fallback if fetch fails (unlikely if ID is valid) $payments = [$notificationData->paymentData]; } // $payment_id is already set above. $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 $unwanted_array = array( 'Š'=>'S', 'š'=>'s', 'Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss', 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ü'=>'u', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y' ); $clean_name = strtr($nombre_cliente, $unwanted_array); $clean_name = preg_replace('/[^A-Za-z0-9_\-]/', '', str_replace(' ', '_', $clean_name)); $fileNameComprobante = 'Comprobante_' . $clean_name . '.pdf'; $rutaArchivo = __DIR__ . '/../../comprobantes/' . $fileNameComprobante; // Asegurar que exista la carpeta de comprobantes if (!is_dir(dirname($rutaArchivo))) { mkdir(dirname($rutaArchivo), 0777, true); } // 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; } // --- NUEVO FLUJO: Microservicio PDF->IMG + MinIO --- $url_file = ''; $rutaImagen = str_replace('.pdf', '.jpg', $rutaArchivo); // Usamos .jpg para la salida del microservicio try { // 1. Instanciar Logger y MinioService $loggerService = new Logger(); // Servicio de Logging propio del namespace $minioService = new MinioStorageService($loggerService); // 2. Configurar Microservicio $ipMicroservice = $config['ipMicroservice'] ?? 'pdf-cropper-service'; $portMicroservice = $config['portMicroservice'] ?? '8000'; $microserviceUrl = "http://{$ipMicroservice}:{$portMicroservice}/process"; $log->appendLog("Procesando PDF con microservicio: $microserviceUrl" . PHP_EOL); // 2. DETECTAR METODO DE PAGO (Overlay) $overlayText = ''; $note = $payments[0]['note'] ?? ''; // Si la nota dice OXXO o Transferencia, preparamos el reemplazo if (stripos($note, 'OXXO') !== false) { $overlayText = 'OXXO Pay'; } elseif (stripos($note, 'Transferencia') !== false) { $overlayText = 'Transferencia Bancaria'; } // Coordenadas APROXIMADAS para el template default de UCRM (Ajustar si es necesario) // Asumiendo PDF a 200dpi (ancho ~1600px). // "Método" suele estar alineado a la izquierda, valor a la derecha. // X=500, Y=650 (ejemplo). W=800, H=40. $overlayX = 450; $overlayY = 665; // Ajustar probando $overlayW = 1000; $overlayH = 50; // 3. Llamar al Microservicio (PDF -> JPG) $multipartData = [ [ 'name' => 'file', 'contents' => fopen($rutaArchivo, 'r'), 'filename' => basename($rutaArchivo) ], [ 'name' => 'mode', 'contents' => 'full' ] ]; if ($overlayText) { $log->appendLog("Aplicando Overlay: $overlayText en ($overlayX, $overlayY)" . PHP_EOL); $multipartData[] = ['name' => 'overlay_text', 'contents' => $overlayText]; $multipartData[] = ['name' => 'overlay_x', 'contents' => (string)$overlayX]; $multipartData[] = ['name' => 'overlay_y', 'contents' => (string)$overlayY]; $multipartData[] = ['name' => 'overlay_w', 'contents' => (string)$overlayW]; $multipartData[] = ['name' => 'overlay_h', 'contents' => (string)$overlayH]; } $guzzleParams = [ 'multipart' => $multipartData, 'timeout' => 30 ]; $httpClient = new Client(); $responseMs = $httpClient->post($microserviceUrl, $guzzleParams); if ($responseMs->getStatusCode() === 200) { $jpgContent = $responseMs->getBody()->getContents(); if (file_put_contents($rutaImagen, $jpgContent) !== false) { $log->appendLog("Imagen generada por microservicio guardada en: $rutaImagen" . PHP_EOL); // 4. Subir a MinIO $fileNameComprobanteImage = str_replace('.jpg', '_' . time() . '.jpg', basename($rutaImagen)); $url_file = $minioService->uploadFile($rutaImagen, $fileNameComprobanteImage); if ($url_file) { $log->appendLog("Imagen subida a MinIO: $url_file" . PHP_EOL); // 5. LIMPIEZA AUTOMÁTICA (Consistencia con req. de usuario) if (file_exists($rutaArchivo)) { unlink($rutaArchivo); //$log->appendLog("Archivo PDF temporal eliminado." . PHP_EOL); } if (file_exists($rutaImagen)) { unlink($rutaImagen); //$log->appendLog("Archivo JPG temporal eliminado." . PHP_EOL); } $log->appendLog("Archivos temporales (PDF/JPG) eliminados tras subida exitosa." . PHP_EOL); } else { $log->appendLog("Error: Falló la subida a MinIO." . PHP_EOL); return false; } } else { $log->appendLog("Error guardando imagen del microservicio." . PHP_EOL); return false; } } else { $log->appendLog("Error microservicio PDF: HTTP " . $responseMs->getStatusCode() . PHP_EOL); return false; } } catch (\Exception $e) { $log->appendLog("Excepción en flujo Microservicio/MinIO: " . $e->getMessage() . PHP_EOL); return false; } // Legacy FTP eliminado // $url_file = $this->UploadReceiptToWordpressByImageFileName($fileNameComprobanteImage); $log->appendLog("Proceso de obtención de imagen finalizado." . 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 = ''; $config = PluginConfigManager::create()->loadConfig(); $gClient = new Client(['base_uri' => "https://{$this->IPServer}/crm/api/v1.0/", 'verify' => false]); $this->ucrmApi = new UcrmApi($gClient, $this->UCRMAPIToken ?? ''); $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 = ''; $passAntenaUCRM = ''; $clabeAttr = ''; // 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'] ?? ''; } if ($attribute['key'] === 'passwordAntenaCliente') { $passAntenaUCRM = $attribute['value'] ?? ''; } if ($attribute['key'] === 'clabeInterbancaria') { $clabeAttr = $attribute['value'] ?? ''; } } if (empty($clabeInterbancaria)) { $clabeInterbancaria = $clabeAttr; } // Parsear contraseñas multi-servicio a JSON $passAntenaJSON = []; if (!empty($passAntenaUCRM)) { if (strpos($passAntenaUCRM, 'Servicio') !== false) { // Buscamos patrones "Servicio X: " // Usamos una expresión más robusta para capturar hasta el siguiente "Servicio" o el final de la cadena preg_match_all('/Servicio (\d+):\s*(.*?)(?=\s*Servicio \d+:|$)/', $passAntenaUCRM, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $numServicio = "Servicio " . $match[1]; $passAntenaJSON[$numServicio] = trim($match[2]); } } else { // Un solo servicio sin etiqueta (o con advertencia ⚠️) $passAntenaJSON["Servicio 1"] = trim($passAntenaUCRM); } } $passAntenaFinal = !empty($passAntenaJSON) ? json_encode($passAntenaJSON) : ""; $log->appendLog("Dentro del proceso del patch: " . PHP_EOL); $config = PluginConfigManager::create()->loadConfig(); $gClient = new Client(['base_uri' => "https://{$this->IPServer}/crm/api/v1.0/", 'verify' => false]); $this->ucrmApi = new UcrmApi($gClient, $this->UCRMAPIToken ?? ''); $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', ]); $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 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"); $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'] . '",' . '"Nombre": "' . sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']) . '",' . '"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 . '",' . '"Password Antena": ' . (empty($passAntenaFinal) ? '""' : $passAntenaFinal) . '}'; $data_CRM = [ "name" => sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']), "custom_fields" => [ "Site" => $site, "Estado" => ($notificationData->clientData['hasSuspendedService']) ? '🟠 Suspendido' : '🟢 Activo ', "URL" => '🌐 https://sistema.siip.mx/crm/client/' . $notificationData->clientId, "Nombre" => sprintf("👤 %s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']), "Cliente" => $notificationData->clientData['id'], "Fecha Ultima Actualizacion" => '📆🔄️ ' . $fecha_actual_ajustada, "Saldo Actual" => $saldoTexto, "Monto Ultimo Pago" => '💲 ' . $payments[0]['amount'], "Clabe Interbancaria" => $clabeInterbancaria, "Fecha Ultimo Pago" => '📆💸 ' . $fecha_ultimoPago_ajustada . ' con ' . $payment_method, "Antena/Sectorial" => $antenaSectorial, "Domicilio" => ($notificationData->clientData['fullAddress'] == null) ? '📍❌ Sin domicilio' : '📍 ' . $notificationData->clientData['fullAddress'], "Resumen" => $resumenClienteJSON, "password-antena" => $passAntenaFinal, ], ]; $log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL); // OPT: Comparación inteligente para evitar patches innecesarios // La respuesta de getContactWhatsapp viene envuelta en 'contact' y usa 'customFields' $contact = $response_getContactCallBell['contact'] ?? []; $contactCustomFields = $contact['customFields'] ?? []; $log->appendLog("DEBUG COMPARACIÓN - CallBell Saldo Actual: '" . ($contactCustomFields['Saldo Actual'] ?? 'NULL') . "'" . PHP_EOL); $log->appendLog("DEBUG COMPARACIÓN - UCRM Saldo Actual: '" . $data_CRM['custom_fields']['Saldo Actual'] . "'" . PHP_EOL); $log->appendLog("DEBUG COMPARACIÓN - CallBell Estado: '" . ($contactCustomFields['Estado'] ?? 'NULL') . "'" . PHP_EOL); $log->appendLog("DEBUG COMPARACIÓN - UCRM Estado: '" . $data_CRM['custom_fields']['Estado'] . "'" . PHP_EOL); $hasChanges = false; if (($contact['name'] ?? '') != $data_CRM['name']) { $log->appendLog("DEBUG COMPARACIÓN - Diferencia en name. CallBell: '" . ($contact['name'] ?? 'NULL') . "', UCRM: '" . $data_CRM['name'] . "'" . PHP_EOL); $hasChanges = true; } else { foreach ($data_CRM['custom_fields'] as $key => $value) { if ($key === 'Fecha Ultima Actualizacion') { continue; // Skip this as it always changes and shouldn't trigger a patch on its own } $callBellValue = $contactCustomFields[$key] ?? ''; if ((string)$callBellValue !== (string)$value) { $log->appendLog("DEBUG COMPARACIÓN - Diferencia encontrada en $key. CallBell: '$callBellValue', UCRM: '$value'" . PHP_EOL); $hasChanges = true; break; } } } if ($hasChanges) { $log->appendLog("EJECUTANDO PATCH - Se detectaron cambios" . PHP_EOL); 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 SE EJECUTA PATCH - No hay cambios que actualizar" . PHP_EOL); curl_close($ch); } } 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); $contact = $response_getContactCallBell['contact'] ?? []; $contactCustomFields = $contact['customFields'] ?? []; if (($contactCustomFields['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); } } }