From 34e4ae66b6a685646e692bf9618e419ac0c268e4 Mon Sep 17 00:00:00 2001 From: MyvTsv Date: Thu, 5 Nov 2026 17:15:53 +0100 Subject: [PATCH 1/2] fix(core): Fix mandatory fields error when creating an item with an assigned technician --- CHANGELOG.md | 1 + inc/container.class.php | 41 ++++++++++++++++++++- tests/Units/ContainerItemUpdateTest.php | 47 +++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9779874c..0b0fdf13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fix search criterion value on multiple dropdown fields being reset after a search, which emptied the criterion when sorting or paging results +- Fix `Some mandatory fields are empty` error displayed when creating an item with an assigned technician ## [1.24.7] - 2026-10-28 diff --git a/inc/container.class.php b/inc/container.class.php index a5a78af4..dd15057e 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -38,6 +38,11 @@ class PluginFieldsContainer extends CommonDBTM public static $rightname = 'config'; + /** + * Values of the items being added, not stored yet + */ + private static ?WeakMap $pending_values = null; + public static function canCreate(): bool { return self::canUpdate(); @@ -2424,6 +2429,7 @@ public static function findAllContainers($itemtype) public static function postItemAdd(CommonDBTM $item) { PluginFieldsDestinationField::registerCreatedItem($item); + self::$pending_values?->offsetUnset($item); if (array_key_exists('_plugin_fields_data', $item->input)) { $container = new self(); @@ -2592,6 +2598,16 @@ public static function preItem(CommonDBTM $item) } } + if ($item->isNewItem()) { + $values_by_container = []; + foreach ($submitted_data as $data) { + $values_by_container[(int) $data['plugin_fields_containers_id']] = $data; + } + + self::$pending_values ??= new WeakMap(); + self::$pending_values[$item] = $values_by_container; + } + if ($submitted_data !== []) { $item->input['_plugin_fields_data'] = $submitted_data; @@ -2601,6 +2617,26 @@ public static function preItem(CommonDBTM $item) return false; } + /** + * Container values of an item being added, not stored yet + * + * @return array + */ + private static function getPendingValues(CommonDBTM $item, int $c_id): array + { + if (self::$pending_values === null || $item->isNewItem()) { + return []; + } + + foreach (self::$pending_values as $added_item => $values) { + if ($added_item::class === $item::class && $added_item->getID() === $item->getID()) { + return $values[$c_id] ?? []; + } + } + + return []; + } + /** * Validate a single container's mandatory fields for the given item, using * either the values submitted in this request or, if none were submitted @@ -2655,12 +2691,15 @@ private static function checkContainerMandatory(CommonDBTM $item, PluginFieldsCo if (!$item->isNewItem()) { $data['items_id'] = $item->getID(); - // merge already persisted values to avoid false positives + // merge already persisted values to avoid false positives, + // or the values still to be stored when the item is being added $classname = self::getClassname($item::getType(), $loc_c->fields['name']); $dbu = new DbUtils(); $obj = $dbu->getItemForItemtype($classname); if ($obj !== false && $obj->getFromDBByCrit(['items_id' => $item->getID()])) { $data += $obj->fields; + } else { + $data += self::getPendingValues($item, $c_id); } } diff --git a/tests/Units/ContainerItemUpdateTest.php b/tests/Units/ContainerItemUpdateTest.php index 4888a513..1873b944 100644 --- a/tests/Units/ContainerItemUpdateTest.php +++ b/tests/Units/ContainerItemUpdateTest.php @@ -37,10 +37,12 @@ use GlpiPlugin\Field\Tests\FieldTestTrait; use PluginFieldsContainer; use PluginFieldsContainerDisplayCondition; +use PluginFieldsField; use Ticket; use Entity; use Notification; use Problem; +use User; require_once __DIR__ . '/../FieldTestCase.php'; @@ -386,6 +388,51 @@ public function testCreateIsBlockedWhenMandatoryDomFieldIsMissing(): void $this->assertSame('filled value', $plugin_row[$field_name]); } + public function testCreateWithAssignedTechnicianAndMandatoryDomField(): void + { + $this->login(); + + $container = $this->createFieldContainer([ + 'label' => 'Mandatory Assign Container', + 'type' => 'dom', + 'itemtypes' => [Ticket::class], + 'is_active' => 1, + 'entities_id' => 0, + 'is_recursive' => 1, + ]); + + $field = $this->createField([ + 'label' => 'Mandatory Field', + 'type' => 'text', + PluginFieldsContainer::getForeignKeyField() => $container->getID(), + 'ranking' => 1, + 'is_active' => 1, + 'is_readonly' => 0, + 'mandatory' => 1, + ]); + $field_name = $field->fields['name']; + + $this->simulateApiBoot(); + + $ticket = $this->createItem(Ticket::class, [ + 'name' => 'Ticket with mandatory field and technician', + 'content' => 'Test creation', + 'entities_id' => 0, + '_actors' => [ + 'assign' => [ + ['itemtype' => User::class, 'items_id' => getItemByTypeName(User::class, 'tech', true)], + ], + ], + $field_name => 'filled value', + ], [$field_name]); + $this->hasNoSessionMessage(ERROR); + $this->assertSame(Ticket::ASSIGNED, $ticket->fields['status']); + + $plugin_row = $this->getPluginFieldValues(Ticket::class, $ticket->getID(), $container->getID()); + $this->assertNotFalse($plugin_row); + $this->assertSame('filled value', $plugin_row[$field_name]); + } + public function testCreateIsNotBlockedForInventoryCreatedItem(): void { $this->login(); From 5e35427d385f781f4ebf7a6de7b75b29279fdaa5 Mon Sep 17 00:00:00 2001 From: MyvTsv Date: Fri, 6 Nov 2026 10:01:07 +0100 Subject: [PATCH 2/2] fix lint --- inc/container.class.php | 2 +- tests/Units/ContainerItemUpdateTest.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/inc/container.class.php b/inc/container.class.php index dd15057e..907678af 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -2624,7 +2624,7 @@ public static function preItem(CommonDBTM $item) */ private static function getPendingValues(CommonDBTM $item, int $c_id): array { - if (self::$pending_values === null || $item->isNewItem()) { + if (!self::$pending_values instanceof WeakMap || $item->isNewItem()) { return []; } diff --git a/tests/Units/ContainerItemUpdateTest.php b/tests/Units/ContainerItemUpdateTest.php index 1873b944..a7a54e8c 100644 --- a/tests/Units/ContainerItemUpdateTest.php +++ b/tests/Units/ContainerItemUpdateTest.php @@ -37,7 +37,6 @@ use GlpiPlugin\Field\Tests\FieldTestTrait; use PluginFieldsContainer; use PluginFieldsContainerDisplayCondition; -use PluginFieldsField; use Ticket; use Entity; use Notification;