Отслеживайте, кто просматривал каждую заявку в GLPI, с Ticket Tracker

В стандартном GLPI нет журнала прочтений. Бесплатный модуль Ticket Tracker записывает каждый просмотр заявки — счётчик, первое и последнее прочтение и журнал каждого обращения по пользователю — и позволяет SQL-запросами находить заявки, которые ответственный так и не открыл.

В этой статьеРазделов: 7

В стандартном GLPI нет журнала прочтений: история заявки хранит то, что изменилось, но никогда — кто просто открыл и прочитал. В сопровождении клиентских инсталляций GLPI это выливается в классический тупик «специалист даже не посмотрел заявку» против «нет, я читал» — и без объективных данных это слово одного против слова другого. Бесплатный модуль Ticket Tracker закрывает этот пробел, регистрируя каждый просмотр заявки. В этом руководстве показано, как он записывает данные, как настроить его, не раздувая счётчики, и три SQL-запроса, которые сразу отвечают на вопрос «кто что прочитал».

Почему GLPI не знает, кто прочитал заявку

Встроенная история (glpi_logs) фиксирует только изменения: создание, смену статуса, новый комментарий, смену специалиста. Открытие формы и чтение не меняют ни одного поля, поэтому никакой строки не появляется. В ядре GLPI нет события «просмотр». Ticket Tracker решает это, подключаясь к моменту отрисовки формы заявки (хук postShowItem у Ticket): каждый раз, когда аутентифицированный сеанс отображает заявку, модуль записывает просмотр. Без ручных действий и без новых полей в форме.

Два уровня записи: сводка и журнал

Модуль пишет в две таблицы с разным назначением. Сводная отвечает на вопрос «сколько раз и когда»; журнальная — «каждое обращение по отдельности»:

