From 0ed158cdfff612801ae135ae62e7afaad767b6d5 Mon Sep 17 00:00:00 2001 From: Etienne Pallier Date: Tue, 28 Jul 2020 08:06:20 +0200 Subject: [PATCH] Page "Statistiques" améliorée (menu Outils, /pages/stats) (v3.7.9.76) --- CHANGES.txt | 8 +++++++- README.md | 4 ++-- src/Controller/MaterielsController.php | 11 ++++------- src/Controller/PagesController.php | 343 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------ src/Template/Emprunts/index.ctp | 17 ++++++++++++++--- src/Template/Pages/stats.ctp | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- 6 files changed, 373 insertions(+), 128 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index daf3ba6..0469cb3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -15,7 +15,7 @@ CHANGEMENTS ------- 25/07/2020 NEWS#2 : -- Nouvelle page "Statistiques" depuis le menu Outils : nombre de matériels créés, validés, archivés, en moyenne, au total, et par année +- Nouvelle page "Statistiques" depuis le menu Outils : nombre de matériels créés, validés, archivés, suivis, et prêtés (en moyenne, au total, et par année) - Améliorations de la page qui liste les matériels (/materiels/index) : => nouveaux filtres "age" et "domaine" pour afficher les matériels par domaine (informatique, électronique, ...) ou/et par tranche d'âge (par défaut "moins de 5 ans", mais aussi 5-10 ans, 10-15 ans...) @@ -77,6 +77,12 @@ Outre ces changements, voici d'autres changements importants : ======= CHANGES ======= ------- +28/07/2020 v3.7.9.76 (EP) + - Page "Statistiques" améliorée (menu Outils, /pages/stats) : + - nombre de matériels créés, validés, archivés, suivis, et prêtés (en moyenne, au total, et par année) + - choix du nb de matériels à lister + +------- 25/07/2020 v3.7.9.72-75 (EP) - Fiabilisation du nouveau script database/update/db-update.sh - Try-catch avant exécution grosses requetes sql (par exemple celle pour la vue index des materiels) diff --git a/README.md b/README.md index 6d40952..b77000c 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ Logiciel testé et validé sur les configurations suivantes : -------------------------------------------------------------------------------------------- -Date: 25/07/2020 -Version: 3.7.9.75 +Date: 28/07/2020 +Version: 3.7.9.76 HISTORIQUE DES CHANGEMENTS DE VERSION : voir le fichier CHANGES.txt (ou la page web /pages/changes) diff --git a/src/Controller/MaterielsController.php b/src/Controller/MaterielsController.php index 791179c..aab451d 100755 --- a/src/Controller/MaterielsController.php +++ b/src/Controller/MaterielsController.php @@ -766,26 +766,23 @@ class MaterielsController extends AppController { if ($GM !== null && $GM != TableRegistry::getTableLocator()->get('GroupesMetiers')->find() ->where([ 'nom =' => 'N/A' - ]) - ->first()['id']) + ])->first()['id']) $conditions = [ 'Materiels.groupes_metier_id =' => $GM, 'Materiels.status !=' => 'ARCHIVED' ]; //else if ($GT !== null && $GT != TableRegistry::get('GroupesThematiques')->find() - else if ($GT !== null && $GT != TableRegistry::getTableLocator()->get('GroupesThematiques')->find() + else if ($GT !== null && $GT != TableRegistry::getTableLocator()->get('GroupesThematiques')->find() ->where([ 'nom =' => 'N/A' ]) - ->first()['id']) + ->first()['id']) $conditions = [ 'Materiels.groupes_thematique_id =' => $GT, 'Materiels.status !=' => 'ARCHIVED' ]; else - $conditions = [ - 'Materiels.id =' => 0 - ]; + $conditions = [ 'Materiels.id =' => 0 ]; } $GMV = $this->request->getQuery('GMV'); diff --git a/src/Controller/PagesController.php b/src/Controller/PagesController.php index 0a617ca..653496d 100755 --- a/src/Controller/PagesController.php +++ b/src/Controller/PagesController.php @@ -295,104 +295,10 @@ class PagesController extends AppController $this->set(compact('lab_name')); } + // - Page des STATISTIQUES - if ($this->page=='stats') { - - // - Année en cours - $now = new \DateTime('now'); - //debug($now); - // 2020 en 2020 - $current_year = (int) $now->format('Y'); - - $materiels = TableRegistry::getTableLocator()->get('Materiels'); - //debug($all_matos->count()); //3967 + if ($this->page=='stats') $this->set_variables_for_page_stats(); - /* - $statuses = [ - 'CREATED' => 'created', - 'VALIDATED' => 'date_validated', - 'ARCHIVED' => 'date_archived' - ]; - */ - $statuses = [ 'CREATED', 'VALIDATED', 'TOBEARCHIVED', 'ARCHIVED' ]; - - // - Donées Totales - $tot = []; - /* - $tot['CREATED'] = 100; - $tot['VALIDATED'] = 70; - $tot['TOBEARCHIVED'] = 10; - $tot['ARCHIVED'] = 10; - */ - foreach ($statuses as $status) { - //TODO: optimiser, à ne faire qu'une seule fois, et non pas à chaque tour de boucle: - // Tous les matos qui ont une date d'achat non nulle - $all_matos = $materiels->find()->where(['year(date_acquisition) >' => 0]); - if ($status != 'CREATED') $all_matos->where(['status' => $status]); - $tot[$status] = $all_matos->count(); - } - - // - Donées Moyennes - $avg = []; - /* - $avg['CREATED'] = 10; - $avg['VALIDATED'] = 7; - $avg['TOBEARCHIVED'] = 1; - $avg['ARCHIVED'] = 1; - */ - foreach ($statuses as $status) { - //TODO: optimiser, à ne faire qu'une seule fois, et non pas à chaque tour de boucle: - // Tous les matos qui ont une date d'achat non nulle - //$all_matos = $materiels->find(); - $all_matos = $materiels->find()->where(['year(date_acquisition) >' => 0]); - //->groupBy('year(date_acquisition)'); - if ($status != 'CREATED') $all_matos->where(['status' => $status]); - $avg[$status] = $all_matos - //->groupBy('year(date_acquisition)'); - ->countBy(function($matos) { - return $matos->date_acquisition->format('Y'); - }) - //->toList(); - //->toArray(); - //->count(); - ->avg(); - $avg[$status] = round($avg[$status]); - } - //debug($avg); - - - // - Données par Année - $years = []; - //$year_min = $materiels->find()->min(['year(date_acquisition)']); - $matos_year_min = $materiels->find() - ->where(['year(date_acquisition) >' => 0]) - ->min(function($matos) { - return $matos->date_acquisition->format('Y'); - }); - //$year_min = 2009; - $year_min = (int) $matos_year_min->date_acquisition->format('Y'); - // TODO: Ajouter progression d'année en année (2020 = 2019 +/- 10%) - for ($y=$current_year ; $y>=$year_min ; $y--) { - //debug($y); - try { - foreach ($statuses as $status) { - //TODO: optimiser, à ne faire qu'une seule fois, et non pas à chaque tour de boucle: - $all_matos_for_year = $materiels - ->find() - ->where(['year(date_acquisition)' => $y]); - if ($status != 'CREATED') $all_matos_for_year->where(['status' => $status]); - $years[$y][$status] = $all_matos_for_year->count(); - } - } catch (\PDOException $e) { - debug("Mauvais format de requete SQL (PagesController), Exception PDO générée !"); - exit; - } - } - //debug($years); - - // Set all variables pour la vue - $this->set(compact('current_year', 'year_min', 'years', 'tot', 'avg')); - } // - Page des OUTILS if ($this->page=='tools') { @@ -415,5 +321,250 @@ class PagesController extends AppController } } // display() + + + + private function set_variables_for_page_stats() { + + // Nb années demandées par l'utilisateur + $nbyears = $this->request->getQuery('nbyears'); + // Par défaut $nbyears = 1 + $nbyears = (is_numeric($nbyears) && $nbyears>0) ? abs(round($nbyears)) : 1; + //debug($nbyears); + + $materiels = TableRegistry::getTableLocator()->get('Materiels'); + $suivis = TableRegistry::getTableLocator()->get('Suivis'); + $prets = TableRegistry::getTableLocator()->get('Emprunts'); + $associated_entities = ['suivis','prets']; + $fk = 'materiel_id'; + + // Tous les matos qui ont une date d'achat non nulle + $all_matos = $materiels->find()->where(['year(date_acquisition) >' => 0]); + + // - Année en cours + $now = new \DateTime('now'); + //debug($now); + // 2020 en 2020 + $current_year = (int) $now->format('Y'); + + // - Année min + //$year_min = $materiels->find()->min(['year(date_acquisition)']); + //$matos_year_min = $materiels->find()->where(['year(date_acquisition) >' => 0]) + $matos_year_min = $all_matos->cleanCopy() + ->min(function($matos) { + return $matos->date_acquisition->format('Y'); + }); + $year_min = (int) $matos_year_min->date_acquisition->format('Y'); + + // - Nb années au total : au moins 1 + $nbyears_max = $current_year - $year_min + 1; + + // - Nb annnées à traiter (entre 1 et $nbyears_max) + // ($nbyears=null si pas passé en paramètre) + // ($nbyears='' si passé en paramètre mais sans valeur '?nbyears=') + //$nbyears = $nbyears ? abs((int)$nbyears) : $nbyears_max; + //debug($nbyears); + $nbyears = min($nbyears,$nbyears_max); + //debug($nbyears); + //debug($nbyears); + // Si on est au max (avec max>2), on enlève la 1ère et la dernière années (car a priori incomplètes) + //sif ($nbyears==$nbyears_max && $nbyears>2) $nbyears -= 2; + // Nouvelle année min + $year_min = $current_year-$nbyears + 1; + + // Nouveau $all_matos, en tronquant à $nbyears + $all_matos = $materiels->find() + ->where(['year(date_acquisition) <=' => $current_year]) + ->where(['year(date_acquisition) >=' => $year_min]); + $all_matos_ids = $all_matos->cleanCopy()->select(['id']); + + /* + $statuses = [ + 'CREATED' => 'created', + 'VALIDATED' => 'date_validated', + 'ARCHIVED' => 'date_archived' + ]; + */ + $statuses = [ 'CREATED', 'VALIDATED', 'TOBEARCHIVED', 'ARCHIVED' ]; + + // - tot : Données Totales (complètes) (tronquées à $nbyears) + $tot = []; + foreach ($statuses as $status) { + $all_matos_copy = $all_matos->cleanCopy(); + // Tous les matos qui ont une date d'achat non nulle + if ($status != 'CREATED') $all_matos_copy->where(['status' => $status]); + $tot[$status] = $all_matos_copy->count(); + } + // Suivis et Prets + // Nb materiels qui ont des suivis (i.e. qui ont au moins 1 suivi) + foreach ($associated_entities as $e) { + //$nb_matos_suivis = $suivis->find() + $tot[$e] = $$e->find() + // materiel_id not null + ->where(["$fk >" => 0]) + ->select([$fk]) + ->distinct([$fk]) + ->where(["$fk IN" => $all_matos_ids]) + ->count(); + } + + /* + // - tot2 : Données Totales Partielles (= tot sauf 1ère et dernière années) + $all_matos2 = $materiels + ->find() + ->where(['year(date_acquisition) <' => $current_year]) + ->where(['year(date_acquisition) >' => $current_year-$nbyears]); + $all_matos_ids2 = $all_matos2->cleanCopy()->select(['id']); + + $tot2 = []; + foreach ($statuses as $status) { + $all_matos_copy = $all_matos2->cleanCopy(); + // Tous les matos qui ont une date d'achat non nulle + if ($status != 'CREATED') $all_matos_copy->where(['status' => $status]); + $tot2[$status] = $all_matos_copy->count(); + } + // Suivis et Prets + // Nb materiels qui sont suivis (i.e. qui ont au moins 1 suivi) + foreach ($associated_entities as $e) { + //$nb_matos_suivis = $suivis->find() + $tot2[$e] = $$e->find() + // materiel_id not null + ->where(["$fk >" => 0]) + ->select([$fk]) + ->distinct([$fk]) + ->where(["$fk IN" => $all_matos_ids2]) + ->count(); + } + */ + + // - Donées Moyennes + $avg = []; + /* + $avg['CREATED'] = 10; + $avg['VALIDATED'] = 7; + $avg['TOBEARCHIVED'] = 1; + $avg['ARCHIVED'] = 1; + */ + foreach ($statuses as $status) { + $avg[$status] = round($tot[$status]/$nbyears, 1); + /* + * (EP) + * J'obtiens pas le meme resultat avec cette methode... + * Peut-être que ca compte pas les années où il n'y a rien (0) + */ + /* + //$all_matos = $materiels->find(); + //$all_matos = $materiels->find()->where(['year(date_acquisition) >' => 0]); + //->groupBy('year(date_acquisition)'); + $all_matos_copy = $all_matos->cleanCopy(); + if ($status != 'CREATED') $all_matos_copy->where(['status' => $status]); + $avg[$status] = $all_matos_copy + //->groupBy('year(date_acquisition)'); + ->countBy(function($matos) { + return $matos->date_acquisition->format('Y'); + }) + ->avg(); + //->toList(); + //->toArray(); + //->count(); + $avg[$status] = round($avg[$status]); + */ + } + // Suivis et Prets + // Nb materiels qui sont suivis (i.e. qui ont au moins 1 suivi) + foreach ($associated_entities as $e) { + $avg[$e] = round($tot[$e]/$nbyears, 1); + /* + $nb_matos_having_entity = $$e->find() + // materiel_id not null + ->where(["$fk >" => 0]) + ->select([ + 'year' => 'YEAR(created)' + ]) + ->group('year') + ->toArray(); + + //->groupBy(function($entity) { + ->group(function($entity) { + return $entity->created->format('Y'); + }) + ->distinct([$fk]) + ->count() + ->avg(); + $avg[$e] = $nb_matos_having_entity; + */ + //debug($nb_matos_having_entity); + } + + + // - Données par Année + $years = []; + $all_matos = $materiels->find(); + for ($y=$current_year ; $y>=$year_min ; $y--) { + //debug($y); + $all_matos_for_year = $all_matos->cleanCopy()->where(['year(date_acquisition)' => $y]); + // - statut par année + try { + foreach ($statuses as $status) { + /* + $all_matos_for_year = $materiels->find(); + ->where(['year(date_acquisition)' => $y]); + $all_matos_for_year = $all_matos->cleanCopy()->where(['year(date_acquisition)' => $y]); + */ + $all_matos_for_year_and_status = $all_matos_for_year->cleanCopy(); + if ($status != 'CREATED') $all_matos_for_year_and_status->where(['status' => $status]); + $years[$y][$status] = $all_matos_for_year_and_status->count(); + } + } catch (\PDOException $e) { + debug("Mauvais format de requete SQL (PagesController suivis), Exception PDO générée !"); + exit; + } + // Suivis et Prets, par année + $all_matos_suivis_for_year = $all_matos_for_year->cleanCopy(); + foreach ($associated_entities as $e) + try { + /* + * SQL equivalent : à tester... + * + * SELECT COUNT(DISTINCT(suivis.materiel_id)) FROM suivis LEFT JOIN materiels + * ON suivis.materiel_id = materiels.id + * WHERE YEAR(materiels.date_acquisition) = $y + */ + //$years[$y]['suivis'] = $suivis + $years[$y][$e] = $$e + // Tous les suivis/emprunts... + ->find() + // ... et leur materiel associé... + ->leftJoinWith('Materiels') + // ... LEFT JOIN ON (suivis.materiel_id = materiels.id) ... // ou emprunts.materiel_id + //->enableAutoFields(true) + // ... (uniquement les materiels de l'année $y) ... + ->where(['year(date_acquisition)' => $y]) + // ... en ne gardant qu'1 seul suivi/emprunt par materiel (meme si ce materiel en a plusieurs) ... + ->distinct(['materiel_id']) + // ... et enfin, on compte le nombre de suivis/emprunts (total pour l'année $y) + ->count(); + //->toArray(); + //$all_matos_for_year + //->contain(['Suivis']) + //->select(['id', 'count_suivis => count(suivis)']) + //->where(['count_suivis >' => 0]) + //->count(); + } catch (\PDOException $e) { + debug("Mauvais format de requete SQL (PagesController prets), Exception PDO générée !"); + exit; + } + //debug($years[$y]['suivis']); + //$years[$y]['suivis'] = 3; + //$years[$y]['prets'] = 4; + } // foreach year + //debug($years); + + // Set all variables pour la vue + //$this->set(compact('current_year', 'year_min', 'tot', 'avg', 'years', 'suivis', 'prets')); + //$this->set(compact('current_year', 'year_min', 'nbyears', 'tot', 'tot2', 'avg', 'years')); + $this->set(compact('current_year', 'year_min', 'nbyears', 'tot', 'avg', 'years')); + + } // set_variables_for_page_stats() } diff --git a/src/Template/Emprunts/index.ctp b/src/Template/Emprunts/index.ctp index acd754a..b27a825 100755 --- a/src/Template/Emprunts/index.ctp +++ b/src/Template/Emprunts/index.ctp @@ -8,7 +8,9 @@ Paginator->sort('id', 'N°') ?> Paginator->sort('materiel_id', 'Matériel') ?> - Paginator->sort('numero_laboratoire', 'N° interne (labo)') ?> + Paginator->sort('emprunt_interne', 'Type') ?> Paginator->sort('date_emprunt' ,'Date emprunt') ?> Paginator->sort('date_retour_emprunt', 'Date retour') ?> @@ -30,12 +32,21 @@ Html->link('Emprunt '.$this->Number->format($emprunt->id), ['action' => 'view', $emprunt->id])?> has('materiel') ? $this->Html->link($emprunt->materiel->designation, ['controller' => 'Materiels', 'action' => 'view', $emprunt->materiel->id]) : '' ?> - has('materiel') ? h($emprunt->materiel->numero_laboratoire) : '' ?> + emprunt_interne) == '1') { echo 'Interne'; } else { echo 'Externe'; } ?> date_emprunt) ?> date_retour_emprunt) ?> nom_emprunteur) ?> - emprunt_interne) == '1') { echo h($emprunt->site->nom).' - '.h($emprunt->e_lieu_detail); } else { echo h($emprunt->laboratoire); } ?> + + emprunt_interne) == '1') + echo h($emprunt->site->nom).' - '.h($emprunt->e_lieu_detail); + else + echo h($emprunt->laboratoire); + ?> + diff --git a/src/Template/Pages/stats.ctp b/src/Template/Pages/stats.ctp index 1d03096..c123768 100644 --- a/src/Template/Pages/stats.ctp +++ b/src/Template/Pages/stats.ctp @@ -20,23 +20,45 @@ for ($y=$year ; $y>$year-5 ; $y--) { $years[$y]['validated'] = 8; $years[$y]['archived'] = 8; } + +$suivis = []; +$prets = []; +$suivis['tot'] = 100; +$suivis['avg'] = 10; +for ($y=$current_year ; $y>=$year_min ; $y--) $suivis[$y] = 8; +$prets = $suivis; */ + + // Parameters passed by controller $current_year = $current_year; -$years = $years; +$year_min = $year_min; +$nbyears = $nbyears; $avg = $avg; $tot = $tot; +//$tot2 = $tot2; +$years = $years; +//debug($suivis); -function echoAsBold($elem, $bold) { - if ($bold) echo ''; - echo $elem; - if ($bold) echo ''; +function echoAsPctAndBold($nbelem, $total=null, $is_bold=false) { + if ($is_bold) echo ''; + if ($total !== null) { + $pct = round( ($nbelem / $total) * 100 , 1 ); + $nbelem = "$pct% ($nbelem)"; + //$nbelem = "$nbelem ($pct%)"; + //$nbelem = "$pct%"; + } + echo $nbelem; + if ($is_bold) echo ''; } -function displayStatsLine($title, $line, $bold=false, $year_prev=null, $avg=null) { + + +//function displayStatsLine($title, $line, $suivis, $prets, $bold=false, $year_prev=null, $avg=null) { +function displayStatsLine($title, $line, $is_bold=false, $year_prev=null, $avg=null) { ?> @@ -63,22 +85,25 @@ function displayStatsLine($title, $line, $bold=false, $year_prev=null, $avg=null - + - - + - - - + + + - + + + + + + + STATISTIQUES SUR LES MATÉRIELS +

