diff --git a/CHANGELOG.md b/CHANGELOG.md
index 269579a..55f6a66 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/).
+## [4.1.3] - 2026-01-26
+
+### Added
+
+- Added a new tab, that when checked, shows ticket's elements with their model
+
## [4.1.2] - 2026-01-08
### Fixed
diff --git a/inc/item_ticketmodel.class.php b/inc/item_ticketmodel.class.php
new file mode 100644
index 0000000..6addb55
--- /dev/null
+++ b/inc/item_ticketmodel.class.php
@@ -0,0 +1,140 @@
+fields['id'];
+
+ if (!$ticket->can($instID, READ)) {
+ return false;
+ }
+
+ $result = $DB->request('glpi_items_tickets',
+ ['SELECT' => 'itemtype',
+ 'DISTINCT' => true,
+ 'WHERE' => ['tickets_id' => $instID],
+ 'ORDER' => 'itemtype']);
+ $number = count($result);
+
+ $pdf->setColumnsSize(100);
+ $title = ''._n('Item', 'Items', $number).'';
+ if (!$number) {
+ $pdf->displayTitle(sprintf(__('%1$s: %2$s'), $title, __('No item to display')));
+ } else {
+ $title = sprintf(__('%1$s: %2$s'), $title, '');
+ $pdf->displayTitle($title);
+
+ $pdf->setColumnsSize(14, 14, 18, 12, 12, 12, 18);
+ $pdf->displayTitle("".__('Type'), __('Name'), __('Model'), __('Serial number'),
+ __('Inventory number'), __('Location'), __('Comments')."");
+
+ $totalnb = 0;
+ foreach ($result as $row) {
+ $itemtype = $row['itemtype'];
+ if (!($item = $dbu->getItemForItemtype($itemtype))) {
+ continue;
+ }
+
+ if ($item->canView()) {
+ $itemtable = $dbu->getTableForItemType($itemtype);
+
+ $model_name = substr($itemtable, 5, -1).'models';
+
+ $query = [
+ "SELECT" => [
+ "`$itemtable`" => ["*"],
+ "`glpi_items_tickets`" => ["`id` AS `IDD`"],
+ "`glpi_entities`" => ["`id` AS `entity`"]
+ ],
+ "FROM" => [
+ "`$itemtable`"
+ ]
+ ];
+
+ if ($itemtype != "Entity") {
+ $query["LEFT JOIN"] = [
+ "`glpi_entities`" => [
+ "ON" => [
+ "`$itemtable`" => "`entities_id`",
+ "`glpi_entities`" => "`id`"
+ ]
+ ]
+ ];
+ }
+
+ $query["INNER JOIN"] = [
+ "`glpi_items_tickets`" => [
+ "ON" => [
+ "`$itemtable`" => "`id`",
+ "`glpi_items_tickets`" => "`items_id`"
+ ]
+ ]
+ ];
+
+ $query["WHERE"] = [
+ "`glpi_items_tickets`.`itemtype`" => "$itemtype",
+ "`glpi_items_tickets`.`tickets_id`" => "$instID"
+ ];
+
+ if ($item->maybeTemplate()) {
+ $query["WHERE"]["AND"]["`$itemtable`.is_template"] = "0";
+ }
+
+ $query["ORDER"] = [
+ "`glpi_entities`.`completename`",
+ "`$itemtable`.`name`"
+ ];
+
+
+ $result_linked = $DB->request($query);
+ $nb = count($result_linked);
+
+ $prem = true;
+ foreach ($result_linked as $data) {
+ $name = $data["name"];
+ if (empty($data["name"])) {
+ $name = "(".$data["id"].")";
+ }
+ if (isset($data[$model_name."_id"])) {
+ $model = Dropdown::getDropdownName("glpi_".$model_name, $data[$model_name."_id"]);
+ } else {
+ $model = "";
+ }
+ if (isset($data["locations_id"])) {
+ $location = Dropdown::getDropdownName("glpi_locations", $data["locations_id"]);
+ } else {
+ $location = "";
+ }
+ if ($prem) {
+ $typename = $item->getTypeName($nb);
+ $pdf->displayLine(Toolbox::stripTags(sprintf(__('%1$s: %2$s'), $typename, $nb)),
+ Toolbox::stripTags($name),
+ Toolbox::stripTags($model),
+ isset($data["serial"])?Toolbox::stripTags($data["serial"]):'',
+ isset($data["otherserial"])?Toolbox::stripTags($data["otherserial"]):'',
+ Toolbox::stripTags($location),
+ Toolbox::stripTags($data['comment']??''),$nb);
+ } else {
+ $pdf->displayLine('',
+ Toolbox::stripTags($name),
+ Toolbox::stripTags($model),
+ isset($data["serial"])?Toolbox::stripTags($data["serial"]):'',
+ isset($data["otherserial"])?Toolbox::stripTags($data["otherserial"]):'',
+ Toolbox::stripTags($location),
+ Toolbox::stripTags($data['comment']??''),$nb);
+ }
+ $prem = false;
+ }
+ $totalnb += $nb;
+ }
+ }
+ $pdf->displayLine("".sprintf(__('%1$s = %2$s')."", __('Total'), $totalnb));
+ }
+ $pdf->displaySpace();
+ }
+}
diff --git a/inc/ticket.class.php b/inc/ticket.class.php
index 49a1213..4120377 100644
--- a/inc/ticket.class.php
+++ b/inc/ticket.class.php
@@ -598,6 +598,8 @@ public function defineAllTabsPDF($options = [])
$onglets['_inforequester_'] = __s('Requester information', 'pdf');
}
+ $onglets['Item_TicketModel$1'] = __s('Elements with model') . $onglets['Item_Ticket$1'];
+
return $onglets;
}
@@ -658,6 +660,10 @@ public static function displayTabContentForPDF(PluginPdfSimplePDF $pdf, CommonGL
PluginPdfTicket_Contract::pdfForTicket($pdf, $item);
break;
+ case 'Item_TicketModel$1' :
+ PluginPdfItem_TicketModel::pdfForTicket($pdf, $item);
+ break;
+
default:
return false;
}
diff --git a/setup.php b/setup.php
index f3da516..6df87b3 100644
--- a/setup.php
+++ b/setup.php
@@ -48,7 +48,7 @@ function plugin_init_pdf()
$PLUGIN_HOOKS['csrf_compliant']['pdf'] = true;
// manage autoload of tcppdf (glpi core now use mdpdf)
- include_once(Plugin::getPhpDir('pdf') . '/vendor/autoload.php');
+ // include_once(Plugin::getPhpDir('pdf') . '/vendor/autoload.php');
Plugin::registerClass('PluginPdfConfig', ['addtabon' => 'Config']);
$PLUGIN_HOOKS['config_page']['pdf'] = 'front/config.form.php';