Revisión 2.1

This commit is contained in:
2025-06-16 14:36:01 -06:00
parent c576ab5b3b
commit 4365919211
18 changed files with 601 additions and 290 deletions

View File

@@ -15,7 +15,7 @@ function lista() {
SELECT
c.*,
(c.nombre + ' ' + c.apellido) AS nombre_completo,
tr.nombre AS transportista
(tr.clave_identificador + ' - ' + tr.nombre) AS transportista
FROM dbo.choferes c
JOIN dbo.transportistas tr
ON c.transportista_id = tr.id_transportista
@@ -45,8 +45,10 @@ function crear() {
// OJO: aquí usamos "activo" según tu esquema original
$sql = "
SELECT id_transportista, nombre
FROM dbo.transportistas
SELECT t.id_transportista, t.clave_identificador, t.nombre, t.ciudad, t.domicilio,
c.nombre AS ciudad_nombre
FROM dbo.transportistas t
LEFT JOIN dbo.ciudades c ON t.ciudad = c.id_ciudad
WHERE id_usuario = ? AND activo = 1
ORDER BY nombre
";
@@ -70,44 +72,86 @@ function guardar() {
$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;
if (!$transportista_id || $nombre === '' || $apellido === '' || $licencia === '') {
if (!$transportista_id || !is_numeric($transportista_id) || $nombre === '' ||
$apellido === '' || $licencia === '' || $gafete === '') {
die("❌ Todos los campos obligatorios deben llenarse.");
}
// Manejo de foto
$conn = getConnection();
// ✅ CRÍTICO: Verificar que el transportista pertenece al usuario
$sqlVerify = "SELECT id_transportista FROM dbo.transportistas WHERE id_transportista = ? AND id_usuario = ?";
$stmtVerify = sqlsrv_query($conn, $sqlVerify, [(int)$transportista_id, $_SESSION['usuario_id']]);
if (!$stmtVerify || !sqlsrv_fetch($stmtVerify)) {
die("❌ Transportista no autorizado.");
}
// ✅ CRÍTICO: Verificar que el número de gafete no existe
$sqlCheckGafete = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND status = 1";
$stmtCheck = sqlsrv_query($conn, $sqlCheckGafete, [$gafete]);
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 con validación
$fotoUrl = null;
if (!empty($_FILES['foto']['tmp_name'])) {
$ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION));
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 (!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.");
}
}
$conn = getConnection();
$sql = "
INSERT INTO dbo.choferes
(transportista_id, nombre, apellido, numero_licencia, telefono, email, fecha_ingreso, foto_url, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)
(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) {
die("Error en guardar(): " . print_r(sqlsrv_errors(), true));
$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');
@@ -126,13 +170,15 @@ function editar() {
$conn = getConnection();
$sql = "
SELECT c.*, tr.nombre AS transportista
FROM dbo.choferes c
JOIN dbo.transportistas tr
ON c.transportista_id = tr.id_transportista
WHERE c.id_chofer = ?
AND tr.id_usuario = ?
AND c.status = 1
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) {
@@ -150,10 +196,12 @@ function editar() {
// Lista de transportistas
$sql2 = "
SELECT id_transportista, nombre
FROM dbo.transportistas
WHERE id_usuario = ? AND activo = 1
ORDER BY nombre
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) {
@@ -167,6 +215,42 @@ function editar() {
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)) {
@@ -178,6 +262,7 @@ function actualizar() {
$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;
@@ -187,15 +272,35 @@ function actualizar() {
if (
!$id || !is_numeric($id) ||
!$transportista_id || !is_numeric($transportista_id) ||
$nombre === '' || $apellido === '' || $licencia === ''
$nombre === '' || $apellido === '' || $licencia === '' || $gafete === ''
) {
die("❌ Datos inválidos o incompletos.");
}
// Manejo de foto nueva (opcional)
$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);
@@ -204,11 +309,10 @@ function actualizar() {
$fotoUrl = "/IMPORTADORES/public/uploads/" . basename($dest);
} else {
error_log("Error al mover foto en actualizar(): {$dest}");
die("❌ Error al subir la foto.");
}
}
$conn = getConnection();
if ($fotoUrl) {
$sql = "
UPDATE dbo.choferes SET
@@ -216,6 +320,7 @@ function actualizar() {
nombre = ?,
apellido = ?,
numero_licencia = ?,
numero_gafete = ?,
telefono = ?,
email = ?,
fecha_ingreso = ?,
@@ -229,6 +334,7 @@ function actualizar() {
$nombre,
$apellido,
$licencia,
$gafete,
$telefono,
$email,
$fecha_ingreso,
@@ -243,6 +349,7 @@ function actualizar() {
nombre = ?,
apellido = ?,
numero_licencia = ?,
numero_gafete = ?,
telefono = ?,
email = ?,
fecha_ingreso = ?,
@@ -255,6 +362,7 @@ function actualizar() {
$nombre,
$apellido,
$licencia,
$gafete,
$telefono,
$email,
$fecha_ingreso,
@@ -265,7 +373,14 @@ function actualizar() {
$stmt = sqlsrv_query($conn, $sql, $params);
if ($stmt === false) {
die("❌ Error en actualizar(): " . print_r(sqlsrv_errors(), true));
$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');