false, 'message' => 'Método no permitido']); break; } } catch (PDOException $e) { http_response_code(500); echo json_encode([ 'success' => false, 'message' => 'Error en el servidor', 'error' => $e->getMessage() ]); } catch (Exception $e) { http_response_code($e->getCode() ?: 500); echo json_encode(['success' => false, 'message' => $e->getMessage()]); } // ============================================================ // FUNCIONES // ============================================================ function handleGet($pdo) { $estado_filtro = isset($_GET['estado']) ? $_GET['estado'] : null; $sql = "SELECT u.id, u.dni, u.nombre, u.apellidos, u.email, u.telefono, u.estado, u.rol, u.fecha_registro, COUNT(DISTINCT m.id) AS num_mascotas, COUNT(DISTINCT r.id) AS num_reservas, COUNT(DISTINCT mu.id) AS num_multas, COALESCE(SUM(CASE WHEN r.estado IN ('confirmada','activa','finalizada') THEN r.importe ELSE 0 END), 0) AS total_gastado, MAX(r.fecha) AS ultima_reserva FROM usuarios u LEFT JOIN mascotas m ON u.id = m.usuario_id LEFT JOIN reservas r ON u.id = r.usuario_id LEFT JOIN multas mu ON u.id = mu.usuario_id WHERE 1=1"; $params = []; if ($estado_filtro && $estado_filtro !== 'TODOS') { $sql .= " AND u.estado = :estado"; $params[':estado'] = $estado_filtro; } $sql .= " GROUP BY u.id ORDER BY u.fecha_registro DESC"; $stmt = $pdo->prepare($sql); $stmt->execute($params); $usuarios = $stmt->fetchAll(); // Estadísticas globales $stats = [ 'total' => count($usuarios), 'activos' => 0, 'inactivos' => 0, 'bloqueados' => 0, 'vip' => 0 ]; foreach ($usuarios as $u) { if ($u['estado'] === 'activo') $stats['activos']++; if ($u['estado'] === 'inactivo') $stats['inactivos']++; if ($u['estado'] === 'bloqueado') $stats['bloqueados']++; if ($u['rol'] === 'vip') $stats['vip']++; } echo json_encode([ 'success' => true, 'message' => 'Usuarios obtenidos correctamente', 'data' => $usuarios, 'stats' => $stats, 'total' => count($usuarios) ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); } function handlePost($pdo) { $input = json_decode(file_get_contents('php://input'), true); if (!$input) $input = $_POST; $campos_obligatorios = ['dni', 'nombre', 'apellidos', 'email', 'telefono']; foreach ($campos_obligatorios as $campo) { if (!isset($input[$campo]) || trim($input[$campo]) === '') { http_response_code(400); echo json_encode(['success' => false, 'message' => "Falta el campo obligatorio: $campo"]); return; } } // Validar email if (!filter_var($input['email'], FILTER_VALIDATE_EMAIL)) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Email no válido']); return; } // Verificar DNI duplicado $stmtCheck = $pdo->prepare("SELECT id FROM usuarios WHERE dni = ?"); $stmtCheck->execute([$input['dni']]); if ($stmtCheck->fetch()) { http_response_code(409); echo json_encode(['success' => false, 'message' => 'Ya existe un usuario con ese DNI']); return; } // Verificar email duplicado $stmtCheck = $pdo->prepare("SELECT id FROM usuarios WHERE email = ?"); $stmtCheck->execute([$input['email']]); if ($stmtCheck->fetch()) { http_response_code(409); echo json_encode(['success' => false, 'message' => 'Ya existe un usuario con ese email']); return; } $estado = $input['estado'] ?? 'activo'; $rol = $input['rol'] ?? 'usuario'; $password_default = password_hash('petstop123', PASSWORD_DEFAULT); $telefono = trim($input['telefono']); $telefono_limpio = preg_replace('/\D/', '', $telefono); $stmt = $pdo->prepare(" INSERT INTO usuarios (dni, nombre, apellidos, email, telefono, password, estado, rol, fecha_registro) VALUES (:dni, :nombre, :apellidos, :email, :telefono, :password, :estado, :rol, NOW()) "); $stmt->execute([ ':dni' => trim($input['dni']), ':nombre' => trim($input['nombre']), ':apellidos' => trim($input['apellidos']), ':email' => trim($input['email']), ':telefono' => $telefono_limpio, ':password' => $password_default, ':estado' => $estado, ':rol' => $rol ]); $nuevo_id = $pdo->lastInsertId(); // Devolver el usuario recién creado $stmtGet = $pdo->prepare("SELECT id, dni, nombre, apellidos, email, telefono, estado, rol, fecha_registro FROM usuarios WHERE id = ?"); $stmtGet->execute([$nuevo_id]); echo json_encode([ 'success' => true, 'message' => 'Usuario creado correctamente. Contraseña por defecto: petstop123', 'data' => $stmtGet->fetch() ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); } function handlePut($pdo) { $id = isset($_GET['id']) ? (int)$_GET['id'] : 0; if ($id <= 0) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'ID no válido (usar ?id=N)']); return; } $input = json_decode(file_get_contents('php://input'), true); // Verificar existencia $stmtCheck = $pdo->prepare("SELECT id FROM usuarios WHERE id = ?"); $stmtCheck->execute([$id]); if (!$stmtCheck->fetch()) { http_response_code(404); echo json_encode(['success' => false, 'message' => 'Usuario no encontrado']); return; } // Campos actualizables $campos = []; $params = [':id' => $id]; $mapa = [ 'dni' => 'dni', 'nombre' => 'nombre', 'apellidos' => 'apellidos', 'email' => 'email', 'telefono' => 'telefono', 'estado' => 'estado', 'rol' => 'rol' ]; foreach ($mapa as $campo_input => $campo_db) { if (isset($input[$campo_input])) { $valor = is_string($input[$campo_input]) ? trim($input[$campo_input]) : $input[$campo_input]; if ($campo_input === 'telefono') { $valor = preg_replace('/\D/', '', $valor); } $campos[] = "$campo_db = :$campo_db"; $params[":$campo_db"] = $valor; } } if (empty($campos)) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'No se proporcionaron campos a actualizar']); return; } // Validar email si viene if (isset($input['email']) && !filter_var($input['email'], FILTER_VALIDATE_EMAIL)) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Email no válido']); return; } // Validar email duplicado (excluyendo el propio) if (isset($input['email'])) { $stmtCheck = $pdo->prepare("SELECT id FROM usuarios WHERE email = ? AND id != ?"); $stmtCheck->execute([trim($input['email']), $id]); if ($stmtCheck->fetch()) { http_response_code(409); echo json_encode(['success' => false, 'message' => 'Email ya en uso por otro usuario']); return; } } // Validar DNI duplicado (excluyendo el propio) if (isset($input['dni'])) { $stmtCheck = $pdo->prepare("SELECT id FROM usuarios WHERE dni = ? AND id != ?"); $stmtCheck->execute([trim($input['dni']), $id]); if ($stmtCheck->fetch()) { http_response_code(409); echo json_encode(['success' => false, 'message' => 'DNI ya en uso por otro usuario']); return; } } // Validar estado if (isset($input['estado'])) { $estados_validos = ['activo', 'inactivo', 'bloqueado', 'vip']; if (!in_array($input['estado'], $estados_validos)) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Estado no válido. Válidos: ' . implode(', ', $estados_validos)]); return; } } $sql = "UPDATE usuarios SET " . implode(', ', $campos) . " WHERE id = :id"; $stmt = $pdo->prepare($sql); $stmt->execute($params); // Devolver usuario actualizado $stmtGet = $pdo->prepare("SELECT id, dni, nombre, apellidos, email, telefono, estado, rol, fecha_registro FROM usuarios WHERE id = ?"); $stmtGet->execute([$id]); echo json_encode([ 'success' => true, 'message' => 'Usuario actualizado correctamente', 'data' => $stmtGet->fetch() ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); } function handleDelete($pdo) { $id = isset($_GET['id']) ? (int)$_GET['id'] : 0; if ($id <= 0) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'ID no válido (usar ?id=N)']); return; } // Verificar existencia $stmtCheck = $pdo->prepare("SELECT id, nombre, apellidos FROM usuarios WHERE id = ?"); $stmtCheck->execute([$id]); $usuario = $stmtCheck->fetch(); if (!$usuario) { http_response_code(404); echo json_encode(['success' => false, 'message' => 'Usuario no encontrado']); return; } // Verificar si tiene reservas activas $stmtReservas = $pdo->prepare(" SELECT COUNT(*) FROM reservas WHERE usuario_id = ? AND estado IN ('confirmada','activa','pagada_pendiente_aprobacion') "); $stmtReservas->execute([$id]); if ((int)$stmtReservas->fetchColumn() > 0) { http_response_code(409); echo json_encode(['success' => false, 'message' => 'No se puede eliminar: el usuario tiene reservas activas']); return; } // Eliminar en cascada: multas, mascotas, reservas históricas, luego usuario $pdo->beginTransaction(); try { $pdo->prepare("DELETE FROM multas WHERE usuario_id = ?")->execute([$id]); $pdo->prepare("DELETE FROM reservas WHERE usuario_id = ?")->execute([$id]); $pdo->prepare("DELETE FROM mascotas WHERE usuario_id = ?")->execute([$id]); $pdo->prepare("DELETE FROM usuarios WHERE id = ?")->execute([$id]); $pdo->commit(); echo json_encode([ 'success' => true, 'message' => 'Usuario eliminado correctamente', 'data' => ['id' => $id, 'nombre' => $usuario['nombre'] . ' ' . $usuario['apellidos']] ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); } catch (Exception $e) { $pdo->rollBack(); http_response_code(500); echo json_encode(['success' => false, 'message' => 'Error eliminando: ' . $e->getMessage()]); } } ?>