From 2bde9a23eb2212a3f163d92e2c3cc96000989d5f Mon Sep 17 00:00:00 2001 From: Herafia Date: Mon, 19 Jan 2026 17:22:04 +0100 Subject: [PATCH 1/4] duplication task (rules) when change category --- inc/ticket.class.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/ticket.class.php b/inc/ticket.class.php index 677607b..17b2b19 100644 --- a/inc/ticket.class.php +++ b/inc/ticket.class.php @@ -102,10 +102,14 @@ public static function pre_item_update(CommonDBTM $item) } $temp_input['_disablenotif'] = true; // Disable notifications for this validation + $item->input['_skip_rules'] = true; $input = $item->prepareInputForUpdate($temp_input); + $item->input['_skip_rules'] = false; unset($item->input['_no_escalade_template_validation']); // Clean up flag } else { + $item->input['_skip_rules'] = true; $input = $item->prepareInputForUpdate($item->input); + $item->input['_skip_rules'] = false; } if (!$input) { From 66f8e34786f15d9d5e56a4c4b4c25ca9ba3923d9 Mon Sep 17 00:00:00 2001 From: Herafia Date: Tue, 20 Jan 2026 09:29:50 +0100 Subject: [PATCH 2/4] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1dce5b..e70f873 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [UNRELEASED] + +### Fixed + +- Fix rules duplication + ## [2.10.1] - 2025-12-09 ### Fixed From be2ea130d55cdbcbd0984d904d45d3a534a1202b Mon Sep 17 00:00:00 2001 From: Herafia Date: Tue, 20 Jan 2026 15:52:12 +0100 Subject: [PATCH 3/4] tests unit --- tests/Units/TicketTest.php | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/Units/TicketTest.php b/tests/Units/TicketTest.php index 16dcd22..52b0d56 100644 --- a/tests/Units/TicketTest.php +++ b/tests/Units/TicketTest.php @@ -42,6 +42,7 @@ use Ticket; use Ticket_User; use User; +use TicketTask; final class TicketTest extends EscaladeTestCase { @@ -1257,4 +1258,79 @@ public function testHistoryButtonEscalationWithMandatoryTemplateFields() $group1->delete(['id' => $group1_id], true); $group2->delete(['id' => $group2_id], true); } + + public function testRuleCreatesTaskWhenCategoryAssigned() + { + $this->initConfig(); + + // Create a task template that will be added by the rule + $task_template = $this->createItem('TaskTemplate', [ + 'name' => 'Rule task template', + 'content' => '

Task created by rule

', + 'entities_id' => 0, + 'is_recursive' => 1, + ]); + $task_template_id = $task_template->getID(); + + // Create the rule that appends a task template when category is set on update + $rule = $this->createItem('Rule', [ + 'name' => 'Create task on category assign', + 'sub_type' => 'RuleTicket', + 'match' => 'AND', + 'is_active' => 1, + 'condition' => \RuleCommonITILObject::ONUPDATE, + 'is_recursive' => 1, + 'entities_id' => 0, + ]); + $rule_id = $rule->getID(); + + $this->createItem('RuleAction', [ + 'rules_id' => $rule_id, + 'action_type' => 'append', + 'field' => 'task_template', + 'value' => $task_template_id, + ]); + + // Create a category that will trigger the rule when assigned + $category = $this->createItem('ITILCategory', [ + 'name' => 'Category triggering task', + 'entities_id' => 0, + 'is_recursive' => 1, + ]); + $category_id = $category->getID(); + + // Ensure the rule triggers only when the ticket category matches the created category + $this->createItem('RuleCriteria', [ + 'rules_id' => $rule_id, + 'criteria' => 'itilcategories_id', + 'condition' => \Rule::PATTERN_IS, + 'pattern' => $category_id, + ]); + + // Create a ticket without category + $ticket = $this->createItem('Ticket', [ + 'name' => 'Ticket for rule test', + 'content' => 'Content for rule test', + 'entities_id' => 0, + ]); + $ticket_id = $ticket->getID(); + + $tickettask = new TicketTask(); + $this->assertEquals(0, count($tickettask->find(['tickets_id' => $ticket_id]))); + + // Assign the category (update) - rule should fire and create a single task + $this->updateItem('Ticket', $ticket_id, [ + 'id' => $ticket_id, + 'itilcategories_id' => $category_id, + ]); + + $tasks = $tickettask->find(['tickets_id' => $ticket_id]); + $this->assertEquals(1, count($tasks)); + + // Clean up + $ticket->delete(['id' => $ticket_id], true); + $task_template->delete(['id' => $task_template_id], true); + $category->delete(['id' => $category_id], true); + $rule->delete(['id' => $rule_id], true); + } } From a24a4ac3a5bd280d809df71e1f55ff84aa7d2ea0 Mon Sep 17 00:00:00 2001 From: Herafia Date: Tue, 20 Jan 2026 16:04:30 +0100 Subject: [PATCH 4/4] test test --- tests/Units/TicketTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Units/TicketTest.php b/tests/Units/TicketTest.php index 52b0d56..3eac308 100644 --- a/tests/Units/TicketTest.php +++ b/tests/Units/TicketTest.php @@ -39,6 +39,8 @@ use Group_User; use ITILCategory; use PluginEscaladeTicket; +use Rule; +use RuleCommonITILObject; use Ticket; use Ticket_User; use User; @@ -1278,7 +1280,7 @@ public function testRuleCreatesTaskWhenCategoryAssigned() 'sub_type' => 'RuleTicket', 'match' => 'AND', 'is_active' => 1, - 'condition' => \RuleCommonITILObject::ONUPDATE, + 'condition' => RuleCommonITILObject::ONUPDATE, 'is_recursive' => 1, 'entities_id' => 0, ]); @@ -1303,7 +1305,7 @@ public function testRuleCreatesTaskWhenCategoryAssigned() $this->createItem('RuleCriteria', [ 'rules_id' => $rule_id, 'criteria' => 'itilcategories_id', - 'condition' => \Rule::PATTERN_IS, + 'condition' => Rule::PATTERN_IS, 'pattern' => $category_id, ]);