diff --git a/app/Http/Livewire/Chat/PublicChat.php b/app/Http/Livewire/Chat/PublicChat.php index e78ab29..ec03f21 100755 --- a/app/Http/Livewire/Chat/PublicChat.php +++ b/app/Http/Livewire/Chat/PublicChat.php @@ -475,6 +475,16 @@ class PublicChat extends Component $this->procesandoImagen = true; try { + // Verificar solicitud activa ANTES de cualquier llamada de API + $solicitud = $this->userId ? \App\Models\SolicitudRecarga::pendiente($this->userId) : null; + if (! $solicitud) { + $this->procesandoImagen = false; + $this->fotoComprobante = null; + $this->guardarMensajeBot($this->convId, "⚠️ No tienes ninguna solicitud de recarga activa. Primero inicia el proceso de recarga desde el menú."); + $this->cargarMensajes(); + return; + } + $path = $this->fotoComprobante->store('comprobantes', 'public'); $url = asset('storage/' . $path); @@ -500,21 +510,6 @@ class PublicChat extends Component return; } - $resultado = app(\App\Services\PagoValidadorService::class)->validar( - $datosPago, $this->userId, $this->nombreUsuario, 'web' - ); - - $monto = (int) ($datosPago['valor'] ?? 0); - $botones = []; - - // Verificar solicitud activa - $solicitud = $this->userId ? \App\Models\SolicitudRecarga::pendiente($this->userId) : null; - if (! $solicitud) { - $this->guardarMensajeBot($this->convId, "No tienes ninguna solicitud de recarga activa. Inicia una recarga desde el menu para poder enviar el comprobante."); - $this->cargarMensajes(); - return; - } - // Verificar que el monto coincida con la solicitud $valorIA = (int) ($datosPago['valor'] ?? 0); if ($valorIA !== $solicitud->monto) { @@ -523,6 +518,10 @@ class PublicChat extends Component return; } + $resultado = app(\App\Services\PagoValidadorService::class)->validar( + $datosPago, $this->userId, $this->nombreUsuario, 'web' + ); + $motivo = $resultado['motivo'] ?? ''; if ($resultado['estado'] === 'confirmado') { diff --git a/app/Services/TelegramBotService.php b/app/Services/TelegramBotService.php index 2da7176..86d5d02 100755 --- a/app/Services/TelegramBotService.php +++ b/app/Services/TelegramBotService.php @@ -19,6 +19,7 @@ use App\Models\Usuario_promo; use App\Models\recarga; use App\Models\Role; use App\Models\Saldo; +use App\Models\SolicitudRecarga; use App\Models\Servicio; use App\Models\Tarifas; use App\Models\User; @@ -148,7 +149,6 @@ class TelegramBotService 'history' => $this->showHistory($chatId), 'profile' => $this->showProfile($chatId), 'agent' => $this->showMainMenu($chatId), - 'pay_apply' => $this->applyPayment($chatId, (int) ($parts[1] ?? 0), $parts[2] ?? null), 'pay_retry' => $this->retryPayment($chatId), default => $this->showMainMenu($chatId), }; @@ -169,6 +169,17 @@ class TelegramBotService return; } + $usuarioId = $state['user_id'] ?? null; + $nombreUsuario = $usuarioId ? (User::find($usuarioId)?->name ?? '') : ''; + + // Verificar solicitud de recarga activa ANTES de cualquier llamada de API + $solicitud = $usuarioId ? SolicitudRecarga::pendiente($usuarioId) : null; + if (! $solicitud) { + $this->send($chatId, "⚠️ No tienes ninguna solicitud de recarga activa. Primero inicia el proceso de recarga desde el menú."); + $this->showMainMenu($chatId); + return; + } + $this->send($chatId, "⏳ Analizando tu comprobante..."); try { @@ -180,7 +191,7 @@ class TelegramBotService $base64 = base64_encode($imageData['content']); $mime = $imageData['mime']; - $datosPago = app(GeminiVisionService::class)->extraerPago($base64, $mime, $state['user_id'] ?? null, 'telegram'); + $datosPago = app(GeminiVisionService::class)->extraerPago($base64, $mime, $usuarioId, 'telegram'); if (! $datosPago) { $this->send($chatId, "No pude leer el comprobante. Intenta con una foto más clara."); @@ -197,67 +208,48 @@ class TelegramBotService return; } - $usuarioId = $state['user_id'] ?? null; - $nombreUsuario = $usuarioId ? (User::find($usuarioId)?->name ?? '') : ''; + // Verificar que el monto del comprobante coincida con la solicitud + $valorIA = (int) ($datosPago['valor'] ?? 0); + if ($valorIA !== $solicitud->monto) { + $this->send($chatId, "⚠️ El monto del comprobante (*\$" . number_format($valorIA) . "*) no coincide con tu solicitud de recarga (*\$" . number_format($solicitud->monto) . "*)."); + $this->showMainMenu($chatId); + return; + } $resultado = app(PagoValidadorService::class)->validar( $datosPago, $usuarioId, $nombreUsuario, 'telegram' ); - $monto = number_format($datosPago['valor'] ?? 0); - $ref = $datosPago['referencia'] ?? 'N/A'; - $valor = (int) ($datosPago['valor'] ?? 0); - - $texto = "📊 *Resultado del análisis:*\n\n"; - $texto .= "Banco: " . ($datosPago['banco'] ?? 'N/A') . "\n"; - $texto .= "Monto: *\$$monto*\n"; - $texto .= "Referencia: `{$ref}`\n"; - if ($datosPago['fecha'] ?? null) { - $texto .= "Fecha: " . $datosPago['fecha']; - if ($datosPago['hora'] ?? null) { - $texto .= " " . $datosPago['hora']; - } - $texto .= "\n"; - } + $motivo = $resultado['motivo'] ?? ''; if ($resultado['estado'] === 'confirmado') { - $texto .= "\nEstado: *✅ Confirmado por correo*"; - $buttons = [ - [['text' => "✅ Aplicar recarga de \$$monto", 'callback_data' => 'pay_apply|' . $valor . '|' . $ref]], - [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], - ]; - } elseif ($resultado['estado'] === 'ya_usado') { - $texto .= "\nEstado: *⛔ Comprobante ya utilizado*\nEste pago ya fue registrado anteriormente."; - $buttons = [ - [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], - ]; - } else { - $motivo = $resultado['motivo'] ?? ''; - if ($motivo === 'sin_coincidencia' || $motivo === 'sin_correos') { - // Guardar datosPago en estado para poder reintentar sin reenviar foto - $state['data']['pago_pendiente'] = $datosPago; - $this->setState($chatId, $state); + $this->autoAplicarRecarga($chatId, $state, $solicitud, $valorIA); - $texto .= "\nEstado: *⏳ Por ahora no encontramos tu pago de confirmación*\n" - . "_Puede demorar entre 1 y 2 minutos en llegar. Espera un momento y presiona Reintentar._"; - $buttons = [ + } elseif ($resultado['estado'] === 'ya_usado') { + $this->sendWithKeyboard($chatId, "⛔ *Comprobante ya utilizado.*\nEste pago ya fue registrado anteriormente.", [ + [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], + ]); + + } elseif ($motivo === 'sin_coincidencia' || $motivo === 'sin_correos') { + $state['data']['pago_pendiente'] = $datosPago; + $this->setState($chatId, $state); + $this->sendWithKeyboard($chatId, + "⏳ *Por ahora no encontramos tu pago de confirmación.*\n_Puede demorar entre 1 y 2 minutos en llegar. Espera un momento y presiona Reintentar._", + [ [['text' => '🔄 Reintentar', 'callback_data' => 'pay_retry']], [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], - ]; - } else { - $motivoTexto = match ($motivo) { - 'correo_deshabilitado' => '📧 Verificación por correo no configurada', - 'error_imap' => '📧 Error al leer correos IMAP', - 'error_sistema' => '⚙️ Error interno, intenta de nuevo en unos minutos', - default => '📧 No se pudo verificar automáticamente', - }; - $texto .= "\nEstado: *⚠️ No confirmado*\n_{$motivoTexto}_"; - $buttons = [ - [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], - ]; - } + ] + ); + } else { + $motivoTexto = match ($motivo) { + 'correo_deshabilitado' => '📧 Verificación por correo no configurada', + 'error_imap' => '📧 Error al leer correos IMAP', + 'error_sistema' => '⚙️ Error interno, intenta de nuevo en unos minutos', + default => '📧 No se pudo verificar automáticamente', + }; + $this->sendWithKeyboard($chatId, "⚠️ *No confirmado*\n_{$motivoTexto}_", [ + [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], + ]); } - - $this->sendWithKeyboard($chatId, $texto, $buttons); } catch (\Throwable $e) { Log::warning('[TelegramBot] Error procesando foto: ' . $e->getMessage()); $this->send($chatId, "Error analizando el comprobante. Por favor intenta de nuevo."); @@ -266,34 +258,31 @@ class TelegramBotService private function retryPayment(string $chatId): void { - $state = $this->getState($chatId); + $state = $this->getState($chatId); $this->convId = $state['conv_id'] ?? null; - $datosPago = $state['data']['pago_pendiente'] ?? null; + $datosPago = $state['data']['pago_pendiente'] ?? null; + $usuarioId = $state['user_id'] ?? null; - if (! $datosPago) { + if (! $datosPago || ! $usuarioId) { $this->send($chatId, "No hay ningún comprobante pendiente. Envía la foto de tu comprobante."); return; } + $solicitud = SolicitudRecarga::pendiente($usuarioId); + if (! $solicitud) { + $this->send($chatId, "⚠️ Tu solicitud de recarga expiró. Inicia una nueva recarga desde el menú."); + $this->showMainMenu($chatId); + return; + } + $this->send($chatId, "⏳ Verificando de nuevo..."); - $usuarioId = $state['user_id'] ?? null; - $nombreUsuario = $usuarioId ? (User::find($usuarioId)?->name ?? '') : ''; - - $resultado = app(PagoValidadorService::class)->validar($datosPago, $usuarioId, $nombreUsuario, 'telegram'); - $monto = number_format($datosPago['valor'] ?? 0); - $ref = $datosPago['referencia'] ?? 'N/A'; - $valor = (int) ($datosPago['valor'] ?? 0); + $nombreUsuario = User::find($usuarioId)?->name ?? ''; + $resultado = app(PagoValidadorService::class)->validar($datosPago, $usuarioId, $nombreUsuario, 'telegram'); + $motivo = $resultado['motivo'] ?? ''; if ($resultado['estado'] === 'confirmado') { - $buttons = [ - [['text' => "✅ Aplicar recarga de \$$monto", 'callback_data' => 'pay_apply|' . $valor . '|' . $ref]], - [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], - ]; - // Limpiar pago pendiente del estado - unset($state['data']['pago_pendiente']); - $this->setState($chatId, $state); - $this->sendWithKeyboard($chatId, "✅ *¡Pago confirmado!* Tu recarga de \$$monto está lista.", $buttons); + $this->autoAplicarRecarga($chatId, $state, $solicitud, $solicitud->monto); } elseif ($resultado['estado'] === 'ya_usado') { unset($state['data']['pago_pendiente']); @@ -303,7 +292,6 @@ class TelegramBotService ]); } else { - // Sigue sin encontrarse — dejar pendiente para otro reintento $this->sendWithKeyboard($chatId, "⏳ *Aún no encontramos tu pago.*\nPuede demorar entre 1 y 2 minutos en llegar. Espera un momento y presiona Reintentar.", [ @@ -314,6 +302,26 @@ class TelegramBotService } } + private function autoAplicarRecarga(string $chatId, array $state, SolicitudRecarga $solicitud, int $monto): void + { + $usuarioId = $state['user_id']; + $user = User::with('saldo')->find($usuarioId); + $saldo = $user->saldo ?? Saldo::create(['usuario_id' => $usuarioId, 'valor' => 0]); + $nuevoSaldo = $saldo->valor + $monto; + $saldo->update(['valor' => $nuevoSaldo]); + + $solicitud->confirmar(); + + unset($state['data']['pago_pendiente'], $state['data']['solicitud_recarga_id']); + $this->setState($chatId, $state); + + $this->send($chatId, + "✅ *¡Tu recarga de \$" . number_format($monto) . " fue aplicada exitosamente!*\n" + . "Tu nuevo saldo es *\$" . number_format($nuevoSaldo) . "*" + ); + $this->showMainMenu($chatId); + } + public function handleVoice(string $chatId, string $fileId, string $nombre = '', int $duracionSegundos = 0): void { $state = $this->getState($chatId); @@ -1216,6 +1224,14 @@ class TelegramBotService $text .= "\n⚠️ Después de transferir, envía la *foto del comprobante* aquí y el sistema lo validará automáticamente." . "\n_Tienes hasta 15 minutos después de la transferencia para enviar el soporte._"; + // Registrar solicitud de recarga pendiente + if ($userId = ($this->getState($chatId)['user_id'] ?? null)) { + $solicitud = SolicitudRecarga::crear($userId, $monto, 'telegram'); + $state = $this->getState($chatId); + $state['data']['solicitud_recarga_id'] = $solicitud->id; + $this->setState($chatId, $state); + } + $this->sendWithKeyboard($chatId, $text, [ [['text' => '🔙 Menú principal', 'callback_data' => 'menu']], ]);