/** * @param array $post * @param array $files */ public function bind(array $post, array $files = array()) { parent::bind($post); if (isset($files['avatar']) && $files['avatar']['tmp_name']) { if (in_array($files['avatar']['type'], array("image/gif", "image/jpeg", "image/png"))) { $uploaded = wp_handle_upload($files['avatar'], array('test_form' => false)); if ($uploaded) { $editor = wp_get_image_editor($uploaded['file']); $editor->resize(200, 200); $editor->save($uploaded['file']); $this->data['avatar_path'] = $uploaded['file']; $this->data['avatar_url'] = $uploaded['url']; // Remove old image. $staff = new AB_Staff(); $staff->load($post['id']); if (file_exists($staff->get('avatar_path'))) { unlink($staff->get('avatar_path')); } } } } }
public function addAdminMenu() { /** @var WP_User $current_user */ global $current_user; // Translated submenu pages. $calendar = __('Calendar', 'bookly'); $appointments = __('Appointments', 'bookly'); $staff_members = __('Staff Members', 'bookly'); $services = __('Services', 'bookly'); $sms = __('SMS Notifications', 'bookly'); $notifications = __('Email Notifications', 'bookly'); $customers = __('Customers', 'bookly'); $payments = __('Payments', 'bookly'); $appearance = __('Appearance', 'bookly'); $settings = __('Settings', 'bookly'); $coupons = __('Coupons', 'bookly'); $custom_fields = __('Custom Fields', 'bookly'); if ($current_user->has_cap('administrator') || AB_Staff::query()->where('wp_user_id', $current_user->ID)->count()) { if (function_exists('add_options_page')) { $dynamic_position = '80.0000001' . mt_rand(1, 1000); // position always is under `Settings` add_menu_page('Bookly', 'Bookly', 'read', 'ab-system', '', plugins_url('resources/images/menu.png', __FILE__), $dynamic_position); add_submenu_page('ab-system', $calendar, $calendar, 'read', 'ab-calendar', array($this->calendarController, 'index')); add_submenu_page('ab-system', $appointments, $appointments, 'manage_options', 'ab-appointments', array($this->appointmentsController, 'index')); if ($current_user->has_cap('administrator')) { add_submenu_page('ab-system', $staff_members, $staff_members, 'manage_options', AB_StaffController::page_slug, array($this->staffController, 'index')); } else { if (1 == get_option('ab_settings_allow_staff_members_edit_profile')) { add_submenu_page('ab-system', __('Profile', 'bookly'), __('Profile', 'bookly'), 'read', AB_StaffController::page_slug, array($this->staffController, 'index')); } } add_submenu_page('ab-system', $services, $services, 'manage_options', AB_ServiceController::page_slug, array($this->serviceController, 'index')); add_submenu_page('ab-system', $customers, $customers, 'manage_options', AB_CustomerController::page_slug, array($this->customerController, 'index')); add_submenu_page('ab-system', $notifications, $notifications, 'manage_options', 'ab-notifications', array($this->notificationsController, 'index')); add_submenu_page('ab-system', $sms, $sms, 'manage_options', AB_SmsController::page_slug, array($this->smsController, 'index')); add_submenu_page('ab-system', $payments, $payments, 'manage_options', 'ab-payments', array($this->paymentController, 'index')); add_submenu_page('ab-system', $appearance, $appearance, 'manage_options', 'ab-appearance', array($this->apearanceController, 'index')); add_submenu_page('ab-system', $custom_fields, $custom_fields, 'manage_options', 'ab-custom-fields', array($this->customFieldsController, 'index')); add_submenu_page('ab-system', $coupons, $coupons, 'manage_options', 'ab-coupons', array($this->couponsController, 'index')); add_submenu_page('ab-system', $settings, $settings, 'manage_options', AB_SettingsController::page_slug, array($this->settingsController, 'index')); global $submenu; do_action('bookly_addons_menu', 'ab-system'); unset($submenu['ab-system'][0]); } } }
/** * Get array with appointments data for customer profile. * * @return array */ public function getAppointmentsForProfile() { $records = array(); if ($this->get('id')) { $result = $this->wpdb->get_results($this->wpdb->prepare('SELECT `c`.`name` `category`, `sv`.`title` `service`, `s`.`full_name` `staff`, `a`.`start_date` `start_date`, `ss`.`price` `price`, `ca`.`number_of_persons` `number_of_persons`, `ca`.`coupon_discount` `coupon_discount`, `ca`.`coupon_deduction` `coupon_deduction`, `ca`.`time_zone_offset` `time_zone_offset`, `ca`.`token` `token` FROM `' . AB_Appointment::getTableName() . '` `a` LEFT JOIN `' . AB_Staff::getTableName() . '` `s` ON `s`.`id` = `a`.`staff_id` LEFT JOIN `' . AB_Service::getTableName() . '` `sv` ON `sv`.`id` = `a`.`service_id` LEFT JOIN `' . AB_Category::getTableName() . '` `c` ON `c`.`id` = `sv`.`category_id` LEFT JOIN `' . AB_StaffService::getTableName() . '` `ss` ON `ss`.`staff_id` = `a`.`staff_id` AND `ss`.`service_id` = `a`.`service_id` INNER JOIN `' . AB_CustomerAppointment::getTableName() . '` `ca` ON `ca`.`appointment_id` = `a`.`id` AND `ca`.`customer_id` = %d', $this->get('id')), ARRAY_A); if ($result) { foreach ($result as $row) { if ($row['time_zone_offset'] !== null) { $row['start_date'] = AB_DateTimeUtils::applyTimeZoneOffset($row['start_date'], $row['time_zone_offset']); } if ($row['coupon_discount'] or $row['coupon_deduction']) { $coupon = new AB_Coupon(); $coupon->set('discount', $row['coupon_discount']); $coupon->set('deduction', $row['coupon_deduction']); $row['price'] = $coupon->apply($row['price']); } $row['price'] *= $row['number_of_persons']; unset($row['time_zone_offset'], $row['coupon_discount'], $row['coupon_deduction'], $row['number_of_persons']); $records[] = $row; } } } return $records; }
/** * Get list of users available for particular staff. * * @global string $table_prefix * @param integer $staff_id If null then it means new staff * @return array */ public function getUsersForStaff($staff_id = null) { /** @var wpdb $wpdb */ global $wpdb; if (!is_multisite()) { $query = sprintf('SELECT ID, user_email, display_name FROM ' . $wpdb->users . ' WHERE ID NOT IN(SELECT DISTINCT IFNULL( wp_user_id, 0 ) FROM ' . AB_Staff::getTableName() . ' %s) ORDER BY display_name', $staff_id !== null ? "WHERE " . AB_Staff::getTableName() . ".id <> {$staff_id}" : ''); $users = $wpdb->get_results($query); } else { // In Multisite show users only for current blog. if ($staff_id == null) { $query = AB_Staff::query('s')->select('DISTINCT wp_user_id')->whereNot('wp_user_id', null); } else { $query = AB_Staff::query('s')->select('wp_user_id')->whereNot('id', $staff_id); } $occupied_wp_users = array(); foreach ($query->fetchArray() as $staff) { $occupied_wp_users[] = $staff['wp_user_id']; } $users = get_users(array('blog_id' => get_current_blog_id(), 'orderby' => 'display_name', 'exclude' => $occupied_wp_users)); } return $users; }
/** * Ajax request for Holidays calendar */ public function executeSettingsHoliday() { $id = $this->getParameter('id', false); $holiday = $this->getParameter('holiday') == 'true'; $repeat = $this->getParameter('repeat') == 'true'; $day = $this->getParameter('day', false); // update or delete the event if ($id) { if ($holiday) { $this->getWpdb()->update(AB_Holiday::getTableName(), array('repeat_event' => intval($repeat)), array('id' => $id), array('%d')); $this->getWpdb()->update(AB_Holiday::getTableName(), array('repeat_event' => intval($repeat)), array('parent_id' => $id), array('%d')); } else { $this->getWpdb()->delete(AB_Holiday::getTableName(), array('id' => $id), array('%d')); $this->getWpdb()->delete(AB_Holiday::getTableName(), array('parent_id' => $id), array('%d')); } // add the new event } elseif ($holiday && $day) { $holiday = new AB_Holiday(array('date' => $day, 'repeat_event' => intval($repeat))); $holiday->save(); foreach (AB_Staff::query()->fetchArray() as $employee) { $staff_holiday = new AB_Holiday(array('date' => $day, 'repeat_event' => intval($repeat), 'staff_id' => $employee['id'], 'parent_id' => $holiday->get('id'))); $staff_holiday->save(); } } // and return refreshed events echo $this->getHolidays(); exit; }
/** * @param AB_Notification $notification */ public function processNotification(AB_Notification $notification) { /** @var $wpdb wpdb */ global $wpdb; $date = new DateTime(); switch ($notification->get('type')) { case 'staff_agenda': if ($date->format('H') >= 18) { $rows = $wpdb->get_results('SELECT `a`.*, `c`.`name` AS `customer_name`, `s`.`title` AS `service_title`, `st`.`email` AS `staff_email`, `st`.`phone` AS `staff_phone`, `st`.`full_name` AS `staff_name` FROM `' . AB_CustomerAppointment::getTableName() . '` `ca` LEFT JOIN `' . AB_Appointment::getTableName() . '` `a` ON `a`.`id` = `ca`.`appointment_id` LEFT JOIN `' . AB_Customer::getTableName() . '` `c` ON `c`.`id` = `ca`.`customer_id` LEFT JOIN `' . AB_Service::getTableName() . '` `s` ON `s`.`id` = `a`.`service_id` LEFT JOIN `' . AB_Staff::getTableName() . '` `st` ON `st`.`id` = `a`.`staff_id` LEFT JOIN `' . AB_StaffService::getTableName() . '` `ss` ON `ss`.`staff_id` = `a`.`staff_id` AND `ss`.`service_id` = `a`.`service_id` WHERE DATE(DATE_ADD("' . $this->mysql_now . '", INTERVAL 1 DAY)) = DATE(`a`.`start_date`) AND NOT EXISTS ( SELECT * FROM `' . AB_SentNotification::getTableName() . '` `sn` WHERE DATE(`sn`.`created`) = DATE("' . $this->mysql_now . '") AND `sn`.`gateway` = "' . $notification->get('gateway') . '" AND `sn`.`type` = "staff_agenda" AND `sn`.`staff_id` = `a`.`staff_id` )'); if ($rows) { $appointments = array(); foreach ($rows as $row) { $appointments[$row->staff_id][] = $row; } foreach ($appointments as $staff_id => $collection) { $sent = false; $staff_email = null; $staff_phone = null; $table = $notification->get('gateway') == 'email' ? '<table>%s</table>' : '%s'; $tr = $notification->get('gateway') == 'email' ? '<tr><td>%s</td><td>%s</td><td>%s</td></tr>' : "%s %s %s\n"; $agenda = ''; foreach ($collection as $appointment) { $startDate = new DateTime($appointment->start_date); $endDate = new DateTime($appointment->end_date); $agenda .= sprintf($tr, $startDate->format('H:i') . '-' . $endDate->format('H:i'), $appointment->service_title, $appointment->customer_name); $staff_email = $appointment->staff_email; $staff_phone = $appointment->staff_phone; } $agenda = sprintf($table, $agenda); if ($staff_email || $staff_phone) { $replacement = new AB_NotificationCodes(); $replacement->set('next_day_agenda', $agenda); $replacement->set('appointment_datetime', $appointment->start_date); $replacement->set('staff_name', $appointment->staff_name); if ($notification->get('gateway') == 'email' && $staff_email) { $message = $replacement->replace($notification->get('message')); $subject = $replacement->replace($notification->get('subject')); // Send email. $sent = wp_mail($staff_email, $subject, wpautop($message), AB_Utils::getEmailHeaders()); } else { if ($notification->get('gateway') == 'sms' && $staff_phone) { $message = $replacement->replace($notification->get('message'), $notification->get('gateway')); // Send sms. $sent = $this->sms->sendSms($staff_phone, $message); } } } if ($sent) { $sent_notification = new AB_SentNotification(); $sent_notification->set('staff_id', $staff_id); $sent_notification->set('gateway', $notification->get('gateway')); $sent_notification->set('type', 'staff_agenda'); $sent_notification->set('created', $date->format('Y-m-d H:i:s')); $sent_notification->save(); } } } } break; case 'client_follow_up': if ($date->format('H') >= 21) { $rows = $wpdb->get_results('SELECT `a`.*, `ca`.* FROM `' . AB_CustomerAppointment::getTableName() . '` `ca` LEFT JOIN `' . AB_Appointment::getTableName() . '` `a` ON `a`.`id` = `ca`.`appointment_id` WHERE DATE("' . $this->mysql_now . '") = DATE(`a`.`start_date`) AND NOT EXISTS ( SELECT * FROM `' . AB_SentNotification::getTableName() . '` `sn` WHERE DATE(`sn`.`created`) = DATE("' . $this->mysql_now . '") AND `sn`.`gateway` = "' . $notification->get('gateway') . '" AND `sn`.`type` = "client_follow_up" AND `sn`.`customer_appointment_id` = `ca`.`id` )', ARRAY_A); if ($rows) { foreach ($rows as $row) { $customer_appointment = new AB_CustomerAppointment(); $customer_appointment->load($row['id']); if (AB_NotificationSender::sendFromCron(AB_NotificationSender::CRON_FOLLOW_UP_EMAIL, $notification, $customer_appointment)) { $sent_notification = new AB_SentNotification(); $sent_notification->set('customer_appointment_id', $customer_appointment->get('id')); $sent_notification->set('gateway', $notification->get('gateway')); $sent_notification->set('type', 'client_follow_up'); $sent_notification->set('created', $date->format('Y-m-d H:i:s')); $sent_notification->save(); } } } } break; case 'client_reminder': if ($date->format('H') >= 18) { $rows = $wpdb->get_results('SELECT `ca`.`id` FROM `' . AB_CustomerAppointment::getTableName() . '` `ca` LEFT JOIN `' . AB_Appointment::getTableName() . '` `a` ON `a`.`id` = `ca`.`appointment_id` WHERE DATE(DATE_ADD("' . $this->mysql_now . '", INTERVAL 1 DAY)) = DATE(`a`.`start_date`) AND NOT EXISTS ( SELECT * FROM `' . AB_SentNotification::getTableName() . '` `sn` WHERE DATE(`sn`.`created`) = DATE("' . $this->mysql_now . '") AND `sn`.`gateway` = "' . $notification->get('gateway') . '" AND `sn`.`type` = "client_reminder" AND `sn`.`customer_appointment_id` = `ca`.`id` )', ARRAY_A); if ($rows) { foreach ($rows as $row) { $customer_appointment = new AB_CustomerAppointment(); $customer_appointment->load($row['id']); if (AB_NotificationSender::sendFromCron(AB_NotificationSender::CRON_NEXT_DAY_APPOINTMENT, $notification, $customer_appointment)) { $sent_notification = new AB_SentNotification(); $sent_notification->set('customer_appointment_id', $customer_appointment->get('id')); $sent_notification->set('gateway', $notification->get('gateway')); $sent_notification->set('type', 'client_reminder'); $sent_notification->set('created', $date->format('Y-m-d H:i:s')); $sent_notification->save(); } } } } break; } }
/** * Get staff name. * * @return string */ public function getStaffName() { $staff_id = $this->getStaffId(); if ($staff_id) { $staff = new AB_Staff(); $staff->load($staff_id); return $staff->get('full_name'); } return __('Any', 'bookly'); }
/** * @return mixed */ private function getStaffCollection() { return AB_Staff::query()->fetchArray(); }
function update_7_0() { global $wpdb; $wpdb->query('ALTER TABLE `ab_customer_appointment` ADD `coupon_deduction` DECIMAL(10,2) DEFAULT NULL AFTER `coupon_discount`'); $wpdb->query('ALTER TABLE `ab_coupons` CHANGE COLUMN `used` `used` INT UNSIGNED NOT NULL DEFAULT 0, ADD COLUMN `deduction` DECIMAL(10,2) NOT NULL DEFAULT 0 AFTER `discount`, ADD COLUMN `usage_limit` INT UNSIGNED NOT NULL DEFAULT 1'); $wpdb->query('ALTER TABLE `ab_notifications` CHANGE `slug` `type` VARCHAR(255) NOT NULL DEFAULT ""'); // SMS. $wpdb->query('ALTER TABLE `ab_notifications` ADD `gateway` ENUM("email","sms") NOT NULL DEFAULT "email"'); $wpdb->query('UPDATE `ab_notifications` SET `gateway` = "email"'); $sms_notifies = array(array('type' => 'client_new_appointment', 'message' => __("Dear [[CLIENT_NAME]].\nThis is confirmation that you have booked [[SERVICE_NAME]].\nWe are waiting you at [[COMPANY_ADDRESS]] on [[APPOINTMENT_DATE]] at [[APPOINTMENT_TIME]].\nThank you for choosing our company.\n[[COMPANY_NAME]]\n[[COMPANY_PHONE]]\n[[COMPANY_WEBSITE]]", 'bookly'), 'active' => 1), array('type' => 'staff_new_appointment', 'message' => __("Hello.\nYou have new booking.\nService: [[SERVICE_NAME]]\nDate: [[APPOINTMENT_DATE]]\nTime: [[APPOINTMENT_TIME]]\nClient name: [[CLIENT_NAME]]\nClient phone: [[CLIENT_PHONE]]\nClient email: [[CLIENT_EMAIL]]", 'bookly'), 'active' => 0), array('type' => 'client_reminder', 'message' => __("Dear [[CLIENT_NAME]].\nWe would like to remind you that you have booked [[SERVICE_NAME]] tomorrow on [[APPOINTMENT_TIME]]. We are waiting you at [[COMPANY_ADDRESS]].\nThank you for choosing our company.\n[[COMPANY_NAME]]\n[[COMPANY_PHONE]]\n[[COMPANY_WEBSITE]]", 'bookly'), 'active' => 0), array('type' => 'client_follow_up', 'message' => __("Dear [[CLIENT_NAME]].\nThank you for choosing [[COMPANY_NAME]]. We hope you were satisfied with your [[SERVICE_NAME]].\nThank you and we look forward to seeing you again soon.\n[[COMPANY_NAME]]\n[[COMPANY_PHONE]]\n[[COMPANY_WEBSITE]]", 'bookly'), 'active' => 0), array('type' => 'staff_agenda', 'message' => __("Hello.\nYour agenda for tomorrow is:\n[[NEXT_DAY_AGENDA]]", 'bookly'), 'active' => 0), array('type' => 'staff_cancelled_appointment', 'message' => __("Hello.\nThe following booking has been cancelled.\nService: [[SERVICE_NAME]]\nDate: [[APPOINTMENT_DATE]]\nTime: [[APPOINTMENT_TIME]]\nClient name: [[CLIENT_NAME]]\nClient phone: [[CLIENT_PHONE]]\nClient email: [[CLIENT_EMAIL]]", 'bookly'), 'active' => 0), array('type' => 'client_new_wp_user', 'message' => __("Hello.\nAn account was created for you at [[SITE_ADDRESS]]\nYour user details:\nuser: [[NEW_USERNAME]]\npassword: [[NEW_PASSWORD]]\n\nThanks.", 'bookly'), 'active' => 1)); // Insert notifications. foreach ($sms_notifies as $data) { $wpdb->insert('ab_notifications', array('gateway' => 'sms', 'type' => $data['type'], 'subject' => '', 'message' => $data['message'], 'active' => $data['active'])); } // Rename notifications. $notifications = array('client_info' => 'client_new_appointment', 'provider_info' => 'staff_new_appointment', 'evening_next_day' => 'client_reminder', 'evening_after' => 'client_follow_up', 'event_next_day' => 'staff_agenda', 'cancel_appointment' => 'staff_cancelled_appointment', 'new_wp_user' => 'client_new_wp_user'); foreach ($notifications as $from => $to) { $wpdb->query("UPDATE `ab_notifications` SET `type` = '{$to}' WHERE `type` = '{$from}'"); } $this->drop('ab_email_notification'); // Rename tables. $ab_tables = array('ab_appointment' => AB_Appointment::getTableName(), 'ab_category' => AB_Category::getTableName(), 'ab_coupons' => AB_Coupon::getTableName(), 'ab_customer' => AB_Customer::getTableName(), 'ab_customer_appointment' => AB_CustomerAppointment::getTableName(), 'ab_holiday' => AB_Holiday::getTableName(), 'ab_notifications' => AB_Notification::getTableName(), 'ab_payment' => AB_Payment::getTableName(), 'ab_schedule_item_break' => AB_ScheduleItemBreak::getTableName(), 'ab_service' => AB_Service::getTableName(), 'ab_staff' => AB_Staff::getTableName(), 'ab_staff_schedule_item' => AB_StaffScheduleItem::getTableName(), 'ab_staff_service' => AB_StaffService::getTableName()); foreach ($ab_tables as $from => $to) { $wpdb->query("ALTER TABLE `{$from}` RENAME TO `{$to}`"); } $wpdb->query("CREATE TABLE IF NOT EXISTS `" . AB_SentNotification::getTableName() . "` (\n `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,\n `customer_appointment_id` INT UNSIGNED,\n `staff_id` INT UNSIGNED,\n `gateway` ENUM('email','sms') NOT NULL DEFAULT 'email',\n `type` VARCHAR(60) NOT NULL,\n `created` DATETIME NOT NULL,\n CONSTRAINT fk_" . AB_SentNotification::getTableName() . "_" . AB_CustomerAppointment::getTableName() . "_id\n FOREIGN KEY (customer_appointment_id)\n REFERENCES " . AB_CustomerAppointment::getTableName() . "(id)\n ON DELETE CASCADE\n ON UPDATE CASCADE,\n CONSTRAINT fk_" . AB_SentNotification::getTableName() . "_" . AB_Staff::getTableName() . "_id\n FOREIGN KEY (staff_id)\n REFERENCES " . AB_Staff::getTableName() . "(id)\n ON DELETE CASCADE\n ON UPDATE CASCADE\n ) ENGINE = INNODB\n DEFAULT CHARACTER SET = utf8\n COLLATE = utf8_general_ci"); // Google Calendar. add_option('ab_settings_google_event_title', '[[SERVICE_NAME]]'); // Link assets. add_option('ab_settings_link_assets_method', 'enqueue'); // SMS. add_option('ab_sms_default_country_code', ''); }
/** * Prepare data for email. * * @param AB_CustomerAppointment $ca * @return array */ private static function _prepareData(AB_CustomerAppointment $ca) { $appointment = new AB_Appointment(); $appointment->load($ca->get('appointment_id')); $customer = new AB_Customer(); $customer->load($ca->get('customer_id')); $staff = new AB_Staff(); $staff->load($appointment->get('staff_id')); $service = new AB_Service(); $service->load($appointment->get('service_id')); $staff_service = new AB_StaffService(); $staff_service->loadBy(array('staff_id' => $staff->get('id'), 'service_id' => $service->get('id'))); $price = $staff_service->get('price'); if ($ca->get('coupon_discount') or $ca->get('coupon_deduction')) { $coupon = new AB_Coupon(); $coupon->set('discount', $ca->get('coupon_discount')); $coupon->set('deduction', $ca->get('coupon_deduction')); $price = $coupon->apply($price); } $codes = new AB_NotificationCodes(); $codes->set('appointment_datetime', $appointment->get('start_date')); $codes->set('appointment_token', $ca->get('token')); $codes->set('category_name', $service->getCategoryName()); $codes->set('client_name', $customer->get('name')); $codes->set('client_phone', $customer->get('phone')); $codes->set('client_email', $customer->get('email')); $codes->set('custom_fields', $ca->getFormattedCustomFields('text')); $codes->set('custom_fields_2c', $ca->getFormattedCustomFields('html')); $codes->set('number_of_persons', $ca->get('number_of_persons')); $codes->set('service_name', $service->getTitle()); $codes->set('service_price', $price); $codes->set('staff_name', $staff->get('full_name')); $codes->set('staff_email', $staff->get('email')); $codes->set('staff_phone', $staff->get('phone')); $codes->set('staff_photo', $staff->get('avatar_url')); return array($codes, $staff, $appointment, $customer); }
/** * Get item data for cart. * * @param $other_data * @param $cart_item * * @return array */ function getItemData($other_data, $cart_item) { if (isset($cart_item['bookly'])) { $info_name = get_option('ab_woocommerce_cart_info_name'); $info_value = get_option('ab_woocommerce_cart_info_value'); $staff = new AB_Staff(); $staff->load($cart_item['bookly']['staff_ids'][0]); $service = new AB_Service(); $service->load($cart_item['bookly']['service_id']); $info_value = strtr($info_value, array('[[APPOINTMENT_TIME]]' => AB_DateTimeUtils::formatTime($cart_item['bookly']['appointment_datetime']), '[[APPOINTMENT_DATE]]' => AB_DateTimeUtils::formatDate($cart_item['bookly']['appointment_datetime']), '[[CATEGORY_NAME]]' => $service->getCategoryName(), '[[SERVICE_NAME]]' => $service->getTitle(), '[[SERVICE_PRICE]]' => $service->get('price'), '[[STAFF_NAME]]' => $staff->get('full_name'))); $other_data[] = array('name' => $info_name, 'value' => $info_value); } return $other_data; }
/** * @return string */ private function getCalendarID() { return $this->staff->get('google_calendar_id') ?: 'primary'; }
/** * 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); }
/** * Constructor. */ public function __construct() { global $wpdb; // Select all services (with categories and staff members) // which have at least one staff member assigned. $rows = $wpdb->get_results($wpdb->prepare(' SELECT IFNULL(`c`.`id`,0) AS `category_id`, IFNULL(`c`.`name`,%s) AS `category_name`, `c`.`position` AS `category_position`, `s`.`id` AS `service_id`, `s`.`position` AS `service_position`, `s`.`title` AS `service_name`, `st`.`id` AS `staff_id`, `st`.`position` AS `staff_position`, `st`.`full_name` AS `staff_name`, `ss`.`capacity` AS `capacity`, `ss`.`price` AS `price` FROM `' . AB_Service::getTableName() . '` `s` INNER JOIN `' . AB_StaffService::getTableName() . '` `ss` ON `s`.`id` = `ss`.`service_id` LEFT JOIN `' . AB_Category::getTableName() . '` `c` ON `s`.`category_id` = `c`.`id` LEFT JOIN `' . AB_Staff::getTableName() . '` `st` ON `ss`.`staff_id` = `st`.`id` ORDER BY `service_name` ', __('Uncategorized', 'bookly')), ARRAY_A); foreach ($rows as $row) { if (!isset($this->services[$row['service_id']])) { $this->services[$row['service_id']] = array('id' => $row['service_id'], 'name' => AB_Utils::getTranslatedString('service_' . $row['service_id'], $row['service_name']), 'category_id' => $row['category_id'], 'staff' => array(), 'max_capacity' => $row['capacity'], 'position' => $row['service_position']); } else { if ($this->services[$row['service_id']]['max_capacity'] < $row['capacity']) { // Detect the max capacity for each service //(it is the max capacity from all staff members who provides this service). $this->services[$row['service_id']]['max_capacity'] = $row['capacity']; } } if (!isset($this->staff[$row['staff_id']])) { $this->staff[$row['staff_id']] = array('id' => $row['staff_id'], 'name' => AB_Utils::getTranslatedString('staff_' . $row['staff_id'], $row['staff_name']), 'services' => array(), 'position' => $row['staff_position']); } if ($row['category_id'] != '' && !isset($this->categories[$row['category_id']])) { $this->categories[$row['category_id']] = array('id' => $row['category_id'], 'name' => AB_Utils::getTranslatedString('category_' . $row['category_id'], $row['category_name']), 'services' => array(), 'position' => $row['category_position']); } if (!isset($this->services[$row['service_id']]['staff'][$row['staff_id']])) { $staff_member = $this->staff[$row['staff_id']]; unset($staff_member['services']); if (self::isPaymentDisabled() == false) { $staff_member['name'] .= ' (' . AB_Utils::formatPrice($row['price']) . ')'; } $this->services[$row['service_id']]['staff'][$row['staff_id']] = $staff_member; } if (!isset($this->staff[$row['staff_id']]['services'][$row['service_id']])) { $service = $this->services[$row['service_id']]; unset($service['staff']); $service['max_capacity'] = $row['capacity']; $this->staff[$row['staff_id']]['services'][$row['service_id']] = $service; } if (!isset($this->categories[intval($row['category_id'])]['staff'][$row['staff_id']])) { $staff_member = $this->staff[$row['staff_id']]; unset($staff_member['services']); $this->categories[intval($row['category_id'])]['staff'][$row['staff_id']] = $staff_member; } if (!isset($this->categories[intval($row['category_id'])]['services'][$row['service_id']])) { $service = $this->services[$row['service_id']]; unset($service['staff']); $this->categories[intval($row['category_id'])]['services'][$row['service_id']] = $service; } } }
/** * Prepare data for staff. * * @param DateTime $start_date */ private function _prepareStaffData(DateTime $start_date) { $this->staffData = array(); $services = AB_StaffService::query('ss')->select('ss.staff_id, ss.price, ss.capacity')->whereIn('ss.staff_id', $this->staff_ids)->where('ss.service_id', $this->userData->get('service_id'))->fetchArray(); foreach ($services as $item) { $this->staffData[$item['staff_id']] = array('price' => $item['price'], 'capacity' => $item['capacity'], 'holidays' => array(), 'bookings' => array(), 'working_hours' => array()); } // Load holidays. $holidays = AB_Holiday::query('h')->whereIn('h.staff_id', $this->staff_ids)->fetchArray(); foreach ($holidays as $item) { $this->staffData[$item['staff_id']]['holidays'][] = $item; } // Load working schedule. $working_schedule = AB_StaffScheduleItem::query('ssi')->select('ssi.*, break.start_time AS break_start, break.end_time AS break_end')->leftJoin('AB_ScheduleItemBreak', 'break', 'break.staff_schedule_item_id = ssi.id')->whereIn('ssi.staff_id', $this->staff_ids)->whereNot('ssi.start_time', null)->fetchArray(); foreach ($working_schedule as $item) { if (!isset($this->staffData[$item['staff_id']]['working_hours'][$item['day_index']])) { $this->staffData[$item['staff_id']]['working_hours'][$item['day_index']] = array('start_time' => $item['start_time'], 'end_time' => $item['end_time'], 'breaks' => array()); } if ($item['break_start']) { $this->staffData[$item['staff_id']]['working_hours'][$item['day_index']]['breaks'][] = array('start' => $item['break_start'], 'end' => $item['break_end']); } } // Load bookings. $bookings = AB_CustomerAppointment::query('ca')->select('a.*, SUM(ca.number_of_persons) AS number_of_bookings')->leftJoin('AB_Appointment', 'a', 'a.id = ca.appointment_id')->leftJoin('AB_StaffService', 'ss', 'ss.staff_id = a.staff_id AND ss.service_id = a.service_id')->whereIn('a.staff_id', $this->staff_ids)->whereGte('a.start_date', $this->userData->get('date_from'))->groupBy('a.start_date')->groupBy('a.staff_id')->groupBy('a.service_id')->fetchArray(); foreach ($bookings as $item) { $item['from_google'] = false; // Handle bookings which end at 24:00. if (substr($item['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). $item['end_date'] = '10_symbols 24:00:00'; } $this->staffData[$item['staff_id']]['bookings'][] = $item; } // Handle Google Calendar events. if (get_option('ab_settings_google_two_way_sync')) { $query = AB_Staff::query('s')->whereIn('s.id', array_merge($this->userData->get('staff_ids'), array(0))); foreach ($query->find() as $staff) { $google = new AB_Google(); if ($google->loadByStaff($staff)) { $this->staffData[$staff->get('id')]['bookings'] = array_merge($this->staffData[$staff->get('id')]['bookings'], $google->getCalendarEvents($start_date) ?: array()); } } } }
/** * Save appointment form (for both create and edit). */ public function executeSaveAppointmentForm() { /** * @var WPDB $wpdb */ global $wpdb; $response = array('status' => 'error'); $start_date = date('Y-m-d H:i:s', strtotime($this->getParameter('start_date'))); $end_date = date('Y-m-d H:i:s', strtotime($this->getParameter('end_date'))); $staff_id = $this->getParameter('staff_id'); $service_id = $this->getParameter('service_id', null); $appointment_id = $this->getParameter('id', 0); $customers = json_decode($this->getParameter('customers', '[]')); $notes = $this->getParameter('notes', ''); $staff_service = new AB_StaffService(); $staff_service->loadByStaffAndService($staff_id, $service_id); // Check for errors. if (!$this->dateIntervalIsAvailableForAppointment($start_date, $end_date, $staff_id, $appointment_id)) { $response['errors'] = array('date_interval_not_available' => true); } if (count($customers) > $staff_service->get('capacity')) { $response['errors']['overflow_capacity'] = true; $response['errors']['overflow_capacity_message'] = __('Number of customers should be not more than ', 'ab') . $staff_service->get('capacity'); } // If no errors then try to save the appointment. if (!isset($response['errors'])) { $appointment = new AB_Appointment(); if ($appointment_id) { // edit $appointment->load($appointment_id); } $appointment->set('start_date', $start_date); $appointment->set('end_date', $end_date); $appointment->set('staff_id', $staff_id); $appointment->set('service_id', $service_id); if ($appointment->save() !== false) { // save customers $current_customers = $appointment->getCustomers(); foreach (array_diff(array_keys($current_customers), $customers) as $el) { $wpdb->delete('ab_customer_appointment', array('appointment_id' => $appointment->get('id'), 'customer_id' => $el)); } foreach (array_diff($customers, array_keys($current_customers)) as $el) { $customer_appointment = new AB_Customer_Appointment(); $customer_appointment->set('appointment_id', $appointment->get('id')); $customer_appointment->set('customer_id', $el); while (true) { $token = md5(uniqid(time(), true)); $result = $wpdb->get_row($wpdb->prepare('SELECT * FROM `ab_customer_appointment` WHERE token = %s', $token)); if (!$result) { break; } } $customer_appointment->set('token', $token); $customer_appointment->save(); } $startDate = new DateTime($appointment->get('start_date')); $endDate = new DateTime($appointment->get('end_date')); $staff = new AB_Staff(); $staff->load($staff_id); $service = new AB_Service(); $service->load($service_id); $response['status'] = 'ok'; $desc = array(); $appointment_additional_info = $wpdb->get_row($wpdb->prepare('SELECT ss.capacity AS max_capacity, COUNT( ca.id ) AS current_capacity, ca.customer_id, ca.notes, ca.id AS ca_id FROM ab_appointment a LEFT JOIN ab_customer_appointment ca ON ca.appointment_id = a.id LEFT JOIN ab_staff_service ss ON ss.staff_id = a.staff_id AND ss.service_id = a.service_id WHERE a.id = %d', $appointment->get('id'))); if ($appointment_additional_info->max_capacity == 1) { // save notes $customer_appointment = new AB_Customer_Appointment(); $customer_appointment->load($appointment_additional_info->ca_id); $customer_appointment->set('notes', $notes); $customer_appointment->save(); $customer = new AB_Customer(); $customer->load($appointment_additional_info->customer_id); foreach (array('name', 'phone', 'email') as $data_entry) { $entry_value = $customer->get($data_entry); if ($entry_value) { $desc[] = '<div class="wc-employee">' . esc_html($entry_value) . '</div>'; } } $desc[] = '<div class="wc-notes">' . nl2br(esc_html($notes ?: $appointment_additional_info->notes)) . '</div>'; } else { // save notes $customer_appointment = new AB_Customer_Appointment(); $customer_appointment->load($appointment_additional_info->ca_id); $customer_appointment->set('notes', null); $customer_appointment->save(); $desc[] = '<div class="wc-notes">Signed up ' . $appointment_additional_info->current_capacity . '</div>'; $desc[] = '<div class="wc-notes">Capacity ' . $appointment_additional_info->max_capacity . '</div>'; } $response['data'] = array('id' => (int) $appointment->get('id'), 'start' => $startDate->format('m/d/Y H:i'), 'end' => $endDate->format('m/d/Y H:i'), 'desc' => implode('', $desc), 'title' => $service->get('title') ? $service->get('title') : __('Untitled', 'ab'), 'color' => $service->get('color'), 'userId' => (int) $appointment->get('staff_id')); // refresh data $current_customers = $appointment->getCustomers(); if ($this->getParameter('email_notification') === 'true') { // Send email notification to client with appointment info $client_notification = $wpdb->get_row('SELECT * FROM ab_notifications WHERE slug = "client_info" AND active = 1'); // Send email notification to service provider with appointment info $staff_notification = $wpdb->get_row('SELECT * FROM ab_notifications WHERE slug = "provider_info" AND active = 1'); foreach ($current_customers as $customer) { if ($client_notification) { $replacement = new AB_NotificationReplacement(); $replacement->setClientName($customer->name); $replacement->setClientPhone($customer->phone); $replacement->setClientEmail($customer->email); // $replacement->setClientNotes( nl2br( esc_html( $notes ) ) ); $replacement->setAppointmentTime($appointment->get('start_date')); $replacement->setServiceName($service->get('title') ? $service->get('title') : __('Untitled', 'ab')); $replacement->setServicePrice($staff_service->get('price')); $replacement->setAppointmentToken($customer->token); $replacement->setStaffName($staff->get('full_name')); $message = wpautop($replacement->replace($client_notification->message)); $subject = $replacement->replaceSubject($client_notification->subject); wp_mail($customer->email, $subject, $message, AB_CommonUtils::getEmailHeaderFrom()); } if ($staff_notification) { $replacement = new AB_NotificationReplacement(); $replacement->setClientName($customer->name); $replacement->setClientPhone($customer->phone); $replacement->setClientEmail($customer->email); // $replacement->setClientNotes( nl2br( esc_html( $notes ) ) ); $replacement->setAppointmentTime($appointment->get('start_date')); $replacement->setServiceName($service->get('title') ? $service->get('title') : __('Untitled', 'ab')); $replacement->setServicePrice($staff_service->get('price')); $replacement->setAppointmentToken($customer->token); $replacement->setStaffName($staff->get('full_name')); $message = wpautop($replacement->replace($staff_notification->message)); $subject = $replacement->replaceSubject($staff_notification->subject); // Send copy to administrators if ($staff_notification->copy) { $admin_emails = AB_CommonUtils::getAdminEmails(); if (!empty($admin_emails)) { wp_mail($admin_emails, $subject, $message, AB_CommonUtils::getEmailHeaderFrom()); } } wp_mail($staff->get('email'), $subject, $message, AB_CommonUtils::getEmailHeaderFrom()); } } } } else { $response['errors'] = array('unknown' => true); } } exit(json_encode($response)); }
/** * @return AB_Appointment */ public function save() { /** @var wpdb $wpdb */ global $wpdb; // #11094: if customer with such name & e-mail exists, append new booking to him, otherwise - create new customer $customer_exists = $wpdb->get_row($wpdb->prepare('SELECT * FROM ab_customer WHERE name = %s AND email = %s', $this->name, $this->email)); $customer = new AB_Customer(); if ($customer_exists) { $customer->set('id', $customer_exists->id); $customer->set('name', $customer_exists->name); $customer->set('email', $customer_exists->email); $customer->set('phone', $customer_exists->phone); } else { $customer->set('name', $this->name); $customer->set('email', $this->email); $customer->set('phone', $this->phone); $customer->save(); } $this->customer_id = $customer->get('id'); $service = new AB_Service(); $service->load($this->service_id); $category = new AB_Category(); $category->load($service->get('category_id')); /** * Get appointment, with same params. * If it is -> create connection to this appointment, * otherwise create appointment and connect customer to new appointment */ $booking = $wpdb->get_row($wpdb->prepare("SELECT * from ab_appointment a WHERE a.staff_id = %d and a.service_id = %d and a.start_date = %s LIMIT 1;", $this->getStaffId(), $this->service_id, $this->booked_datetime)); $appointment = new AB_Appointment(); if ($booking) { $appointment->load($booking->id); } else { $appointment->set('staff_id', $this->getStaffId()); $appointment->set('service_id', $this->service_id); $appointment->set('start_date', date('Y-m-d H:i:s', strtotime($this->booked_datetime))); $endDate = new DateTime($this->booked_datetime); $di = "+ {$service->get('duration')} sec"; $endDate->modify($di); $appointment->set('end_date', $endDate->format('Y-m-d H:i:s')); $appointment->save(); } $customer_appointment = new AB_Customer_Appointment(); $customer_appointment->set('appointment_id', $appointment->get('id')); $customer_appointment->set('customer_id', $customer->get('id')); $customer_appointment->set('token', md5($this->form_id)); $customer_appointment->set('notes', $this->notes); $customer_appointment->save(); $staff = new AB_Staff(); $staff->load($this->getStaffId()); return $appointment; }
/** * Extend parent method to control access on staff member level. * * @param string $action * @return bool */ protected function hasAccess($action) { if (parent::hasAccess($action)) { if (!AB_Utils::isCurrentUserAdmin()) { $staff = new AB_Staff(); switch ($action) { case 'executeEditStaff': case 'executeDeleteStaffAvatar': case 'executeStaffServices': case 'executeStaffSchedule': case 'executeStaffHolidays': $staff->load($this->getParameter('id')); break; case 'executeStaffServicesUpdate': case 'executeStaffHolidaysUpdate': $staff->load($this->getParameter('staff_id')); break; case 'executeStaffScheduleHandleBreak': $staffScheduleItem = new AB_StaffScheduleItem(); $staffScheduleItem->load($this->getParameter('staff_schedule_item_id')); $staff->load($staffScheduleItem->get('staff_id')); break; case 'executeDeleteStaffScheduleBreak': $break = new AB_ScheduleItemBreak(); $break->load($this->getParameter('id')); $staffScheduleItem = new AB_StaffScheduleItem(); $staffScheduleItem->load($break->get('staff_schedule_item_id')); $staff->load($staffScheduleItem->get('staff_id')); break; case 'executeStaffScheduleUpdate': if ($this->hasParameter('days')) { foreach ($this->getParameter('days') as $id => $day_index) { $staffScheduleItem = new AB_StaffScheduleItem(); $staffScheduleItem->load($id); $staff = new AB_Staff(); $staff->load($staffScheduleItem->get('staff_id')); if ($staff->get('wp_user_id') != get_current_user_id()) { return false; } } } break; default: return false; } return $staff->get('wp_user_id') == get_current_user_id(); } return true; } return false; }
private function _drop_tables() { /** @var wpdb $wpdb */ global $wpdb; $ab_tables = array(AB_Appointment::getTableName(), AB_Category::getTableName(), AB_Coupon::getTableName(), AB_Customer::getTableName(), AB_CustomerAppointment::getTableName(), AB_Holiday::getTableName(), AB_Notification::getTableName(), AB_Payment::getTableName(), AB_ScheduleItemBreak::getTableName(), AB_SentNotification::getTableName(), AB_Service::getTableName(), AB_Staff::getTableName(), AB_StaffScheduleItem::getTableName(), AB_StaffService::getTableName()); $this->_drop_fk($ab_tables); $wpdb->query('DROP TABLE IF EXISTS `' . implode('`, `', $ab_tables) . '` CASCADE;'); }
public function executeRenderPayment() { $form_id = $this->getParameter('form_id'); $response = null; if ($form_id) { $payment_disabled = AB_BookingConfiguration::isPaymentDisabled(); $this->userData = new AB_UserBookingData($form_id); $this->userData->load(); if ($this->userData->hasData()) { if ($this->userData->getServicePrice() <= 0) { $payment_disabled = true; } } if ($payment_disabled == false) { $this->form_id = $form_id; $this->info_text = nl2br(esc_html(get_option('ab_appearance_text_info_fourth_step'))); $this->info_text_coupon = $this->_prepareInfoText(4, $this->userData); if ($this->userData->hasData()) { $employee = new AB_Staff(); $employee->load($this->userData->getStaffId()); $service = new AB_Service(); $service->load($this->userData->getServiceId()); $price = $this->getWpdb()->get_var($this->getWpdb()->prepare(' SELECT price FROM ab_staff_service WHERE staff_id = %d AND service_id = %d', $employee->get('id'), $service->get('id'))); $this->_prepareProgressTracker(4, $price); // Set response. $response = array('status' => 'success', 'html' => $this->render('payment', array(), false)); } else { if (isset($_SESSION['tmp_booking_data'])) { $tmp_booking_data = AB_CommonUtils::getTemporaryBookingData(); if (!empty($tmp_booking_data)) { $tmp_form_id = $tmp_booking_data['form_id']; if (isset($_SESSION['appointment_booking'][$tmp_form_id]) && $_SESSION['appointment_booking'][$tmp_form_id]['cancelled'] === true) { $employee = new AB_Staff(); $employee->load($tmp_booking_data['staff_id'][0]); $service = new AB_Service(); $service->load($tmp_booking_data['service_id']); $price = $this->getWpdb()->get_var($this->getWpdb()->prepare(' SELECT price FROM ab_staff_service WHERE staff_id = %d AND service_id = %d', $employee->get('id'), $service->get('id'))); // create a paypal object $paypal = new PayPal(); $product = new stdClass(); $product->name = $service->get('title'); $product->desc = $service->getTitleWithDuration(); $product->price = $price; $product->qty = 1; $paypal->addProduct($product); // get the products information from the $_POST and create the Product objects $this->paypal = $paypal; $this->_prepareProgressTracker(4, $price); $error_msg = isset($_SESSION['appointment_booking'][$tmp_form_id]['paypal_error']) ? $_SESSION['appointment_booking'][$tmp_form_id]['paypal_error'] : ""; unset($_SESSION['appointment_booking'][$tmp_form_id]['paypal_error']); // Set response. $response = array('status' => 'success', 'html' => $this->render('payment', array('form_id' => $tmp_form_id, 'error_msg' => $error_msg), false)); } } } } } } // Output JSON response. if ($response === null) { $response = array('status' => 'no-data'); } header('Content-Type: application/json'); echo json_encode($response); exit(0); }
public function executeDeleteStaffAvatar() { $staff = new AB_Staff(); $staff->load(1); unlink($staff->get('avatar_path')); $staff->set('avatar_url', ''); $staff->set('avatar_path', ''); $staff->save(); exit; }