Commit 8c519d1fa5c3f01494af74cce301f5270cdae340

Authored by Etienne Pallier
1 parent f0576366
Exists in master and in 1 other branch dev

Modif champs obligatoires pour IP2I et harmonisation des libelles (intitulé, status)

CHANGELOG
... ... @@ -12,6 +12,12 @@ CHANGEMENTS
12 12 ======= NEWS =======
13 13  
14 14 -------
  15 +31/03/2021 NEWS#6 (v4.108.18) :
  16 +
  17 +- Installation du logiciel désormais disponible via DOCKER (en quelques petites minutes)
  18 +
  19 +
  20 +-------
15 21 FÉVRIER 2021 (v4.108.0-3.7.9) - GROSSE AMÉLIORATION DE LA PHASE INSTALLATION (FROM SCRATCH) :
16 22  
17 23 - Documentation en ligne (install et technique) grandement mise à jour, pour une progression plus logique
... ... @@ -31,12 +37,6 @@ ROADMAP IRAP :
31 37  
32 38  
33 39 -------
34   -31/03/2021 NEWS#6 (v4.108.18) :
35   -
36   -- Installation du logiciel désormais disponible via DOCKER (en quelques petites minutes)
37   -
38   -
39   --------
40 40 30/11/2020 NEWS#5 (v4.107.21) :
41 41  
42 42 - Liste des matériels beaucoup plus pratique (colonnes plus pertinentes) et filtrage plus efficace
... ... @@ -331,6 +331,13 @@ Commencer à implémenter le nouveau workflow v5 :
331 331 ======= CHANGES =======
332 332  
333 333 -------
  334 +31/08/2021 v4.108.22-3.7.9
  335 + - Gestion spécifique des champs obligatoires selon le labo (pour l'instant on ne gère qu'une exception pour IP2I)
  336 + - Harmonisation des libellés :
  337 + - "intitulé" pour prêts et suivis
  338 + - "statut" des matériels
  339 +
  340 +-------
334 341 31/05/2021 v4.108.21-3.7.9
335 342 - Ajout asterisque sur nouveaux champs obligatoires pour LOT1 : description, organisme, budgets
336 343 - (Refactorisation des LOT1 et LOT2 dans MaterielsTable, plus de redondance)
... ...
README.md
... ... @@ -52,8 +52,8 @@ Logiciel testé et validé sur les configurations suivantes :
52 52  
53 53 --------------------------------------------------------------------------------------------
54 54  
55   -Date: 31/05/2021
56   -Version: v4.108.21-3.7.9
  55 +Date: 31/08/2021
  56 +Version: v4.108.22-3.7.9
