public function __construct()
 {
     global $PHP_SELF;
     if (is_admin() && (strpos($PHP_SELF, 'post-new.php') !== false || strpos($PHP_SELF, 'post.php') !== false)) {
         wp_enqueue_script('backbone');
         wp_enqueue_script('underscore');
         add_action('admin_footer', array(&$this, 'renderPopup'));
         add_filter('media_buttons', array(&$this, 'addButton'), 50);
         $configuration = new AB_BookingConfiguration();
         $this->vars['categoriesJson'] = $configuration->getCategoriesJson();
         $this->vars['staffJson'] = $configuration->getStaffJson();
         $this->vars['servicesJson'] = $configuration->getServicesJson();
     }
 }
Esempio n. 2
0
 /**
  * Constructor.
  *
  * @param array $options
  */
 public function __construct(array $options = array())
 {
     // Handle widget options.
     $options = array_merge(array('use_empty' => true, 'empty_value' => null, 'exclude_last_slot' => false), $options);
     // Insert empty value if required.
     if ($options['use_empty']) {
         $this->values[null] = $options['empty_value'];
     }
     $ts_length = AB_BookingConfiguration::getTimeSlotLength();
     $time_start = AB_StaffScheduleItem::WORKING_START_TIME;
     $time_end = AB_StaffScheduleItem::WORKING_END_TIME;
     if ($options['exclude_last_slot']) {
         $time_end -= $ts_length;
     }
     // Run the loop.
     while ($time_start <= $time_end) {
         $this->values[AB_DateTimeUtils::buildTimeString($time_start)] = AB_DateTimeUtils::formatTime($time_start);
         $time_start += $ts_length;
     }
 }
Esempio n. 3
0
 /**
  * @param string $field_name
  * @param bool $is_start
  * @return string
  */
 public function renderField($field_name = 'ab_settings_monday', $is_start = true)
 {
     $ts_length = AB_BookingConfiguration::getTimeSlotLength();
     $time_output = AB_StaffScheduleItem::WORKING_START_TIME;
     $time_end = AB_StaffScheduleItem::WORKING_END_TIME;
     $option_name = $field_name . ($is_start ? '_start' : '_end');
     $class_name = $is_start ? 'select_start' : 'select_end';
     $selected_value = get_option($option_name);
     $output = "<select class='form-control ab-auto-w {$class_name}' name={$option_name}>";
     if ($is_start) {
         $output .= "<option value=''>" . __('OFF', 'bookly') . "</option>";
         $time_end -= $ts_length;
     }
     while ($time_output <= $time_end) {
         $value = AB_DateTimeUtils::buildTimeString($time_output, false);
         $op_name = AB_DateTimeUtils::formatTime($time_output);
         $output .= "<option value='{$value}'" . selected($value, $selected_value, false) . ">{$op_name}</option>";
         $time_output += $ts_length;
     }
     $output .= '</select>';
     return $output;
 }
Esempio n. 4
0
 /**
  * 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);
         }
     }
 }
Esempio n. 5
0
 /**
  * Render progress tracker into a variable.
  *
  * @param int $booking_step
  * @param int|bool $price
  */
 private function _prepareProgressTracker($booking_step, $price = false)
 {
     if (get_option('ab_appearance_show_progress_tracker') == 1) {
         $payment_disabled = AB_BookingConfiguration::isPaymentDisabled() || $price !== false && $price <= 0;
         $tracker = $this->render('_progress_tracker', array('booking_step' => $booking_step, 'payment_disabled' => $payment_disabled), false);
     } else {
         $tracker = '';
     }
     $this->progress_tracker = $tracker;
 }
Esempio n. 6
0
?>
,
            attributes     : <?php 
echo $attributes;
?>
,
            form_id        : <?php 
echo json_encode($form_id);
?>
,
            start_of_week  : <?php 
echo (int) get_option('start_of_week');
?>
,
            date_min       : <?php 
