Modificaciones para enviar referencias de OXXO PAGO por medio de imagen

This commit is contained in:
server 2025-06-10 02:46:31 -06:00
parent c73a51bbf2
commit 8d8a1ec648
14 changed files with 2633 additions and 63841 deletions

5
.gitignore vendored
View File

@ -1,5 +1,8 @@
*.pdf *.pdf
*.log *.log
*.png *.png
*.jpeg
.vscode/ .vscode/
*.zip *.zip
vouchers_oxxo/
comprobantes/

View File

@ -4,6 +4,15 @@ Este plugin sincroniza los clientes del sitema UISP CRM con los contactos de Wha
## REGISTRO DE CAMBIOS ## REGISTRO DE CAMBIOS
# VERSIÓN 2.8.7
## 🟢 Novedades
1⃣ Ahora las referencias de OXXO Pago han cambiado, en lugar de enviarse la URL o link de pago al cliente será la imagen del código de barras y la información que aparece en el link directamente en el mensaje, de esta manera será más cómodo para el cliente tener la imagen en su chat a tener que abrir una URL o link externo.
## 🔵 Mejoras
1⃣ Se modificaron nodos del bot OXXO_BOT para poder adaptar esta actualización correctamente
2⃣ Mejoras en el código fuente del flujo de trabajo para las referencias de OXXO PAGO.
# VERSIÓN 2.8.6 # VERSIÓN 2.8.6
## 🔵 Mejoras ## 🔵 Mejoras
1⃣ Se modificó la información para el envío de notificaciones a llos instaladores en el flujo de trabajo para la desasignación de tareas que hacía que no se viera correctamente la información 1⃣ Se modificó la información para el envío de notificaciones a llos instaladores en el flujo de trabajo para la desasignación de tareas que hacía que no se viera correctamente la información

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
"displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp", "displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp",
"description": "Este plugin sincroniza los clientes del sistema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes", "description": "Este plugin sincroniza los clientes del sistema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes",
"url": "https://siip.mx/", "url": "https://siip.mx/",
"version": "2.8.6", "version": "2.8.7",
"unmsVersionCompliancy": { "unmsVersionCompliancy": {
"min": "2.1.0", "min": "2.1.0",
"max": null "max": null

View File

@ -233,7 +233,6 @@ abstract class AbstractMessageNotifierFacade
$this->logger->debug('Valor de $jsonNotificationData en verifyJobActionToDo: ' . json_encode($jsonNotificationData) . PHP_EOL); $this->logger->debug('Valor de $jsonNotificationData en verifyJobActionToDo: ' . json_encode($jsonNotificationData) . PHP_EOL);
$this->logger->debug('Valor de $jsonNotificationData en verifyJobActionToDo: ' . json_encode($jsonNotificationData) . PHP_EOL);
$clientId = $jsonNotificationData['extraData']['entity']['clientId']; $clientId = $jsonNotificationData['extraData']['entity']['clientId'];
$installerId = $jsonNotificationData['extraData']['entity']['assignedUserId']; $installerId = $jsonNotificationData['extraData']['entity']['assignedUserId'];
$jobId = $jsonNotificationData['entityId']; $jobId = $jsonNotificationData['entityId'];
@ -412,24 +411,24 @@ abstract class AbstractMessageNotifierFacade
// Procesar cada número // Procesar cada número
$resultados = []; $resultados = [];
foreach ($arrayNumeros as $numero) { foreach ($arrayNumeros as $numero) {
// Limpiar espacios alrededor de cada número
$numero = trim($numero); $numero = trim($numero);
// Validar el número
$numeroValidado = $this->validarNumeroTelefono($numero); $numeroValidado = $this->validarNumeroTelefono($numero);
// Remover el prefijo 521 si está presente y tiene 12 dígitos // Asegurar que solo quedan números
if (substr($numeroValidado, 0, 3) === "521" && strlen($numeroValidado) === 12) { $numeroValidado = preg_replace('/\D/', '', $numeroValidado);
$resultados[] = substr($numeroValidado, 3); // Remover "521"
// 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 { } else {
$resultados[] = $numeroValidado; // Mantener el número sin cambios $resultados[] = $numeroValidado;
} }
} }
$this->logger->debug('Valor de $resultados en verifyJobActionToDo: ' . json_encode($resultados) . PHP_EOL); $this->logger->debug('Valor de $resultados en verifyJobActionToDo: ' . json_encode($resultados) . PHP_EOL);
// Convertir el array de resultados en una cadena separada por comas // Convertir el array de resultados en una cadena separada por comas
$resultadoFinalNumerosCliente = implode(', ', $resultados); $resultadoFinalNumerosCliente = implode(', ', $resultados);
// $this->logger->debug('Valor de $resultadoFinalNumerosCliente en verifyJobActionToDo: ' . $resultadoFinalNumerosCliente . PHP_EOL); $this->logger->debug('Valor de $resultadoFinalNumerosCliente en verifyJobActionToDo: ' . $resultadoFinalNumerosCliente . PHP_EOL);
$client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken); $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);

