332 lines
15 KiB
PHP
332 lines
15 KiB
PHP
<?php
|
|
session_start();
|
|
|
|
$userRole = $_SESSION['user_role'] ?? '';
|
|
if (!isset($_SESSION['user_id']) || ($userRole !== 'Administrador' && $userRole !== 'admin')) {
|
|
header('Location: dashboard.php');
|
|
exit;
|
|
}
|
|
|
|
require_once 'db/config.php';
|
|
$pdo = db();
|
|
|
|
$schemaInitError = null;
|
|
require_once 'includes/hr_bootstrap.php';
|
|
try {
|
|
hr_ensure_schema($pdo);
|
|
} catch (Throwable $e) {
|
|
$schemaInitError = $e->getMessage();
|
|
}
|
|
|
|
$pageTitle = "Recursos Humanos - Evaluaciones";
|
|
$pageDescription = "Registro de evaluaciones internas y seguimiento del desempeño del personal.";
|
|
|
|
$areasValidas = ['Ventas', 'Almacén', 'Marketing', 'Administración', 'Finanzas', 'Gerencia'];
|
|
$resultadosValidos = ['Aprobado', 'En Capacitación', 'Requiere Seguimiento'];
|
|
|
|
$notice = null;
|
|
$noticeType = 'success';
|
|
|
|
if (!empty($schemaInitError)) {
|
|
$notice = 'Error al preparar las tablas de Recursos Humanos.';
|
|
$noticeType = 'danger';
|
|
error_log('HR schema init error (evaluaciones): ' . $schemaInitError);
|
|
}
|
|
|
|
if (isset($_GET['success']) && $_GET['success'] === '1') {
|
|
$notice = 'Evaluación guardada correctamente.';
|
|
$noticeType = 'success';
|
|
}
|
|
|
|
// Lista de colaboradores para los selects
|
|
$colaboradores = [];
|
|
try {
|
|
$stmt = $pdo->query('SELECT id, nombre_completo, area FROM hr_colaboradores ORDER BY nombre_completo ASC');
|
|
$colaboradores = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
} catch (Throwable $e) {
|
|
$colaboradores = [];
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
if ($action === 'add_evaluacion') {
|
|
try {
|
|
$colaborador_id = (int)($_POST['colaborador_id'] ?? 0);
|
|
$fecha = $_POST['fecha'] ?? date('Y-m-d');
|
|
$tipo_evaluacion = trim((string)($_POST['tipo_evaluacion'] ?? ''));
|
|
$puntaje = (int)($_POST['puntaje'] ?? 0);
|
|
$resultado = (string)($_POST['resultado'] ?? '');
|
|
$observaciones = trim((string)($_POST['observaciones'] ?? ''));
|
|
|
|
if ($colaborador_id <= 0) {
|
|
throw new RuntimeException('Selecciona un colaborador.');
|
|
}
|
|
if ($tipo_evaluacion === '') {
|
|
throw new RuntimeException('Tipo de evaluación es obligatorio.');
|
|
}
|
|
if (!in_array($resultado, $resultadosValidos, true)) {
|
|
throw new RuntimeException('Resultado inválido.');
|
|
}
|
|
|
|
// Traer área del colaborador para guardarla en el registro
|
|
$stmtArea = $pdo->prepare('SELECT area FROM hr_colaboradores WHERE id = ? LIMIT 1');
|
|
$stmtArea->execute([$colaborador_id]);
|
|
$areaRow = $stmtArea->fetch(PDO::FETCH_ASSOC);
|
|
if (!$areaRow || empty($areaRow['area'])) {
|
|
throw new RuntimeException('No se encontró el área del colaborador.');
|
|
}
|
|
$area = (string)$areaRow['area'];
|
|
if (!in_array($area, $areasValidas, true)) {
|
|
// Seguridad extra
|
|
throw new RuntimeException('Área inválida en el colaborador.');
|
|
}
|
|
|
|
$stmt = $pdo->prepare('INSERT INTO hr_evaluaciones (colaborador_id, area, fecha, tipo_evaluacion, puntaje, resultado, observaciones) VALUES (?, ?, ?, ?, ?, ?, ?)');
|
|
$stmt->execute([
|
|
$colaborador_id,
|
|
$area,
|
|
$fecha,
|
|
$tipo_evaluacion,
|
|
$puntaje,
|
|
$resultado,
|
|
$observaciones,
|
|
]);
|
|
|
|
header('Location: hr_evaluaciones.php?success=1');
|
|
exit;
|
|
} catch (Throwable $e) {
|
|
$notice = 'No se pudo guardar la evaluación: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
|
|
$noticeType = 'danger';
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Filtros de listado ---
|
|
$f_colaborador = (int)($_GET['colaborador_id'] ?? 0);
|
|
$f_resultado = (string)($_GET['resultado'] ?? 'Todos');
|
|
$f_fecha_desde = trim((string)($_GET['fecha_desde'] ?? ''));
|
|
$f_fecha_hasta = trim((string)($_GET['fecha_hasta'] ?? ''));
|
|
|
|
if ($f_resultado !== 'Todos' && !in_array($f_resultado, $resultadosValidos, true)) {
|
|
$f_resultado = 'Todos';
|
|
}
|
|
|
|
$where = [];
|
|
$params = [];
|
|
|
|
if ($f_colaborador > 0) {
|
|
$where[] = 'e.colaborador_id = ?';
|
|
$params[] = $f_colaborador;
|
|
}
|
|
if ($f_resultado !== 'Todos') {
|
|
$where[] = 'e.resultado = ?';
|
|
$params[] = $f_resultado;
|
|
}
|
|
if ($f_fecha_desde !== '') {
|
|
$where[] = 'e.fecha >= ?';
|
|
$params[] = $f_fecha_desde;
|
|
}
|
|
if ($f_fecha_hasta !== '') {
|
|
$where[] = 'e.fecha <= ?';
|
|
$params[] = $f_fecha_hasta;
|
|
}
|
|
|
|
$sql = 'SELECT e.id, e.fecha, e.tipo_evaluacion, e.puntaje, e.resultado, e.area, e.observaciones, c.nombre_completo, c.dni FROM hr_evaluaciones e LEFT JOIN hr_colaboradores c ON c.id = e.colaborador_id';
|
|
if (!empty($where)) {
|
|
$sql .= ' WHERE ' . implode(' AND ', $where);
|
|
}
|
|
$sql .= ' ORDER BY e.fecha DESC, e.id DESC';
|
|
|
|
$evaluaciones = [];
|
|
try {
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$evaluaciones = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
} catch (PDOException $e) {
|
|
error_log('HR Evaluaciones DB error: ' . $e->getMessage());
|
|
$notice = 'No se pudo cargar el listado de evaluaciones.';
|
|
$noticeType = 'danger';
|
|
}
|
|
|
|
|
|
$fechaHoy = date('Y-m-d');
|
|
|
|
include 'layout_header.php';
|
|
?>
|
|
|
|
<div class="container-fluid mt-4">
|
|
<?php if ($notice): ?>
|
|
<div class="alert alert-<?= htmlspecialchars($noticeType, ENT_QUOTES, 'UTF-8'); ?> mb-4" role="alert">
|
|
<?= $notice; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-lg-4">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-light">
|
|
<h2 class="h5 mb-0">Nueva Evaluación</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
<?php if (empty($colaboradores)): ?>
|
|
<div class="alert alert-warning">
|
|
Primero agrega colaboradores en <b>Colaboradores</b>.
|
|
</div>
|
|
<?php else: ?>
|
|
<form method="POST">
|
|
<input type="hidden" name="action" value="add_evaluacion">
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Colaborador</label>
|
|
<select name="colaborador_id" class="form-select" required>
|
|
<?php foreach ($colaboradores as $c): ?>
|
|
<option value="<?= (int)$c['id']; ?>">
|
|
<?= htmlspecialchars($c['nombre_completo'] ?? '', ENT_QUOTES, 'UTF-8'); ?>
|
|
(<?= htmlspecialchars($c['area'] ?? '', ENT_QUOTES, 'UTF-8'); ?>)
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Fecha</label>
|
|
<input type="date" name="fecha" class="form-control" value="<?= htmlspecialchars($fechaHoy, ENT_QUOTES, 'UTF-8'); ?>" required>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Tipo de Evaluación</label>
|
|
<input type="text" name="tipo_evaluacion" class="form-control" placeholder="Ej: Evaluación Mensual" required>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Puntaje</label>
|
|
<input type="number" name="puntaje" class="form-control" value="0" min="0" required>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Resultado</label>
|
|
<select name="resultado" class="form-select" required>
|
|
<?php foreach ($resultadosValidos as $r): ?>
|
|
<option value="<?= htmlspecialchars($r, ENT_QUOTES, 'UTF-8'); ?>">
|
|
<?= htmlspecialchars($r, ENT_QUOTES, 'UTF-8'); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Observaciones</label>
|
|
<textarea name="observaciones" class="form-control" rows="3"></textarea>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary w-100">
|
|
<i class="fas fa-save me-1"></i> Guardar
|
|
</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-8">
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-header bg-light d-flex justify-content-between align-items-center">
|
|
<h2 class="h5 mb-0">Evaluaciones</h2>
|
|
<span class="badge bg-secondary">Total: <?= count($evaluaciones); ?></span>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="GET" class="row g-2 align-items-end">
|
|
<div class="col-sm-5">
|
|
<label class="form-label">Colaborador</label>
|
|
<select name="colaborador_id" class="form-select">
|
|
<option value="0">Todos</option>
|
|
<?php foreach ($colaboradores as $c): ?>
|
|
<option value="<?= (int)$c['id']; ?>" <?= $f_colaborador === (int)$c['id'] ? 'selected' : ''; ?>>
|
|
<?= htmlspecialchars($c['nombre_completo'] ?? '', ENT_QUOTES, 'UTF-8'); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-3">
|
|
<label class="form-label">Resultado</label>
|
|
<select name="resultado" class="form-select">
|
|
<option value="Todos" <?= $f_resultado === 'Todos' ? 'selected' : ''; ?>>Todos</option>
|
|
<?php foreach ($resultadosValidos as $r): ?>
|
|
<option value="<?= htmlspecialchars($r, ENT_QUOTES, 'UTF-8'); ?>" <?= $f_resultado === $r ? 'selected' : ''; ?>>
|
|
<?= htmlspecialchars($r, ENT_QUOTES, 'UTF-8'); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-2">
|
|
<label class="form-label">Desde</label>
|
|
<input type="date" name="fecha_desde" class="form-control" value="<?= htmlspecialchars($f_fecha_desde, ENT_QUOTES, 'UTF-8'); ?>">
|
|
</div>
|
|
<div class="col-sm-2">
|
|
<label class="form-label">Hasta</label>
|
|
<input type="date" name="fecha_hasta" class="form-control" value="<?= htmlspecialchars($f_fecha_hasta, ENT_QUOTES, 'UTF-8'); ?>">
|
|
</div>
|
|
<div class="col-12 d-flex justify-content-end gap-2 mt-2">
|
|
<a class="btn btn-outline-secondary" href="hr_evaluaciones.php">Limpiar</a>
|
|
<button class="btn btn-primary" type="submit">
|
|
<i class="fas fa-filter me-1"></i> Filtrar
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-striped align-middle">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Colaborador</th>
|
|
<th>Área</th>
|
|
<th>Fecha</th>
|
|
<th>Tipo</th>
|
|
<th>Puntaje</th>
|
|
<th>Resultado</th>
|
|
<th>Observaciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($evaluaciones)): ?>
|
|
<tr>
|
|
<td colspan="8" class="text-center py-4 text-muted">No hay evaluaciones para los filtros seleccionados.</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($evaluaciones as $e): ?>
|
|
<tr>
|
|
<td><?= (int)$e['id']; ?></td>
|
|
<td>
|
|
<?= htmlspecialchars($e['nombre_completo'] ?? '', ENT_QUOTES, 'UTF-8'); ?>
|
|
<?php if (!empty($e['dni'])): ?>
|
|
<div class="text-muted small">DNI: <?= htmlspecialchars($e['dni'], ENT_QUOTES, 'UTF-8'); ?></div>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td><span class="badge bg-primary"><?= htmlspecialchars($e['area'] ?? '', ENT_QUOTES, 'UTF-8'); ?></span></td>
|
|
<td><?= htmlspecialchars($e['fecha'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><?= htmlspecialchars($e['tipo_evaluacion'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><b><?= (int)($e['puntaje'] ?? 0); ?></b></td>
|
|
<td>
|
|
<span class="badge bg-info text-dark">
|
|
<?= htmlspecialchars($e['resultado'] ?? '', ENT_QUOTES, 'UTF-8'); ?>
|
|
</span>
|
|
</td>
|
|
<td style="max-width: 260px;">
|
|
<div style="white-space: pre-wrap;"><?= htmlspecialchars($e['observaciones'] ?? '', ENT_QUOTES, 'UTF-8'); ?></div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php include 'layout_footer.php'; ?>
|