From 6f94427f6a0e5cc03cd15287ef6dbe6aca82dcce Mon Sep 17 00:00:00 2001 From: Yoan Bozhilov Date: Tue, 28 Apr 2026 11:14:58 +0300 Subject: [PATCH 1/2] Add Orderable capacity and per-user permission filtering for GLPI 11 custom assets Following review feedback on pluginsGLPI#574, replace the unconditional auto-registration of all active custom asset definitions with an explicit, admin-controlled opt-in via a new Orderable capacity: - Introduce PluginOrderOrderableCapacity (extends \Glpi\Asset\Capacity\AbstractCapacity). Admins enable/disable it per asset definition under Setup -> Asset definitions -> {asset} -> Capacities. Provides label, icon, description, and a usage count based on existing PluginOrderReference rows. - In plugin_init_order(), register the capacity with AssetDefinitionManager, then iterate active definitions and append the generated asset class to $ORDER_TYPES only when: 1. the Orderable capacity is enabled on that definition, AND 2. the current user passes $class::canView() (which delegates to the asset's AssignableItem READ check + is_active). - The class_exists() guard preserves backward compatibility on GLPI <= 10.x. End-to-end tested on GLPI 11.0.6, PHP 8.3, Order plugin 2.12.6: - Capacity appears in the Capacities tab with proper label/icon/description. - With capacity disabled: custom asset is absent from the Item type dropdown. - With capacity enabled: custom asset appears, references can be created, Generate item massive action renders and submits, items reach Taken delivery state, and generated assets appear in the Assets section. - Native itemtypes remain unaffected. Addresses review comments from @stonebuzz on pluginsGLPI#574. --- CHANGELOG.md | 3 +++ inc/orderablecapacity.class.php | 45 +++++++++++++++++++++++++++++++++ setup.php | 23 +++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 inc/orderablecapacity.class.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 233952fe40..4b324348fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] +### Added +- Add an `Orderable` capacity for GLPI 11 custom asset definitions, allowing each definition to opt-in to being used as a Product reference itemtype. Asset classes are filtered by per-user read permission. + ### Fixed - Fix generate associated item massive action diff --git a/inc/orderablecapacity.class.php b/inc/orderablecapacity.class.php new file mode 100644 index 0000000000..951637c48a --- /dev/null +++ b/inc/orderablecapacity.class.php @@ -0,0 +1,45 @@ + + * Asset definitions -> {your asset} -> Capacities), the corresponding + * generated asset class is appended to $ORDER_TYPES and becomes selectable + * as an Item type when creating a Product reference. + */ +class PluginOrderOrderableCapacity extends \Glpi\Asset\Capacity\AbstractCapacity +{ + public function getLabel(): string + { + return __('Orderable', 'order'); + } + + public function getIcon(): string + { + return 'ti ti-shopping-cart'; + } + + public function getDescription(): string + { + return __( + 'Allow this asset to be referenced as a Product reference and ' + . 'generated from the Generate item massive action.', + 'order' + ); + } + + public function getCapacityUsageDescription(string $classname): string + { + $count = 0; + if (class_exists('PluginOrderReference')) { + $count = countElementsInTable( + \PluginOrderReference::getTable(), + ['itemtype' => $classname] + ); + } + return sprintf( + _n('Used by %d order reference', 'Used by %d order references', $count, 'order'), + $count + ); + } +} diff --git a/setup.php b/setup.php index 7cd7cfd6b0..d59fdfcc4f 100644 --- a/setup.php +++ b/setup.php @@ -125,6 +125,29 @@ function plugin_init_order() 'Pdu', ]; + + // Register the Orderable capacity for GLPI 11 custom assets and append + // any custom asset class that has it enabled to $ORDER_TYPES, provided + // the current user is allowed to view it. + if (class_exists(\Glpi\Asset\AssetDefinitionManager::class)) { + $asset_manager = \Glpi\Asset\AssetDefinitionManager::getInstance(); + $orderable_capacity = new PluginOrderOrderableCapacity(); + $asset_manager->registerCapacity($orderable_capacity); + $asset_manager->bootDefinitions(); + foreach ($asset_manager->getDefinitions(true) as $definition) { + if (!$definition->hasCapacityEnabled($orderable_capacity)) { + continue; + } + $custom_asset_class = $definition->getAssetClassName(); + if ( + !in_array($custom_asset_class, $ORDER_TYPES, true) + && $custom_asset_class::canView() + ) { + $ORDER_TYPES[] = $custom_asset_class; + } + } + } + $CFG_GLPI['plugin_order_types'] = $ORDER_TYPES; $PLUGIN_HOOKS['pre_item_purge']['order'] = [ From 5fd09757a11bfe1962385648d42c224f9ac0139d Mon Sep 17 00:00:00 2001 From: Yoan Bozhilov Date: Tue, 28 Apr 2026 17:22:12 +0300 Subject: [PATCH 2/2] Clean up linked plugin data when Orderable capacity is disabled Following further review feedback on pluginsGLPI#574, implement the onCapacityDisabled() callback on PluginOrderOrderableCapacity so that disabling the Orderable capacity on a custom asset definition removes the plugin data that becomes meaningless once the asset class is no longer orderable. The cascade order matters: PluginOrderReference::pre_deleteItem() refuses deletion while a reference is still in use by orders_items rows, so child records (order line items) are removed before parent records (product references). Both passes target only rows whose itemtype matches the disabled custom asset class, leaving native itemtypes and other custom assets untouched. Free-form references (PluginOrderReferenceFree) are intentionally not touched, as they are standalone records that do not store any itemtype. End-to-end tested on GLPI 11.0.6, PHP 8.3 on two independent installations: - Disabling the capacity on a definition with linked references and order line items removes both, with native itemtypes and other custom assets untouched. - Re-enabling the capacity restores the asset class in the Item type dropdown; new references and order items can be created normally. - The capacity usage description (visible in the Capacities tab and in the GLPI confirmation dialog) shows the correct count of order references that will be removed if the admin proceeds. Addresses follow-up review comment from @stonebuzz on pluginsGLPI#574. --- CHANGELOG.md | 2 +- inc/orderablecapacity.class.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b324348fe..279f830d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] ### Added -- Add an `Orderable` capacity for GLPI 11 custom asset definitions, allowing each definition to opt-in to being used as a Product reference itemtype. Asset classes are filtered by per-user read permission. +- Add an `Orderable` capacity for GLPI 11 custom asset definitions, allowing each definition to opt-in to being used as a Product reference itemtype. Asset classes are filtered by per-user read permission. Disabling the capacity on a definition cleans up its order line items and product references. ### Fixed diff --git a/inc/orderablecapacity.class.php b/inc/orderablecapacity.class.php index 951637c48a..47c4578da1 100644 --- a/inc/orderablecapacity.class.php +++ b/inc/orderablecapacity.class.php @@ -42,4 +42,32 @@ public function getCapacityUsageDescription(string $classname): string $count ); } + + /** + * Clean up plugin data linked to the asset class when the capacity is + * disabled on its definition: remove Product references targeting the + * class and order line items that link orders to instances of the class. + * Free-form references are intentionally left untouched, as they are + * standalone records that do not reference any itemtype. + */ + public function onCapacityDisabled(string $classname, \Glpi\Asset\CapacityConfig $config): void + { + // Delete order line items first: PluginOrderReference::pre_deleteItem() + // refuses deletion while references are still in use by orders_items, + // so child records must be removed before parent references. + if (class_exists('PluginOrderOrder_Item')) { + (new \PluginOrderOrder_Item())->deleteByCriteria( + ['itemtype' => $classname], + force: true, + history: false + ); + } + if (class_exists('PluginOrderReference')) { + (new \PluginOrderReference())->deleteByCriteria( + ['itemtype' => $classname], + force: true, + history: false + ); + } + } }