diff --git a/application/modules/admin/controllers/MultimediaController.php b/application/modules/admin/controllers/MultimediaController.php index 8cfcb77623915a4dbb641918dda4f9c0c44097e5..aab04669bb71c47e712178ac5f1bb32c84d32319 100644 --- a/application/modules/admin/controllers/MultimediaController.php +++ b/application/modules/admin/controllers/MultimediaController.php @@ -11,87 +11,121 @@ * * AFI-OPAC 2.0 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 + * 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 AFI-OPAC 2.0; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class Admin_MultimediaController extends ZendAfi_Controller_Action { - public function getRessourceDefinitions() { - return array( - 'model' => array('class' => 'Class_Multimedia_Location', 'name' => 'site'), - 'messages' => array('successful_save' => 'Site %s sauvegardé'), - 'actions' => array('edit' => array('title' => 'Modifier un site multimédia'), - 'index' => array('title' => 'Sites multimédia')), - 'display_groups' => array('config' => array( - 'legend' => 'Configuration', - 'elements' => array( - 'slot_size' => array( - 'element' => 'text', - 'options' => array( - 'label' => 'Réservation minimale (slot) *', - 'title'=> 'en minutes', - 'size' => 4, - 'required' => true, - 'allowEmpty' => false, - 'validators' => array('digits'))), - 'max_slots' => array( - 'element' => 'text', - 'options' => array( - 'label' => 'Réservation maximale *', - 'title' => 'en nombre de "slots"', - 'size' => 4, - 'required' => true, - 'allowEmpty' => false, - 'validators' => array('digits'))), - 'hold_delay_min' => array( - 'element' => 'text', - 'options' => array( - 'label' => 'Délai minimum de réservation *', - 'title' => 'en jours, 0 autorise les réservations le jour même', - 'size' => 4, - 'required' => true, - 'allowEmpty' => false, - 'validators' => array('digits'))), - 'hold_delay_max' => array( - 'element' => 'text', - 'options' => array( - 'label' => 'Délai maximum de réservation *', - 'title' => 'en jours, doit être supérieur au délai minimum', - 'size' => 4, - 'required' => true, - 'allowEmpty' => false, - 'validators' => array('digits', new ZendAfi_Validate_FieldGreater('hold_delay_min', 'Délai minimum de réservation')))), - 'auth_delay' => array( - 'element' => 'text', - 'options' => array( - 'label' => 'Délai de connection *', - 'title' => 'en minutes, passé ce délai la réservation est annulée', - 'size' => 4, - 'required' => true, - 'allowEmpty' => false, - 'validators' => array('digits'))), - 'autohold' => array( - 'element' => 'checkbox', - 'options' => array( - 'label' => 'Autoriser la réservation automatique *', - 'title' => 'quand un abonné se connecte sur un poste non réservé, une réservation lui est attribuée', - 'required' => true, - 'allowEmpty' => false)), - 'autohold_slots_max' => array( - 'element' => 'text', - 'options' => array( - 'label' => 'Réservation automatique maximale *', - 'title' => 'en nombre de "slots"', - 'size' => 4, - 'required' => true, - 'allowEmpty' => false, - 'validators' => array('digits'))), + public function getRessourceDefinitions() { + return array( + 'model' => array('class' => 'Class_Multimedia_Location', 'name' => 'site'), + 'messages' => array('successful_save' => 'Site %s sauvegardé'), + 'actions' => array('edit' => array('title' => 'Modifier un site multimédia'), + 'index' => array('title' => 'Sites multimédia')), + 'display_groups' => array( + 'config' => array( + 'legend' => 'Réservation', + 'elements' => array( + 'slot_size' => array( + 'element' => 'text', + 'options' => array( + 'label' => 'Réservation minimale (slot) *', + 'title'=> 'en minutes', + 'size' => 4, + 'required' => true, + 'allowEmpty' => false, + 'validators' => array('digits'))), + 'max_slots' => array( + 'element' => 'text', + 'options' => array( + 'label' => 'Réservation maximale *', + 'title' => 'en nombre de "slots"', + 'size' => 4, + 'required' => true, + 'allowEmpty' => false, + 'validators' => array('digits'))), + 'hold_delay_min' => array( + 'element' => 'text', + 'options' => array( + 'label' => 'Délai minimum de réservation *', + 'title' => 'en jours, 0 autorise les réservations le jour même', + 'size' => 4, + 'required' => true, + 'allowEmpty' => false, + 'validators' => array('digits'))), + 'hold_delay_max' => array( + 'element' => 'text', + 'options' => array( + 'label' => 'Délai maximum de réservation *', + 'title' => 'en jours, doit être supérieur au délai minimum', + 'size' => 4, + 'required' => true, + 'allowEmpty' => false, + 'validators' => array('digits', new ZendAfi_Validate_FieldGreater('hold_delay_min', 'Délai minimum de réservation')))), + 'auth_delay' => array( + 'element' => 'text', + 'options' => array( + 'label' => 'Délai de connection *', + 'title' => 'en minutes, passé ce délai la réservation est annulée', + 'size' => 4, + 'required' => true, + 'allowEmpty' => false, + 'validators' => array('digits'))), + 'autohold' => array( + 'element' => 'checkbox', + 'options' => array( + 'label' => 'Autoriser la réservation automatique *', + 'title' => 'quand un abonné se connecte sur un poste non réservé, une réservation lui est attribuée', + 'required' => true, + 'allowEmpty' => false)), + 'autohold_slots_max' => array( + 'element' => 'text', + 'options' => array( + 'label' => 'Réservation automatique maximale *', + 'title' => 'en nombre de "slots"', + 'size' => 4, + 'required' => true, + 'allowEmpty' => false, + 'validators' => array('digits'))), + )), + 'planning' => array( + 'legend' => 'Planning', + 'elements' => array( + 'days' => array( + 'element' => 'multiCheckbox', + 'options' => array( + 'label' => 'Jours d\'ouverture *', + 'multioptions' => Class_Multimedia_Location::getLoader()->getPossibleDays(), + 'separator' => '', + ) + ), + 'open_hour' => array( + 'element' => 'select', + 'options' => array( + 'label' => 'Heure d\'ouverture *', + 'multioptions' => Class_Multimedia_Location::getLoader()->getPossibleHours(15), + 'required' => true, + 'allowEmpty' => false, + 'validators' => array(new Zend_Validate_Regex('/[0-9]{2}:[0-9]{2}/')), + ) + ), + 'close_hour' => array( + 'element' => 'select', + 'options' => array( + 'label' => 'Heure de fermeture *', + 'title' => 'Doit être après l\'heure d\'ouverture', + 'multioptions' => Class_Multimedia_Location::getLoader()->getPossibleHours(15), + 'required' => true, + 'allowEmpty' => false, + 'validators' => array(new Zend_Validate_Regex('/[0-9]{2}:[0-9]{2}/')), + ) ) - )) - ); + ) + ) + )); } @@ -103,14 +137,15 @@ class Admin_MultimediaController extends ZendAfi_Controller_Action { $devices = $location->getDevices(); $this->view->subview = $this->view->partial('multimedia/browse.phtml', - array('titre' => sprintf('Postes du site multimédia "%s"', $location->getLibelle()), - 'devices' => $devices)); + array('titre' => sprintf('Postes du site multimédia "%s"', $location->getLibelle()), + 'devices' => $devices)); $this->_forward('index'); } protected function _postEditAction($model) { $this->view->titre = 'Modification du site multimédia "' . $this->view->escape($model->getLibelle()) . '"'; + $this->view->form->getElement('days')->setValue($model->getDaysAsArray()); } diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php index b5ebb70ef0695a1932ba945127d7bba066ca1ab1..a301644dbe8a41a07b61747ecd33b05e087da0ad 100644 --- a/application/modules/opac/controllers/AbonneController.php +++ b/application/modules/opac/controllers/AbonneController.php @@ -565,6 +565,12 @@ class AbonneController extends Zend_Controller_Action { $this->view->minDate = $location->getMinDate(); $this->view->maxDate = $location->getMaxDate(); + $this->view->beforeShowDay = ' + var result = [true, \'\']; + if (-1 == $.inArray(date.getDay(), [' . $location->getDays() . '])) { + result[0] = false; + } + return result;'; $this->view->timelineActions = $this->_getTimelineActions('day'); } @@ -586,14 +592,21 @@ class AbonneController extends Zend_Controller_Action { $start = $holdLoader->getTimeFromDayAndTime($bean->day, $this->_getParam('time')); $end = $holdLoader->getTimeFromStartAndDuration($start, $this->_getParam('duration')); - if (0 == $holdLoader->countBetweenTimesForUser($start, $end, $this->_user)) { + if (0 < $holdLoader->countBetweenTimesForUser($start, $end, $this->_user)) { + $this->view->error = $this->view->_('Vous avez déjà une réservation dans ce créneau horaire'); + } + + if ($start < $location->getMinTimeForDate($bean->day) + || $end > $location->getMaxTimeForDate($bean->day)) { + $this->view->error = $this->view->_('Ce créneau n\'est pas dans les heures d\'ouverture.'); + } + + if (!$this->view->error) { $bean->time = $this->_getParam('time'); $bean->duration = (int)$this->_getParam('duration'); $this->_redirect('/abonne/multimedia-hold-device'); return; } - - $this->view->error = $this->view->_('Vous avez déjà une réservation dans ce créneau horaire'); } $this->view->timelineActions = $this->_getTimelineActions('hours'); diff --git a/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml b/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml index 0035f08de9eae78ce952f6efef21fb56ce6de54c..66d7a14d1c5634ed2f50c4b33458927b58eb97fb 100644 --- a/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml +++ b/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml @@ -10,7 +10,8 @@ Class_ScriptLoader::getInstance() {onSelect: function (dateText, inst){location.href = location.href + "/day/" + dateText;}, dateFormat: "yy-mm-dd", minDate: "' . $this->minDate . '", - maxDate: "' . $this->maxDate . '"} + maxDate: "' . $this->maxDate . '", + beforeShowDay: function(date){' . $this->beforeShowDay . '}} );'); ?> <div id="hold-day" class="calendar"></div> diff --git a/library/Class/Multimedia/Location.php b/library/Class/Multimedia/Location.php index 09b62dff26ac4d4dc71d00e3f10a5a5e17ce7130..9dd847a39a902cd217dbb280c559bd7edc9c333d 100644 --- a/library/Class/Multimedia/Location.php +++ b/library/Class/Multimedia/Location.php @@ -20,6 +20,44 @@ */ class Multimedia_LocationLoader extends Storm_Model_Loader { + /** + * @return array + */ + public function getPossibleDays() { + $days = array(); + $day = strtotime('next monday'); + for ($i = 0; $i < 7; ++$i) { + $days[strftime('%w', $day)] = strftime('%A', $day); + $day = strtotime('+1 day', $day); + } + return $days; + } + + + /** + * @param $increment int + * @return array + */ + public function getPossibleHours($increment, $from = null, $to = null) { + if (0 == $increment) + return array(); + + if (null == $from) + $from = strtotime('today'); + + if (null == $to) + $to = strtotime('tomorrow'); + + $steps = range($from, $to, 60 * $increment); + + $hours = array(); + foreach ($steps as $step) + $hours[date('H:i', $step)] = date('H\hi', $step); + + return $hours; + } + + /** * @param $json_model stdClass * @return Class_Multimedia_Location @@ -53,21 +91,30 @@ class Class_Multimedia_Location extends Storm_Model_Abstract { * @return array */ public function getStartTimesForDate($date) { - if (0 == $this->getSlotSize()) - return array(); - - $steps = range(strtotime('today'), - strtotime('tomorrow'), - 60 * $this->getSlotSize()); + return $this->getLoader()->getPossibleHours($this->getSlotSize(), + $this->getMinTimeForDate($date), + $this->getMaxTimeForDate($date)); + } - $start_times = array(); - foreach ($steps as $step) - $start_times[date('H:i', $step)] = date('H\hi', $step); - return $start_times; + /** + * @param $date string (YYYY-MM-DD) + * @return int + */ + public function getMinTimeForDate($date) { + return strtotime($date . ' ' . $this->getOpenHour() . ':00'); } + /** + * @param $date string (YYYY-MM-DD) + * @return int + */ + public function getMaxTimeForDate($date) { + return strtotime($date . ' ' . $this->getCloseHour() . ':00'); + } + + /** @return array */ public function getDurations() { if (0 == $this->getSlotSize()) @@ -119,6 +166,20 @@ class Class_Multimedia_Location extends Storm_Model_Abstract { } + /** + * @return array + */ + public function getDaysAsArray() { + return explode(',', $this->getDays()); + } + + + public function beforeSave() { + if (is_array($days = $this->getDays())) + $this->setDays(implode(',', $days)); + } + + /** * @param $duration int in minutes * @return string diff --git a/library/ZendAfi/Controller/Action.php b/library/ZendAfi/Controller/Action.php index b5cf2c93a08a7c03bed68c4c1ccaf6b1d9028a26..a32f5f36c8a1f39e001a3f402c9453951d89711f 100644 --- a/library/ZendAfi/Controller/Action.php +++ b/library/ZendAfi/Controller/Action.php @@ -87,8 +87,9 @@ class ZendAfi_Controller_Action extends Zend_Controller_Action { $this->view->form = $form; if ($this->_request->isPost() && $form->isValid($this->_request->getPost())) { + $values = $form->getValues(); return $model - ->updateAttributes($this->_request->getPost()) + ->updateAttributes($values) ->save(); } return false; @@ -114,10 +115,6 @@ class ZendAfi_Controller_Action extends Zend_Controller_Action { * Hook appelé en fin d'action d'édition * @param $model Storm_Model_Abstract */ - protected function _postEditAction($model) { - - } + protected function _postEditAction($model) {} } - - ?> \ No newline at end of file diff --git a/tests/application/modules/admin/controllers/MultimediaControllerTest.php b/tests/application/modules/admin/controllers/MultimediaControllerTest.php index 7a2c92bcb570677d9846cb28caf5ac7ca01675c1..dcd8f8c6fe58ca5e21afd146f98218cf9622bd42 100644 --- a/tests/application/modules/admin/controllers/MultimediaControllerTest.php +++ b/tests/application/modules/admin/controllers/MultimediaControllerTest.php @@ -75,7 +75,8 @@ class Admin_MultimediaControllerEditTest extends Admin_AbstractControllerTestCas Class_Multimedia_Location::getLoader()->newInstanceWithId(33) ->setLibelle('Antibe') ->setSlotSize(15) - ->setMaxSlots(4); + ->setMaxSlots(4) + ->setDays('3,4'); $this->dispatch('/admin/multimedia/edit/id/33', true); } @@ -127,6 +128,18 @@ class Admin_MultimediaControllerEditTest extends Admin_AbstractControllerTestCas public function autoHoldMaxSlotsInputShouldBePresent() { $this->assertXPath('//input[@name="autohold_slots_max"]'); } + + + /** @test */ + public function openHourShouldBePresent() { + $this->assertXPath('//select[@name="open_hour"]'); + } + + + /** @test */ + public function closeHourShouldBePresent() { + $this->assertXPath('//select[@name="close_hour"]'); + } } diff --git a/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php b/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php index 7e5cb356331cce36fe3401ce243f07df47f17225..08fb4ca18d9d4cc4e5599540157745f38964c989 100644 --- a/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php +++ b/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php @@ -249,7 +249,10 @@ abstract class AbonneControllerMultimediaHoldTestCase extends AbstractController ->setSlotSize(30) ->setMaxSlots(4) ->setHoldDelayMin(0) - ->setHoldDelayMax(60); + ->setHoldDelayMax(60) + ->setDays('3,4') + ->setOpenHour('08:30') + ->setCloseHour('17:45'); } @@ -399,7 +402,7 @@ class AbonneControllerMultimediaHoldHoursTest extends AbonneControllerMultimedia /** @test */ public function listOfStartTimesShouldBePresent() { - $this->assertXPathCount('//select[@id="time"]/option', 48); + $this->assertXPathCount('//select[@id="time"]/option', 19); }