Skip to content

[ENHANCEMENT] Auto-unassign user from tickets during approved holiday period #54

@giovanny07

Description

@giovanny07

Plugin version: 3.2.6
GLPI version: 11.x
Priority: Medium
File: src/HolidayValidation.php
Related issue: #7

Summary

When a holiday is approved, technicians assigned to open tickets during that period are not automatically unassigned. This means tickets remain assigned to an unavailable technician, potentially breaching SLA without any warning. This enhancement adds an opt-in auto-unassign behavior triggered on holiday approval.

Proposed behavior

When a holiday transitions to ACCEPTED status:

  1. Find all open tickets where the applicant is assigned as a technician.
  2. If the ticket's expected resolution date falls within the holiday period, or if the ticket has no planned end date, optionally unassign the technician.
  3. Log the unassignment in the ticket's followups for traceability.
  4. Optionally reassign to a group manager or leave unassigned (configurable).

Implementation

Step 1 — Add configuration option

// src/Option.php — add to getDefaultValues() and to the options form
'auto_unassign_on_holiday' => 0,  // 0 = disabled, 1 = enabled

Step 2 — Hook into holiday approval in HolidayValidation

// src/HolidayValidation.php

public function post_updateItem(array $history = []): void
{
    // Only act when transitioning to ACCEPTED
    if (!isset($this->input['accept_holiday']) || $this->input['accept_holiday'] != 1) {
        return;
    }

    $holiday = new Holiday();
    if (!$holiday->getFromDB($this->fields['plugin_activity_holidays_id'])) {
        return;
    }

    $opt = Option::getInstance();
    if (!$opt->fields['auto_unassign_on_holiday']) {
        return;
    }

    self::unassignUserDuringHoliday($holiday);

    // Raise the answer notification
    NotificationEvent::raiseEvent('answervalidation', $holiday);
}

/**
 * Unassign a user from open tickets that overlap with their holiday period.
 */
public static function unassignUserDuringHoliday(Holiday $holiday): void
{
    global $DB;

    $usersId    = (int) $holiday->fields['users_id'];
    $beginDate  = $holiday->fields['begin'];
    $endDate    = $holiday->fields['end'];

    // Find all open tickets where this user is assigned as a technician
    // and the ticket is open during the holiday window
    $iterator = $DB->request([
        'SELECT' => ['t.id AS ticket_id', 'tu.id AS ticket_user_id'],
        'FROM'   => 'glpi_tickets AS t',
        'INNER JOIN' => [
            'glpi_tickets_users AS tu' => [
                'FKEY' => ['t' => 'id', 'tu' => 'tickets_id'],
            ],
        ],
        'WHERE'  => [
            'tu.users_id' => $usersId,
            'tu.type'     => CommonITILActor::ASSIGN,
            't.status'    => ['NOT IN', [CommonITILObject::CLOSED, CommonITILObject::SOLVED]],
            // Ticket overlaps with holiday (no expected end OR expected end is during holiday)
            'OR' => [
                ['t.time_to_resolve' => null],
                [
                    ['t.time_to_resolve' => ['>=', $beginDate . ' 00:00:00']],
                    ['t.time_to_resolve' => ['<=', $endDate   . ' 23:59:59']],
                ],
            ],
        ],
    ]);

    foreach ($iterator as $row) {
        // Remove the assignment
        $ticketUser = new Ticket_User();
        $ticketUser->delete(['id' => $row['ticket_user_id']], true);

        // Add a followup explaining the unassignment
        $ticket = new Ticket();
        $ticket->getFromDB($row['ticket_id']);

        $followup = new ITILFollowup();
        $followup->add([
            'itemtype'        => Ticket::class,
            'items_id'        => $row['ticket_id'],
            'content'         => sprintf(
                __('%s has been unassigned from this ticket due to an approved holiday from %s to %s.', 'activity'),
                getUserName($usersId),
                Html::convDate($beginDate),
                Html::convDate($endDate)
            ),
            'is_private'      => 1,
            'requesttypes_id' => 6, // Automatic followup
            'users_id'        => 0, // System
        ]);
    }
}

Step 3 — Add toggle in the plugin Options form

{# templates/option_form.html.twig — add field #}
{{ fields.checkboxField(
    'auto_unassign_on_holiday',
    item.fields['auto_unassign_on_holiday'],
    __('Auto-unassign technician from tickets when holiday is approved', 'activity')
) }}

Configuration

The feature is opt-in and disabled by default to avoid unexpected behavior on existing installations. It can be enabled in Activity > Configuration > Options.

Notes

  • Only tickets in NEW, ASSIGNED, PLANNED, or PENDING status are affected.
  • The user is always logged in the ticket followup so the change is traceable.
  • Consider a future enhancement to optionally reassign to the user's group manager (use_groupmanager option already exists in the plugin).
  • This resolves the feature request in issue Not adding people / removing them as assignees if they are on holiday #7.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions