'Visa', 'sentri' => 'Sentri/Global', 'pasaporte' => 'Pasaporte', 'adelanto_cita' => 'Adelanto Cita', 'doble_nacionalidad' => 'Doble Nacionalidad', ]; $estadoLabels = [ 'nuevo' => 'Nuevo', 'en_proceso' => 'En Proceso', 'en_revision' => 'En Revisión', 'completado' => 'Completado', 'cancelado' => 'Cancelado', ]; // Determine mode: edit (id exists) or create (no id) $tramiteId = isset($_GET['id']) ? (int)$_GET['id'] : 0; $isEdit = $tramiteId > 0; $tramite = null; $errors = []; $success = ''; // ── Handle POST actions ───────────────────────────────────────── if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrfValidate()) { $action = $_POST['action'] ?? 'save_tramite'; switch ($action) { // ── Save tramite (create / update) ────────────────────── case 'save_tramite': $clienteId = (int)($_POST['cliente_id'] ?? 0); $tipo = trim($_POST['tipo'] ?? ''); $estado = trim($_POST['estado'] ?? 'nuevo'); $fechaSolicitud = trim($_POST['fecha_solicitud'] ?? ''); $fechaCita = trim($_POST['fecha_cita'] ?? ''); $fechaResolucion = trim($_POST['fecha_resolucion'] ?? ''); $precio = $_POST['precio'] ?? ''; $notas = trim($_POST['notas'] ?? ''); // Validate required fields if ($clienteId <= 0) { $errors[] = 'Debe seleccionar un cliente.'; } if (!array_key_exists($tipo, $tipoLabels)) { $errors[] = 'El tipo de trámite no es válido.'; } if (!array_key_exists($estado, $estadoLabels)) { $errors[] = 'El estado no es válido.'; } // Sanitize optional dates $fechaSolicitud = $fechaSolicitud !== '' ? $fechaSolicitud : null; $fechaCita = $fechaCita !== '' ? $fechaCita : null; $fechaResolucion = $fechaResolucion !== '' ? $fechaResolucion : null; $precio = $precio !== '' ? (float)$precio : null; if (empty($errors)) { if ($isEdit) { $stmt = $db->prepare("UPDATE tramites SET cliente_id=?, tipo=?, estado=?, fecha_solicitud=?, fecha_cita=?, fecha_resolucion=?, precio=?, notas=?, updated_at=NOW() WHERE id=?"); $stmt->execute([ $clienteId, $tipo, $estado, $fechaSolicitud, $fechaCita, $fechaResolucion, $precio, $notas, $tramiteId ]); header("Location: tramite-detalle.php?id=$tramiteId&saved=1"); exit; } else { $stmt = $db->prepare("INSERT INTO tramites (cliente_id, tipo, estado, fecha_solicitud, fecha_cita, fecha_resolucion, precio, notas) VALUES (?,?,?,?,?,?,?,?)"); $stmt->execute([ $clienteId, $tipo, $estado, $fechaSolicitud, $fechaCita, $fechaResolucion, $precio, $notas ]); $newId = $db->lastInsertId(); header("Location: tramite-detalle.php?id=$newId&saved=1"); exit; } } break; // ── Upload document ───────────────────────────────────── case 'upload_document': if (!$isEdit) break; $docNombre = trim($_POST['doc_nombre'] ?? ''); $file = $_FILES['doc_archivo'] ?? null; if ($docNombre === '') { $errors[] = 'El nombre del documento es obligatorio.'; } if (!$file || $file['error'] !== UPLOAD_ERR_OK) { $errors[] = 'Debe seleccionar un archivo válido.'; } else { $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($ext, ALLOWED_EXTENSIONS)) { $errors[] = 'Tipo de archivo no permitido. Permitidos: ' . implode(', ', ALLOWED_EXTENSIONS); } if ($file['size'] > MAX_FILE_SIZE) { $errors[] = 'El archivo excede el tamaño máximo de ' . (MAX_FILE_SIZE / 1024 / 1024) . ' MB.'; } } if (empty($errors)) { // Load tramite to get cliente_id for directory $stmtT = $db->prepare("SELECT cliente_id FROM tramites WHERE id=?"); $stmtT->execute([$tramiteId]); $tData = $stmtT->fetch(); if ($tData) { $uploadDir = UPLOAD_DIR . 'client_' . $tData['cliente_id'] . '/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); } $safeFilename = preg_replace('/[^a-zA-Z0-9_\-.]/', '_', $file['name']); $filename = time() . '_' . $safeFilename; $destPath = $uploadDir . $filename; if (move_uploaded_file($file['tmp_name'], $destPath)) { $rutaArchivo = 'client_' . $tData['cliente_id'] . '/' . $filename; $stmt = $db->prepare("INSERT INTO documentos (cliente_id, tramite_id, nombre, ruta_archivo, tipo) VALUES (?,?,?,?,?)"); $stmt->execute([$tData['cliente_id'], $tramiteId, $docNombre, $rutaArchivo, $ext]); header("Location: tramite-detalle.php?id=$tramiteId&doc_saved=1#documentos"); exit; } else { $errors[] = 'Error al subir el archivo. Intente de nuevo.'; } } } break; // ── Delete document ───────────────────────────────────── case 'delete_document': if (!$isEdit) break; $docId = (int)($_POST['doc_id'] ?? 0); if ($docId > 0) { $stmt = $db->prepare("SELECT ruta_archivo FROM documentos WHERE id=? AND tramite_id=?"); $stmt->execute([$docId, $tramiteId]); $doc = $stmt->fetch(); if ($doc) { $filePath = UPLOAD_DIR . $doc['ruta_archivo']; if (file_exists($filePath)) { unlink($filePath); } $stmt = $db->prepare("DELETE FROM documentos WHERE id=? AND tramite_id=?"); $stmt->execute([$docId, $tramiteId]); } } header("Location: tramite-detalle.php?id=$tramiteId&doc_deleted=1#documentos"); exit; // ── Delete tramite ────────────────────────────────────── case 'delete_tramite': if (!$isEdit) break; // Delete associated documents from disk $stmtDocs = $db->prepare("SELECT ruta_archivo FROM documentos WHERE tramite_id=?"); $stmtDocs->execute([$tramiteId]); $docsToDelete = $stmtDocs->fetchAll(); foreach ($docsToDelete as $doc) { $filePath = UPLOAD_DIR . $doc['ruta_archivo']; if (file_exists($filePath)) { unlink($filePath); } } // Delete document records $stmt = $db->prepare("DELETE FROM documentos WHERE tramite_id=?"); $stmt->execute([$tramiteId]); // Delete tramite $stmt = $db->prepare("DELETE FROM tramites WHERE id=?"); $stmt->execute([$tramiteId]); header("Location: tramites.php?deleted=1"); exit; } } // ── Handle document download (GET) ────────────────────────────── if (isset($_GET['download']) && $isEdit) { $docId = (int)$_GET['download']; $stmt = $db->prepare("SELECT nombre, ruta_archivo, tipo FROM documentos WHERE id=? AND tramite_id=?"); $stmt->execute([$docId, $tramiteId]); $doc = $stmt->fetch(); if ($doc) { $filePath = UPLOAD_DIR . $doc['ruta_archivo']; if (file_exists($filePath)) { $mimeTypes = [ 'pdf' => 'application/pdf', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', ]; $mime = $mimeTypes[$doc['tipo']] ?? 'application/octet-stream'; $downloadName = $doc['nombre'] . '.' . $doc['tipo']; header('Content-Type: ' . $mime); header('Content-Disposition: attachment; filename="' . $downloadName . '"'); header('Content-Length: ' . filesize($filePath)); header('Cache-Control: no-cache, must-revalidate'); readfile($filePath); exit; } } $errors[] = 'Documento no encontrado.'; } // ── Load tramite data for edit mode ───────────────────────────── if ($isEdit) { $stmt = $db->prepare("SELECT t.*, c.nombre AS cliente_nombre FROM tramites t LEFT JOIN clientes c ON t.cliente_id = c.id WHERE t.id=?"); $stmt->execute([$tramiteId]); $tramite = $stmt->fetch(); if (!$tramite) { header('Location: tramites.php'); exit; } // Fetch documents linked to this tramite $stmtDoc = $db->prepare("SELECT * FROM documentos WHERE tramite_id=? ORDER BY created_at DESC"); $stmtDoc->execute([$tramiteId]); $documentos = $stmtDoc->fetchAll(); } // ── Load all clients for dropdown ─────────────────────────────── $stmtClientes = $db->prepare("SELECT id, nombre FROM clientes ORDER BY nombre ASC"); $stmtClientes->execute(); $allClientes = $stmtClientes->fetchAll(); // ── Pre-select client from query param ────────────────────────── $preClienteId = 0; if (!$isEdit && isset($_GET['cliente_id'])) { $preClienteId = (int)$_GET['cliente_id']; } // ── Preserve POST data on validation errors ───────────────────── $prefill = [ 'cliente_id' => $preClienteId, 'tipo' => '', 'estado' => 'nuevo', 'fecha_solicitud' => date('Y-m-d'), 'fecha_cita' => '', 'fecha_resolucion' => '', 'precio' => '', 'notas' => '', ]; if (!empty($errors) && ($_POST['action'] ?? '') === 'save_tramite') { $prefill['cliente_id'] = (int)($_POST['cliente_id'] ?? 0); $prefill['tipo'] = $_POST['tipo'] ?? ''; $prefill['estado'] = $_POST['estado'] ?? 'nuevo'; $prefill['fecha_solicitud'] = $_POST['fecha_solicitud'] ?? ''; $prefill['fecha_cita'] = $_POST['fecha_cita'] ?? ''; $prefill['fecha_resolucion'] = $_POST['fecha_resolucion'] ?? ''; $prefill['precio'] = $_POST['precio'] ?? ''; $prefill['notas'] = $_POST['notas'] ?? ''; } // Success messages from redirects if (isset($_GET['saved'])) $success = 'Trámite guardado correctamente.'; if (isset($_GET['doc_saved'])) $success = 'Documento subido correctamente.'; if (isset($_GET['doc_deleted'])) $success = 'Documento eliminado.'; $pageTitle = $isEdit ? 'Trámite: ' . ($tipoLabels[$tramite['tipo']] ?? $tramite['tipo']) : 'Nuevo Trámite'; ?>

Volver a Trámites Ver Cliente:

Datos del Trámite

Creado: — Actualizado:

Documentos del Trámite

Nombre Tipo Fecha Acciones

No hay documentos subidos para este trámite.

Subir Documento

Máx. MB. Formatos: PDF, JPG, PNG, DOC, DOCX

Zona de Peligro

Eliminar este trámite borrará también todos los documentos asociados. Esta acción no se puede deshacer.