View File

@ -11,6 +11,9 @@ use SmsNotifier\Service\SmsNumberProvider;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Exception\RequestException;
use Ubnt\UcrmPluginSdk\Service\UcrmApi; use Ubnt\UcrmPluginSdk\Service\UcrmApi;
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
use Ubnt\UcrmPluginSdk\Service\PluginLogManager;
use Dompdf\Dompdf;
/* /*
@ -60,28 +63,28 @@ abstract class AbstractOxxoOperationsFacade
* @throws \Stripe\Exception\ApiErrorException * @throws \Stripe\Exception\ApiErrorException
* @throws Exception * @throws Exception
*/ */
public function createOxxoPaymentIntent($event_json, $amount = null): array public function createOxxoPaymentIntent($event_json, $amount = null): array
{ {
//declarar un array asociativo de strings pero no asignarle nada aun //declarar un array asociativo de strings pero no asignarle nada aun
$arrayOxxoPayment = array(); $arrayOxxoPayment = array();
$integerAmount = $amount; $integerAmount = $amount;
$this->logger->info("Creando referencia del cliente para OXXO: " . PHP_EOL); $this->logger->info("Creando referencia del cliente para OXXO: " . PHP_EOL);
$configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create(); $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
$config = $configManager->loadConfig(); $config = $configManager->loadConfig();
$StripeToken = $config['tokenstripe']; $StripeToken = $config['tokenstripe'];
$IPServer = $config['ipserver']; $IPServer = $config['ipserver'];
$tokenCRM = $config['apitoken']; $tokenCRM = $config['apitoken'];
$baseUri = 'https://' . $IPServer . '/crm/api/v1.0/'; $baseUri = 'https://' . $IPServer . '/crm/api/v1.0/';
$this->ucrmApi = UcrmApi::create(); $this->ucrmApi = UcrmApi::create();
$currentUserAdmin = $this->ucrmApi->get('users/admins', []); $currentUserAdmin = $this->ucrmApi->get('users/admins', []);
$clientID = $event_json['client_id']; $clientID = $event_json['client_id'];
$stripeCustomerId = null; $stripeCustomerId = null;
$clientEmail = ''; $clientEmail = '';
$clientFullName = ''; $clientFullName = '';
$clientGuzzleHttp = new Client([ $clientGuzzleHttp = new Client([
'base_uri' => $baseUri, 'base_uri' => $baseUri,
'headers' => [ 'headers' => [
@ -91,7 +94,7 @@ abstract class AbstractOxxoOperationsFacade
'verify' => false, 'verify' => false,
'timeout' => 5, // Timeout de 5 segundos 'timeout' => 5, // Timeout de 5 segundos
]); ]);
try { try {
$response = $clientGuzzleHttp->request('GET', "clients/" . $clientID); $response = $clientGuzzleHttp->request('GET', "clients/" . $clientID);
$arrayClientCRM = json_decode($response->getBody()->getContents(), true); $arrayClientCRM = json_decode($response->getBody()->getContents(), true);
@ -108,9 +111,10 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
//timeout //timeout
if ($e->getCode() === 408) { if ($e->getCode() === 408) {
@ -123,6 +127,7 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
$this->logger->error("Error al obtener el cliente en CRM (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL); $this->logger->error("Error al obtener el cliente en CRM (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
@ -134,10 +139,11 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
// Obtener email del cliente // Obtener email del cliente
foreach ($arrayClientCRM['contacts'] as $contact) { foreach ($arrayClientCRM['contacts'] as $contact) {
if (!empty($contact['email'])) { if (!empty($contact['email'])) {
@ -147,7 +153,7 @@ abstract class AbstractOxxoOperationsFacade
$clientEmail = 'siip8873@gmail.com'; // Default $clientEmail = 'siip8873@gmail.com'; // Default
} }
} }
try { try {
// Obtener stripeCustomerId // Obtener stripeCustomerId
foreach ($arrayClientCRM['attributes'] as $attribute) { foreach ($arrayClientCRM['attributes'] as $attribute) {
@ -156,7 +162,7 @@ abstract class AbstractOxxoOperationsFacade
break; break;
} }
} }
$this->logger->info("Stripe Customer ID obtenido: " . $stripeCustomerId . PHP_EOL); $this->logger->info("Stripe Customer ID obtenido: " . $stripeCustomerId . PHP_EOL);
} catch (Exception $e) { } catch (Exception $e) {
$this->logger->error("Error al obtener el Customer ID de Stripe (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL); $this->logger->error("Error al obtener el Customer ID de Stripe (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
@ -167,24 +173,25 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
if ($amount === null) { if ($amount === null) {
$amount = abs($arrayClientCRM['accountOutstanding']); $amount = abs($arrayClientCRM['accountOutstanding']);
} else { } else {
$this->logger->info("Monto proporcionado directamente: $amount " . PHP_EOL); $this->logger->info("Monto proporcionado directamente: $amount " . PHP_EOL);
} }
if ($amount > 10) { if ($amount > 10) {
$amount = intval($amount * 100); $amount = intval($amount * 100);
try { try {
$this->logger->info("Creando referencia en Stripe por $amount para el cliente $stripeCustomerId" . PHP_EOL); $this->logger->info("Creando referencia en Stripe por $amount para el cliente $stripeCustomerId" . PHP_EOL);
$guzzleClient = new Client([ $guzzleClient = new Client([
'timeout' => 5, 'timeout' => 5, // Timeout de 5 segundos
]); ]);
$response = $guzzleClient->post('https://api.stripe.com/v1/payment_intents', [ $response = $guzzleClient->post('https://api.stripe.com/v1/payment_intents', [
'auth' => [$StripeToken, ''], 'auth' => [$StripeToken, ''],
'form_params' => [ 'form_params' => [
@ -207,9 +214,9 @@ abstract class AbstractOxxoOperationsFacade
], ],
] ]
]); ]);
$paymentIntent = json_decode($response->getBody()->getContents(), true); $paymentIntent = json_decode($response->getBody()->getContents(), true);
} catch (\Stripe\Exception\ApiConnectionException $e) { } catch (\Stripe\Exception\ApiConnectionException $e) {
$this->logger->error("Error de conexión con Stripe (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL); $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 //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
@ -220,8 +227,9 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} catch (\Stripe\Exception\ApiErrorException $e) { } catch (\Stripe\Exception\ApiErrorException $e) {
$this->logger->error("Error de la API de Stripe: " . $e->getMessage() . PHP_EOL); $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 //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
@ -232,15 +240,16 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} catch (Exception $e) { } catch (Exception $e) {
$this->logger->error("Error inesperado al crear PaymentIntent (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL); $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" //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...)'){ 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); $this->logger->error("Este cliente no tiene cuenta de Stripe" . PHP_EOL);
$arrayOxxoPayment['failDescription'] = 'Este cliente no tiene cuenta de Stripe: ' . $clientID; $arrayOxxoPayment['failDescription'] = 'Este cliente no tiene cuenta de Stripe: ' . $clientID;
}else{ } else {
$this->logger->error("Error inesperado al crear PaymentIntent: " . $e->getMessage() . PHP_EOL); $this->logger->error("Error inesperado al crear PaymentIntent: " . $e->getMessage() . PHP_EOL);
$arrayOxxoPayment['failDescription'] = 'Error inesperado al crear PaymentIntent: ' . $clientID; $arrayOxxoPayment['failDescription'] = 'Error inesperado al crear PaymentIntent: ' . $clientID;
} }
@ -249,16 +258,17 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['url'] = ''; $arrayOxxoPayment['url'] = '';
$arrayOxxoPayment['error'] = 'errorCreatePaymentIntent'; $arrayOxxoPayment['error'] = 'errorCreatePaymentIntent';
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
try { try {
$firstName = isset($arrayClientCRM['firstName']) ? trim($arrayClientCRM['firstName']) : ''; $firstName = isset($arrayClientCRM['firstName']) ? trim($arrayClientCRM['firstName']) : '';
$lastName = isset($arrayClientCRM['lastName']) ? trim($arrayClientCRM['lastName']) : ''; $lastName = isset($arrayClientCRM['lastName']) ? trim($arrayClientCRM['lastName']) : '';
if (strlen($firstName) < 2 || strlen($lastName) < 2) { if (strlen($firstName) < 2 || strlen($lastName) < 2) {
$this->logger->error("Nombre/apellido inválido: ' . $firstName . ' ' . $lastName" . PHP_EOL); $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 //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
@ -269,10 +279,11 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
$responsePaymentMethod = $guzzleClient->post('https://api.stripe.com/v1/payment_methods', [ $responsePaymentMethod = $guzzleClient->post('https://api.stripe.com/v1/payment_methods', [
'auth' => [$StripeToken, ''], 'auth' => [$StripeToken, ''],
'form_params' => [ 'form_params' => [
@ -283,18 +294,18 @@ abstract class AbstractOxxoOperationsFacade
], ],
] ]
]); ]);
$paymentMethod = json_decode($responsePaymentMethod->getBody()->getContents(), true); $paymentMethod = json_decode($responsePaymentMethod->getBody()->getContents(), true);
$responseConfirmPaymentIntent = $guzzleClient->post('https://api.stripe.com/v1/payment_intents/' . $paymentIntent['id'] . '/confirm', [ $responseConfirmPaymentIntent = $guzzleClient->post('https://api.stripe.com/v1/payment_intents/' . $paymentIntent['id'] . '/confirm', [
'auth' => [$StripeToken, ''], 'auth' => [$StripeToken, ''],
'form_params' => [ 'form_params' => [
'payment_method' => $paymentMethod['id'], 'payment_method' => $paymentMethod['id'],
] ]
]); ]);
$paymentIntentConfirm = json_decode($responseConfirmPaymentIntent->getBody()->getContents(), true); $paymentIntentConfirm = json_decode($responseConfirmPaymentIntent->getBody()->getContents(), true);
} catch (Exception $e) { } catch (Exception $e) {
$this->logger->error("Error al confirmar PaymentIntent: " . $e->getMessage() . PHP_EOL); $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 //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
@ -305,26 +316,110 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
if (!empty($paymentIntentConfirm['next_action']) && isset($paymentIntentConfirm['next_action']['oxxo_display_details'])) { if (!empty($paymentIntentConfirm['next_action']) && isset($paymentIntentConfirm['next_action']['oxxo_display_details'])) {
$oxxoPayment = $paymentIntentConfirm['next_action']['oxxo_display_details']; $oxxoPayment = $paymentIntentConfirm['next_action']['oxxo_display_details'];
$oxxo_reference = $oxxoPayment['number']; $oxxo_reference = $oxxoPayment['number'];
$oxxo_receipt_url = $oxxoPayment['hosted_voucher_url']; $oxxo_receipt_url = $oxxoPayment['hosted_voucher_url'];
$this->logger->info("Referencia OXXO: " . $oxxo_reference . PHP_EOL); $this->logger->info("Referencia OXXO: " . $oxxo_reference . PHP_EOL);
$this->logger->info("URL del recibo: " . $oxxo_receipt_url . PHP_EOL); $this->logger->info("URL del recibo: " . $oxxo_receipt_url . PHP_EOL);
//$this->captureScreenshot($oxxo_receipt_url); //$this->captureScreenshot($oxxo_receipt_url);
//devolver un array con los campos de url de oxxo, descripción de la falla, clientID y amount //devolver un array con los campos de url de oxxo, descripción de la falla, clientID y amount
$arrayOxxoPayment['oxxo_reference'] = $oxxo_reference; $arrayOxxoPayment['oxxo_reference'] = $oxxo_reference;
$arrayOxxoPayment['url'] = $oxxo_receipt_url; $arrayOxxoPayment['url'] = $oxxo_receipt_url;
$arrayOxxoPayment['error'] = '';
$arrayOxxoPayment['failDescription'] = '';
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['failDescription'] = '';
$arrayOxxoPayment['error'] = '';
$this->logger->info("Referencia OXXO creada correctamente." . PHP_EOL); $this->logger->info("Referencia OXXO creada correctamente." . PHP_EOL);
// Configuración de la API de tu servicio Docker de Puppeteer
$api_url = 'http://172.16.5.134:3000/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; return $arrayOxxoPayment;
} else { } else {
$this->logger->info("El PaymentIntent no tiene detalles de OXXO disponibles. Estado: " . $paymentIntentConfirm['status'] . PHP_EOL); $this->logger->info("El PaymentIntent no tiene detalles de OXXO disponibles. Estado: " . $paymentIntentConfirm['status'] . PHP_EOL);
@ -336,10 +431,11 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
} else { } else {
$this->logger->info("Este cliente no tiene adeudos." . PHP_EOL); $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 //devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
@ -350,6 +446,7 @@ abstract class AbstractOxxoOperationsFacade
$arrayOxxoPayment['clientID'] = $clientID; $arrayOxxoPayment['clientID'] = $clientID;
$arrayOxxoPayment['clientFullName'] = $clientFullName; $arrayOxxoPayment['clientFullName'] = $clientFullName;
$arrayOxxoPayment['amount'] = $integerAmount; $arrayOxxoPayment['amount'] = $integerAmount;
$arrayOxxoPayment['voucher_image_url'] = '';
return $arrayOxxoPayment; return $arrayOxxoPayment;
} }
} }
@ -372,7 +469,7 @@ abstract class AbstractOxxoOperationsFacade
function validarEmail($email) function validarEmail($email)
{ {
$this->logger->info('SE VALIDA EL EMAIL!!! ' . PHP_EOL); $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 // Utilizar la función filter_var con el filtro FILTER_VALIDATE_EMAIL para validar el email
if (filter_var($email, FILTER_VALIDATE_EMAIL)) { if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
// Si el email es válido, devolver el email // Si el email es válido, devolver el email
@ -492,36 +589,177 @@ abstract class AbstractOxxoOperationsFacade
/** /**
* Función para capturar una pantalla de una URL usando el servicio Puppeteer. * Función para capturar una pantalla de una URL usando el servicio Puppeteer.
* *
* @param string $url La URL de la página web que se desea capturar. * @param string $url La URL de la página web que se desea capturar.
* @return string La ruta del archivo de la captura de pantalla. * @return string La ruta del archivo de la captura de pantalla.
*/ */
function captureScreenshot($url) { function captureScreenshot($url)
// URL del servicio Puppeteer {
$puppeteerUrl = 'http://172.16.5.134:4000'; // URL del servicio Puppeteer
$puppeteerUrl = 'http://172.16.5.134:4000';
// Datos a enviar // Datos a enviar
$data = http_build_query(['url' => $url]); $data = http_build_query(['url' => $url]);
// Configurar la solicitud POST // Configurar la solicitud POST
$options = [ $options = [
'http' => [ 'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST', 'method' => 'POST',
'content' => $data, 'content' => $data,
], ],
]; ];
// Ejecutar la solicitud // Ejecutar la solicitud
$context = stream_context_create($options); $context = stream_context_create($options);
$response = file_get_contents($puppeteerUrl, false, $context); $response = file_get_contents($puppeteerUrl, false, $context);
if ($response === false) { if ($response === false) {
throw new Exception("Error al comunicarse con el servicio Puppeteer."); throw new Exception("Error al comunicarse con el servicio Puppeteer.");
}
return trim($response);
} }
return trim($response); 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;
}
}
} }

View File

@ -185,6 +185,8 @@ class Plugin
//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 //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 = '{' . $response = '{' .
'"url": "' . $responseOxxo['url'] . '",' . '"url": "' . $responseOxxo['url'] . '",' .
'"oxxo_reference": "' . $responseOxxo['oxxo_reference'] . '",' .
'"voucher_image_url": "' . $responseOxxo['voucher_image_url'] . '",' .
'"error": "' . $responseOxxo['error'] . '",' . '"error": "' . $responseOxxo['error'] . '",' .
'"failDescription": "' . $responseOxxo['failDescription'] . '",' . '"failDescription": "' . $responseOxxo['failDescription'] . '",' .
'"clientID": "' . $responseOxxo['clientID'] . '",' . '"clientID": "' . $responseOxxo['clientID'] . '",' .
@ -201,6 +203,7 @@ class Plugin
$response = '{' . $response = '{' .
'"url": "' . $responseOxxo['url'] . '",' . '"url": "' . $responseOxxo['url'] . '",' .
'"oxxo_reference": "' . $responseOxxo['oxxo_reference'] . '",' . '"oxxo_reference": "' . $responseOxxo['oxxo_reference'] . '",' .
'"voucher_image_url": "' . $responseOxxo['voucher_image_url'] . '",' .
'"error": "' . $responseOxxo['error'] . '",' . '"error": "' . $responseOxxo['error'] . '",' .
'"failDescription": "' . $responseOxxo['failDescription'] . '",' . '"failDescription": "' . $responseOxxo['failDescription'] . '",' .
'"clientID": "' . $responseOxxo['clientID'] . '",' . '"clientID": "' . $responseOxxo['clientID'] . '",' .

File diff suppressed because it is too large Load Diff

View File

@ -34,13 +34,22 @@ class ComposerAutoloaderInitd6442a7ec79f2f43fc97d16bdcdd18ee
call_user_func(\Composer\Autoload\ComposerStaticInitd6442a7ec79f2f43fc97d16bdcdd18ee::getInitializer($loader)); call_user_func(\Composer\Autoload\ComposerStaticInitd6442a7ec79f2f43fc97d16bdcdd18ee::getInitializer($loader));
} else { } else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php'; $classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) { if ($classMap) {
$loader->addClassMap($classMap); $loader->addClassMap($classMap);
} }
} }
$loader->setClassMapAuthoritative(true);
$loader->register(true); $loader->register(true);
if ($useStaticLoader) { if ($useStaticLoader) {

File diff suppressed because it is too large Load Diff

View File

@ -2040,6 +2040,6 @@
"install-path": "../ubnt/ucrm-plugin-sdk" "install-path": "../ubnt/ucrm-plugin-sdk"
} }
], ],
"dev": false, "dev": true,
"dev-package-names": [] "dev-package-names": []
} }

View File

@ -5,9 +5,9 @@
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => '5374054289a4a615c4f2ae96ca75200ff1a7b830', 'reference' => 'c73a51bbf23d230c7a46654cf8b95a51f7da5d13',
'name' => 'ucrm-plugins/sms-twilio', 'name' => 'ucrm-plugins/sms-twilio',
'dev' => false, 'dev' => true,
), ),
'versions' => array( 'versions' => array(
'firebase/php-jwt' => array( 'firebase/php-jwt' => array(
@ -307,7 +307,7 @@
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => '5374054289a4a615c4f2ae96ca75200ff1a7b830', 'reference' => 'c73a51bbf23d230c7a46654cf8b95a51f7da5d13',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
), ),