5 * 1024 * 1024) { die("❌ El archivo es demasiado grande. Máximo 5MB."); } $dest = __DIR__ . '/../../public/uploads/chofer_'.uniqid().".{$ext}"; if (!is_dir(dirname($dest))) { mkdir(dirname($dest), 0755, true); } if (move_uploaded_file($_FILES['foto']['tmp_name'], $dest)) { $fotoUrl = "/IMPORTADORES/public/uploads/" . basename($dest); } else { error_log("Error al mover foto en guardar(): {$dest}"); die("❌ Error al subir la foto."); } } $sql = " INSERT INTO dbo.choferes (transportista_id, nombre, apellido, numero_licencia, numero_gafete, telefono, email, fecha_ingreso, foto_url, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, GETDATE()) "; $params = [ (int)$transportista_id, $nombre, $apellido, $licencia, $gafete, $telefono, $email, $fecha_ingreso, $fotoUrl ]; $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { $errors = sqlsrv_errors(); // ✅ Manejo específico de error de duplicado foreach ($errors as $error) { if (strpos($error['message'], 'UQ_numero_gafete') !== false) { die("❌ El número de gafete ya está en uso. Por favor, use otro número."); } } die("❌ Error en guardar(): " . print_r($errors, true)); } header('Location: /IMPORTADORES/choferes/lista?created=ok'); exit; } function editar() { if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } $id = $_GET['id'] ?? null; if (!$id || !is_numeric($id)) { die("❌ ID inválido."); } $conn = getConnection(); $sql = " SELECT ch.*, tr.clave_identificador, tr.nombre AS transportista_nombre, tr.ciudad, tr.domicilio, ciu.nombre AS ciudad_nombre FROM dbo.choferes ch LEFT JOIN dbo.transportistas tr ON ch.transportista_id = tr.id_transportista LEFT JOIN dbo.ciudades ciu ON tr.ciudad = ciu.id_ciudad WHERE ch.id_chofer = ? AND tr.id_usuario = ? AND ch.status = 1 "; $stmt = sqlsrv_query($conn, $sql, [(int)$id, $_SESSION['usuario_id']]); if ($stmt === false) { die("Error en editar(): " . print_r(sqlsrv_errors(), true)); } $chofer = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); if (!$chofer) { die("❌ Chofer no encontrado o no autorizado."); } // ✅ Aquí convertimos fecha_ingreso a string YYYY-MM-DD if ($chofer['fecha_ingreso'] instanceof DateTime) { $chofer['fecha_ingreso'] = $chofer['fecha_ingreso']->format('Y-m-d'); } // Lista de transportistas $sql2 = " SELECT tr.id_transportista, tr.clave_identificador, tr.nombre, tr.domicilio, ciu.nombre AS ciudad_nombre FROM dbo.transportistas tr LEFT JOIN dbo.ciudades ciu ON tr.ciudad = ciu.id_ciudad WHERE tr.id_usuario = ? AND tr.activo = 1 ORDER BY tr.nombre "; $stmt2 = sqlsrv_query($conn, $sql2, [$_SESSION['usuario_id']]); if ($stmt2 === false) { die("Error en editar() [transportistas]: " . print_r(sqlsrv_errors(), true)); } $transportistas = []; while ($r = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_ASSOC)) { $transportistas[] = $r; } include __DIR__ . '/../../views/choferes/editar.php'; } /** Valida que el número de gafete sea único **/ function validarNumeroGafete() { if (!($_SESSION['usuario_id'] ?? false)) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'No autorizado']); exit; } $gafete = trim($_GET['numero_gafete'] ?? ''); $id_chofer = $_GET['id_chofer'] ?? null; if ($gafete === '') { echo json_encode(['success' => false, 'message' => 'Número de gafete vacío']); exit; } $conn = getConnection(); if ($id_chofer) { // Edición: excluir el chofer actual $sql = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND id_chofer <> ? AND status = 1"; $stmt = sqlsrv_query($conn, $sql, [$gafete, $id_chofer]); } else { // Alta nueva $sql = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND status = 1"; $stmt = sqlsrv_query($conn, $sql, [$gafete]); } if ($stmt && sqlsrv_fetch($stmt)) { echo json_encode(['success' => true, 'existe' => true]); } else { echo json_encode(['success' => true, 'existe' => false]); } exit; } /** Procesa la actualización de un chofer **/ function actualizar() { if (!($_SESSION['usuario_id'] ?? false)) { die("⚠️ No autorizado."); } $id = $_POST['id_chofer'] ?? null; $transportista_id = $_POST['transportista_id'] ?? null; $nombre = trim($_POST['nombre'] ?? ''); $apellido = trim($_POST['apellido'] ?? ''); $licencia = trim($_POST['numero_licencia']?? ''); $gafete = trim($_POST['numero_gafete']?? ''); $telefono = trim($_POST['telefono'] ?? ''); $email = trim($_POST['email'] ?? ''); $fecha_ingreso = $_POST['fecha_ingreso'] ?: null; $status = isset($_POST['status']) ? 1 : 0; // Validación básica if ( !$id || !is_numeric($id) || !$transportista_id || !is_numeric($transportista_id) || $nombre === '' || $apellido === '' || $licencia === '' || $gafete === '' ) { die("❌ Datos inválidos o incompletos."); } $conn = getConnection(); // ✅ CRÍTICO: Verificar que el número de gafete no existe (excluyendo el chofer actual) $sqlCheckGafete = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND id_chofer <> ? AND status = 1"; $stmtCheck = sqlsrv_query($conn, $sqlCheckGafete, [$gafete, $id_chofer]); if ($stmtCheck && sqlsrv_fetch($stmtCheck)) { die("❌ El número de gafete '{$gafete}' ya está en uso. Por favor, use otro número."); } // ✅ MEJORADO: Manejo de foto nueva con validación $fotoUrl = null; if (!empty($_FILES['foto']['tmp_name']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) { $allowedTypes = ['jpg', 'jpeg', 'png', 'gif']; $ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); if (!in_array($ext, $allowedTypes)) { die("❌ Tipo de archivo no permitido. Solo JPG, PNG, GIF."); } // Validar tamaño (ej: máximo 5MB) if ($_FILES['foto']['size'] > 5 * 1024 * 1024) { die("❌ El archivo es demasiado grande. Máximo 5MB."); } $dest = __DIR__ . '/../../public/uploads/chofer_'.uniqid().".{$ext}"; if (!is_dir(dirname($dest))) { mkdir(dirname($dest), 0755, true); } if (move_uploaded_file($_FILES['foto']['tmp_name'], $dest)) { $fotoUrl = "/IMPORTADORES/public/uploads/" . basename($dest); } else { error_log("Error al mover foto en actualizar(): {$dest}"); die("❌ Error al subir la foto."); } } if ($fotoUrl) { $sql = " UPDATE dbo.choferes SET transportista_id = ?, nombre = ?, apellido = ?, numero_licencia = ?, numero_gafete = ?, telefono = ?, email = ?, fecha_ingreso = ?, foto_url = ?, status = ?, updated_at = GETDATE() WHERE id_chofer = ? "; $params = [ (int)$transportista_id, $nombre, $apellido, $licencia, $gafete, $telefono, $email, $fecha_ingreso, $fotoUrl, $status, (int)$id ]; } else { $sql = " UPDATE dbo.choferes SET transportista_id = ?, nombre = ?, apellido = ?, numero_licencia = ?, numero_gafete = ?, telefono = ?, email = ?, fecha_ingreso = ?, status = ?, updated_at = GETDATE() WHERE id_chofer = ? "; $params = [ (int)$transportista_id, $nombre, $apellido, $licencia, $gafete, $telefono, $email, $fecha_ingreso, $status, (int)$id ]; } $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { $errors = sqlsrv_errors(); // ✅ Manejo específico de error de duplicado foreach ($errors as $error) { if (strpos($error['message'], 'UQ_numero_gafete') !== false) { die("❌ El número de gafete ya está en uso por otro chofer. Por favor, use otro número."); } } die("❌ Error en actualizar(): " . print_r($errors, true)); } header('Location: /IMPORTADORES/choferes/lista?updated=ok'); exit; } /** “Soft-delete” (status = 0) de un chofer **/ function eliminar() { if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } $id = $_GET['id'] ?? null; if (!$id || !is_numeric($id)) { die("❌ ID inválido."); } $conn = getConnection(); $sql = " UPDATE dbo.choferes SET status = 0, updated_at = GETDATE() WHERE id_chofer = ? "; $stmt = sqlsrv_query($conn, $sql, [(int)$id]); if ($stmt === false) { die("❌ Error en eliminar(): " . print_r(sqlsrv_errors(), true)); } header('Location: /IMPORTADORES/choferes/lista?deleted=ok'); exit; }