diff --git a/app/controllers/course/dates.php b/app/controllers/course/dates.php index 3d744c17ad18b4485b619eef1369cfb19a0f60fc..d1fa6459d7b29a4e31d621502dbfebe0e5beb17b 100644 --- a/app/controllers/course/dates.php +++ b/app/controllers/course/dates.php @@ -54,6 +54,7 @@ class Course_DatesController extends AuthenticatedController $this->assignLockRulesToTemplate(); $this->last_visitdate = object_get_visit($this->course->id, $this->studip_module->getPluginId()); + $semester_id = Request::get('semester_id'); $semester = null; if ($semester_id != 'all') { @@ -100,6 +101,16 @@ class Course_DatesController extends AuthenticatedController $this->url_for('course/dates/export_csv'), Icon::create('file-excel') ); + + if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) { + $actions->addLink( + _('Laufende Termine'), + $this->url_for('course/dates/current_day_dates'), + Icon::create('date') + )->asDialog(); + } + + $sidebar->addWidget($actions); if (count($this->course->semesters) !== 1) { @@ -127,6 +138,42 @@ class Course_DatesController extends AuthenticatedController } } + public function current_day_dates_action() + { + if (!$this->hasAccess() || !Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) { + throw new AccessDeniedException(); + } + + if (Request::isPost()) { + CSRFProtection::verifyUnsafeRequest(); + + foreach (Request::getArray('termin_id') as $index => $terminId) { + $numberOfParticipants = Request::intArray('number_of_participants')[$index]; + if ($numberOfParticipants < 0) { + continue; + } + + $courseDate = CourseDate::find($terminId); + $courseDate->number_of_participants = $numberOfParticipants; + $courseDate->store(); + } + + PageLayout::postSuccess(_('Die Anzahl der Teilnehmenden wurde gespeichert.')); + + $this->redirect($this->indexURL()); + } + + $beginOfDay = strtotime('today 00:00:00'); + $endOfDay = strtotime('today 23:59:59'); + $this->dates = $this->course->getDatesWithExdates($beginOfDay, $endOfDay); + + $resourceId = Request::option('resource_id'); + if ($resourceId) { + $this->dates = $this->dates->filter(function ($date) use ($resourceId) { + return $date->room_booking->resource_id === $resourceId; + }); + } + } /** * This method is called to show the dialog to edit a date for a course. @@ -247,6 +294,10 @@ class Course_DatesController extends AuthenticatedController if ($termin) { $termin->date_typ = Request::get('dateType'); + if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) { + $termin->number_of_participants = strlen(Request::get('number_of_participants')) && Request::int('number_of_participants') >= 0 ? Request::int('number_of_participants') : null; + } + // Assign teachers $assigned_teachers = Request::optionArray('assigned_teachers'); $current_count = CourseMember::countByCourseAndStatus( @@ -445,7 +496,8 @@ class Course_DatesController extends AuthenticatedController _('Gruppen'), _('Raum'), _('Raumbeschreibung'), - _('Sitzplätze') + _('Sitzplätze'), + _('Teilnehmende') ]; $data = [$columns]; @@ -504,6 +556,8 @@ class Course_DatesController extends AuthenticatedController $row[] = ''; } + $row[] = $date->number_of_participants; + $data[] = $row; } diff --git a/app/controllers/course/timesrooms.php b/app/controllers/course/timesrooms.php index 3989edc3242e326509b0763ab95a5c0aa0fa8d82..6249d4790f9a4d60c19dcdc8a3b7f2afa488b0cf 100644 --- a/app/controllers/course/timesrooms.php +++ b/app/controllers/course/timesrooms.php @@ -490,6 +490,10 @@ class Course_TimesroomsController extends AuthenticatedController $assigned_groups = Request::optionArray('assigned-groups'); $termin->statusgruppen = Statusgruppen::findMany($assigned_groups); + if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) { + $termin->number_of_participants = strlen(Request::get('number_of_participants')) && Request::int('number_of_participants') >= 0 ? Request::int('number_of_participants') : null; + } + $termin->store(); if ($time_changed) { diff --git a/app/controllers/resources/export.php b/app/controllers/resources/export.php index 626563a89aa14c76083c69bea7da9987fb15a791..585c5db8ef45e5f9d7c3c8042cf1d44e46cde8de 100644 --- a/app/controllers/resources/export.php +++ b/app/controllers/resources/export.php @@ -342,6 +342,11 @@ class Resources_ExportController extends AuthenticatedController ] ]; + if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) { + $number_of_participants = null; + $booking_data[0][] = _('Anzahl der Teilnehmenden'); + } + foreach ($resources as $resource) { //Retrieve the bookings in the specified time range: $intervals = ResourceBookingInterval::findBySql( @@ -398,9 +403,12 @@ class Resources_ExportController extends AuthenticatedController if ($course instanceof Course) { $description = $course->getFullName(); $turnout = $course->admission_turnout; + if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) { + $number_of_participants = $booking->assigned_course_date->number_of_participants; + } } } - $booking_data[] = [ + $row = [ date('d.m.Y', $interval->begin), date('H:i', $interval->begin + $booking->preparation_time), date('H:i', $interval->end), @@ -429,6 +437,12 @@ class Resources_ExportController extends AuthenticatedController implode(', ', $booking->getAssignedUsers()), $booking->internal_comment ]; + + if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) { + $row[] = $number_of_participants; + } + + $booking_data[] = $row; } } diff --git a/app/controllers/resources/room_planning.php b/app/controllers/resources/room_planning.php index 593201a875d5381c411e9f5ffc0135cac0de7caa..37e9193023080abd0809f0ae49ae7b29915a4900 100644 --- a/app/controllers/resources/room_planning.php +++ b/app/controllers/resources/room_planning.php @@ -374,6 +374,19 @@ class Resources_RoomPlanningController extends AuthenticatedController ] ); + $actions->addLink( + _('QR-Code zur Eingabe der Anzahl'), + URLHelper::getURL( + 'dispatch.php/resources/room_planning/courses/' . $this->resource->id + ), + Icon::create('code-qr'), + [ + 'data-qr-code' => '', + 'data-qr-code-print' => '1', + 'data-qr-title' => _('Zur Eingabe der Anzahl') + ] + ); + if ($this->user instanceof User) { //No check necessary here: This part of the controller is only called //when a room has been selected before. @@ -777,4 +790,30 @@ class Resources_RoomPlanningController extends AuthenticatedController } } } + + public function courses_action($resourceId) + { + $query = DBManager::get()->prepare(" + SELECT + `seminare`.`Seminar_id`, + `seminare`.`Name` + FROM + `resource_bookings` + JOIN `termine` ON (`resource_bookings`.`range_id` = `termine`.`termin_id` AND `termine`.`date` > :begin_of_day AND `termine`.`end_time` < :end_of_day) + JOIN `seminare` ON `seminare`.`Seminar_id` = `termine`.`range_id` + WHERE + `resource_bookings`.`resource_id` = :resource_id + GROUP BY `seminare`.`Seminar_id` + "); + + $query->execute([ + 'resource_id' => $resourceId, + 'begin_of_day' => strtotime('today 00:00:00'), + 'end_of_day' => strtotime('today 23:59:59'), + ]); + + $this->resourceId = $resourceId; + + $this->courses = $query->fetchAll(PDO::FETCH_ASSOC); + } } diff --git a/app/views/course/dates/current_day_dates.php b/app/views/course/dates/current_day_dates.php new file mode 100644 index 0000000000000000000000000000000000000000..f7ca4b9bae5fd8c74a4b700b758f1d48c22b0249 --- /dev/null +++ b/app/views/course/dates/current_day_dates.php @@ -0,0 +1,49 @@ +<form class="default" action="<?= $controller->current_day_dates() ?>" method="post"> + <?= CSRFProtection::tokenTag() ?> + <table class="dates default sortable-table" data-sortlist="[[0, 0]]" data-table-id="<?= htmlReady($course->id) ?>"> + <thead> + <tr> + <th data-sort="htmldata"><?= _('Zeit') ?></th> + <th data-sort="text"><?= _('Raum') ?></th> + <th data-sort="htmldata"><?= _('Anzahl der Teilnehmenden') ?></th> + </tr> + </thead> + <tbody> + <? foreach ($dates as $date): ?> + <tr> + <td data-sort-value="<?= htmlReady($date->date) ?>" class="date_name"> + <?= Icon::create('date')->asImg(['class' => 'text-bottom']) ?> + <?= htmlReady($date->getFullName(CourseDate::FORMAT_VERBOSE)) ?> + </td> + <td> + <? $room = $date->getRoom(); ?> + <? if ($room): ?> + <a href="<?= $room->getActionLink('show') ?>" data-dialog> + <?= htmlReady($room->name) ?> + </a> + <? else: ?> + <?= htmlReady($date->raum) ?> + <? endif ?> + </td> + <td data-sort-value="<?= htmlReady($date->number_of_participants) ?>"> + <input type="hidden" name="termin_id[]" value="<?= htmlReady($date->termin_id) ?>"> + <input type="number" min="0" name="number_of_participants[]" value="<?= htmlReady($date->number_of_participants) ?>"> + </td> + </tr> + <? endforeach; ?> + <?if (count($dates) === 0) : ?> + <tr> + <td colspan="3"> + <?= _('Es sind noch keine laufenden Termine vorhanden.') ?> + </td> + </tr> + <? endif ?> + </tbody> + </table> + + <footer data-dialog-button> + <?= Studip\Button::createAccept(_('Speichern')) ?> + <?= Studip\LinkButton::createCancel(_('Abbrechen'), $controller->indexURL()) ?> + </footer> +</form> + diff --git a/app/views/course/dates/details-edit.php b/app/views/course/dates/details-edit.php index 7fb409ef4906e8f85bc16913f9f024c3743c7cd1..a2351ed60d82c119f943ee89b57b3c7e033eb7ed 100644 --- a/app/views/course/dates/details-edit.php +++ b/app/views/course/dates/details-edit.php @@ -152,6 +152,15 @@ </div> </fieldset> <? endif; ?> +<? if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) : ?> + <fieldset> + <legend><?= _('Teilnehmende') ?></legend> + <label> + <?=_('Anzahl der Teilnehmenden')?> + <input type="number" name="number_of_participants" value="<?= htmlReady($date->number_of_participants) ?>"> + </label> + </fieldset> +<? endif ?> <footer data-dialog-button> <? if (!$metadata_locked): ?> diff --git a/app/views/course/dates/export.php b/app/views/course/dates/export.php index 685748ded9cf012080254d792062d04f5e4da74c..d95a68b2f8aa9807afeabc8ff63053183ea9f35f 100644 --- a/app/views/course/dates/export.php +++ b/app/views/course/dates/export.php @@ -29,7 +29,7 @@ foreach ($all_semester as $zwsem) { if (!empty($zwsem['beginn'])) { if ( ($zwsem['beginn'] < $date['start']) && ($zwsem['ende'] > $date['start']) ) { - $grenze = $zwsem['ende']; + $grenze = $zwsem['ende'] ?? null; ?> <tr> <td colspan="5"> diff --git a/app/views/course/timesrooms/editDate.php b/app/views/course/timesrooms/editDate.php index 3fbae994e91854d6dcbb7069c980e2cc69b23044..5012a431d239f2a37b26c1ba6876a258d80f8fb7 100644 --- a/app/views/course/timesrooms/editDate.php +++ b/app/views/course/timesrooms/editDate.php @@ -226,6 +226,15 @@ </div> </fieldset> <? endif ?> +<? if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) : ?> + <fieldset> + <legend><?= _('Teilnehmende') ?></legend> + <label> + <?=_('Anzahl der Teilnehmenden')?> + <input type="number" min="0" name="number_of_participants" value="<?= htmlReady($date->number_of_participants) ?>"> + </label> + </fieldset> +<? endif ?> <footer data-dialog-button> <?= Studip\Button::createAccept(_('Speichern'), 'save_dates') ?> diff --git a/app/views/resources/room_planning/courses.php b/app/views/resources/room_planning/courses.php new file mode 100644 index 0000000000000000000000000000000000000000..98f44d4901f59195b776d9a66118eae42f666e33 --- /dev/null +++ b/app/views/resources/room_planning/courses.php @@ -0,0 +1,28 @@ +<table class="default"> + <thead> + <tr> + <th><?= _('Courses') ?></th> + </tr> + </thead> + <tbody> + <? foreach ($courses as $course): ?> + <tr> + <td> + <a href="<?= URLHelper::getURL('dispatch.php/course/dates/current_day_dates', [ + 'cid' => $course['Seminar_id'], + 'resource_id' => $resourceId + ]) ?>"> + <?= htmlReady($course['Name']) ?> + </a> + </td> + </tr> + <? endforeach; ?> + <? if (count($courses) === 0) : ?> + <tr> + <td> + <?= _('Es sind noch keine Veranstaltungen vorhanden.') ?> + </td> + </tr> + <? endif ?> + </tbody> +</table> diff --git a/db/migrations/6.0.25_step_4253.php b/db/migrations/6.0.25_step_4253.php new file mode 100644 index 0000000000000000000000000000000000000000..582b49abfbee8826d27e6cca87f62d1e6a503ead --- /dev/null +++ b/db/migrations/6.0.25_step_4253.php @@ -0,0 +1,38 @@ +<?php +return new class extends Migration { + + public function description() + { + return 'Adds column and configuration option for actual number of participants'; + } + + protected function up() + { + $db = DBManager::get(); + $db->exec("INSERT IGNORE INTO `config` + (`field`, `value`, `type`, `range`, `section`, `mkdate`, `chdate`, `description`) + VALUES + ( + 'ENABLE_NUMBER_OF_PARTICIPANTS', + 0, + 'bool', + 'global', + 'global', + UNIX_TIMESTAMP(), + UNIX_TIMESTAMP(), + 'Schaltet die Möglichkeit zum Erfassen der tatsächlichen Teilnehmendenanzahl pro Termin ein.' + )" + ); + $db->exec("ALTER TABLE `termine` ADD `number_of_participants` SMALLINT NULL DEFAULT NULL"); + } + + protected function down() + { + $db = DBManager::get(); + $db->exec("DELETE `config`, `config_values` + FROM `config` LEFT JOIN `config_values` USING (`field`) + WHERE `field` = 'ENABLE_NUMBER_OF_PARTICIPANTS'"); + $db->exec("ALTER TABLE `termine` DROP `number_of_participants`"); + + } +};