Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [unreleased]

### Fixed

- change status after escalation on update only

## [2.9.19] - 2026-27-01

### Fixed
Expand Down
37 changes: 28 additions & 9 deletions inc/ticket.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,27 @@ public static function AssignLastGroupOnRejectedSolution(CommonDBTM $item)
}
}

/**
* Check whether the current call stack originates from the creation of an ITIL
* object (Ticket, Change, Problem).
*
*
* @return bool
*/
private static function isRunningDuringItilCreation(): bool
{
foreach (debug_backtrace() as $backtrace) {
if (
$backtrace['function'] == "add"
&& ($backtrace['object'] instanceof CommonITILObject)
) {
return true;
}
}

return false;
}


/**
* remove old groups to a ticket when a new group assigned
Expand Down Expand Up @@ -480,14 +501,8 @@ public static function addHistoryOnAddGroup(CommonDBTM $item)

// check if group assignment is made during ticket creation
// in this case, skip following steps as it cannot be considered as a group escalation
$backtraces = debug_backtrace();
foreach ($backtraces as $backtrace) {
if (
$backtrace['function'] == "add"
&& ($backtrace['object'] instanceof CommonITILObject)
) {
return;
}
if (self::isRunningDuringItilCreation()) {
return;
}

//add a task to inform the escalation (pass if solution)
Expand Down Expand Up @@ -519,7 +534,11 @@ public static function processAfterAddGroup(Group_Ticket $item)
// The config is checked in the function.
self::removeAssignUsers($item);

if ($_SESSION['glpi_plugins']['escalade']['config']['ticket_last_status'] != self::MANAGED_BY_CORE) {
// Assigning a group during ticket creation is not an escalation, so the
// "status after an escalation" option must override the status only if it is not during ticket creation.
if (!self::isRunningDuringItilCreation()
&& $_SESSION['glpi_plugins']['escalade']['config']['ticket_last_status'] != self::MANAGED_BY_CORE
) {
$ticket = new Ticket();
$ticket->update([
'id' => $tickets_id,
Expand Down
105 changes: 105 additions & 0 deletions tests/Units/GroupEscalationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,111 @@ public function testHistory()
$this->assertEquals(1, count($history->find(['tickets_id' => $t_id, 'groups_id' => $group1_id])));
}

public function testStatusAfterEscalationIsNotAppliedOnTicketCreation()
{
$this->login();

// Force a specific status after an escalation.
$this->updateItem(
PluginEscaladeConfig::class,
1,
['ticket_last_status' => \CommonITILObject::WAITING],
);
PluginEscaladeConfig::loadInSession();

$group = $this->createItem(\Group::class, ['name' => 'Creation escalation group']);

// Create a ticket that is assigned to a group right away.
$ticket = $this->createItem(
\Ticket::class,
[
'name' => 'Status after escalation on creation',
'content' => 'content',
'_actors' => [
'assign' => [
[
'items_id' => $group->getID(),
'itemtype' => 'Group',
],
],
],
],
);

// The escalation status (WAITING) must not have been forced on creation.
$this->assertNotEquals(
\CommonITILObject::WAITING,
(int) $ticket->fields['status'],
'The "status after an escalation" option must not be applied on ticket creation',
);

// A ticket created with an assigned group is simply "assigned".
$this->assertEquals(\CommonITILObject::ASSIGNED, (int) $ticket->fields['status']);
}

public function testStatusAfterEscalationIsAppliedOnRealEscalation()
{
$this->login();

// Force a specific status after an escalation.
$this->updateItem(
PluginEscaladeConfig::class,
1,
['ticket_last_status' => \CommonITILObject::WAITING],
);
PluginEscaladeConfig::loadInSession();

$group1 = $this->createItem(\Group::class, ['name' => 'Escalation group 1']);
$group2 = $this->createItem(\Group::class, ['name' => 'Escalation group 2']);

// Create a ticket assigned to the first group (creation, not an escalation).
$ticket = $this->createItem(
\Ticket::class,
[
'name' => 'Status after real escalation',
'content' => 'content',
'_actors' => [
'assign' => [
[
'items_id' => $group1->getID(),
'itemtype' => 'Group',
],
],
],
],
);

$this->assertNotEquals(\CommonITILObject::WAITING, (int) $ticket->fields['status']);

// Escalate the existing ticket to a second group: this IS an escalation,
// so the configured status must now be applied.
$this->updateItem(
\Ticket::class,
$ticket->getID(),
[
'_actors' => [
'assign' => [
[
'items_id' => $group1->getID(),
'itemtype' => 'Group',
],
[
'items_id' => $group2->getID(),
'itemtype' => 'Group',
],
],
],
],
);

$this->assertTrue($ticket->getFromDB($ticket->getID()));
$this->assertEquals(
\CommonITILObject::WAITING,
(int) $ticket->fields['status'],
'The "status after an escalation" option must be applied on a real escalation',
);
}

/**
* Test that the standard target "Group in charge of the ticket"
* sends notifications to users of both groups (old and new) during an escalation
Expand Down