echo json_encode(AB_BookingConfiguration::getDateMin());
?>
,
            date_format    : <?php 
echo json_encode(AB_DateTimeUtils::convertFormat('date', AB_DateTimeUtils::FORMAT_PICKADATE));
?>
,
            custom_fields  : <?php 
echo get_option('ab_custom_fields');
?>
,
            show_calendar  : <?php 
echo intval(get_option('ab_appearance_show_calendar'));
?>
,
            woocommerce    : <?php 
 /**
  * Render progress tracker into a variable.
  *
  * @param int $booking_step
  * @param int|null $price
  */
 private function _prepareProgressTracker($booking_step, $price = null)
 {
     $payment_disabled = AB_BookingConfiguration::isPaymentDisabled() || $price !== null && $price <= 0;
     $this->progress_tracker = $this->render('_progress_tracker', array('booking_step' => $booking_step, 'payment_disabled' => $payment_disabled), false);
 }
Esempio n. 8
0
 /**
  * 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;
 }
Esempio n. 9
0
 /**
  * Returns a collection of Google calendar events
  *
  * @param DateTime $startDate
  * @return array|false
  */
 public function getCalendarEvents(DateTime $startDate)
 {
     // get all events from calendar, without timeMin filter (the end of the event can be later then the start of searched time period)
     $result = array();
     try {
         $calendar_access = $this->getCalendarAccess();
         $time_slot_length = AB_BookingConfiguration::getTimeSlotLength();
         $limit_events = get_option('ab_settings_google_limit_events');
         $timeMin = clone $startDate;
         $timeMin = $timeMin->modify('-1 day')->format(DateTime::RFC3339);
         $events = $this->service->events->listEvents($this->getCalendarID(), array('singleEvents' => true, 'orderBy' => 'startTime', 'timeMin' => $timeMin, 'maxResults' => $limit_events ?: self::EVENTS_PER_REQUEST));
         while (true) {
             foreach ($events->getItems() as $event) {
                 /** @var Google_Service_Calendar_Event $event */
                 if ($event->getStatus() !== 'cancelled') {
                     // Skip events created by Bookly in non freeBusyReader calendar.
                     if ($calendar_access != 'freeBusyReader') {
                         $ext_properties = $event->getExtendedProperties();
                         if ($ext_properties !== null) {
                             $private = $ext_properties->private;
                             if ($private !== null && array_key_exists('service_id', $private)) {
                                 continue;
                             }
                         }
                     }
                     // Get start/end dates of event and transform them into WP timezone (Google doesn't transform whole day events into our timezone).
                     $event_start = $event->getStart();
                     $event_end = $event->getEnd();
                     if ($event_start->dateTime == null) {
                         // All day event.
                         $eventStartDate = new DateTime($event_start->date, new DateTimeZone($this->getCalendarTimezone()));
                         $eventEndDate = new DateTime($event_end->date, new DateTimeZone($this->getCalendarTimezone()));
                     } else {
                         // Regular event.
                         $eventStartDate = new DateTime($event_start->dateTime);
                         $eventEndDate = new DateTime($event_end->dateTime);
                     }
                     $eventStartDate->setTimezone(new DateTimeZone(AB_Utils::getTimezoneString()));
                     $eventEndDate->setTimezone(new DateTimeZone(AB_Utils::getTimezoneString()));
                     // Check if event intersects with out datetime interval.
                     if ($eventEndDate > $startDate) {
                         // If event lasts for more than 1 day, then divide it.
                         for ($loop_start = $eventStartDate; $loop_start < $eventEndDate; $loop_start->modify('+1 day')->setTime(0, 0, 0)) {
                             // Start date.
                             if ($loop_start->format('Ymd') > $eventStartDate->format('Ymd')) {
                                 $start_date = $loop_start->format('Y-m-d 00:00:00');
                             } else {
                                 $start_date = $loop_start->format('Y-m-d H:i:s');
                             }
                             // End date.
                             if ($loop_start->format('Ymd') < $eventEndDate->format('Ymd')) {
                                 $end_date = '10_symbols 24:00:00';
                             } else {
                                 $loop_end = clone $eventEndDate;
                                 $end_date = $loop_end->getTimestamp();
                                 // Round end time to a multiple of the default time slot length.
                                 $extra = $end_date % $time_slot_length;
                                 if ($extra) {
                                     $end_date += $time_slot_length - $extra;
                                 }
                                 $loop_end->setTimestamp($end_date);
                                 $end_date = $loop_end->format('Y-m-d H:i:s');
                                 if (substr($end_date, 11) == '00:00:00') {
                                     // Set time to 24:00:00 (date part does not matter, it just needs to be 10 characters length).
                                     $end_date = '10_symbols 24:00:00';
                                 }
                             }
                             $result[] = array('staff_id' => $this->staff->get('id'), 'start_date' => $start_date, 'end_date' => $end_date, 'number_of_bookings' => 1, 'from_google' => true);
                         }
                     }
                 }
             }
             if (!$limit_events && $events->getNextPageToken()) {
                 $events = $this->service->events->listEvents($this->getCalendarID(), array('singleEvents' => true, 'orderBy' => 'startTime', 'timeMin' => $timeMin, 'pageToken' => $events->getNextPageToken()));
             } else {
                 break;
             }
         }
         return $result;
     } catch (Exception $e) {
         $this->errors[] = $e->getMessage();
     }
     return false;
 }
