Show validation failure reason and allow manual payment application

When email validation fails (IMAP disabled, no emails, no match), show the
specific reason instead of a generic "No confirmado". Also add a manual
"Aplicar de todas formas" button so the user isn't stuck — they can still
apply the recharge after visually verifying the receipt.

Also show banco/fecha/hora in the Telegram analysis result for context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro
2026-07-18 16:27:56 +00:00
co-authored by Claude Sonnet 4.6
parent b26f6f1130
commit 6c0396d3c0
2 changed files with 49 additions and 9 deletions
+24 -3
View File
@@ -480,19 +480,39 @@ class PublicChat extends Component
return; return;
} }
$resultado = app(\App\Services\PagoValidadorService::class)->validar($datosPago); $resultado = app(\App\Services\PagoValidadorService::class)->validar(
$datosPago, $this->userId, $this->nombreUsuario, 'web'
);
$monto = (int) ($datosPago['valor'] ?? 0);
$botones = []; $botones = [];
if ($resultado['estado'] === 'confirmado') { if ($resultado['estado'] === 'confirmado') {
$botones[] = [ $botones[] = [
'label' => 'Aplicar recarga de $' . number_format($datosPago['valor'] ?? 0), 'label' => 'Aplicar recarga de $' . number_format($monto),
'action' => 'pago.aplicar', 'action' => 'pago.aplicar',
'data' => ['monto' => $datosPago['valor'], 'referencia' => $datosPago['referencia'] ?? null], 'data' => ['monto' => $monto, 'referencia' => $datosPago['referencia'] ?? null],
];
} elseif ($resultado['estado'] !== 'ya_usado') {
// No confirmado: ofrecer aplicar manualmente
$botones[] = [
'label' => 'Aplicar $' . number_format($monto) . ' (manual)',
'action' => 'pago.aplicar',
'data' => ['monto' => $monto, 'referencia' => $datosPago['referencia'] ?? null],
]; ];
} }
$botones[] = ['label' => 'Hablar con asesor', 'action' => 'asesor.solicitar', 'data' => []]; $botones[] = ['label' => 'Hablar con asesor', 'action' => 'asesor.solicitar', 'data' => []];
$botones[] = ['label' => '<- Menu', 'action' => 'menu.principal', 'data' => []]; $botones[] = ['label' => '<- Menu', 'action' => 'menu.principal', 'data' => []];
$motivoTexto = match ($resultado['motivo'] ?? '') {
'correo_deshabilitado' => 'Verificación por correo no configurada',
'error_imap' => 'Error al leer correos IMAP',
'sin_correos' => 'Sin correos recientes en bandeja',
'sin_coincidencia' => 'Ningún correo coincide con este monto/fecha',
default => null,
};
ChatMessage::create([ ChatMessage::create([
'conversation_id' => $this->convId, 'conversation_id' => $this->convId,
'tipo' => 'bot', 'tipo' => 'bot',
@@ -500,6 +520,7 @@ class PublicChat extends Component
'contenido' => 'Resultado del analisis:', 'contenido' => 'Resultado del analisis:',
'payload' => [ 'payload' => [
'estado' => $resultado['estado'], 'estado' => $resultado['estado'],
'motivo' => $motivoTexto,
'ia_datos' => $datosPago, 'ia_datos' => $datosPago,
'botones' => $botones, 'botones' => $botones,
], ],
+23 -4
View File
@@ -207,26 +207,45 @@ class TelegramBotService
); );
$monto = number_format($datosPago['valor'] ?? 0); $monto = number_format($datosPago['valor'] ?? 0);
$ref = $datosPago['referencia'] ?? 'N/A'; $ref = $datosPago['referencia'] ?? 'N/A';
$valor = (int) ($datosPago['valor'] ?? 0);
$texto = "📊 *Resultado del análisis:*\n\n"; $texto = "📊 *Resultado del análisis:*\n\n";
$texto .= "Banco: " . ($datosPago['banco'] ?? 'N/A') . "\n";
$texto .= "Monto: *\$$monto*\n"; $texto .= "Monto: *\$$monto*\n";
$texto .= "Referencia: `{$ref}`\n"; $texto .= "Referencia: `{$ref}`\n";
if ($datosPago['fecha'] ?? null) {
$texto .= "Fecha: " . $datosPago['fecha'];
if ($datosPago['hora'] ?? null) {
$texto .= " " . $datosPago['hora'];
}
$texto .= "\n";
}
if ($resultado['estado'] === 'confirmado') { if ($resultado['estado'] === 'confirmado') {
$texto .= "Estado: *✅ Confirmado*"; $texto .= "\nEstado: *✅ Confirmado por correo*";
$buttons = [ $buttons = [
[['text' => "✅ Aplicar recarga de \$$monto", 'callback_data' => 'pay_apply|' . ($datosPago['valor'] ?? 0) . '|' . $ref]], [['text' => "✅ Aplicar recarga de \$$monto", 'callback_data' => 'pay_apply|' . $valor . '|' . $ref]],
[['text' => '🔙 Menú principal', 'callback_data' => 'menu']], [['text' => '🔙 Menú principal', 'callback_data' => 'menu']],
]; ];
} elseif ($resultado['estado'] === 'ya_usado') { } elseif ($resultado['estado'] === 'ya_usado') {
$texto .= "Estado: *⛔ Comprobante ya utilizado*\nEste pago ya fue registrado por otro usuario."; $texto .= "\nEstado: *⛔ Comprobante ya utilizado*\nEste pago ya fue registrado.";
$buttons = [ $buttons = [
[['text' => '🧑 Hablar con asesor', 'callback_data' => 'agent']], [['text' => '🧑 Hablar con asesor', 'callback_data' => 'agent']],
[['text' => '🔙 Menú principal', 'callback_data' => 'menu']], [['text' => '🔙 Menú principal', 'callback_data' => 'menu']],
]; ];
} else { } else {
$texto .= "Estado: *⚠️ No confirmado*"; $motivo = match ($resultado['motivo'] ?? '') {
'correo_deshabilitado' => '📧 Verificación por correo no configurada',
'error_imap' => '📧 Error al leer correos IMAP',
'sin_correos' => '📧 Sin correos recientes en bandeja',
'sin_coincidencia' => '📧 Ningún correo coincide con este monto/fecha',
default => '📧 No se pudo verificar',
};
$texto .= "\nEstado: *⚠️ No confirmado automáticamente*\n_{$motivo}_";
// Ofrecer aplicar manualmente si el comprobante fue leído correctamente
$buttons = [ $buttons = [
[['text' => "✅ Aplicar \$$monto de todas formas", 'callback_data' => 'pay_apply|' . $valor . '|' . $ref]],
[['text' => '🧑 Hablar con asesor', 'callback_data' => 'agent']], [['text' => '🧑 Hablar con asesor', 'callback_data' => 'agent']],
[['text' => '🔙 Menú principal', 'callback_data' => 'menu']], [['text' => '🔙 Menú principal', 'callback_data' => 'menu']],
]; ];