Files
whatsapp/services/PatientDataValidator.php
T
2026-01-13 01:48:33 -05:00

316 lines
9.7 KiB
PHP

<?php
/**
* Validadores de Datos del Paciente
* Valida información para agendamientos y procesos
*/
class PatientDataValidator
{
/**
* Valida todos los datos del paciente para agendamiento
* @param array $data
* @return array ['valid' => bool, 'errors' => array, 'data' => array]
*/
public static function validateAppointmentData(array $data): array
{
$errors = [];
$validData = [];
// Nombre completo
if (empty($data['nombre'])) {
$errors[] = "Falta el nombre completo";
} elseif (!self::validateFullName($data['nombre'])) {
$errors[] = "El nombre debe tener al menos nombre y apellido";
} else {
$validData['nombre'] = self::sanitizeName($data['nombre']);
}
// Documento
if (empty($data['documento'])) {
$errors[] = "Falta el número de documento";
} elseif (!self::validateDocument($data['documento'])) {
$errors[] = "El documento debe tener entre 6 y 11 dígitos";
} else {
$validData['documento'] = self::sanitizeDocument($data['documento']);
}
// Dirección
if (empty($data['direccion'])) {
$errors[] = "Falta la dirección completa";
} elseif (strlen($data['direccion']) < 10) {
$errors[] = "La dirección debe ser más específica (mínimo 10 caracteres)";
} else {
$validData['direccion'] = trim($data['direccion']);
}
// Teléfono
if (empty($data['telefono'])) {
$errors[] = "Falta el número de celular";
} elseif (!self::validatePhone($data['telefono'])) {
$errors[] = "El número de celular debe tener 10 dígitos y comenzar con 3";
} else {
$validData['telefono'] = self::sanitizePhone($data['telefono']);
}
// Email
if (empty($data['email'])) {
$errors[] = "Falta el correo electrónico";
} elseif (!self::validateEmail($data['email'])) {
$errors[] = "El correo electrónico no es válido";
} else {
$validData['email'] = strtolower(trim($data['email']));
}
// Tipo (particular/seguro)
if (empty($data['tipo'])) {
$errors[] = "Falta indicar si es particular o por seguro";
} else {
$tipo = strtolower(trim($data['tipo']));
if (strpos($tipo, 'particular') !== false) {
$validData['tipo'] = 'particular';
} elseif (strpos($tipo, 'seguro') !== false || strpos($tipo, 'eps') !== false) {
$validData['tipo'] = 'seguro';
// Extraer nombre del seguro si lo menciona
$validData['nombre_seguro'] = self::extractInsuranceName($data['tipo']);
} else {
$errors[] = "Debe indicar 'particular' o 'seguro'";
}
}
return [
'valid' => empty($errors),
'errors' => $errors,
'data' => $validData
];
}
/**
* Valida un nombre completo
* @param string $name
* @return bool
*/
public static function validateFullName(string $name): bool
{
$name = trim($name);
// Debe tener al menos 2 palabras
$words = preg_split('/\s+/', $name);
if (count($words) < 2) {
return false;
}
// Solo debe contener letras y espacios
return preg_match('/^[a-záéíóúñA-ZÁÉÍÓÚÑ\s]+$/u', $name);
}
/**
* Valida un número de documento
* @param string $document
* @return bool
*/
public static function validateDocument(string $document): bool
{
$doc = preg_replace('/[^0-9]/', '', $document);
$length = strlen($doc);
return $length >= 6 && $length <= 11;
}
/**
* Valida un número de teléfono colombiano
* @param string $phone
* @return bool
*/
public static function validatePhone(string $phone): bool
{
$phone = preg_replace('/[^0-9]/', '', $phone);
// Debe tener 10 dígitos y comenzar con 3
return strlen($phone) === 10 && $phone[0] === '3';
}
/**
* Valida un correo electrónico
* @param string $email
* @return bool
*/
public static function validateEmail(string $email): bool
{
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
/**
* Sanitiza un nombre
* @param string $name
* @return string
*/
public static function sanitizeName(string $name): string
{
// Convertir a formato título (Primera Letra Mayúscula)
$name = mb_convert_case(trim($name), MB_CASE_TITLE, 'UTF-8');
// Remover espacios extras
$name = preg_replace('/\s+/', ' ', $name);
return $name;
}
/**
* Sanitiza un documento
* @param string $document
* @return string
*/
public static function sanitizeDocument(string $document): string
{
return preg_replace('/[^0-9]/', '', $document);
}
/**
* Sanitiza un teléfono
* @param string $phone
* @return string
*/
public static function sanitizePhone(string $phone): string
{
$phone = preg_replace('/[^0-9]/', '', $phone);
// Si tiene 13 dígitos y empieza con 57, quitar el 57
if (strlen($phone) === 12 && substr($phone, 0, 2) === '57') {
$phone = substr($phone, 2);
}
return $phone;
}
/**
* Extrae el nombre del seguro del texto
* @param string $text
* @return string|null
*/
private static function extractInsuranceName(string $text): ?string
{
$insurances = [
'colsanitas' => 'Colsanitas',
'sanitas' => 'Sanitas',
'sura' => 'Sura',
'compensar' => 'Compensar',
'salud total' => 'Salud Total',
'famisanar' => 'Famisanar',
'nueva eps' => 'Nueva EPS',
'coomeva' => 'Coomeva'
];
$textLower = strtolower($text);
foreach ($insurances as $key => $name) {
if (strpos($textLower, $key) !== false) {
return $name;
}
}
return null;
}
/**
* Parsea datos del paciente desde un mensaje de texto
* @param string $message
* @return array
*/
public static function parsePatientDataFromMessage(string $message): array
{
$data = [];
// Dividir por líneas
$lines = explode("\n", $message);
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) {
continue;
}
// Detectar nombre (primera línea larga con letras)
if (empty($data['nombre']) && preg_match('/^[a-záéíóúñA-ZÁÉÍÓÚÑ\s]{5,}$/u', $line)) {
$data['nombre'] = $line;
continue;
}
// Detectar documento (números de 6-11 dígitos)
if (empty($data['documento']) && preg_match('/(\d{6,11})/', $line, $matches)) {
$data['documento'] = $matches[1];
continue;
}
// Detectar teléfono (10 dígitos comenzando con 3)
if (empty($data['telefono']) && preg_match('/(3\d{9})/', $line, $matches)) {
$data['telefono'] = $matches[1];
continue;
}
// Detectar email
if (empty($data['email']) && preg_match('/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]+)/', $line, $matches)) {
$data['email'] = $matches[1];
continue;
}
// Detectar dirección (contiene calle, carrera, etc.)
if (empty($data['direccion']) && preg_match('/(calle|carrera|cra|cl|diagonal|transversal|avenida|av)/i', $line)) {
$data['direccion'] = $line;
continue;
}
// Detectar tipo (particular/seguro)
if (empty($data['tipo']) && preg_match('/(particular|seguro|eps)/i', $line)) {
$data['tipo'] = $line;
continue;
}
}
return $data;
}
/**
* Genera un mensaje con los errores de validación
* @param array $errors
* @return string
*/
public static function formatValidationErrors(array $errors): string
{
$message = "⚠️ Por favor corrige los siguientes datos:\n\n";
foreach ($errors as $error) {
$message .= "❌ $error\n";
}
$message .= "\nEnvía la información completa de nuevo.";
return $message;
}
/**
* Genera un resumen de los datos validados
* @param array $data
* @return string
*/
public static function formatDataSummary(array $data): string
{
$message = "📋 DATOS RECIBIDOS:\n\n";
$message .= "👤 Nombre: {$data['nombre']}\n";
$message .= "🆔 Documento: {$data['documento']}\n";
$message .= "📍 Dirección: {$data['direccion']}\n";
$message .= "📱 Teléfono: {$data['telefono']}\n";
$message .= "📧 Email: {$data['email']}\n";
$message .= "💳 Tipo: {$data['tipo']}";
if (isset($data['nombre_seguro'])) {
$message .= " ({$data['nombre_seguro']})";
}
$message .= "\n\n¿Los datos son correctos?\nResponde: *SÍ* o *NO*";
return $message;
}
}