Commit 8fe06187d2f742a840af36c6cb16e63a2fcaf84f

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

Renforcement important controles sur les dates d'un matériel...

(v3.7.9.6)

- Renforcement important controles sur les dates d'un matériel (achat,
livraison, fin garantie)

- Le numero d'inventaire généré automatiquement en fonction de l'année
d'achat est désormais MIS À JOUR à chaque fois qu'on change la date
d'achat !!!
CHANGES.txt
... ... @@ -65,6 +65,12 @@ Outre ces changements, voici d'autres changements importants :
65 65 ======= CHANGES =======
66 66  
67 67 -------
  68 +17/07/2020 v3.7.9.63 (EP)
  69 + - (i) Renforcement important des controles sur les dates d'un matériel (achat, livraison, fin garantie)
  70 + - (i) Le numero d'inventaire généré automatiquement en fonction de l'année d'achat est désormais MIS À JOUR à chaque fois qu'on change la date d'achat !!!
  71 +
  72 +
  73 +-------
68 74 16/07/2020 v3.7.9.61-62 (EP)
69 75 - (e) Amélioration importante de la nouvelle page web "Changements" (/pages/changes)
70 76 - (b) Bugfix "sauf ARCHIVED" dans materiels/index/ (pour profils user et resp)
... ...
README.md
... ... @@ -42,8 +42,8 @@ Logiciel testé et validé sur les configurations suivantes :
42 42  
43 43 --------------------------------------------------------------------------------------------
44 44  
45   -Date: 16/07/2020
46   -Version: 3.7.9.62
  45 +Date: 17/07/2020
  46 +Version: 3.7.9.63
47 47  
48 48  
49 49 HISTORIQUE DES CHANGEMENTS DE VERSION : voir le fichier CHANGES.txt (ou la page web /pages/changes)
... ...
src/Controller/MaterielsController.php
... ... @@ -1349,6 +1349,10 @@ class MaterielsController extends AppController {
1349 1349 // et le numero_laboratoire est vu comme invalide car déjà utilisé et doit etre unique !!!
1350 1350 // et on a pour résultat : "le matériel n'a pas pu être ajouté" (sans savoir pourquoi !!!)
1351 1351 $materiel = $this->Materiels->patchEntity($materiel, $materiel_to_copy, ['validate' => false]);
  1352 + //TODO: On pourrait traiter les erreurs de validation déjà ici
  1353 + if ($materiel->errors()) {
  1354 + // traitement
  1355 + }
1352 1356 // Du coup, on supprime le champ numero_laboratoire car il va être généré automatiquement
1353 1357 unset($materiel->numero_laboratoire);
1354 1358 // IMPORTANT: on ne doit pas laisser l'id égal à celui du matériel copié !!! il en faut un nouveau
... ... @@ -3904,6 +3908,7 @@ class MaterielsController extends AppController {
3904 3908 break;
3905 3909 }
3906 3910 */
  3911 + //debug("toto".$date_next->format('d/m/Y')."toto"); exit;
3907 3912  
3908 3913 //$this->set('date', date_format($date_next, 'd-m-Y'));
3909 3914 //$this->set('date', date_format($date_next, 'd/m/Y'));
... ...
src/Model/Table/MaterielsTable.php
... ... @@ -129,27 +129,59 @@ class MaterielsTable extends AppTable
129 129  
130 130  
131 131 }
  132 +
  133 + public function dateIsValid($value, array $context) {
  134 + //debug($entity);
  135 + // /^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
  136 + //$valid = preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/([1-2][0-9]{3})$/",$entity);
  137 + //debug((bool)$valid);
  138 + return (bool) preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/([1-2][0-9]{3})$/",$value);
  139 + }
  140 +
  141 +
132 142  
133 143 /**
134 144 * Default validation rules.
135 145 *
  146 + * (EP 2020)
  147 + * NIVEAU 1 DE VALIDATION : au moment où les données sont converties en Entity avec newEntity(), patchEntity()...
  148 + * On vérifie ici seulement le format des données, indépendamment de leur sens (ce que l'application va en faire)
  149 + * Le niveau 2 "Application Rules" est appliqué par la fonction buildRules() ci-après
  150 + *
136 151 * @param \Cake\Validation\Validator $validator
137 152 * Validator instance.
138 153 * @return \Cake\Validation\Validator
139 154 */
140   - public function validationDefault(Validator $validator)
  155 + // php7
  156 + //public function validationDefault(Validator $validator) : Validator
  157 + public function validationDefault(Validator $validator) //: Validator