Esempio n. 10
0
 /**
  * Get data needed for appointment form initialisation.
  */
 public function executeGetDataForAppointmentForm()
 {
     $result = array('staff' => array(), 'customers' => array(), 'custom_fields' => array(), 'time' => array(), 'time_interval' => get_option('ab_settings_time_slot_length') * 60);
     // Staff list.
     $staff_members = AB_Utils::isCurrentUserAdmin() ? AB_Staff::query()->sortBy('position')->find() : AB_Staff::query()->where('wp_user_id', get_current_user_id())->find();
     /** @var AB_Staff $staff_member */
     foreach ($staff_members as $staff_member) {
         $services = array();
         foreach ($staff_member->getStaffServices() as $staff_service) {
             $services[] = array('id' => $staff_service->service->get('id'), 'title' => sprintf('%s (%s)', $staff_service->service->get('title'), AB_Service::durationToString($staff_service->service->get('duration'))), 'duration' => $staff_service->service->get('duration'), 'capacity' => $staff_service->get('capacity'));
         }
         $result['staff'][] = array('id' => $staff_member->get('id'), 'full_name' => $staff_member->get('full_name'), 'services' => $services);
     }
     // Customers list.
     foreach (AB_Customer::query()->sortBy('name')->find() as $customer) {
         $name = $customer->get('name');
         if ($customer->get('email') != '' || $customer->get('phone') != '') {
             $name .= ' (' . trim($customer->get('email') . ', ' . $customer->get('phone'), ', ') . ')';
         }
         $result['customers'][] = array('id' => $customer->get('id'), 'name' => $name, 'custom_fields' => array(), 'number_of_persons' => 1);
     }
     // Time list.
     $ts_length = AB_BookingConfiguration::getTimeSlotLength();
     $time_start = AB_StaffScheduleItem::WORKING_START_TIME;
     $time_end = AB_StaffScheduleItem::WORKING_END_TIME;
     // Run the loop.
     while ($time_start <= $time_end) {
         $result['time'][] = array('value' => AB_DateTimeUtils::buildTimeString($time_start, false), 'title' => AB_DateTimeUtils::formatTime($time_start));
         $time_start += $ts_length;
     }
     wp_send_json($result);
 }
 /**
  * Find array of time slots available for booking
  * for given date.
  *
  * @access private
  * @param string $date
  * @return array
  */
 private function _findAvailableTime($date)
 {
     $result = array();
     $dayofweek = date('w', strtotime($date)) + 1;
     // 1-7
     $is_date_today = $date == date('Y-m-d', current_time('timestamp'));
     $current_time = date('H:i:s', ceil(current_time('timestamp') / AB_BookingConfiguration::getTimeSlotLength()) * AB_BookingConfiguration::getTimeSlotLength());
     foreach ($this->staff_working_hours as $staff_id => $hours) {
         if (isset($hours[$dayofweek]) && $this->isWorkingDay($date, $staff_id)) {
             // Find intersection between working and requested hours
             //(excluding time slots in the past).
             $working_start_time = $is_date_today && $current_time > $hours[$dayofweek]['start_time'] ? $current_time : $hours[$dayofweek]['start_time'];
             $intersection = $this->_findIntersection($this->_strToTime($working_start_time), $this->_strToTime($hours[$dayofweek]['end_time']), $this->_strToTime($this->_userData->getRequestedTimeFrom()), $this->_strToTime($this->_userData->getRequestedTimeTo()));
             if (is_array($intersection) && !array_key_exists('start', $intersection)) {
                 $intersections = $intersection;
                 foreach ($intersections as $intersection) {
                     if ($intersection && $this->service_duration <= $intersection['end'] - $intersection['start']) {
                         // Initialize time frames.
                         $timeframes = array(array('start' => $intersection['start'], 'end' => $intersection['end'], 'staff_id' => $staff_id));
                         // Remove breaks from the time frames.
                         foreach ($hours[$dayofweek]['breaks'] as $break) {
                             $timeframes = $this->_removeTimePeriod($timeframes, $this->_strToTime($break['start']), $this->_strToTime($break['end']));
                         }
                         // Remove bookings from the time frames.
                         $bookings = isset($this->bookings[$staff_id]) ? $this->bookings[$staff_id] : array();
                         foreach ($bookings as $booking) {
                             $bookingStart = new DateTime($booking->start_date);
                             if ($date == $bookingStart->format('Y-m-d')) {
                                 $bookingEnd = new DateTime($booking->end_date);
                                 $booking_start = $bookingStart->format('U') % (24 * 60 * 60);
                                 $booking_end = $bookingEnd->format('U') % (24 * 60 * 60);
                                 $timeframes = $this->_removeTimePeriod($timeframes, $booking_start, $booking_end);
                             }
                         }
                         $result = array_merge($result, $timeframes);
                     }
                 }
             } else {
                 if ($intersection && $this->service_duration <= $intersection['end'] - $intersection['start']) {
                     // Initialize time frames.
                     $timeframes = array(array('start' => $intersection['start'], 'end' => $intersection['end'], 'staff_id' => $staff_id));
                     // Remove breaks from the time frames.
                     foreach ($hours[$dayofweek]['breaks'] as $break) {
                         $timeframes = $this->_removeTimePeriod($timeframes, $this->_strToTime($break['start']), $this->_strToTime($break['end']));
                     }
                     // Remove bookings from the time frames.
                     $bookings = isset($this->bookings[$staff_id]) ? $this->bookings[$staff_id] : array();
                     foreach ($bookings as $booking) {
                         $bookingStart = new DateTime($booking->start_date);
                         if ($date == $bookingStart->format('Y-m-d')) {
                             $bookingEnd = new DateTime($booking->end_date);
                             $booking_start = $bookingStart->format('U') % (24 * 60 * 60);
                             $booking_end = $bookingEnd->format('U') % (24 * 60 * 60);
                             $timeframes = $this->_removeTimePeriod($timeframes, $booking_start, $booking_end);
                         }
                     }
                     $result = array_merge($result, $timeframes);
                 }
             }
         }
     }
     usort($result, create_function('$a, $b', 'return $a[\'start\'] - $b[\'start\'];'));
     return $result;
 }