diff --git a/install/Install.php b/install/Install.php index 34c1cebb..1ba40627 100644 --- a/install/Install.php +++ b/install/Install.php @@ -105,11 +105,18 @@ public function install(array $args = []): bool global $DB; $dbFile = plugin_carbon_getSchemaPath(); - if ($dbFile === null || !$DB->runFile($dbFile)) { + if ($dbFile === null) { $this->migration->addWarningMessage("Error creating tables : " . $DB->error()); return false; } + try { + $DB->runFile($dbFile); + } catch (\RuntimeException $e) { + $this->migration->addWarningMessage("Error creating tables : " . $e->getMessage()); + return false; + } + // Execute all install sub tasks $install_dir = __DIR__ . '/install/'; $update_scripts = scandir($install_dir); diff --git a/install/data/carbon_intensity/carbon-intensity-electricity.txt b/install/data/carbon_intensity/carbon-intensity-electricity.txt new file mode 100644 index 00000000..a776620c --- /dev/null +++ b/install/data/carbon_intensity/carbon-intensity-electricity.txt @@ -0,0 +1,2 @@ +Data source: +https://ourworldindata.org/grapher/carbon-intensity-electricity \ No newline at end of file diff --git a/install/data/report_dashboard.json b/install/data/report_dashboard.json index 0c561512..bbfd65f6 100644 --- a/install/data/report_dashboard.json +++ b/install/data/report_dashboard.json @@ -77,27 +77,27 @@ "point_labels": "0" } }, - "plugin_carbon_report_embodied_abiotic_depletion": { + "plugin_carbon_report_embodied_adp_impact": { "x": 5, "y": 3, "width": 5, "height": 3, "card_options": { "color": "#ffd966", - "widgettype": "embodied_abiotic_depletion", + "widgettype": "impact_criteria_number", "use_gradient": "0", "point_labels": "0", "limit": "7" } }, - "plugin_carbon_report_embodied_global_warming": { + "plugin_carbon_report_embodied_gwp_impact": { "x": 10, "y": 0, "width": 5, "height": 3, "card_options": { "color": "#7a941e", - "widgettype": "embodied_global_warming", + "widgettype": "impact_criteria_number", "use_gradient": "0", "point_labels": "0", "limit": "7" @@ -110,7 +110,7 @@ "height": 3, "card_options": { "color": "#326319", - "widgettype": "embodied_primary_energy", + "widgettype": "impact_criteria_number", "use_gradient": "0", "point_labels": "0", "limit": "7" diff --git a/install/install/init_datasources.php b/install/install/init_datasources.php index b7e18c64..cff83fc3 100644 --- a/install/install/init_datasources.php +++ b/install/install/init_datasources.php @@ -104,18 +104,18 @@ Install::linkSourceZone($source_id, $zone_id, $code); // Insert into the database - $success = $DB->updateOrInsert($table, [ - 'intensity' => $intensity, - 'data_quality' => 2 // constant GlpiPlugin\Carbon\DataTracking::DATA_QUALITY_ESTIMATED - ], [ - 'date' => "$year-01-01 00:00:00", - 'plugin_carbon_sources_id' => $source_id, - 'plugin_carbon_zones_id' => $zone_id, - ]); - - if ($success === false) { + try { + $DB->updateOrInsert($table, [ + 'intensity' => $intensity, + 'data_quality' => 2 // constant GlpiPlugin\Carbon\DataTracking::DATA_QUALITY_ESTIMATED + ], [ + 'date' => "$year-01-01 00:00:00", + 'plugin_carbon_sources_id' => $source_id, + 'plugin_carbon_zones_id' => $zone_id, + ]); + } catch (\RuntimeException $e) { $file = null; // close the file - throw new \RuntimeException("Failed to insert data for year $year"); + throw new \RuntimeException("Failed to insert data for year $year; reason: " . $e->getMessage(), $e->getCode(), $e); } } if ($progress_bar) { @@ -129,17 +129,17 @@ $quebec_carbon_intensity = include(dirname(__DIR__) . '/data/carbon_intensity/quebec.php'); foreach ($quebec_carbon_intensity as $year => $intensity) { - $success = $DB->updateOrInsert($table, [ - 'intensity' => $intensity, - 'data_quality' => 2 // constant GlpiPlugin\Carbon\DataTracking::DATA_QUALITY_ESTIMATED - ], [ - 'date' => "$year-01-01 00:00:00", - 'plugin_carbon_sources_id' => $source_id, - 'plugin_carbon_zones_id' => $zone_id_quebec, - ]); - - if ($success === false) { + try { + $DB->updateOrInsert($table, [ + 'intensity' => $intensity, + 'data_quality' => 2 // constant GlpiPlugin\Carbon\DataTracking::DATA_QUALITY_ESTIMATED + ], [ + 'date' => "$year-01-01 00:00:00", + 'plugin_carbon_sources_id' => $source_id, + 'plugin_carbon_zones_id' => $zone_id_quebec, + ]); + } catch (\RuntimeException $e) { $file = null; // close the file - throw new \RuntimeException("Failed to insert data for year $year"); + throw new \RuntimeException("Failed to insert data for year $year; reason: " . $e->getMessage(), $e->getCode(), $e); } } diff --git a/install/migration/update_1.0.0_to_1.0.1.php b/install/migration/update_1.0.0_to_1.0.1.php index 975bf076..9d2ff61a 100644 --- a/install/migration/update_1.0.0_to_1.0.1.php +++ b/install/migration/update_1.0.0_to_1.0.1.php @@ -57,10 +57,16 @@ function update100to101(Migration $migration) } $dbFile = plugin_carbon_getSchemaPath($to_version); - if ($dbFile === null || !$DB->runFile($dbFile)) { + if ($dbFile === null) { $migration->addWarningMessage("Error creating tables : " . $DB->error()); $updateresult = false; } + try { + $DB->runFile($dbFile); + } catch (\RuntimeException $e) { + $migration->addWarningMessage("Error creating tables : " . $e->getMessage()); + $updateresult = false; + } // ************ Keep it at the end ************** $migration->executeMigration(); diff --git a/install/migration/update_1.0.1_to_1.1.0.php b/install/migration/update_1.0.1_to_1.1.0.php index c32d549a..6998fce6 100644 --- a/install/migration/update_1.0.1_to_1.1.0.php +++ b/install/migration/update_1.0.1_to_1.1.0.php @@ -57,10 +57,17 @@ function update101to110(Migration $migration) } $dbFile = plugin_carbon_getSchemaPath($to_version); - if ($dbFile === null || !$DB->runFile($dbFile)) { + if ($dbFile === null) { $migration->addWarningMessage("Error creating tables : " . $DB->error()); $updateresult = false; } + try { + $DB->runFile($dbFile); + } catch (\RuntimeException $e) { + $migration->addWarningMessage("Error creating tables : " . $e->getMessage()); + $updateresult = false; + } + // ************ Keep it at the end ************** $migration->executeMigration(); diff --git a/install/migration/update_1.1.1_to_1.2.0.php b/install/migration/update_1.1.1_to_1.2.0.php index 4e62e6d3..d5ca343a 100644 --- a/install/migration/update_1.1.1_to_1.2.0.php +++ b/install/migration/update_1.1.1_to_1.2.0.php @@ -57,10 +57,17 @@ function update111to120(Migration $migration) } $dbFile = plugin_carbon_getSchemaPath($to_version); - if ($dbFile === null || !$DB->runFile($dbFile)) { + if ($dbFile === null) { $migration->addWarningMessage("Error creating tables : " . $DB->error()); $updateresult = false; } + try { + $DB->runFile($dbFile); + } catch (\RuntimeException $e) { + $migration->addWarningMessage("Error creating tables : " . $e->getMessage()); + $updateresult = false; + } + // ************ Keep it at the end ************** $migration->executeMigration(); diff --git a/install/migration/update_1.1.1_to_1.2.0/09_add_impact_criterias.php b/install/migration/update_1.1.1_to_1.2.0/09_add_impact_criterias.php new file mode 100644 index 00000000..382f707a --- /dev/null +++ b/install/migration/update_1.1.1_to_1.2.0/09_add_impact_criterias.php @@ -0,0 +1,225 @@ +. + * + * ------------------------------------------------------------------------- + */ + +/** @var DBmysql $DB */ +/** @var Migration $migration */ + +use Glpi\Dashboard\Item as DashboardItem; + +$new_criterias = [ + 'gwppb' => '(unit g CO2 eq) Climate change - Contribution of biogenic emissions', + 'gwppf' => '(unit g CO2 eq) Climate change - Contribution of fossil fuel emissions', + 'gwpplu' => '(unit g CO2 eq) Climate change - Contribution of emissions from land use change', + 'ir' => '(unit g U235 eq) Emissions of radionizing substances', + 'lu' => '(unit none) Land use', + 'odp' => '(unit g CFC-11 eq) Depletion of the ozone layer', + 'pm' => '(unit Disease occurrence) Fine particle emissions', + 'pocp' => '(unit g NMVOC eq) Photochemical ozone formation', + 'wu' => '(unit L) Use of water resources', + 'mips' => '(unit g) Material input per unit of service', + 'adpe' => '(unit g SB eq) Use of mineral and metal resources', + 'adpf' => '(unit J) Use of fossil resources (including nuclear)', + 'ap' => '(unit mol H+ eq) Acidification', + 'ctue' => '(unit CTUe) Freshwater ecotoxicity', + // ctuh_c => '(unit CTUh) Human toxicity - Carcinogenic effects', + // ctuh_nc => (unit CTUh) Human toxicity - non-carcinogenic effects', + 'epf' => '(unit g P eq) Eutrophication of freshwater', + 'epm' => '(unit g N eq) Eutrophication of marine waters', + 'ept' => '(unit mol N eq) Terrestrial eutrophication', +]; + +$tables = ['glpi_plugin_carbon_embodiedimpacts', 'glpi_plugin_carbon_usageimpacts']; +foreach ($tables as $table) { + $previous_criteria = 'pe'; + foreach ($new_criterias as $criteria => $comment) { + $migration->addField( + $table, + $criteria, + 'float DEFAULT \'0\'', + [ + 'comment' => $comment, + 'after' => $previous_criteria . '_quality', + ] + ); + $migration->addField( + $table, + $criteria . '_quality', + 'int unsigned NOT NULL DEFAULT \'0\'', + [ + 'comment' => 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + 'after' => $criteria, + ] + ); + $previous_criteria = $criteria; + } + + // Uniformize existing impact : make floats signed + $old_criterias = [ + 'gwp' => '(unit g CO2 eq) Global warming potential', + 'adp' => '(unit g Sb eq) Abiotic depletion potential', + 'pe' => '(unit J) Primary energy', + ]; + foreach ($old_criterias as $criteria => $comment) { + $migration->changeField($table, $criteria, $criteria, 'float DEFAULT \'0\'', [ + 'comment' => $comment, + ]); + } + + // Add a recalculate boolean + $migration->addField($table, 'recalculate', 'bool', [ + 'after' => 'date_mod', + 'update' => 1 + ]); +} + +// Rename cards for the report +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_report_embodied_global_warming' +]); +foreach ($rows as $row) { + $card_options = json_decode($row['card_options'], true); + if ($card_options['widgettype'] === 'embodied_global_warming') { + $card_options['widgettype'] = 'impact_criteria_number'; + } + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_report_embodied_gwp_impact', + 'card_options' => json_encode($card_options), + ]); +} + +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_report_usage_abiotic_depletion' +]); +foreach ($rows as $row) { + $card_options = json_decode($row['card_options'], true); + if ($card_options['widgettype'] === 'usage_abiotic_depletion') { + $card_options['widgettype'] = 'impact_criteria_number'; + } + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_report_usage_adp_impact', + 'card_options' => json_encode($card_options), + ]); +} + +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_report_embodied_abiotic_depletion' +]); +foreach ($rows as $row) { + $card_options = json_decode($row['card_options'], true); + if ($card_options['widgettype'] === 'embodied_abiotic_depletion') { + $card_options['widgettype'] = 'impact_criteria_number'; + } + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_report_embodied_adp_impact', + 'card_options' => json_encode($card_options), + ]); +} + +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_report_embodied_pe_impact' +]); +foreach ($rows as $row) { + $card_options = json_decode($row['card_options'], true); + if ($card_options['widgettype'] === 'embodied_primary_energy') { + $card_options['widgettype'] = 'impact_criteria_number'; + } + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_report_embodied_pe_impact', + 'card_options' => json_encode($card_options), + ]); +} + +// Rename cards for the standard dashboard : usage indicators + +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_total_usage_power' +]); +foreach ($rows as $row) { + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_usage_pe_impact', + ]); +} + +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_total_usage_carbon_emission' +]); +foreach ($rows as $row) { + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_usage_gwp_impact', + ]); +} + +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_total_usage_adp_impact' +]); +foreach ($rows as $row) { + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_usage_adp_impact', + ]); +} + +// Rename cards for the standard dashboard : Embodied + usage indicators +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_total_gwp_impact' +]); +foreach ($rows as $row) { + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_all_scopes_gwp_impact', + ]); +} + +$dashboard_item = new DashboardItem(); +$rows = $dashboard_item->find([ + 'card_id' => 'plugin_carbon_total_adp_impact' +]); +foreach ($rows as $row) { + $dashboard_item->update([ + 'id' => $row['id'], + 'card_id' => 'plugin_carbon_all_scopes_adp_impact', + ]); +} diff --git a/install/migration/update_1.1.1_to_1.2.0/10_update_display_preferences.php b/install/migration/update_1.1.1_to_1.2.0/10_update_display_preferences.php new file mode 100644 index 00000000..b38067c6 --- /dev/null +++ b/install/migration/update_1.1.1_to_1.2.0/10_update_display_preferences.php @@ -0,0 +1,138 @@ +. + * + * ------------------------------------------------------------------------- + */ + +use GlpiPlugin\Carbon\EmbodiedImpact; + +/** @var DBmysql $DB */ +/** @var Migration $migration */ + +$display_pref = new DisplayPreference(); + +$plugin_so_base = 128000; +$group_base = 1200; + +// +// EmbodiedImpact search options +// + +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 5 // Was GWP, now recalculate flag +]); +$id = $plugin_so_base + $group_base; +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} + +$id = $plugin_so_base + $group_base + 2; +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 6 // Was ADP, now recalculate flag +]); +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} + +$id = $plugin_so_base + $group_base + 4; +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 7 // Was PE, now recalculate flag +]); +foreach ($rows as $row) { + $row['num'] = 1204; + $display_pref->update($row); +} + +// +// UsageImpact search options +// +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 128701 // usage GWP +]); +$id = $plugin_so_base + $group_base; +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} + +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 128702 // usage GWP qiality +]); +$id = $plugin_so_base + $group_base + 1; +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} + +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 128703 // usage ADP +]); +$id = $plugin_so_base + $group_base + 2; +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} + +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 128704 // usage ADP qiality +]); +$id = $plugin_so_base + $group_base + 3; +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} + +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 128705 // usage PE +]); +$id = $plugin_so_base + $group_base + 4; +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} + +$rows = $display_pref->find([ + 'itemtype' => EmbodiedImpact::class, + 'num' => 128706 // usage PE qiality +]); +$id = $plugin_so_base + $group_base + 5; +foreach ($rows as $row) { + $row['num'] = $id; + $display_pref->update($row); +} diff --git a/install/migration/update_x.x.x_to_y.y.y.php b/install/migration/update_x.x.x_to_y.y.y.php index cb9599dc..2b416877 100644 --- a/install/migration/update_x.x.x_to_y.y.y.php +++ b/install/migration/update_x.x.x_to_y.y.y.php @@ -57,10 +57,17 @@ function update001to100(Migration $migration) } $dbFile = plugin_carbon_getSchemaPath($to_version); - if ($dbFile === null || !$DB->runFile($dbFile)) { + if ($dbFile === null) { $migration->addWarningMessage("Error creating tables : " . $DB->error()); $updateresult = false; } + try { + $DB->runFile($dbFile); + } catch (\RuntimeException $e) { + $migration->addWarningMessage("Error creating tables : " . $e->getMessage()); + $updateresult = false; + } + // ************ Keep it at the end ************** $migration->executeMigration(); diff --git a/install/mysql/plugin_carbon_empty.sql b/install/mysql/plugin_carbon_empty.sql index da2f1360..25f37f5c 100644 --- a/install/mysql/plugin_carbon_empty.sql +++ b/install/mysql/plugin_carbon_empty.sql @@ -132,17 +132,52 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_computerusageprofiles` ( CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_embodiedimpacts` ( `id` int unsigned NOT NULL AUTO_INCREMENT, - `itemtype` varchar(255) DEFAULT NULL, + `itemtype` varchar(255) DEFAULT NULL, `items_id` int unsigned NOT NULL DEFAULT '0', - `engine` varchar(255) DEFAULT NULL, - `engine_version` varchar(255) DEFAULT NULL, - `date_mod` timestamp NULL DEFAULT NULL, - `gwp` float unsigned DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', + `engine` varchar(255) DEFAULT NULL, + `engine_version` varchar(255) DEFAULT NULL, + `date_mod` timestamp NULL DEFAULT NULL, + `recalculate` tinyint NOT NULL DEFAULT '0', + `gwp` float DEFAULT '0' COMMENT '(unit g CO2 eq) Global warming potential', `gwp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `adp` float unsigned DEFAULT '0' COMMENT '(unit gSbeq) Abiotic depletion potential', + `adp` float DEFAULT '0' COMMENT '(unit g Sb eq) Abiotic depletion potential', `adp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `pe` float unsigned DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe` float DEFAULT '0' COMMENT '(unit J) Primary energy', `pe_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwppb` float DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of biogenic emissions', + `gwppb_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwppf` float DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of fossil fuel emissions', + `gwppf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwpplu` float DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of emissions from land use change', + `gwpplu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ir` float DEFAULT '0' COMMENT '(unit g U235 eq) Emissions of radionizing substances', + `ir_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `lu` float DEFAULT '0' COMMENT '(unit none) Land use', + `lu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `odp` float DEFAULT '0' COMMENT '(unit g CFC-11 eq) Depletion of the ozone layer', + `odp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pm` float DEFAULT '0' COMMENT '(unit Disease occurrence) Fine particle emissions', + `pm_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pocp` float DEFAULT '0' COMMENT '(unit g NMVOC eq) Photochemical ozone formation', + `pocp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `wu` float DEFAULT '0' COMMENT '(unit L) Use of water resources', + `wu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `mips` float DEFAULT '0' COMMENT '(unit g) Material input per unit of service', + `mips_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adpe` float DEFAULT '0' COMMENT '(unit g SB eq) Use of mineral and metal resources', + `adpe_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adpf` float DEFAULT '0' COMMENT '(unit J) Use of fossil resources (including nuclear)', + `adpf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ap` float DEFAULT '0' COMMENT '(unit mol H+ eq) Acidification', + `ap_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ctue` float DEFAULT '0' COMMENT '(unit CTUe) Freshwater ecotoxicity', + `ctue_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `epf` float DEFAULT '0' COMMENT '(unit g P eq) Eutrophication of freshwater', + `epf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `epm` float DEFAULT '0' COMMENT '(unit g N eq) Eutrophication of marine waters', + `epm_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ept` float DEFAULT '0' COMMENT '(unit mol N eq) Terrestrial eutrophication', + `ept_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', PRIMARY KEY (`id`), UNIQUE KEY `unicity` (`itemtype`, `items_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; @@ -161,12 +196,12 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_monitormodels` ( `gwp` int DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', `gwp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', `gwp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `adp` int DEFAULT '0' COMMENT '(unit gSbEq) Abiotic depletion potential', - `adp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', - `adp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `pe` int DEFAULT '0' COMMENT '(unit J) Primary energy', - `pe_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', - `pe_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adp` int DEFAULT '0' COMMENT '(unit gSbEq) Abiotic depletion potential', + `adp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `adp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pe` int DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `pe_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', PRIMARY KEY (`id`), UNIQUE KEY `unicity` (`monitormodels_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; @@ -226,17 +261,52 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_usageinfos` ( CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_usageimpacts` ( `id` int unsigned NOT NULL AUTO_INCREMENT, - `itemtype` varchar(255) DEFAULT NULL, + `itemtype` varchar(255) DEFAULT NULL, `items_id` int unsigned NOT NULL DEFAULT '0', - `engine` varchar(255) DEFAULT NULL, - `engine_version` varchar(255) DEFAULT NULL, - `date_mod` timestamp NULL DEFAULT NULL, - `gwp` float unsigned DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', + `engine` varchar(255) DEFAULT NULL, + `engine_version` varchar(255) DEFAULT NULL, + `date_mod` timestamp NULL DEFAULT NULL, + `recalculate` tinyint NOT NULL DEFAULT '0', + `gwp` float DEFAULT '0' COMMENT '(unit g CO2 eq) Global warming potential', `gwp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `adp` float unsigned DEFAULT '0' COMMENT '(unit gSbeq) Abiotic depletion potential', + `adp` float DEFAULT '0' COMMENT '(unit g Sb eq) Abiotic depletion potential', `adp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `pe` float unsigned DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe` float DEFAULT '0' COMMENT '(unit J) Primary energy', `pe_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwppb` float DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of biogenic emissions', + `gwppb_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwppf` float DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of fossil fuel emissions', + `gwppf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwpplu` float DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of emissions from land use change', + `gwpplu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ir` float DEFAULT '0' COMMENT '(unit g U235 eq) Emissions of radionizing substances', + `ir_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `lu` float DEFAULT '0' COMMENT '(unit none) Land use', + `lu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `odp` float DEFAULT '0' COMMENT '(unit g CFC-11 eq) Depletion of the ozone layer', + `odp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pm` float DEFAULT '0' COMMENT '(unit Disease occurrence) Fine particle emissions', + `pm_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pocp` float DEFAULT '0' COMMENT '(unit g NMVOC eq) Photochemical ozone formation', + `pocp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `wu` float DEFAULT '0' COMMENT '(unit L) Use of water resources', + `wu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `mips` float DEFAULT '0' COMMENT '(unit g) Material input per unit of service', + `mips_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adpe` float DEFAULT '0' COMMENT '(unit g SB eq) Use of mineral and metal resources', + `adpe_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adpf` float DEFAULT '0' COMMENT '(unit J) Use of fossil resources (including nuclear)', + `adpf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ap` float DEFAULT '0' COMMENT '(unit mol H+ eq) Acidification', + `ap_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ctue` float DEFAULT '0' COMMENT '(unit CTUe) Freshwater ecotoxicity', + `ctue_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `epf` float DEFAULT '0' COMMENT '(unit g P eq) Eutrophication of freshwater', + `epf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `epm` float DEFAULT '0' COMMENT '(unit g N eq) Eutrophication of marine waters', + `epm_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ept` float DEFAULT '0' COMMENT '(unit mol N eq) Terrestrial eutrophication', + `ept_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', PRIMARY KEY (`id`), UNIQUE KEY `unicity` (`itemtype`, `items_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/src/AbstractImpact.php b/src/AbstractImpact.php new file mode 100644 index 00000000..82137a11 --- /dev/null +++ b/src/AbstractImpact.php @@ -0,0 +1,147 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon; + +use CommonDBChild; +use GlpiPlugin\Carbon\Impact\Type; + +abstract class AbstractImpact extends CommonDBChild +{ + public static $itemtype = 'itemtype'; + public static $items_id = 'items_id'; + + public static $rightname = 'carbon:report'; + + public function rawSearchOptions() + { + $tab = parent::rawSearchOptions(); + + $tab[] = [ + 'id' => '2', + 'table' => $this->getTable(), + 'field' => 'id', + 'name' => __('ID'), + 'massiveaction' => false, // implicit field is id + 'datatype' => 'number' + ]; + + $tab[] = [ + 'id' => '3', + 'table' => $this->getTable(), + 'field' => 'items_id', + 'name' => __('Associated item ID'), + 'massiveaction' => false, + 'datatype' => 'specific', + 'additionalfields' => ['itemtype'] + ]; + + $tab[] = [ + 'id' => '4', + 'table' => $this->getTable(), + 'field' => 'itemtype', + 'name' => _n('Type', 'Types', 1), + 'massiveaction' => false, + 'datatype' => 'itemtypename', + ]; + + $tab[] = [ + 'id' => '5', + 'table' => $this->getTable(), + 'field' => 'recalculate', + 'name' => __('', 'carbon'), + 'massiveaction' => false, + 'datatype' => 'bool', + ]; + + $id = SearchOptions::IMPACT_BASE; + foreach (Type::getImpactTypes() as $type_id => $type) { + $id = SearchOptions::IMPACT_BASE + $type_id * 2; + $tab[] = [ + 'id' => $id, + 'table' => $this->getTable(), + 'field' => $type, + 'name' => Type::getEmbodiedImpactLabel($type), + 'massiveaction' => false, + 'datatype' => 'number', + 'unit' => implode(' ', Type::getImpactUnit($type)), + ]; + $id++; + + $tab[] = [ + 'id' => $id, + 'table' => $this->getTable(), + 'field' => "{$type}_quality", + 'name' => Type::getEmbodiedImpactLabel($type), + 'massiveaction' => false, + 'datatype' => 'number', + 'unit' => implode(' ', Type::getImpactUnit($type)), + ]; + } + + $tab[] = [ + 'id' => SearchOptions::CALCULATION_DATE, + 'table' => self::getTable(), + 'field' => 'date_mod', + 'name' => __('Date of evaluation', 'carbon') + ]; + + $tab[] = [ + 'id' => SearchOptions::CALCULATION_ENGINE, + 'table' => self::getTable(), + 'field' => 'engine', + 'name' => __('Engine', 'carbon') + ]; + + $tab[] = [ + 'id' => SearchOptions::CALCULATION_ENGINE_VERSION, + 'table' => self::getTable(), + 'field' => 'engine_version', + 'name' => __('Engine version', 'carbon') + ]; + + return $tab; + } + + /** + * Get impact value in a human r eadable format, selecting the best unit + * + * @param string $field the field of the impact + */ + public function getHumanReadableImpact(string $field): string + { + return Toolbox::getHumanReadableValue( + $this->fields[$field], + Type::getImpactUnit($field) + ); + } +} diff --git a/src/CarbonEmission.php b/src/CarbonEmission.php index b8dabee7..dbc5dcbb 100644 --- a/src/CarbonEmission.php +++ b/src/CarbonEmission.php @@ -145,21 +145,21 @@ public function rawSearchOptions() ]; $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_CALC_DATE, + 'id' => SearchOptions::CALCULATION_DATE, 'table' => self::getTable(), 'field' => 'date_mod', 'name' => __('Date of evaluation', 'carbon') ]; $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_ENGINE, + 'id' => SearchOptions::CALCULATION_ENGINE, 'table' => self::getTable(), 'field' => 'engine', 'name' => __('Engine', 'carbon') ]; $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_ENGINE_VER, + 'id' => SearchOptions::CALCULATION_ENGINE_VERSION, 'table' => self::getTable(), 'field' => 'engine_version', 'name' => __('Engine version', 'carbon') diff --git a/src/CronTask.php b/src/CronTask.php index 7baa822b..7016cc0f 100644 --- a/src/CronTask.php +++ b/src/CronTask.php @@ -146,6 +146,7 @@ public static function cronUsageImpact(GlpiCronTask $task): int $task->setVolume(0); // start with zero $usage_impacts = Toolbox::getGwpUsageImpactClasses(); + $task->setVolume(0); // start with zero $remaining = $task->fields['param']; $limit_per_type = (int) floor(($remaining) / count($usage_impacts)); // Half of job for GWP, the other half for other impacts diff --git a/src/Dashboard/DemoProvider.php b/src/Dashboard/DemoProvider.php index e8ca167d..6fa60037 100644 --- a/src/Dashboard/DemoProvider.php +++ b/src/Dashboard/DemoProvider.php @@ -36,6 +36,7 @@ use DateInterval; use DateTime; use DateTimeImmutable; +use GlpiPlugin\Carbon\Impact\Type; use GlpiPlugin\Carbon\Toolbox; use Monitor; use NetworkEquipment; @@ -43,69 +44,31 @@ class DemoProvider { - public static function getEmbodiedGlobalWarming(array $params = []): array - { - $value = 616000000; - $value = Toolbox::getWeight($value) . __('CO₂eq', 'carbon'); - - $params['icon'] = 'fa-solid fa-temperature-arrow-up'; - - return [ - 'number' => $value, - 'label' => $params['label'], - 'icon' => $params['icon'], - ]; - } - - public static function getEmbodiedPrimaryEnergy(array $params = []): array - { - $value = 491000000; - $value = Toolbox::getEnergy($value / 3600); - - $params['icon'] = 'fa-solid fa-fire-flame-simple'; - - return [ - 'number' => $value, - 'label' => $params['label'], - 'icon' => $params['icon'], - ]; - } - - public static function getEmbodiedAbioticDepletion(array $params = [], array $crit = []): array - { - $default_params = [ - 'label' => __('Embodied abiotic depletion potential', 'carbon'), - 'icon' => 'fa-solid fa-temperature-arrow-up', - ]; - $params = array_merge($default_params, $params); - - $value = 12.748; - $value = Toolbox::getWeight($value) . __('Sbeq', 'carbon'); - - return [ - 'number' => $value, - 'label' => $params['label'], - 'icon' => $params['icon'], - ]; - } - - public static function getUsageAbioticDepletion(array $params = [], array $crit = []): array - { - $default_params = [ - 'label' => __('Usage abiotic depletion potential', 'carbon'), - 'icon' => 'fa-solid fa-temperature-arrow-up', - ]; - $params = array_merge($default_params, $params); - - $value = 2.86; - $value = Toolbox::getWeight($value) . __('Sbeq', 'carbon'); - - return [ - 'number' => $value, - 'label' => $params['label'], - 'icon' => $params['icon'], - ]; - } + /** @var array $impact_values Embodied and usage impact values*/ + private static array $impact_values = [ + 'gwp' => [616000000, 176483], + 'adp' => [12.748, 2.86], + 'pe' => [491000000, null], + 'gwppb' => [null, null], + 'gwppf' => [null, null], + 'gwpplu' => [null, null], + 'ir' => [null, null], + 'lu' => [-101, null], + 'odp' => [null, null], + 'pm' => [null, null], + 'pocp' => [null, null], + 'wu' => [null, null], + 'mips' => [null, null], + 'adpe' => [null, null], + 'adpf' => [null, null], + 'ap' => [null, null], + 'ctue' => [null, null], + // 'ctuh_c' => [null, null], + // 'ctuh_nc' => [null, null], + 'epf' => [null, null], + 'epm' => [null, null], + 'ept' => [null, null], + ]; public static function getUsageCarbonEmissionPerMonth(array $params = [], array $crit = []): array { @@ -400,23 +363,122 @@ public static function getSumUsageEmissionsPerModel(array $params = [], array $w } /** - * Get usage CO2 emissions + * Get the value of an impact criteria for the embodied scope * * @param array $params + * @param array $crit * @return array */ - public static function getUsageCarbonEmission(array $params = []): array + public static function getImpactOfEmbodiedCriteria(string $impact_type, array $params = [], array $crit = []): array { $default_params = [ - 'label' => __('plugin carbon - Usage carbon emission', 'carbon'), - 'icon' => 'fa-solid fa-temperature-arrow-up', + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'icon' => Type::getCriteriaIcon($impact_type), + ]; + $params = array_merge($default_params, $params); + if (count($crit['itemtype'] ?? []) === 0) { + $crit['itemtype'] = PLUGIN_CARBON_TYPES; + } else { + $crit['itemtype'] = array_intersect($crit['itemtype'], PLUGIN_CARBON_TYPES); + } + + $value = self::$impact_values[$impact_type][0]; + if ($value === null) { + $value = 'N/A'; + } else { + $value = Toolbox::getHumanReadableValue( + $value, + Type::getImpactUnit($impact_type) + ); + } + + return [ + 'number' => $value, + 'label' => $params['label'], + 'icon' => $params['icon'], + 'tooltip' => Type::getCriteriaTooltip($impact_type), + 'pictogram_file' => Type::getCriteriaPictogram($impact_type), + 'doc_url' => Type::getCriteriaInfoLink($impact_type), + ]; + } + + /** + * Get the value of an impact criteria for the usage scope + * + * @param array $params + * @param array $crit + * @return array + */ + public static function getImpactOfUsageCriteria(string $impact_type, array $params = [], array $crit = []): array + { + $default_params = [ + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'icon' => Type::getCriteriaIcon($impact_type), ]; $params = array_merge($default_params, $params); - $gwp = Toolbox::getWeight(176483) . __('CO₂eq', 'carbon'); + if (count($crit['itemtype'] ?? []) === 0) { + $crit['itemtype'] = PLUGIN_CARBON_TYPES; + } else { + $crit['itemtype'] = array_intersect($crit['itemtype'], PLUGIN_CARBON_TYPES); + } + + $value = self::$impact_values[$impact_type][1]; + if ($value === null) { + $value = 'N/A'; + } else { + $value = Toolbox::getHumanReadableValue( + $value, + Type::getImpactUnit($impact_type) + ); + } + return [ - 'number' => $gwp, + 'number' => $value, + 'label' => $params['label'], + 'icon' => $params['icon'], + 'tooltip' => Type::getCriteriaTooltip($impact_type), + 'pictogram_file' => Type::getCriteriaPictogram($impact_type), + 'doc_url' => Type::getCriteriaInfoLink($impact_type), + ]; + } + + /** + * Get the value of an impact criteria for the embodied + usage scopes + * + * @param array $params + * @param array $crit + * @return array + */ + public static function getImpactOfEmbodiedAndUsageCriteria(string $impact_type, array $params = [], array $crit = []): array + { + $default_params = [ + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'icon' => Type::getCriteriaIcon($impact_type), + ]; + $params = array_merge($default_params, $params); + if (count($crit['itemtype'] ?? []) === 0) { + $crit['itemtype'] = PLUGIN_CARBON_TYPES; + } else { + $crit['itemtype'] = array_intersect($crit['itemtype'], PLUGIN_CARBON_TYPES); + } + + if (self::$impact_values[$impact_type][0] === null && self::$impact_values[$impact_type][1] === null) { + $value = 'N/A'; + } else { + $value = (self::$impact_values[$impact_type][0] ?? 0) + (self::$impact_values[$impact_type][1] ?? 0); + $value = Toolbox::getHumanReadableValue( + $value, + Type::getImpactUnit($impact_type) + ); + } + + return [ + 'number' => $value, 'label' => $params['label'], 'icon' => $params['icon'], + 'tooltip' => Type::getCriteriaTooltip($impact_type), + 'pictogram_file' => Type::getCriteriaPictogram($impact_type), + 'doc_url' => Type::getCriteriaInfoLink($impact_type), ]; } } diff --git a/src/Dashboard/Grid.php b/src/Dashboard/Grid.php index 3dc30e84..e1914b6c 100644 --- a/src/Dashboard/Grid.php +++ b/src/Dashboard/Grid.php @@ -35,6 +35,7 @@ use Computer; use Glpi\Dashboard\Filter; use GlpiPlugin\Carbon\Config; +use GlpiPlugin\Carbon\Impact\Type; use Session; class Grid @@ -153,67 +154,64 @@ protected static function getStandardCards(): array ]; } - $new_cards += [ - // Usage impact - 'plugin_carbon_total_usage_power' => [ - 'widgettype' => ['bigNumber'], - 'group' => $group, - 'label' => __('Usage power consumption', 'carbon'), - 'provider' => Provider::class . '::getUsagePower', - ], - 'plugin_carbon_total_usage_carbon_emission' => [ - 'widgettype' => ['bigNumber'], - 'group' => $group, - 'label' => __('Usage carbon emission', 'carbon'), - 'provider' => Provider::class . '::getUsageCarbonEmission', - ], - 'plugin_carbon_total_usage_adp_impact' => [ - 'widgettype' => ['bigNumber'], - 'group' => $group, - 'label' => __('Usage abiotic depletion potential', 'carbon'), - 'provider' => Provider::class . '::getUsageAbioticDepletion', - ], + $impact_types = Type::getImpactTypes(); - // Embodied impact - 'plugin_carbon_embodied_gwp_impact' => [ - 'widgettype' => ['bigNumber'], - 'group' => $group, - 'label' => __('Embodied global warming potential', 'carbon'), - 'provider' => Provider::class . '::getEmbodiedGlobalWarming', - ], - 'plugin_carbon_embodied_pe_impact' => [ - 'widgettype' => ['bigNumber'], - 'group' => $group, - 'label' => __('Embodied primary energy consumed', 'carbon'), - 'provider' => Provider::class . '::getEmbodiedPrimaryEnergy', - ], - 'plugin_carbon_embodied_adp_impact' => [ + // Embodied impact + foreach ($impact_types as $impact_type) { + $key = "plugin_carbon_embodied_{$impact_type}_impact"; + if (isset($new_cards[$key])) { + trigger_error("The card $key already exists", E_USER_WARNING); + } + $new_cards[$key] = [ 'widgettype' => ['bigNumber'], 'group' => $group, - 'label' => __('Embodied abiotic depletion potential', 'carbon'), - 'provider' => Provider::class . '::getEmbodiedAbioticDepletion', - ], + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'provider' => Provider::class . '::getImpactOfEmbodiedCriteria', + 'args' => [ + 'impact_type' => $impact_type + ] + ]; + } - // embodied + usage impact - 'plugin_carbon_total_gwp_impact' => [ + // Usage impact + foreach ($impact_types as $impact_type) { + $key = "plugin_carbon_usage_{$impact_type}_impact"; + if (isset($new_cards[$key])) { + trigger_error("The card $key already exists", E_USER_WARNING); + } + $new_cards[$key] = [ 'widgettype' => ['bigNumber'], 'group' => $group, - 'label' => __('Global warming potential', 'carbon'), - 'provider' => Provider::class . '::getTotalGlobalWarming', - ], - 'plugin_carbon_total_adp_impact' => [ + 'label' => Type::getUsageImpactLabel($impact_type), + 'provider' => Provider::class . '::getImpactOfUsageCriteria', + 'args' => [ + 'impact_type' => $impact_type + ] + ]; + } + + // embodied + usage impact + foreach ($impact_types as $impact_type) { + $key = "plugin_carbon_all_scopes_{$impact_type}_impact"; + if (isset($new_cards[$key])) { + trigger_error("The card $key already exists", E_USER_WARNING); + } + $new_cards[$key] = [ 'widgettype' => ['bigNumber'], 'group' => $group, - 'label' => __('Abiotic depletion potential', 'carbon'), - 'provider' => Provider::class . '::getTotalAbioticDepletion', - ], - ]; + 'label' => Type::getEmbodiedAndUsageImpactLabel($impact_type), + 'provider' => Provider::class . '::getImpactOfEmbodiedAndUsageCriteria', + 'args' => [ + 'impact_type' => $impact_type + ] + ]; + } return $new_cards; } /** - * getdescription of cards for dashboard in the reporting page of the plugin + * Get description of cards for dashboard in the reporting page of the plugin * * @return array */ @@ -238,8 +236,8 @@ protected static function getReportCards(): array ]; } - // Usage impact $new_cards += [ + // Usage impact 'plugin_carbon_report_usage_carbon_emission_ytd' => [ 'widgettype' => ['usage_carbon_emission_ytd'], 'group' => $group, @@ -270,33 +268,33 @@ protected static function getReportCards(): array 'label' => __('Biggest monthly averaged carbon emission per model', 'carbon'), 'provider' => Provider::class . '::getSumUsageEmissionsPerModel', ], - 'plugin_carbon_report_usage_abiotic_depletion' => [ - 'widgettype' => ['usage_abiotic_depletion'], + 'plugin_carbon_report_usage_adp_impact' => [ + 'widgettype' => ['impact_criteria_number'], 'group' => $group, 'label' => __('Usage abiotic depletion potential', 'carbon'), - 'provider' => Provider::class . '::getUsageAbioticDepletion', + 'provider' => Provider::class . '::getImpactOfUsageCriteria', + 'args' => [ + 'impact_type' => 'adp', + ] ], + ]; - // Embodied impact - 'plugin_carbon_report_embodied_global_warming' => [ - 'widgettype' => ['embodied_global_warming'], - 'group' => $group, - 'label' => __('Embodied global warming potential', 'carbon'), - 'provider' => Provider::class . '::getEmbodiedGlobalWarming', - ], - 'plugin_carbon_report_embodied_abiotic_depletion' => [ - 'widgettype' => ['embodied_abiotic_depletion'], - 'group' => $group, - 'label' => __('Embodied abiotic depletion potential', 'carbon'), - 'provider' => Provider::class . '::getEmbodiedAbioticDepletion', - ], - 'plugin_carbon_report_embodied_pe_impact' => [ - 'widgettype' => ['embodied_primary_energy'], + // Embodied impact + foreach (Type::getImpactTypes() as $impact_type) { + $key = "plugin_carbon_report_embodied_{$impact_type}_impact"; + if (isset($new_cards[$key])) { + trigger_error("The card $key already exists", E_USER_WARNING); + } + $new_cards[$key] = [ + 'widgettype' => ['impact_criteria_number'], 'group' => $group, - 'label' => __('Embodied primary energy consumed', 'carbon'), - 'provider' => Provider::class . '::getEmbodiedPrimaryEnergy', - ], - ]; + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'provider' => Provider::class . '::getImpactOfEmbodiedCriteria', + 'args' => [ + 'impact_type' => $impact_type + ] + ]; + } // Informational content $new_cards += [ diff --git a/src/Dashboard/Provider.php b/src/Dashboard/Provider.php index 1e8f188e..1df8619a 100644 --- a/src/Dashboard/Provider.php +++ b/src/Dashboard/Provider.php @@ -53,6 +53,7 @@ use GlpiPlugin\Carbon\UsageImpact; use Glpi\DBAL\QueryExpression; use Glpi\DBAL\QuerySubQuery; +use GlpiPlugin\Carbon\Impact\Type; use Search; use Session; use Toolbox as GlpiToolbox; @@ -718,6 +719,81 @@ public static function getUsageCarbonEmission(array $params = []): array ]; } + /** + * Get usage abiotic depletion potential in antimony equivalent + * + * @param array $params + * @param array $crit + * @return array + */ + public static function getUsageAbioticDepletion(array $params = [], array $crit = []): array + { + $default_params = [ + 'label' => __('Usage abiotic depletion potential', 'carbon'), + 'icon' => 'fa-solid fa-temperature-arrow-up', + ]; + $params = array_merge($default_params, $params); + if (count($crit['itemtype'] ?? []) === 0) { + $crit['itemtype'] = PLUGIN_CARBON_TYPES; + } else { + $crit['itemtype'] = array_intersect($crit['itemtype'], PLUGIN_CARBON_TYPES); + } + + $value = self::getSum(UsageImpact::getTable(), 'adp', $params, $crit); + if ($value === null) { + $value = 'N/A'; + } else { + $value = Toolbox::getWeight($value) . __('Sbeq', 'carbon'); + } + + return [ + 'number' => $value, + 'label' => $params['label'], + 'icon' => $params['icon'], + ]; + } + + /** + * Get usage impact for the given criteria + * + * @param string $impact_type Impact type identifier + * @param array $params + * @param array $crit + * @return array + */ + public static function getImpactOfUsageCriteria(string $impact_type, array $params = [], array $crit = []): array + { + $default_params = [ + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'icon' => Type::getCriteriaIcon($impact_type), + ]; + $params = array_merge($default_params, $params); + if (count($crit['itemtype'] ?? []) === 0) { + $crit['itemtype'] = PLUGIN_CARBON_TYPES; + } else { + $crit['itemtype'] = array_intersect($crit['itemtype'], PLUGIN_CARBON_TYPES); + } + + $value = self::getSum(UsageImpact::getTable(), 'adp', $params, $crit); + if ($value === null) { + $value = 'N/A'; + } else { + $value = Toolbox::getHumanReadableValue( + $value, + Type::getImpactUnit($impact_type) + ); + } + + return [ + 'number' => $value, + 'label' => $params['label'], + 'icon' => $params['icon'], + 'tooltip' => Type::getCriteriaTooltip($impact_type), + 'pictogram_file' => Type::getCriteriaPictogram($impact_type), + 'doc_url' => Type::getCriteriaInfoLink($impact_type), + ]; + } + /** * Get the usage carbon emission of the 12 last elapsed months * @@ -863,105 +939,60 @@ public static function getFiltersCriteria(string $table = "", array $apply_filte return $criteria; } - public static function getEmbodiedGlobalWarming(array $params = []): array - { - $default_params = [ - 'label' => __('Total embodied global warming potential', 'carbon'), - 'icon' => 'fa-solid fa-temperature-arrow-up', - ]; - $params = array_merge($default_params, $params); - - $crit = [ - 'itemtype' => PLUGIN_CARBON_TYPES, - ]; - $value = self::getSum(EmbodiedImpact::getTable(), 'gwp', $params, $crit); - if ($value === null) { - $value = 'N/A'; - } else { - $value = Toolbox::getWeight($value) . __('CO₂eq', 'carbon'); - } - - return [ - 'number' => $value, - 'label' => $params['label'], - 'icon' => $params['icon'], - ]; - } - - /** - * Get the primary energy consumed to build assets - * - * @param array $params - * @return array - */ - public static function getEmbodiedPrimaryEnergy(array $params = []): array - { - $crit = [ - 'itemtype' => PLUGIN_CARBON_TYPES, - ]; - $value = self::getSum(EmbodiedImpact::getTable(), 'pe', $params, $crit); - if ($value === null) { - $value = 'N/A'; - } else { - // Convert into Watt.hour - $value = Toolbox::getEnergy($value / 3600); - } - - $params['icon'] = 'fa-solid fa-fire-flame-simple'; - - return [ - 'number' => $value, - 'label' => $params['label'], - 'icon' => $params['icon'], - ]; - } - /** - * Total embodied abiotic depletion potential in antimony equivalent + * Total embodied impact for the given criteria * - * @param array $params - * @param array $crit + * @param string $impact_type Impact type identifier + * @param array $params + * @param array $crit * @return array */ - public static function getEmbodiedAbioticDepletion(array $params = [], array $crit = []): array + public static function getImpactOfEmbodiedCriteria(string $impact_type, array $params = [], array $crit = []): array { $default_params = [ - 'label' => __('Embodied abiotic depletion potential', 'carbon'), - 'icon' => 'fa-solid fa-temperature-arrow-up', + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'icon' => Type::getCriteriaIcon($impact_type), ]; $params = array_merge($default_params, $params); - if (count($crit['itemtype'] ?? []) === 0) { $crit['itemtype'] = PLUGIN_CARBON_TYPES; } else { $crit['itemtype'] = array_intersect($crit['itemtype'], PLUGIN_CARBON_TYPES); } - $value = self::getSum(EmbodiedImpact::getTable(), 'adp', $params, $crit); + + $value = self::getSum(EmbodiedImpact::getTable(), $impact_type, $params, $crit); if ($value === null) { $value = 'N/A'; } else { - $value = Toolbox::getWeight($value) . __('Sbeq', 'carbon'); + $value = Toolbox::getHumanReadableValue( + $value, + Type::getImpactUnit($impact_type) + ); } return [ - 'number' => $value, - 'label' => $params['label'], - 'icon' => $params['icon'], + 'number' => $value, + 'label' => $params['label'], + 'icon' => $params['icon'], + 'tooltip' => Type::getCriteriaTooltip($impact_type), + 'pictogram_file' => Type::getCriteriaPictogram($impact_type), + 'doc_url' => Type::getCriteriaInfoLink($impact_type), ]; } /** - * Get usage abiotic depletion potential in antimony equivalent + * Get the value of an impact criteria for the embodied + usage scopes * - * @param array $params - * @param array $crit + * @param string $impact_type Impact type identifier + * @param array $params + * @param array $crit * @return array */ - public static function getUsageAbioticDepletion(array $params = [], array $crit = []): array + public static function getImpactOfEmbodiedAndUsageCriteria(string $impact_type, array $params = [], array $crit = []): array { $default_params = [ - 'label' => __('Usage abiotic depletion potential', 'carbon'), - 'icon' => 'fa-solid fa-temperature-arrow-up', + 'label' => Type::getEmbodiedImpactLabel($impact_type), + 'icon' => Type::getCriteriaIcon($impact_type), ]; $params = array_merge($default_params, $params); if (count($crit['itemtype'] ?? []) === 0) { @@ -970,17 +1001,23 @@ public static function getUsageAbioticDepletion(array $params = [], array $crit $crit['itemtype'] = array_intersect($crit['itemtype'], PLUGIN_CARBON_TYPES); } - $value = self::getSum(UsageImpact::getTable(), 'adp', $params, $crit); + $value = self::getSum(EmbodiedImpact::getTable(), $impact_type, $params, $crit); if ($value === null) { $value = 'N/A'; } else { - $value = Toolbox::getWeight($value) . __('Sbeq', 'carbon'); + $value = Toolbox::getHumanReadableValue( + $value, + Type::getImpactUnit($impact_type) + ); } return [ 'number' => $value, 'label' => $params['label'], 'icon' => $params['icon'], + 'tooltip' => Type::getCriteriaTooltip($impact_type), + 'pictogram_file' => Type::getCriteriaPictogram($impact_type), + 'doc_url' => Type::getCriteriaInfoLink($impact_type), ]; } diff --git a/src/Dashboard/Widget.php b/src/Dashboard/Widget.php index dd639208..cddc3f97 100644 --- a/src/Dashboard/Widget.php +++ b/src/Dashboard/Widget.php @@ -40,6 +40,7 @@ use Glpi\Application\View\TemplateRenderer; use Glpi\Dashboard\Widget as GlpiDashboardWidget; use GlpiPlugin\Carbon\Documentation; +use GlpiPlugin\Carbon\Impact\Type; use GlpiPlugin\Carbon\Report; use GlpiPlugin\Carbon\Toolbox; use Monitor; @@ -107,27 +108,34 @@ public static function WidgetTypes(): array ], // Embodied impact - 'embodied_global_warming' => [ - 'label' => __('Embodied carbon emission', 'carbon'), - 'function' => self::class . '::displayEmbodiedCarbonEmission', - 'image' => '', - 'width' => 6, - 'height' => 3, - ], - 'embodied_abiotic_depletion' => [ - 'label' => __('Embodied abiotic depletion potential', 'carbon'), - 'function' => self::class . '::displayEmbodiedAbioticDepletion', - 'image' => '', - 'width' => 6, - 'height' => 3, - ], - 'embodied_primary_energy' => [ - 'label' => __('Embodied consumed primary energy', 'carbon'), - 'function' => self::class . '::displayEmbodiedPrimaryEnergy', + // 'embodied_global_warming' => [ + // 'label' => __('Embodied carbon emission', 'carbon'), + // 'function' => self::class . '::displayEmbodiedCarbonEmission', + // 'image' => '', + // 'width' => 6, + // 'height' => 3, + // ], + // 'embodied_abiotic_depletion' => [ + // 'label' => __('Embodied abiotic depletion potential', 'carbon'), + // 'function' => self::class . '::displayEmbodiedAbioticDepletion', + // 'image' => '', + // 'width' => 6, + // 'height' => 3, + // ], + // 'embodied_primary_energy' => [ + // 'label' => __('Embodied consumed primary energy', 'carbon'), + // 'function' => self::class . '::displayEmbodiedPrimaryEnergy', + // 'image' => '', + // 'width' => 6, + // 'height' => 3, + // ], + 'impact_criteria_number' => [ + 'label' => __('Impact criteria', 'carbon'), + 'function' => self::class . '::displayImpactCriteriaNumber', 'image' => '', 'width' => 6, 'height' => 3, - ], + ] ]; // Data diagnostic @@ -737,7 +745,7 @@ public static function displayMonthlyCarbonEmission(array $params = []): string $last_month['series'][0]['unit'] ); - $url = Documentation::getInfoLink('carbon_emission'); + $url = Type::getCriteriaInfoLink('gwp'); $tooltip = __('Evaluates the usage carbon emission in CO₂ equivalent during the last 2 months. %s More information %s', 'carbon'); $tooltip = sprintf($tooltip, '
', ''); $tooltip_html = Html::showToolTip($tooltip, [ @@ -803,7 +811,7 @@ public static function displayUsageCarbonEmissionYearToDate(array $params = []): break; } - $url = Documentation::getInfoLink('carbon_emission'); + $url = Type::getCriteriaInfoLink('gwp'); $tooltip = __('Evaluates the usage carbon emission in CO₂ equivalent during the last 12 elapsed months. %s More information %s', 'carbon'); $tooltip = sprintf($tooltip, '
', ''); $tooltip_html = Html::showToolTip($tooltip, [ @@ -830,23 +838,24 @@ public static function displayUsageCarbonEmissionYearToDate(array $params = []): ]); } - public static function displayEmbodiedCarbonEmission(array $params = []): string + public static function displayImpactCriteriaNumber(array $params = []): string { $default = [ - 'number' => 0, 'url' => '', 'label' => '', 'alt' => '', 'color' => '', 'icon' => '', - 'id' => 'plugin_carbon_embodied_carbon_emission_' . mt_rand(), + 'id' => 'plugin_carbon_impact_criteria_' . mt_rand(), 'filters' => [], // TODO: Not implemented yet (is this useful ?) ]; $p = array_merge($default, $params); - $url = Documentation::getInfoLink('carbon_emission'); - $tooltip = __('Evaluates the carbon emission in CO₂ equivalent. %s More information %s', 'carbon'); - $tooltip = sprintf($tooltip, '
', ''); + $url = $p['doc_url']; + $tooltip = $p['tooltip']; + $tooltip .= '
' + . __('More information', 'carbon') + . ''; $tooltip_html = Html::showToolTip($tooltip, [ 'display' => false, 'applyto' => $p['id'] . '_tip', @@ -854,43 +863,7 @@ public static function displayEmbodiedCarbonEmission(array $params = []): string $label_color = '#626976'; $fg_color = GlpiToolbox::getFgColor($p['color']); - return TemplateRenderer::getInstance()->render('@carbon/dashboard/embodied-carbon-emission.html.twig', [ - 'id' => $p['id'], - 'color' => $p['color'], - 'fg_color' => $fg_color, - 'fg_hover_color' => GlpiToolbox::getFgColor($p['color'], 15), - 'fg_hover_border' => GlpiToolbox::getFgColor($p['color'], 30), - 'label_color' => Toolbox::getAdaptedFgColor($p['color'], $label_color, 4), - 'dark_label_color' => Toolbox::getAdaptedFgColor($fg_color, $label_color, 4), - 'number' => $p['number'], - 'tooltip_html' => $tooltip_html, - ]); - } - - public static function displayEmbodiedAbioticDepletion(array $params = []): string - { - $default = [ - 'number' => 0, - 'url' => '', - 'label' => '', - 'alt' => '', - 'color' => '', - 'icon' => '', - 'id' => 'plugin_carbon_embodied_abiotic_depletion_' . mt_rand(), - 'filters' => [], // TODO: Not implemented yet (is this useful ?) - ]; - $p = array_merge($default, $params); - $url = Documentation::getInfoLink('abiotic_depletion_impact'); - $tooltip = __('Evaluates the consumption of non renewable resources in Antimony equivalent. %s More information %s', 'carbon'); - $tooltip = sprintf($tooltip, '
', ''); - $tooltip_html = Html::showToolTip($tooltip, [ - 'display' => false, - 'applyto' => $p['id'] . '_tip', - ]); - - $label_color = '#626976'; - $fg_color = GlpiToolbox::getFgColor($p['color']); - return TemplateRenderer::getInstance()->render('@carbon/dashboard/embodied-abiotic-depletion.html.twig', [ + return TemplateRenderer::getInstance()->render('@carbon/dashboard/impact-criteria.html.twig', [ 'id' => $p['id'], 'color' => $p['color'], 'fg_color' => $fg_color, @@ -898,8 +871,10 @@ public static function displayEmbodiedAbioticDepletion(array $params = []): stri 'fg_hover_border' => GlpiToolbox::getFgColor($p['color'], 30), 'label_color' => Toolbox::getAdaptedFgColor($p['color'], $label_color, 4), 'dark_label_color' => Toolbox::getAdaptedFgColor($fg_color, $label_color, 4), + 'label' => $p['label'], 'number' => $p['number'], 'tooltip_html' => $tooltip_html, + 'pictogram_file' => $p['pictogram_file'], ]); } @@ -917,7 +892,7 @@ public static function displayUsageAbioticDepletion(array $params = []): string ]; $p = array_merge($default, $params); - $url = Documentation::getInfoLink('abiotic_depletion_impact'); + $url = Type::getCriteriaInfoLink('adp'); $tooltip = __('Evaluates the consumption of non renewable resources in Antimony equivalent. %s More information %s', 'carbon'); $tooltip = sprintf($tooltip, '
', ''); $tooltip_html = Html::showToolTip($tooltip, [ @@ -1085,42 +1060,6 @@ public static function displayInformationMethodology(array $params = []): string ]); } - public static function displayEmbodiedPrimaryEnergy(array $params = []): string - { - $default = [ - 'url' => '', - 'label' => __('Total embodied primary energy', 'carbon'), - 'alt' => '', - 'color' => '', - 'icon' => '', - 'id' => 'plugin_carbon_embodied_primary_energy_' . mt_rand(), - 'filters' => [], // TODO: Not implemented yet (is this useful ?) - ]; - $p = array_merge($default, $params); - - $url = Documentation::getInfoLink('primary_energy_impact'); - $tooltip = __('Evaluates the primary energy consumed. %s More information %s', 'carbon'); - $tooltip = sprintf($tooltip, '
', ''); - $tooltip_html = Html::showToolTip($tooltip, [ - 'display' => false, - 'applyto' => $p['id'] . '_tip', - ]); - - $label_color = '#626976'; - $fg_color = GlpiToolbox::getFgColor($p['color']); - return TemplateRenderer::getInstance()->render('@carbon/dashboard/embodied-primary-energy.html.twig', [ - 'id' => $p['id'], - 'color' => $p['color'], - 'fg_color' => $fg_color, - 'fg_hover_color' => GlpiToolbox::getFgColor($p['color'], 15), - 'fg_hover_border' => GlpiToolbox::getFgColor($p['color'], 30), - 'label_color' => Toolbox::getAdaptedFgColor($p['color'], $label_color, 4), - 'dark_label_color' => Toolbox::getAdaptedFgColor($fg_color, $label_color, 4), - 'number' => $p['number'], - 'tooltip_html' => $tooltip_html, - ]); - } - /** * Displays a widget with a radar (or web) chart * diff --git a/src/Documentation.php b/src/Documentation.php deleted file mode 100644 index 6b32cbff..00000000 --- a/src/Documentation.php +++ /dev/null @@ -1,63 +0,0 @@ -. - * - * ------------------------------------------------------------------------- - */ - -namespace GlpiPlugin\Carbon; - -class Documentation -{ - private const BASE_URL = 'https://glpi-plugins.readthedocs.io/%s/latest/carbon'; - /** - * Get external URL to a detailed description of the given path - * - * @param string $object_descriptor - * @return string - */ - public static function getInfoLink(string $object_descriptor): string - { - // $lang = substr($_SESSION['glpilanguage'], 0, 2); - $lang = 'en'; - $base_url = sprintf( - self::BASE_URL, - $lang - ); - switch ($object_descriptor) { - case 'abiotic_depletion_impact': - return "$base_url/types_of_impact.html#antimony-equivalent"; - case 'primary_energy_impact': - return "$base_url/carbon/types_of_impact.html#primary-energy"; - case 'carbon_emission': - return "$base_url/carbon/types_of_impact.html#carbon-dioxyde-equivalent"; - } - - return ''; - } -} diff --git a/src/EmbodiedImpact.php b/src/EmbodiedImpact.php index 13271feb..d8c38537 100644 --- a/src/EmbodiedImpact.php +++ b/src/EmbodiedImpact.php @@ -42,101 +42,13 @@ * * Embodied impact is the impact of the asset while it is built and destroyed or recycled */ -class EmbodiedImpact extends CommonDBTM +class EmbodiedImpact extends AbstractImpact { - public static $rightname = 'carbon:report'; - public function canEdit($ID): bool { return false; } - public function rawSearchOptions() - { - $tab = parent::rawSearchOptions(); - - $tab[] = [ - 'id' => '2', - 'table' => $this->getTable(), - 'field' => 'id', - 'name' => __('ID'), - 'massiveaction' => false, // implicit field is id - 'datatype' => 'number' - ]; - - $tab[] = [ - 'id' => '3', - 'table' => $this->getTable(), - 'field' => 'items_id', - 'name' => __('Associated item ID'), - 'massiveaction' => false, - 'datatype' => 'specific', - 'additionalfields' => ['itemtype'] - ]; - - $tab[] = [ - 'id' => '4', - 'table' => $this->getTable(), - 'field' => 'itemtype', - 'name' => _n('Type', 'Types', 1), - 'massiveaction' => false, - 'datatype' => 'itemtypename', - ]; - - $tab[] = [ - 'id' => '5', - 'table' => $this->getTable(), - 'field' => 'gwp', - 'name' => __('Global Warming Potential', 'carbon'), - 'massiveaction' => false, - 'datatype' => 'number', - 'unit' => 'gCO2eq', - ]; - - $tab[] = [ - 'id' => '6', - 'table' => $this->getTable(), - 'field' => 'adp', - 'name' => __('Abiotic Depletion Potential', 'carbon'), - 'massiveaction' => false, - 'datatype' => 'number', - 'unit' => 'KgSbeq', - ]; - - $tab[] = [ - 'id' => '7', - 'table' => $this->getTable(), - 'field' => 'pe', - 'name' => __('Primary energy', 'carbon'), - 'massiveaction' => false, - 'datatype' => 'number', - 'unit' => 'J', - ]; - - $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_CALC_DATE, - 'table' => self::getTable(), - 'field' => 'date_mod', - 'name' => __('Date of evaluation', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_ENGINE, - 'table' => self::getTable(), - 'field' => 'engine', - 'name' => __('Engine', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_ENGINE_VER, - 'table' => self::getTable(), - 'field' => 'engine_version', - 'name' => __('Engine version', 'carbon') - ]; - - return $tab; - } - /** * Get iterator of items without known embodied impact for a specified itemtype * @@ -208,21 +120,4 @@ public function calculateImpact(string $lca_type, int $limit = 0): int return $iterator->count(); } - - /** - * Get impact value in a human r eadable format, selecting the best unit - */ - public function getHumanReadableImpact(string $field): string - { - switch ($field) { - case 'gwp': - return Toolbox::getWeight($this->fields[$field]) . 'CO2eq'; - case 'adp': - return Toolbox::getWeight($this->fields[$field]) . 'Sbeq'; - case 'pe': - return Toolbox::getEnergy($this->fields[$field] / 3600); // Convert J into Wh - } - - return ''; - } } diff --git a/src/Impact/Embodied/AbstractEmbodiedImpact.php b/src/Impact/Embodied/AbstractEmbodiedImpact.php index 03f94fd4..2cbe9979 100644 --- a/src/Impact/Embodied/AbstractEmbodiedImpact.php +++ b/src/Impact/Embodied/AbstractEmbodiedImpact.php @@ -108,11 +108,12 @@ public static function getItemsToEvaluate(string $itemtype, array $crit = []): D /** @var DBmysql $DB */ global $DB; - // if (!is_subclass_of($itemtype, CommonDBTM::class)) { - // throw new \LogicException('Itemtype does not inherits from ' . CommonDBTM::class); - // } - - $crit[EmbodiedImpact::getTableField('id')] = null; + $crit[] = [ + 'OR' => [ + EmbodiedImpact::getTableField('id') => null, + EmbodiedImpact::getTableField('recalculate') => 1, + ] + ]; $iterator = $DB->request(self::getEvaluableQuery($itemtype, $crit, false)); return $iterator; @@ -122,9 +123,8 @@ public function evaluateItem(): bool { $itemtype = get_class($this->item); - $input['engine'] = $this->engine; try { - $input['engine_version'] = $this->getVersion(); + $this->getVersion(); $impacts = $this->doEvaluation(); } catch (ConnectException $e) { Session::addMessageAfterRedirect(__('Connection to Boavizta failed.', 'carbon'), false, ERROR); @@ -148,6 +148,10 @@ public function evaluateItem(): bool $embodied_impact->getFromDBByCrit($input); $impact_types = Type::getImpactTypes(); + $input['recalculate'] = 0; + $input['engine'] = $this->engine; + $input['engine_version'] = self::$engine_version; + // Prepare inputs for add or update foreach ($impacts as $type => $value) { $key = $impact_types[$type]; diff --git a/src/Impact/Embodied/Boavizta/AbstractAsset.php b/src/Impact/Embodied/Boavizta/AbstractAsset.php index f6db53a6..c1490d04 100644 --- a/src/Impact/Embodied/Boavizta/AbstractAsset.php +++ b/src/Impact/Embodied/Boavizta/AbstractAsset.php @@ -44,7 +44,7 @@ abstract class AbstractAsset extends AbstractEmbodiedImpact implements AssetInte protected string $engine = 'Boavizta'; /** @var string $engine_version Version of the calculation engine */ - protected static string $engine_version = 'unknown'; + // protected static string $engine_version = 'unknown'; /** @var string Endpoint to query for the itemtype, to be filled in child class */ protected string $endpoint = ''; @@ -55,6 +55,32 @@ abstract class AbstractAsset extends AbstractEmbodiedImpact implements AssetInte /** @var Client instance of the HTTP client */ protected ?Client $client = null; + /** @var array Supported impact criterias and the multiplier unit of the value returned by Boaviztapi */ + protected array $criteria_units = [ + 'gwp' => 1000, // Kg + 'adp' => 1000, // Kg + 'pe' => 1000000, // MJ + 'gwppb' => 1000, // Kg + 'gwppf' => 1000, // Kg + 'gwpplu' => 1000, // Kg + 'ir' => 1000, // Kg + 'lu' => 1, // (no unit) + 'odp' => 1000, // Kg + 'pm' => 1, // (no unit) + 'pocp' => 1000, // Kg + 'wu' => 1000, // M^3 + 'mips' => 1000, // Kg + 'adpe' => 1000, // Kg + 'adpf' => 1000000, // MJ + 'ap' => 1, // mol + 'ctue' => 1, // CTUe + // 'ctuh_c' => 1, // CTUh request fails when this criteria is added, not a URL encoding issue + // 'ctuh_nc' => 1, // CTUh request fails when this criteria is added, not a URL encoding issue + 'epf' => 1000, // Kg + 'epm' => 1000, // Kg + 'ept' => 1, // mol + ]; + // abstract public static function getEngine(CommonDBTM $item): EngineInterface; /** @@ -98,7 +124,23 @@ protected function getVersion(): string return self::$engine_version; } - protected function query($description): array + /** + * Get the quety string specifying the impact criterias for the HTTP request + * + * @return string + */ + protected function getCriteriasQueryString(): string + { + return 'criteria=' . implode('&criteria=', array_keys($this->criteria_units)); + } + + /** + * Send a HTTP query + * + * @param array $description + * @return array + */ + protected function query(array $description): array { try { $response = $this->client->post($this->endpoint, [ @@ -115,6 +157,7 @@ protected function query($description): array /** * Read the response to find the impacts provided by Boaviztapi * + * @param array $response * @return array */ protected function parseResponse(array $response): array @@ -130,22 +173,28 @@ protected function parseResponse(array $response): array if ($impact_id === false) { continue; } - switch ($type) { - case 'gwp': - $impacts[$impact_id] = $this->parseGwp($response['impacts'][$type]); - break; - case 'adp': - $impacts[$impact_id] = $this->parseAdp($response['impacts'][$type]); - break; - case 'pe': - $impacts[$impact_id] = $this->parsePe($response['impacts'][$type]); - break; - } + $impacts[$impact_id] = $this->parseCriteria($type, $response['impacts'][$type]); } return $impacts; } + protected function parseCriteria(string $name, array $impact): ?TrackedFloat + { + if ($impact['embedded'] === 'not implemented') { + return null; + } + + $unit_multiplier = $this->criteria_units[$name]; + $value = new TrackedFloat( + $impact['embedded']['value'] * $unit_multiplier, + null, + TrackedFloat::DATA_QUALITY_ESTIMATED + ); + + return $value; + } + protected function parseGwp(array $impact): ?TrackedFloat { if ($impact['embedded'] === 'not implemented') { diff --git a/src/Impact/Embodied/Boavizta/Computer.php b/src/Impact/Embodied/Boavizta/Computer.php index f395664e..12e6e4b8 100644 --- a/src/Impact/Embodied/Boavizta/Computer.php +++ b/src/Impact/Embodied/Boavizta/Computer.php @@ -59,6 +59,7 @@ protected function doEvaluation(): ?array // adapt $this->endpoint depending on the type of computer (server, laptop, ...) $type = $this->getType($this->item); $this->endpoint = $this->getEndpoint($type); + $this->endpoint .= '?' . $this->getCriteriasQueryString(); // Ask for embodied impact only $handle_hardware = in_array($type, [ diff --git a/src/Impact/Embodied/Engine.php b/src/Impact/Embodied/Engine.php index 7a3a2dbb..a66b2b70 100644 --- a/src/Impact/Embodied/Engine.php +++ b/src/Impact/Embodied/Engine.php @@ -34,6 +34,7 @@ use CommonGLPI; use CommonDBTM; +use DBmysql; use GlpiPlugin\Carbon\AbstractModel; use GlpiPlugin\Carbon\Config; use GlpiPlugin\Carbon\DataSource\Lca\Boaviztapi\Client; @@ -131,6 +132,9 @@ protected static function configureEngine(EmbodiedImpactInterface $engine): Embo */ private static function hasModelData(CommonDBTM $item): bool { + /** @var DBmysql $DB */ + global $DB; + $itemtype = get_class($item); $glpi_model_class = $itemtype . 'Model'; $glpi_model_class_fk = getForeignKeyFieldForItemType($glpi_model_class); @@ -138,12 +142,16 @@ private static function hasModelData(CommonDBTM $item): bool * @var class-string $model_class */ $model_class = 'GlpiPlugin\\Carbon\\' . $glpi_model_class; + $model_table = getTableForItemType($model_class); $glpi_model_id = $item->fields[$glpi_model_class_fk]; $crit = [ $glpi_model_class_fk => $glpi_model_id ]; $types = Type::getImpactTypes(); foreach ($types as $key => $type) { + if (!$DB->fieldExists($model_table, $type)) { + continue; + } $crit['OR'][] = [ $type . '_quality' => ['<>', AbstractTracked::DATA_QUALITY_UNSET_VALUE] ]; diff --git a/src/Impact/Type.php b/src/Impact/Type.php index 7c3f5551..bc817a96 100644 --- a/src/Impact/Type.php +++ b/src/Impact/Type.php @@ -35,16 +35,91 @@ class Type { - const IMPACT_GWP = 0; // Global warming potential - const IMPACT_ADP = 1; // Abiotic Depletion Potential - const IMPACT_PE = 2; // Primary Energy + private const BASE_URL = 'https://glpi-plugins.readthedocs.io/%s/latest/carbon'; + + const IMPACT_GWP = 0; // Global warming potential + const IMPACT_ADP = 1; // Abiotic Depletion Potential + const IMPACT_PE = 2; // Primary Energy + const IMPACT_GWPPB = 3; + const IMPACT_GWPPF = 4; + const IMPACT_GWPPLU = 5; + const IMPACT_IR = 6; + const IMPACT_LU = 7; + const IMPACT_ODP = 8; + const IMPACT_PM = 9; + const IMPACT_POCP = 10; + const IMPACT_WU = 11; + const IMPACT_MIPS = 12; + const IMPACT_ADPE = 13; + const IMPACT_ADPF = 14; + const IMPACT_AP = 15; + const IMPACT_CTUE = 16; + // const IMPACT_CTUHC = 17; + // const IMPACT_CTUHNC = 18; + const IMPACT_EPF = 19; + const IMPACT_EPM = 20; + const IMPACT_EPT = 21; private static array $impact_types = [ - self::IMPACT_GWP => 'gwp', - self::IMPACT_ADP => 'adp', - self::IMPACT_PE => 'pe', + self::IMPACT_GWP => 'gwp', + self::IMPACT_ADP => 'adp', + self::IMPACT_PE => 'pe', + self::IMPACT_GWPPB => 'gwppb', + self::IMPACT_GWPPF => 'gwppf', + self::IMPACT_GWPPLU => 'gwpplu', + self::IMPACT_IR => 'ir', + self::IMPACT_LU => 'lu', + self::IMPACT_ODP => 'odp', + self::IMPACT_PM => 'pm', + self::IMPACT_POCP => 'pocp', + self::IMPACT_WU => 'wu', + self::IMPACT_MIPS => 'mips', + self::IMPACT_ADPE => 'adpe', + self::IMPACT_ADPF => 'adpf', + self::IMPACT_AP => 'ap', + self::IMPACT_CTUE => 'ctue', + // self::IMPACT_CTUHC => 'ctuh_c', + // self::IMPACT_CTUHNC => 'ctuh_nc', + self::IMPACT_EPF => 'epf', + self::IMPACT_EPM => 'epm', + self::IMPACT_EPT => 'ept', + ]; + + /** + * Unit of impact criterias + * + * @var array + */ + private static array $impact_units = [ + 'gwp' => ['g', 'CO₂ eq'], + 'adp' => ['g', 'SB eq'], + 'pe' => ['J', ''], + 'gwppb' => ['g', 'CO₂ eq'], + 'gwppf' => ['g', 'CO₂ eq'], + 'gwpplu' => ['g', 'CO₂ eq'], + 'ir' => ['g', 'U235 eq'], + 'lu' => null, + 'odp' => ['g', 'CFC-11 eq'], + 'pm' => null, + 'pocp' => ['g', 'U235 eq'], + 'wu' => ['m³', ''], + 'mips' => ['g', ''], + 'adpe' => ['g', 'SB eq'], + 'adpf' => ['J', ''], + 'ap' => ['mol', 'H+ eq'], + 'ctue' => null, + // 'ctuh_c' => [null, 'CTUh'], + // 'ctuh_nc' => [null, 'CTUh'], + 'epf' => ['g', 'P eq'], + 'epm' => ['g', 'N eq'], + 'ept' => ['mol', 'N eq'], ]; + /** + * get an array of impact types + * + * @return array + */ public static function getImpactTypes(): array { return self::$impact_types; @@ -55,9 +130,275 @@ public static function getImpactTypes(): array * * @param string $type * @return int|string|false - */ + **/ public static function getImpactId(string $type) { return array_search($type, self::$impact_types); } + + /** + * Get the unit of an impact type + * + * @param string $type impact type name + * @return array + **/ + public static function getImpactUnit(string $type): array + { + return self::$impact_units[$type] ?? ['', '']; + } + + /** + * Get the unit of an impact type + * + * @param string $type impact type name + * @return string + **/ + public static function getEmbodiedImpactLabel(string $type): string + { + $label = match ($type) { + 'gwp' => __('Embodied Global warming potential', 'carbon'), + 'adp' => __('Embodied Abiotic depletion potential', 'carbon'), + 'pe' => __('Embodied Primary energy consumed', 'carbon'), + 'gwppb' => __('Embodied Climate change - Contribution of biogenic emissions', 'carbon'), + 'gwppf' => __('Embodied Climate change - Contribution of fossil fuel emissions', 'carbon'), + 'gwpplu' => __('Embodied Climate change - Contribution of emissions from land use change', 'carbon'), + 'ir' => __('Embodied Emissions of radionizing substances', 'carbon'), + 'lu' => __('Embodied Land use', 'carbon'), + 'odp' => __('Embodied Depletion of the ozone layer', 'carbon'), + 'pm' => __('Embodied Fine particle emissions', 'carbon'), + 'pocp' => __('Embodied Photochemical ozone formation', 'carbon'), + 'wu' => __('Embodied Use of water resources', 'carbon'), + 'mips' => __('Embodied Material input per unit of service', 'carbon'), + 'adpe' => __('Embodied Use of mineral and metal resources', 'carbon'), + 'adpf' => __('Embodied Use of fossil resources (including nuclear)', 'carbon'), + 'ap' => __('Embodied Acidification', 'carbon'), + 'ctue' => __('Embodied Freshwater ecotoxicity', 'carbon'), + // 'ctuh_c' => __('Embodied Human Toxicity - Carcinogenic Effects', 'carbon'), + // 'ctuh_nc' => __('Embodied Human toxicity - non-carcinogenic effects', 'carbon'), + 'epf' => __('Embodied Eutrophication of freshwater', 'carbon'), + 'epm' => __('Embodied Eutrophication of marine waters', 'carbon'), + 'ept' => __('Embodied Terrestrial eutrophication', 'carbon'), + default => '', + }; + return $label; + } + + /** + * Get the unit of an impact type + * + * @param string $type impact type name + * @return string + **/ + public static function getUsageImpactLabel(string $type): string + { + $label = match ($type) { + 'gwp' => __('Usage Global warming potential', 'carbon'), + 'adp' => __('Usage Abiotic depletion potential', 'carbon'), + 'pe' => __('Usage Primary energy consumed', 'carbon'), + 'gwppb' => __('Usage Climate change - Contribution of biogenic emissions', 'carbon'), + 'gwppf' => __('Usage Climate change - Contribution of fossil fuel emissions', 'carbon'), + 'gwpplu' => __('Usage Climate change - Contribution of emissions from land use change', 'carbon'), + 'ir' => __('Usage Emissions of radionizing substances', 'carbon'), + 'lu' => __('Usage Land use', 'carbon'), + 'odp' => __('Usage Depletion of the ozone layer', 'carbon'), + 'pm' => __('Usage Fine particle emissions', 'carbon'), + 'pocp' => __('Usage Photochemical ozone formation', 'carbon'), + 'wu' => __('Usage Use of water resources', 'carbon'), + 'mips' => __('Usage Material input per unit of service', 'carbon'), + 'adpe' => __('Usage Use of mineral and metal resources', 'carbon'), + 'adpf' => __('Usage Use of fossil resources (including nuclear)', 'carbon'), + 'ap' => __('Usage Acidification', 'carbon'), + 'ctue' => __('Usage Freshwater ecotoxicity', 'carbon'), + // 'ctuh_c' => __('Usage Human Toxicity - Carcinogenic Effects', 'carbon'), + // 'ctuh_nc' => __('Usage Human toxicity - non-carcinogenic effects', 'carbon'), + 'epf' => __('Usage Eutrophication of freshwater', 'carbon'), + 'epm' => __('Usage Eutrophication of marine waters', 'carbon'), + 'ept' => __('Usage Terrestrial eutrophication', 'carbon'), + default => '' + }; + return $label; + } + + /** + * Get the unit of an impact type + * + * @param string $type impact type name + * @return string + **/ + public static function getEmbodiedAndUsageImpactLabel(string $type): string + { + $label = match ($type) { + 'gwp' => __('Total Global warming potential', 'carbon'), + 'adp' => __('Total Abiotic depletion potential', 'carbon'), + 'pe' => __('Total Primary energy consumed', 'carbon'), + 'gwppb' => __('Total Climate change - Contribution of biogenic emissions', 'carbon'), + 'gwppf' => __('Total Climate change - Contribution of fossil fuel emissions', 'carbon'), + 'gwpplu' => __('Total Climate change - Contribution of emissions from land use change', 'carbon'), + 'ir' => __('Total Emissions of radionizing substances', 'carbon'), + 'lu' => __('Total Land use', 'carbon'), + 'odp' => __('Total Depletion of the ozone layer', 'carbon'), + 'pm' => __('Total Fine particle emissions', 'carbon'), + 'pocp' => __('Total Photochemical ozone formation', 'carbon'), + 'wu' => __('Total Use of water resources', 'carbon'), + 'mips' => __('Total Material input per unit of service', 'carbon'), + 'adpe' => __('Total Use of mineral and metal resources', 'carbon'), + 'adpf' => __('Total Use of fossil resources (including nuclear)', 'carbon'), + 'ap' => __('Total Acidification', 'carbon'), + 'ctue' => __('Total Freshwater ecotoxicity', 'carbon'), + // 'ctuh_c' => __('Total Human Toxicity - Carcinogenic Effects', 'carbon'), + // 'ctuh_nc' => __('Total Human toxicity - non-carcinogenic effects', 'carbon'), + 'epf' => __('Total Eutrophication of freshwater', 'carbon'), + 'epm' => __('Total Eutrophication of marine waters', 'carbon'), + 'ept' => __('Total Terrestrial eutrophication', 'carbon'), + default => '', + }; + return $label; + } + + public static function getCriteriaIcon(string $type): string + { + return match ($type) { + // Global Warming Potential + 'gwp', 'gwppb', 'gwppf', 'gwpplu' + => 'fa-solid fa-temperature-high', + + // Abiotic depletion (minerals / fossil) + 'adp', 'adpe' + => 'fa-solid fa-gem', + 'adpf' + => 'fa-solid fa-oil-can', + + // Primary energy + 'pe' + => 'fa-solid fa-bolt', + + // Ionising radiation + 'ir' + => 'fa-solid fa-radiation', + + // Land use + 'lu' + => 'fa-solid fa-tree', + + // Ozone depletion + 'odp' + => 'fa-solid fa-cloud', + + // Particulate matter + 'pm' + => 'fa-solid fa-smog', + + // Photochemical ozone creation + 'pocp' + => 'fa-solid fa-sun', + + // Water use + 'wu' + => 'fa-solid fa-droplet', + + // Material input per service unit + 'mips' + => 'fa-solid fa-boxes-stacked', + + // Acidification + 'ap' + => 'fa-solid fa-flask', + + // Ecotoxicity (freshwater, marine, terrestrial) + 'epf', 'epm', 'ept' + => 'fa-solid fa-fish', + + // Human toxicity / ecotoxicity + 'ctue', 'ctuh_c', 'ctuh_nc' + => 'fa-solid fa-skull-crossbones', + + default + => '', // or 'fa-solid fa-circle-question', + }; + } + + public static function getCriteriaTooltip(string $type): string + { + return match ($type) { + 'gwp' => __('Carbon emission in CO₂ equivalent', 'carbon'), + 'adp' => __('Consumption of non renewable resources in Antimony equivalent.', 'carbon'), + 'pe' => __('Primary energy consumed.', 'carbon'), + 'gwppb' => __('', 'carbon'), + 'gwppf' => __('', 'carbon'), + 'gwpplu' => __('', 'carbon'), + 'ir' => __('', 'carbon'), + 'lu' => __('', 'carbon'), + 'odp' => __('', 'carbon'), + 'pm' => __('', 'carbon'), + 'pocp' => __('', 'carbon'), + 'wu' => __('', 'carbon'), + 'mips' => __('', 'carbon'), + 'adpe' => __('', 'carbon'), + 'adpf' => __('', 'carbon'), + 'ap' => __('', 'carbon'), + 'ctue' => __('', 'carbon'), + // 'ctuh_c' => __('', 'carbon'), + // 'ctuh_nc' => __('', 'carbon'), + 'epf' => __('Usage Eutrophication of freshwater', 'carbon'), + 'epm' => __('Usage Eutrophication of marine waters', 'carbon'), + 'ept' => __('Usage Terrestrial eutrophication', 'carbon'), + default => '' + }; + } + + public static function getCriteriaPictogram(string $type): string + { + $pictogram_file = match ($type) { + 'gwp' => 'icon-carbon-emission.svg', + 'adp' => 'icon-fossil-primary-energy.svg', + 'pe' => 'icon-pickaxe.svg', + 'gwppb' => '', + 'gwppf' => '', + 'gwpplu' => '', + 'ir' => '', + 'lu' => '', + 'odp' => '', + 'pm' => '', + 'pocp' => '', + 'wu' => '', + 'mips' => '', + 'adpe' => '', + 'adpf' => '', + 'ap' => '', + 'ctue' => '', + // 'ctuh_c' => '', + // 'ctuh_nc' => '', + 'epf' => '', + 'epm' => '', + 'ept' => '', + default => '' + }; + return $pictogram_file; + } + + /** + * Get external URL to a detailed description of the given path + * + * @param string $impact_type + * @return string + */ + public static function getCriteriaInfoLink(string $impact_type): string + { + // $lang = substr($_SESSION['glpilanguage'], 0, 2); + $lang = 'en'; + $base_url = sprintf( + self::BASE_URL, + $lang + ); + switch ($impact_type) { + case 'gwp': + return "$base_url/types_of_impact.html#carbon-dioxyde-equivalent"; + case 'adp': + return "$base_url/types_of_impact.html#antimony-equivalent"; + case 'pe': + return "$base_url/carbon/types_of_impact.html#primary-energy"; + } + + return ''; + } } diff --git a/src/Impact/Usage/AbstractUsageImpact.php b/src/Impact/Usage/AbstractUsageImpact.php index 9d6101d7..38414f36 100644 --- a/src/Impact/Usage/AbstractUsageImpact.php +++ b/src/Impact/Usage/AbstractUsageImpact.php @@ -58,7 +58,7 @@ abstract class AbstractUsageImpact implements UsageImpactInterface protected string $engine = 'undefined'; /** @var string $engine_version Version of the calculation engine */ - protected string $engine_version = 'unknown'; + protected static string $engine_version = 'unknown'; /** @var array of TrackedFloat */ protected array $impacts = []; @@ -70,6 +70,8 @@ public function __construct() } } + abstract protected function getVersion(): string; + /** * Get the unit of an impact * @@ -114,6 +116,12 @@ public function getItemsToEvaluate(array $crit = []): DBmysqlIterator throw new \LogicException('Itemtype does not inherits from ' . CommonDBTM::class); } + $crit[] = [ + 'OR' => [ + UsageImpact::getTableField('id') => null, + UsageImpact::getTableField('recalculate') => 1, + ] + ]; $crit[UsageImpact::getTableField('id')] = null; $iterator = $DB->request($this->getEvaluableQuery($crit, false)); @@ -169,6 +177,7 @@ public function evaluateItem(int $id): bool } try { + $this->getVersion(); $impacts = $this->doEvaluation($item); } catch (\RuntimeException $e) { return false; @@ -188,8 +197,9 @@ public function evaluateItem(int $id): bool $usage_impact->getFromDBByCrit($input); $impact_types = Type::getImpactTypes(); + $input['recalculate'] = 0; $input['engine'] = $this->engine; - $input['engine_version'] = $this->engine_version; + $input['engine_version'] = self::$engine_version; // Prepare inputs for add or update foreach ($impacts as $type => $value) { @@ -226,11 +236,6 @@ public function getEvaluableQuery(array $crit = [], bool $entity_restrict = true $glpi_location_table = GlpiLocation::getTable(); $usage_impact_table = UsageImpact::getTable(); - // $where = []; - // if (!$recalculate) { - // $where = [UsageImpact::getTableField('id') => null]; - // } - $request = [ 'SELECT' => [ $itemtype::getTableField('id'), diff --git a/src/Impact/Usage/Boavizta/AbstractAsset.php b/src/Impact/Usage/Boavizta/AbstractAsset.php index 1d89e986..417fb7f8 100644 --- a/src/Impact/Usage/Boavizta/AbstractAsset.php +++ b/src/Impact/Usage/Boavizta/AbstractAsset.php @@ -53,7 +53,7 @@ abstract class AbstractAsset extends AbstractUsageImpact implements AssetInterfa protected string $engine = 'Boavizta'; /** @var string $engine_version Version of the calculation engine */ - protected string $engine_version = 'unknown'; + // protected static string $engine_version = 'unknown'; /** @var string Endpoint to query for the itemtype, to be filled in child class */ protected string $endpoint = ''; @@ -91,11 +91,14 @@ abstract protected function getAveragePower(int $id): ?int; public function setClient(Client $client) { $this->client = $client; - // $this->engine_version = $this->getVersion(); } protected function getVersion(): string { + if (self::$engine_version !== 'unknown') { + return self::$engine_version; + } + try { $response = $this->client->get('utils/version'); } catch (\RuntimeException $e) { @@ -109,8 +112,8 @@ protected function getVersion(): string ), E_USER_WARNING); throw new \RuntimeException('Invalid response from Boavizta API'); } - - return $response[0]; + self::$engine_version = $response[0]; + return self::$engine_version; } protected function query($description): array diff --git a/src/Impact/Usage/Boavizta/Computer.php b/src/Impact/Usage/Boavizta/Computer.php index cb1d328c..69f3b35b 100644 --- a/src/Impact/Usage/Boavizta/Computer.php +++ b/src/Impact/Usage/Boavizta/Computer.php @@ -183,7 +183,7 @@ protected function doEvaluation(CommonDBTM $item): ?array $average_power = $this->getAveragePower($item->getID()); - // Ask for embodied impact only + // Ask for usage impact only $configuration = $this->analyzeHardware($item); if (count($configuration) === 0) { return null; diff --git a/src/Report.php b/src/Report.php index bbb6f8ed..8b5861a9 100644 --- a/src/Report.php +++ b/src/Report.php @@ -129,7 +129,7 @@ public static function getUsageCarbonEmission(array $params = []): array $end_date = DateTime::createFromFormat('Y-m-d\TH:i:s.v\Z', $params['args']['apply_filters'][1]); } - $value = Provider::getUsageCarbonEmission($params)['number']; + $value = Provider::getImpactOfUsageCriteria('gwp', $params)['number']; // Prepare date format $date_format = 'Y F'; @@ -166,7 +166,7 @@ public static function getTotalEmbodiedCarbonEmission(array $params = []): array $end_date = DateTime::createFromFormat('Y-m-d\TH:i:s.v\Z', $params['args']['apply_filters'][1]); } - $value = Provider::getEmbodiedGlobalWarming($params); + $value = Provider::getImpactOfEmbodiedCriteria('gwp', $params); // Prepare date format $date_format = 'Y F'; diff --git a/src/SearchOptions.php b/src/SearchOptions.php index 1d2dc9b4..b416bad3 100644 --- a/src/SearchOptions.php +++ b/src/SearchOptions.php @@ -89,17 +89,9 @@ class SearchOptions public const CARBON_EMISSION_PER_DAY = self::SEARCH_OPTION_BASE + 602; public const CARBON_EMISSION_ENERGY_QUALITY = self::SEARCH_OPTION_BASE + 603; public const CARBON_EMISSION_EMISSION_QUALITY = self::SEARCH_OPTION_BASE + 604; - public const CARBON_EMISSION_CALC_DATE = self::SEARCH_OPTION_BASE + 605; - public const CARBON_EMISSION_ENGINE = self::SEARCH_OPTION_BASE + 606; - public const CARBON_EMISSION_ENGINE_VER = self::SEARCH_OPTION_BASE + 607; - - public const USAGE_IMPACT_DATE = self::SEARCH_OPTION_BASE + 700; - public const USAGE_IMPACT_GWP = self::SEARCH_OPTION_BASE + 701; - public const USAGE_IMPACT_GWP_QUALITY = self::SEARCH_OPTION_BASE + 702; - public const USAGE_IMPACT_ADP = self::SEARCH_OPTION_BASE + 703; - public const USAGE_IMPACT_ADP_QUALITY = self::SEARCH_OPTION_BASE + 704; - public const USAGE_IMPACT_PE = self::SEARCH_OPTION_BASE + 705; - public const USAGE_IMPACT_PE_QUALITY = self::SEARCH_OPTION_BASE + 706; + public const CALCULATION_DATE = self::SEARCH_OPTION_BASE + 605; + public const CALCULATION_ENGINE = self::SEARCH_OPTION_BASE + 606; + public const CALCULATION_ENGINE_VERSION = self::SEARCH_OPTION_BASE + 607; public const COMPUTER_TYPE_CATEGORY = self::SEARCH_OPTION_BASE + 800; public const COMPUTER_TYPE_IS_IGNORED = self::SEARCH_OPTION_BASE + 801; @@ -110,6 +102,13 @@ class SearchOptions public const NETEQUIP_TYPE_IS_IGNORED = self::SEARCH_OPTION_BASE + 1100; + // First search option ID for all imapcts + // Impacts are numbered accross several consecutive IDs + // - impact type + // - impact quality + // @see AbstractImpact::rawSearchOption + public const IMPACT_BASE = self::SEARCH_OPTION_BASE + 1200; + public const EMBODIED_IMPACT_GWP = self::SEARCH_OPTION_BASE + 1200; public const EMBODIED_IMPACT_GWP_SOURCE = self::SEARCH_OPTION_BASE + 1201; public const EMBODIED_IMPACT_GWP_QUALITY = self::SEARCH_OPTION_BASE + 1202; diff --git a/src/Toolbox.php b/src/Toolbox.php index 328e34cf..67517d2d 100644 --- a/src/Toolbox.php +++ b/src/Toolbox.php @@ -224,20 +224,7 @@ public static function getWeight(float $weight): string $weight = self::dynamicRound($weight); //TRANS: %1$s is a number maybe float or string and %2$s the unit - return sprintf(__('%1$s %2$s'), $weight, $human_readable_unit); - } - - public static function dynamicRound(float $number): float - { - if ($number < 10) { - $number = round($number, 2); - } else if ($number < 100) { - $number = round($number, 1); - } else { - $number = round($number, 0); - } - - return $number; + return sprintf(__('%1$s %2$s'), $weight, $human_readable_unit); } /** @@ -272,19 +259,19 @@ public static function getPower(float $p): string $p = self::dynamicRound($p); //TRANS: %1$s is a number maybe float or string and %2$s the unit - return sprintf(__('%1$s %2$s'), $p, $human_readable_unit); + return sprintf(__('%1$s %2$s'), $p, $human_readable_unit); } /** - * Format a power passing a power in grams + * Format a energy in watt.hour * - * @param float $p Power in Watt + * @param float $p Energy in watt.hour * - * @return string formatted power + * @return string formatted energy **/ public static function getEnergy(float $p): string { - //TRANS: list of unit (W for watt) + //TRANS: list of unit (Wh for watt.hour) $units = [ __('Wh', 'carbon'), __('KWh', 'carbon'), @@ -307,7 +294,49 @@ public static function getEnergy(float $p): string $p = self::dynamicRound($p); //TRANS: %1$s is a number maybe float or string and %2$s the unit - return sprintf(__('%1$s %2$s'), $p, $human_readable_unit); + return sprintf(__('%1$s %2$s'), $p, $human_readable_unit); + } + + public static function dynamicRound(float $number): float + { + if ($number < 10) { + $number = round($number, 2); + } else if ($number < 100) { + $number = round($number, 1); + } else { + $number = round($number, 0); + } + + return $number; + } + + /** + * Convert a value and its unit into a human readable value + * + * Unit is an array i.e. ['g', 'CO2 eq'] for grams of carbondioxyde equivalent + * + * @param float $value value of the quantity to convert + * @param array $unit unit splitted into a standard unit and a qualification. + * @return string + */ + public static function getHumanReadableValue(float $value, array $unit): string + { + switch ($unit[0]) { + case 'g': + return self::getWeight($value) . $unit[1]; + case 'J': + // To be converted into watt.hour + return self::getEnergy($value / 3600) . $unit[1]; + case 'Wh': + return self::getEnergy($value) . $unit[1]; + case 'm³': + // Value is in m^3 + return sprintf(__('%1$s %2$s', 'carbon'), $value * 1000, 'L'); + case 'mol': + break; + } + + return sprintf(__('%1$s %2$s', 'carbon'), $value, implode(' ', $unit)); } /** diff --git a/src/UsageImpact.php b/src/UsageImpact.php index 5ee94260..de422c6f 100644 --- a/src/UsageImpact.php +++ b/src/UsageImpact.php @@ -32,19 +32,10 @@ namespace GlpiPlugin\Carbon; -use CommonDBChild; -use DateInterval; -use DateTimeInterface; -use Entity; -use Location; +use GlpiPlugin\Carbon\Impact\Type; -class UsageImpact extends CommonDBChild +class UsageImpact extends AbstractImpact { - public static $itemtype = 'itemtype'; - public static $items_id = 'items_id'; - - public static $rightname = 'carbon:report'; - public static function getTypeName($nb = 0) { return _n("Usage impact", "Usage impacts", $nb, 'carbon'); @@ -58,128 +49,4 @@ public function prepareInputForAdd($input) } return $input; } - - public function rawSearchOptions() - { - $tab = parent::rawSearchOptions(); - - $tab[] = [ - 'id' => '2', - 'table' => $this->getTable(), - 'field' => 'id', - 'name' => __('ID'), - 'massiveaction' => false, // implicit field is id - 'datatype' => 'number' - ]; - - $tab[] = [ - 'id' => '3', - 'table' => $this->getTable(), - 'field' => 'items_id', - 'name' => __('Associated item ID'), - 'massiveaction' => false, - 'datatype' => 'specific', - 'additionalfields' => ['itemtype'] - ]; - - $tab[] = [ - 'id' => '4', - 'table' => $this->getTable(), - 'field' => 'itemtype', - 'name' => _n('Type', 'Types', 1), - 'massiveaction' => false, - 'datatype' => 'itemtypename', - ]; - - $tab[] = [ - 'id' => SearchOptions::USAGE_IMPACT_DATE, - 'table' => self::getTable(), - 'field' => 'date', - 'name' => __('Date') - ]; - - $tab[] = [ - 'id' => SearchOptions::USAGE_IMPACT_GWP, - 'table' => self::getTable(), - 'field' => 'gwp', - 'name' => __('Global warming potential', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::USAGE_IMPACT_GWP_QUALITY, - 'table' => self::getTable(), - 'field' => 'gwp_quality', - 'name' => __('Global warming potential quality', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::USAGE_IMPACT_ADP, - 'table' => self::getTable(), - 'field' => 'adp', - 'name' => __('Abiotic depletion potential', 'carbon') - - ]; - - $tab[] = [ - 'id' => SearchOptions::USAGE_IMPACT_ADP_QUALITY, - 'table' => self::getTable(), - 'field' => 'adp_quality', - 'name' => __('Abiotic depletion potential quality', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::USAGE_IMPACT_PE, - 'table' => self::getTable(), - 'field' => 'pe', - 'name' => __('Primary energy quality', 'carbon') - - ]; - - $tab[] = [ - 'id' => SearchOptions::USAGE_IMPACT_PE_QUALITY, - 'table' => self::getTable(), - 'field' => 'pe_quality', - 'name' => __('Primary energy quality', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_CALC_DATE, - 'table' => self::getTable(), - 'field' => 'date_mod', - 'name' => __('Date of evaluation', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_ENGINE, - 'table' => self::getTable(), - 'field' => 'engine', - 'name' => __('Engine', 'carbon') - ]; - - $tab[] = [ - 'id' => SearchOptions::CARBON_EMISSION_ENGINE_VER, - 'table' => self::getTable(), - 'field' => 'engine_version', - 'name' => __('Engine version', 'carbon') - ]; - - return $tab; - } - - /** - * Get impact value in a human r eadable format, selecting the best unit - */ - public function getHumanReadableImpact(string $field): string - { - switch ($field) { - case 'gwp': - return Toolbox::getWeight($this->fields[$field]) . 'CO2eq'; - case 'adp': - return Toolbox::getWeight($this->fields[$field]) . 'Sbeq'; - case 'pe': - return Toolbox::getEnergy($this->fields[$field] / 3600); // Convert J into Wh - } - - return ''; - } } diff --git a/src/UsageInfo.php b/src/UsageInfo.php index b88f1728..1449493d 100644 --- a/src/UsageInfo.php +++ b/src/UsageInfo.php @@ -39,6 +39,7 @@ use Glpi\Application\View\TemplateRenderer; use GlpiPlugin\Carbon\Dashboard\Provider; use GlpiPlugin\Carbon\Dashboard\Widget; +use GlpiPlugin\Carbon\Impact\Type; use Html; use Monitor; use NetworkEquipment; @@ -214,33 +215,35 @@ public static function showCharts(CommonDBTM $asset) 'items_id' => $asset->getID(), ]); - $url = Documentation::getInfoLink('carbon_emission'); - $tooltip = __('Evaluates the carbon emission in CO₂ equivalent. %s More information %s', 'carbon'); - $tooltip = sprintf($tooltip, '
', ''); - $carbon_emission_tooltip_html = Html::showToolTip($tooltip, [ - 'display' => false, - 'applyto' => 'carbon_emission_tip', - ]); - - $url = Documentation::getInfoLink('abiotic_depletion_impact'); - $tooltip = __('Evaluates the consumption of non renewable resources in Antimony equivalent. %s More information %s', 'carbon'); - $tooltip = sprintf($tooltip, '
', ''); - $usage_abiotic_depletion_tooltip_html = Html::showToolTip($tooltip, [ - 'display' => false, - 'applyto' => 'usage_abiotic_depletion_tip', - ]); - $embodied_abiotic_depletion_tooltip_html = Html::showToolTip($tooltip, [ - 'display' => false, - 'applyto' => 'embodied_abiotic_depletion_tip', - ]); - - $url = Documentation::getInfoLink('primary_energy'); - $tooltip = __('Evaluates the primary energy consumed. %s More information %s', 'carbon'); - $tooltip = sprintf($tooltip, '
', ''); - $embodied_primary_energy_tooltip_html = Html::showToolTip($tooltip, [ - 'display' => false, - 'applyto' => 'embodied_primary_energy_tip', - ]); + $embodied_tooltips = []; + $usage_tooltips = []; + $embodied_labels = []; + $usage_labels = []; + foreach (Type::getImpactTypes() as $impact_type) { + $tooltip = Type::getCriteriaTooltip($impact_type); + $url = Type::getCriteriaInfoLink($impact_type); + if ($url !== '') { + $tooltip = sprintf( + $tooltip . __('%s More information %s', 'carbon'), + '
', + '' + ); + } + $embodied_tooltips[$impact_type] = ''; + $usage_tooltips[$impact_type] = ''; + if ($tooltip !== '') { + $embodied_tooltips[$impact_type] = Html::showToolTip($tooltip, [ + 'display' => false, + 'applyto' => 'embodied_' . $impact_type . '_tip', + ]); + $usage_tooltips[$impact_type] = Html::showToolTip($tooltip, [ + 'display' => false, + 'applyto' => 'usage_' . $impact_type . '_tip', + ]); + } + $embodied_labels[$impact_type] = Type::getEmbodiedImpactLabel($impact_type); + $usage_labels[$impact_type] = Type::getUsageImpactLabel($impact_type); + } $usage_imapct_action_url = $CFG_GLPI['root_doc'] . '/plugins/carbon/front/usageimpact.form.php'; $embodied_impact_action_url = $CFG_GLPI['root_doc'] . '/plugins/carbon/front/embodiedimpact.form.php'; @@ -250,11 +253,11 @@ public static function showCharts(CommonDBTM $asset) 'usage_carbon_emission_count' => $usage_carbon_emission_count, 'embodied_impact' => $embodied_impact, 'usage_impact' => $usage_impact, + 'embodied_labels' => $embodied_labels, + 'usage_labels' => $usage_labels, + 'embodied_tooltips' => $embodied_tooltips, + 'usage_tooltips' => $usage_tooltips, 'usage_carbon_emission_graph' => Widget::DisplayGraphUsageCarbonEmissionPerMonth($data), - 'carbon_emission_tooltip_html' => $carbon_emission_tooltip_html, - 'usage_abiotic_depletion_tooltip_html' => $usage_abiotic_depletion_tooltip_html, - 'embodied_abiotic_depletion_tooltip_html' => $embodied_abiotic_depletion_tooltip_html, - 'embodied_primary_energy_tooltip_html' => $embodied_primary_energy_tooltip_html, 'usage_impact_action_url' => $usage_imapct_action_url, 'embodied_impact_action_url' => $embodied_impact_action_url, ]); diff --git a/templates/dashboard/embodied-carbon-emission.html.twig b/templates/dashboard/embodied-carbon-emission.html.twig deleted file mode 100644 index e530f997..00000000 --- a/templates/dashboard/embodied-carbon-emission.html.twig +++ /dev/null @@ -1,102 +0,0 @@ -{# - # ------------------------------------------------------------------------- - # Carbon plugin for GLPI - # - # @copyright Copyright (C) 2024-2025 Teclib' and contributors. - # @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+ - # @license MIT https://opensource.org/licenses/mit-license.php - # @link https://github.com/pluginsGLPI/carbon - # - # ------------------------------------------------------------------------- - # - # LICENSE - # - # This file is part of Carbon plugin for GLPI. - # - # This program is free software: you can redistribute it and/or modify - # it under the terms of the GNU General Public License as published by - # the Free Software Foundation, either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # GNU General Public License for more details. - # - # You should have received a copy of the GNU General Public License - # along with this program. If not, see . - # - # ------------------------------------------------------------------------- - #} - - -
-
-
-
- - {{ source('@carbon/dashboard/icon-carbon-emission.svg') }} - -
-
-
{{ __('Embodied carbon emission', 'carbon') }}
-
-
{{ number|raw }}
-
- - - -
-
-
-
- -{{ tooltip_html|raw }} diff --git a/templates/dashboard/embodied-primary-energy.html.twig b/templates/dashboard/embodied-primary-energy.html.twig deleted file mode 100644 index cf201e70..00000000 --- a/templates/dashboard/embodied-primary-energy.html.twig +++ /dev/null @@ -1,102 +0,0 @@ -{# - # ------------------------------------------------------------------------- - # Carbon plugin for GLPI - # - # @copyright Copyright (C) 2024-2025 Teclib' and contributors. - # @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+ - # @license MIT https://opensource.org/licenses/mit-license.php - # @link https://github.com/pluginsGLPI/carbon - # - # ------------------------------------------------------------------------- - # - # LICENSE - # - # This file is part of Carbon plugin for GLPI. - # - # This program is free software: you can redistribute it and/or modify - # it under the terms of the GNU General Public License as published by - # the Free Software Foundation, either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # GNU General Public License for more details. - # - # You should have received a copy of the GNU General Public License - # along with this program. If not, see . - # - # ------------------------------------------------------------------------- - #} - - -
-
-
-
- - {{ source('@carbon/dashboard/icon-fossil-primary-energy.svg') }} - -
-
-
{{ __('Embodied primary energy', 'carbon') }}
-
-
{{ number|raw }}
-
- - - -
-
-
-
- -{{ tooltip_html|raw }} diff --git a/templates/dashboard/embodied-abiotic-depletion.html.twig b/templates/dashboard/impact-criteria.html.twig similarity index 85% rename from templates/dashboard/embodied-abiotic-depletion.html.twig rename to templates/dashboard/impact-criteria.html.twig index 71201be5..a9672f65 100644 --- a/templates/dashboard/embodied-abiotic-depletion.html.twig +++ b/templates/dashboard/impact-criteria.html.twig @@ -74,11 +74,13 @@
- {{ source('@carbon/dashboard/icon-pickaxe.svg') }} + {% if pictogram_file != '' %} + {{ source('@carbon/dashboard/' ~ pictogram_file) }} + {% endif %}
-
{{ __('Embodied abiotic depletion potential', 'carbon') }}
+
{{ label }}
{{ number|raw }}
@@ -90,13 +92,13 @@
{{ tooltip_html|raw }} diff --git a/templates/dashboard/usage-abiotic-depletion.html.twig b/templates/dashboard/usage-abiotic-depletion.html.twig deleted file mode 100644 index ec47aa10..00000000 --- a/templates/dashboard/usage-abiotic-depletion.html.twig +++ /dev/null @@ -1,102 +0,0 @@ -{# - # ------------------------------------------------------------------------- - # Carbon plugin for GLPI - # - # @copyright Copyright (C) 2024-2025 Teclib' and contributors. - # @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+ - # @license MIT https://opensource.org/licenses/mit-license.php - # @link https://github.com/pluginsGLPI/carbon - # - # ------------------------------------------------------------------------- - # - # LICENSE - # - # This file is part of Carbon plugin for GLPI. - # - # This program is free software: you can redistribute it and/or modify - # it under the terms of the GNU General Public License as published by - # the Free Software Foundation, either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # GNU General Public License for more details. - # - # You should have received a copy of the GNU General Public License - # along with this program. If not, see . - # - # ------------------------------------------------------------------------- - #} - - -
-
-
-
- - {{ source('@carbon/dashboard/icon-pickaxe.svg') }} - -
-
-
{{ __('Usage abiotic depletion potential', 'carbon') }}
-
-
{{ number|raw }}
-
- - - -
-
-
-
- -{{ tooltip_html|raw }} diff --git a/templates/environmentalimpact-item.html.twig b/templates/environmentalimpact-item.html.twig index f5f9fd01..b4f31b31 100644 --- a/templates/environmentalimpact-item.html.twig +++ b/templates/environmentalimpact-item.html.twig @@ -37,24 +37,30 @@ ) }} {{ usage_carbon_emission_graph|raw }} -
+
+
+
+
+ {% for criteria, label in usage_labels %} + {% if usage_impact.fields[criteria] ?? null is not null %} +
+ {{ label }} +
+
+ + {{ usage_impact.getHumanReadableImpact(criteria)|raw }} + {# #} + + {{ usage_tooltips[criteria]|raw }} +
+ {% endif %} + {% endfor %} +
+
+
{% if usage_impact.fields.gwp ?? null is not null %}
{{ usage_impact.getHumanReadableImpact('gwp')|raw }}
{% endif %} - - {% if usage_impact.fields.adp ?? null is not null %} -
- - {{ usage_impact.getHumanReadableImpact('adp')|raw }} - {# #} - - {{ usage_abiotic_depletion_tooltip_html|raw }} -
- {% endif %} - - {% if usage_impact.fields.pe ?? null is not null %} -
{{ usage_impact.getHumanReadableImpact('pe')|raw }}
- {% endif %}
@@ -71,37 +77,27 @@ 'fas fa-chart-pie' ) }} -
- {% if embodied_impact.fields.gwp ?? null is not null %} -
- - {{ embodied_impact.getHumanReadableImpact('gwp')|raw }} - {# #} - - {{ carbon_emission_tooltip_html|raw }} -
- {% endif %} - - {% if embodied_impact.fields.adp ?? null is not null %} -
- - {{ embodied_impact.getHumanReadableImpact('adp')|raw }} - {# #} - - {{ embodied_abiotic_depletion_tooltip_html|raw }} -
- {% endif %} - - {% if embodied_impact.fields.pe ?? null is not null %} -
- - {{ embodied_impact.getHumanReadableImpact('pe')|raw }} - {# #} - - {{ embodied_primary_energy_tooltip_html|raw }} +
+
+
+
+ {% for criteria, label in embodied_labels %} + {% if embodied_impact.fields[criteria] ?? null is not null %} +
+ {{ label }} +
+
+ + {{ embodied_impact.getHumanReadableImpact(criteria)|raw }} + {# #} + + {{ embodied_tooltips[criteria]|raw }} +
+ {% endif %} + {% endfor %} +
- {% endif %} - +
{% if not embodied_impact.isNewItem() %} {% set reset_args = "{_glpi_csrf_token: '" ~ csrf_token() ~ "', reset: '', id: '" ~ embodied_impact.getID() ~ "'}" %} diff --git a/tests/integration/SearchOptionTest.php b/tests/integration/SearchOptionTest.php index e8e979b9..6a45a523 100644 --- a/tests/integration/SearchOptionTest.php +++ b/tests/integration/SearchOptionTest.php @@ -81,6 +81,25 @@ class SearchOptionTest extends CommonTestCase 'gwp_quality', 'adp_quality', 'pe_quality', + 'gwppb_quality', + 'gwppf_quality', + 'gwpplu_quality', + 'ir_quality', + 'lu_quality', + 'odp_quality', + 'pm_quality', + 'pocp_quality', + 'wu_quality', + 'mips_quality', + 'adpe_quality', + 'adpf_quality', + 'ap_quality', + 'ctue_quality', + 'ctuh_c_quality', + 'ctuh_nc_quality', + 'epf_quality', + 'epm_quality', + 'ept_quality', ], Location::class => [], Zone::class => [ diff --git a/tests/src/Impact/Engine/AbstractEmbodiedImpactTest.php b/tests/src/Impact/Embodied/AbstractEmbodiedImpactTest.php similarity index 83% rename from tests/src/Impact/Engine/AbstractEmbodiedImpactTest.php rename to tests/src/Impact/Embodied/AbstractEmbodiedImpactTest.php index 1ca380aa..cda8aae2 100644 --- a/tests/src/Impact/Engine/AbstractEmbodiedImpactTest.php +++ b/tests/src/Impact/Embodied/AbstractEmbodiedImpactTest.php @@ -30,7 +30,7 @@ * ------------------------------------------------------------------------- */ -namespace GlpiPlugin\Carbon\Tests\Impact\Engine; +namespace GlpiPlugin\Carbon\Tests\Impact\Embodied; use DBmysql; use GlpiPlugin\Carbon\EmbodiedImpact; @@ -45,7 +45,7 @@ class AbstractEmbodiedImpactTest extends DbTestCase protected static string $itemtype_type = ''; protected static string $itemtype_model = ''; - public function testGetEvaluableItems() + public function testGetItemsToEvaluate() { if (static::$itemtype === '' || static::$itemtype_type === '' || static::$itemtype_model === '') { // Ensure that the inherited test class is properly implemented for this test @@ -65,7 +65,7 @@ public function testGetEvaluableItems() ]); $this->assertEquals(1, $iterator->count()); - // Test the asset is no longer evaluable when no embodied impact is in the DB + // Test the asset is no longer evaluable when there is embodied impact in the DB $glpi_asset_type = $this->createItem(static::$itemtype_type); $asset_type = $this->createItem('GlpiPlugin\\Carbon\\' . static::$itemtype_type, [ getForeignKeyFieldForItemType(static::$itemtype_type) => $glpi_asset_type->getID(), @@ -76,11 +76,30 @@ public function testGetEvaluableItems() $embodied_impact = $this->createItem(EmbodiedImpact::class, [ 'itemtype' => $asset->getType(), 'items_id' => $asset->getID(), + 'recalculate' => 0, ]); $iterator = AbstractEmbodiedImpact::getItemsToEvaluate(static::$itemtype, [ $asset::getTableField('id') => $asset->getID(), ]); $this->assertEquals(0, $iterator->count()); + + // Test the asset is evaluable when there is embodied impact in the DB but recamculate is set + $glpi_asset_type = $this->createItem(static::$itemtype_type); + $asset_type = $this->createItem('GlpiPlugin\\Carbon\\' . static::$itemtype_type, [ + getForeignKeyFieldForItemType(static::$itemtype_type) => $glpi_asset_type->getID(), + ]); + $asset = $this->createItem(static::$itemtype, [ + getForeignKeyFieldForItemType(static::$itemtype_type) => $glpi_asset_type->getID(), + ]); + $embodied_impact = $this->createItem(EmbodiedImpact::class, [ + 'itemtype' => $asset->getType(), + 'items_id' => $asset->getID(), + 'recalculate' => 1, + ]); + $iterator = AbstractEmbodiedImpact::getItemsToEvaluate(static::$itemtype, [ + $asset::getTableField('id') => $asset->getID(), + ]); + $this->assertEquals(1, $iterator->count()); } public function testGetEvaluableQuery() diff --git a/tests/uninstall/PluginUninstallTest.php b/tests/uninstall/PluginUninstallTest.php index ad99ad5c..241679c3 100644 --- a/tests/uninstall/PluginUninstallTest.php +++ b/tests/uninstall/PluginUninstallTest.php @@ -36,6 +36,7 @@ use CronTask; use DisplayPreference; use Glpi\Dashboard\Dashboard; +use Glpi\Dashboard\Dashboard_Item; use GlpiPlugin\Carbon\CarbonEmission; use GlpiPlugin\Carbon\CarbonIntensity; use GlpiPlugin\Carbon\Uninstall; @@ -75,7 +76,6 @@ public function testUninstallPlugin() $this->checkConfig(); // $this->checkRequestType(); $this->checkAutomaticAction(); - // $this->checkDashboard(); $this->checkRights(); $this->checkDisplayPrefs(); $this->checkDashboard(); diff --git a/tests/units/Impact/Embodied/Boavizta/ComputerTest.php b/tests/units/Impact/Embodied/Boavizta/ComputerTest.php index 292fc130..3d664042 100644 --- a/tests/units/Impact/Embodied/Boavizta/ComputerTest.php +++ b/tests/units/Impact/Embodied/Boavizta/ComputerTest.php @@ -30,15 +30,13 @@ * ------------------------------------------------------------------------- */ -namespace GlpiPlugin\Carbon\Impact\Engine\Boavizta\Tests; +namespace GlpiPlugin\Carbon\Impact\Embodied\Boavizta\Tests; use Computer as GlpiComputer; use ComputerType as GlpiComputerType; use ComputerModel as GlpiComputerModel; -use DBmysql; -use GlpiPlugin\Carbon\Impact\Embodied\AbstractEmbodiedImpact; use GlpiPlugin\Carbon\Impact\Embodied\Boavizta\Computer as BoaviztaComputer; -use GlpiPlugin\Carbon\Tests\Impact\Engine\AbstractEmbodiedImpactTest; +use GlpiPlugin\Carbon\Tests\Impact\Embodied\AbstractEmbodiedImpactTest; use PHPUnit\Framework\Attributes\CoversClass; #[CoversClass(BoaviztaComputer::class)] diff --git a/tests/units/Impact/Embodied/Boavizta/MonitorTest.php b/tests/units/Impact/Embodied/Boavizta/MonitorTest.php index 3fa1a550..c5101e5d 100644 --- a/tests/units/Impact/Embodied/Boavizta/MonitorTest.php +++ b/tests/units/Impact/Embodied/Boavizta/MonitorTest.php @@ -30,15 +30,13 @@ * ------------------------------------------------------------------------- */ -namespace GlpiPlugin\Carbon\Impact\Engine\Boavizta\Tests; +namespace GlpiPlugin\Carbon\Impact\Embodied\Boavizta\Tests; use Monitor as GlpiMonitor; use MonitorType as GlpiMonitorType; use MonitorModel as glpiMonitorModel; -use DBmysql; -use GlpiPlugin\Carbon\Impact\Embodied\AbstractEmbodiedImpact; use GlpiPlugin\Carbon\Impact\Embodied\Boavizta\Monitor as BoaviztaMonitor; -use GlpiPlugin\Carbon\Tests\Impact\Engine\AbstractEmbodiedImpactTest; +use GlpiPlugin\Carbon\Tests\Impact\Embodied\AbstractEmbodiedImpactTest; use PHPUnit\Framework\Attributes\CoversClass; #[CoversClass(BoaviztaMonitor::class)] diff --git a/tests/units/UsageInfoTest.php b/tests/units/UsageInfoTest.php index 90bbe459..cc905236 100644 --- a/tests/units/UsageInfoTest.php +++ b/tests/units/UsageInfoTest.php @@ -247,19 +247,19 @@ public function testShowcharts() private function testEmbodiedGwp(Crawler $crawler): bool { - $items = $crawler->filter('#plugin_carbon_embodied_impacts #embodied_carbon_emission_tip'); + $items = $crawler->filter('#plugin_carbon_embodied_impacts #embodied_gwp_tip'); return $items->count() === 1; } private function testEmbodiedAdp(Crawler $crawler): bool { - $items = $crawler->filter('#plugin_carbon_embodied_impacts #embodied_abiotic_depletion_tip'); + $items = $crawler->filter('#plugin_carbon_embodied_impacts #embodied_adp_tip'); return $items->count() === 1; } private function testEmbodiedPe(Crawler $crawler): bool { - $items = $crawler->filter('#plugin_carbon_embodied_impacts #embodied_primary_energy_tip'); + $items = $crawler->filter('#plugin_carbon_embodied_impacts #embodied_pe_tip'); return $items->count() === 1; } }