-- Summary per (ticket, user): one row, updated on each access.
CREATE TABLE `glpi_plugin_nextool_tickettracker_views` (
  `id`         int unsigned NOT NULL AUTO_INCREMENT,
  `tickets_id` int unsigned NOT NULL,
  `users_id`   int unsigned NOT NULL,
  `view_count` int unsigned NOT NULL DEFAULT 1,
  `first_view` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `last_view`  timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_ticket_user` (`tickets_id`, `users_id`)
);

-- Detailed log: one row per individual access.
CREATE TABLE `glpi_plugin_nextool_tickettracker_viewlog` (
  `id`         int unsigned NOT NULL AUTO_INCREMENT,
  `tickets_id` int unsigned NOT NULL,
  `users_id`   int unsigned NOT NULL,
  `view_date`  timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
);

Ключ UNIQUE (tickets_id, users_id) — сердце сводной таблицы: у каждой пары заявка/пользователь ровно одна строка. Запись выполняется через INSERT ... ON DUPLICATE KEY UPDATE view_count = view_count + 1 — атомарный upsert: два одновременных обращения одного пользователя не создают дублирующую строку и не теряют счёт. Вкладка «Просмотры» в заявке читает сводку (таблица со всеми просмотревшими, счётчиком, первым и последним прочтением) и предлагает раскрывающийся список, который подтягивает из журнала каждое отдельное обращение с датой и временем.

Включение и чек-лист настройки

Модуль бесплатный и включается в каталоге NexTool. После активации настройки находятся в Модули > Ticket Tracker, вкладка Функциональность:

  1. Модуль активен — тот же переключатель, что на странице Модулей. Если выключен, ничего не отслеживается.
  2. Отслеживание активно (tracking_enabled) — включает запись просмотров. Может быть включено при скрытой вкладке, если вы хотите собирать данные, не показывая их.
  3. Показывать вкладку в заявке (show_tab_on_ticket) — показывает или скрывает вкладку «Просмотры» в форме заявки.
  4. Минимальный интервал (с) (min_interval_seconds, по умолчанию 60) — окно debounce: обращения одного пользователя к одной заявке в пределах этого интервала считаются одним.
  5. Игнорируемые (вкладка Дополнительные права) — пользователи, профили или группы, чьи просмотры не отслеживаются. Если всё пусто — учитываются все обращения.

Ошибка настройки, которая раздувает (или обнуляет) счётчики

Частая ошибка — обнулить минимальный интервал в расчёте на то, что «чем детальнее, тем лучше». Хук срабатывает при каждой отрисовке формы — в том числе при перезагрузках, возврате назад и повторном открытии вкладки. При min_interval_seconds = 0 специалист, который держит заявку открытой и трижды нажимает F5, превращается в «три прочтения», и view_count теряет смысл «сколько раз он действительно возвращался к вопросу». Значение по умолчанию 60 секунд существует именно для того, чтобы схлопнуть серию перезагрузок в одно прочтение. Используйте 0 только для разовой диагностики и затем вернитесь к значению по умолчанию.

Вторая ошибка тоньше, и мы столкнулись с ней у клиента: до версии модуля 1.2.0 запись зависела от права видеть вкладку «Просмотры» — то есть учитывались только административные профили. Инициатор и наблюдатели открывали заявку, и ничего не фиксировалось, поэтому база недоучитывала как раз тех, кто важнее всего в споре об SLA. Мы отвязали запись от права видеть вкладку: сейчас учитывается любой аутентифицированный сеанс, отрисовавший заявку, — инициатор, наблюдатель или специалист — независимо от профиля. Если у вас более ранняя версия, обновитесь, прежде чем доверять цифрам.

Матрица решений: интервал и игнорируемые по сценариям

Правильная настройка зависит от того, что вы хотите доказать. Матрица, которую мы используем при проектировании:

Сценарий эксплуатацииОтслеживаниеМинимальный интервал (с)Кого добавить в «игнорируемые»
Аудит прочтений / SLA (по умолчанию)Включено60Никого
Инсталляция с автообновлением или настенной панельюВключено180–300Интеграционные учётные записи / роботы
Контроль, который не должен раздувать счётчикВключено60Профиль руководителей / аудиторов
Разовая диагностика (считать каждое обращение)Включено0 (временно)Никого

Три SQL-запроса, которые отвечают сразу

Вкладка решает вопрос по отдельной заявке; для картины по всей инсталляции идите прямо в базу. Открытые назначенные заявки, которые ответственный специалист ещё не открывал (type = 2 в glpi_tickets_users — назначенный специалист):

-- Open assigned tickets the responsible technician has NEVER viewed.
SELECT t.id AS ticket, t.name AS title, u.name AS technician, t.date AS opened_at
FROM glpi_tickets t
JOIN glpi_tickets_users tu ON tu.tickets_id = t.id AND tu.type = 2
JOIN glpi_users u ON u.id = tu.users_id
LEFT JOIN glpi_plugin_nextool_tickettracker_views v
       ON v.tickets_id = t.id AND v.users_id = tu.users_id
WHERE t.is_deleted = 0
  AND t.status IN (1, 2, 3, 4)   -- new, assigned, planned, pending
  AND v.id IS NULL               -- no read logged by the technician
ORDER BY t.date ASC;

Задержка прочтения — сколько минут заявка была открыта до первого прочтения назначенным специалистом. Эта метрика предшествует первому ответу и часто объясняет нарушенный SLA:

-- Minutes between opening and the 1st read by the assigned technician.
SELECT t.id AS ticket,
       TIMESTAMPDIFF(MINUTE, t.date, v.first_view) AS minutes_to_first_read
FROM glpi_tickets t
JOIN glpi_tickets_users tu ON tu.tickets_id = t.id AND tu.type = 2
JOIN glpi_plugin_nextool_tickettracker_views v
       ON v.tickets_id = t.id AND v.users_id = tu.users_id
WHERE t.is_deleted = 0
ORDER BY minutes_to_first_read DESC;

Самые активные просматривающие конкретной заявки, из сводки, — чтобы понять, кто действительно следит за ней (замените 12345 на ID заявки):

-- Who opened ticket 12345 the most, from most recurrent to least.
SELECT u.name AS username, v.view_count, v.first_view, v.last_view
FROM glpi_plugin_nextool_tickettracker_views v
JOIN glpi_users u ON u.id = v.users_id
WHERE v.tickets_id = 12345
ORDER BY v.view_count DESC;

Прочтение — не ответ: что доказывает счётчик

Данные мощные, но у них есть честное ограничение: они доказывают, что форма была отрисована для этого пользователя, а не что человек внимательно прочитал или что-то сделал. Высокий view_count без комментариев — жёлтый сигнал: кто-то открывает и закрывает, не решая. Заявка с нулём просмотров у ответственного при идущем SLA — красный сигнал: никто даже не посмотрел. В сопровождении реальная ценность не в слежке за специалистами, а в закрытии доказательного пробела: когда клиент спрашивает «почему эта заявка простояла три дня?», ответ перестаёт быть мнением и получает отметку даты и времени.

Нужна реальная прозрачность работы службы поддержки в вашем GLPI, с правильными модулями, включёнными и настроенными под ваш процесс? Узнайте о сопровождении GLPI от NexTool.


Проверено командой NexTool Solutions.

Часто задаваемые вопросы

Нет. История (glpi_logs) записывает только изменения полей — статус, комментарий, смену специалиста. Открытие и чтение ничего не меняют, поэтому нативного журнала просмотров нет. Ticket Tracker заполняет этот пробел, записывая каждое отображение формы заявки.

В текущей версии нет. Подробный журнал хранит заявку, пользователя и дату/время каждого обращения; идентификация идёт по аутентифицированному пользователю GLPI, а не по IP. Для аудита по людям users_id надёжнее IP, который меняется из-за VPN, NAT и прокси.

Нет, если настроен минимальный интервал. Значение по умолчанию 60 секунд означает, что обращения одного пользователя к одной заявке в пределах окна считаются одним. Только при интервале 0 каждый F5 становится прочтением — используйте 0 лишь для диагностики и затем верните значение по умолчанию.

Добавьте пользователя, профиль или группу в список «игнорируемых» (вкладка Дополнительные права). Они просматривают заявки как обычно, но обращение не фиксируется — это полезно для контроля и для интеграционных учётных записей.

Соедините glpi_tickets_users (type = 2, назначенный специалист) со сводной таблицей модуля через LEFT JOIN и отфильтруйте v.id IS NULL. Запрос из статьи выводит ровно открытые назначенные заявки, которые ответственный ни разу не прочитал.

Да. Это бесплатный модуль NexTool, доступный для GLPI 10 и 11, который включается прямо из каталога без обязательной дополнительной настройки.

Нужна помощь?