+ + + + + + +
Prendre en compte les +Form->create('Statistiques', [ + 'type' => 'get', + ]); + //echo ''; + echo $this->Form->control('nbyears', [ + 'id' => 'nby', + //'class' => 'search-input', + 'label' => '', + //'type' => 'text', + 'default' => $nbyears + ]); + /* + echo $this->Form->submit('Chercher', [ + 'name' => 'MaterielSAll', + 'id' => 'MaterielSAll', + 'style' => 'margin: 0px;' + ]); + */ + echo $this->Form->end(); +?> +dernières années ()
+

+ @@ -118,9 +175,12 @@ function displayStatsLine($title, $line, $bold=false, $year_prev=null, $avg=null + + --> + @@ -134,8 +194,13 @@ function displayStatsLine($title, $line, $bold=false, $year_prev=null, $avg=null --> + + + + + @@ -143,16 +208,27 @@ function displayStatsLine($title, $line, $bold=false, $year_prev=null, $avg=null - + + + + + + @@ -163,6 +239,8 @@ function displayStatsLine($title, $line, $bold=false, $year_prev=null, $avg=null + + @@ -181,7 +259,9 @@ function displayStatsLine($title, $line, $bold=false, $year_prev=null, $avg=null $year_prev = $y==$year_min ? null : $years[$y-1]; displayStatsLine($year_title, $val, false, $year_prev, $avg); } + ?> +
Validés En demande d'archivage ArchivésMatériels suivisMatériels empruntés
Matériels acquis Suivis et Emprunts
Evol. \ N-1Total ValidésEn demande d'archivageA archiver ArchivésMatériels suivisMatériels prêtés
-- libgit2 0.21.2