57 57  
58 58  
59 59  
... ...
config/bootstrap.php
... ... @@ -85,6 +85,11 @@ use Cake\Utility\Security;
85 85 try {
86 86 Configure::config('default', new PhpConfig());
87 87 Configure::load('app', 'default', false);
  88 + /* IP2I
  89 + // (EP 2021 08 Ajout nouveaux fichiers config pour les champs obligatoires et les autorisations)
  90 + Configure::load('app_labinvent_mandatory_fields', 'default');
  91 + Configure::load('app_labinvent_authorizations', 'default');
  92 + */
88 93 } catch (\Exception $e) {
89 94 exit($e->getMessage() . "\n");
90 95 }
... ...
install/installation.macos.temp.sh deleted
... ... @@ -1,492 +0,0 @@
1   -#!/bin/bash
2   -
3   -#
4   -# ------------ A - SETUP ------------
5   -#
6   -
7   -# Le script peut-il continuer et créer les fichiers qui lui sont nécessaires ?
8   -access_path=`dirname $0`
9   -if [ -r "$access_path" ]; then
10   - if [ -w "$access_path" ]; then
11   - if [ -x "$access_path" ]; then
12   - echo "Vous avez les droits suffisants sur ce repertoire pour exécuter ce script"
13   - else
14   - echo "Veuillez relancer le script en root"
15   - exit 1
16   - fi
17   - else
18   - echo "Veuillez relancer le script en root"
19   - exit 1
20   - fi
21   -else
22   - echo "Veuillez relancer le script en root"
23   - exit 1
24   -fi
25   -
26   -# Git ne doit pas tenir compte des changements de permission sur les fichiers (style "chmod +x" ou "chmod -R"...)
27   -# Ca signifie qu'un changement de permission sur un fichier n'est pas vu par git (et donc pas commité)
28   -git config core.fileMode false
29   -
30   -# Pour Mac OS recent (10.10, Yosemite), la syntaxe du SED est differente
31   -# Il faut donc faire une copie de ce fichier et transformer les instructions sed a l'interieur
32   -# Pour cela, il suffit d'executer ces 2 lignes :
33   -# cp installation.sh installation_macosx.sh
34   -# sed -e "s/ -i '' / -i '' /" -i '' installation_macosx.sh
35   -
36   -if [ ! -f ./installation.sh ] ; then
37   - echo "Vous devez executer ce script depuis le dossier install/"
38   - exit 1
39   -fi
40   -
41   -# Pour pouvoir ajouter les donnees IRAP (categories...) pendant l'installation, mettre à 1
42   -INSTALL_DATA_IRAP=1
43   -
44   -# Revenir a la racine du projet (car on est dans le repertoire install/) :
45   -#cd ../
46   -#if [ $0 != "install/installation.sh" ] ; then
47   -# cd ../
48   -#fi
49   -
50   -
51   -#Configurer l'application
52   -# Donner le nom du groupe webService
53   -echo
54   -echo "LabInvent Copyright (C) 2012-2020 IRAP (Toulouse - France)"
55   -echo "Auteurs : Etienne Pallier <etienne.pallier@irap.omp.eu>, Elodie Bourrec <elodie.bourrec@irap.omp.eu>"
56   -echo "Licence GPL (http://www.gnu.org/copyleft/gpl.html)"
57   -echo "Ce logiciel est mis a disposition tel quel, SANS AUCUNE GARANTIE."
58   -echo "C'est un logiciel libre, et vous pouvez le redistribuer sous certaines conditions."
59   -echo "Il est construit sur le framework Php open source CakePhp (v3, http://cakephp.org) avec le langage Php v7"
60   -echo
61   -
62   -echo "Votre serveur Mysql doit etre demarre (ainsi que votre serveur web)"
63   -echo "Si c'est bien le cas, appuyez sur une touche pour continuer..."
64   -read
65   -
66   -echo "La commande 'mysql' doit aussi etre accessible:"
67   -res=`which mysql`
68   -[[ -z "$res" ]] && exit 1
69   -echo "ok"
70   -echo
71   -
72   -while : ; do
73   - echo "Donner le nom du GROUPE du serveur web (ex: apache (centOs), www-data (Ubuntu), _www (MacOS avec Apache), daemon (MacOS avec XAMPP), nobody (MacOS), admin, ...)"
74   - read grp
75   - [[ -n "$grp" ]] && break
76   -done
77   -echo "==> groupe = $grp"
78   -echo
79   -
80   -echo "Vous devez avoir les droits administrateur (via sudo) pour executer les commandes suivantes"
81   -echo "Appuyez sur une touche pour continuer..."
82   -read
83   -
84   -
85   -
86   -#
87   -# ------------ B - PLUGINS ------------
88   -#
89   -
90   -# Installation des plugins dans vendor/ (cakephp, phpunit, phpqrcode, fpdf, ...)
91   -echo "Installation des plugins dans vendor/ ..."
92   -#cd install/
93   -chmod +x plugins_set.sh
94   -chmod +x plugins_install.sh
95   -./plugins_install.sh
96   -#cd ../
97   -
98   -
99   -# Revenir a la racine du projet (car on est dans le repertoire install/) :
100   -cd ../
101   -
102   -
103   -
104   -#
105   -# ------------ C - DOSSIERS LOCAUX DE TRAVAIL (./logs, ./tmp, ./webroot) ------------
106   -#
107   -
108   -
109   -# - 1) Creation des dossiers temporaires (tmp, logs, webroot)
110   -
111   -echo "Création des dossiers temporaires..."
112   -if [ ! -d "./logs" ]; then
113   - mkdir ./logs/
114   -fi
115   -if [ ! -f "./logs/error.log" ]; then
116   - touch ./logs/error.log
117   -fi
118   -if [ ! -f "./logs/cli-error.log" ]; then
119   - touch ./logs/cli-error.log
120   -fi
121   -
122   -if [ ! -d "./tmp" ]; then
123   - mkdir ./tmp/
124   -fi
125   -if [ ! -d "./tmp/bake" ]; then
126   - mkdir ./tmp/bake/
127   -fi
128   -if [ ! -d "./tmp/cache" ]; then
129   - mkdir ./tmp/cache/
130   -fi
131   -if [ ! -d "./tmp/cache/models" ]; then
132   - mkdir ./tmp/cache/models/
133   -fi
134   -if [ ! -d "./tmp/cache/persistent" ]; then
135   - mkdir ./tmp/cache/persistent/
136   -fi
137   -if [ ! -d "./tmp/cache/views" ]; then
138   - mkdir ./tmp/cache/views/
139   -fi
140   -if [ ! -d "./tmp/documents" ]; then
141   - mkdir ./tmp/documents/
142   -fi
143   -if [ ! -d "./tmp/sessions" ]; then
144   - mkdir ./tmp/sessions/
145   -fi
146   -if [ ! -d "./tmp/tests" ]; then
147   - mkdir ./tmp/tests/
148   -fi
149   -if [ ! -d "./webroot/img/qrcodes" ]; then
150   - # Normalement webroot/img/ existe déjà mais on ne sait jamais (donc -p)
151   - mkdir -p ./webroot/img/qrcodes
152   -fi
153   -
154   -# (EP 11/6/19) Pour pouvoir upload des photos (doc attaché)
155   -folder=./webroot/img/photos
156   -if [ ! -d "$folder" ]; then
157   - mkdir $folder
158   -fi
159   -# Inutile car fait un peu plus loin
160   -#chmod 777 $folder
161   -
162   -# (EP 24/5/19) Pour pouvoir upload des docs attachés
163   -# Question: A quoi sert tmp/documents/ ci-dessus ? On peut le virer ?
164   -folder=./webroot/files
165   -if [ ! -d "$folder" ]; then
166   - mkdir $folder
167   -fi
168   -chmod 777 $folder
169   -
170   -# (EP) Est-ce vraiment utile ?
171   -#if [ ! -d "./vendor/phpunit" ]; then
172   - #./composer.phar require --dev phpunit/phpunit
173   -#else
174   - #./composer.phar remove phpunit/phpunit
175   - #./composer.phar require --dev phpunit/phpunit
176   -#fi
177   -
178   -echo "==>Done"
179   -
180   -
181   -# - 2) Mise à jour des droits d'accès sur ces dossiers temporaires
182   -
183   -echo "Mise à jour des droits des dossiers..."
184   -echo "(Please enter your sudoer password)"
185   -
186   -# - a) POUR LES QRCODES
187   -# Ajouter les droits en ecriture pour la creation des qrcodes
188   -# phpqrcode write its errors into its folder ...
189   -sudo chmod -R 775 ./vendor/aferrandini/phpqrcode/
190   -touch ./vendor/aferrandini/phpqrcode/errors.txt
191   -chmod 775 ./vendor/aferrandini/phpqrcode/errors.txt
192   -sudo chgrp -R $grp ./vendor/aferrandini/phpqrcode/
193   -[[ $? -ne 0 ]] && echo "Vous devez avoir le droit de faire un 'sudo' sinon executer ce script en tant que root" && exit 1
194   -
195   -##sudo chmod -R 775 ./webroot/img/
196   -# TODO: ca serait mieux d'eviter ca ;
197   -# Normalement, il faudrait ecrire dans app/tmp et pas dans app/webroot
198   -# EP 2014/12/11 chmod 775 ne suffit pas
199   -#chmod -R 775 ./webroot/img/
200   -#sudo chmod -R 770 ./webroot/img/
201   -sudo chmod -R 777 ./webroot/img/
202   -#sudo chown -R $grp:$grp ./webroot/img/
203   -sudo chgrp -R $grp ./webroot/img/
204   -# TODO: il faudrait plutot faire ceci :
205   -#sudo chown -R $webServerLogin:$webServerGroup ./webroot/img/
206   -#chmod -R 775 ./webroot/img/
207   -
208   -# - b) POUR LES DOCUMENTS
209   -# Ajoute les droits en ecriture pour la generation des documents
210   -dir="./tmp/documents/generator/"
211   -if [ ! -d "$dir" ]; then
212   - mkdir ./tmp/documents/generator/
213   -fi
214   -##sudo chmod -R 775 ./tmp/documents/
215   -#chmod -R 775 ./tmp/documents/
216   -
217   -# - c) POUR CAKEPHP (seule modif demandee par le framework)
218   -# Les dossiers ./tmp et ./logs doivent être modifiable par le serveur web :
219   -#chmod -R 775 ./tmp/
220   -sudo chmod -R 777 ./tmp/cache/
221   -chmod -R 777 ./tmp/
222   -sudo chgrp -R $grp ./tmp/
223   -chmod -R 777 ./logs/
224   -sudo chgrp -R $grp ./logs/
225   -#Il semble qu'il manque des droits au dossier Vendor, droit trop général à réduire (identifié les composants qui ont besoin de s'éxécuter ou de se lire, pas d'écriture dans le dossier Vendor normalement...)
226   -#sudo chmod -R 770 ./vendor/
227   -sudo chmod -R 777 ./vendor/
228   -echo "==> Done"
229   -
230   -echo
231   -echo "Mise à jour des droits des dossiers tmp et logs"
232   -echo
233   -
234   -HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1`
235   -setfacl -R -m u:${HTTPDUSER}:rwx tmp
236   -setfacl -R -d -m u:${HTTPDUSER}:rwx tmp
237   -setfacl -R -m u:${HTTPDUSER}:rwx logs
238   -setfacl -R -d -m u:${HTTPDUSER}:rwx logs
239   -
240   -
241   -
242   -#
243   -# ------------ D - MODE : install or update ? ------------
244   -#
245   -
246   -# Mode install or update
247   -
248   -while : ; do
249   -echo "Voulez-vous effectuer une premiere installation OU BIEN une reconfiguration ('install'/'update') ? ['install'] :"
250   - read mode
251   - [[ -z $mode ]] && mode="install"
252   - [[ $mode == "install" || $mode == "update" ]] && break
253   -done
254   -echo "==> Utilisation en mode $mode"
255   -
256   -
257   -
258   -#
259   -# ------------ D - CONFIGURATION Database (fichier config/app.php) ------------
260   -#
261   -
262   -cakephpAppPath=./
263   -configPath=$cakephpAppPath/config
264   -dbConfigFile=$configPath/app.php
265   -myConfigFile=$configPath/app.php
266   -configFile=$configPath/app.php
267   -
268   -# If INSTALL mode => copy sample GENERAL config file to real personal file (make a copy first if already exists !)
269   -[[ -f $myConfigFile ]] && cp -p $myConfigFile $myConfigFile.ORIG
270   -[[ $mode == "install" ]] && cp $configPath/app.default.php $myConfigFile
271   -
272   -while : ; do
273   - echo "Voulez-vous (re-)créer la base de données (O/N) ? [N] :"
274   - read rep
275   - [[ -z $rep ]] && rep="N"
276   - [[ $rep == "O" || $rep == "N" ]] && break
277   -done
278   -BDD=$rep
279   -if [[ $BDD == "O" ]] ; then
280   - echo "==> (re-)Création de la base de donnees"
281   -else
282   - echo "==> Pas de création de la base de donnees (la BD existe déjà)"
283   -fi
284   -
285   -# Set database ip
286   -echo "Entrez le nom ou l'adresse du serveur MySQL hebergeant la base de donnnees : (defaut=localhost)"
287   -read bddIp
288   -if [ -z $bddIp ] ; then
289   - bddIp="localhost"
290   -fi
291   -echo "==> Adresse du serveur MySql = $bddIp"
292   -echo
293   -
294   -if [[ $BDD == "O" ]] ; then
295   - echo "Entrez le login privilegie vous donnant le droit de CREER les bases de donnees (NB: ce login ne sera utilise qu'une seule fois, pour la creation des bases ; par defaut=root) :"
296   - echo "Si vous n'avez pas la permission de créer de nouvelles bases sur le serveur mais souhaitez installer le logiciel dans une base existante, entrez 'bd_existante'"
297   - #echo "Si vous n'avez pas la permission de créer de nouvelles bases sur le serveur mais souhaitez installer le logiciel dans une base existante, entrez 'latmos'"
298   - read bddAdminName
299   - if [ -z $bddAdminName ] ; then
300   - bddAdminName="root"
301   - fi
302   - echo "==> SGBD admin login = $bddAdminName"
303   - echo
304   - echo "Entrez le mot de passe de ce login privilegie (sinon, entrer le mot de passe de root) :"
305   - read -s bddAdminPass
306   - echo
307   -fi
308   -
309   -echo
310   -
311   -# Configuration BD test et prod dans fichier config/app.php
312   -
313   -# - BD test
314   -
315   -sed -e "s/'database' => 'test_database'/'database' => 'test_labinvent2'/" -i '' $dbConfigFile
316   -sed -e "s/'username' => 'test_username'/'username' => 'superadmin'/" -i '' $dbConfigFile
317   -sed -e "s/'password' => 'test_password'/'password' => 'superadmin'/" -i '' $dbConfigFile
318   -
319   -# - BD prod
320   -
321   -#sed -e "s#/\*d\*/'host' => 'localhost'//\*d\*/'host' => '$bddIp'/" -i '' $dbConfigFile
322   -sed -e "s/\*d\*\/'host' => 'localhost'/\*d\*\/'host' => '$bddIp'/" -i '' $dbConfigFile
323   -
324   -echo "Entrez le nom de la base a utiliser pour l'inventaire (defaut=labinvent)"
325   -read bddName
326   -if [ -z $bddName ] ; then
327   - bddName="labinvent"
328   -fi
329   -echo "==> Nom de la BD = $bddName"
330   -echo
331   -sed -e "s/'database' => 'database'/'database' => '$bddName'/" -i '' $dbConfigFile
332   -
333   -# Attention, le login doit faire maximum 16 caracteres, car Mysql ne supporte pas plus
334   -defaultBddUserName=${bddName:0:12}user
335   -echo "Entrez le login qui doit etre cree pour que le logiciel puisse avoir acces a la base de donnees inventaire"
336   -echo "Ce login sera utilise par le logiciel pour acceder et modifier la BD d'inventaire, quelque soit l'utilisateur connecte"
337   -echo "Attention, il ne s'agit pas d'un utilisateur humain, mais d'un login associe au logiciel, il peut donc porter le nom du logiciel par exemple"
338   -echo "Ce login doit faire 16 caracteres MAX (proposition par defaut, $defaultBddUserName):"
339   -read bddUserName
340   -if [ -z $bddUserName ] ; then
341   - bddUserName=$defaultBddUserName
342   -fi
343   -echo "==> BDD inventaire user login = $bddUserName"
344   -echo
345   -sed -e "s/'username' => 'username'/'username' => '$bddUserName'/" -i '' $dbConfigFile
346   -sed -e "s/'username' => 'superadmin'/'username' => '$bddUserName'/" -i '' $dbConfigFile
347   -echo "Entrez le mot de passe de cet utilisateur :"
348   -read -s bddUserPass
349   -echo "==> BDD inventaire user pass = $bddUserPass"
350   -echo
351   -sed -e "s/'password' => 'password'/'password' => '$bddUserPass'/" -i '' $dbConfigFile
352   -sed -e "s/'password' => 'superadmin'/'password' => '$bddUserPass'/" -i '' $dbConfigFile
353   -
354   -# DATABASE INSTALLATION
355   -
356   -#if [ $BDD == "N" ] ; then
357   -# #Structure de la base de test présente dans le fichier "labinvent_mode_update.sql"
358   -# cat ./labinvent_mode_update.sql > ./build_update.sql
359   -# mysql --user=$bddAdminName --password=$bddAdminPass -h $bddIp < ./build_update.sql
360   -#else
361   -
362   -if [ $BDD == "O" ] ; then
363   - cd database/
364   - echo "Creation script de construction de la BD."
365   - [[ -f build.sql ]] && cp -p build.sql build.sql.ORIG
366   -
367   - # Structure de la base présente dans le fichier "labinvent_last_version.sql"
368   - # (EP 25/5/19) TODO: il faut un script sql adapté au cas 'bd_existante',
369   - # c'est à dire SANS "create schema...", mais juste des "drop table if exists + create table"
370   - if [ $bddAdminName == 'bd_existante' ] ; then
371   - #cat ./labinvent_2.1_22-05-17.sql > ./build.sql
372   - #cat ./labinvent_last_version_from_existing_bd.sql > ./build.sql
373   - # (1) On crée un fichier vide
374   - echo "" > ./build.sql
375   - else
376   - # (1) Instructions de création de la BD
377   - cat ./create_database.sql > ./build.sql
378   - fi
379   - # (2) Instructions de création des tables
380   - #cat ./labinvent_last_version_from_scratch.sql >> ./build.sql
381   - cat ./create_tables.sql >> ./build.sql
382   - # (3) Insertions des données de base indispensables (surtout la table configurations)
383   - cat ./insert_tables_default_data_general.sql >> ./build.sql
384   -
385   -
386   - # Ajout login & mdp utlisateur application dans le script build.sql
387   - #sed -e "s/'mydb'/'$bddUserName'/" -i '' ./build.sql
388   - sed -e "s/'mydb_user'/'$bddUserName'/" -i '' ./build.sql
389   - #sed -e "s/'mydb1'/'$bddUserPass'/" -i '' ./build.sql
390   - sed -e "s/'mydb_pass'/'$bddUserPass'/" -i '' ./build.sql
391   -
392   - # Seulement pour IRAP
393   - if [ $INSTALL_DATA_IRAP -eq 1 ] ; then
394   - echo "Voulez-vous installer les donnees propres a l'IRAP (categories, groupes metiers, groupes thematiques) dans la base de donnees, Oui/Non ? (reponse par defaut Oui) :"
395   - read rep
396   - if [ -z $rep ] || [ $rep == "O" ] || [ $rep == "o" ] || [ $rep == "Oui" ] || [ $rep == "oui" ] || [ $rep == "OUI" ]; then
397   - echo "Installation des donnees IRAP dans la base de donnees"
398   - #cat ./Insert_TablesFunct.sql >> ./build.sql
399   - cat ./insert_tables_default_data_IRAP.sql >> ./build.sql
400   - else
401   - echo "Pas d'install de donnees IRAP dans la base"
402   - fi
403   - fi
404   - echo
405   -
406   - #rep=" "
407   - cat ./insert_superadmin_user.sql >> ./build.sql
408   -
409   - echo "Maintenant, nous allons definir l utilisateur qui sera superadministrateur de l application, ca peut etre VOUS (Pas de mot de passe par défaut) :"
410   - echo "- Entrez ses (vos) Nom et Prenom (sous forme : Nom Prenom ) :"
411   - read UserName UserPrenom
412   - echo
413   - echo "- Entrez son (votre) login (par exemple, votre login ldap - par défaut 'superadmin') :"
414   - read login
415   - # par defaut, on met superadmin (utilisé en fake ldap)
416   - if [ -z $login ] ; then
417   - login="superadmin"
418   - fi
419   - echo "==> login du super administrateur de LabInvent = $login"
420   - echo "*** ATTENTION *** : Notez bien ce login, c'est celui qui vous permettra par défaut de vous connecter à LabInvent en tant que super administrateur (avec le mot de passe 'login')"
421   - echo
422   - echo "- Entrez son (votre) email :"
423   - read mel
424   - echo
425   - sed -e "s/Nom/$UserName/" -i '' ./build.sql
426   - sed -e "s/Prenom/$UserPrenom/" -i '' ./build.sql
427   - sed -e "s/userlogin/$login/" -i '' ./build.sql
428   - sed -e "s/'__@__'/'$mel'/" -i '' ./build.sql
429   -
430   - echo "Voulez-vous installer quelques utilisateurs supplémentaires (bidons, 1 par profil) dans la base de donnees (vous pourrez ensuite changer leur nom dans l'application, ou meme les supprimer ; par defaut, Oui): Oui/Non ?"
431   - read rep
432   - if [ -z $rep ] || [ $rep == "O" ] || [ $rep == "o" ] || [ $rep == "Oui" ] || [ $rep == "oui" ] || [ $rep == "OUI" ]; then
433   - echo "Ajout de quelques utilisateurs supplementaires dans la base (Mot de passe par défaut : login)"
434   - cat ./insert_fake_users.sql >> ./build.sql
435   - fi
436   -
437   - # Remplacement des "use mydb" par "use $bddName"
438   - sed -e "s/mydb/$bddName/" -i '' ./build.sql
439   -
440   - echo
441   - echo "Creation base de donnees (Attention, votre serveur de BD doit etre demarre)"
442   - if [ $bddAdminName == 'bd_existante' ] ; then
443   - mysql --user=$bddUserName --password=$bddUserPass -h $bddIp < ./build.sql
444   - else
445   - mysql --user=$bddAdminName --password=$bddAdminPass -h $bddIp < ./build.sql
446   - fi
447   - echo "Base créée (a verifier)"
448   - cd ../
449   -fi
450   -
451   -
452   -echo
453   -echo "Passage de l'application en mode INSTALL"
454   -cd database/
455   -chmod +x mode_panique_macos.sh
456   -./mode_panique_macos.sh
457   -
458   -
459   -
460   -
461   -
462   -echo
463   -echo "*** FIN DE L'INSTALLATION ***"
464   -echo
465   -
466   -#echo "Maintenant, veuillez poursuivre en suivant (rigoureusement) les indications données sur le wiki du projet : https://projects.irap.omp.eu/projects/inventirap/wiki/Installation#C-TESTS"
467   -
468   -#if [ $mode == 'install' ] ; then
469   -# echo "Si vous voulez le conserver, le script de creation de la BD est database/build.sql"
470   -# echo "Le fichier de configuration app.php a été écrasé, vous pouvez retrouver votre ancienne configuration dans le fichier app.php.ORIG."
471   -# echo
472   -# echo "MAINTENANT :"
473   -# echo "1) Verifiez que la BD d'inventaire ($bddName) a bien ete cree (avec phpmyadmin par exemple)"
474   -# echo "2) Verifiez que les tests passent, placez vous à la racine du projet, exécutez la commande 'vendor/bin/phpunit'."
475   -# echo "3) Allez sur l'application, vous devriez arriver par défaut sur un mode install vous donnant des informations sur la configuration de votre application, vérifiez que tous les points sont bien validés (verts), sinon rajouter les extensions manquantes..."
476   -# echo "4) Testez l'accès à l'application par le web"
477   -#else
478   -# echo
479   -# echo "MAINTENANT :"
480   -# echo "1) Verifiez que les tests passent, placez vous à la racine du projet, exécutez la commande 'vendor/bin/phpunit'."
481   -# echo "2) Allez sur l'application, vous devriez arriver par défaut sur un mode install vous donnant des informations sur la configuration de votre application, vérifiez que tous les points sont bien validés (verts), sinon rajouter les extensions manquantes..."
482   -# echo "3) Testez l'accès à l'application par le web"
483   -#fi
484   -#
485   -#echo "Pour aller sur l'application, suivez la suite des instructions qui sont dans le fichier INSTALLATION.txt (à la racine du projet), que vous avez normalement deja commence a lire (ou bien sur le web (https://projects.irap.omp.eu/projects/inventirap/wiki/Installation)"
486   -#echo
487   -#echo "N'oubliez pas 3 choses importantes :"
488   -#echo "1) Personnaliser les 2 fichiers logos suivants dans webroot/img/ :"
489   -#echo "- logo_entity.jpg : le logo du laboratoire"
490   -#echo "- logo_software.jpg : le logo du logiciel"
491   -#echo "2) Personnaliser le logiciel pour votre entité (laboratoire) (via le menu de configuration dans la section outils de l\'application)"
492   -#echo "3) Passer en mode LDAP (via le menu de configuration dans la section outils de l\'application)"
src/Controller/AppController.php
... ... @@ -1956,7 +1956,24 @@ class AppController extends Controller
1956 1956 // (EP 23/5/19) Exception si la config est vide, inutile d'aller plus loin !
1957 1957 if (is_null($this->confLabinvent)) throw new \Exception("EXCEPTION: La table 'configurations' de la base de données est vide");
1958 1958  
1959   - // Initialisation des autorisations pour les actions du controleur
  1959 +
  1960 + // (IP2I) Initialisation des autorisations pour les actions du controleur
  1961 + /*
  1962 + $configKey = 'GeneralAuthorizations';
  1963 + if ( Configure::check($configKey) ) {
  1964 + $defaultAuthorizations = Configure::readOrFail($configKey);
  1965 + //debug($defaultAuthorizations);
  1966 + }
  1967 + else debug("error");
  1968 +
  1969 + $configKey = 'MaterielsAuthorizations';
  1970 + if ( Configure::check($configKey) ) {
  1971 + $defaultAuthorizations = Configure::readOrFail($configKey);
  1972 + //debug($defaultAuthorizations);
  1973 + }
  1974 + else debug("error");
  1975 + */
  1976 +
1960 1977 // 1) Initialisation des autorisations par défaut du parent (AppController)
1961 1978 $this->setDefaultAuthorizations();
1962 1979 // 2) Ajout des autorisations spécifiques par le controleur courant
... ...
src/Controller/MaterielsController.php
... ... @@ -485,7 +485,7 @@ class MaterielsController extends AppController {
485 485 'resp' => ['NOT CREATED',1]
486 486 ]);
487 487  
488   - // Action 'updgrade' (avancement du statut d'un matériel)
  488 + // Action 'upgrade' (avancement du statut d'un matériel)
489 489 // CREATED => VALIDATED => TBA => ARCHIVED
490 490 /*
491 491 $this->setAuthorizationsForAction('upgrade', ['NOT ARCHIVED',0], [ // En fait, l'action fait juste passer au statut "suivant"
... ... @@ -496,7 +496,6 @@ class MaterielsController extends AppController {
496 496 'resp' => 'user'
497 497 ]);
498 498 */
499   - // Action 'updgrade' (avancement du statut d'un matériel)
500 499 // - Validation d'un materiel (passe à VALIDATED) : CREATED => VALIDATED
501 500 $this->setAuthorizationsForAction('statusValidated (valider)', ['CREATED',0], [
502 501 'user' => -1, // interdit
... ... @@ -2114,10 +2113,12 @@ class MaterielsController extends AppController {
2114 2113 */
2115 2114  
2116 2115 // Attributs obligatoires pour la phase COMMANDE
2117   - $LOT1 = $this->Materiels->MANDATORY_FIELDS_LOT1;
  2116 + //$LOT1 = $this->Materiels->MANDATORY_FIELDS_LOT1;
  2117 + $LOT1 = $this->Materiels->getMandatoryFieldsLot1();
2118 2118  
2119 2119 // Attributs obligatoires pour la phase VALIDATION (livré et payé)
2120   - $LOT2 = $this->Materiels->MANDATORY_FIELDS_LOT2;
  2120 + //$LOT2 = $this->Materiels->MANDATORY_FIELDS_LOT2;
  2121 + $LOT2 = $this->Materiels->getMandatoryFieldsLot2();
2121 2122  
2122 2123 // Seulement si prix > 10K€ : exiger la facture jointe et le n° série
2123 2124 if ($materiel->prix_ht > 10000) {
... ... @@ -2125,10 +2126,11 @@ class MaterielsController extends AppController {
2125 2126 $LOT2['numero_serie'] = 'S/N';
2126 2127 }
2127 2128 // LOT2 = LOT1 + LOT2;
2128   - $LOT2 = array_merge($LOT1, $LOT2);
  2129 + ////$LOT2 = array_merge($LOT1, $LOT2);
2129 2130 //debug($LOT2);exit;
2130 2131 // Champs obligatoires = LOT1 si CREATED, LOT2 sinon (>CREATED, c'est à dire VALIDATED ou plus)
2131 2132 $mandatory_fields = ($materiel->status == 'CREATED') ? $LOT1 : $LOT2;
  2133 + //debug($mandatory_fields); exit;
2132 2134  
2133 2135 $verb = $IS_ADD ? "ajouté" : "modifié";
2134 2136  
... ... @@ -2136,7 +2138,13 @@ class MaterielsController extends AppController {
2136 2138 // Si au moins un champ obligatoire est nul ou vide => ERROR
2137 2139 $ALL_MANDATORY_FIELDS_GIVEN = true;
2138 2140 //foreach ($mandatory_fields as $fname => $fval) {
  2141 + //print_r($materiel);
2139 2142 foreach ($mandatory_fields as $fname=>$fname_nice) {
  2143 +
  2144 + // Champs spéciaux dont le caractère obligatoire est géré indirectement (via beforeSave())
  2145 + // (fournisseur_id, et autres champs ajoutés dans l'avenir ? ...)
  2146 + if ($fname=='fournisseur_id') continue;
  2147 +
2140 2148 if ($materiel->$fname === null || $materiel->$fname == '') {
2141 2149 $ALL_MANDATORY_FIELDS_GIVEN = false;
2142 2150 /* (EP 2020 03)
... ... @@ -2184,8 +2192,20 @@ class MaterielsController extends AppController {
2184 2192 // (EP202009) $this->e doit refléter le matériel mis à jour
2185 2193 /////$this->e = $materiel;
2186 2194 $this->myDebug($materiel->getErrors());
  2195 +
  2196 + //$msgError1 = "Pour valider un matériel, le champ suivant ne doit pas être vide : ".'fourniss'.' du matériel';
  2197 + //$this->Flash->error($msgError1);
  2198 +
  2199 + //debug($materiel->getErrors());
  2200 + $flash_msg = "Le matériel n'a pas pu être $verb";
  2201 + //if (is_null($materiel->Fournisseur)) $flash_msg .= ' (il faut préciser le fournisseur)';
  2202 + $this->Flash->error(__($flash_msg));
  2203 +
2187 2204 //debug($materiel->getErrors());
2188   - $this->Flash->error(__("Le matériel n'a pas pu être $verb"));
  2205 + //foreach ($materiel->getErrors() as $f=>$e) $this->Flash->error(__($e[0].' : '.$f));
  2206 + foreach ($materiel->getErrors() as $f=>$e)
  2207 + foreach($e as $k=>$v) $this->Flash->error(__($v.' : '.$f));
  2208 +
2189 2209 }
2190 2210 else {
2191 2211 //debug($this->getCurrentEntity()); exit;
... ... @@ -2241,7 +2261,7 @@ class MaterielsController extends AppController {
2241 2261  
2242 2262 /*
2243 2263 * \AV2 - OPTIONS
2244   - * (Domaine de définitionde de chaque champ, si peut s'exprimer comme une liste)
  2264 + * (Domaine de définition de de chaque champ, si peut s'exprimer comme une liste)
2245 2265 *
2246 2266 * INITIALISATION DE LISTES qu'on va passer à la vue (edit ou add) pour assister la saisie (listes de choix proposés)
2247 2267 *
... ... @@ -2788,6 +2808,11 @@ class MaterielsController extends AppController {
2788 2808  
2789 2809 // - VALIDATED
2790 2810 if ($newStatus == 'VALIDATED') {
  2811 + // Attributs obligatoires pour la phase VALIDATION (livré et payé) (LOT2)
  2812 + $mandatoryFields = $this->Materiels->getMandatoryFieldsLot2();
  2813 + //$mandatoryFields = $this->Materiels->MANDATORY_FIELDS_LOT2;
  2814 + //debug($mandatoryFields);exit;
  2815 + /*
2791 2816 $mandatoryFields = array(
2792 2817 'Nom utilisateur' => $materiel->nom_responsable,
2793 2818 'Fournisseur' => $materiel->fournisseur_id,
... ... @@ -2798,6 +2823,7 @@ class MaterielsController extends AppController {
2798 2823 // (EP202009) Un gestionnaire par défaut (de référence) doit être choisi AVANT validation
2799 2824 'Gestionnaire de référence' => $materiel->gestionnaire_id
2800 2825 );
  2826 + */
2801 2827 /*
2802 2828 $mandatoryFields = array(
2803 2829 $materiel->nom_responsable,
... ... @@ -2818,8 +2844,11 @@ class MaterielsController extends AppController {
2818 2844 */
2819 2845  
2820 2846 // Si au moins un champ obligatoire est nul ou vide => ERROR
2821   - foreach ($mandatoryFields as $fname => $fval) {
  2847 + foreach ($mandatoryFields as $fname => $fnicename) {
  2848 + $fval = $materiel->$fname;
  2849 + //debug($fname); debug($fval);
2822 2850 if ($fval === null || $fval == '') {
  2851 + //debug($fname);
2823 2852 // Validation d'un seul matériel => on revient à "edit"
2824 2853 if ($onlyOneMateriel) {
2825 2854 /* (EP 2020 03)
... ... @@ -2830,7 +2859,7 @@ class MaterielsController extends AppController {
2830 2859 * (il se peut qu'on n'aie plus besoin de faire ça dans une prochaine version
2831 2860 * de bootstrap, ou bootsrap-ui, ou cakephp..., à surveiller donc)
2832 2861 */
2833   - $msgError1 = "Pour valider un matériel, le champ suivant ne doit pas être vide : ".$fname.' du matériel';
  2862 + $msgError1 = "Pour valider un matériel, le champ suivant ne doit pas être vide : ".$fnicename.' du matériel';
2834 2863 $this->Flash->error($msgError1);
2835 2864 /* MARCHE PAS POURQUOI ?
2836 2865 $materiel->setError($field, 'Ce champ ne doit pas être vide');
... ... @@ -2849,6 +2878,8 @@ class MaterielsController extends AppController {
2849 2878 }
2850 2879 }
2851 2880 }
  2881 + //debug("OK");
  2882 + //exit;
2852 2883 // Le matos est valide, on peut donc marquer la date de validation
2853 2884 $materiel->set('date_validated', date('Y-m-d'));
2854 2885 //$materiel->date_validated = date('Y-m-d');
... ...
src/Model/Entity/Materiel.php
... ... @@ -149,6 +149,14 @@ class Materiel extends Entity {
149 149 protected function _getIsTobearchived() { return $this->status == 'TOBEARCHIVED'; }
150 150 protected function _getIsArchived() { return $this->status == 'ARCHIVED'; }
151 151  
  152 + public function getNiceStatus() {
  153 + if ($this->is_created) return 'À VALIDER';
  154 + if ($this->is_validated) return 'VALIDÉ';
  155 + if ($this->is_tobearchived) return 'À SORTIR';
  156 + //if ($this->is_archived)
  157 + return 'ARCHIVÉ';
  158 + }
  159 +
152 160  
153 161 // Ce matériel est utilisé ou déclaré par l'utilisateur $userfullname
154 162 // is Owned Or Declared By User
... ...
src/Model/Table/AppTable.php
... ... @@ -18,6 +18,12 @@ class AppTable extends Table
18 18 // accents + - _ / () . , \s (=space)
19 19 private $chaine = "a-zA-Z0-9éèàùâêôîïôûç%().,\/\s\+\-_'";
20 20  
  21 + // Check prix > 0
  22 + public function checkPriceIsPositive($prix_ht) {
  23 + if (trim($prix_ht) != '') return is_numeric($prix_ht) && $prix_ht >= 0;
  24 + return true;
  25 + }
  26 +
21 27 public function check_string($check)
22 28 {
23 29 return (bool) preg_match(
... ...
src/Model/Table/LdapConnectionsTable.php
... ... @@ -1021,7 +1021,9 @@ class LdapConnectionsTable extends AppTable
1021 1021 else
1022 1022 // - ldap anonyme => binding anonyme
1023 1023 $ldapbind = @ldap_bind($ldapConnection);
1024   - if (! $ldapbind) die("Impossible de faire un BIND simple sur le serveur ldap");
  1024 + if (! $ldapbind) {
  1025 + die("Impossible de faire un BIND simple sur le serveur ldap " . $this->ldap_authentified ? "(mode authentifié) !" : "(mode anonyme) !");
  1026 + }
1025 1027  
1026 1028 // (4) SEARCH : Recherche d'infos (sur le user qui se connecte, ou bien sur tous les users)
1027 1029 // $filter = "(&".$this->filter."(".$this->authenticationType . '=' . $user_login."))";
... ...
src/Model/Table/MaterielsTable.php
... ... @@ -12,6 +12,9 @@ use Cake\ORM\Association\BelongsTo;
12 12 use Cake\ORM\Entity;
13 13 use Cake\I18n\FrozenDate;
14 14  
  15 +// (2021 08) EP added to read new config files (config/app_mandatory_fields, ...)
  16 +use Cake\Core\Configure;
  17 +
15 18 /**
16 19 * Materiels Model
17 20 *
... ... @@ -42,96 +45,193 @@ use Cake\I18n\FrozenDate;
42 45 */
43 46  
44 47  
  48 +//const IP2I = false;
  49 +//const IP2I = true;
  50 +
45 51 // Max 10 ans entre 2 dates
46 52 //const MAX_DIFF_YEARS = 10;
47 53  
48   -class MaterielsTable extends AppTable
49   -{
  54 +const MANDATORY_FIELDS_LOT1 = [
  55 +
  56 + // Infos toujours obligatoires (cachées car calculées automatiquement)
  57 + //'status',
  58 + //'tobeordered',
  59 +
  60 + //'hors_service', // O/N
  61 +
  62 + 'designation' => 'Désignation',
  63 +
  64 + 'description' => 'Description',
  65 + //'permanent',
  66 + //'will_stay', // O/N
  67 +
  68 + 'sur_categorie_id' => 'Domaine',
  69 + 'categorie_id' => 'Catégorie',
  70 +
  71 + // - Utilisateur
  72 + 'nom_user' => "Nom de l'utilisateur de ce matériel",
  73 +
  74 + // - Acheteur
  75 + 'nom_responsable' => 'Nom du responsable',
  76 + // (rempli automatiquement)
  77 + 'email_responsable' => 'Email du responsable',
  78 +
  79 + // Calculé auto au moment du save()
  80 + //'numero_laboratoire',
  81 +
  82 + 'organisme_id' => 'Organisme',
  83 +
  84 + 'prix_ht' => 'Prix HT',
  85 +
  86 + // Optionnel car par défaut = acheteur
  87 + //'resp_credit' => 'Responsable du crédit',
  88 +
  89 +
  90 + //TODO: a remettre ? avec "je ne sais pas"
  91 + /////'gestionnaire_id' => 'Gestionnaire de référence',
  92 +
  93 +
  94 + //'fournisseur',
  95 +
  96 + //'devis joint',
  97 +
  98 + // Utilisé par la Gestion pour remplir le champ eotp
  99 + 'budgets' => 'Budgets',
  100 +
  101 + // INFOS ADMINISTRATIVES
  102 + // - EOTP : obligatoire seulement dans LOT2
  103 + //'eotp' => 'Entité(s) dépensière(s) (budget(s))', // ligne budgétaire (sur quel(s) budget(s)) ou entité(s) dépensière(s)
  104 +
  105 +]; // $MANDATORY_FIELDS_LOT1
50 106  
51   - private $PREV_SEUIL_INVENTORIABLE = 800;
  107 +const MANDATORY_FIELDS_LOT2 = [
52 108  
53   - private $LAST_SEUIL_INVENTORIABLE_YEAR = 2020;
54   - private $LAST_SEUIL_INVENTORIABLE_DATE = '03/06/2020';
55   - private $LAST_SEUIL_INVENTORIABLE; // 1000€ pour IRAP (depuis 3/6/2020)
  109 + //'fournisseur_id' => 'Fournisseur',
  110 + //'fournisseur' => 'Fournisseur',
56 111  
  112 + 'date_acquisition' => "Date d'achat",
57 113  
58   - public $MANDATORY_FIELDS_LOT1 = [
  114 + 'date_reception' => 'Date de livraison',
59 115  
60   - // Infos toujours obligatoires (cachées car calculées automatiquement)
61   - //'status',
62   - //'tobeordered',
63   -
64   - //'hors_service', // O/N
65   -
66   - 'designation' => 'Désignation',
67   -
68   - 'description' => 'Description',
69   - //'permanent',
70   - //'will_stay', // O/N
71   -
72   - 'sur_categorie_id' => 'Domaine',
73   - 'categorie_id' => 'Catégorie',
74   -
75   - // - Utilisateur
76   - 'nom_user' => "Nom de l'utilisateur de ce matériel",
77   -
78   - // - Acheteur
79   - 'nom_responsable' => 'Nom du responsable',
80   - // (rempli automatiquement)
81   - 'email_responsable' => 'Email du responsable',
  116 + //'etiquette', // O/N
  117 +
  118 + 'site_id' => 'Site',
  119 +
  120 + 'lieu_detail' => 'Lieu de stockage',
  121 +
  122 + // INFOS ADMINISTRATIVES :
  123 +
  124 + // La Gestion doit remplir ce champ a partir des infos qui sont dans le champ "budget" (rempli par acheteur)
  125 + 'eotp' => 'Entité(s) dépensière(s) (budget(s))', // ligne budgétaire (sur quel(s) budget(s)) ou entité(s) dépensière(s)
  126 +
  127 + 'numero_commande' => 'Num. BC',
  128 + 'numero_inventaire_organisme' => "N° inventaire de l'organisme",
  129 +
  130 +];
82 131  
83   - // Calculé auto au moment du save()
84   - //'numero_laboratoire',
85   -
86   - 'organisme_id' => 'Organisme',
  132 +/*
  133 +const IP2I_optional_fields = [
  134 + 'organisme_id'=>'',
  135 + 'prix_ht'=>'',
  136 + 'budgets'=>'',
  137 +
  138 + 'eotp'=>'',
  139 + 'numero_commande'=>'',
  140 + 'date_reception'=>'',
  141 + 'gestionnaire_id'=>'',
  142 +];
  143 +*/
87 144  
88   - 'prix_ht' => 'Prix HT',
89   -
90   - // Optionnel car par défaut = acheteur
91   - //'resp_credit' => 'Responsable du crédit',
92   -
93   -
94   - //TODO: a remettre ? avec "je ne sais pas"
95   - /////'gestionnaire_id' => 'Gestionnaire de référence',
96   -
97   -
98   - //'fournisseur',
99   -
100   - //'devis joint',
101   -
102   - // Utilisé par la Gestion pour remplir le champ eotp
103   - 'budgets' => 'Budgets',
104   -
105   - // INFOS ADMINISTRATIVES
106   - // - EOTP : obligatoire seulement dans LOT2
107   - //'eotp' => 'Entité(s) dépensière(s) (budget(s))', // ligne budgétaire (sur quel(s) budget(s)) ou entité(s) dépensière(s)
  145 +
  146 +//const MANDATORY_FIELDS_LOT1_IP2I = [
  147 +define ('MANDATORY_FIELDS_LOT1_IP2I', [
108 148  
109   - ]; // $MANDATORY_FIELDS_LOT1
110 149  
  150 + // Infos toujours obligatoires (cachées car calculées automatiquement)
  151 + //'status',
  152 + //'tobeordered',
111 153  
112   - public $MANDATORY_FIELDS_LOT2 = [
113   -
114   - 'fournisseur_id' => 'Fournisseur',
115   -
116   - 'date_acquisition' => "Date d'achat",
117   -
118   - 'date_reception' => 'Date de livraison',
119   -
120   - //'etiquette', // O/N
121   -
122   - 'site_id' => 'Site',
123   -
124   - 'lieu_detail' => 'Lieu de stockage',
125   -
126   - // INFOS ADMINISTRATIVES :
127   -
128   - // La Gestion doit remplir ce champ a partir des infos qui sont dans le champ "budget" (rempli par acheteur)
129   - 'eotp' => 'Entité(s) dépensière(s) (budget(s))', // ligne budgétaire (sur quel(s) budget(s)) ou entité(s) dépensière(s)
130   -
131   - 'numero_commande' => 'Num. BC',
132   - 'numero_inventaire_organisme' => "N° inventaire de l'organisme",
133   -
134   - ];
  154 + //'hors_service', // O/N
  155 +
  156 + 'designation' => 'Désignation',
  157 +
  158 + 'description' => 'Description',
  159 + //'permanent',
  160 + //'will_stay', // O/N
  161 +
  162 + 'sur_categorie_id' => 'Domaine',
  163 + 'categorie_id' => 'Catégorie',
  164 +
  165 + 'fournisseur_id' => 'Fournisseur',
  166 +
  167 + // - Utilisateur
  168 + 'nom_user' => "Nom de l'utilisateur de ce matériel",
  169 +
  170 + // - Acheteur
  171 + 'nom_responsable' => 'Nom du responsable',
  172 + // (rempli automatiquement)
  173 + 'email_responsable' => 'Email du responsable',
  174 +
  175 + // Calculé auto au moment du save()
  176 + //'numero_laboratoire',
  177 +
  178 + ////'organisme_id' => 'Organisme',
  179 +
  180 + ////'prix_ht' => 'Prix HT',
  181 +
  182 + // Optionnel car par défaut = acheteur
  183 + //'resp_credit' => 'Responsable du crédit',
  184 +
  185 +
  186 + //TODO: a remettre ? avec "je ne sais pas"
  187 + /////'gestionnaire_id' => 'Gestionnaire de référence',
  188 +
  189 +
  190 + //'fournisseur',
  191 +
  192 + //'devis joint',
  193 +
  194 + // Utilisé par la Gestion pour remplir le champ eotp
  195 + ////'budgets' => 'Budgets',
  196 +
  197 +
  198 +
  199 + 'date_acquisition' => "Date d'achat",
  200 +
  201 + ////'date_reception' => 'Date de livraison',
  202 +
  203 + //'etiquette', // O/N
  204 +
  205 + ///'site_id' => 'Site',
  206 +
  207 + ///'lieu_detail' => 'Lieu de stockage',
  208 +
  209 +
  210 + // INFOS ADMINISTRATIVES :
  211 +
  212 + // La Gestion doit remplir ce champ a partir des infos qui sont dans le champ "budget" (rempli par acheteur)
  213 + ///'eotp' => 'Entité(s) dépensière(s) (budget(s))', // ligne budgétaire (sur quel(s) budget(s)) ou entité(s) dépensière(s)
  214 +
  215 + ////'numero_commande' => 'Num. BC',
  216 + ////'numero_inventaire_organisme' => "N° inventaire de l'organisme",
  217 +
  218 +]); // $MANDATORY_FIELDS_LOT1
  219 +
  220 +//const MANDATORY_FIELDS_LOT2_IP2I = MANDATORY_FIELDS_LOT1_IP2I;
  221 +define ('MANDATORY_FIELDS_LOT2_IP2I', MANDATORY_FIELDS_LOT1_IP2I);
  222 +
  223 +
  224 +
  225 +class MaterielsTable extends AppTable
  226 +{
  227 +
  228 + public static $LAB = null;
  229 +
  230 + private $PREV_SEUIL_INVENTORIABLE = 800;
  231 +
  232 + private $LAST_SEUIL_INVENTORIABLE_YEAR = 2020;
  233 + private $LAST_SEUIL_INVENTORIABLE_DATE = '03/06/2020';
  234 + private $LAST_SEUIL_INVENTORIABLE; // 1000€ pour IRAP (depuis 3/6/2020)
135 235  
136 236  
137 237 public $ALL_STATUS = array(
... ... @@ -142,6 +242,44 @@ class MaterielsTable extends AppTable
142 242 );
143 243  
144 244 public function toto() { return "titi"; }
  245 +
  246 + public static function getLabName() {
  247 + // Singleton (on ne lit qu'1 seule fois la config !!!)
  248 + if (! self::$LAB) {
  249 + $confLabinvent = TableRegistry::getTableLocator()->get('Configurations')->find()->first();
  250 + if (is_null($confLabinvent)) throw new \Exception("EXCEPTION (from Model): La table 'configurations' de la base de données est vide");
  251 + self::$LAB = $confLabinvent->labNameShort ? $confLabinvent->labNameShort : 'LABO';
  252 + //debug(self::$LAB);
  253 + }
  254 + return self::$LAB;
  255 + }
  256 +
  257 + public static function getMandatoryFieldsLot1() {
  258 + //return IP2I ? MANDATORY_FIELDS_LOT1_IP2I : MANDATORY_FIELDS_LOT1;
  259 + $specific_constant_name = "MANDATORY_FIELDS_LOT1_".self::getLabName();
  260 + //debug($constantName);
  261 + //debug(defined($constantName));
  262 + $mandatory_fields_lot1 = defined($specific_constant_name) ? constant($specific_constant_name) : MANDATORY_FIELDS_LOT1;
  263 + //debug($mandatory_fields_lot1);
  264 + return $mandatory_fields_lot1;
  265 + }
  266 +
  267 + public static function getMandatoryFieldsLot2() {
  268 + //$mandatory_fields_lot2 = IP2I ? MANDATORY_FIELDS_LOT2_IP2I : MANDATORY_FIELDS_LOT2;
  269 + $constantName = "MANDATORY_FIELDS_LOT2_".self::getLabName();
  270 + //debug($constantName);
  271 + $mandatory_fields_lot2 = defined($constantName) ? constant($constantName) : MANDATORY_FIELDS_LOT2;
  272 + //debug($mandatory_fields_lot2);
  273 + return array_merge(self::getMandatoryFieldsLot1(), $mandatory_fields_lot2);
  274 + }
  275 +
  276 + public static function getMandatoryFieldsForMaterielStatus($status) {
  277 +
  278 + // CREATED => LOT1
  279 + // VALIDATED et au-dessus => LOT2
  280 + return ($status == 'CREATED') ? self::getMandatoryFieldsLot1() : self::getMandatoryFieldsLot2();
  281 +
  282 + }
145 283  
146 284 /**
147 285 * Initialize method
... ... @@ -157,6 +295,27 @@ class MaterielsTable extends AppTable
157 295 {
158 296 parent::initialize($config);
159 297  
  298 + //debug($config);
  299 + /* (IP2I)
  300 + $mf1 = Configure::readOrFail('MANDATORY_FIELDS_LOT1');
  301 + $mf2 = Configure::readOrFail('MANDATORY_FIELDS_LOT2');
  302 + debug($mf1);
  303 + debug($mf2);
  304 + if ( Configure::check('MANDATORY_FIELDS_LOT1_IP2I') ) {
  305 + $mf1_IP2I = Configure::readOrFail('MANDATORY_FIELDS_LOT1_IP2I');
  306 + debug($mf1_IP2I);
  307 + }
  308 + else debug("error");
  309 + */
  310 +
  311 +
  312 + /*
  313 + $confLabinvent = TableRegistry::getTableLocator()->get('Configurations')->find()->first();
  314 + if (is_null($confLabinvent)) throw new \Exception("EXCEPTION (from Model): La table 'configurations' de la base de données est vide");
  315 + self::$LAB = $confLabinvent->labNameShort ? $confLabinvent->labNameShort : 'LABO';
  316 + //debug(self::$LAB);
  317 + */
  318 +
160 319 $this->setTable('materiels');
161 320 //$this->setDisplayField('id');
162 321 $this->setDisplayField('designation');
... ... @@ -298,9 +457,52 @@ class MaterielsTable extends AppTable
298 457 public function validationDefault(Validator $validator) //: Validator
299 458 {
300 459  
  460 + /*
  461 + if (IP2I) {
  462 +
  463 + //$this->MANDATORY_FIELDS_LOT1['fournisseur_id'] = 'Fournisseur';
  464 + //$this->MANDATORY_FIELDS_LOT1['fournisseur.name'] = 'Fournisseur';
  465 +
  466 + $optional_fields = [
  467 + 'organisme_id',
  468 + 'prix_ht',
  469 + 'budgets',
  470 +
  471 + 'eotp',
  472 + 'numero_commande',
  473 + 'date_reception',
  474 + 'gestionnaire_id',
  475 + ];
  476 +
  477 + foreach ($optional_fields as $fname) {
  478 + // LOT1
  479 + unset($this->MANDATORY_FIELDS_LOT1[$fname]);
  480 +
  481 + // LOT2
  482 + unset($this->MANDATORY_FIELDS_LOT2[$fname]);
  483 +
  484 + $validator->allowEmptyString($fname, true);
  485 + }
  486 +
  487 + }
  488 + //print_r($this->MANDATORY_FIELDS_LOT1);
  489 + */
  490 +
  491 +
  492 + /*
  493 + // TODO : améliorer ça. C'est lot1 si CREATED, et lot2 si VALIDATED+
  494 + $lot = $this->getMandatoryFieldsLot1();
  495 +
301 496 // (EP 31/5/21) Champs obligatoires (LOT1)
302   - foreach ($this->MANDATORY_FIELDS_LOT1 as $fname=>$fdisp)
  497 + foreach ($lot as $fname=>$fdisp) {
  498 +
  499 + // Champs spéciaux dont le caractère obligatoire est géré indirectement (via beforeSave())
  500 + // (fournisseur_id, et autres champs ajoutés dans l'avenir ? ...)
  501 + if ($fname=='fournisseur_id') continue;
  502 +
303 503 $validator->allowEmptyString($fname, false, 'Ce champ doit être rempli');
  504 + }
  505 + */
304 506  
305 507 // Check date is dd/mm/yyyy
306 508 /*
... ... @@ -520,7 +722,21 @@ class MaterielsTable extends AppTable
520 722  
521 723  
522 724  
523   - $validator->numeric('prix_ht');
  725 + //$validator->numeric('prix_ht');
  726 + /*
  727 + $validator->add($checkPriceIsStrictPositive, [
  728 + 'errorField' => 'prix_ht',
  729 + //'message' => 'Le matériel ne peut pas être inventoriable et ne pas avoir de prix'
  730 + 'message' => "Le montant doit être supérieur à 0 €"
  731 + ]);
  732 + */
  733 + $validator->allowEmpty('prix_ht')->add('prix_ht', 'valid', [
  734 + 'rule' => 'checkPriceIsPositive',
  735 + 'message' => 'Le prix doit être numérique et positif',
  736 + 'provider' => 'table'
  737 + ]);
  738 +
  739 +
524 740 // (EP202010 prix obligatoire)
525 741 //->allowEmpty('prix_ht')
526 742 /*
... ... @@ -611,9 +827,54 @@ class MaterielsTable extends AppTable
611 827 $validator->allowEmpty('duree_garantie');
612 828 $validator->allowEmpty('unite_duree_garantie');
613 829  
  830 + $mandatory_fields = $this->getMandatoryFieldsLot1();
  831 + $this->_setMandatoryFields($validator, $mandatory_fields);
  832 + $optional_fields = array_diff_key(MANDATORY_FIELDS_LOT1, $mandatory_fields);
  833 + //debug($optional_fields);
  834 + foreach ($optional_fields as $fname) $validator->allowEmptyString($fname, true);
  835 +
614 836 return $validator;
615 837  
616 838 } // validationDefault()
  839 +
  840 +
  841 + private function _setMandatoryFields(Validator $validator, array $fields) {
  842 +
  843 + // (EP 31/5/21) Champs obligatoires (LOT1)
  844 + foreach ($fields as $fname=>$fdisp) {
  845 +
  846 + // Champs spéciaux dont le caractère obligatoire est géré indirectement (via beforeSave())
  847 + // (fournisseur_id, et autres champs ajoutés dans l'avenir ? ...)
  848 + if ($fname=='fournisseur_id') continue;
  849 +
  850 + $validator->allowEmptyString($fname, false, 'Ce champ doit être rempli');
  851 + }
  852 +
  853 + }
  854 +
  855 + public function validationLOT1(Validator $validator)
  856 + {
  857 + $validator = $this->validationDefault($validator);
  858 +
  859 + //$this->_setMandatoryFields( $validator, $this->getMandatoryFieldsLot1() );
  860 +
  861 + //$validator->add('password', 'length', ['rule' => ['lengthBetween', 8, 100]]);
  862 +
  863 + return $validator;
  864 + }
  865 +
  866 + public function validationLOT2(Validator $validator)
  867 + {
  868 + $validator = $this->validationDefault($validator);
  869 +
  870 + $this->_setMandatoryFields( $validator, $this->getMandatoryFieldsLot2() );
  871 +
  872 + //$validator->add('password', 'length', ['rule' => ['lengthBetween', 8, 100]]);
  873 +
  874 + return $validator;
  875 + }
  876 +
  877 +
617 878  
618 879 public function checkStatus($check) { return ($check !== null && in_array($check, $this->ALL_STATUS)); }
619 880  
... ... @@ -709,10 +970,17 @@ class MaterielsTable extends AppTable
709 970 return true;
710 971 };
711 972  
  973 + /*
712 974 // Check prix > 0
713 975 $checkPriceIsStrictPositive = function (Entity $entity) {
714   - return $entity->prix_ht > 0;
  976 + if ($entity->prix_ht) return $entity->prix_ht > 0;
  977 + return true;
715 978 };
  979 + $checkPriceIsNumeric = function (Entity $entity) {
  980 + if ($entity->prix_ht) return numeric($entity->prix_ht);
  981 + return true;
  982 + };
  983 + */
716 984  
717 985 // Check DATES
718 986  
... ... @@ -808,11 +1076,14 @@ class MaterielsTable extends AppTable
808 1076 'message' => "Si le matériel n'est pas technique, son prix HT doit obligatoirement être supérieur à ".$this->LAST_SEUIL_INVENTORIABLE."€ (inventoriable)"
809 1077 ]);
810 1078 */
  1079 + /*
  1080 + //if (! IP2I) $rules->add($checkPriceIsStrictPositive, [
811 1081 $rules->add($checkPriceIsStrictPositive, [
812 1082 'errorField' => 'prix_ht',
813 1083 //'message' => 'Le matériel ne peut pas être inventoriable et ne pas avoir de prix'
814 1084 'message' => "Le montant doit être supérieur à 0 €"
815 1085 ]);
  1086 + */
816 1087  
817 1088  
818 1089  
... ... @@ -1068,6 +1339,30 @@ class MaterielsTable extends AppTable
1068 1339 $fournisseur_asis = $entity->fournisseur ? $entity->fournisseur['name'] : '';
1069 1340 // Enlever les espaces superflus
1070 1341 $fournisseur = trim($fournisseur_asis);
  1342 +
  1343 + // Si champ fournisseur obligatoire, vérification qu'il est bien rempli (ou emission d'une erreur)
  1344 + //if (IP2I && $entity->fournisseur && $fournisseur == '') {
  1345 + if (
  1346 + // - fournisseur_id est obligatoire pour le statut courant du matos
  1347 + //in_array( 'fournisseur_id', array_keys($this->getMandatoryFieldsLot1()) )
  1348 + in_array( 'fournisseur_id', array_keys($this->getMandatoryFieldsForMaterielStatus($entity->status)) )
  1349 + // - et on est en mode add ou edit (le champ fournisseur existe)
  1350 + && $entity->fournisseur
  1351 + // - et le champ fournisseur est vide
  1352 + && $fournisseur == ''
  1353 + ) {
  1354 + //debug("champ fournisseur vide !");exit;
  1355 + //$msgError1 = "Pour valider un matériel, le champ suivant ne doit pas être vide : ".'fourniss'.' du matériel';
  1356 + //$this->Flash->error($msgError1);
  1357 + /* MARCHE PAS POURQUOI ?
  1358 + $materiel->setError($field, 'Ce champ ne doit pas être vide');
  1359 + $materiel->setError('numero_commande', 'Ce champ ne doit pas être vide');
  1360 + */
  1361 + $entity->setError('fournisseur', 'Ce champ ne doit pas être vide');
  1362 +
  1363 + return false;
  1364 + }
  1365 +
1071 1366 //debug($fournisseur);
1072 1367 //debug($entity->fournisseur_orig);
1073 1368 //exit;
... ...
src/Template/Element/materiels_list.ctp
... ... @@ -215,7 +215,7 @@ $materiels = $materiels;
215 215 -->
216 216 <th><?= $this->Paginator->sort('Categories.nom', 'Catégorie') ?></th>
217 217  
218   - <th><?= $this->Paginator->sort('status', "Statut (CVTA)") ?></th>
  218 + <th><?= $this->Paginator->sort('status', 'Statut') ?></th>
219 219  
220 220 <th><?= $this->Paginator->sort('date_acquisition', 'Date Achat') ?></th>
221 221  
... ... @@ -318,23 +318,30 @@ $materiels = $materiels;
318 318  
319 319 <?php
320 320 // (4) COLONNE MATERIEL STATUS : C/V/TBA/A
  321 + $statut = $materiel->getNiceStatus();
  322 + /*
321 323 switch (h($materiel->status)) {
322 324 case 'CREATED':
323   - $statut = 'C';
  325 + //$statut = 'C';
  326 + $statut = 'A Valider';
324 327 break;
325 328 case 'VALIDATED':
326   - $statut = 'V';
  329 + //$statut = 'V';
  330 + $statut = 'Validé';
327 331 break;
328 332 case 'TOBEARCHIVED':
329   - $statut = 'T';
  333 + //$statut = 'T';
  334 + $statut = 'A sortir';
330 335 break;
331 336 case 'ARCHIVED':
332   - $statut = 'A';
  337 + //$statut = 'A';
  338 + $statut = 'Archivé';
333 339 break;
334 340 default:
335 341 $statut = '';
336 342 break;
337 343 }
  344 + */
338 345 ?>
339 346 <td class="smallText" <?=$color?>><?=$statut?></td>
340 347  
... ...
src/Template/Emprunts/add_edit.ctp
... ... @@ -139,7 +139,7 @@ else {
139 139  
140 140 // - Nom emprunt (facultatif)
141 141 echo $this->Form->control('nom', [
142   - 'label' => "Label (facultatif)",
  142 + 'label' => "Intitulé (facultatif)",
143 143 'placeholder' => 'Label pour désigner cet emprunt (facultatif)',
144 144 ]);
145 145  
... ...
src/Template/Emprunts/index.ctp
... ... @@ -6,7 +6,7 @@
6 6 <tr>
7 7 <th class="actions"><?= __('') ?></th>
8 8  
9   - <th><?= $this->Paginator->sort('id', '') ?></th>
  9 + <th><?= $this->Paginator->sort('id', 'Intitulé') ?></th>
10 10 <th><?= $this->Paginator->sort('materiel_id', 'Matériel') ?></th>
11 11 <!-- (EP 202007) inutile
12 12 <th><= $this->Paginator->sort('numero_laboratoire', 'N° interne (labo)') ?></th>
... ...
src/Template/Emprunts/view.ctp
... ... @@ -58,7 +58,7 @@ $status = $entity-&gt;status_from_dates;
58 58 </tr>
59 59 <?php
60 60  
61   - $displayElement(__('Label emprunt'), h($entity->nom));
  61 + $displayElement(__('Intitulé'), h($entity->nom));
62 62  
63 63 $displayElement(__('Materiel concerné'), $entity->has('materiel') ? $this->Html->link($entity->materiel->designation, [
64 64 'controller' => 'Materiels',
... ...
src/Template/Materiels/add_edit.ctp
... ... @@ -896,7 +896,7 @@ if (isset($cpMateriel)) {
896 896 </datalist>
897 897 <?php
898 898 if ($USER_IS_ADMIN_OR_MORE) {
899   - echo $this->Html->link('Gérer les Fournisseurs', [
  899 + echo '<br>'.$this->Html->link('Gérer les Fournisseurs', [
900 900 'controller' => 'Fournisseurs',
901 901 'action' => 'index'
902 902 ]);
... ...
src/Template/Materiels/index.ctp
... ... @@ -223,10 +223,10 @@ $displayStatusButtons = function($SELECTED_STATUS, $params, $nbMateriels, $statu
223 223  
224 224 $statuses = [
225 225 'TOUS' => [$b_all, 'TOUS', 'Tous les matériels', 5],
226   - 'CREATED' => [$b_cre, 'A valider', 'Seulement les matériels créés', 5],
227   - 'VALIDATED' => [$b_val, 'Validés', "Seulement les matériels validés", 5],
228   - 'TOBEARCHIVED' => [$b_toarc, 'A sortir', "Seulement les matériels à archiver", 5],
229   - 'ARCHIVED' => [$b_arc, 'Archivés', "Seulement les matériels sortis de l'inventaire", 0],
  226 + 'CREATED' => [$b_cre, 'À VALIDER', 'Seulement les matériels créés', 5],
  227 + 'VALIDATED' => [$b_val, 'VALIDÉS', "Seulement les matériels validés", 5],
  228 + 'TOBEARCHIVED' => [$b_toarc, 'À SORTIR', "Seulement les matériels à archiver", 5],
  229 + 'ARCHIVED' => [$b_arc, 'ARCHIVÉS', "Seulement les matériels sortis de l'inventaire", 0],
230 230 ];
231 231 // https://book.cakephp.org/3/en/views/helpers/html.html#creating-links
232 232 foreach ($statuses as $status=>$status_params) {
... ...
src/Template/Materiels/view.ctp
... ... @@ -677,7 +677,8 @@ $CAN_PRINT_LABEL = $IS_VALIDATED &amp;&amp; $configuration-&gt;hasPrinter &amp;&amp; $USER_IS_ADMIN
677 677 }
678 678 $displayElement(__('Date fin de garantie'), h($entity->date_fin_garantie), $style);
679 679  
680   - $displayElement(__('Statut'), h($entity->status));
  680 + //$displayElement(__('Statut'), h($entity->status));
  681 + $displayElement(__('Statut'), h($entity->getNiceStatus($entity->status)));
681 682  
682 683 $displayElement(__('Date de création'), h($entity->created));
683 684 if ($entity->status == 'VALIDATED') {
... ...