/**
  * 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;
 }
 /**
  * @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;
 }
 /**
  * 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));
 }
 /**
  * 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);
 }