/** * Save all data and create appointment. * * @return AB_Appointment */ public function save() { $user_id = get_current_user_id(); $customer = new AB_Customer(); if ($user_id) { // Try to find customer by WP user ID. $customer->loadBy(array('wp_user_id' => $user_id)); } if (!$customer->isLoaded()) { // If customer with such name & e-mail exists, append new booking to him, otherwise - create new customer $customer->loadBy(array('name' => $this->get('name'), 'email' => $this->get('email'))); } $customer->set('name', $this->get('name')); $customer->set('email', $this->get('email')); $customer->set('phone', $this->get('phone')); if (get_option('ab_settings_create_account', 0) && !$customer->get('wp_user_id')) { // Create WP user and link it to customer. $customer->setWPUser($user_id ?: null); } $customer->save(); $this->customer_id = $customer->get('id'); $service = $this->getService(); /** * Get appointment, with same params. * If it is -> create connection to this appointment, * otherwise create appointment and connect customer to new appointment */ $appointment = new AB_Appointment(); $appointment->loadBy(array('staff_id' => $this->getStaffId(), 'service_id' => $this->get('service_id'), 'start_date' => $this->get('appointment_datetime'))); if ($appointment->isLoaded() == false) { $appointment->set('staff_id', $this->getStaffId()); $appointment->set('service_id', $this->get('service_id')); $appointment->set('start_date', $this->get('appointment_datetime')); $endDate = new DateTime($this->get('appointment_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_CustomerAppointment(); $customer_appointment->loadBy(array('customer_id' => $customer->get('id'), 'appointment_id' => $appointment->get('id'))); if ($customer_appointment->isLoaded()) { // Add number of persons to existing booking. $customer_appointment->set('number_of_persons', $customer_appointment->get('number_of_persons') + $this->get('number_of_persons')); } else { $customer_appointment->set('customer_id', $customer->get('id')); $customer_appointment->set('appointment_id', $appointment->get('id')); $customer_appointment->set('number_of_persons', $this->get('number_of_persons')); } $customer_appointment->set('custom_fields', $this->get('custom_fields')); $customer_appointment->set('time_zone_offset', $this->get('time_zone_offset')); $coupon = $this->getCoupon(); if ($coupon) { $customer_appointment->set('coupon_code', $coupon->get('code')); $customer_appointment->set('coupon_discount', $coupon->get('discount')); $customer_appointment->set('coupon_deduction', $coupon->get('deduction')); $coupon->claim(); $coupon->save(); } $customer_appointment->save(); // Create fake payment record for 100% discount coupons. if ($coupon && $coupon->get('discount') == '100') { $payment = new AB_Payment(); $payment->set('total', '0.00'); $payment->set('type', 'coupon'); $payment->set('created', current_time('mysql')); $payment->set('customer_appointment_id', $customer_appointment->get('id')); $payment->save(); } // Google Calendar. $appointment->handleGoogleCalendar(); // Send email notifications. AB_NotificationSender::send(AB_NotificationSender::INSTANT_NEW_APPOINTMENT, $customer_appointment); return $appointment; }
/** * 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); }
/** * 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; }
/** * @param AB_Appointment $appointment */ private function handleEventData(AB_Appointment $appointment) { $start_datetime = new Google_Service_Calendar_EventDateTime(); $start_datetime->setDateTime(DateTime::createFromFormat('Y-m-d H:i:s', $appointment->get('start_date'), new DateTimeZone(AB_Utils::getTimezoneString()))->format(DateTime::RFC3339)); $end_datetime = new Google_Service_Calendar_EventDateTime(); $end_datetime->setDateTime(DateTime::createFromFormat('Y-m-d H:i:s', $appointment->get('end_date'), new DateTimeZone(AB_Utils::getTimezoneString()))->format(DateTime::RFC3339)); $service = new AB_Service(); $service->load($appointment->get('service_id')); $description = __('Service', 'bookly') . ": " . $service->get('title') . PHP_EOL; $client_names = array(); foreach ($appointment->getCustomerAppointments() as $ca) { $description .= sprintf("%s: %s\n%s: %s\n%s: %s\n", __('Name', 'bookly'), $ca->customer->get('name'), __('Email', 'bookly'), $ca->customer->get('email'), __('Phone', 'bookly'), $ca->customer->get('phone')); $description .= $ca->getFormattedCustomFields('text'); $description .= PHP_EOL; $client_names[] = $ca->customer->get('name'); } $staff = new AB_Staff(); $staff->load($appointment->get('staff_id')); $title = strtr(get_option('ab_settings_google_event_title', '[[SERVICE_NAME]]'), array('[[SERVICE_NAME]]' => $service->get('title'), '[[CLIENT_NAMES]]' => implode(', ', $client_names), '[[STAFF_NAME]]' => $staff->get('full_name'))); $this->event->setStart($start_datetime); $this->event->setEnd($end_datetime); $this->event->setSummary($title); $this->event->setDescription($description); $extended_property = new Google_Service_Calendar_EventExtendedProperties(); $extended_property->setPrivate(array('customers' => json_encode(array_map(function ($ca) { return $ca->customer->get('id'); }, $appointment->getCustomerAppointments())), 'service_id' => $service->get('id'), 'appointment_id' => $appointment->get('id'))); $this->event->setExtendedProperties($extended_property); }
/** * Save appointment form (for both create and edit). */ public function executeSaveAppointmentForm() { $response = array('success' => false); $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'); $appointment_id = $this->getParameter('id', 0); $customers = json_decode($this->getParameter('customers', '[]'), true); $staff_service = new AB_StaffService(); $staff_service->loadBy(array('staff_id' => $staff_id, 'service_id' => $service_id)); // Check for errors. if (!$service_id) { $response['errors']['service_required'] = true; } if (empty($customers)) { $response['errors']['customers_required'] = true; } if (!$this->dateIntervalIsAvailableForAppointment($start_date, $end_date, $staff_id, $appointment_id)) { $response['errors']['date_interval_not_available'] = true; } $number_of_persons = 0; foreach ($customers as $customer) { $number_of_persons += $customer['number_of_persons']; } if ($number_of_persons > $staff_service->get('capacity')) { $response['errors']['overflow_capacity'] = __('The number of customers should be not more than ', 'bookly') . $staff_service->get('capacity'); } if (!$this->getParameter('start_date')) { $response['errors']['time_interval'] = __('Start time must not be empty', 'bookly'); } elseif (!$this->getParameter('end_date')) { $response['errors']['time_interval'] = __('End time must not be empty', 'bookly'); } elseif ($start_date == $end_date) { $response['errors']['time_interval'] = __('End time must not be equal to start time', 'bookly'); } // 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. $appointment->setCustomers($customers); // Google Calendar. $appointment->handleGoogleCalendar(); if ($this->getParameter('email_notification') === 'true') { foreach ($appointment->getCustomerAppointments() as $ca) { AB_NotificationSender::send(AB_NotificationSender::INSTANT_NEW_APPOINTMENT, $ca); } } $startDate = new DateTime($appointment->get('start_date')); $endDate = new DateTime($appointment->get('end_date')); $desc = array(); if ($staff_service->get('capacity') == 1) { $customer_appointments = $appointment->getCustomerAppointments(); if (!empty($customer_appointments)) { $ca = $customer_appointments[0]->customer; foreach (array('name', 'phone', 'email') as $data_entry) { $entry_value = $ca->get($data_entry); if ($entry_value) { $desc[] = '<div class="fc-employee">' . esc_html($entry_value) . '</div>'; } } foreach ($customer_appointments[0]->getCustomFields() as $custom_field) { $desc[] = '<div class="fc-notes">' . wp_strip_all_tags($custom_field['label']) . ': ' . esc_html($custom_field['value']) . '</div>'; } } } else { $signed_up = 0; foreach ($appointment->getCustomerAppointments() as $ca) { $signed_up += $ca->get('number_of_persons'); } $desc[] = '<div class="fc-notes">' . __('Signed up', 'bookly') . ' ' . $signed_up . '</div>'; $desc[] = '<div class="fc-notes">' . __('Capacity', 'bookly') . ' ' . $staff_service->get('capacity') . '</div>'; } $service = new AB_Service(); $service->load($service_id); $response['success'] = true; $response['data'] = array('id' => (int) $appointment->get('id'), 'start' => $startDate->format('Y-m-d H:i:s'), 'end' => $endDate->format('Y-m-d H:i:s'), 'desc' => implode('', $desc), 'title' => $service->get('title') ? $service->get('title') : __('Untitled', 'bookly'), 'color' => $service->get('color'), 'staffId' => $appointment->get('staff_id')); } else { $response['errors'] = array('db' => __('Could not save appointment in database.', 'bookly')); } } wp_send_json($response); }