/** * Send the Express Checkout NVP request * * @param $form_id * @throws Exception */ public function send_EC_Request($form_id) { if (!session_id()) { @session_start(); } if (!count($this->products)) { throw new Exception('Products not found!'); } $total = 0; // create the data to send on PayPal $data = '&SOLUTIONTYPE=' . 'Sole' . '&PAYMENTREQUEST_0_PAYMENTACTION=' . 'Sale' . '&PAYMENTREQUEST_0_CURRENCYCODE=' . urlencode(get_option('ab_paypal_currency')) . '&RETURNURL=' . urlencode(add_query_arg(array('action' => 'ab-paypal-returnurl', 'ab_fid' => $form_id), AB_Utils::getCurrentPageURL())) . '&CANCELURL=' . urlencode(add_query_arg(array('action' => 'ab-paypal-cancelurl', 'ab_fid' => $form_id), AB_Utils::getCurrentPageURL())); foreach ($this->products as $k => $product) { $data .= "&L_PAYMENTREQUEST_0_NAME{$k}=" . urlencode($product->name) . "&L_PAYMENTREQUEST_0_DESC{$k}=" . urlencode($product->desc) . "&L_PAYMENTREQUEST_0_AMT{$k}=" . urlencode($product->price) . "&L_PAYMENTREQUEST_0_QTY{$k}=" . urlencode($product->qty); $total += $product->qty * $product->price; } $data .= "&PAYMENTREQUEST_0_AMT=" . urlencode($total) . "&PAYMENTREQUEST_0_ITEMAMT=" . urlencode($total); // send the request to PayPal $response = self::sendNvpRequest('SetExpressCheckout', $data); //Respond according to message we receive from Paypal if ("SUCCESS" == strtoupper($response["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($response["ACK"])) { $_SESSION['bookly'][$form_id]['paypal_response'] = array($response, $form_id); $paypalurl = 'https://www' . get_option('ab_paypal_ec_mode') . '.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=' . urldecode($response["TOKEN"]); header('Location: ' . $paypalurl); exit; } else { header('Location: ' . wp_sanitize_redirect(add_query_arg(array('action' => 'ab-paypal-errorurl', 'ab_fid' => $form_id, 'error_msg' => $response["L_LONGMESSAGE0"]), AB_Utils::getCurrentPageURL()))); exit; } }
/** * Do replacements. * * @param $text * @param string $type * * @return string */ public function replace($text, $type = 'email') { // Company logo as <img> tag. $company_logo = ''; if (get_option('ab_settings_company_logo_url') != '') { $company_logo = sprintf('<img src="%s" alt="%s" />', esc_attr(get_option('ab_settings_company_logo_url')), esc_attr(get_option('ab_settings_company_name'))); } // Staff photo as <img> tag. $staff_photo = ''; if ($this->data['staff_photo'] != '') { $staff_photo = sprintf('<img src="%s" alt="%s" />', esc_attr($this->get('staff_photo')), esc_attr($this->get('staff_name'))); } // Cancel appointment URL and <a> tag. $cancel_appointment_url = admin_url('admin-ajax.php') . '?action=ab_cancel_appointment&token=' . $this->get('appointment_token'); $cancel_appointment = sprintf('<a href="%1$s">%1$s</a>', $cancel_appointment_url); // Codes. $codes = array('[[APPOINTMENT_TIME]]' => AB_DateTimeUtils::formatTime($this->get('appointment_datetime')), '[[APPOINTMENT_DATE]]' => AB_DateTimeUtils::formatDate($this->get('appointment_datetime')), '[[CUSTOM_FIELDS]]' => $this->get('custom_fields'), '[[CUSTOM_FIELDS_2C]]' => $this->get('custom_fields_2c'), '[[CLIENT_NAME]]' => $this->get('client_name'), '[[CLIENT_PHONE]]' => $this->get('client_phone'), '[[CLIENT_EMAIL]]' => $this->get('client_email'), '[[SERVICE_NAME]]' => $this->get('service_name'), '[[SERVICE_PRICE]]' => AB_Utils::formatPrice($this->get('service_price')), '[[STAFF_EMAIL]]' => $this->get('staff_email'), '[[STAFF_NAME]]' => $this->get('staff_name'), '[[STAFF_PHONE]]' => $this->get('staff_phone'), '[[STAFF_PHOTO]]' => $staff_photo, '[[CANCEL_APPOINTMENT]]' => $cancel_appointment, '[[CANCEL_APPOINTMENT_URL]]' => $cancel_appointment_url, '[[CATEGORY_NAME]]' => $this->get('category_name'), '[[COMPANY_ADDRESS]]' => $type == 'email' ? nl2br(get_option('ab_settings_company_address')) : get_option('ab_settings_company_address'), '[[COMPANY_LOGO]]' => $company_logo, '[[COMPANY_NAME]]' => get_option('ab_settings_company_name'), '[[COMPANY_PHONE]]' => get_option('ab_settings_company_phone'), '[[COMPANY_WEBSITE]]' => get_option('ab_settings_company_website'), '[[NEXT_DAY_AGENDA]]' => $this->get('next_day_agenda'), '[[TOMORROW_DATE]]' => date_i18n(get_option('date_format'), strtotime($this->get('appointment_datetime'))), '[[TOTAL_PRICE]]' => AB_Utils::formatPrice($this->get('service_price') * $this->get('number_of_persons')), '[[NUMBER_OF_PERSONS]]' => $this->get('number_of_persons'), '[[SITE_ADDRESS]]' => $this->get('site_address'), '[[NEW_USERNAME]]' => $this->get('new_username'), '[[NEW_PASSWORD]]' => $this->get('new_password')); return strtr($text, $codes); }
/** * Get list of customers. */ public function executeGetCustomers() { $wpdb = $this->getWpdb(); $response = array('customers' => array(), 'total' => 0, 'pages' => 0, 'active_page' => 0); $page = intval($this->getParameter('page')); $sort = in_array($this->getParameter('sort'), array('name', 'phone', 'email', 'notes', 'last_appointment', 'total_appointments', 'payments', 'wp_user')) ? $this->getParameter('sort') : 'name'; $order = in_array($this->getParameter('order'), array('asc', 'desc')) ? $this->getParameter('order') : 'asc'; $filter = $wpdb->_real_escape($this->getParameter('filter')); $items_per_page = 20; $total = AB_Customer::query()->count(); $pages = ceil($total / $items_per_page); if ($page < 1 || $page > $pages) { $page = 1; } if ($total) { $query = AB_Customer::query('c')->select('c.*, MAX(a.start_date) AS last_appointment, COUNT(a.id) AS total_appointments, COALESCE(SUM(p.total),0) AS payments, wpu.display_name AS wp_user')->leftJoin('AB_CustomerAppointment', 'ca', 'ca.customer_id = c.id')->leftJoin('AB_Appointment', 'a', 'a.id = ca.appointment_id')->leftJoin('AB_Payment', 'p', 'p.customer_appointment_id = ca.id')->tableJoin($wpdb->users, 'wpu', 'wpu.ID = c.wp_user_id'); // WHERE if ($filter !== '') { $query->whereLike('c.name', "%{$filter}%")->whereLike('c.phone', "%{$filter}%", 'OR')->whereLike('c.email', "%{$filter}%", 'OR'); } $data = $query->groupBy('c.id')->sortBy($sort)->order($order)->limit($items_per_page)->offset(($page - 1) * $items_per_page)->fetchArray(); array_walk($data, function (&$row) { if ($row['last_appointment']) { $row['last_appointment'] = AB_DateTimeUtils::formatDateTime($row['last_appointment']); } $row['payments'] = AB_Utils::formatPrice($row['payments']); }); // Populate response. $response['customers'] = $data; $response['total'] = $total; $response['pages'] = $pages; $response['active_page'] = $page; } wp_send_json_success($response); }
/** * 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; } } }
<li class="ab-step-tabs<?php if ($booking_step >= 4) { ?> active<?php } ?> "> <a href="javascript:void(0)">4. <?php echo AB_Utils::getTranslatedOption('ab_appearance_text_step_payment'); ?> </a> <div class=step></div> </li> <li class="ab-step-tabs<?php if ($booking_step >= 5) { ?> active<?php } ?> ab-last"> <a href="javascript:void(0)">5. <?php echo AB_Utils::getTranslatedOption('ab_appearance_text_step_done'); ?> </a> <div class=step></div> </li> <?php } ?> </ul> </div>
_e('Title', 'bookly'); ?> </th> <th width="80"><?php _e('Duration', 'bookly'); ?> </th> <th width="80"><?php _e('Price', 'bookly'); ?> </th> <th width="140"><?php _e('Capacity', 'bookly'); ?> <?php AB_Utils::popover(__('The maximum number of customers allowed to book the service for the certain time period.', 'bookly'), 'width:16px;margin-left:0;'); ?> <th><?php _e('Staff', 'bookly'); ?> </th> <th><?php _e('Category', 'bookly'); ?> </th> <th class="last"> </th> </tr> </thead> <tbody> <?php foreach ($service_collection as $i => $service) {
</td> <td> <?php echo $form->renderField('ab_settings_' . $day); ?> <span> <?php _e('to', 'bookly'); ?> </span> <?php echo $form->renderField('ab_settings_' . $day, false); ?> </td> </tr> <?php } ?> </tbody> <tr> <td></td> <td> <?php AB_Utils::submitButton(); ?> <?php AB_Utils::resetButton('ab-hours-reset'); ?> </td> </tr> </table> </form>
<div class="ab-payment-nav"> <div style="margin-bottom: 15px!important;" class="ab-row-fluid"><?php _e($info_text, 'bookly'); ?> </div> <?php if ($_local) { ?> <div class="ab-row-fluid ab-list"> <label> <input type="radio" class="ab-local-payment" checked="checked" name="payment-method-<?php echo $form_id; ?> " value="local"/> <?php echo AB_Utils::getTranslatedOption('ab_appearance_text_label_pay_locally'); ?> </label> </div> <?php } ?> <?php if ($_paypal) { ?> <div class="ab-row-fluid ab-list"> <label> <input type="radio" class="ab-paypal-payment" <?php checked(!$_local); ?>
"<?php selected($userData->get('time_from') == $key); ?> ><?php echo $time; ?> </option> <?php } ?> </select> </div> </div> <div class="ab-left ab-time-to"> <label class="ab-bold"><?php echo AB_Utils::getTranslatedOption('ab_appearance_text_label_finish_by'); ?> </label> <div> <select class="ab-select-time-to"> <?php foreach ($time_list as $key => $time) { ?> <option value="<?php echo $key; ?> "<?php selected($userData->get('time_to') == $key); ?> ><?php echo $time;
_e('Please add your staff members.', 'bookly'); ?> </li> <li><?php _e('Add services and assign them to the staff members you created earlier.', 'bookly'); ?> </li> </ol> <hr> <a class="btn btn-info" href="<?php echo AB_Utils::escAdminUrl(AB_StaffController::page_slug); ?> "><?php _e('Add Staff Members', 'bookly'); ?> </a> <a class="btn btn-info" href="<?php echo AB_Utils::escAdminUrl(AB_ServiceController::page_slug); ?> "><?php _e('Add Services', 'bookly'); ?> </a> <?php } ?> </div> </div> </div>
/** * 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; }
width="1" height="1"> </form> <form class="ab-inline-block ab-ctext" action="<?php echo esc_url($action); ?> " method="post"> <input type="hidden" name="item_name" value="Bookly SMS"> <input type="hidden" name="currency_code" value="USD"> <input type="hidden" name="amount" value="100"> <input type="hidden" name="return" value="<?php echo AB_Utils::escAdminUrl(AB_SmsController::page_slug, array('paypal_result' => 'success')); ?> "> <input type="hidden" name="cancel_return" value="<?php echo AB_Utils::escAdminUrl(AB_SmsController::page_slug, array('paypal_result' => 'cancel')); ?> "> <input type="hidden" name="cmd" value="_xclick"> <input type="hidden" name="business" value="<?php echo esc_attr($business); ?> "> <input type="hidden" name="custom" value="<?php echo esc_attr($sms->getUserName()); ?> "> <input type="hidden" name="no_shipping" value="1"> <input type="hidden" name="handling" value="4.92"> <input type="image" src="<?php
<td class="ab-column-date"><?php echo AB_DateTimeUtils::formatDate($a['start_date']); ?> </td><?php break; case 'time': ?> <td class="ab-column-time"><?php echo AB_DateTimeUtils::formatTime($a['start_date']); ?> </td><?php break; case 'price': ?> <td class="ab-column-price"><?php echo AB_Utils::formatPrice($a['price']); ?> </td><?php break; case 'cancel': ?> <td class="ab-column-cancel"> <?php if ($a['start_date'] > current_time('mysql')) { ?> <a class="ab-btn orange" href="<?php echo esc_attr(admin_url('admin-ajax.php') . '?action=ab_cancel_appointment&token=' . $a['token']); ?> "> <span class="ab_label"><?php _e('Cancel', 'bookly');
/** * 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); }
/** * 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; }
/** * Show admin notice about purchase code and license. */ public function showAdminNotice() { if (AB_Utils::isCurrentUserAdmin() && !get_user_meta(get_current_user_id(), 'ab_dismiss_admin_notice', true) && get_option('ab_envato_purchase_code') == '' && time() > get_option('ab_installation_time') + 604800) { $this->render('admin_notice'); } }
/** * Process the Express Checkout RETURNURL */ public function paypalResponseSuccess() { $form_id = $_GET['ab_fid']; $paypal = new AB_PayPal(); if (isset($_GET["token"]) && isset($_GET["PayerID"])) { $token = $_GET["token"]; $payer_id = $_GET["PayerID"]; // send the request to PayPal $response = $paypal->sendNvpRequest('GetExpressCheckoutDetails', sprintf('&TOKEN=%s', $token)); if (strtoupper($response["ACK"]) == "SUCCESS") { $data = sprintf('&TOKEN=%s&PAYERID=%s&PAYMENTREQUEST_0_PAYMENTACTION=Sale', $token, $payer_id); // response keys containing useful data to send via DoExpressCheckoutPayment operation $response_data_keys_pattern = sprintf('/^(%s)/', implode('|', array('PAYMENTREQUEST_0_AMT', 'PAYMENTREQUEST_0_ITEMAMT', 'PAYMENTREQUEST_0_CURRENCYCODE', 'L_PAYMENTREQUEST_0'))); foreach ($response as $key => $value) { // collect product data from response using defined response keys if (preg_match($response_data_keys_pattern, $key)) { $data .= sprintf('&%s=%s', $key, $value); } } //We need to execute the "DoExpressCheckoutPayment" at this point to Receive payment from user. $response = $paypal->sendNvpRequest('DoExpressCheckoutPayment', $data); if ("SUCCESS" == strtoupper($response["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($response["ACK"])) { // get transaction info $response = $paypal->sendNvpRequest('GetTransactionDetails', "&TRANSACTIONID=" . urlencode($response["PAYMENTINFO_0_TRANSACTIONID"])); if ("SUCCESS" == strtoupper($response["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($response["ACK"])) { // need session to get Total and Token $token = $_SESSION['bookly'][$form_id]['paypal_response'][0]['TOKEN']; $userData = new AB_UserBookingData($form_id); $userData->load(); if ($userData->get('service_id')) { $appointment = $userData->save(); $customer_appointment = new AB_CustomerAppointment(); $customer_appointment->loadBy(array('appointment_id' => $appointment->get('id'), 'customer_id' => $userData->getCustomerId())); $payment = new AB_Payment(); $payment->set('token', urldecode($token)); $payment->set('total', $userData->getFinalServicePrice() * $userData->get('number_of_persons')); $payment->set('customer_appointment_id', $customer_appointment->get('id')); $payment->set('transaction', urlencode($response["TRANSACTIONID"])); $payment->set('created', current_time('mysql')); $payment->save(); $userData->setPayPalStatus('success'); } @wp_redirect(remove_query_arg(array('action', 'token', 'PayerID', 'ab_fid'), AB_Utils::getCurrentPageURL())); exit(0); } else { header('Location: ' . wp_sanitize_redirect(add_query_arg(array('action' => 'ab-paypal-errorurl', 'ab_fid' => $form_id, 'error_msg' => $response["L_LONGMESSAGE0"]), AB_Utils::getCurrentPageURL()))); exit; } } else { header('Location: ' . wp_sanitize_redirect(add_query_arg(array('action' => 'ab-paypal-errorurl', 'ab_fid' => $form_id, 'error_msg' => $response["L_LONGMESSAGE0"]), AB_Utils::getCurrentPageURL()))); exit; } } else { header('Location: ' . wp_sanitize_redirect(add_query_arg(array('action' => 'ab-paypal-errorurl', 'ab_fid' => $form_id, 'error_msg' => 'Invalid token provided'), AB_Utils::getCurrentPageURL()))); exit; } } else { throw new Exception('Token parameter not found!'); } }
/** * Send email to $mail_to. * * @param AB_Notification $notification * @param AB_NotificationCodes $codes * @param string $mail_to * @param string $phone * @return bool */ private static function _send(AB_Notification $notification, AB_NotificationCodes $codes, $mail_to, $phone = '') { $result = false; if ($notification->get('gateway') == 'email') { $message = $codes->replace($notification->get('message')); // Send email to recipient. $subject = $codes->replace($notification->get('subject')); $result = wp_mail($mail_to, $subject, wpautop($message), AB_Utils::getEmailHeaders()); // Send copy to administrators. if ($notification->get('copy')) { $admin_emails = AB_Utils::getAdminEmails(); if (!empty($admin_emails)) { wp_mail($admin_emails, $subject, wpautop($message), AB_Utils::getEmailHeaders()); } } } elseif ($notification->get('gateway') == 'sms') { $message = $codes->replace($notification->get('message'), 'sms'); if (self::$sms_authorized === null) { self::$sms = new AB_SMS(); self::$sms_authorized = self::$sms->loadProfile(); } if (self::$sms_authorized) { if ($phone != '') { $result = self::$sms->sendSms($phone, $message); } if ($notification->get('copy')) { if ($administrator_phone = get_option('ab_sms_administrator_phone', '') != '') { self::$sms->sendSms($administrator_phone, $message); } } } } return $result; }
<a class="ab-popup-close ab-popup-close-icon" href="javascript:void(0)"></a> </div> </div> </div> </td> <td class="breaks"> <?php include '_breaks.php'; ?> </td> </tr> <?php } ?> <tr class="staff-schedule-item-row ab-last-row"> <td></td> <td colspan="3"> <input type="hidden" name="action" value="ab_staff_schedule_update"/> <?php AB_Utils::submitButton('ajax-send-staff-schedule'); ?> <?php AB_Utils::resetButton('ab-schedule-reset'); ?> </td> </tr> </tbody> </table> </div> </form> </div>
/** * Render info text into a variable. * * @param string $text * @param AB_UserBookingData $userData * @param int $preset_price * * @return string */ private function _prepareInfoText($text, $userData, $preset_price = null) { if (empty($this->replacement)) { $service = $userData->getService(); $category_name = $service->getCategoryName(); $staff_name = $userData->getStaffName(); $price = $preset_price === null ? $userData->getServicePrice() : $preset_price; $number_of_persons = $userData->get('number_of_persons'); $service_date = AB_DateTimeUtils::formatDate($userData->get('appointment_datetime')); if (get_option('ab_settings_use_client_time_zone')) { $service_time = AB_DateTimeUtils::formatTime(AB_DateTimeUtils::applyTimeZoneOffset($userData->get('appointment_datetime'), $userData->get('time_zone_offset'))); } else { $service_time = AB_DateTimeUtils::formatTime($userData->get('appointment_datetime')); } $this->replacement = array('[[STAFF_NAME]]' => '<b>' . $staff_name . '</b>', '[[SERVICE_NAME]]' => '<b>' . $service->get('title') . '</b>', '[[CATEGORY_NAME]]' => '<b>' . $category_name . '</b>', '[[NUMBER_OF_PERSONS]]' => '<b>' . $number_of_persons . '</b>', '[[SERVICE_TIME]]' => '<b>' . $service_time . '</b>', '[[SERVICE_DATE]]' => '<b>' . $service_date . '</b>', '[[SERVICE_PRICE]]' => '<b>' . AB_Utils::formatPrice($price) . '</b>', '[[TOTAL_PRICE]]' => '<b>' . AB_Utils::formatPrice($price * $number_of_persons) . '</b>', '[[LOGIN_FORM]]' => get_current_user_id() == 0 ? $this->render('_login_form', array(), false) : ''); } return strtr(nl2br($text), $this->replacement); }
" /> <div class="ab-popup" style="display: none; margin-top: 10px;"> <div class="ab-arrow"></div> <div class="ab-content"> <form method="post" id="new-category-form"> <table class="form-horizontal"> <tr> <td> <input class="form-control ab-clear-text" style="width: 170px" type="text" name="name" /> <input type="hidden" name="action" value="ab_category_form" /> </td> </tr> <tr> <td> <?php AB_Utils::submitButton(); ?> <a class="ab-popup-close" href="#"><?php _e('Cancel', 'bookly'); ?> </a> </td> </tr> </table> <a class="ab-popup-close ab-popup-close-icon" href="#"></a> </form> </div> </div> </div> </div> <div class="ab-right-content col-md-9 col-sm-9 col-xs-12 col-lg-9" id="ab_services_wrapper">
<div class="ab-formGroup ab-left"> <label class="ab-formLabel"><?php echo AB_Utils::getTranslatedOption('ab_appearance_text_label_phone'); ?> </label> <div class="ab-formField"> <input class="ab-formElement ab-user-phone" maxlength="30" type="tel" value="<?php echo esc_attr($userData->get('phone')); ?> "/> </div> <div class="ab-user-phone-error ab-label-error ab-bold"></div> </div> <div class="ab-formGroup ab-left"> <label class="ab-formLabel"><?php echo AB_Utils::getTranslatedOption('ab_appearance_text_label_email'); ?> </label> <div class="ab-formField" style="margin-right: 0"> <input class="ab-formElement ab-user-email" maxlength="40" type="text" value="<?php echo esc_attr($userData->get('email')); ?> "/> </div> <div class="ab-user-email-error ab-label-error ab-bold"></div> </div> </div> <?php foreach ($custom_fields as $custom_field) { ?>
/** * Constructor */ public function __construct() { date_default_timezone_set(AB_Utils::getTimezoneString()); wp_load_translations_early(); $now = new DateTime(); $this->mysql_now = $now->format('Y-m-d H:i:s'); $this->sms = new AB_SMS(); $this->sms_authorized = $this->sms->loadProfile(); $query = AB_Notification::query()->where('active', 1)->whereIn('type', array('staff_agenda', 'client_follow_up', 'client_reminder')); foreach ($query->find() as $notification) { $this->processNotification($notification); } }
</td> <td><input id="ab_settings_company_phone" class="form-control" type="text" name="ab_settings_company_phone" value="<?php echo esc_attr(get_option('ab_settings_company_phone')); ?> " /></td> </tr> <tr> <td> <label for="ab_settings_company_website"><?php _e('Website', 'bookly'); ?> </label> </td> <td><input id="ab_settings_company_website" class="form-control" type="text" name="ab_settings_company_website" value="<?php echo esc_attr(get_option('ab_settings_company_website')); ?> " /></td> </tr> <tr> <td></td> <td> <?php AB_Utils::submitButton(); ?> <?php AB_Utils::resetButton('ab-settings-company-reset'); ?> </td> </tr> </table> </form>
"> </div> <div class="form-group"> <label for="new_password_repeat"><?php _e('Repeat new password', 'bookly'); ?> </label> <input type="password" class="form-control" id="new_password_repeat" placeholder="<?php echo esc_attr(__('Repeat new password', 'bookly')); ?> "> </div> </div> <div class="modal-footer"> <?php AB_Utils::submitButton('ajax-send-change-password'); ?> <button type="button" class="ab-reset-form" data-dismiss="modal"><?php _e('Cancel', 'bookly'); ?> </button> </div> <input type="hidden" name="action" value="ab_change_password"> </div> </div> </form> </div> <?php } else { ?>
?> </option> <?php } ?> </select> </td> </tr> <tr class="ab-stripe"> <td><label for="ab_stripe_secret_key"><?php _e('Secret Key', 'bookly'); ?> </label></td> <td><input id="ab_stripe_secret_key" class="form-control" type="text" size="33" name="ab_stripe_secret_key" value="<?php echo get_option('ab_stripe_secret_key'); ?> "/></td> </tr> <tr> <td colspan="2"> <?php AB_Utils::submitButton(); ?> <?php AB_Utils::resetButton('ab-payments-reset'); ?> </td> <td></td> </tr> </table> </form>
/** * Export Appointment to CSV */ public function executeExportToCSV() { $start_date = new DateTime($this->getParameter('date_start')); $start_date = $start_date->format('Y-m-d H:i:s'); $end_date = new DateTime($this->getParameter('date_end')); $end_date = $end_date->modify('+1 day')->format('Y-m-d H:i:s'); $delimiter = $this->getParameter('delimiter', ','); header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=Appointments.csv'); $header = array(__('Booking Time', 'bookly'), __('Staff Member', 'bookly'), __('Service', 'bookly'), __('Duration', 'bookly'), __('Price', 'bookly'), __('Customer', 'bookly'), __('Phone', 'bookly'), __('Email', 'bookly')); $custom_fields = array(); $fields_data = json_decode(get_option('ab_custom_fields')); foreach ($fields_data as $field_data) { $custom_fields[$field_data->id] = ''; $header[] = $field_data->label; } $output = fopen('php://output', 'w'); fwrite($output, pack("CCC", 0xef, 0xbb, 0xbf)); fputcsv($output, $header, $delimiter); $rows = AB_CustomerAppointment::query()->select('r.id, r.number_of_persons, r.coupon_discount, r.coupon_deduction, st.full_name AS staff_name, s.title AS service_title, s.duration AS service_duration, c.name AS customer_name, c.phone AS customer_phone, c.email AS customer_email, ss.price, a.start_date')->leftJoin('AB_Appointment', 'a', 'a.id = r.appointment_id')->leftJoin('AB_Service', 's', 's.id = a.service_id')->leftJoin('AB_Staff', 'st', 'st.id = a.staff_id')->leftJoin('AB_Customer', 'c', 'c.id = r.customer_id')->leftJoin('AB_StaffService', 'ss', 'ss.staff_id = st.id AND ss.service_id = s.id')->whereBetween('a.start_date', $start_date, $end_date)->sortBy('a.start_date')->order(AB_Query::ORDER_DESCENDING)->fetchArray(); foreach ($rows as $row) { 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']; $row_data = array($row['start_date'], $row['staff_name'], $row['service_title'], AB_Service::durationToString($row['service_duration']), AB_Utils::formatPrice($row['price']), $row['customer_name'], $row['customer_phone'], $row['customer_email']); $customer_appointment = new AB_CustomerAppointment(); $customer_appointment->load($row['id']); foreach ($customer_appointment->getCustomFields() as $custom_field) { $custom_fields[$custom_field['id']] = $custom_field['value']; } fputcsv($output, array_merge($row_data, $custom_fields), $delimiter); $custom_fields = array_map(function () { return ''; }, $custom_fields); } fclose($output); exit; }
</span>) <?php } else { ?> <?php _e('Profile', 'bookly'); ?> <?php } ?> </h3> </div> <div class="panel-body"> <div class="row"> <div id="ab-staff" class="ab-left-bar col-md-3 col-sm-3 col-xs-12 col-lg-3"<?php if (!AB_Utils::isCurrentUserAdmin()) { ?> style="display: none" <?php } ?> > <ul id="ab-staff-list"> <?php if ($staff_members) { ?> <?php foreach ($staff_members as $staff) { ?> <li class="ab-staff-member" id="ab-list-staff-<?php echo $staff['id']; ?>
default: include '_codes.php'; } ?> </tbody> </table> </div> </div> </div> </div> <?php } ?> <div class="ab-notifications"> <?php echo '<i>' . __('To send scheduled notifications please execute the following script hourly with your cron:', 'bookly') . '</i><br />'; echo '<b>php -f ' . realpath(AB_PATH . '/lib/utils/send_notifications_cron.php') . '</b>'; ?> </div> </div> <div class="panel-footer"> <?php AB_Utils::submitButton(); ?> <?php AB_Utils::resetButton(); ?> </div> </div> </form>
/** * Check if the current user has access to the action. * * Default access (if is not set with annotation for the controller or action) is "admin" * Access type: * "admin" - check if the current user is super admin * "user" - check if the current user is authenticated * "anonymous" - anonymous user * * @param string $action * @return bool */ protected function hasAccess($action) { $permissions = $this->getPermissions(); $security = isset($permissions[$action]) ? $permissions[$action] : null; if (is_null($security)) { // Check if controller class has permission $security = isset($permissions['_this']) ? $permissions['_this'] : null; if (is_null($security)) { $security = 'admin'; } } switch ($security) { case 'admin': return AB_Utils::isCurrentUserAdmin(); case 'user': return is_user_logged_in(); case 'anonymous': return true; } return false; }