From 8925a86103941ea09f2c6a80cc20b607617cdf3f Mon Sep 17 00:00:00 2001
From: Patrick Barroca <pbarroca@afi-sa.fr>
Date: Thu, 18 Jun 2020 16:31:45 +0200
Subject: [PATCH] dev #111127 : drive : add created at datetime, display in
 admin and csv exports

---
 VERSIONS_WIP/111127                           |   3 +-
 .../controllers/SessionActivityController.php |   7 +-
 cosmogramme/sql/patch/patch_390.php           |   6 +
 library/Class/DriveCheckout.php               |  35 +++++-
 library/Class/DriveCheckout/Hold.php          |   7 ++
 library/Class/Entity.php                      |   7 +-
 .../DriveCheckout/HoldsWithCheckouts.php      |  19 ++-
 .../TableDescription/DriveCheckout/List.php   |   4 +-
 .../DriveCheckout/ListWithActions.php         |   1 +
 .../TableDescription/PNBItemsRenderer.php     |   7 +-
 library/Trait/GetterByAttributeName.php       |  27 ++++
 tests/db/UpgradeDBTest.php                    |  21 ++++
 .../DriveCheckOutBookingTest.php              |   5 +-
 .../DriveCheckoutAdminControllerTest.php      | 115 ++++++++++--------
 14 files changed, 178 insertions(+), 86 deletions(-)
 create mode 100644 cosmogramme/sql/patch/patch_390.php
 create mode 100644 library/Trait/GetterByAttributeName.php

diff --git a/VERSIONS_WIP/111127 b/VERSIONS_WIP/111127
index afe6b2c02f0..a2f406ad2b5 100644
--- a/VERSIONS_WIP/111127
+++ b/VERSIONS_WIP/111127
@@ -6,4 +6,5 @@
        - prise de rendez-vous : s'il n'y a qu'un site de retrait possible l'abonné est dirigé directement sur le choix d'une date pour ce site
        - prise de rendez-vous : nouvelle variable "DRIVE_DISABLE_HOLD_CHECK" permettant la prise de rendez-vous sans vérification de l'existence ou de l'état des réservations de l'abonné
        - prise de rendez-vous : modification du libellé de suppression pour "Annuler ou replanifier", ajout de détail dans le message de confirmation de suppression
