fix initial+refresher
This commit is contained in:
@@ -47,7 +47,8 @@ $sent = 0;
|
|||||||
$skipped = 0;
|
$skipped = 0;
|
||||||
$errors = 0;
|
$errors = 0;
|
||||||
|
|
||||||
/* Candidate trainings (with optional override reminder + topic default) */
|
/* Candidate trainings (with optional override reminder + topic default).
|
||||||
|
Only the most recent record per (employee, topic) — older history rows skipped. */
|
||||||
$stmt = $pdo->query("
|
$stmt = $pdo->query("
|
||||||
SELECT et.id, et.employee_id, et.completed_date, et.next_due_date,
|
SELECT et.id, et.employee_id, et.completed_date, et.next_due_date,
|
||||||
et.reminder_days, et.delivered_by,
|
et.reminder_days, et.delivered_by,
|
||||||
@@ -60,6 +61,13 @@ $stmt = $pdo->query("
|
|||||||
JOIN employees e ON e.id = et.employee_id
|
JOIN employees e ON e.id = et.employee_id
|
||||||
LEFT JOIN auth_users au ON au.id = e.auth_user_id
|
LEFT JOIN auth_users au ON au.id = e.auth_user_id
|
||||||
WHERE et.next_due_date IS NOT NULL
|
WHERE et.next_due_date IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM employee_trainings et2
|
||||||
|
WHERE et2.employee_id = et.employee_id
|
||||||
|
AND et2.training_topic_id = et.training_topic_id
|
||||||
|
AND (et2.completed_date > et.completed_date
|
||||||
|
OR (et2.completed_date = et.completed_date AND et2.id > et.id))
|
||||||
|
)
|
||||||
");
|
");
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,15 @@ if ($employee) {
|
|||||||
$stmt->execute(['eid' => $employeeId]);
|
$stmt->execute(['eid' => $employeeId]);
|
||||||
$trainings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$trainings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Mark the most recent record per topic — older ones are history, not "expired".
|
||||||
|
$seenTopics = [];
|
||||||
|
foreach ($trainings as &$t) {
|
||||||
|
$tid = (int)$t['training_topic_id'];
|
||||||
|
$t['_is_latest'] = !isset($seenTopics[$tid]);
|
||||||
|
$seenTopics[$tid] = true;
|
||||||
|
}
|
||||||
|
unset($t);
|
||||||
|
|
||||||
if ($canEdit) {
|
if ($canEdit) {
|
||||||
$trainingTopicsAll = $pdo->query("
|
$trainingTopicsAll = $pdo->query("
|
||||||
SELECT id, name, default_frequency_months, default_reminder_days
|
SELECT id, name, default_frequency_months, default_reminder_days
|
||||||
@@ -270,6 +279,7 @@ function fmtFileSize(?int $bytes): string {
|
|||||||
.pill-status-success { background: #d1fae5; color: #065f46; }
|
.pill-status-success { background: #d1fae5; color: #065f46; }
|
||||||
.pill-status-secondary { background: #e5e7eb; color: #374151; }
|
.pill-status-secondary { background: #e5e7eb; color: #374151; }
|
||||||
.pill-status-warning { background: #fef3c7; color: #92400e; }
|
.pill-status-warning { background: #fef3c7; color: #92400e; }
|
||||||
|
.pill-status-danger { background: #fee2e2; color: #991b1b; }
|
||||||
|
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
border-bottom: 1px solid #e2e8f0;
|
border-bottom: 1px solid #e2e8f0;
|
||||||
@@ -871,9 +881,11 @@ function fmtFileSize(?int $bytes): string {
|
|||||||
<?php foreach ($trainings as $t): ?>
|
<?php foreach ($trainings as $t): ?>
|
||||||
<?php
|
<?php
|
||||||
$tid = (int)$t['id'];
|
$tid = (int)$t['id'];
|
||||||
$s = trainingStatus($t['next_due_date'] ?: null,
|
$s = !empty($t['_is_latest'])
|
||||||
|
? trainingStatus($t['next_due_date'] ?: null,
|
||||||
$t['reminder_days'] !== null ? (int)$t['reminder_days'] : null,
|
$t['reminder_days'] !== null ? (int)$t['reminder_days'] : null,
|
||||||
$t['topic_default_rem'] !== null ? (int)$t['topic_default_rem'] : null);
|
$t['topic_default_rem'] !== null ? (int)$t['topic_default_rem'] : null)
|
||||||
|
: ['code' => 'storico', 'label' => 'Storico', 'class' => 'secondary'];
|
||||||
$typeLabel = $t['training_type'] === 'refresher' ? 'Aggiornamento' : 'Iniziale';
|
$typeLabel = $t['training_type'] === 'refresher' ? 'Aggiornamento' : 'Iniziale';
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -918,9 +930,11 @@ function fmtFileSize(?int $bytes): string {
|
|||||||
<?php foreach ($trainings as $t): ?>
|
<?php foreach ($trainings as $t): ?>
|
||||||
<?php
|
<?php
|
||||||
$tid = (int)$t['id'];
|
$tid = (int)$t['id'];
|
||||||
$s = trainingStatus($t['next_due_date'] ?: null,
|
$s = !empty($t['_is_latest'])
|
||||||
|
? trainingStatus($t['next_due_date'] ?: null,
|
||||||
$t['reminder_days'] !== null ? (int)$t['reminder_days'] : null,
|
$t['reminder_days'] !== null ? (int)$t['reminder_days'] : null,
|
||||||
$t['topic_default_rem'] !== null ? (int)$t['topic_default_rem'] : null);
|
$t['topic_default_rem'] !== null ? (int)$t['topic_default_rem'] : null)
|
||||||
|
: ['code' => 'storico', 'label' => 'Storico', 'class' => 'secondary'];
|
||||||
$typeLabel = $t['training_type'] === 'refresher' ? 'Aggiornamento' : 'Iniziale';
|
$typeLabel = $t['training_type'] === 'refresher' ? 'Aggiornamento' : 'Iniziale';
|
||||||
?>
|
?>
|
||||||
<div class="doc-card">
|
<div class="doc-card">
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ if (!$__trWidgetHr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only the most recent record per (employee, topic) — older history rows ignored. */
|
||||||
$__trRows = $pdo->query("
|
$__trRows = $pdo->query("
|
||||||
SELECT et.id,
|
SELECT et.id,
|
||||||
et.next_due_date,
|
et.next_due_date,
|
||||||
@@ -27,6 +28,13 @@ $__trRows = $pdo->query("
|
|||||||
FROM employee_trainings et
|
FROM employee_trainings et
|
||||||
JOIN training_topics tt ON tt.id = et.training_topic_id
|
JOIN training_topics tt ON tt.id = et.training_topic_id
|
||||||
WHERE et.next_due_date IS NOT NULL
|
WHERE et.next_due_date IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM employee_trainings et2
|
||||||
|
WHERE et2.employee_id = et.employee_id
|
||||||
|
AND et2.training_topic_id = et.training_topic_id
|
||||||
|
AND (et2.completed_date > et.completed_date
|
||||||
|
OR (et2.completed_date = et.completed_date AND et2.id > et.id))
|
||||||
|
)
|
||||||
")->fetchAll(PDO::FETCH_ASSOC);
|
")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$__expiredCount = 0;
|
$__expiredCount = 0;
|
||||||
|
|||||||
@@ -30,6 +30,15 @@ $fDepartmentId = isset($_GET['department_id'])&& $_GET['department_id']!== '' ?
|
|||||||
========================================== */
|
========================================== */
|
||||||
$where = [];
|
$where = [];
|
||||||
$params = [];
|
$params = [];
|
||||||
|
// Only the most recent record per (employee, topic) — older initial/refresher
|
||||||
|
// rows stay as history on the employee profile, not in this overview.
|
||||||
|
$where[] = "NOT EXISTS (
|
||||||
|
SELECT 1 FROM employee_trainings et2
|
||||||
|
WHERE et2.employee_id = et.employee_id
|
||||||
|
AND et2.training_topic_id = et.training_topic_id
|
||||||
|
AND (et2.completed_date > et.completed_date
|
||||||
|
OR (et2.completed_date = et.completed_date AND et2.id > et.id))
|
||||||
|
)";
|
||||||
if ($fEmployeeId > 0) { $where[] = 'et.employee_id = :eid'; $params['eid'] = $fEmployeeId; }
|
if ($fEmployeeId > 0) { $where[] = 'et.employee_id = :eid'; $params['eid'] = $fEmployeeId; }
|
||||||
if ($fTopicId > 0) { $where[] = 'et.training_topic_id = :tid'; $params['tid'] = $fTopicId; }
|
if ($fTopicId > 0) { $where[] = 'et.training_topic_id = :tid'; $params['tid'] = $fTopicId; }
|
||||||
if ($fType !== '' && in_array($fType, ['initial', 'refresher'], true)) {
|
if ($fType !== '' && in_array($fType, ['initial', 'refresher'], true)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user