141 158 {
142   -
143   - $dateValide = function ($entity) {
144   - //date_default_timezone_set('Europe/Paris');
  159 + // Check date is dd/mm/yyyy
  160 + /*
  161 + $dateIsValid = function ($entity) {
  162 + //debug($entity);
  163 + // /^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
  164 + //$valid = preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/([1-2][0-9]{3})$/",$entity);
  165 + //debug((bool)$valid);
  166 + return (bool) preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/([1-2][0-9]{3})$/",$entity);
  167 + };
  168 + */
  169 + // return true si date n'est pas future (maxi = today)
  170 + $dateIsNotFutureAndNotTooOld = function ($date_string) {
145 171 $tz = new \DateTimeZone('Europe/Paris');
146   - $today = (new \DateTime('now',$tz))->format('Ymd');
  172 + // DateTime lit les dates au format JJ-MM-YYYY (et non pas JJ/MM/YYYY)
  173 + $date = ( new \DateTime(strtr($date_string,'/','-'),$tz) )->format('Ymd');
  174 + //date_default_timezone_set('Europe/Paris');
  175 + //$today = (new \DateTime('now',$tz))->format('Ymd');
  176 + $today = new \DateTime('now',$tz);
  177 + $date_too_old = $today;
  178 + $today = $today->format('Ymd');
  179 + // today - 50 ans = trop vieux !
  180 + $date_too_old = $date_too_old->sub(new \DateInterval('P50Y'))->format('Ymd');
147 181 /*
148 182 $time = Time::now(); // On récupère la date et l'heure actuelles
149 183 $today = (new date("$time->year-$time->month-$time->day"))->format('Ymd'); // On extrait la date on la formatte en un format comparable de type 20171231
150 184 */
151   - // DateTume lit les dates au format JJ-MM-YYYY (et non pas JJ/MM/YYYY)
152   - $date = ( new \DateTime(strtr($entity,'/','-'),$tz) )->format('Ymd');
153 185 /*
154 186 $timeEntity = new time($entity);
155 187 $dateEntity = (new date("$timeEntity->year-$timeEntity->month-$timeEntity->day"))->format('Ymd');
... ... @@ -160,7 +192,11 @@ class MaterielsTable extends AppTable
160 192 debug($date);
161 193 exit;
162 194 */
163   - return ($today >= $date);
  195 + debug($today); // '20200717'
  196 + debug($date); // '20200718' => pas bon
  197 + debug($date_too_old);
  198 + //return ($today >= $date);
  199 + return ($date<=$today && $date>$date_too_old);
164 200 };
165 201  
166 202 $validator->integer('id')->allowEmpty('id', 'create');
... ... @@ -194,22 +230,90 @@ class MaterielsTable extends AppTable
194 230 'message' => 'Le statut doit prendre une des 4 valeurs CREATED, VALIDATED, TOBEARCHIVED, ou ARCHIVED',
195 231 'provider' => 'table'
196 232 ]);
  233 + /*
197 234 $configuration = TableRegistry::get('Configurations')->find()
198 235 ->where([
199 236 'id =' => 1
200 237 ])
201   - ->first();
202   - if ($configuration->date_commande_facultative) {
203   - $validator->allowEmpty('date_acquisition')->add('date_acquisition', 'custom', [
204   - 'rule' => $dateValide,
205   - 'message' => "La date n'est pas valide (car trop lointaine)"
  238 + ->first();
  239 + */
  240 + $configuration = TableRegistry::get('Configurations')->get(1);
  241 +
  242 +
  243 +
  244 + // Validation des DATES
  245 +
  246 + // - Date achat
  247 + $f = 'date_acquisition';
  248 + $validator
  249 + ->allowEmptyString($f, $configuration->date_commande_facultative, 'Ce champ doit être rempli')
  250 + ->date($f, 'dmy', 'Date invalide') // https://api.cakephp.org/3.8/class-Cake.Validation.Validation.html#_date
  251 + ->add($f, 'valide', [
  252 + // 2 façons d'appeler une règle de validation locale :
  253 + // - par son nom de fonction définie LOCALEMENT (ici dans CETTE fonction) comme une variable (avec un $)
  254 + //'rule' => $dateIsValid,
  255 + // - mieux, par son nom, la fonction étant définie n'importe où dans CETTE classe
  256 + 'rule' => 'dateIsValid',
  257 + 'message' => "La date n'est pas valide (JJ/MM/AAAA)",
  258 + 'provider' => 'table',
  259 + ])
  260 + ->add($f, 'acceptable', [
  261 + 'rule' => $dateIsNotFutureAndNotTooOld,
  262 + 'message' => "La date ne doit être ni future ni trop ancienne"
206 263 ]);
207   - } else {
208   - $validator->notEmpty('date_acquisition', 'Ce champ doit être rempli')->add('date_acquisition', 'custom', [
209   - 'rule' => $dateValide,
210   - 'message' => "La date n'est pas valide (car trop lointaine)"
  264 +
  265 + // - Date livraison
  266 + $f = 'date_reception';
  267 + $validator
  268 + ->allowEmptyString($f)
  269 + ->date($f, 'dmy', 'Date invalide') // https://api.cakephp.org/3.8/class-Cake.Validation.Validation.html#_date
  270 + //->add('date_reception', 'valid', ['rule' => 'date', 'message' => 'Date invalide']);
  271 + ->add($f, 'valide-JJslashMMslashAAAA', [
  272 + 'rule' => 'dateIsValid',
  273 + 'message' => "La date n'est pas valide (JJ/MM/AAAA)",
  274 + 'provider' => 'table',
  275 + ]);
  276 +
  277 + // - Date fin garantie
  278 + $f = 'date_fin_garantie';
  279 + $validator
  280 + ->allowEmptyString($f)
  281 + ->date($f, 'dmy', 'Date invalide') // https://api.cakephp.org/3.8/class-Cake.Validation.Validation.html#_date
  282 + ->add($f, 'valide-JJslashMMslashAAAA', [
  283 + 'rule' => 'dateIsValid',
  284 + 'message' => "La date n'est pas valide (JJ/MM/AAAA)",
  285 + 'provider' => 'table',
211 286 ]);
  287 +
  288 +
  289 +
  290 + /*
  291 + if ($configuration->date_commande_facultative) {
  292 + //$validator->allowEmpty('date_acquisition')->add('date_acquisition', 'custom', [
  293 + $validator
  294 + ->allowEmptyString('date_acquisition')
  295 + ->add('date_acquisition', 'custom1', [
  296 + 'rule' => $dateIsValid,
  297 + 'message' => "La date n'est pas valide (JJ/MM/AAAA)"
  298 + ])
  299 + ->add('date_acquisition', 'custom2', [
  300 + 'rule' => $dateIsNotFuture,
  301 + 'message' => "La date ne doit pas être future"
  302 + ]);
  303 + } else {
  304 + $validator
  305 + //->notEmpty('date_acquisition', 'Ce champ doit être rempli')
  306 + ->allowEmptyString('date_acquisition', false, 'Ce champ doit être rempli')
  307 + ->add('date_acquisition', 'custom1', [
  308 + 'rule' => $dateIsValid,
  309 + 'message' => "La date n'est pas valide (JJ/MM/AAAA)"
  310 + ])
  311 + ->add('date_acquisition', 'custom2', [
  312 + 'rule' => $dateIsNotFutureAndNotTooOld,
  313 + 'message' => "La date ne doit être ni future ni trop ancienne"
  314 + ]);
212 315 }
  316 + */
213 317 /*
214 318 // Attention, configuration désactivée, cela ne génère pas ne num de labo, voir dans config/edit.ctp
215 319 $validator->allowEmpty('fournisseur')->add('fournisseur', 'valid', [
... ... @@ -218,6 +322,9 @@ class MaterielsTable extends AppTable
218 322 'provider' => 'table'
219 323 ]);
220 324 */
  325 +
  326 +
  327 +
221 328 $validator->numeric('prix_ht')
222 329 ->allowEmpty('prix_ht')
223 330 ->add('prix_ht', 'valid', [
... ... @@ -286,10 +393,11 @@ class MaterielsTable extends AppTable
286 393 ->allowEmpty('nom_modificateur');
287 394 */
288 395  
289   - $validator->allowEmpty('date_reception');
290   - $validator->allowEmpty('date_fin_garantie');
  396 + //$validator->allowEmpty('date_reception');
  397 + //$validator->allowEmpty('date_fin_garantie');
291 398 $validator->allowEmpty('duree_garantie');
292 399 $validator->allowEmpty('unite_duree_garantie');
  400 +
293 401 return $validator;
294 402 }
295 403  
... ... @@ -298,12 +406,18 @@ class MaterielsTable extends AppTable
298 406 /**
299 407 * Returns a rules checker object that will be used for validating
300 408 * application integrity.
  409 + *
  410 + * (EP 2020)
  411 + * NIVEAU 2 DE VALIDATION : au moment où les Entity sont persistées dans la BD
  412 + * On vérifie ici le sens des données (ce que l'application va en faire)
  413 + * Le niveau 1 "Validation Rules" est appliqué par la fonction validationDefault() ci-dessus
  414 +
301 415 *
302 416 * @param \Cake\ORM\RulesChecker $rules
303 417 * The rules object to be modified.
304 418 * @return \Cake\ORM\RulesChecker
305 419 */
306   - public function buildRules(RulesChecker $rules)
  420 + public function buildRules(RulesChecker $rules) //: RulesChecker
307 421 {
308 422 //$configuration = TableRegistry::get('Configurations')->find()
309 423 /*
... ... @@ -348,6 +462,27 @@ class MaterielsTable extends AppTable
348 462 //return ($entity->prix_ht !== null);
349 463 return true;
350 464 };
  465 +
  466 + // Check dates
  467 + $dateIsAfterDateAchat = function ($entity) {
  468 + $tz = new \DateTimeZone('Europe/Paris');
  469 + // DateTime lit les dates au format JJ-MM-YYYY (et non pas JJ/MM/YYYY)
  470 + $d1 = ( new \DateTime(strtr($entity->date_acquisition,'/','-'),$tz) )->format('Ymd');
  471 + $d2 = ( new \DateTime(strtr($entity->date_reception,'/','-'),$tz) )->format('Ymd');
  472 + //date_default_timezone_set('Europe/Paris');
  473 + //$today = (new \DateTime('now',$tz))->format('Ymd');
  474 + return ($d2 >= $d1);
  475 + };
  476 + $dateIsAfterDateReception = function ($entity) {
  477 + $tz = new \DateTimeZone('Europe/Paris');
  478 + // DateTime lit les dates au format JJ-MM-YYYY (et non pas JJ/MM/YYYY)
  479 + $d1 = ( new \DateTime(strtr($entity->date_reception,'/','-'),$tz) )->format('Ymd');
  480 + $d2 = ( new \DateTime(strtr($entity->date_fin_garantie,'/','-'),$tz) )->format('Ymd');
  481 + //date_default_timezone_set('Europe/Paris');
  482 + //$today = (new \DateTime('now',$tz))->format('Ymd');
  483 + return ($d2 >= $d1);
  484 + };
  485 +
351 486 /*
352 487 $rules->add($checkAtLeastOneChecked, [
353 488 'errorField' => 'materiel_administratif',
... ... @@ -408,6 +543,17 @@ class MaterielsTable extends AppTable
408 543 //$rules->add($rules->existsIn(['photo_id'], 'Photos'));
409 544 ///$rules->add($rules->existsIn(['fournisseur_id'], 'Fournisseurs'));
410 545  
  546 + // Check dates reception et fin garantie
  547 + $rules->add($dateIsAfterDateAchat, [
  548 + 'errorField' => 'date_reception',
  549 + 'message' => "La date doit être postérieure à la date d'achat"
  550 + ]);
  551 + $rules->add($dateIsAfterDateReception, [
  552 + 'errorField' => 'date_fin_garantie',
  553 + 'message' => "La date doit être postérieure à la date de livraison"
  554 + ]);
  555 +
  556 +
411 557 return $rules;
412 558 }
413 559  
... ... @@ -427,20 +573,27 @@ class MaterielsTable extends AppTable
427 573 $entity->set('nom_ancien_responsable', $entity->get('nom_responsable'));
428 574 }
429 575 */
430   - // numero_laboratoire generator (QC changed this in Jan 2015)
  576 + /*
431 577 $configuration = TableRegistry::get('Configurations')->find()
432 578 ->where([
433 579 'id =' => 1
434 580 ]) -> first();
435   -
  581 + */
  582 + $configuration = TableRegistry::get('Configurations')->get(1);
  583 +
  584 + // numero_laboratoire generator (QC changed this in Jan 2015)
436 585 // (EP) Set new $labNumber (laboratory number) for this new materiel
437 586 $WITH_YEAR = FALSE;
438 587 $DATE_GIVEN = TRUE;
439   - if (!$configuration->numero_labo_sans_annee) {
  588 + if (! $configuration->numero_labo_sans_annee) {
440 589 $WITH_YEAR = TRUE;
441 590 $DATE_GIVEN = !empty($entity->get('date_acquisition'));
442 591 }
443   - if ( empty($entity->get('numero_laboratoire')) && $DATE_GIVEN ) {
  592 + // (EP 202007)
  593 + // Numero inventaire généré 1 seule fois (la toute première)
  594 + //if ( empty($entity->get('numero_laboratoire')) && $DATE_GIVEN ) {
  595 + // Numero inventaire regénéré A CHAQUE FOIS
  596 + if ( $DATE_GIVEN ) {
444 597 if ($WITH_YEAR) {
445 598 $year=substr($entity->get('date_acquisition'), 6, 4);
446 599 if (strlen($year) == 2) {
... ...
src/Template/Materiels/add_edit.ctp
... ... @@ -550,12 +550,13 @@ if (isset($cpMateriel)) {
550 550 </div>
551 551 <?php
552 552  
  553 + $comment = 'Entrez une date (JJ/MM/AAAA)';
553 554 // - Date acquisition
554 555 echo $this->Form->control('date_acquisition', [
555 556 'type' => 'text',
556 557 'label' => 'Date commande (BC)',
557 558 'class' => 'datepicker',
558   - 'placeholder' => 'Cliquez pour une date (JJ/MM/AAAA)',
  559 + 'placeholder' => $comment,
559 560 // ADD only
560 561 //'default' => $Date_acquisition
561 562 //'default' => $materiel->date_acquisition,
... ... @@ -569,7 +570,7 @@ if (isset($cpMateriel)) {
569 570 'type' => 'text',
570 571 'label' => 'Date de réception',
571 572 'class' => 'datepicker',
572   - 'placeholder' => 'A éditer lors de la réception uniquement.',
  573 + 'placeholder' => $comment,
573 574 'empty' => true,
574 575 // ADD only
575 576 //'default' => $Date_reception
... ... @@ -613,7 +614,7 @@ if (isset($cpMateriel)) {
613 614 echo $this->Form->control('date_fin_garantie', [
614 615 'type' => 'text',
615 616 'label' => 'Date fin de garantie',
616   - 'placeholder' => 'Cliquez pour selectionner une date',
  617 + 'placeholder' => $comment,
617 618 'class' => 'datepicker',
618 619 'default' => NULL
619 620 ]);
... ... @@ -1111,6 +1112,7 @@ $(document).ready(function() {
1111 1112 /**
1112 1113 * OnChange durée garantie OU unité => calcul date fin de garantie
1113 1114 */
  1115 + /*
1114 1116 function calcul_date_fin_garantie(event) {
1115 1117 if($("#date-reception").val() != "" && $("#duree-garantie").val() != "") {
1116 1118 var url = document.URL;
... ... @@ -1125,6 +1127,7 @@ $(document).ready(function() {
1125 1127 }
1126 1128 $("#duree-garantie").bind("change", calcul_date_fin_garantie(event));
1127 1129 $("#unite-duree-garantie").bind("change", calcul_date_fin_garantie(event));
  1130 + */
1128 1131 /*
1129 1132 TODO: factoriser, c'est 2 fois la MEME fonction !!!
1130 1133 // - OnChange durée
... ...
webroot/js/Verifications_dates_materiels.js
... ... @@ -209,12 +209,12 @@ $(document).ready(function () {
209 209  
210 210 // (EP 20200410) Vérification date cde <= date réception
211 211 function check_date_acq_inf_date_rec() {
212   - return check_dates_d1_inf_d2("#date-acquisition", "#date-reception", "La date de réception doit être postérieure à la date d'acquisition");
  212 + return check_dates_d1_inf_d2("#date-acquisition", "#date-reception", "La date de réception doit être postérieure à la date d'achat");
213 213 }
214 214  
215 215 //(EP 20200410) Vérification date rec <= date garantie
216 216 function check_date_rec_inf_date_gar() {
217   - return check_dates_d1_inf_d2("#date-reception", "#date-fin-garantie", "La date de fin de garantie doit être supérieure à la date de réception");
  217 + return check_dates_d1_inf_d2("#date-reception", "#date-fin-garantie", "La date de fin de garantie doit être supérieure à la date de livraison");
218 218 }
219 219  
220 220  
... ... @@ -257,7 +257,7 @@ function date_fin_garantie_update() {
257 257 $.ajax({
258 258 url: dateUrl + $("#date-reception").val() + "/" + $("#duree-garantie").val() + "/" + $("#unite-duree-garantie").val()
259 259 }).done(function(data) {
260   - $("#date-fin-garantie").val(data)
  260 + $("#date-fin-garantie").val(data.trim())
261 261 });
262 262 }
263 263 }
... ...