Commit d6da8a5492b574a48b10ae09cbd204ebb8310121

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

Nouveau workflow avec Commande (& bugfixes)

Amélioration : Nouveau workflow incluant la "commande d'un matériel" :
		- nouveau bouton "Commander"
		- nouveau statut "TOBEORDERED" (à commander)
		- L'étape de commande est optionnelle

Bugfixes :
		- lier un doc à un matos (erreur sur doc qui n'est pas une photo)
		- supprimer un doc attaché générait une erreur

=> v4.108.25-3.7.9
CHANGELOG
... ... @@ -11,6 +11,18 @@ CHANGEMENTS
11 11  
12 12 ======= NEWS =======
13 13  
  14 +
  15 +-------
  16 +06/09/2021 NEWS#7 (v5.0.0) :
  17 +
  18 +- Nouveau workflow incluant la "commande d'un matériel" :
  19 + - nouveau bouton "Commander"
  20 + - nouveau statut "TOBEORDERED" (à commander)
  21 + - L'étape de commande est optionnelle
  22 +
  23 +- Champs obligatoires désormais configurables (pour la saisie d'un matériel)
  24 +
  25 +
14 26 -------
15 27 31/03/2021 NEWS#6 (v4.108.18) :
16 28  
... ... @@ -18,7 +30,7 @@ CHANGEMENTS
18 30  
19 31  
20 32 -------
21   -FÉVRIER 2021 (v4.108.0-3.7.9) - GROSSE AMÉLIORATION DE LA PHASE INSTALLATION (FROM SCRATCH) :
  33 +FÉVRIER 2021 (v4.108.0) - GROSSE AMÉLIORATION DE LA PHASE INSTALLATION (FROM SCRATCH) :
22 34  
23 35 - Documentation en ligne (install et technique) grandement mise à jour, pour une progression plus logique
24 36 - Install from scratch OK !
... ... @@ -27,14 +39,6 @@ FÉVRIER 2021 (v4.108.0-3.7.9) - GROSSE AMÉLIORATION DE LA PHASE INSTALLATION (
27 39 - Bugfix plusieurs erreurs qui apparaissent quand il n'y a aucun matériel dans la BD...
28 40 - ...
29 41  
30   --------
31   -NOVEMBRE 2020 - MARS 2021 : Chantier en cours pour arriver à la v5 avec le nouveau workflow de commande
32   -
33   -ROADMAP IRAP :
34   -- Janvier : test en production
35   -- Février : présentation aux JST
36   -- Mars : usage obligatoire pour toute commande
37   -
38 42  
39 43 -------
40 44 30/11/2020 NEWS#5 (v4.107.21) :
... ... @@ -44,7 +48,7 @@ ROADMAP IRAP :
44 48  
45 49  
46 50 -------
47   -20/10/2020 NEWS#4 (v4.105.29-3.7.9) :
  51 +20/10/2020 NEWS#4 (v4.105.29) :
48 52  
49 53 Page "Gestion des fournisseurs" enrichie (/fournisseurs/index) avec :
50 54 => (superadmin) Bouton "Nettoyer la liste complète" (nettoyage "automagique" de la liste par suppression intelligente des doublons et espaces en trop)
... ... @@ -331,8 +335,18 @@ Commencer à implémenter le nouveau workflow v5 :
331 335 ======= CHANGES =======
332 336  
333 337 -------
  338 +06/09/2021 v4.108.25-3.7.9
  339 + - (b) BUGfixes :
  340 + - lier un doc à un matos (erreur sur doc qui n'est pas une photo)
  341 + - supprimer un doc attaché générait une erreur
  342 + - (i) Nouveau workflow incluant la "commande d'un matériel" :
  343 + - nouveau bouton "Commander"
  344 + - nouveau statut "TOBEORDERED" (à commander)
  345 + - L'étape de commande est optionnelle
  346 +
  347 +-------
334 348 02/09/2021 v4.108.24-3.7.9
335   - - BUGfix (le fichier de config était constamment écrasé par la version par défaut)
  349 + - (b) BUGfix (le fichier de config était constamment écrasé par la version par défaut)
336 350 - Ajout plugin guemidiborhane/yaml-config pour gérer les configs yaml (remplace l'obsolète chobo1210/yaml)
337 351 - Liste des champs obligatoires de l'entité Materiels => gérée via fichier config YAML
338 352 - (Liste des autorisations AUSSI en cours de migration pour être gérée via fichier config YAML)
... ...
README.md
... ... @@ -52,8 +52,8 @@ Logiciel testé et validé sur les configurations suivantes :
52 52  
53 53 --------------------------------------------------------------------------------------------
54 54  
55   -Date: 02/09/2021
56   -Version: v4.108.24-3.7.9
  55 +Date: 06/09/2021
  56 +Version: v5.0.0-3.7.9
57 57  
58 58  
59 59  
... ...
config/app_labinvent_mandatory_fields.default.yml
1 1  
  2 +
  3 +# Activer la possibilité de commander un matériel (au service gestion) en cliquant sur un bouton "Commander" ?
  4 +# L'étape "A commander" (status TOBEORDERED) devient alors une étape intermédiaire OPTIONNELLE entre CREATED et VALIDATED
  5 +# Les transitions de statut d'un materiel sont alors : CREATED => [ TEBEORDERED (à commander) ] => VALIDATED => TOBEARCHIVED => ARCHIVED
  6 +#
  7 +HAS_ORDER_BUTTON: true
  8 +
  9 +
2 10 # Infos minimum obligatoires pour créer une fiche Matériel
3 11 #MANDATORY_FIELDS_LOT0: []
4 12 MANDATORY_FIELDS_LOT0:
... ... @@ -13,15 +21,22 @@ MANDATORY_FIELDS_LOT0:
13 21  
14 22 sur_categorie_id: 'Domaine'
15 23 categorie_id: 'Catégorie'
  24 +
  25 + # - Utilisateur
  26 + nom_user: "Nom de l'utilisateur"
  27 +
  28 + # - Acheteur
  29 + nom_responsable: 'Nom du responsable'
  30 + # (rempli automatiquement)
  31 + email_responsable: 'Email du responsable'
16 32  
17 33 # Calculé auto au moment du save()
18 34 #'numero_laboratoire',
19 35  
20 36 # ******* END OF $MANDATORY_FIELDS_LOT0 ********
  37 +
21 38  
22   -
23   -
24   -# Infos obligatoires pour le LOT1 (pour passer la commande)
  39 +# Infos obligatoires pour le LOT1 (pour passer la commande, étape optionnelle)
25 40 # Ne mettre ici QUE les infos obligatoires SUPPLÉMENTAIRES à celles de LOT0
26 41 MANDATORY_FIELDS_LOT1:
27 42  
... ... @@ -31,23 +46,23 @@ MANDATORY_FIELDS_LOT1:
31 46  
32 47 #'hors_service', // O/N
33 48  
34   - designation: 'Désignation'
  49 + ##designation: 'Désignation'
35 50  
36   - description: 'Description'
  51 + ##description: 'Description'
37 52  
38 53 #'permanent',
39 54 #'will_stay', // O/N
40 55  
41   - sur_categorie_id: 'Domaine'
42   - categorie_id: 'Catégorie'
  56 + ##sur_categorie_id: 'Domaine'
  57 + ##categorie_id: 'Catégorie'
43 58  
44 59 # - Utilisateur
45   - nom_user: "Nom de l'utilisateur de ce matériel"
  60 + #nom_user: "Nom de l'utilisateur de ce matériel"
46 61  
47 62 # - Acheteur
48   - nom_responsable: 'Nom du responsable'
  63 + #nom_responsable: 'Nom du responsable'
49 64 # (rempli automatiquement)
50   - email_responsable: 'Email du responsable'
  65 + #email_responsable: 'Email du responsable'
51 66  
52 67 # Calculé auto au moment du save()
53 68 #'numero_laboratoire',
... ... @@ -59,14 +74,13 @@ MANDATORY_FIELDS_LOT1:
59 74 # Optionnel car par défaut = acheteur
60 75 #'resp_credit' => 'Responsable du crédit',
61 76  
62   -
63 77 #TODO: a remettre ? avec "je ne sais pas"
64   - #/////'gestionnaire_id' => 'Gestionnaire de référence',
65   -
  78 + gestionnaire_id: 'Gestionnaire de référence'
66 79  
67   - #'fournisseur',
  80 + #'fournisseur'
68 81  
69   - #'devis joint',
  82 + # Devis joint : c'est un champ virtuel, il n'existe pas physiquement (sauf dans la table Documents)
  83 + DEVIS: 'Devis'
70 84  
71 85 # Utilisé par la Gestion pour remplir le champ eotp
72 86 budgets: 'Budgets'
... ... @@ -94,6 +108,7 @@ MANDATORY_FIELDS_LOT2:
94 108  
95 109 site_id: 'Site'
96 110  
  111 + #TODO: seulement si prix > 10K€
97 112 lieu_detail: 'Lieu de stockage'
98 113  
99 114 #// INFOS ADMINISTRATIVES :
... ...
src/Controller/AppController.php
... ... @@ -3585,11 +3585,14 @@ class AppController extends Controller
3585 3585  
3586 3586 // Par exemple, pour les actions documents/mail-devis ou users/login ...
3587 3587 if (!$entity && $this->e_id) $entity = $this->getEntity($this->e_id);
3588   - //debug($entity); exit;
  3588 +
  3589 + // Action
  3590 + //$action = $this->request->getAttribute('params')['action']; // add or edit or delete or ...
  3591 + $action = $this->a;
3589 3592  
3590 3593 // Cas particulier pour un Document, on veut aussi son type (bon commande, bon livraison, ...)
3591 3594 if ($entity instanceof Document) {
3592   - $entity = $this->getEntity($entity->id, false, ['TypeDocuments']);
  3595 + if ($action != 'delete') $entity = $this->getEntity($entity->id, false, ['TypeDocuments']);
3593 3596 $type_doc = $entity->type_document->nom;
3594 3597 $format = $entity->type_doc;
3595 3598 $doc_infos = " ($type_doc - $format)";
... ... @@ -3602,10 +3605,12 @@ class AppController extends Controller
3602 3605 else
3603 3606 $entity_name = null;
3604 3607  
3605   - // Action
3606   - //$action = $this->request->getAttribute('params')['action']; // add or edit or delete or ...
3607   - $action = $this->a;
3608   - //debug($action); exit;
  3608 +
  3609 + /*
  3610 + debug($entity);
  3611 + debug($action);
  3612 + exit;
  3613 + */
3609 3614  
3610 3615  
3611 3616 /*
... ... @@ -3677,7 +3682,8 @@ class AppController extends Controller
3677 3682 }
3678 3683 elseif ($IS_ENTITY_LINKED_TO_MATERIEL)
3679 3684 $materiel = $this->getCurrentEntityRelatedMateriel($entity->materiel_id, $contain);
3680   -
  3685 +
  3686 +
3681 3687  
3682 3688 /*
3683 3689 * 3) LOG (si log demandé)
... ... @@ -3736,6 +3742,7 @@ class AppController extends Controller
3736 3742 if (!$DEBUG)
3737 3743 if (! $this->isNotifierActionSendingEmail($action) ) return null;
3738 3744  
  3745 +
3739 3746 /*
3740 3747 * 4.A - CRÉATION DU MAIL (sujet et body)
3741 3748 *
... ... @@ -3823,8 +3830,17 @@ class AppController extends Controller
3823 3830 if ($msg_detail) $msg_mail .= $msg_detail;
3824 3831  
3825 3832 } // Entité Materiel ou associée
  3833 +
  3834 + // - (3a) Commande de matériel : commentaire spécial pour le gestionnaire
  3835 + //sdebug($action);
  3836 + if ($action=='statusTobeordered') {
  3837 + $msg_mail .= "\n\n";
  3838 + $msg_mail .= "\n\nMERCI DE BIEN VOULOIR PASSER COMMANDE DE CE MATÉRIEL";
  3839 + $msg_mail .= " (un devis a normalement été joint par l'acheteur à la fiche matériel - url ci-dessus).";
  3840 + $msg_mail .= "\n\n";
  3841 + }
3826 3842  
3827   - // - (3) Matos only (sauf delete, dévalidé, TBA et archive) : "Veuillez vérifier la fiche matériel..."
  3843 + // - (3b) Matos only (sauf delete, dévalidé, TBA et archive) : "Veuillez vérifier la fiche matériel..."
3828 3844 $actions_no_need_to_be_checked = ['view', 'index', 'delete', 'statusCreated', 'statusTobearchived', 'statusArchived'];
3829 3845 if ( $IS_ENTITY_MATERIEL && !in_array($action,$actions_no_need_to_be_checked) )
3830 3846 $msg_mail .= "\n\nVeuillez vérifier et compléter si besoin la fiche correspondante.";
... ... @@ -3982,11 +3998,13 @@ class AppController extends Controller
3982 3998 $mailList[] = 'elodie.bourrec@irap.omp.eu';
3983 3999 $mailList[] = 'Elodie.bourrec@irap.omp.eu';
3984 4000 */
  4001 +
3985 4002 // - (1) On supprime les doublons
3986 4003 // On met tous les mails en minuscule car sinon certains doublons pourraient ne pas être identifiés...
3987 4004 $mailList = array_map('strtolower', $mailList);
3988 4005 $mailList = array_unique($mailList);
3989 4006 //$DEBUG && debug($mailList);
  4007 +
3990 4008 // - (2) On supprime l'auteur de l'action le cas échéant
3991 4009 //if ($DEBUG) debug($this->u->email);
3992 4010 $found = array_search(strtolower($this->u->email), $mailList);
... ... @@ -4041,8 +4059,8 @@ class AppController extends Controller
4041 4059 ////} // entity not null
4042 4060  
4043 4061 } //foreach ($mailList as $mail)
4044   - $DEBUG && debug($mailList);
4045   - $DEBUG && exit;
  4062 + $DEBUG && debug("Liste destinataires :"); debug($mailList);
  4063 + //$DEBUG && exit;
4046 4064  
4047 4065 return $mailList;
4048 4066  
... ...
src/Controller/DocumentsController.php
... ... @@ -604,10 +604,15 @@ class DocumentsController extends AppController
604 604 'post',
605 605 'delete'
606 606 ]);
607   - $document = $this->Documents->get($id);
  607 +
  608 + //$document = $this->Documents->get($id);
  609 + $document = $this->Documents->get($id, [
  610 + 'contain' => ['TypeDocuments']
  611 + ]);
  612 + //$document = $this->getEntity($id, false, ['TypeDocuments']);
608 613  
609 614 if ($document->photo) {
610   - $materielTable = TableRegistry::get('Materiels');
  615 + $materielTable = TableRegistry::getTableLocator()->get('Materiels');
611 616 $materiel = $materielTable->get($document->materiel_id);
612 617  
613 618 $materiel->set('photo_id', null);
... ...
src/Controller/MaterielsController.php
... ... @@ -12,6 +12,7 @@ use Cake\I18n\FrozenDate;
12 12 use Cake\Database\Expression\QueryExpression;
13 13 use Cake\Database\Query;
14 14 use phpDocumentor\Reflection\Types\True_;
  15 +use App\Model\Table\MaterielsTable;
15 16  
16 17 //use App\Controller\DocumentsController;
17 18 //App::import('Controller', 'Documents');
... ... @@ -87,28 +88,37 @@ class MaterielsController extends AppController {
87 88  
88 89 ]; // SORT_LIST_FOR_SEARCH
89 90  
90   - const CREATED = 1;
  91 + //const CREATED = 1;
  92 + const CREATED = 0;
  93 + const TOBEORDERED = 1;
91 94 const VALIDATED = 2;
92 95 const TOBEARCHIVED = 3;
93 96 const ARCHIVED = 4;
94 97 const statuses = [
95 98 'CREATED' => self::CREATED,
  99 + 'TOBEORDERED' => self::TOBEORDERED,
96 100 'VALIDATED' => self::VALIDATED,
97 101 'TOBEARCHIVED' => self::TOBEARCHIVED,
98 102 'ARCHIVED' => self::ARCHIVED
99 103 ];
100 104 const statuses_color = [
101   - 'CREATED' => 'blue',
  105 + //'CREATED' => 'blue',
  106 + 'CREATED' => 'orange',
  107 + 'TOBEORDERED' => 'red',
102 108 'VALIDATED' => 'black',
103   - 'TOBEARCHIVED' => 'orange',
104   - 'ARCHIVED' => 'red'
  109 + 'TOBEARCHIVED' => 'red',
  110 + 'ARCHIVED' => 'blue'
105 111 ];
  112 + /*
106 113 const statuses_display = [
107   - 'CREATED' => 'A commander',
  114 + //'CREATED' => 'A commander',
  115 + 'CREATED' => 'Fiche créée',
  116 + 'TOBEORDERED' => 'Commandé',
108 117 'VALIDATED' => 'Livré, validé',
109 118 'TOBEARCHIVED' => 'A archiver',
110 119 'ARCHIVED' => 'Archivé'
111 120 ];
  121 + */
112 122  
113 123 // - ATTRIBUTS VARIABLES
114 124  
... ... @@ -124,6 +134,7 @@ class MaterielsController extends AppController {
124 134  
125 135 private $NOTARCHIVED = [
126 136 'CREATED',
  137 + 'TOBEORDERED',
127 138 'VALIDATED',
128 139 'TOBEARCHIVED'
129 140 ];
... ... @@ -308,6 +319,7 @@ class MaterielsController extends AppController {
308 319  
309 320 // $this->layout = 'default';
310 321 $this->set('CREATED', self::CREATED);
  322 + $this->set('TOBEORDERED', self::TOBEORDERED);
311 323 $this->set('VALIDATED', self::VALIDATED);
312 324 $this->set('TOBEARCHIVED', self::TOBEARCHIVED);
313 325 $this->set('ARCHIVED', self::ARCHIVED);
... ... @@ -372,6 +384,7 @@ class MaterielsController extends AppController {
372 384 */
373 385 $this->setActionsNounAndPastVerb([
374 386 'statusCreated' => ['Dé-validation','dé-validé'],
  387 + 'statusTobeordered' => ['COMMANDE','commandé'],
375 388 'statusValidated' => ['Validation','validé'],
376 389 //TODO: spécial
377 390 'statusTobearchived' => ["Demande d'archivage","demandé l'archivage", '', "d'un "],
... ... @@ -401,6 +414,7 @@ class MaterielsController extends AppController {
401 414  
402 415 // status changed
403 416 'statusCreated' => 'log',
  417 + 'statusTobeordered' => 'both',
404 418 'statusValidated' => 'both',
405 419 'statusTobearchived' => 'both',
406 420 'statusArchived' => 'both',
... ... @@ -463,8 +477,14 @@ class MaterielsController extends AppController {
463 477 );
464 478 */
465 479  
466   - // - Action 'edit' (modif d'un matériel)
467   - $this->setAuthorizationsForAction('edit (modifier)', ['CREATED',0], [
  480 + /*
  481 + - Action 'edit' (modif d'un matériel)
  482 + (EP) Changé depuis 2021-09 car désormais on peut TOUJOURS modifier un matériel (sauf si ARCHIVED)
  483 + tant que certains champs restent obligatoires
  484 + (les champs obligatoires correspondant au statut en cours du matos)
  485 + */
  486 + //$this->setAuthorizationsForAction('edit (modifier)', ['CREATED',0], [
  487 + $this->setAuthorizationsForAction('edit (modifier)', ['NOT ARCHIVED',0], [
468 488 'user' => ['CREATED',1],
469 489 'resp' => 'user',
470 490 //'resp' => -1,
... ... @@ -474,10 +494,10 @@ class MaterielsController extends AppController {
474 494 //$super = 'default' // + champs techniques
475 495 ]);
476 496  
477   - // Action 'delete' (suppression d'un matériel)
  497 + // - Action 'delete' (suppression d'un matériel)
478 498 $this->setAuthorizationsForAction('delete (supprimer)', ['CREATED',1]);
479 499  
480   - // Action 'devalidate' ou 'invalidate' (repasser le matériel au statut 'CREATED', c'est à dire le dé-valider ou l'invalider)
  500 + // - Action 'devalidate' ou 'invalidate' (repasser le matériel au statut 'CREATED', c'est à dire le dé-valider ou l'invalider)
481 501 // (VALIDATED ou TBA ou ARCHIVED) => CREATED
482 502 //$this->setAuthorizationsForAction('devalidate',
483 503 $this->setAuthorizationsForAction('statusCreated (dévalider)', ['NOT CREATED',0], [
... ... @@ -485,8 +505,8 @@ class MaterielsController extends AppController {
485 505 'resp' => ['NOT CREATED',1]
486 506 ]);
487 507  
488   - // Action 'upgrade' (avancement du statut d'un matériel)
489   - // CREATED => VALIDATED => TBA => ARCHIVED
  508 + // - Action 'upgrade' (avancement du statut d'un matériel)
  509 + // CREATED [=> TBO] => VALIDATED => TBA => ARCHIVED
490 510 /*
491 511 $this->setAuthorizationsForAction('upgrade', ['NOT ARCHIVED',0], [ // En fait, l'action fait juste passer au statut "suivant"
492 512 //$default = ['PREVIOUS',0], // le matériel doit avoir le statut "précédent" du statut actuel
... ... @@ -496,20 +516,25 @@ class MaterielsController extends AppController {
496 516 'resp' => 'user'
497 517 ]);
498 518 */
499   - // - Validation d'un materiel (passe à VALIDATED) : CREATED => VALIDATED
500   - $this->setAuthorizationsForAction('statusValidated (valider)', ['CREATED',0], [
  519 + // - Commande d'un materiel => TBO
  520 + $this->setAuthorizationsForAction('statusTobeordered (commander)', ['CREATED',0], [
  521 + 'user' => ['CREATED',1],
  522 + //'resp' => -1 // interdit
  523 + ]);
  524 + // - Validation d'un materiel => VALIDATED
  525 + $this->setAuthorizationsForAction('statusValidated (valider)', ['CREATED||TOBEORDERED',0], [
501 526 'user' => -1, // interdit
502 527 'resp' => -1 // interdit
503 528 ]);
504   - // - Demande d'archivage : VALIDATED => TBA
505   - $this->setAuthorizationsForAction("statusTobearchived (demander l'archivage)", ['VALIDATED',0], [
  529 + // - Demande d'archivage => TBA
  530 + $this->setAuthorizationsForAction("statusTobearchived (demander l'archivage)", ['VALIDATED',0], [
506 531 //$user = ['default',1],
507 532 'user' => ['VALIDATED',1],
508 533 //$resp = ['default',1]
509 534 //$resp = ['VALIDATED',1]
510 535 'resp' => 'user'
511 536 ]);
512   - // - Archivage : TBA => ARCHIVED
  537 + // - Archivage => ARCHIVED
513 538 $this->setAuthorizationsForAction('statusArchived (archiver)', ['TOBEARCHIVED',0], [
514 539 'user' => -1, // interdit
515 540 'resp' => -1 // interdit
... ... @@ -950,6 +975,7 @@ class MaterielsController extends AppController {
950 975 */
951 976 }
952 977 public function isCreated($id=null) { return $this->hasStatus($id, 'CREATED'); }
  978 + public function isToBeOrdered($id=null) { return $this->hasStatus($id, 'TOBEORDERED'); }
953 979 public function isValidated($id=null) { return $this->hasStatus($id, 'VALIDATED'); }
954 980 public function isToBeArchived($id=null) { return $this->hasStatus($id, 'TOBEARCHIVED'); }
955 981 public function isArchived($id=null) { return $this->hasStatus($id, 'ARCHIVED'); }
... ... @@ -984,11 +1010,18 @@ class MaterielsController extends AppController {
984 1010 */
985 1011 // (EP 202007 NEW way pour gérer les statuts : /materiels/index?status=VALIDATED)
986 1012 $SELECTED_STATUS = $this->request->getQuery('status');
987   - if ( $SELECTED_STATUS && in_array($SELECTED_STATUS,['TOUS','CREATED','VALIDATED','TOBEARCHIVED','ARCHIVED']) ) {
988   - //$conditions['Materiels.sur_categorie_id'] = $domain_id;
989   - $conditions = [
990   - 'Materiels.status =' => $SELECTED_STATUS
991   - ];
  1013 + if ( $SELECTED_STATUS && in_array($SELECTED_STATUS,['TOUS','CREATED','TOBEORDERED','VALIDATED','TOBEARCHIVED','ARCHIVED']) ) {
  1014 + if ($SELECTED_STATUS=='CREATED')
  1015 + $conditions[] = [
  1016 + 'OR' => [
  1017 + 0 => ['Materiels.status =' => $SELECTED_STATUS],
  1018 + 1 => ['Materiels.status =' => 'TOBEORDERED']
  1019 + ]
  1020 + ];
  1021 + else
  1022 + $conditions = [
  1023 + 'Materiels.status =' => $SELECTED_STATUS
  1024 + ];
992 1025 }
993 1026 else $SELECTED_STATUS = null;
994 1027 $this->set(compact('SELECTED_STATUS'));
... ... @@ -1481,6 +1514,7 @@ class MaterielsController extends AppController {
1481 1514 'materiels'
1482 1515 ]);
1483 1516 */
  1517 + //debug($conditions);
1484 1518  
1485 1519 } // index()
1486 1520  
... ... @@ -1574,10 +1608,11 @@ class MaterielsController extends AppController {
1574 1608 $IS_ARCHIVED = ($materiel->status == 'ARCHIVED');
1575 1609 */
1576 1610 $IS_CREATED = $e->is_created;
  1611 + $IS_TOBEORDERED = $e->is_tobeordered;
1577 1612 $IS_VALIDATED = $e->is_validated;
1578 1613 $IS_TOBEARCHIVED = $e->is_tobearchived;
1579 1614 $IS_ARCHIVED = $e->is_archived;
1580   - $this->set(compact('IS_CREATED', 'IS_VALIDATED', 'IS_TOBEARCHIVED', 'IS_ARCHIVED'));
  1615 + $this->set(compact('IS_CREATED', 'IS_TOBEORDERED', 'IS_VALIDATED', 'IS_TOBEARCHIVED', 'IS_ARCHIVED'));
1581 1616  
1582 1617  
1583 1618 // 1) DROITS SUR LE MATERIEL VU
... ... @@ -1604,7 +1639,9 @@ class MaterielsController extends AppController {
1604 1639 $this->d("can print ? "); $this->d2($CAN_PRINT_LABEL);
1605 1640 $this->set(compact('CAN_EDIT', 'CAN_DELETE', 'CAN_COPY', 'CAN_PRINT_LABEL'));
1606 1641  
1607   - // - valider, devalider, tba, archiver
  1642 + // - commander, valider, devalider, tba, archiver
  1643 +
  1644 + $CAN_ORDER = $this->isAuthorizedActionForCurrentUser('statusTobeordered', $id);
1608 1645 /*
1609 1646 $CAN_VALIDATE_OR_INVALIDATE = $this->USER_IS_ADMIN_OR_MORE || ( $materiel->materiel_administratif==0 && $USER_IS_RESPONSABLE_AND_SAME_GROUP_AS_MATERIEL );
1610 1647 $CAN_VALIDATE = $IS_CREATED && $CAN_VALIDATE_OR_INVALIDATE;
... ... @@ -1627,7 +1664,9 @@ class MaterielsController extends AppController {
1627 1664 //$CAN_ARCHIVE = $this->isAuthorized($u,'statusArchived');
1628 1665 //$CAN_ARCHIVE = $IS_TOBEARCHIVED && $this->USER_IS_ADMIN_OR_MORE;
1629 1666 $this->d("can CAN_ARCHIVE ? "); $this->d2($CAN_ARCHIVE);
1630   - $this->set(compact('CAN_VALIDATE', 'CAN_INVALIDATE', 'CAN_TBA', 'CAN_ARCHIVE'));
  1667 + $this->set(compact(
  1668 + 'CAN_ORDER', 'CAN_VALIDATE', 'CAN_INVALIDATE', 'CAN_TBA', 'CAN_ARCHIVE'
  1669 + ));
1631 1670  
1632 1671 // - Emprunter et Suivre
1633 1672 //$CAN_LEND = $CAN_FOLLOW = true;
... ... @@ -1655,7 +1694,13 @@ class MaterielsController extends AppController {
1655 1694 $this->d("CAN_EDIT_DOC_SORTIE ? "); $this->d2($CAN_EDIT_DOC_SORTIE);
1656 1695 //$CAN_LEND = $CAN_DO_SUIVI = $CAN_ATTACH_A_DOC = $CAN_EDIT_DOC_ADMISSION = $CAN_EDIT_DOC_SORTIE = TRUE;
1657 1696  
1658   - $this->set(compact('CAN_LEND', 'CAN_DO_SUIVI', 'CAN_ATTACH_A_DOC', 'CAN_EDIT_DOC_ADMISSION', 'CAN_EDIT_DOC_SORTIE'));
  1697 + $this->set(compact(
  1698 + 'CAN_LEND',
  1699 + 'CAN_DO_SUIVI',
  1700 + 'CAN_ATTACH_A_DOC',
  1701 + 'CAN_EDIT_DOC_ADMISSION',
  1702 + 'CAN_EDIT_DOC_SORTIE'
  1703 + ));
1659 1704  
1660 1705 // Current user is creator or owner of current materiel
1661 1706 /*
... ... @@ -1792,10 +1837,11 @@ class MaterielsController extends AppController {
1792 1837  
1793 1838 $entity = $materiel;
1794 1839 $status_color = self::statuses_color[$entity->status];
1795   - $status_display = self::statuses_display[$entity->status];
  1840 + //$status_display = self::statuses_display[$entity->status];
1796 1841 $this->set(compact('entity'));
1797 1842 $this->set(compact(
1798   - 'status_color', 'status_display',
  1843 + 'status_color',
  1844 + //'status_display',
1799 1845 'sites', 'typeDocuments'
1800 1846 //'materiel', // @deprecated
1801 1847 //'fournisseurs'
... ... @@ -2112,6 +2158,7 @@ class MaterielsController extends AppController {
2112 2158 * On définit les infos obligatoires et on vérifie qu'elles sont bien présentes dans le POST
2113 2159 */
2114 2160  
  2161 + /*
2115 2162 // Attributs obligatoires pour la phase COMMANDE
2116 2163 //$LOT1 = $this->Materiels->MANDATORY_FIELDS_LOT1;
2117 2164 $LOT1 = $this->Materiels->getMandatoryFieldsForLot(1);
... ... @@ -2120,6 +2167,7 @@ class MaterielsController extends AppController {
2120 2167 //$LOT2 = $this->Materiels->MANDATORY_FIELDS_LOT2;
2121 2168 $LOT2 = $this->Materiels->getMandatoryFieldsForLot(2);
2122 2169  
  2170 + //TODO 202109
2123 2171 // Seulement si prix > 10K€ : exiger la facture jointe et le n° série
2124 2172 if ($materiel->prix_ht > 10000) {
2125 2173 //$LOT2[] = 'facture jointe';
... ... @@ -2131,6 +2179,11 @@ class MaterielsController extends AppController {
2131 2179 // Champs obligatoires = LOT1 si CREATED, LOT2 sinon (>CREATED, c'est à dire VALIDATED ou plus)
2132 2180 $mandatory_fields = ($materiel->status == 'CREATED') ? $LOT1 : $LOT2;
2133 2181 //debug($mandatory_fields); exit;
  2182 + */
  2183 + //$mandatory_fields = MaterielsTable::getMandatoryFieldsForMaterielStatus($materiel->status);
  2184 + $mandatory_fields = $this->Materiels->getMandatoryFieldsForMateriel($materiel);
  2185 + //$mandatory_fields = $this->Materiels->getMandatoryFieldsForMaterielStatus($materiel->status);
  2186 + //debug($mandatory_fields); exit;
2134 2187  
2135 2188 $verb = $IS_ADD ? "ajouté" : "modifié";
2136 2189  
... ... @@ -2561,6 +2614,7 @@ class MaterielsController extends AppController {
2561 2614 //$this->set(compact('designation', 'utilisateurconnect', 'users', 'materiel', 'surCategories', 'categories', 'sousCategories', 'groupesThematiques', 'groupesMetiers', 'organismes', 'sites', 'utilisateurs', 'mail_responsable', 'domaineresp', 'lieu_detail', 'fournisseurs'));
2562 2615 $statuses = [
2563 2616 'CREATED' => 'CREATED',
  2617 + 'TOBEORDERED' => 'TOBEORDERED',
2564 2618 'VALIDATED' => 'VALIDATED',
2565 2619 'TOBEARCHIVED' => 'TOBEARCHIVED',
2566 2620 'ARCHIVED' => 'ARCHIVED'
... ... @@ -2773,7 +2827,7 @@ class MaterielsController extends AppController {
2773 2827 if ( $this->Materiels->delete($materiel) ) {
2774 2828 $this->Flash->success(__("Le matériel a bien été $verb"));
2775 2829 /*
2776   - $this->ilog("Materiel $verb = '$materiel' (id=$id)");
  2830 + this->ilog("Materiel $verb = '$materiel' (id=$id)");
2777 2831 //(EP202009)
2778 2832 //$this->sendEmail($materiel);
2779 2833 $this->sendmail($materiel);
... ... @@ -2798,13 +2852,89 @@ class MaterielsController extends AppController {
2798 2852 * @param string $from
2799 2853 * @return \Cake\Network\Response|NULL
2800 2854 */
2801   - private function statusSetTo($newStatus, $message, $id = null, $from = 'index', $onlyOneMateriel = True) {
2802   - $materiel = $this->Materiels->get($id)->set('status', $newStatus);
  2855 + private function _statusSetTo($newStatus, $message, $id = null, $from = 'index', $onlyOneMateriel = True) {
  2856 +
  2857 + //$materiel = $this->Materiels->get($id)->set('status', $newStatus);
  2858 + $materiel = $this->Materiels->get($id, [
  2859 + 'contain' => [
  2860 +
  2861 + // 1) HasOne
  2862 +
  2863 + /*
  2864 + 'SurCategories',
  2865 + 'Categories',
  2866 + 'SousCategories',
  2867 + 'GroupesThematiques',
  2868 + 'GroupesMetiers',
  2869 + 'Projets',
  2870 + 'Organismes',
  2871 + 'Sites',
  2872 + 'Fournisseurs',
  2873 +
  2874 + //'Gestionnaires',
  2875 + 'Users',
  2876 + */
  2877 +
  2878 + // 2) HasMany
  2879 +
  2880 + // Tous les Documents de ce $materiel (sans leur type)
  2881 + //'Documents',
  2882 + // Tous les Documents de ce $materiel AVEC leur type
  2883 + 'Documents.TypeDocuments',
  2884 + /*
  2885 + 'Emprunts',
  2886 + // Tous les Suivis de ce $materiel (sans leur type)
  2887 + //'Suivis',
  2888 + // Tous les Suivis de ce $materiel AVEC leur type de suivi
  2889 + 'Suivis.TypeSuivis',
  2890 + */
  2891 +
  2892 + ]
  2893 + ]);
  2894 +
  2895 + // Set new status
  2896 + $materiel->set('status', $newStatus);
  2897 +
  2898 + //debug($materiel); exit;
2803 2899 $msgError2 = "Le statut du matériel " . $materiel->designation . " (" . $materiel->numero_laboratoire . ") n'a pas pu être modifié";
2804 2900  
2805   - // - ARCHIVED
2806   - if ($newStatus == 'ARCHIVED')
2807   - $materiel->set('date_archived', date('Y-m-d'));
  2901 + // - TOBEORDERED
  2902 + if ($newStatus == 'TOBEORDERED') {
  2903 +
  2904 + // Attributs obligatoires pour la phase COMMANDE (LOT1)
  2905 + $mandatoryFields = $this->Materiels->getMandatoryFieldsForLot(1);
  2906 +
  2907 + // Si au moins un champ obligatoire est nul ou vide => ERROR
  2908 + foreach ($mandatoryFields as $fname => $fnicename) {
  2909 + // Champ virtuel ?
  2910 + if ($fname == 'DEVIS') {
  2911 + if (! $materiel->hasDevis()) {
  2912 + // on passe au champ suivant
  2913 + $msgError1 = "Pour ordonner la commande de ce matériel, vous devez d'abord joindre un devis à cette fiche (bouton 'Lier un doc.') ";
  2914 + $this->Flash->error($msgError1);
  2915 + // => on reste sur "view"
  2916 + return $this->redirect(['action'=>'view',$id]);
  2917 + }
  2918 + continue;
  2919 + }
  2920 + // Champ physique (réel) ?
  2921 + $fval = $materiel->$fname;
  2922 + if ($fval === null || $fval == '') {
  2923 + $msgError1 = "Pour ordonner la commande d'un matériel, le champ suivant ne doit pas être vide : ".$fnicename.' du matériel';
  2924 + $this->Flash->error($msgError1);
  2925 + $this->e->setError($fname, 'Ce champ ne doit pas être vide');
  2926 + // => on revient à "edit"
  2927 + return $this->redirect(['action'=>'edit',$id]);
  2928 + }
  2929 + }
  2930 +
  2931 + //TODO
  2932 + // Le matos est valide, on pourrait donc marquer la date de commande
  2933 + ////$materiel->set('date_ordered', date('Y-m-d'));
  2934 + //$materiel->date_ordered = date('Y-m-d');
  2935 +
  2936 + } // TOBEORDERED
  2937 +
2808 2938  
2809 2939 // - VALIDATED
2810 2940 if ($newStatus == 'VALIDATED') {
... ... @@ -2845,6 +2975,10 @@ class MaterielsController extends AppController {
2845 2975  
2846 2976 // Si au moins un champ obligatoire est nul ou vide => ERROR
2847 2977 foreach ($mandatoryFields as $fname => $fnicename) {
  2978 +
  2979 + // Champ virtuel ? => ignorer
  2980 + if ($fname == 'DEVIS') continue;
  2981 +
2848 2982 $fval = $materiel->$fname;
2849 2983 //debug($fname); debug($fval);
2850 2984 if ($fval === null || $fval == '') {
... ... @@ -2919,6 +3053,11 @@ class MaterielsController extends AppController {
2919 3053 } // VALIDATED
2920 3054  
2921 3055  
  3056 + // - ARCHIVED
  3057 + if ($newStatus == 'ARCHIVED')
  3058 + $materiel->set('date_archived', date('Y-m-d'));
  3059 +
  3060 +
2922 3061 // SAVE
2923 3062 $success = False;
2924 3063 // - SAVE KO
... ... @@ -2969,6 +3108,7 @@ class MaterielsController extends AppController {
2969 3108 protected function get_actions_with_email() {
2970 3109 return [
2971 3110 'add', 'edit', 'delete',
  3111 + 'statusTobeordered',
2972 3112 'statusCreated', 'statusTobearchived', 'statusValidated', 'statusArchived'
2973 3113 // ...
2974 3114 ];
... ... @@ -2989,7 +3129,7 @@ class MaterielsController extends AppController {
2989 3129 //'administrer'
2990 3130 // - Autres
2991 3131 'find',
2992   - 'statusCreated','statusValidated','statusTobearchived','statusArchived',
  3132 + 'statusCreated', 'statusTobeordered', 'statusValidated','statusTobearchived','statusArchived',
2993 3133 //'execActions',
2994 3134 //'updateSelectedStatus',
2995 3135 //'export',
... ... @@ -3014,7 +3154,7 @@ class MaterielsController extends AppController {
3014 3154 */
3015 3155 public function statusCreated($id = null, $from = 'index')
3016 3156 {
3017   - $this->statusSetTo('CREATED', 'Le matériel a bien été rétrogradé au statut CREATED', $id, $from);
  3157 + $this->_statusSetTo('CREATED', "Le matériel a bien été rétrogradé au statut 'CRÉÉ'", $id, $from);
3018 3158 }
3019 3159  
3020 3160 /**
... ... @@ -3023,9 +3163,31 @@ class MaterielsController extends AppController {
3023 3163 * @param string $id
3024 3164 * @param string $from
3025 3165 */
  3166 + public function statusTobeordered($id = null, $from = 'index')
  3167 + {
  3168 + $this->_statusSetTo('TOBEORDERED', 'La demande de commande du matériel a bien été transmise', $id, $from);
  3169 + /*
  3170 + * (EP) moved to statusSetTo()
  3171 + * if (in_array($_SESSION['Auth']['User']['sn'][0], TableRegistry::get('Users')
  3172 + * ->find('list', ['keyField' => 'id', 'valueField' => 'nom'])
  3173 + * ->where(['role =' => 'Administration'])
  3174 + * ->toArray())) {
  3175 + * $gestionnaireID = TableRegistry::get('Users')->find()->where(['nom' => $_SESSION['Auth']['User']['sn'][0]])->first()->id;
  3176 + * $materiel->gestionnaire_id = $gestionnaireID;
  3177 + * }
  3178 + * $this->sendEmail($this->Materiels->get($id));
  3179 + */
  3180 + }
  3181 +
  3182 + /**
  3183 + * StatusValidated method
  3184 + *
  3185 + * @param string $id
  3186 + * @param string $from
  3187 + */
3026 3188 public function statusValidated($id = null, $from = 'index')
3027 3189 {
3028   - $this->statusSetTo('VALIDATED', 'Le matériel a bien été validé', $id, $from);
  3190 + $this->_statusSetTo('VALIDATED', 'Le matériel a bien été validé', $id, $from);
3029 3191 /*
3030 3192 * (EP) moved to statusSetTo()
3031 3193 * if (in_array($_SESSION['Auth']['User']['sn'][0], TableRegistry::get('Users')
... ... @@ -3048,7 +3210,7 @@ class MaterielsController extends AppController {
3048 3210 //public function statusTobearchived($id = null, $from = 'index')
3049 3211 public function statusTobearchived($id = null, $from = 'index')
3050 3212 {
3051   - $this->statusSetTo('TOBEARCHIVED', "La sortie d'inventaire a bien été demandée", $id, $from);
  3213 + $this->_statusSetTo('TOBEARCHIVED', "La sortie d'inventaire a bien été demandée", $id, $from);
3052 3214 // (EP) moved to statusSetTo()
3053 3215 // $this->sendEmail($this->Materiels->get($id));
3054 3216 }
... ... @@ -3061,7 +3223,7 @@ class MaterielsController extends AppController {
3061 3223 */
3062 3224 public function statusArchived($id = null, $from = 'index')
3063 3225 {
3064   - $this->statusSetTo('ARCHIVED', "Le matériel a bien été archivé (sorti de l'inventaire)", $id, $from);
  3226 + $this->_statusSetTo('ARCHIVED', "Le matériel a bien été archivé (sorti de l'inventaire)", $id, $from);
3065 3227 // (EP) moved to statusSetTo()
3066 3228 // $this->sendEmail($this->Materiels->get($id));
3067 3229 }
... ... @@ -3889,8 +4051,16 @@ class MaterielsController extends AppController {
3889 4051 $materielIdentification = $materiel->designation . '-' . $materiel->numero_laboratoire;
3890 4052 switch ($what) {
3891 4053 case 'CREATED':
  4054 + /*
3892 4055 $new = 'VALIDATED';
3893 4056 $msgError = "le materiel " . $materielIdentification . " n'a pas pu être validé car au moins un des champs nécessaire n'est pas rempli.";
  4057 + */
  4058 + $new = 'TOBEORDERED';
  4059 + $msgError = "le materiel " . $materielIdentification . " n'a pas pu être commandé (un champ obligatoire est manquant)";
  4060 + break;
  4061 + case 'TOBEORDERED':
  4062 + $new = 'VALIDATED';
  4063 + $msgError = "le materiel " . $materielIdentification . " n'a pas pu être validé (un champ obligatoire est manquant)";
3894 4064 break;
3895 4065 case 'VALIDATED':
3896 4066 $new = 'TOBEARCHIVED';
... ... @@ -3903,7 +4073,7 @@ class MaterielsController extends AppController {
3903 4073 }
3904 4074 // if mode_debug desactivate (POURQUOI ???)
3905 4075 if (! $this->isLabinventDebugMode()) {
3906   - if (! $this->statusSetTo($new, 'Le matériel a bien été ???', $id, 'index', false))
  4076 + if (! $this->_statusSetTo($new, 'Le matériel a bien été ???', $id, 'index', false))
3907 4077 $nb --;
3908 4078 /*
3909 4079 * //debug($materiel); exit;
... ...
src/Model/Entity/Document.php
... ... @@ -35,4 +35,21 @@ class Document extends Entity
35 35 '*' => true,
36 36 'id' => false
37 37 ];
  38 +
  39 + // (EP 20200504)
  40 + // Propriétés virtuelles (attributs virtuels de l'entité)
  41 + // A utiliser dans le controleur ainsi : $materiel->is_devis
  42 + //protected function _getIsCreated() { return $this->_fields['status'] == 'CREATED'; }
  43 + protected function _getIsDevis() {
  44 + //debug($this);
  45 + /*
  46 + // Ceci permettra des accès du type $document->type_document->nom depuis la vue
  47 + $document = $this->Documents->get($id, [
  48 + 'contain' => ['TypeDocuments']
  49 + ])
  50 + $doc_type = $this->Documents->TypeDocuments->get($this->type_document_id)['nom'];
  51 + */
  52 + return $this->type_document->nom == 'DEVIS';
  53 + }
  54 +
38 55 }
... ...
src/Model/Entity/Materiel.php
... ... @@ -133,6 +133,14 @@ class Materiel extends Entity {
133 133 return $diff->y < MAX_DIFF_YEARS;
134 134 //return true;
135 135 }
  136 +
  137 + public function hasDevis() {
  138 + //debug($this->documents);
  139 + foreach ($this->documents as $document)
  140 + if ($document->is_devis) return true;
  141 + // par défaut, faux
  142 + return false;
  143 + }
136 144  
137 145 protected function hasStatus($status) { return $this->status == $status; }
138 146  
... ... @@ -143,6 +151,7 @@ class Materiel extends Entity {
143 151 //protected function _getIsCreated() { return $this->_fields['status'] == 'CREATED'; }
144 152 protected function _getIsCreated() { return $this->status == 'CREATED'; }
145 153 //return $this->status == 'CREATED';
  154 + protected function _getIsOrdered() { return $this->status == 'TOBEORDERED'; }
146 155 protected function _getIsValidated() { return $this->status == 'VALIDATED'; }
147 156 //protected function _getIsValidated() { return $this->_fields['status'] == 'VALIDATED'; }
148 157 //public function is_tobearchived() { return $this->status == 'TOBEARCHIVED'; }
... ... @@ -150,7 +159,9 @@ class Materiel extends Entity {
150 159 protected function _getIsArchived() { return $this->status == 'ARCHIVED'; }
151 160  
152 161 public function getNiceStatus() {
153   - if ($this->is_created) return 'À VALIDER';
  162 + //if ($this->is_created) return 'À VALIDER';
  163 + if ($this->is_created) return 'CRÉÉ - à valider';
  164 + if ($this->is_ordered) return 'EN COMMANDE - à valider';
154 165 if ($this->is_validated) return 'VALIDÉ';
155 166 if ($this->is_tobearchived) return 'À SORTIR';
156 167 //if ($this->is_archived)
... ...
src/Model/Table/DocumentsTable.php
... ... @@ -6,6 +6,10 @@ use Cake\ORM\Table;
6 6 use Cake\Validation\Validator;
7 7 use Cake\ORM\TableRegistry;
8 8  
  9 +// (EP) ajouté pour delete()
  10 +use Cake\Datasource\EntityInterface;
  11 +
  12 +
9 13 /**
10 14 * Documents Model
11 15 *
... ... @@ -132,6 +136,23 @@ class DocumentsTable extends AppTable
132 136 };
133 137  
134 138 $checkPhotoFormat = function ($entity) {
  139 + //debug($entity); exit;
  140 + if (! empty($entity->get('chemin_file')['tmp_name'])) {
  141 + //if ($entity->get('photo') || $entity->get('type_document_id')==4) {
  142 + if ($entity->get('photo')) {
  143 + $extension = strtolower(pathinfo($entity->get('chemin_file')['name'], PATHINFO_EXTENSION));
  144 + return in_array($extension, $this->photo_formats);
  145 + }
  146 + return true;
  147 + }
  148 + /*
  149 + if ( $entity->get('edit') && $entity->get('type_document_id')==4 && !in_array($entity->get('type_doc'), $this->photo_formats))
  150 + return false;
  151 + */
  152 + return true;
  153 + };
  154 + /*
  155 + $checkPhotoFormat = function ($entity) {
135 156 if (! empty($entity->get('chemin_file')['tmp_name'])) {
136 157 if ($entity->get('photo') || $entity->get('type_document_id')==4) {
137 158 $extension = strtolower(pathinfo($entity->get('chemin_file')['name'], PATHINFO_EXTENSION));
... ... @@ -143,6 +164,7 @@ class DocumentsTable extends AppTable
143 164 return false;
144 165 return true;
145 166 };
  167 + */
146 168  
147 169 $checkFilePresence = function ($entity) {
148 170 if (!$entity->get('edit'))
... ... @@ -272,6 +294,15 @@ class DocumentsTable extends AppTable
272 294 }
273 295 return true;
274 296 }
  297 +
  298 + /*
  299 + // Surcharge de la methode delete de AppTable
  300 + public function delete(EntityInterface $entity, $options = []) {
  301 + // On sauvegarde l'entité pour la réutiliser dans les notifications (ou ailleurs)
  302 + $this->current_entity = $entity;
  303 + return parent::delete($entity,$options);
  304 + }
  305 + */
275 306  
276 307 /**
277 308 * CakePHP Model Functions
... ...
src/Model/Table/MaterielsTable.php
... ... @@ -221,6 +221,7 @@ class MaterielsTable extends AppTable
221 221  
222 222 public $ALL_STATUS = array(
223 223 'CREATED',
  224 + 'TOBEORDERED',
224 225 'VALIDATED',
225 226 'TOBEARCHIVED',
226 227 'ARCHIVED'
... ... @@ -285,10 +286,32 @@ class MaterielsTable extends AppTable
285 286 }
286 287 */
287 288  
  289 + public static function getMandatoryFieldsForMateriel($mat) {
  290 + $status = $mat->status;
  291 + $fields = self::getMandatoryFieldsForMaterielStatus($status);
  292 + // Seulement si prix > 10K€ : exiger la facture jointe et le n° série et lieu de stockage précis
  293 + if ($status == 'VALIDATED' && $mat->prix_ht && $mat->prix_ht > 10000) {
  294 + $fields['numero_serie'] = 'S/N';
  295 + //TODO 202109
  296 + //$fields[] = 'lieu stockage';
  297 + //$fields[] = 'facture jointe';
  298 + }
  299 + return $fields;
  300 + }
288 301 public static function getMandatoryFieldsForMaterielStatus($status) {
289   - // CREATED => LOT1
290   - // VALIDATED et au-dessus => LOT2
291   - return ($status == 'CREATED') ? self::getMandatoryFieldsForLot(1) : self::getMandatoryFieldsForLot(2);
  302 +
  303 + if (is_null($status)) $status='CREATED';
  304 + // On recup le LOT qui convient au status courant du matos
  305 + //$fields = ($status == 'CREATED') ? self::getMandatoryFieldsForLot(1) : self::getMandatoryFieldsForLot(2);
  306 + // CREATED => LOT0
  307 + if ($status == 'CREATED') $lot_num = 0;
  308 + // TOBEORDERED => LOT1
  309 + elseif ($status == 'TOBEORDERED') $lot_num = 1;
  310 + // >= VALIDATED => LOT2
  311 + else $lot_num=2;
  312 + $fields = self::getMandatoryFieldsForLot($lot_num);
  313 +
  314 + return $fields;
292 315 }
293 316  
294 317 /**
... ... @@ -318,6 +341,7 @@ class MaterielsTable extends AppTable
318 341 debug($mf1);
319 342 */
320 343  
  344 + /*
321 345 // - YML
322 346 $keys = ['MANDATORY_FIELDS_LOT0', 'MANDATORY_FIELDS_LOT1', 'MANDATORY_FIELDS_LOT2'];
323 347 foreach ($keys as $k) {
... ... @@ -328,6 +352,7 @@ class MaterielsTable extends AppTable
328 352 }
329 353 else debug("error on key $k");
330 354 }
  355 + */
331 356  
332 357  
333 358 /* Autorisations
... ... @@ -489,7 +514,6 @@ class MaterielsTable extends AppTable
489 514 //public function validationDefault(Validator $validator) : Validator
490 515 public function validationDefault(Validator $validator) //: Validator
491 516 {
492   -
493 517 /*
494 518 if (IP2I) {
495 519  
... ... @@ -636,7 +660,7 @@ class MaterielsTable extends AppTable
636 660  
637 661 $validator->add('status', 'valid', [
638 662 'rule' => 'checkStatus',
639   - 'message' => 'Le statut doit prendre une des 4 valeurs CREATED, VALIDATED, TOBEARCHIVED, ou ARCHIVED',
  663 + 'message' => 'Le statut doit prendre une des 4 valeurs CREATED, TOBEORDERED, VALIDATED, TOBEARCHIVED, ou ARCHIVED',
640 664 'provider' => 'table'
641 665 ]);
642 666 /*
... ... @@ -827,7 +851,7 @@ class MaterielsTable extends AppTable
827 851 'provider' => 'table'
828 852 ]);
829 853 $validator
830   - ->allowEmptyString('nom_user', false, 'Ce champ est obligatoire')
  854 + //->allowEmptyString('nom_user', false, 'Ce champ est obligatoire')
831 855 ->add('nom_user', 'valid', [
832 856 'rule' => 'check_string',
833 857 'message' => 'Ce champ contient des caractères interdits',
... ... @@ -860,15 +884,56 @@ class MaterielsTable extends AppTable
860 884 $validator->allowEmpty('duree_garantie');
861 885 $validator->allowEmpty('unite_duree_garantie');
862 886  
863   - $mandatory_fields = $this->getMandatoryFieldsForLot(1);
  887 + /*
  888 + * (EP 202109) Annulation des champs obligatoires définis comme tels dans le schéma de la BD
  889 + * (afin de pouvoir les rendre éventuellement optionnels si on le désire via la configuration)
  890 + */
  891 + $bd_mandatory_fields = ['nom_user', 'nom_responsable', 'email_responsable'];
  892 + foreach ($bd_mandatory_fields as $fname) $validator->allowEmpty($fname, true);
  893 + //foreach ($bd_mandatory_fields as $fname) $validator->allowEmptyString($fname, true);
  894 +
  895 + /*
  896 + * (EP 202109) Définition des champs obligatoires pour la création (et modif) d'une fiche matériel
  897 + * selon le fichier de configuration (config/app_labinvent_mandatory_fields.yml)
  898 + *
  899 + * TODO: faire plutot dépendre cette liste du statut du matériel :
  900 + * (solution ici: https://book.cakephp.org/4/en/core-libraries/validation.html#conditional-validation)
  901 + * - CREATED => LOT0
  902 + * - TOBEORDERED => LOT1
  903 + * - VALIDATED (et plus) => LOT2
  904 + */
  905 + // - Par défaut, tous les champs du LOT 0
  906 + $mandatory_fields = $this->getMandatoryFieldsForLot(0);
  907 + // - Par défaut, tous les champs du LOT 1 (plus contraignant)
  908 + //$mandatory_fields = $this->getMandatoryFieldsForLot(1);
864 909 $this->_setMandatoryFields($validator, $mandatory_fields);
865 910  
  911 + // Définition des champs qui doivent rester optionnels
866 912 /*
867 913 $optional_fields = array_diff_key(MANDATORY_FIELDS_LOT1, $mandatory_fields);
868 914 //debug($optional_fields);
869 915 foreach ($optional_fields as $fname) $validator->allowEmptyString($fname, true);
870 916 */
871 917  
  918 + /*
  919 + *
  920 + * TRES INSTRUCTIF
  921 + *
  922 + * debug($validator);
  923 + *
  924 + * => Affiche la liste des champs qui sont obligatoires :
  925 + *
  926 + object(Cake\Validation\Validator) {
  927 + '_allowEmptyMessages' => [
  928 + 'designation' => 'Ce champ doit être rempli',
  929 + 'description' => 'Ce champ doit être rempli',
  930 + 'sur_categorie_id' => 'Ce champ doit être rempli',
  931 + 'categorie_id' => 'Ce champ doit être rempli'
  932 + ],
  933 + ...
  934 + */
  935 + //debug($validator);
  936 +
872 937 return $validator;
873 938  
874 939 } // validationDefault()
... ...
src/Template/Element/materiels_list.ctp
... ... @@ -112,7 +112,7 @@ $displayActionButtonsForMateriel = function($materiel, $statuses_color, $usernam
112 112 'title' => 'Demander la sortie de l\'inventaire',
113 113 'style' => 'margin: 0 2px',
114 114 'escape' => false,
115   - 'confirm' => 'Êtes-vous sur de vouloir faire une demande d\'archive ' . $materiel->designation . ' ?'
  115 + 'confirm' => "Êtes-vous sûr de vouloir demander l'archivage de " . $materiel->designation . ' ?'
116 116 ]
117 117 );
118 118 //else if ($materiel->status=='TOBEARCHIVED' && !$USER_IS_RESPONSABLE)
... ...
src/Template/Materiels/index.ctp
... ... @@ -223,7 +223,8 @@ $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, 'À VALIDER', 'Seulement les matériels créés', 5],
  226 + 'CREATED' => [$b_cre, 'À VALIDER', 'Seulement les matériels créés (à valider)', 5],
  227 + 'TOBEORDERED' => [$b_cre, 'EN COMMANDE', 'Seulement les matériels commandés (à valider)', 5],
227 228 'VALIDATED' => [$b_val, 'VALIDÉS', "Seulement les matériels validés", 5],
228 229 'TOBEARCHIVED' => [$b_toarc, 'À SORTIR', "Seulement les matériels à archiver", 5],
229 230 'ARCHIVED' => [$b_arc, 'ARCHIVÉS', "Seulement les matériels sortis de l'inventaire", 0],
... ... @@ -515,6 +516,9 @@ $displayActionButtonsForSelectedOrAllElements = function(
515 516 case 'CREATED':
516 517 $action = 'Valider les';
517 518 break;
  519 + case 'TOBEORDERED':
  520 + $action = "Valider les";
  521 + break;
518 522 case 'VALIDATED':
519 523 $action = "Demander l'archivage des";
520 524 break;
... ... @@ -574,7 +578,14 @@ $displayLegend = function() {
574 578 //echo "<p><i><b><u>Couleur</u> :</b> <div>bleu=à valider</div> ; vert=validé ; orange=à sortir ; rouge=archivé (couleur date rouge = fin garantie)</i></p>";
575 579 //echo "<p><i><b><u>Statut</u> :</b> <i><b>C</b>(réé)=Matériel à commander</i> ; <i><b>V</b>(alidé)=Matériel livré</i> ; <i><b>TBA</b>=à sortir</i> ; <i><b>A</b>=Archivé</i> ; </p>";
576 580 //echo "<p><i><b><u>Couleur</u> :</b> <i style='color:blue'>bleu=à valider</i> ; <i style='color:green'>vert=validé</i> ; <i style='color:orange'>orange=à sortir</i> ; <i style='color:red'>rouge=archivé</i> ; couleur date rouge = <i style='color:red'>fin garantie</i></i></p>";
577   - echo "<p><i><b><u>Couleur</u> :</b> <i style='color:blue'>bleu=à commander</i> ; <i style='color:black'>noir=livré (validé)</i> ; <i style='color:orange'>orange=à sortir</i> ; <i style='color:red'>rouge=archivé</i> ; couleur date rouge = <i style='color:red'>fin garantie</i></i></p>";
  581 + echo "<p><i><b><u>Couleur</u> :</b>
  582 + <i style='color:orange'>orange=créé (à valider)</i> ;
  583 + <i style='color:red'>rouge=en commande (à valider)</i> ;
  584 + <i style='color:black'>noir=livré (validé)</i> ;
  585 + <i style='color:red'>rouge=à sortir</i> ;
  586 + <i style='color:blue'>bleu=archivé</i> ;
  587 + (couleur date rouge = <i style='color:red'>fin garantie</i>)
  588 + </i></p>";
578 589 };
579 590  
580 591  
... ... @@ -672,14 +683,16 @@ echo $this-&gt;Form-&gt;create(&#39;materiels&#39;, [
672 683 // $form2 = $this->Form;
673 684 // /echo $this->Form->create('materiels', ['url' => '/materiels/execActions']);
674 685 if ($SELECTED_STATUS) echo $this->Form->hidden('what', ['value'=>$SELECTED_STATUS]);
675   - ?>
676 686  
  687 + // - Légende
  688 + $displayLegend();
  689 + ?>
677 690  
678 691 <!--
679 692 Affichage de la liste des matériels (table headers + data)
680 693 -->
681 694 <?php
682   - //<table style="border-collapse: separate; border-spacing: 0;">
  695 + //<table style="border-collapse: separate; border-spacing: 0;">
683 696 //$METRO = true;
684 697 // fetch from src/Template/Element/materiels_list.ctp
685 698 //echo $this->element('materiels_list_headers',
... ... @@ -694,7 +707,7 @@ echo $this-&gt;Form-&gt;create(&#39;materiels&#39;, [
694 707  
695 708 <?php
696 709 // - Légende, Boutons actions, et Pagination
697   - $displayLegend();
  710 + //$displayLegend();
698 711 $displayActionButtonsForSelectedOrAllElements(
699 712 $this->Form,
700 713 $SELECTED_STATUS,
... ...
src/Template/Materiels/view.ctp
... ... @@ -15,7 +15,7 @@ $configuration = $configuration;
15 15  
16 16 // Couleur et affichage, en fonction du statut
17 17 $status_color = $status_color;
18   -$status_display = $status_display;
  18 +///$status_display = $status_display;
19 19  
20 20 // - User status:
21 21 $role = $role;
... ... @@ -50,7 +50,8 @@ $IS_VALIDATED = $IS_VALIDATED;
50 50 $IS_TOBEARCHIVED = $IS_TOBEARCHIVED;
51 51 $IS_ARCHIVED = $IS_ARCHIVED;
52 52  
53   -// - User capabilities on materiel:
  53 +// - User capabilities on materiel (from Controller) :
  54 +$CAN_ORDER = $CAN_ORDER;
54 55 $CAN_VALIDATE = $CAN_VALIDATE;
55 56 $CAN_INVALIDATE = $CAN_INVALIDATE;
56 57 $CAN_TBA = $CAN_TBA;
... ... @@ -225,7 +226,9 @@ $CAN_PRINT_LABEL = $IS_VALIDATED &amp;&amp; $configuration-&gt;hasPrinter &amp;&amp; $USER_IS_ADMIN
225 226 $action = "Archivé";
226 227 }
227 228 */
228   - echo "<b>($status_display)</b>";
  229 + //echo "<b>($status_display)</b>";
  230 + $nice_status = $entity->getNiceStatus();
  231 + echo "<b>($nice_status)</b>";
229 232 ?>
230 233 <br />
231 234 <br />
... ... @@ -377,7 +380,7 @@ $CAN_PRINT_LABEL = $IS_VALIDATED &amp;&amp; $configuration-&gt;hasPrinter &amp;&amp; $USER_IS_ADMIN
377 380  
378 381 // BOUTONS "Lier un Doc" et "Remplacer/Lier photo"
379 382 if ($CAN_ATTACH_A_DOC) {
380   - $echoActionButton($this->Html, 'icon-file', $bStyle, ' Lier un Doc. (ou photo)', 'documents', 'add', $entity->id, ['mat'], 'Attacher un Doc. à ce matériel');
  383 + $echoActionButton($this->Html, 'icon-file', $bStyle, ' Lier un Doc. (doc, devis, photo)', 'documents', 'add', $entity->id, ['mat'], 'Attacher un document, un devis, ou une photo à ce matériel');
381 384 /*
382 385 // BOUTON "photo"
383 386 if ($entity->photo_id != null)
... ... @@ -456,19 +459,26 @@ $CAN_PRINT_LABEL = $IS_VALIDATED &amp;&amp; $configuration-&gt;hasPrinter &amp;&amp; $USER_IS_ADMIN
456 459 $CAN_TBA = $IS_VALIDATED && ($USER_IS_ADMIN_OR_MORE || $USER_IS_CREATOR_OR_OWNER || ($USER_IS_RESPONSABLE && $USER_IS_SAME_GROUP_AS_MATERIEL));
457 460 $CAN_ARCHIVE = $IS_TOBEARCHIVED && $CAN_VALIDATE_OR_INVALIDATE;
458 461 */
459   - // CREATED
460   - //if ($IS_CREATED) {
461   - // Bouton VALIDER
462   - if ($CAN_VALIDATE) $echoActionButton($this->Html, 'icon-ok-sign', $bStyle2Red, ' Valider', '', 'statusValidated', $entity->id, ['view'], "Valider ce matériel");
463   - //}
464   - // VALIDATED or more
465   - //else {
466   - // Bouton Invalider (Dévalider)
  462 +
  463 + // - CREATED :
  464 +
  465 + // Bouton COMMANDER
  466 + if ($CAN_ORDER) $echoActionButton($this->Html, 'icon-ok-sign', $bStyle2Red, ' Commander', '', 'statusTobeordered', $entity->id, ['view'], "Demander la commande de ce matériel)");
  467 +
  468 + // Bouton VALIDER
  469 + if ($CAN_VALIDATE) $echoActionButton($this->Html, 'icon-ok-sign', $bStyle2Red, ' Valider (=livré)', '', 'statusValidated', $entity->id, ['view'], "Valider ce matériel (le déclarer comme étant livré)");
  470 +
  471 + // - VALIDATED or more :
  472 +
  473 + // Bouton Invalider (Dévalider)
  474 + // (EP désactivé depuis 2021-09 car n'est plus utile
  475 + // => on peut toujours modifier un matériel tant que certains champs restent obligatoires
467 476 if ($CAN_INVALIDATE)
468 477 $echoActionButton(
469   - $this->Html, 'icon-remove-sign', $bStyle2Red, ' valider', '', 'statusCreated', $entity->id, ['view'],
  478 + $this->Html, 'icon-remove-sign', $bStyle2Red, ' Invalider', '', 'statusCreated', $entity->id, ['view'],
470 479 "dé-valider le matériel (le repasser au statut Créé, il faudra le re-valider ensuite)"
471 480 );
  481 +
472 482 // Bouton TBA
473 483 if ($CAN_TBA)
474 484 $echoActionButton(
... ... @@ -482,7 +492,7 @@ $CAN_PRINT_LABEL = $IS_VALIDATED &amp;&amp; $configuration-&gt;hasPrinter &amp;&amp; $USER_IS_ADMIN
482 492 "Sortir définitivement de l'inventaire",
483 493 "Êtes-vous sur de bien vouloir archiver $entity->designation ?"
484 494 );
485   - //} // VALIDATED or more
  495 +
486 496 /*
487 497 if ($USER_IS_ADMIN_OR_MORE || ($USER_IS_RESPONSABLE && $USER_IS_SAME_GROUP_AS_MATERIEL)) {
488 498 // CREATED
... ...