-       - prise de rendez-vous : ajout d'une notification par mail lors de la suppression
\ No newline at end of file
+       - prise de rendez-vous : ajout d'une notification par mail lors de la suppression
+       - prise de rendez-vous : enregistrement de la date de création du rendez-vous qui est affichée en administration et présentée dans les exports csv
\ No newline at end of file
diff --git a/application/modules/admin/controllers/SessionActivityController.php b/application/modules/admin/controllers/SessionActivityController.php
index b93a06c2328..f02b6bc5886 100644
--- a/application/modules/admin/controllers/SessionActivityController.php
+++ b/application/modules/admin/controllers/SessionActivityController.php
@@ -308,6 +308,8 @@ class SessionOneLetterPerDayFusionStrategy extends AbstractSessionFusionStrategy
 
 
 class FusionDateContext {
+  use Trait_GetterByAttributeName;
+
   protected $_current_date;
 
   public function __construct($datestr=null) {
@@ -339,11 +341,6 @@ class FusionDateContext {
     $other_date->sub($this->_current_date);
     return ($other_date->toValue(Zend_Date::DAY)-1);
   }
-
-
-  public function callGetterByAttributeName($attribute) {
-    return call_user_func(array($this, 'get'.Storm_Inflector::camelize($attribute)));
-  }
 }
 
 
diff --git a/cosmogramme/sql/patch/patch_390.php b/cosmogramme/sql/patch/patch_390.php
new file mode 100644
index 00000000000..f1fa358912d
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_390.php
@@ -0,0 +1,6 @@
+<?php
+$adapter = Zend_Db_Table::getDefaultAdapter();
+
+try {
+  $adapter->query('alter table drive_checkout add created_at datetime not null');
+} catch (Exception $e) {}
diff --git a/library/Class/DriveCheckout.php b/library/Class/DriveCheckout.php
index 2cb7d61ceaa..754b326a686 100644
--- a/library/Class/DriveCheckout.php
+++ b/library/Class/DriveCheckout.php
@@ -80,7 +80,9 @@ class Class_DriveCheckoutLoader extends Storm_Model_Loader {
 
 
 class Class_DriveCheckout extends Storm_Model_Abstract {
-  use Trait_Translator;
+  use Trait_Translator, Trait_TimeSource;
+
+  const DATETIME_FORMAT = 'Y-m-d H:i:s';
 
   protected
     $_loader_class = 'Class_DriveCheckoutLoader',
@@ -94,6 +96,12 @@ class Class_DriveCheckout extends Storm_Model_Abstract {
     $_date_time_label;
 
 
+  public function beforeSave() {
+    if ($this->isNew())
+      $this->setCreatedAt($this->getCurrentDateTime());
+  }
+
+
   public function getLibraryLabel() {
     return ($library = $this->getLibrary())
       ? $library->getLibelle()
@@ -123,8 +131,29 @@ class Class_DriveCheckout extends Storm_Model_Abstract {
   }
 
 
+  public function getCreatedAtLabel() {
+    return ($created = $this->getDateTimeCreatedAt())
+      ? strftime($this->_('%d %B à %Hh%M'), $created->getTimestamp())
+      : $this->_('n/a');
+  }
+
+
+  public function getCreatedAtForCsv() {
+    return ($created = $this->getDateTimeCreatedAt())
+      ? $created->format(static::DATETIME_FORMAT)
+      : '';
+  }
+
+
+  public function getDateTimeCreatedAt() {
+    return ($date_time = $this->getCreatedAt()) && $date_time != '0000-00-00 00:00:00'
+      ? DateTime::createFromFormat(static::DATETIME_FORMAT, $date_time)
+      : null;
+  }
+
+
   public function getDateTimeStartAt() {
-    return DateTime::createFromFormat('Y-m-d H:i:s', $this->getStartAt());
+    return DateTime::createFromFormat(static::DATETIME_FORMAT, $this->getStartAt());
   }
 
 
@@ -191,4 +220,4 @@ class Class_DriveCheckout extends Storm_Model_Abstract {
   public function notifyDelete() {
     return (new Class_DriveCheckout_DeletionNotification($this))->send();
   }
-}
\ No newline at end of file
+}
diff --git a/library/Class/DriveCheckout/Hold.php b/library/Class/DriveCheckout/Hold.php
index b5690377a5d..631ca5b63d0 100644
--- a/library/Class/DriveCheckout/Hold.php
+++ b/library/Class/DriveCheckout/Hold.php
@@ -21,6 +21,8 @@
 
 
 class Class_DriveCheckout_Hold {
+  use Trait_GetterByAttributeName;
+
   protected
     $_checkout,
     $_hold,
@@ -48,6 +50,11 @@ class Class_DriveCheckout_Hold {
   }
 
 
+  public function getCreatedAtForCsv() {
+    return $this->_checkout->getCreatedAtForCsv();
+  }
+
+
   public function getCote() {
     return $this->_item
       ? $this->_item->getCote()
diff --git a/library/Class/Entity.php b/library/Class/Entity.php
index 10bab2a777e..998bf5f1043 100644
--- a/library/Class/Entity.php
+++ b/library/Class/Entity.php
@@ -21,6 +21,8 @@
 
 
 class Class_Entity {
+  use Trait_GetterByAttributeName;
+
   protected
     $_attribs = [],
     $_methods = [];
@@ -80,11 +82,6 @@ class Class_Entity {
   }
 
 
-  public function callGetterByAttributeName($attribute) {
-    return call_user_func([$this, 'get' . Storm_Inflector::camelize($attribute)]);
-  }
-
-
   public function __toString() {
     return get_class($this);
   }
diff --git a/library/Class/TableDescription/DriveCheckout/HoldsWithCheckouts.php b/library/Class/TableDescription/DriveCheckout/HoldsWithCheckouts.php
index cba0bb694df..7a365926794 100644
--- a/library/Class/TableDescription/DriveCheckout/HoldsWithCheckouts.php
+++ b/library/Class/TableDescription/DriveCheckout/HoldsWithCheckouts.php
@@ -27,19 +27,14 @@ class Class_TableDescription_DriveCheckout_HoldsWithCheckouts extends Class_Tabl
                   function($hold) { return strftime('%d %B',strtotime($hold->getStartAt())); })
       ->addColumn($this->_('Heure'),
                   function($hold) { return strftime('%H:%M',strtotime($hold->getStartAt())); })
-      ->addColumn($this->_('Carte'),
-                  function($hold) { return $hold->getIdabon(); })
-      ->addColumn($this->_('Abonné'),
-                  function($hold) { return $hold->getNomComplet(); })
-      ->addColumn($this->_('Section'),
-                  function($hold) { return $hold->getSectionLabel(); })
-      ->addColumn($this->_('Emplacement'),
-                  function($hold) { return $hold->getEmplacementLabel(); })
-      ->addColumn($this->_('Cote'),
-                  function($hold) { return $hold->getCote(); })
 
-      ->addColumn($this->_('Code-barres'),
-                  function($hold) { return $hold->getCodeBarres(); })
+      ->addColumn($this->_('Carte'), 'idabon')
+      ->addColumn($this->_('Abonné'), 'nom_complet')
+      ->addColumn($this->_('Créé le'), 'created_at_for_csv')
+      ->addColumn($this->_('Section'), 'section_label')
+      ->addColumn($this->_('Emplacement'), 'emplacement_label')
+      ->addColumn($this->_('Cote'), 'cote')
+      ->addColumn($this->_('Code-barres'), 'code_barres')
 
       ->addColumn($this->_('Titre'),
                   function($hold){ return strip_tags($hold->getTitle()); });
diff --git a/library/Class/TableDescription/DriveCheckout/List.php b/library/Class/TableDescription/DriveCheckout/List.php
index 31b86158f86..b648ca6153b 100644
--- a/library/Class/TableDescription/DriveCheckout/List.php
+++ b/library/Class/TableDescription/DriveCheckout/List.php
@@ -36,6 +36,8 @@ class Class_TableDescription_DriveCheckout_List extends Class_TableDescription {
                                     strtotime($checkout->getStartAt()));
                   })
       ->addColumn($this->_('Carte'), 'id_abon')
-      ->addColumn($this->_('Abonné'), 'nom_complet');
+      ->addColumn($this->_('Abonné'), 'nom_complet')
+      ->addColumn($this->_('Créé le'), 'created_at_for_csv')
+      ;
   }
 }
\ No newline at end of file
diff --git a/library/Class/TableDescription/DriveCheckout/ListWithActions.php b/library/Class/TableDescription/DriveCheckout/ListWithActions.php
index aa28d82e8e2..a56c6efa3d8 100644
--- a/library/Class/TableDescription/DriveCheckout/ListWithActions.php
+++ b/library/Class/TableDescription/DriveCheckout/ListWithActions.php
@@ -32,6 +32,7 @@ class Class_TableDescription_DriveCheckout_ListWithActions extends Class_TableDe
                   })
       ->addColumn($this->_('Carte'), 'id_abon')
       ->addColumn($this->_('Abonné'), 'nom_complet')
