1<?php 2 3/* Copyright (c) 1998-2019 ILIAS open source, Extended GPL, see docs/LICENSE */ 4 5/** 6 * Booking process ui class 7 * 8 * @author killing@leifos.de 9 * @ingroup ModulesBookingManager 10 */ 11class ilBookingProcessGUI 12{ 13 /** 14 * @var ilObjBookingPool 15 */ 16 protected $pool; 17 18 /** 19 * @var 20 */ 21 protected $booking_object_id; 22 23 /** 24 * user to be booked: user being assigned or deassigned to/from a reservation 25 * @var int 26 */ 27 protected $user_id_to_book; 28 29 /** 30 * @var int 31 */ 32 protected $user_id_assigner; 33 34 /** 35 * @var string 36 */ 37 protected $seed; 38 39 /** 40 * @var ilBookingHelpAdapter 41 */ 42 protected $help; 43 44 /** 45 * @var int 46 */ 47 protected $context_obj_id; 48 49 /** 50 * Constructor 51 */ 52 public function __construct( 53 ilObjBookingPool $pool, 54 int $booking_object_id, 55 ilBookingHelpAdapter $help, 56 string $seed = "", 57 string $sseed = "", 58 int $context_obj_id = 0 59 ) { 60 global $DIC; 61 62 $this->ctrl = $DIC->ctrl(); 63 $this->tpl = $DIC["tpl"]; 64 $this->lng = $DIC->language(); 65 $this->access = $DIC->access(); 66 $this->tabs_gui = $DIC->tabs(); 67 $this->user = $DIC->user(); 68 $this->help = $help; 69 70 $this->context_obj_id = $context_obj_id; 71 72 $this->book_obj_id = $booking_object_id; 73 74 $this->pool = $pool; 75 76 $this->seed = $seed; 77 $this->sseed = $sseed; 78 79 $this->rsv_ids = explode(";", $_REQUEST["rsv_ids"]); 80 81 82 $this->user_id_assigner = $this->user->getId(); 83 if ($_GET['bkusr']) { 84 $this->user_id_to_book = (int) $_GET['bkusr']; 85 } else { 86 $this->user_id_to_book = $this->user_id_assigner; // by default user books his own booking objects. 87 } 88 $this->ctrl->saveParameter($this, ["bkusr"]); 89 } 90 91 /** 92 * Execute command 93 */ 94 public function executeCommand() 95 { 96 $ctrl = $this->ctrl; 97 98 $next_class = $ctrl->getNextClass($this); 99 $cmd = $ctrl->getCmd("show"); 100 switch ($next_class) { 101 default: 102 if (in_array($cmd, array("book", "back", 103 "assignParticipants", 104 "bookMultipleParticipants", 105 "saveMultipleBookings", 106 "confirmedBooking", 107 "confirmBookingNumbers", 108 "confirmedBookingNumbers", 109 "displayPostInfo", 110 "deliverPostFile" 111 ))) { 112 $this->$cmd(); 113 } 114 } 115 } 116 117 /** 118 * Back to parent 119 */ 120 protected function back() // ok 121 { 122 $this->ctrl->returnToParent($this); 123 } 124 125 /** 126 * @param string $a_id 127 */ 128 protected function setHelpId(string $a_id) 129 { 130 $this->help->setHelpId($a_id); 131 } 132 133 /** 134 * Check permission 135 * 136 * @param $a_perm 137 */ 138 protected function checkPermissionBool($a_perm) 139 { 140 $ilAccess = $this->access; 141 142 if (!$ilAccess->checkAccess($a_perm, "", $this->pool->getRefId())) { 143 return false; 144 } 145 return true; 146 } 147 148 /** 149 * Check permission 150 * 151 * @param $a_perm 152 */ 153 protected function checkPermission($a_perm) 154 { 155 if (!$this->checkPermissionBool($a_perm)) { 156 ilUtil::sendFailure($this->lng->txt("no_permission"), true); 157 $this->back(); 158 } 159 } 160 161 // 162 // Step 1 163 // 164 165 166 /** 167 * First step in booking process 168 */ 169 public function book() // ok 170 { 171 $tpl = $this->tpl; 172 173 $this->tabs_gui->clearTargets(); 174 $this->tabs_gui->setBackTarget($this->lng->txt('book_back_to_list'), $this->ctrl->getLinkTarget($this, 'back')); 175 176 $this->setHelpId("book"); 177 178 $obj = new ilBookingObject($this->book_obj_id); 179 180 $this->lng->loadLanguageModule("dateplaner"); 181 $this->ctrl->setParameter($this, 'object_id', $obj->getId()); 182 183 if ($this->user_id_to_book != $this->user_id_assigner) { 184 $this->ctrl->setParameter($this, 'bkusr', $this->user_id_to_book); 185 } 186 187 if ($this->pool->getScheduleType() == ilObjBookingPool::TYPE_FIX_SCHEDULE) { 188 $schedule = new ilBookingSchedule($obj->getScheduleId()); 189 190 $tpl->setContent($this->renderSlots($schedule, array($obj->getId()), $obj->getTitle())); 191 } else { 192 $cgui = new ilConfirmationGUI(); 193 $cgui->setHeaderText($this->lng->txt("book_confirm_booking_no_schedule")); 194 195 $cgui->setFormAction($this->ctrl->getFormAction($this)); 196 $cgui->setCancel($this->lng->txt("cancel"), "back"); 197 $cgui->setConfirm($this->lng->txt("confirm"), "confirmedBooking"); 198 199 $cgui->addItem("object_id", $obj->getId(), $obj->getTitle()); 200 201 $tpl->setContent($cgui->getHTML()); 202 } 203 } 204 205 /** 206 * @param ilBookingSchedule $schedule 207 * @param array $object_ids 208 * @param string $title 209 * @return string 210 */ 211 protected function renderSlots(ilBookingSchedule $schedule, array $object_ids, string $title) // ok 212 { 213 $ilUser = $this->user; 214 215 // fix 216 if (!$schedule->getRaster()) { 217 $mytpl = new ilTemplate('tpl.booking_reservation_fix.html', true, true, 'Modules/BookingManager'); 218 219 $mytpl->setVariable('FORM_ACTION', $this->ctrl->getFormAction($this)); 220 $mytpl->setVariable('TXT_TITLE', $this->lng->txt('book_reservation_title')); 221 $mytpl->setVariable('TXT_INFO', $this->lng->txt('book_reservation_fix_info')); 222 $mytpl->setVariable('TXT_OBJECT', $title); 223 $mytpl->setVariable('TXT_CMD_BOOK', $this->lng->txt('book_confirm_booking')); 224 $mytpl->setVariable('TXT_CMD_CANCEL', $this->lng->txt('cancel')); 225 226 $user_settings = ilCalendarUserSettings::_getInstanceByUserId($ilUser->getId()); 227 228 $morning_aggr = $user_settings->getDayStart(); 229 $evening_aggr = $user_settings->getDayEnd(); 230 $hours = array(); 231 for ($i = $morning_aggr;$i <= $evening_aggr;$i++) { 232 switch ($user_settings->getTimeFormat()) { 233 case ilCalendarSettings::TIME_FORMAT_24: 234 if ($morning_aggr > 0 && $i == $morning_aggr) { 235 $hours[$i] = sprintf('%02d:00', 0) . "-"; 236 } 237 $hours[$i] .= sprintf('%02d:00', $i); 238 if ($evening_aggr < 23 && $i == $evening_aggr) { 239 $hours[$i] .= "-" . sprintf('%02d:00', 23); 240 } 241 break; 242 243 case ilCalendarSettings::TIME_FORMAT_12: 244 if ($morning_aggr > 0 && $i == $morning_aggr) { 245 $hours[$i] = date('h a', mktime(0, 0, 0, 1, 1, 2000)) . "-"; 246 } 247 $hours[$i] .= date('h a', mktime($i, 0, 0, 1, 1, 2000)); 248 if ($evening_aggr < 23 && $i == $evening_aggr) { 249 $hours[$i] .= "-" . date('h a', mktime(23, 0, 0, 1, 1, 2000)); 250 } 251 break; 252 } 253 } 254 255 if ($this->seed != "") { 256 $find_first_open = false; 257 $seed = new ilDate($this->seed, IL_CAL_DATE); 258 } else { 259 $find_first_open = true; 260 $seed = ($this->sseed != "") 261 ? new ilDate($this->sseed, IL_CAL_DATE) 262 : new ilDate(time(), IL_CAL_UNIX); 263 } 264 265 $week_start = $user_settings->getWeekStart(); 266 267 if (!$find_first_open) { 268 $dates = array(); 269 $this->buildDatesBySchedule($week_start, $hours, $schedule, $object_ids, $seed, $dates); 270 } else { 271 $dates = array(); 272 273 //loop for 1 week 274 $has_open_slot = $this->buildDatesBySchedule($week_start, $hours, $schedule, $object_ids, $seed, $dates); 275 276 // find first open slot 277 if (!$has_open_slot) { 278 // 1 year is limit for search 279 $limit = clone($seed); 280 $limit->increment(ilDate::YEAR, 1); 281 $limit = $limit->get(IL_CAL_UNIX); 282 283 while (!$has_open_slot && $seed->get(IL_CAL_UNIX) < $limit) { 284 $seed->increment(ilDate::WEEK, 1); 285 286 $dates = array(); 287 $has_open_slot = $this->buildDatesBySchedule($week_start, $hours, $schedule, $object_ids, $seed, $dates); 288 } 289 } 290 } 291 292 $navigation = new ilCalendarHeaderNavigationGUI($this, $seed, ilDateTime::WEEK, 'book'); 293 $mytpl->setVariable('NAVIGATION', $navigation->getHTML()); 294 295 /** @var ilDateTime $date */ 296 foreach (ilCalendarUtil::_buildWeekDayList($seed, $week_start)->get() as $date) { 297 $date_info = $date->get(IL_CAL_FKT_GETDATE, '', 'UTC'); 298 299 $mytpl->setCurrentBlock('weekdays'); 300 $mytpl->setVariable('TXT_WEEKDAY', ilCalendarUtil:: _numericDayToString($date_info['wday'])); 301 $mytpl->setVariable('TXT_DATE', $date_info['mday'] . ' ' . ilCalendarUtil:: _numericMonthToString($date_info['mon'])); 302 $mytpl->parseCurrentBlock(); 303 } 304 305 $color = array(); 306 $all = ilCalendarAppointmentColors::_getColorsByType('crs'); 307 for ($loop = 0; $loop < 7; $loop++) { 308 $col = $all[$loop]; 309 $fnt = ilCalendarUtil::calculateFontColor($col); 310 $color[$loop + 1] = 'border-bottom: 1px solid ' . $col . '; background-color: ' . $col . '; color: ' . $fnt; 311 } 312 313 $counter = 0; 314 foreach ($dates as $hour => $days) { 315 $caption = $days; 316 $caption = array_shift($caption); 317 318 for ($loop = 1; $loop < 8; $loop++) { 319 if (!isset($days[$loop])) { 320 $mytpl->setCurrentBlock('dates'); 321 $mytpl->setVariable('DUMMY', ' '); 322 $mytpl->parseCurrentBlock(); 323 } else { 324 if (isset($days[$loop]['captions'])) { 325 foreach ($days[$loop]['captions'] as $slot_id => $slot_caption) { 326 $mytpl->setCurrentBlock('choice'); 327 $mytpl->setVariable('TXT_DATE', $slot_caption); 328 $mytpl->setVariable('VALUE_DATE', $slot_id); 329 $mytpl->setVariable('DATE_COLOR', $color[$loop]); 330 $mytpl->setVariable( 331 'TXT_AVAILABLE', 332 sprintf( 333 $this->lng->txt('book_reservation_available'), 334 $days[$loop]['available'][$slot_id] 335 ) 336 ); 337 $mytpl->parseCurrentBlock(); 338 } 339 340 $mytpl->setCurrentBlock('dates'); 341 $mytpl->setVariable('DUMMY', ''); 342 $mytpl->parseCurrentBlock(); 343 } elseif (isset($days[$loop]['in_slot'])) { 344 $mytpl->setCurrentBlock('dates'); 345 $mytpl->setVariable('DATE_COLOR', $color[$loop]); 346 $mytpl->parseCurrentBlock(); 347 } else { 348 $mytpl->setCurrentBlock('dates'); 349 $mytpl->setVariable('DUMMY', ' '); 350 $mytpl->parseCurrentBlock(); 351 } 352 } 353 } 354 355 $mytpl->setCurrentBlock('slots'); 356 $mytpl->setVariable('TXT_HOUR', $caption); 357 if ($counter % 2) { 358 $mytpl->setVariable('CSS_ROW', 'tblrow1'); 359 } else { 360 $mytpl->setVariable('CSS_ROW', 'tblrow2'); 361 } 362 $mytpl->parseCurrentBlock(); 363 364 $counter++; 365 } 366 } 367 368 return $mytpl->get(); 369 } 370 371 /** 372 * @param $week_start 373 * @param array $hours 374 * @param ilBookingSchedule $schedule 375 * @param array $object_ids 376 * @param $seed 377 * @param array $dates 378 * @return bool 379 */ 380 protected function buildDatesBySchedule($week_start, array $hours, ilBookingSchedule $schedule, array $object_ids, $seed, array &$dates) // ok 381 { 382 $ilUser = $this->user; 383 384 $user_settings = ilCalendarUserSettings::_getInstanceByUserId($ilUser->getId()); 385 386 $map = array('mo', 'tu', 'we', 'th', 'fr', 'sa', 'su'); 387 $definition = $schedule->getDefinition(); 388 389 $av_from = ($schedule->getAvailabilityFrom() && !$schedule->getAvailabilityFrom()->isNull()) 390 ? $schedule->getAvailabilityFrom()->get(IL_CAL_DATE) 391 : null; 392 $av_to = ($schedule->getAvailabilityTo() && !$schedule->getAvailabilityTo()->isNull()) 393 ? $schedule->getAvailabilityTo()->get(IL_CAL_DATE) 394 : null; 395 396 $has_open_slot = false; 397 /** @var ilDateTime $date */ 398 foreach (ilCalendarUtil::_buildWeekDayList($seed, $week_start)->get() as $date) { 399 $date_info = $date->get(IL_CAL_FKT_GETDATE, '', 'UTC'); 400 401 #24045 and #24936 402 if ($av_from || $av_to) { 403 $today = $date->get(IL_CAL_DATE); 404 405 if ($av_from && $av_from > $today) { 406 continue; 407 } 408 409 if ($av_to && $av_to < $today) { 410 continue; 411 } 412 } 413 414 $slots = array(); 415 if (isset($definition[$map[$date_info['isoday'] - 1]])) { 416 $slots = array(); 417 foreach ($definition[$map[$date_info['isoday'] - 1]] as $slot) { 418 $slot = explode('-', $slot); 419 $slots[] = array('from' => str_replace(':', '', $slot[0]), 420 'to' => str_replace(':', '', $slot[1])); 421 } 422 } 423 424 $last = array_pop(array_keys($hours)); 425 $slot_captions = array(); 426 foreach ($hours as $hour => $period) { 427 $dates[$hour][0] = $period; 428 429 $period = explode("-", $period); 430 431 // #13738 432 if ($user_settings->getTimeFormat() == ilCalendarSettings::TIME_FORMAT_12) { 433 $period[0] = date("H", strtotime($period[0])); 434 if (sizeof($period) == 2) { 435 $period[1] = date("H", strtotime($period[1])); 436 } 437 } 438 439 if (sizeof($period) == 1) { 440 $period_from = (int) substr($period[0], 0, 2) . "00"; 441 $period_to = (int) substr($period[0], 0, 2) . "59"; 442 } else { 443 $period_from = (int) substr($period[0], 0, 2) . "00"; 444 $period_to = (int) substr($period[1], 0, 2) . "59"; 445 } 446 447 $column = $date_info['isoday']; 448 if (!$week_start) { 449 if ($column < 7) { 450 $column++; 451 } else { 452 $column = 1; 453 } 454 } 455 456 if (sizeof($slots)) { 457 $in = false; 458 foreach ($slots as $slot) { 459 $slot_from = mktime(substr($slot['from'], 0, 2), substr($slot['from'], 2, 2), 0, $date_info["mon"], $date_info["mday"], $date_info["year"]); 460 $slot_to = mktime(substr($slot['to'], 0, 2), substr($slot['to'], 2, 2), 0, $date_info["mon"], $date_info["mday"], $date_info["year"]); 461 462 // always single object, we can sum up 463 $nr_available = (array) ilBookingReservation::getAvailableObject($object_ids, $slot_from, $slot_to - 1, false, true); 464 465 // any objects available? 466 if (!array_sum($nr_available)) { 467 continue; 468 } 469 470 // check deadline 471 if ($schedule->getDeadline() >= 0) { 472 // 0-n hours before slots begins 473 if ($slot_from < (time() + $schedule->getDeadline() * 60 * 60)) { 474 continue; 475 } 476 } else { 477 // running slots can be booked, only ended slots are invalid 478 if ($slot_to < time()) { 479 continue; 480 } 481 } 482 483 // is slot active in current hour? 484 if ((int) $slot['from'] < $period_to && (int) $slot['to'] > $period_from) { 485 $from = ilDatePresentation::formatDate(new ilDateTime($slot_from, IL_CAL_UNIX)); 486 $from = array_pop(explode(' ', $from)); 487 $to = ilDatePresentation::formatDate(new ilDateTime($slot_to, IL_CAL_UNIX)); 488 $to = array_pop(explode(' ', $to)); 489 490 // show caption (first hour) of slot 491 $id = $slot_from . '_' . $slot_to; 492 if (!in_array($id, $slot_captions)) { 493 $dates[$hour][$column]['captions'][$id] = $from . '-' . $to; 494 $dates[$hour][$column]['available'][$id] = array_sum($nr_available); 495 $slot_captions[] = $id; 496 } 497 498 $in = true; 499 } 500 } 501 // (any) active slot 502 if ($in) { 503 $has_open_slot = true; 504 $dates[$hour][$column]['in_slot'] = $in; 505 } 506 } 507 } 508 } 509 510 return $has_open_slot; 511 } 512 513 // 514 // Step 1a) 515 // 516 // Assign multiple participants (starting from participants screen) (no, from object screen!) 517 // 518 519 //Table to assing participants to an object. 520 public function assignParticipants() 521 { 522 $this->tabs_gui->clearTargets(); 523 $this->tabs_gui->setBackTarget($this->lng->txt('book_back_to_list'), $this->ctrl->getLinkTarget($this, 'back')); 524 525 $table = new ilBookingAssignParticipantsTableGUI($this, 'assignParticipants', $this->pool->getRefId(), $this->pool->getId(), $this->book_obj_id); 526 527 $this->tpl->setContent($table->getHTML()); 528 } 529 530 /** 531 * Create reservations for a bunch of booking pool participants. 532 */ 533 public function bookMultipleParticipants() 534 { 535 if ($_POST["mass"]) { 536 $participants = $_POST["mass"]; 537 } else { 538 $this->back(); 539 } 540 541 $this->tabs_gui->clearTargets(); 542 $this->tabs_gui->setBackTarget($this->lng->txt("back"), $this->ctrl->getLinkTarget($this, 'assignparticipants')); 543 544 $conf = new ilConfirmationGUI(); 545 $conf->setFormAction($this->ctrl->getFormAction($this)); 546 547 //add user list as items. 548 foreach ($participants as $id) { 549 $name = ilObjUser::_lookupFullname($id); 550 $conf->addItem("participants[]", $id, $name); 551 } 552 553 $available = ilBookingReservation::numAvailableFromObjectNoSchedule($this->book_obj_id); 554 if (sizeof($participants) > $available) { 555 $obj = new ilBookingObject($this->book_obj_id); 556 $conf->setHeaderText( 557 sprintf( 558 $this->lng->txt('book_limit_objects_available'), 559 sizeof($participants), 560 $obj->getTitle(), 561 $available 562 ) 563 ); 564 } else { 565 $conf->setHeaderText($this->lng->txt('book_confirm_booking_no_schedule')); 566 $conf->addHiddenItem("object_id", $this->book_obj_id); 567 $conf->setConfirm($this->lng->txt("assign"), "saveMultipleBookings"); 568 } 569 570 $conf->setCancel($this->lng->txt("cancel"), 'redirectToList'); 571 $this->tpl->setContent($conf->getHTML()); 572 } 573 574 public function redirectToList() 575 { 576 $this->ctrl->redirect($this, 'assignParticipants'); 577 } 578 579 /** 580 * Save multiple users reservations for one booking pool object. 581 * //TODO check if object/user exist in the DB, 582 */ 583 public function saveMultipleBookings() 584 { 585 if ($_POST["participants"] && $_POST['object_id']) { 586 $participants = $_POST["participants"]; 587 $this->book_obj_id = $_POST['object_id']; 588 } else { 589 $this->back(); 590 } 591 $rsv_ids = array(); 592 foreach ($participants as $id) { 593 $this->user_id_to_book = $id; 594 $rsv_ids[] = $this->processBooking($this->book_obj_id); 595 } 596 597 if (sizeof($rsv_ids)) { 598 ilUtil::sendSuccess("booking_multiple_succesfully"); 599 $this->back(); 600 } else { 601 ilUtil::sendFailure($this->lng->txt('book_reservation_failed_overbooked'), true); 602 $this->back(); 603 } 604 } 605 606 607 // 608 // Step 2: Confirmation 609 // 610 611 /** 612 * Book object - either of type or specific - for given dates 613 * @return bool 614 */ 615 public function confirmedBooking() // ok 616 { 617 $success = false; 618 $rsv_ids = array(); 619 620 if ($this->pool->getScheduleType() != ilObjBookingPool::TYPE_FIX_SCHEDULE) { 621 if ($this->book_obj_id > 0) { 622 $object_id = $this->book_obj_id; 623 if ($object_id) { 624 if (ilBookingReservation::isObjectAvailableNoSchedule($object_id) && 625 !ilBookingReservation::getObjectReservationForUser($object_id, $this->user_id_to_book)) { // #18304 626 $rsv_ids[] = $this->processBooking($object_id); 627 $success = $object_id; 628 } else { 629 // #11852 630 ilUtil::sendFailure($this->lng->txt('book_reservation_failed_overbooked'), true); 631 $this->ctrl->redirect($this, 'back'); 632 } 633 } 634 } 635 } else { 636 if (!isset($_POST['date'])) { 637 ilUtil::sendFailure($this->lng->txt('select_one')); 638 $this->book(); 639 return false; 640 } 641 642 // single object reservation(s) 643 if ($this->book_obj_id > 0) { 644 $confirm = array(); 645 646 $object_id = $this->book_obj_id; 647 if ($object_id) { 648 $group_id = null; 649 $nr = ilBookingObject::getNrOfItemsForObjects(array($object_id)); 650 // needed for recurrence 651 $f = new ilBookingReservationDBRepositoryFactory(); 652 $repo = $f->getRepo(); 653 $group_id = $repo->getNewGroupId(); 654 foreach ($_POST['date'] as $date) { 655 $fromto = explode('_', $date); 656 $fromto[1]--; 657 658 $counter = ilBookingReservation::getAvailableObject(array($object_id), $fromto[0], $fromto[1], false, true); 659 $counter = $counter[$object_id]; 660 if ($counter) { 661 // needed for recurrence 662 $confirm[$object_id . "_" . $fromto[0] . "_" . ($fromto[1] + 1)] = $counter; 663 } 664 } 665 } 666 667 if (sizeof($confirm)) { 668 $this->confirmBookingNumbers($confirm, $group_id); 669 return false; 670 } 671 } 672 } 673 674 if ($success) { 675 $this->saveParticipant(); 676 $this->handleBookingSuccess($success, $rsv_ids); 677 } else { 678 ilUtil::sendFailure($this->lng->txt('book_reservation_failed'), true); 679 $this->ctrl->redirect($this, 'book'); 680 } 681 return true; 682 } 683 684 /** 685 * save booking participant. 686 */ 687 protected function saveParticipant() 688 { 689 $participant = new ilBookingParticipant($this->user_id_to_book, $this->pool->getId()); 690 } 691 692 /** 693 * Book object for date 694 * 695 * @param int $a_object_id 696 * @param int $a_from timestamp 697 * @param int $a_to timestamp 698 * @param int $a_group_id 699 * @return int 700 */ 701 public function processBooking($a_object_id, $a_from = null, $a_to = null, $a_group_id = null) 702 { 703 // #11995 704 $this->checkPermission('read'); 705 706 $reservation = new ilBookingReservation(); 707 $reservation->setObjectId($a_object_id); 708 $reservation->setUserId($this->user_id_to_book); 709 $reservation->setAssignerId($this->user_id_assigner); 710 $reservation->setFrom($a_from); 711 $reservation->setTo($a_to); 712 $reservation->setGroupId($a_group_id); 713 $reservation->setContextObjId($this->context_obj_id); 714 $reservation->save(); 715 716 if ($a_from) { 717 $this->lng->loadLanguageModule('dateplaner'); 718 $def_cat = ilCalendarUtil::initDefaultCalendarByType(ilCalendarCategory::TYPE_BOOK, $this->user_id_to_book, $this->lng->txt('cal_ch_personal_book'), true); 719 720 $object = new ilBookingObject($a_object_id); 721 722 $entry = new ilCalendarEntry; 723 $entry->setStart(new ilDateTime($a_from, IL_CAL_UNIX)); 724 $entry->setEnd(new ilDateTime($a_to, IL_CAL_UNIX)); 725 $entry->setTitle($this->lng->txt('book_cal_entry') . ' ' . $object->getTitle()); 726 $entry->setContextId($reservation->getId()); 727 $entry->save(); 728 729 $assignment = new ilCalendarCategoryAssignments($entry->getEntryId()); 730 $assignment->addAssignment($def_cat->getCategoryId()); 731 } 732 733 return $reservation->getId(); 734 } 735 736 // 737 // Confirm booking numbers 738 // 739 740 public function confirmBookingNumbers(array $a_objects_counter, $a_group_id, ilPropertyFormGUI $a_form = null) 741 { 742 $tpl = $this->tpl; 743 744 $this->tabs_gui->clearTargets(); 745 $this->tabs_gui->setBackTarget($this->lng->txt('book_back_to_list'), $this->ctrl->getLinkTarget($this, 'back')); 746 747 if (!$a_form) { 748 $a_form = $this->initBookingNumbersForm($a_objects_counter, $a_group_id); 749 } 750 751 $tpl->setContent($a_form->getHTML()); 752 } 753 754 755 protected function initBookingNumbersForm(array $a_objects_counter, $a_group_id, $a_reload = false) 756 { 757 $form = new ilPropertyFormGUI(); 758 $form->setFormAction($this->ctrl->getFormAction($this, "confirmedBooking")); 759 $form->setTitle($this->lng->txt("book_confirm_booking_schedule_number_of_objects")); 760 $form->setDescription($this->lng->txt("book_confirm_booking_schedule_number_of_objects_info")); 761 762 $section = false; 763 $min_date = null; 764 foreach ($a_objects_counter as $id => $counter) { 765 $id = explode("_", $id); 766 $book_id = $id[0] . "_" . $id[1] . "_" . $id[2] . "_" . $counter; 767 768 $obj = new ilBookingObject($id[0]); 769 770 if (!$section) { 771 $section = new ilFormSectionHeaderGUI(); 772 $section->setTitle($obj->getTitle()); 773 $form->addItem($section); 774 775 $section = true; 776 } 777 778 $period = /* $this->lng->txt("book_period").": ". */ 779 ilDatePresentation::formatPeriod( 780 new ilDateTime($id[1], IL_CAL_UNIX), 781 new ilDateTime($id[2], IL_CAL_UNIX) 782 ); 783 784 $nr_field = new ilNumberInputGUI($period, "conf_nr__" . $book_id); 785 $nr_field->setValue(1); 786 $nr_field->setSize(3); 787 $nr_field->setMaxValue($counter); 788 $nr_field->setMinValue($counter ? 1 : 0); 789 $nr_field->setRequired(true); 790 $form->addItem($nr_field); 791 792 if (!$min_date || $id[1] < $min_date) { 793 $min_date = $id[1]; 794 } 795 } 796 797 // recurrence 798 $this->lng->loadLanguageModule("dateplaner"); 799 $rec_mode = new ilSelectInputGUI($this->lng->txt("cal_recurrences"), "recm"); 800 $rec_mode->setRequired(true); 801 $rec_mode->setOptions(array( 802 "-1" => $this->lng->txt("cal_no_recurrence"), 803 1 => $this->lng->txt("cal_weekly"), 804 2 => $this->lng->txt("r_14"), 805 4 => $this->lng->txt("r_4_weeks") 806 )); 807 $form->addItem($rec_mode); 808 809 $rec_end = new ilDateTimeInputGUI($this->lng->txt("cal_repeat_until"), "rece"); 810 $rec_end->setRequired(true); 811 $rec_mode->addSubItem($rec_end); 812 813 if (!$a_reload) { 814 // show date only if active recurrence 815 $rec_mode->setHideSubForm(true, '>= 1'); 816 817 if ($min_date) { 818 $rec_end->setDate(new ilDateTime($min_date, IL_CAL_UNIX)); 819 } 820 } else { 821 // recurrence may not be changed on reload 822 $rec_mode->setDisabled(true); 823 $rec_end->setDisabled(true); 824 } 825 826 if ($a_group_id) { 827 $grp = new ilHiddenInputGUI("grp_id"); 828 $grp->setValue($a_group_id); 829 $form->addItem($grp); 830 } 831 832 if ($this->user_id_assigner != $this->user_id_to_book) { 833 $usr = new ilHiddenInputGUI("bkusr"); 834 $usr->setValue($this->user_id_to_book); 835 $form->addItem($usr); 836 } 837 838 $form->addCommandButton("confirmedBookingNumbers", $this->lng->txt("confirm")); 839 $form->addCommandButton("back", $this->lng->txt("cancel")); 840 841 return $form; 842 } 843 844 public function confirmedBookingNumbers() // ok 845 { 846 847 //get the user who will get the booking. 848 if ($_POST['bkusr']) { 849 $this->user_id_to_book = (int) $_POST['bkusr']; 850 } 851 852 // convert post data to initial form config 853 $counter = array(); 854 $current_first = $obj_id = null; 855 foreach (array_keys($_POST) as $id) { 856 if (substr($id, 0, 9) == "conf_nr__") { 857 $id = explode("_", substr($id, 9)); 858 $counter[$id[0] . "_" . $id[1] . "_" . $id[2]] = (int) $id[3]; 859 if (!$current_first) { 860 $current_first = date("Y-m-d", $id[1]); 861 } 862 } 863 } 864 865 // recurrence 866 867 // checkInput() has not been called yet, so we have to improvise 868 $end = ilCalendarUtil::parseIncomingDate($_POST["rece"], null); 869 870 if ((int) $_POST["recm"] > 0 && $end && $current_first) { 871 ksort($counter); 872 $end = $end->get(IL_CAL_DATE); 873 $cycle = (int) $_POST["recm"] * 7; 874 $cut = 0; 875 $org = $counter; 876 while ($cut < 1000 && $this->addDaysDate($current_first, $cycle) <= $end) { 877 $cut++; 878 $current_first = null; 879 foreach ($org as $item_id => $max) { 880 $parts = explode("_", $item_id); 881 $obj_id = $parts[0]; 882 883 $from = $this->addDaysStamp($parts[1], $cycle * $cut); 884 $to = $this->addDaysStamp($parts[2], $cycle * $cut); 885 886 $new_item_id = $obj_id . "_" . $from . "_" . $to; 887 888 // form reload because of validation errors 889 if (!isset($counter[$new_item_id]) && date("Y-m-d", $to) <= $end) { 890 // get max available for added dates 891 $new_max = ilBookingReservation::getAvailableObject(array($obj_id), $from, $to - 1, false, true); 892 $new_max = (int) $new_max[$obj_id]; 893 894 $counter[$new_item_id] = $new_max; 895 896 if (!$current_first) { 897 $current_first = date("Y-m-d", $from); 898 } 899 900 // clone input 901 $_POST["conf_nr__" . $new_item_id . "_" . $new_max] = $_POST["conf_nr__" . $item_id . "_" . $max]; 902 } 903 } 904 } 905 } 906 907 $group_id = $_POST["grp_id"]; 908 909 $form = $this->initBookingNumbersForm($counter, $group_id, true); 910 if ($form->checkInput()) { 911 $success = false; 912 $rsv_ids = array(); 913 foreach ($counter as $id => $all_nr) { 914 $book_nr = $form->getInput("conf_nr__" . $id . "_" . $all_nr); 915 $parts = explode("_", $id); 916 $obj_id = $parts[0]; 917 $from = $parts[1]; 918 $to = $parts[2] - 1; 919 920 // get currently available slots 921 $counter = ilBookingReservation::getAvailableObject(array($obj_id), $from, $to, false, true); 922 $counter = $counter[$obj_id]; 923 if ($counter) { 924 // we can only book what is left 925 $book_nr = min($book_nr, $counter); 926 for ($loop = 0; $loop < $book_nr; $loop++) { 927 $rsv_ids[] = $this->processBooking($obj_id, $from, $to, $group_id); 928 $success = $obj_id; 929 } 930 } 931 } 932 if ($success) { 933 $this->saveParticipant(); 934 $this->handleBookingSuccess($success, $rsv_ids); 935 } else { 936 ilUtil::sendFailure($this->lng->txt('book_reservation_failed'), true); 937 $this->back(); 938 } 939 } else { 940 // ilDateTimeInputGUI does NOT add hidden values on disabled! 941 942 $rece_array = explode(".", $_POST['rece']); 943 944 $rece_day = str_pad($rece_array[0], 2, "0", STR_PAD_LEFT); 945 $rece_month = str_pad($rece_array[1], 2, "0", STR_PAD_LEFT); 946 $rece_year = $rece_array[2]; 947 948 // ilDateTimeInputGUI will choke on POST array format 949 $_POST["rece"] = null; 950 951 $form->setValuesByPost(); 952 953 $rece_date = new ilDate($rece_year . "-" . $rece_month . "-" . $rece_day, IL_CAL_DATE); 954 955 $form->getItemByPostVar("rece")->setDate($rece_date); 956 $form->getItemByPostVar("recm")->setHideSubForm($_POST["recm"] < 1); 957 958 $hidden_date = new ilHiddenInputGUI("rece"); 959 $hidden_date->setValue($rece_date); 960 $form->addItem($hidden_date); 961 962 $this->confirmBookingNumbers($counter, $group_id, $form); 963 } 964 } 965 966 protected function addDaysDate($a_date, $a_days) 967 { 968 $date = date_parse($a_date); 969 $stamp = mktime(0, 0, 1, $date["month"], $date["day"] + $a_days, $date["year"]); 970 return date("Y-m-d", $stamp); 971 } 972 973 protected function addDaysStamp($a_stamp, $a_days) 974 { 975 $date = getDate($a_stamp); 976 return mktime( 977 $date["hours"], 978 $date["minutes"], 979 $date["seconds"], 980 $date["mon"], 981 $date["mday"] + $a_days, 982 $date["year"] 983 ); 984 } 985 986 // 987 // Step 3: Display post success info 988 // 989 990 protected function handleBookingSuccess($a_obj_id, array $a_rsv_ids = null) 991 { 992 ilUtil::sendSuccess($this->lng->txt('book_reservation_confirmed'), true); 993 994 // show post booking information? 995 $obj = new ilBookingObject($a_obj_id); 996 $pfile = $obj->getPostFile(); 997 $ptext = $obj->getPostText(); 998 999 if (trim($ptext) || $pfile) { 1000 if (sizeof($a_rsv_ids)) { 1001 $this->ctrl->setParameter($this, 'rsv_ids', implode(";", $a_rsv_ids)); 1002 } 1003 $this->ctrl->redirect($this, 'displayPostInfo'); 1004 } else { 1005 $this->back(); 1006 } 1007 } 1008 1009 /** 1010 * Display post booking informatins 1011 */ 1012 public function displayPostInfo() 1013 { 1014 $tpl = $this->tpl; 1015 $lng = $this->lng; 1016 $ilCtrl = $this->ctrl; 1017 $id = $this->book_obj_id; 1018 if (!$id) { 1019 return; 1020 } 1021 1022 // placeholder 1023 1024 $book_ids = ilBookingReservation::getObjectReservationForUser($id, $this->user_id_assigner, true); 1025 $tmp = array(); 1026 foreach ($book_ids as $book_id) { 1027 if (in_array($book_id, $this->rsv_ids)) { 1028 $obj = new ilBookingReservation($book_id); 1029 $from = $obj->getFrom(); 1030 $to = $obj->getTo(); 1031 if ($from > time()) { 1032 $tmp[$from . "-" . $to]++; 1033 } 1034 } 1035 } 1036 1037 $olddt = ilDatePresentation::useRelativeDates(); 1038 ilDatePresentation::setUseRelativeDates(false); 1039 1040 $period = array(); 1041 ksort($tmp); 1042 foreach ($tmp as $time => $counter) { 1043 $time = explode("-", $time); 1044 $time = ilDatePresentation::formatPeriod( 1045 new ilDateTime($time[0], IL_CAL_UNIX), 1046 new ilDateTime($time[1], IL_CAL_UNIX) 1047 ); 1048 if ($counter > 1) { 1049 $time .= " (" . $counter . ")"; 1050 } 1051 $period[] = $time; 1052 } 1053 $book_id = array_shift($book_ids); 1054 1055 ilDatePresentation::setUseRelativeDates($olddt); 1056 1057 1058 /* 1059 #23578 since Booking pool participants. 1060 $obj = new ilBookingReservation($book_id); 1061 if ($obj->getUserId() != $ilUser->getId()) 1062 { 1063 return; 1064 } 1065 */ 1066 1067 $obj = new ilBookingObject($id); 1068 $pfile = $obj->getPostFile(); 1069 $ptext = $obj->getPostText(); 1070 1071 $mytpl = new ilTemplate('tpl.booking_reservation_post.html', true, true, 'Modules/BookingManager/BookingProcess'); 1072 $mytpl->setVariable("TITLE", $lng->txt('book_post_booking_information')); 1073 1074 if ($ptext) { 1075 // placeholder 1076 $ptext = str_replace("[OBJECT]", $obj->getTitle(), $ptext); 1077 $ptext = str_replace("[PERIOD]", implode("<br />", $period), $ptext); 1078 1079 $mytpl->setVariable("POST_TEXT", nl2br($ptext)); 1080 } 1081 1082 if ($pfile) { 1083 $url = $ilCtrl->getLinkTarget($this, 'deliverPostFile'); 1084 1085 $mytpl->setVariable("DOWNLOAD", $lng->txt('download')); 1086 $mytpl->setVariable("URL_FILE", $url); 1087 $mytpl->setVariable("TXT_FILE", $pfile); 1088 } 1089 1090 $mytpl->setVariable("TXT_SUBMIT", $lng->txt('ok')); 1091 $mytpl->setVariable("URL_SUBMIT", $ilCtrl->getLinkTarget($this, "back")); 1092 1093 $tpl->setContent($mytpl->get()); 1094 } 1095 1096 /** 1097 * Deliver post booking file 1098 */ 1099 public function deliverPostFile() 1100 { 1101 $id = $this->book_obj_id; 1102 if (!$id) { 1103 return; 1104 } 1105 1106 $book_id = ilBookingReservation::getObjectReservationForUser($id, $this->user_id_assigner); 1107 $obj = new ilBookingReservation($book_id); 1108 if ($obj->getUserId() != $this->user_id_assigner) { 1109 return; 1110 } 1111 1112 $obj = new ilBookingObject($id); 1113 $file = $obj->getPostFileFullPath(); 1114 if ($file) { 1115 ilUtil::deliverFile($file, $obj->getPostFile()); 1116 } 1117 } 1118} 1119