diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b582f6f..a45cf583 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 mandatory fields of a block hidden by its display conditions blocking the save of an item + ## [1.24.6] - 2026-10-06 ### Added diff --git a/inc/container.class.php b/inc/container.class.php index 0bed98d9..41822731 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -2212,6 +2212,12 @@ private static function checkContainerMandatory(CommonDBTM $item, PluginFieldsCo return []; } + //container hidden by its display conditions: its fields can't be filled + $display_condition = new PluginFieldsContainerDisplayCondition(); + if (!$display_condition->computeDisplayContainer($item, $c_id)) { + return []; + } + $status_field_name = PluginFieldsStatusOverride::getStatusFieldName($item::getType()); $data = ['plugin_fields_containers_id' => $c_id]; if ($item->input['_auto_import'] ?? false) { diff --git a/tests/Units/ContainerItemUpdateTest.php b/tests/Units/ContainerItemUpdateTest.php index 90367905..f68a24e2 100644 --- a/tests/Units/ContainerItemUpdateTest.php +++ b/tests/Units/ContainerItemUpdateTest.php @@ -35,6 +35,7 @@ use Glpi\Tests\GLPITestCase; use GlpiPlugin\Field\Tests\FieldTestTrait; use PluginFieldsContainer; +use PluginFieldsContainerDisplayCondition; use Ticket; use Entity; use Notification; @@ -1034,4 +1035,76 @@ public function testSuccessiveUpdatesOverwritePluginFieldValues(): void 'Plugin value must not be erased by a native-only update.', ); } + + /** + * A mandatory DOM field must not block creation/update when its container is + * hidden by a display condition. + */ + public function testNotBlockedWhenMandatoryDomContainerIsHidden(): void + { + $this->login(); + + $container = $this->createFieldContainer([ + 'label' => 'Hidden Mandatory Dom Container', + 'type' => 'dom', + 'itemtypes' => [Ticket::class], + 'is_active' => 1, + 'entities_id' => 0, + 'is_recursive' => 1, + ]); + $this->createField([ + 'label' => 'Mandatory Field', + 'type' => 'text', + PluginFieldsContainer::getForeignKeyField() => $container->getID(), + 'ranking' => 1, + 'is_active' => 1, + 'is_readonly' => 0, + 'mandatory' => 1, + ]); + + // Hide the container for incidents. + $this->createItem(PluginFieldsContainerDisplayCondition::class, [ + PluginFieldsContainer::getForeignKeyField() => $container->getID(), + 'itemtype' => Ticket::class, + 'search_option' => 14, // type + 'condition' => PluginFieldsContainerDisplayCondition::SHOW_CONDITION_EQ, + 'value' => Ticket::INCIDENT_TYPE, + ]); + + // The container is visible for requests + $ticket = new Ticket(); + $ticket_id = $ticket->add([ + 'name' => 'Request with visible mandatory field', + 'content' => 'Test', + 'entities_id' => 0, + 'type' => Ticket::DEMAND_TYPE, + ]); + $this->assertFalse($ticket_id, 'A mandatory field in a visible container must block creation.'); + $this->hasSessionMessageThatContains( + __('Some mandatory fields are empty', 'fields'), + ERROR, + ); + $this->hasSessionMessageThatContains( + __('The form or source creating this item does not provide the mandatory fields above: map them to it, or make them optional.', 'fields'), + ERROR, + ); + + $ticket = new Ticket(); + $ticket = $this->createItem(Ticket::class, [ + 'name' => 'Incident with hidden mandatory field', + 'content' => 'Test', + 'entities_id' => 0, + 'type' => Ticket::INCIDENT_TYPE, + ]); + + $is_updated = $ticket->update([ + 'id' => $ticket->getID(), + 'type' => Ticket::DEMAND_TYPE, + ]); + $this->assertFalse($is_updated); + $this->hasSessionMessageThatContains( + __('Some mandatory fields are empty', 'fields'), + ERROR, + ); + } }