diff --git a/app/controllers/resources/room_request.php b/app/controllers/resources/room_request.php index 0986dbce97cea8761c382526a1d1dd4753b78bf1..4aede3a600b40de53b511ff57f578d477cc895d3 100644 --- a/app/controllers/resources/room_request.php +++ b/app/controllers/resources/room_request.php @@ -202,7 +202,7 @@ class Resources_RoomRequestController extends AuthenticatedController if (!$this->filter['specific_requests']) { $sql .= "OR resource_id IS NULL or resource_id = ''"; } - $sql .= ') '; + $sql .= ") "; if (!$this->filter['own_requests']) { $sql .= " AND resource_requests.user_id <> :current_user_id "; $sql_params['current_user_id'] = User::findCurrent()->id; @@ -391,13 +391,15 @@ class Resources_RoomRequestController extends AuthenticatedController protected function getRoomAvailability(Room $room, $time_intervals = []) { $availability = []; + foreach ($time_intervals as $interval) { $begin = new DateTime(); $end = new DateTime(); $begin->setTimestamp($interval['begin']); $end->setTimestamp($interval['end']); - $availability[] = $room->isAvailable($begin, $end); + $availability[] = $room->isAvailable($begin, $end, [$interval['booking_id']]); } + return $availability; } @@ -1268,6 +1270,7 @@ class Resources_RoomRequestController extends AuthenticatedController //Get dates grouped by metadates. $this->request_time_intervals = $this->request->getGroupedTimeIntervals(true); } + $this->request_semester_string = ''; $request_start_semester = $this->request->getStartSemester(); $request_end_semester = $this->request->getEndSemester(); @@ -1311,6 +1314,7 @@ class Resources_RoomRequestController extends AuthenticatedController $selected_room, $data['intervals'] ); + $metadate_available = true; foreach ($metadate_availability as $available) { if (!$available) { @@ -1318,7 +1322,17 @@ class Resources_RoomRequestController extends AuthenticatedController break; } } - if ($metadate_available && !$this->selected_rooms) { + + $all_dates_same_room = true; + // check, if ALL dates are booked for the same room + foreach ($data['intervals'] as $interval) { + if ($interval['booked_room'] != $selected_room->id) { + $all_dates_same_room = false; + break; + } + } + + if ($all_dates_same_room && $metadate_available && !$this->selected_rooms) { $this->selected_rooms['SeminarCycleDate_' . $metadate_id] = $selected_room->id; } $this->room_availability[$selected_room->id][$metadate_id] = [$metadate_available]; @@ -1503,6 +1517,37 @@ class Resources_RoomRequestController extends AuthenticatedController $this->alternative_rooms = array_merge($this->alternative_rooms, $request_rooms); } } + + // add all booked rooms as well + $booked_rooms = []; + foreach($this->request_time_intervals as $key => $data) { + foreach ($data['intervals'] as $timeslot) { + if (!isset($booked_rooms[$timeslot['booked_room']])) { + $room = Room::find($timeslot['booked_room']); + if ($room) { + $booked_rooms[$timeslot['booked_room']] = $room; + } + } + } + } + + if (!empty($booked_rooms)) { + $this->alternative_rooms = array_merge($booked_rooms, $this->alternative_rooms); + } + + // deduplicate array + $deduplicated = []; + + foreach ($this->alternative_rooms as $room) { + if ($room->id != $this->request_resource->id + && !isset($deduplicated[$room->id]) + ) { + $deduplicated[$room->id] = $room; + } + } + + $this->alternative_rooms = $deduplicated; + foreach ($this->alternative_rooms as $room) { $this->metadate_available[$room->id] = []; $this->room_availability[$room->id] = []; @@ -1544,10 +1589,11 @@ class Resources_RoomRequestController extends AuthenticatedController $force_resolve = Request::submitted('force_resolve'); $resolve = Request::submitted('resolve') || $force_resolve; $this->show_force_resolve_button = false; + $save_only = Request::submitted('save_only'); $this->booked_room_infos = []; - if ($resolve) { + if ($resolve || $save_only) { CSRFProtection::verifyUnsafeRequest(); $this->selected_rooms = array_filter(Request::getArray('selected_rooms')); $this->notification_settings = Request::get('notification_settings'); @@ -1564,7 +1610,7 @@ class Resources_RoomRequestController extends AuthenticatedController return; } - if (count($this->selected_rooms) < $this->visible_dates && !$force_resolve) { + if (count($this->selected_rooms) < $this->visible_dates && !$force_resolve && !$save_only) { PageLayout::postWarning( _('Es wurden nicht für alle Termine der Anfrage Räume ausgewählt! Soll die Anfrage wirklich aufgelöst werden?') ); @@ -1623,37 +1669,39 @@ class Resources_RoomRequestController extends AuthenticatedController return; } - try { - $booking = $room->createBooking( - $this->current_user, - $course_date->id, - [ + if ($course_date->room_booking->resource_id != $room_id) { + try { + $booking = $room->createBooking( + $this->current_user, + $course_date->id, [ - 'begin' => $course_date->date, - 'end' => $course_date->end_time - ] - ], - null, - 0, - $course_date->end_time, - $this->request->preparation_time - ); - if ($booking instanceof ResourceBooking) { - $bookings[] = $booking; - if ($this->booked_room_infos[$room->id]) { - if ($this->booked_room_infos[$room->id]['first_booking_date'] > $booking->begin) { - $this->booked_room_infos[$room->id]['first_booking_date'] = $booking->begin; + [ + 'begin' => $course_date->date, + 'end' => $course_date->end_time + ] + ], + null, + 0, + $course_date->end_time, + $this->request->preparation_time + ); + if ($booking instanceof ResourceBooking) { + $bookings[] = $booking; + if ($this->booked_room_infos[$room->id]) { + if ($this->booked_room_infos[$room->id]['first_booking_date'] > $booking->begin) { + $this->booked_room_infos[$room->id]['first_booking_date'] = $booking->begin; + } + } else { + $this->booked_room_infos[$room->id] = [ + 'room' => $room, + 'first_booking_date' => $booking->begin + ]; } - } else { - $this->booked_room_infos[$room->id] = [ - 'room' => $room, - 'first_booking_date' => $booking->begin - ]; } + } catch (Exception $e) { + $errors[] = $e->getMessage(); + continue; } - } catch (Exception $e) { - $errors[] = $e->getMessage(); - continue; } } elseif ($range_data[0] == 'SeminarCycleDate') { //Get the dates of the metadate and create a booking for @@ -1670,27 +1718,29 @@ class Resources_RoomRequestController extends AuthenticatedController } if ($metadate->dates) { foreach ($metadate->dates as $date) { - try { - $booking = $room->createBooking( - $this->current_user, - $date->id, - [ + if ($date->room_booking->resource_id != $room_id) { + try { + $booking = $room->createBooking( + $this->current_user, + $date->id, [ - 'begin' => $date->date, - 'end' => $date->end_time - ] - ], - null, - 0, - $course_date->end_time, - $this->request->preparation_time - ); - if ($booking instanceof ResourceBooking) { - $bookings[] = $booking; + [ + 'begin' => $date->date, + 'end' => $date->end_time + ] + ], + null, + 0, + $course_date->end_time, + $this->request->preparation_time + ); + if ($booking instanceof ResourceBooking) { + $bookings[] = $booking; + } + } catch (Exception $e) { + $errors[] = $e->getMessage(); + continue; } - } catch (Exception $e) { - $errors[] = $e->getMessage(); - continue; } } } @@ -1747,8 +1797,9 @@ class Resources_RoomRequestController extends AuthenticatedController _('Es traten Fehler beim Auflösen der Anfrage auf!'), $errors ); - } else { + } else if (!$save_only) { //No errors: We can close the request. + $success = $this->request->closeRequest( $this->notification_settings == 'creator_and_lecturers', $bookings @@ -1782,6 +1833,11 @@ class Resources_RoomRequestController extends AuthenticatedController ); } } + + if ($save_only) { + // redirect to reload all infos and showing the most current ones + $this->redirect('resources/room_request/resolve/' . $request_id); + } } public function decline_action($request_id = null) diff --git a/app/views/resources/room_request/resolve.php b/app/views/resources/room_request/resolve.php index ef8bc2cca59c0914ded06b712accddcaf174d9c1..9ebf8c2fae4f18bbd21845adf178e2e0a2f29deb 100644 --- a/app/views/resources/room_request/resolve.php +++ b/app/views/resources/room_request/resolve.php @@ -284,7 +284,7 @@ </thead> <tbody> <tr class="nohover"> - <td><?= _('Keine Auswahl') ?></td> + <td><?= _('Keine Auswahl / keine Änderung') ?></td> <? if (count($request_time_intervals) > 1) : ?> <td> <input type="checkbox" data-proxyfor="input.radio-null" @@ -372,6 +372,7 @@ <? else: ?> <?= \Studip\Button::create(_('Anfrage auflösen'), 'resolve') ?> <? endif ?> + <?= \Studip\Button::create(_('Anfrage zwischenspeichern'), 'save_only') ?> <? if ($request->isSimpleRequest() && !$request->isReadOnlyForUser($current_user)): ?> <?= \Studip\LinkButton::create( diff --git a/app/views/resources/room_request/resolve_room_tr.php b/app/views/resources/room_request/resolve_room_tr.php index fb95c296562cf4a6d32e586ab000be77ac78e670..ff1e53bb0fa99e30800aa0fee3350b16c461bff8 100644 --- a/app/views/resources/room_request/resolve_room_tr.php +++ b/app/views/resources/room_request/resolve_room_tr.php @@ -55,6 +55,20 @@ ? 'checked="checked"' : ''?>> <?= Icon::create('check-circle', Icon::ROLE_STATUS_GREEN)->asImg(['class' => 'text-bottom']) ?> + + <? $stats = 0; array_walk($data['intervals'], function(&$item, $key, $room_id) use (&$stats) { + if ($item['booked_room'] == $room_id) { + $stats++; + } + }, $room->id) ?> + + <? if ($stats > 0) : ?> + <?= tooltipIcon(sprintf( + _('%s von %s Terminen sind in diesem Raum'), + $stats, sizeof($data['intervals']) + )); + ?> + <? endif ?> <? else: ?> <input type="radio" name="<?= htmlReady($room_radio_name) ?>" value="1" disabled="disabled" @@ -71,11 +85,12 @@ $room_radio_name = 'selected_rooms[' . $range_index . ']'; ?> <td> - <? if ($available): ?> + <? if ($available || $interval['booked_room'] == $room->id): ?> <input type="radio" name="<?= htmlReady($room_radio_name) ?>" class="text-bottom radio-<?= htmlReady($room->id) ?>" value="<?= htmlReady($room->id) ?>" - <?= $selected_dates[$range_index] == $room->id + <?= ($selected_dates[$range_index] == $room->id + || $interval['booked_room'] == $room->id) ? 'checked="checked"' : ''?>> <?= Icon::create('check-circle', Icon::ROLE_STATUS_GREEN)->asImg(['class' => 'text-bottom']) ?> diff --git a/lib/models/resources/ResourceRequest.class.php b/lib/models/resources/ResourceRequest.class.php index 30edac8b2e47e6a7510088e8579684b7f26e9238..037419a78e20a5be253b9af4feb3ad8fc8ac6a3b 100644 --- a/lib/models/resources/ResourceRequest.class.php +++ b/lib/models/resources/ResourceRequest.class.php @@ -926,11 +926,20 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen 'end' => $appointment->appointment->end_time ]; } + + $date = CourseDate::find($appointment->appointment_id); $interval['range'] = 'CourseDate'; $interval['range_id'] = $appointment->appointment_id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; $time_intervals['']['intervals'][] = $interval; } - return $time_intervals; + + if (empty($time_intervals['']['intervals'])) { + return []; + } else { + return $time_intervals; + } } elseif ($this->termin_id) { if ($with_preparation_time) { $interval = [ @@ -943,14 +952,23 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen 'end' => $this->date->end_time ]; } - $interval['range'] = 'CourseDate'; - $interval['range_id'] = $this->termin_id; - return [ - '' => [ - 'metadate' => null, - 'intervals' => [$interval] - ] - ]; + + $date = CourseDate::find($this->termin_id); + $interval['range'] = 'CourseDate'; + $interval['range_id'] = $this->termin_id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; + + if (!empty($interval)) { + return [ + '' => [ + 'metadate' => null, + 'intervals' => [$interval] + ] + ]; + } else { + return []; + } } elseif ($this->metadate_id) { $time_intervals = [ $this->metadate_id => [ @@ -972,6 +990,8 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen } $interval['range'] = 'CourseDate'; $interval['range_id'] = $date->id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; $time_intervals[$this->metadate_id]['intervals'][] = $interval; } return $time_intervals; @@ -998,6 +1018,8 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen } $interval['range'] = 'CourseDate'; $interval['range_id'] = $date->id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; $time_intervals[$cycle->id]['intervals'][] = $interval; } } @@ -1026,8 +1048,14 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen } $interval['range'] = 'CourseDate'; $interval['range_id'] = $date->id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; $time_intervals['']['intervals'][] = $interval; } + + if (empty($time_intervals['']['intervals'])) { + unset($time_intervals['']); + } } return $time_intervals; } elseif ($this->begin && $this->end) { @@ -1044,6 +1072,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen } $interval['range'] = 'User'; $interval['range_id'] = $this->user_id; + return [ '' => [ 'metadate' => null, @@ -1099,8 +1128,13 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ]; } if ($with_range) { - $interval['range'] = 'ResourceRequestAppointment'; - $interval['range_id'] = $appointment->appointment_id; + $date = CourseDate::find($appointment->appointment_id); + + $interval['range'] = 'ResourceRequestAppointment'; + $interval['range_id'] = $appointment->appointment_id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; + } $time_intervals[] = $interval; } @@ -1118,8 +1152,10 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ]; } if ($with_range) { - $interval['range'] = 'CourseDate'; - $interval['range_id'] = $this->termin_id; + $interval['range'] = 'CourseDate'; + $interval['range_id'] = $this->termin_id; + $interval['booked_room'] = $this->date->room_booking->resource_id; + $interval['booking_id'] = $this->date->room_booking->id; } return [$interval]; } elseif ($this->metadate_id) { @@ -1137,8 +1173,10 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ]; } if ($with_range) { - $interval['range'] = 'CourseDate'; - $interval['range_id'] = $date->id; + $interval['range'] = 'CourseDate'; + $interval['range_id'] = $date->id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; } $time_intervals[] = $interval; } @@ -1159,8 +1197,10 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ]; } if ($with_range) { - $interval['range'] = 'CourseDate'; - $interval['range_id'] = $date->id; + $interval['range'] = 'CourseDate'; + $interval['range_id'] = $date->id; + $interval['booked_room'] = $date->room_booking->resource_id; + $interval['booking_id'] = $date->room_booking->id; } $time_intervals[] = $interval; } @@ -1350,10 +1390,9 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen } elseif ($this->course_id) { $course = new Seminar($this->course_id); if ($course) { - $strings[] = $course->getDatesExport( + $strings[] = $course->getDatesTemplate('dates/seminar_html_roomplanning', [ - 'short' => true, - 'shrink' => true, + 'shrink' => false, 'show_room' => true ] ); diff --git a/templates/dates/seminar_export.php b/templates/dates/seminar_export.php index 60c667b45d1b7c1099c5bd892e466f5071333c3a..944e02cc2cd7cddae47fab1b7f3a41d40e3c624b 100644 --- a/templates/dates/seminar_export.php +++ b/templates/dates/seminar_export.php @@ -54,15 +54,27 @@ if (!empty($dates['regular']['turnus_data']) || !empty($dates['irregular'])) : $rooms = array_merge(getPlainRooms($irregular_rooms, false), array_keys($freetext_rooms)); if (is_array($irregular) && sizeof($irregular)) : - echo _("Termine am") . implode(', ', shrink_dates($irregular)); - if (is_array($rooms) && sizeof($rooms) > 0) : - if (sizeof($rooms) > 3) : - $rooms = array_slice($rooms, sizeof($rooms) - 3, sizeof($rooms)); - endif; + if (isset($shrink) && !$shrink && sizeof($irregular < 20)) : + foreach ($irregular as $date) : + echo $date['tostring']; + + if ($show_room && $date['resource_id']) : + echo ', '. _('Ort:') . ' '; + echo Room::find($date['resource_id']); + endif; + echo "\n"; + endforeach; + else : + echo _("Termine am") . implode(', ', shrink_dates($irregular)); + if (is_array($rooms) && sizeof($rooms) > 0) : + if (sizeof($rooms) > 3) : + $rooms = array_slice($rooms, sizeof($rooms) - 3, sizeof($rooms)); + endif; - if ($show_room) : - echo ', ' . _("Ort:") . ' '; - echo implode(', ', $rooms); + if ($show_room) : + echo ', ' . _("Ort:") . ' '; + echo implode(', ', $rooms); + endif; endif; endif; endif; diff --git a/templates/dates/seminar_html_roomplanning.php b/templates/dates/seminar_html_roomplanning.php new file mode 100644 index 0000000000000000000000000000000000000000..f3311494aefeaa419cbf07d22f1a31756089e78f --- /dev/null +++ b/templates/dates/seminar_html_roomplanning.php @@ -0,0 +1,86 @@ +<? +if (!isset($show_room)) : + // show rooms only if there is more than one + if (empty($dates['rooms']) || sizeof($dates['rooms']) === 1) : + $show_room = false; + else : + $show_room = true; + endif; +endif; + +if (!empty($dates['regular']['turnus_data']) || !empty($dates['irregular'])) : + $output = []; + if (is_array($dates['regular']['turnus_data'])) foreach ($dates['regular']['turnus_data'] as $cycle) : + $first_date = sprintf(_("ab %s"), strftime('%x', $cycle['first_date']['date'])); + if ($cycle['cycle'] == 1) : + $cycle_output = $cycle['tostring_short'] . ' (' . sprintf(_("zweiwöchentlich, %s"), $first_date) . ')'; + elseif ($cycle['cycle'] == 2) : + $cycle_output = $cycle['tostring_short'] . ' (' . sprintf(_("dreiwöchentlich, %s"), $first_date) . ')'; + else : + $cycle_output = $cycle['tostring_short'] . ' (' . _("wöchentlich") . ')'; + endif; + if ($cycle['desc']) + $cycle_output .= ' - '. $cycle['desc']; + + if ($show_room) : + $cycle_output .= $this->render_partial('dates/_seminar_rooms', + [ + 'assigned' => $cycle['assigned_rooms'], + 'freetext' => $cycle['freetext_rooms'], + 'link' => true + ] + ); + endif; + + $output[] = $cycle_output; + endforeach; + + echo implode(", <br>", $output); + + $freetext_rooms = []; + + if (is_array($dates['irregular'])): + foreach ($dates['irregular'] as $date) : + $irregular[] = $date; + $irregular_strings[] = $date['tostring']; + if ($date['resource_id']) : + $irregular_rooms[$date['resource_id']]++; + elseif ($date['raum']) : + $freetext_rooms['('. $date['raum'] .')']++; + endif; + endforeach; + unset($irregular_rooms['']); + echo sizeof($output) ? ", <br>" : ''; + + $rooms = array_merge(getPlainRooms($irregular_rooms, false), array_keys($freetext_rooms)); + + if (is_array($irregular) && sizeof($irregular)) : + if (isset($shrink) && !$shrink && sizeof($irregular < 20)) : + foreach ($irregular as $date) : + echo $date['tostring']; + + if ($show_room && $date['resource_id']) : + echo ', '. _('Ort:') . ' '; + $room_obj = Room::find($date['resource_id']); + echo '<a href="' . $room_obj->getActionLink('show') . '" target="_blank">' + . htmlReady($room_obj->name) . '</a>'; + endif; + echo "<br>"; + endforeach; + else : + echo _("Termine am") . implode(', ', shrink_dates($irregular)); + if (is_array($rooms) && sizeof($rooms) > 0) : + if (sizeof($rooms) > 3) : + $rooms = array_slice($rooms, sizeof($rooms) - 3, sizeof($rooms)); + endif; + + if ($show_room) : + echo ', ' . _("Ort:") . ' '; + echo implode(', ', $rooms); + endif; + endif; + echo "<br>"; + endif; + endif; + endif; +endif;