/** * Contructor. * * @param $form_id */ public function __construct($form_id) { $this->form_id = $form_id; // Set up default parameters. $prior_time = AB_BookingConfiguration::getMinimumTimePriorBooking(); $this->set('date_from', date('Y-m-d', current_time('timestamp') + $prior_time)); $schedule_item = AB_StaffScheduleItem::query('ssi')->select('SUBSTRING_INDEX(MIN(ssi.start_time), ":", 2) AS min_end_time')->whereNot('start_time', null)->fetchArray(); $this->set('time_from', $schedule_item[0]['min_end_time']); $schedule_item = AB_StaffScheduleItem::query('ssi')->select('SUBSTRING_INDEX(MAX(end_time), ":", 2) AS max_end_time')->whereNot('start_time', null)->fetchArray(); $this->set('time_to', $schedule_item[0]['max_end_time']); // If logged in then set name, email and if existing customer then also phone. $current_user = wp_get_current_user(); if ($current_user && $current_user->ID) { $customer = new AB_Customer(); if ($customer->loadBy(array('wp_user_id' => $current_user->ID))) { $this->set('name', $customer->get('name')); $this->set('email', $customer->get('email')); $this->set('phone', $customer->get('phone')); } else { $this->set('name', $current_user->display_name); $this->set('email', $current_user->user_email); } } }
/** * 1. Render first step. * * @return string JSON */ public function executeRenderService() { $response = null; $form_id = $this->getParameter('form_id'); if ($form_id) { $configuration = new AB_BookingConfiguration(); $userData = new AB_UserBookingData($form_id); $userData->load(); if (get_option('ab_settings_use_client_time_zone')) { $time_zone_offset = $this->getParameter('time_zone_offset'); $configuration->setClientTimeZoneOffset($time_zone_offset / 60); $userData->saveData(array('time_zone_offset' => $time_zone_offset, 'date_from' => date('Y-m-d', current_time('timestamp') + AB_BookingConfiguration::getMinimumTimePriorBooking() - (get_option('gmt_offset') * HOUR_IN_SECONDS + $time_zone_offset * 60)))); } $this->work_day_time_data = $configuration->fetchAvailableWorkDaysAndTime(); $this->_prepareProgressTracker(1, $userData->getServicePrice()); $this->info_text = $this->_prepareInfoText(get_option('ab_appearance_text_info_first_step'), $userData); // Prepare week days that need to be checked. $days_checked = $userData->get('days'); if (empty($days_checked)) { // Check all available days. $days_checked = array_keys($this->work_day_time_data['available_days']); } $response = array('status' => 'success', 'html' => $this->render('1_service', array('userData' => $userData, 'days_checked' => $days_checked), false), 'categories' => $configuration->getCategories(), 'staff' => $configuration->getStaff(), 'services' => $configuration->getServices(), 'attributes' => $userData->get('service_id') ? array('service_id' => $userData->get('service_id'), 'staff_member_id' => $userData->getStaffId(), 'number_of_persons' => $userData->get('number_of_persons')) : null); } else { $response = array('status' => 'error', 'error' => __('Form ID error.', 'bookly')); } // Output JSON response. wp_send_json($response); }
/** * Find array of time slots available for booking * for given date. * * @access private * @param DateTime $date * @return array */ private function _findAvailableTime(DateTime $date) { $result = array(); $time_slot_length = AB_BookingConfiguration::getTimeSlotLength(); $prior_time = AB_BookingConfiguration::getMinimumTimePriorBooking(); $show_blocked_slots = AB_BookingConfiguration::showBlockedTimeSlots(); $current_timestamp = (int) current_time('timestamp') + $prior_time; $current_date = date_create('@' . $current_timestamp)->setTime(0, 0); if ($date < $current_date) { return array(); } $day_of_week = $date->format('w') + 1; // 1-7 $start_time = date('H:i:s', ceil($current_timestamp / $time_slot_length) * $time_slot_length); foreach ($this->staffData as $staff_id => $staff) { if ($staff['capacity'] < $this->userData->get('number_of_persons')) { continue; } if (isset($staff['working_hours'][$day_of_week]) && $this->isWorkingDay($date, $staff_id)) { if ($this->isWholeDayService()) { // For whole day services do not check staff working hours. $intersections = array(array('start' => 0, 'end' => 86400)); } else { // Find intersection between working and requested hours //(excluding time slots in the past). $working_start_time = $date == $current_date && $start_time > $staff['working_hours'][$day_of_week]['start_time'] ? $start_time : $staff['working_hours'][$day_of_week]['start_time']; $intersections = $this->_findIntersections($this->_timeToSecs($working_start_time), $this->_timeToSecs($staff['working_hours'][$day_of_week]['end_time']), $this->_timeToSecs($this->userData->get('time_from')), $this->_timeToSecs($this->userData->get('time_to'))); } foreach ($intersections as $intersection) { if ($intersection['end'] - $intersection['start'] >= $this->service_duration) { // Initialize time frames. $frames = array(array('start' => $intersection['start'], 'end' => $intersection['end'], 'staff_id' => $staff_id)); if (!$this->isWholeDayService()) { // Remove breaks from time frames for non whole day services only. foreach ($staff['working_hours'][$day_of_week]['breaks'] as $break) { $frames = $this->_removeTimePeriod($frames, $this->_timeToSecs($break['start']), $this->_timeToSecs($break['end'])); } } // Remove bookings from time frames. foreach ($staff['bookings'] as $booking) { // Work with bookings for the current day only. if ($date->format('Y-m-d') == substr($booking['start_date'], 0, 10)) { $booking_start = $this->_timeToSecs(substr($booking['start_date'], 11)); $booking_end = $this->_timeToSecs(substr($booking['end_date'], 11)); $frames = $this->_removeTimePeriod($frames, $booking_start, $booking_end, $removed); if ($removed) { // Handle not full bookings (when number of bookings is less than capacity). if ($booking['from_google'] == false && $booking['service_id'] == $this->userData->get('service_id') && $booking_start >= $intersection['start'] && $staff['capacity'] - $booking['number_of_bookings'] >= $this->userData->get('number_of_persons')) { // Show only the first slot as available. $frames[] = array('start' => $booking_start, 'end' => $booking_start + $time_slot_length, 'staff_id' => $staff_id, 'not_full' => true); if ($this->isWholeDayService()) { // For whole day services there can be just one not full appointment // for a day, thus we break the loop and do not add 'booked' slots. break; } if ($show_blocked_slots) { // When displaying blocked slots then the rest must be shown as blocked. $frames[] = array('start' => $booking_start + $time_slot_length, 'end' => $booking_end <= $intersection['end'] ? $booking_end : $intersection['end'], 'staff_id' => $staff_id, 'booked' => true); } } else { if ($show_blocked_slots) { // Show removed slots as blocked. if ($this->isWholeDayService()) { $frames[] = array('start' => 0, 'end' => $time_slot_length, 'staff_id' => $staff_id, 'booked' => true); // For whole day services we break the loop since the day is not available // and we do not need more 'booked' slots. break; } else { $frames[] = array('start' => $booking_start >= $intersection['start'] ? $booking_start : $intersection['start'], 'end' => $booking_end <= $intersection['end'] ? $booking_end : $intersection['end'], 'staff_id' => $staff_id, 'booked' => true); } } } } } } $result = array_merge($result, $frames); } } } } usort($result, function ($a, $b) { return $a['start'] - $b['start']; }); return $result; }