+      ->addColumn($this->_('Créé le'), 'created_at_label')
       ->addRowAction(['canvas_callback' => [$this, 'listHolds']])
       ->addRowAction(['canvas_callback' => [$this, 'viewUser']])
       ->addRowAction(['canvas_callback' => [$this, 'deleteCheckout']])
diff --git a/library/Class/TableDescription/PNBItemsRenderer.php b/library/Class/TableDescription/PNBItemsRenderer.php
index f40234de32f..72c48ce68b4 100644
--- a/library/Class/TableDescription/PNBItemsRenderer.php
+++ b/library/Class/TableDescription/PNBItemsRenderer.php
@@ -21,6 +21,8 @@
 
 
 class Class_TableDescription_PNBItemsRenderer {
+  use Trait_GetterByAttributeName;
+
   protected $_item;
 
   public function __construct($item) {
@@ -28,11 +30,6 @@ class Class_TableDescription_PNBItemsRenderer {
   }
 
 
-  public function callGetterByAttributeName($attribute) {
-    return call_user_func([$this, 'get' . Storm_Inflector::camelize($attribute)]);
-  }
-
-
   public function __call($name, $params) {
     return call_user_func_array([$this->_item, $name], $params);
   }
diff --git a/library/Trait/GetterByAttributeName.php b/library/Trait/GetterByAttributeName.php
new file mode 100644
index 00000000000..4b3208ef0a2
--- /dev/null
+++ b/library/Trait/GetterByAttributeName.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+trait Trait_GetterByAttributeName {
+  public function callGetterByAttributeName($name) {
+    return call_user_func([$this, 'get' . Storm_Inflector::camelize($name)]);
+  }
+}
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index c5338f69a40..56f0ae89617 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -239,6 +239,12 @@ abstract class UpgradeDBTestCase extends PHPUnit_Framework_TestCase {
   }
 
 
+  protected function dropFieldFrom($table, $field) {
+    return $this->silentQuery(sprintf('alter table %s drop column %s',
+                                      $table, $field));
+  }
+
+
   protected function dropIndexedFieldFrom($table, $field) {
     return $this->silentQuery('ALTER TABLE ' . $table . ' '
                               . 'DROP KEY ' . $field . ', '
@@ -3322,4 +3328,19 @@ class UpgradeDB_389_Test extends UpgradeDBTestCase {
   public function tableOuverturesShouldContainsColumnMaxPerPeriodApresMidiAsInt(){
     $this->assertFieldType('ouvertures', 'max_per_period_apres_midi', 'int(11)');
   }
+}
+
+
+
+
+class UpgradeDB_390_Test extends UpgradeDBTestCase {
+  public function prepare() {
+    $this->dropFieldFrom('drive_checkout', 'created_at');
+  }
+
+
+  /** @test */
+  public function tableDriveCheckoutShouldContainsCreatedAtColumn() {
+    $this->assertFieldType('drive_checkout', 'created_at', 'datetime');
+  }
 }
\ No newline at end of file
diff --git a/tests/scenarios/DriveCheckOut/DriveCheckOutBookingTest.php b/tests/scenarios/DriveCheckOut/DriveCheckOutBookingTest.php
index 3841230060f..60be3e417c4 100644
--- a/tests/scenarios/DriveCheckOut/DriveCheckOutBookingTest.php
+++ b/tests/scenarios/DriveCheckOut/DriveCheckOutBookingTest.php
@@ -60,6 +60,7 @@ abstract class DriveCheckOutBookingTestCase extends AbstractControllerTestCase {
 
     $timesource = new TimeSourceForTest('2020-05-05 11:30');
     Class_DriveCheckout_Plan::setTimeSource($timesource);
+    Class_DriveCheckout::setTimeSource($timesource);
 
     $this->_mail_transport = new MockMailTransport();
     Zend_Mail::setDefaultTransport($this->_mail_transport);
@@ -72,6 +73,7 @@ abstract class DriveCheckOutBookingTestCase extends AbstractControllerTestCase {
 
   public function tearDown() {
     Class_DriveCheckout_Plan::setTimeSource(null);
+    Class_DriveCheckout::setTimeSource(null);
     Class_Systeme_ModulesAccueil::reset();
     parent::tearDown();
   }
@@ -807,7 +809,8 @@ class DriveCheckOutBookingPlanBibHotelDieuAt2020_05_12_09_00Test
   public function checkoutShouldBePlanned() {
     $this->assertNotNull(Class_DriveCheckout::findFirstBy(['user_id' => $this->_marcus->getId(),
                                                            'library_id' => 1,
-                                                           'start_at' => '2020-05-12 09:00:00']));
+                                                           'start_at' => '2020-05-12 09:00:00',
+                                                           'created_at' => '2020-05-05 11:30:00']));
   }
 
 
diff --git a/tests/scenarios/DriveCheckOut/DriveCheckoutAdminControllerTest.php b/tests/scenarios/DriveCheckOut/DriveCheckoutAdminControllerTest.php
index 88f3e5724f9..5694ab45f36 100644
--- a/tests/scenarios/DriveCheckOut/DriveCheckoutAdminControllerTest.php
+++ b/tests/scenarios/DriveCheckOut/DriveCheckoutAdminControllerTest.php
@@ -86,6 +86,41 @@ abstract class DriveCheckOutAdminControllerTestCase extends Admin_AbstractContro
                     'libelle' => 'BD',
                     'regles' => '995$e=bd']);
 
+    $holds = [Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
+              ->setExemplaireOPAC($this->fixture('Class_Exemplaire',
+                                                 ['id' => 2,
+                                                  'code_barres' => 'tintin123',
+                                                  'notice' => $this->fixture('Class_Notice',
+                                                                             ['id' => 123,
+                                                                              'titre_principal' => 'Tintin à Dole']),
+                                                  'emplacement' => 2,
+                                                  'section' => 3,
+                                                  'cote' => 'BD2']))
+              ->setBibliotheque($lib_camus->getLibelle())
+              ->setCodeBarre('tintin123')
+              ->setTitre('Tintin à Dole')
+              ->setEtat('On le cherche')
+              ->setWaitingToBePulled(),
+
+              Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
+              ->setBibliotheque($lib_camus->getLibelle())
+              ->setCodeBarre('milou123')
+              ->setTitre('Milou à Dole')
+              ->setWaitingToBePulled(),
+
+              Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
+              ->setBibliotheque($lib_maurissette->getLibelle())
+              ->setCodeBarre('tournesol123')
+              ->setEtat('Disponible')
+              ->setTitre('Tournesol à Maurissette')
+              ->setWaitingToBePulled(),
+
+              Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
+              ->setBibliotheque($lib_camus->getLibelle())
+              ->setCodeBarre('dupont123')
+              ->setTitre('Dupont à Dole')
+    ];
+
     $maurice = $this->fixture('Class_Users',
                               ['id' => 4,
                                'login' => 'maurice',
@@ -95,78 +130,48 @@ abstract class DriveCheckOutAdminControllerTestCase extends Admin_AbstractContro
                                'bib' => $lib_hotel_dieu])
                     ->setFicheSigb(['type_comm' => Class_IntBib::COM_NANOOK,
                                     'fiche' => (new Class_WebService_SIGB_Emprunteur(4, 'Maurice'))
-                                    ->reservationsAddAll(
-                                                         [Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
-                                                          ->setExemplaireOPAC($this->fixture('Class_Exemplaire',
-                                                                                             ['id' => 2,
-                                                                                              'code_barres' => 'tintin123',
-                                                                                              'notice' => $this->fixture('Class_Notice',
-                                                                                                                         ['id' => 123,
-                                                                                                                          'titre_principal' => 'Tintin à Dole']),
-                                                                                              'emplacement' => 2,
-                                                                                              'section' => 3,
-                                                                                              'cote' => 'BD2']))
-                                                          ->setBibliotheque($lib_camus->getLibelle())
-                                                          ->setCodeBarre('tintin123')
-                                                          ->setTitre('Tintin à Dole')
-                                                          ->setEtat('On le cherche')
-                                                          ->setWaitingToBePulled(),
-
-                                                          Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
-                                                          ->setBibliotheque($lib_camus->getLibelle())
-                                                          ->setCodeBarre('milou123')
-                                                          ->setTitre('Milou à Dole')
-                                                          ->setWaitingToBePulled(),
-
-                                                          Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
-                                                          ->setBibliotheque($lib_maurissette->getLibelle())
-                                                          ->setCodeBarre('tournesol123')
-                                                          ->setEtat('Disponible')
-                                                          ->setTitre('Tournesol à Maurissette')
-                                                          ->setWaitingToBePulled(),
-
-                                                          Class_WebService_SIGB_Reservation::newInstanceWithEmptyExemplaire()
-                                                          ->setBibliotheque($lib_camus->getLibelle())
-                                                          ->setCodeBarre('dupont123')
-                                                          ->setTitre('Dupont à Dole')
-                                                         ])]);
-
+                                    ->reservationsAddAll($holds)]);
 
     $this->fixture('Class_DriveCheckout',
                    ['id' => 1,
                     'user' => $emilie,
                     'library' => $lib_hotel_dieu,
-                    'start_at' => '2020-05-12 09:00:00']);
+                    'start_at' => '2020-05-12 09:00:00',
+                    'created_at' => '0000-00-00 00:00:00']);
 
     $this->fixture('Class_DriveCheckout',
                    ['id' => 2,
                     'user' => $bernard,
                     'library' => $lib_hotel_dieu,
-                    'start_at' => '2020-05-12 14:00:00']);
+                    'start_at' => '2020-05-12 14:00:00',
+                    'created_at' => '2020-05-02 23:46:33']);
 
     $this->fixture('Class_DriveCheckout',
                    ['id' => 3,
                     'user' => $maurice,
                     'library' => $lib_camus,
-                    'start_at' => '2020-05-14 09:00:00']);
+                    'start_at' => '2020-05-14 09:00:00',
+                    'created_at' => '0000-00-00 00:00:00']);
 
     $this->fixture('Class_DriveCheckout',
                    ['id' => 4,
                     'user' => $emilie,
                     'library' => $lib_camus,
-                    'start_at' => '2020-05-14 09:15:00']);
+                    'start_at' => '2020-05-14 09:15:00',
+                    'created_at' => '2020-05-03 19:32:55']);
 
     $this->fixture('Class_DriveCheckout',
                    ['id' => 5,
                     'user' => $bernard,
                     'library' => $lib_camus,
-                    'start_at' => '2020-05-15 10:00:00']);
-
+                    'start_at' => '2020-05-15 10:00:00',
+                    'created_at' => '0000-00-00 00:00:00']);
   }
 }
 
 
 
+
 class DriveCheckoutAdminControllerAdminVarTest extends DriveCheckOutAdminControllerTestCase {
   /** @test */
   public function withAdminVarEnableDriveFalseShouldNotDisplayMenuEntry() {
@@ -266,13 +271,13 @@ class DriveCheckoutAdminControllerListHotelDieuTest extends DriveCheckOutAdminCo
 
   /** @test */
   public function pageShouldContainsTableWithCheckout2020_05_12_at_9_00_For_Emilie() {
-    $this->assertXPath('//table//td[text()="09:00"]/following-sibling::td[text()="A121"]/following-sibling::td[text()="emilie"]');
+    $this->assertXPath('//table//td[text()="09:00"]/following-sibling::td[text()="A121"]/following-sibling::td[text()="emilie"]/following-sibling::td[text()="n/a"]');
   }
 
 
   /** @test */
   public function pageShouldContainsTableWithCheckout2020_05_12_at_14_00_For_Bernard() {
-    $this->assertXPath('//table//td[text()="14:00"]/following-sibling::td[text()="A123"]/following-sibling::td[text()="bernard"]');
+    $this->assertXPath('//table//td[text()="14:00"]/following-sibling::td[text()="A123"]/following-sibling::td[text()="bernard"]/following-sibling::td[text()="02 mai à 23h46"]');
   }
 
 
@@ -373,7 +378,9 @@ class DriveCheckoutAdminControllerListCamusOnMayFourteenthDaysSevenTest extends
 
 
 
-class DriveCheckoutAdminControllerExportCSVCamusOnMayFourteenthTest extends DriveCheckOutAdminControllerTestCase {
+class DriveCheckoutAdminControllerExportCSVCamusOnMayFourteenthTest
+  extends DriveCheckOutAdminControllerTestCase {
+
   public function setUp() {
     parent::setUp();
     $this->dispatch('/admin/drive-checkout/list-csv/id_bib/2/date/2020-05-14');
@@ -390,9 +397,9 @@ class DriveCheckoutAdminControllerExportCSVCamusOnMayFourteenthTest extends Driv
 
   /** @test */
   public function csvShouldContainsCheckouts() {
-    $this->assertEquals("Jour;Heure;Carte;Abonné\n"
-                        ."\"14 mai\";09:00;A124;maurice\n"
-                        ."\"14 mai\";09:15;A121;emilie\n",
+    $this->assertEquals("Jour;Heure;Carte;Abonné;\"Créé le\"\n"
+                        ."\"14 mai\";09:00;A124;maurice;\n"
+                        ."\"14 mai\";09:15;A121;emilie;\"2020-05-03 19:32:55\"\n",
                         $this->_response->getBody());
   }
 }
@@ -400,7 +407,9 @@ class DriveCheckoutAdminControllerExportCSVCamusOnMayFourteenthTest extends Driv
 
 
 
-class DriveCheckoutAdminControllerListHoldsForCheckoutThreeTest extends DriveCheckOutAdminControllerTestCase {
+class DriveCheckoutAdminControllerListHoldsForCheckoutThreeTest
+  extends DriveCheckOutAdminControllerTestCase {
+
   public function setUp() {
     parent::setUp();
     $this->dispatch('/admin/drive-checkout/list-holds/id/3');
@@ -486,10 +495,10 @@ class DriveCheckoutAdminControllerExportItemsCSVCamusOnMayFourteenthTest extends
 
   /** @test */
   public function csvShouldContainsTintinMilouAndDupontItems() {
-    $this->assertEquals("Jour;Heure;Carte;Abonné;Section;Emplacement;Cote;Code-barres;Titre\n"
-                        . "\"14 mai\";09:00;A124;maurice;Jeunesse;BD;BD2;tintin123;\"Tintin à Dole\"\n"
-                        . "\"14 mai\";09:00;A124;maurice;;;;milou123;\"Milou à Dole\"\n"
-                        . "\"14 mai\";09:00;A124;maurice;;;;dupont123;\"Dupont à Dole\"\n",
+    $this->assertEquals("Jour;Heure;Carte;Abonné;\"Créé le\";Section;Emplacement;Cote;Code-barres;Titre\n"
+                        . "\"14 mai\";09:00;A124;maurice;;Jeunesse;BD;BD2;tintin123;\"Tintin à Dole\"\n"
+                        . "\"14 mai\";09:00;A124;maurice;;;;;milou123;\"Milou à Dole\"\n"
+                        . "\"14 mai\";09:00;A124;maurice;;;;;dupont123;\"Dupont à Dole\"\n",
                         $this->_response->getBody());
   }
 }
-- 
GitLab