loadAjaxActions(); } protected function loadAjaxActions() { $hooks = [ 'rr_get_restaurant_data', // Get initial data 'rr_get_month_available_dates', // Get available dates for a specific dates range //'rr_search_bookings', // Get slots bases on guests, date and time. OLD 'rr_get_service_slots', // Get slots based on shift/event selected 'rr_hold_booking', 'rr_hold_booking_with_table', // Usado para los custom layouts 'rr_hold_booking_remove', 'rr_get_fields', 'rr_get_booking_tags', 'rr_make_booking', // finally procceed with the booking 'rr_cancel_booking', // From view booking actions 'rr_confirm_booking', // From view booking user confirms 'rr_get_booking', // Used for the view booking front page 'rr_modify_booking', // Modify existing booking // Stripe payment 'rr_stripe_create', // Generate intent payment secretClient 'rr_stripe_payment_confirmed', 'rr_stripe_save_token', // para pre-autorizar un pago // ViewBooking 'rr_get_payment_details', // Get the payment details for a booking, amonunt, currenct 'rr_get_stripe_receipt', // Get the url of the receipt from the intent id 'rr_update_booking_status', // Email actions // For selecting areas and tables 'rr_get_floorplan', 'rr_get_floorplan_with_panoramas', // Redsys 'rr_redsys_create', // Generate request for redsys 'rr_redsys_fetch', // Get previos parameters for the booking view // Paypal 'rr_paypal_create', // Save payment request with result after the Paypal response 'rr_paypal_save_card', 'rr_paypal_pre_auth', 'rr_paypal_fetch', // BookingView. Get data to prepare the payment to pay pending Paypal // Mercadopago 'rr_mercadopago_create', // Create payment and generate Preference for mercado pago with the url to redirect 'rr_mercadopago_fetch', // Get url to redirect again // Mollie 'rr_mollie_create', // Generate the link for payment 'rr_mollie_fetch', // Viewbooking -> get the link to try payment // Square 'rr_square_create', 'rr_square_fetch', // Xendit 'rr_xendit_create', 'rr_xendit_webhook', 'rr_xendit_fetch', // Webhooks 'rr_webhook', // @TODO PENDING mercadopago // Voice API //'rr_api_get_options_for_date', // Tables with layouts 'rr_get_tables_layouts' ]; foreach ($hooks as $action){ $func = str_replace('rr_', '', $action); add_action( 'wp_ajax_'.$action, array($this, $func)); add_action( 'wp_ajax_nopriv_'.$action, array($this, $func)); } } /** * Wrapper for the wp verify nonce * * @param $restaurant_id * * @return false|int */ protected function verify_nonce($restaurant_id) { //ray('verify nonce ' . $restaurant_id); $nonce = sanitize_text_field( $_REQUEST['nonce'] ); return evavel_tenant_verify_nonce($nonce, $restaurant_id); } protected function getShowAlternativeDays($w_form) { $show_alternative_dates = isset($w_form->form_config['show_alternative_dates']) ? $w_form->form_config['show_alternative_dates'] : 'yes'; if (!in_array($show_alternative_dates, ['yes', 'no'])) { $show_alternative_dates = 'yes'; } return $show_alternative_dates; } /** * STEP 1 - Data needed for the first step * * @return void */ public function get_restaurant_data() { //ray('CALL get_restaurant_data'); $restaurant_id = sanitize_text_field($_REQUEST['restaurantId']); if ( ! $this->verify_nonce($restaurant_id) ) { wp_send_json_error(['error' => __eva('Cannot open the widget. Invalid nonce. Try to refresh the page.')]); } $widget_id = sanitize_text_field($_REQUEST['widgetId']); $restaurant = \Alexr\Models\Restaurant::where('active', 1)->where('id', $restaurant_id)->first(); if (!$restaurant) { wp_send_json_error(['error' => __eva('Restaurant is not available.')]); } // ++++ I need to remove HOLDED booking before calculating the slots available // Removed selected bookings with more than X minutes holded //alexr_remove_holded_bookings($restaurant_id); // This way does not generate default fields //$widget_form = \Alexr\Settings\WidgetForm::where('restaurant_id', $restaurant->id)->first(); //$form_config = $widget_form->form_config; //$form_fields = $widget_form->form_fields; // Check widget exists $widget_form = \Alexr\Settings\WidgetForm::where('id', $widget_id)->first(); if (!$widget_form) { wp_send_json_error(['error' => __eva('Form is not available.')]); } $show_services_dropdown = $widget_form->form_config['show_services_dropdown']; $show_services_dropdown = $show_services_dropdown == 'no' ? false : true; $show_services_duration = isset($widget_form->form_config['show_services_duration']) ? $widget_form->form_config['show_services_duration'] : 'yes'; $show_services_duration = $show_services_duration == 'no' ? false : true; $show_not_available_slots = isset($widget_form->form_config['show_not_available_slots']) ? $widget_form->form_config['show_not_available_slots'] : 'no'; $show_not_available_slots = $show_not_available_slots == 'no' ? false : true; $show_slots_mode = isset($widget_form->form_config['show_slots_mode']) ? $widget_form->form_config['show_slots_mode'] : 'buttons'; if (!in_array($show_slots_mode, ['buttons', 'dropdown'])) { $show_slots_mode = 'buttons'; } $show_alternative_dates = $this->getShowAlternativeDays($widget_form); // This generates default values if empty $items = \Alexr\Settings\WidgetForm::getItems(null, $restaurant_id, $widget_id); $form_config = $items['form_config']; $form_fields = $items['form_fields']; $guests_range = $restaurant->guestsMinMax($widget_id); if ($restaurant) { //$daysAvailable = ['2022-11-22', '2022-11-23', '2022-11-24']; //$daysAvailable = $restaurant->availableDates($widget_id); // Calcular tiempo $start_time = microtime(true); // Also filter available dates by closed days setting // false = no calcular slots available de los shifts que es muy lento // ESTOS DAYS AVAILABLE NO CALCULAN LOS SHIFTS PERO SIRVEN DE CARGA INICIAL // Luego ya desde el calendar se cargan los verdaderos days available teniendo en cuenta // los shifts time slots que sobreescriben a estos (get_month_available_dates()) $daysAvailableWithShifts = $restaurant->availableDates($widget_id, true, false); $daysAvailable = array_keys($daysAvailableWithShifts); //$endtime = microtime(true); //ray('TIME get_restaurant_data: ' . ($endtime - $start_time) . ' seconds'); wp_send_json_success([ 'restaurant' => $restaurant->toArray(), 'config' => [ 'guests_min' => $guests_range['min'], 'guests_max' => $guests_range['max'], 'time_slots' => $restaurant->timeSlotsBookable($widget_id), 'services' => $restaurant->getServices($widget_id), 'show_services_dropdown' => $show_services_dropdown, 'show_services_duration' => $show_services_duration, 'show_not_available_slots' => $show_not_available_slots, 'show_slots_mode' => $show_slots_mode, 'show_alternative_dates' => $show_alternative_dates, 'base_color' => $form_config['base_color'], 'text_color' => $form_config['text_color'], 'link_terms_of_service' => isset($form_config['link_terms_of_service']) ? $form_config['link_terms_of_service'] : '/', 'link_privacy_policy' => isset($form_config['link_privacy_policy']) ? $form_config['link_privacy_policy'] : '/', 'isBookable' => count($daysAvailable) > 0, 'daysAvailable' => $daysAvailable, 'daysAvailableWithShifts' => $daysAvailableWithShifts, // @TODO PENDING 'closedDates' => [], 'events' => $restaurant->getEventsToDisplayInCalendar($widget_id, $daysAvailable), 'header_text' => isset($form_config['header_text']) ? $form_config['header_text'] : '', 'language_default' => $form_config['language_default'], 'languages_allowed' => $form_config['languages_allowed'], 'date_formats' => alexr_config('app.date_formats'), 'webhook_url_1' => $form_config['webhook_url_1'], 'webhook_url_2' => $form_config['webhook_url_2'], 'webhook_url_3' => $form_config['webhook_url_3'] ] ]); } wp_send_json_error(['error' => __eva('Restaurant does not exists.')]); } public function get_month_available_dates(){ $restaurant_id = sanitize_text_field($_REQUEST['restaurantId']); if ( ! $this->verify_nonce($restaurant_id) ) { wp_send_json_error(['error' => __eva('Cannot open the widget. Invalid nonce. Try to refresh the page.')]); } $widget_id = sanitize_text_field($_REQUEST['widgetId']); $restaurant = \Alexr\Models\Restaurant::where('active', 1)->where('id', $restaurant_id)->first(); if (!$restaurant) { wp_send_json_error(['error' => __eva('Restaurant is not available.')]); } // Obtener el servicio seleccionado $service_id = isset($_REQUEST['serviceId']) ? sanitize_text_field($_REQUEST['serviceId']) : 'all'; $startDate = sanitize_text_field($_REQUEST['startDate']); $endDate = sanitize_text_field($_REQUEST['endDate']); $daysAvailableWithShifts = $restaurant->availableDates_StartEndDates($startDate, $endDate, $widget_id, $service_id, true, true); $daysAvailable = array_keys($daysAvailableWithShifts); wp_send_json_success([ 'daysAvailable' => $daysAvailable, 'daysAvailableWithShifts' => $daysAvailableWithShifts, ]); } /** * STEP 2 - Request allowed bookings * Search based on Guests, Date, Time * OLD WAY - now is showing all Shift slots available * @return void */ public function search_bookings() { // In case restaurant is not active or all hours are blocked //wp_send_json_error(['message' => 'No bookings are allowed at the moment.']); $restaurant_id = sanitize_text_field($_REQUEST['restaurantId']); // @TODO. pending nonce $widget_id = sanitize_text_field($_REQUEST['widgetId']); $restaurant = \Alexr\Models\Restaurant::where('active', 1)->where('id', $restaurant_id)->first(); if (!$restaurant) { wp_send_json_error(['message' => __eva('Restaurant is not active.')]); } $guests = intval($_REQUEST['guests']); $date = sanitize_text_field($_REQUEST['date']); $time = intval($_REQUEST['time']); $result = [ 'request' => [ 'tenant' => $restaurant_id, 'guests' => $guests, 'date' => $date, 'time' => $time ], 'resultDate' => [ 'date' => $date, 'slots' => $restaurant->getSlotsAvailable($guests, $date, $time, $widget_id), ], 'resultOtherDates' => $restaurant->getOtherDaysSlotsAvailable($guests, $date, $time, $widget_id), ]; wp_send_json_success($result); } /** * Get the fields for the booking form * * @return void */ public function get_fields() { $restaurant_id = sanitize_text_field($_REQUEST['restaurantId']); if ( ! $this->verify_nonce($restaurant_id) ) { wp_send_json_error(['error' => __eva('Could not get the fields.')]); } $widget_id = intval($_REQUEST['widgetId']); $service_id = intval($_REQUEST['serviceId']); $restaurant = \Alexr\Models\Restaurant::where('active', 1) ->where('id', $restaurant_id) ->first(); if (!$restaurant) { wp_send_json_error(['error' => 'Restaurant not found.']); } $controller = new \Alexr\Http\Controllers\SearchBookingsController(); $fields = $controller->fields(null, $restaurant->id, $widget_id, $service_id); wp_send_json_success($fields); } /** * Get the list of Booking Tags * * @return void */ public function get_booking_tags() { $restaurant_id = sanitize_text_field($_REQUEST['restaurantId']); if ( ! $this->verify_nonce($restaurant_id) ) { wp_send_json_error(['error' => __eva('Forbidden to remove the booking.')]); } $restaurant = \Alexr\Models\Restaurant::where('active', 1) ->where('id', $restaurant_id) ->first(); if (!$restaurant){ wp_send_json_error(['error' => 'Restaurant not found.']); } $tags = BTag::where('restaurant_id', $restaurant_id) ->orderBy('ordering', 'ASC') ->get(); $final_tags = []; foreach($tags as $tag) { $final_tags[] = $tag->toArray(); } $groups = BTagGroup::where('restaurant_id', $restaurant->id) ->orderBy('ordering', 'ASC') ->get(); $final_groups = []; foreach($groups as $group) { $final_groups[] = $group->toArray(); } wp_send_json_success([ 'groups' => $final_groups, 'tags' => $final_tags ]); } function attachAreaTableSelected($booking, $service, $date, $time, $party) { $area_selected_id = intval($_REQUEST['area_selected_id']); $table_selected_id = intval($_REQUEST['table_selected_id']); $combination_selected_id = intval($_REQUEST['combination_selected_id']); // Set selected area if ($area_selected_id > 0) { $booking->area_selected_id = $area_selected_id; } else { $booking->area_selected_id = null; } // Handle single table selection if ($table_selected_id > 0) { $booking->table_selected_id = $table_selected_id; // Attach table to the booking if it's free if ($service->isTableFreeForGuests($date, $time, $party, $table_selected_id)) { $booking->tables()->sync([$table_selected_id]); } } else { $booking->table_selected_id = null; } // Handle combination selection if ($combination_selected_id > 0) { // Get all available combinations $allAvailableTables = $service->getAllAvailableTables($date, $time, $party); // Find the selected combination $selectedCombination = null; if ($allAvailableTables && isset($allAvailableTables['combinations'])) { foreach ($allAvailableTables['combinations'] as $combination) { if ($combination['id'] == $combination_selected_id) { $selectedCombination = $combination; break; } } } // If combination found and has tables, sync them to the booking if ($selectedCombination && isset($selectedCombination['tables'])) { $tableIds = array_map(function($table) { return $table['id']; }, $selectedCombination['tables']); $booking->tables()->sync($tableIds); } } // If no table or combination selected but area selected, try to find available tables in that area else if (in_array($service->availability_type, ['tables', 'specific_tables']) && $booking->area_selected_id != null && $booking->table_selected_id == null && !$combination_selected_id) { $singleTablesRequireToBeOnlineForGroup = false; $tables_assigned = $service->isAvailableBy_SearchTables( $date, $time, $party, $singleTablesRequireToBeOnlineForGroup, $booking->area_selected_id ); if (!empty($tables_assigned)) { $list_ids = array_map(function($table) { return $table['id']; }, $tables_assigned); $booking->tables()->sync($list_ids); } } } function sendBookingNotifications($booking, $lang = false, $skip_admin_notifications = false, $is_modify_booking = false, $original_details = []) { if (!$lang){ $lang = isset($_REQUEST['lang']) ? sanitize_text_field($_REQUEST['lang']) : 'en'; } if ($booking->status == BookingStatus::PENDING) { // Envia dos emails, el de la modification y el de pending if ($is_modify_booking) { $booking->sendEmailModified($lang); } $booking->sendEmailPending($lang); if (!$skip_admin_notifications) { if ($is_modify_booking) { $booking->sendEmailAdminModified(); } else { $booking->sendEmailAdminPending(); } } // Widget message pending $message = $booking->messagePending($lang); // Para el restaurante $booking->sendSmsPendingAdmin(null); if ($booking->agree_receive_sms == 1) { $booking->sendSmsPending($lang); } } else if ($booking->status == BookingStatus::BOOKED) { // Envia el de la modification y el de la confirmacion if ($is_modify_booking) { $booking->sendEmailModified($lang); } $booking->sendEmailBooked($lang); if (!$skip_admin_notifications) { if ($is_modify_booking) { $booking->sendEmailAdminModified(); } else { $booking->sendEmailAdminBooked(); } } // Widget message booked $message = $booking->messageBooked($lang); // Para el restaurante $booking->sendSmsBookedAdmin(null); if ($booking->agree_receive_sms == 1) { $booking->sendSmsBooked($lang); } } // This is used only when the admin change the status from the front view // so the message returned is not displayed anywhere // Tambien puede ser que se haya denegado la reserva al cliente else if ($booking->status == BookingStatus::DENIED) { $booking->sendEmailDenied($lang); $message = $booking->messageDenied($lang); if ($booking->agree_receive_sms == 1) { $booking->sendSmsDenied($lang); } } // Dashboard notification if ($booking->restaurant) { if ($is_modify_booking) { $booking->restaurant->notify(new \Alexr\Notifications\BookingModifiedReceived($booking, $original_details)); } else { $booking->restaurant->notify(new \Alexr\Notifications\BookingOnlineReceived($booking)); } } return $message; } function isBookingDuplicated() { // Check widget exists $widget_id = intval($_REQUEST['widgetId']); $serviceId = intval($_REQUEST['serviceId']); $w_form = \Alexr\Settings\WidgetForm::where('id', $widget_id)->first(); if (!$w_form) return false; // Check if option is enabled $prevent_duplicate_bookings = $w_form->form_config['prevent_duplicate_bookings']; if ($prevent_duplicate_bookings == 'no') return false; $email = sanitize_text_field($_REQUEST['email']); $widget_id = intval($_REQUEST['widgetId']); $date = sanitize_text_field($_REQUEST['dateSelected']); // Find any booking that belongs to this widget with same email and date and shift // permite diferentes formularios $booking = \Alexr\Models\Booking::where('email', $email) ->where('date', $date) //->where('widget_id', $widget_id) ->where('shift_event_id', $serviceId) ->where('status', '!=', BookingStatus::CANCELLED) ->where('status', '!=', BookingStatus::DELETED) ->where('status', '!=', BookingStatus::DENIED) ->first(); if ($booking) { return true; } return false; } /** * Cancel a booking * Can be called from 2 places: * 1. From the last step of the Widget form where the user can decide to cancel (mode == widget-form) * 2. From the view booking page that can be accessed from the email link sent to the user (mode == view-booking) * * @return void */ function cancel_booking() { //ray('USER CANCELLED BOOKING', $_REQUEST); $restaurant_id = intval($_REQUEST['restaurantId']); $booking_uuid = sanitize_text_field($_REQUEST['uuid']); if (!$booking_uuid) { wp_send_json_error(['error' => __eva('Booking not found. Cannot be cancelled.')]); } // Verify nonce depends on the mode $mode = sanitize_text_field($_REQUEST['mode']); if (!$mode){ wp_send_json_error(['error' => __eva('Mode not defined.')]); } if ($mode == 'widget-form'){ if ( ! $this->verify_nonce($restaurant_id) ) { wp_send_json_error(['error' => __eva('Cannot cancel the booking.')]); } } else if ($mode == 'view-booking') { $nonce = sanitize_text_field($_REQUEST['nonce']); if (!evavel_verify_nonce($nonce, 'booking-'.$booking_uuid)) { wp_send_json_error(['error' => __eva('Invalid booking.')]); } } else { wp_send_json_error(['error' => __eva('Mode is not valid.')]); } // Check booking exists $booking = \Alexr\Models\Booking::where('uuid', $booking_uuid)->where('status', '!=', BookingStatus::DELETED) ->first(); if (!$booking){ wp_send_json_error(['error' => __eva('Booking not found. Cannot be cancelled.')]); } $old_status = $booking->status; $booking->status = BookingStatus::CANCELLED; if (isset($_REQUEST['cancelReason'])) { $booking->cancelReason = sanitize_text_field($_REQUEST['cancelReason']); } $booking->save(); evavel_event(new \Alexr\Events\EventBookingStatusChangedByCustomer($booking, $old_status, BookingStatus::CANCELLED)); $lang = 'en'; if (isset($_REQUEST['lang'])){ $lang = sanitize_text_field($_REQUEST['lang']); } // Send email $booking->sendEmailCancelled($lang); $booking->sendEmailAdminCancelled(); // Notificar al cliente $booking->restaurant->notify(new \Alexr\Notifications\BookingCancelledByUser($booking)); wp_send_json_success(); } function confirm_booking() { $restaurant_id = intval($_REQUEST['restaurantId']); $booking_uuid = sanitize_text_field($_REQUEST['uuid']); if (!$booking_uuid) { wp_send_json_error(['error' => __eva('Booking not found. Cannot be confirmed.')]); } // Verify nonce depends on the mode $mode = sanitize_text_field($_REQUEST['mode']); if (!$mode){ wp_send_json_error(['error' => __eva('Mode not defined.')]); } if ($mode == 'widget-form'){ if ( ! $this->verify_nonce($restaurant_id) ) { wp_send_json_error(['error' => __eva('Cannot confirm the booking.')]); } } else if ($mode == 'view-booking') { $nonce = sanitize_text_field($_REQUEST['nonce']); if (!evavel_verify_nonce($nonce, 'booking-'.$booking_uuid)) { wp_send_json_error(['error' => __eva('Invalid booking.')]); } } else { wp_send_json_error(['error' => __eva('Mode is not valid.')]); } // Check booking exists $booking = \Alexr\Models\Booking::where('uuid', $booking_uuid) ->where('status', BookingStatus::BOOKED) ->first(); if (!$booking){ wp_send_json_error(['error' => __eva('Booking not found. Cannot be confirmed.')]); } $old_status = $booking->status; $booking->status = BookingStatus::CONFIRMED; $booking->save(); evavel_event(new \Alexr\Events\EventBookingStatusChangedByCustomer($booking, $old_status, BookingStatus::CONFIRMED)); $lang = 'en'; if (isset($_REQUEST['lang'])){ $lang = sanitize_text_field($_REQUEST['lang']); } $booking->sendEmailConfirmed($lang); $booking->sendEmailAdminConfirmed(); $booking->restaurant->notify(new \Alexr\Notifications\BookingConfirmedByUser($booking)); wp_send_json_success(); } function get_booking() { $restaurant_id = sanitize_text_field($_REQUEST['restaurantId']); $nonce = sanitize_text_field($_REQUEST['nonce']); $uuid = sanitize_text_field($_REQUEST['uuid']); if (!evavel_verify_nonce($nonce, 'booking-'.$uuid)) { wp_send_json_error(['error' => __eva('Invalid booking.')]); } $booking = \Alexr\Models\Booking::where('uuid', $uuid)->where('status', '!=', BookingStatus::DELETED)->first(); if (!$booking) { wp_send_json_error(['error' => __eva('Invalid booking.')]); } wp_send_json_success([ 'booking' => \Alexr\Models\Booking::toDataArray($booking), ]); } function modify_booking() { return $this->make_booking(true); } /** * Update booking data * * @param $booking * * @return void */ protected function updateBookingValuesFromRequest($booking) { //ray($_REQUEST); $first_name = isset($_REQUEST['first_name']) ? sanitize_text_field($_REQUEST['first_name']) : 'Guest'; $last_name = isset($_REQUEST['last_name']) ? sanitize_text_field($_REQUEST['last_name']) : ''; $booking->first_name = $first_name; $booking->last_name = $last_name; $booking->email = sanitize_text_field($_REQUEST['email']); // First save point $booking->save(); if (isset($_REQUEST['source'])) { $source = sanitize_text_field($_REQUEST['source']); if (!empty($source)) { $booking->source = $source; } } if (isset($_REQUEST['phone'])) { $phone = sanitize_text_field($_REQUEST['phone']); if (!empty($phone)) { $booking->phone = $phone; } } if (isset($_REQUEST['dial_code_country'])) { $dial_code_country = sanitize_text_field($_REQUEST['dial_code_country']); if (!empty($dial_code_country)) { $booking->dial_code_country = $dial_code_country; } } if (isset($_REQUEST['dial_code'])) { $dial_code = sanitize_text_field($_REQUEST['dial_code']); if (!empty($dial_code)) { $booking->dial_code = $dial_code; } } if (isset($_REQUEST['country_code'])) { $country_code = sanitize_text_field($_REQUEST['country_code']); if (!empty($country_code)) { $booking->country_code = $country_code; } } if (isset($_REQUEST['birthday'])) { $birthday = sanitize_text_field($_REQUEST['birthday']); if (!empty($birthday)) { $booking->birthday = $birthday; } } if (isset($_REQUEST['notes'])) { $notes = sanitize_text_field($_REQUEST['notes']); if (!empty($notes)) { $booking->notes = $notes; } } // Language $booking->language = 'en'; if (isset($_REQUEST['lang'])){ $lang = sanitize_text_field($_REQUEST['lang']); $booking->language = $lang; } // Gateway if (isset($_REQUEST['gateway'])){ $gateway = sanitize_text_field($_REQUEST['gateway']); $booking->gateway = $gateway; } // Receive email always true $booking->agree_receive_email = 1; // Receive sms has to be enabled $booking->agree_receive_sms = 1; if (isset($_REQUEST['agree_sms'])) { $agree_sms = sanitize_text_field($_REQUEST['agree_sms']); if ($agree_sms == 'true') { $booking->agree_receive_sms = 1; } else { $booking->agree_receive_sms = 0; } } // Second save point $booking->save(); // Tags if (isset($_REQUEST['tags'])) { $tags = sanitize_text_field($_REQUEST['tags']); $tags = str_replace(['[',']'], '', $tags); if ($tags != null && $tags != 'null' && $tags != '') { $tags = explode(',', $tags); if (!empty($tags)) { $booking->tags()->sync($tags); } } } // Custom fields // Save the field component so can be changed later if needed $widget_id = $booking->widget_id; $restaurant_id = $booking->restaurant_id; $controller = new \Alexr\Http\Controllers\SearchBookingsController(); $fields = $controller->fields(null, $restaurant_id, $widget_id, $booking->shift_event_id); $custom_fields = []; foreach($_REQUEST as $key => $value) { if (preg_match('#custom_#', $key)) { $the_field = null; foreach ( $fields as $field ) { if ($field['attribute'] == $key) { $the_field = $field; } } // Transform checkbox if ($the_field['type'] == 'checkbox'){ $value = $value == 'true' ? true : false; } // Options else if ($the_field['type'] == 'options'){ $value = str_replace('\"', '"', $value); $value = json_decode($value, true); } else if ($the_field['type'] == 'select'){ $value = str_replace('\"', '"', $value); $value = json_decode($value, true); } // Save $custom_fields[$key] = [ 'field' => $the_field, 'value' => $value ]; } $booking->custom_fields = $custom_fields; } // Voy a guardar por si acaso evavel_log_to_file(\Evavel\Log\Log::AJAX_SAVE_BOOKING_VALUES, json_encode($booking->toArray())); $booking->save(); } /** * Assign Booking user (search existing or create a new one) * * @param $booking * * @return void */ protected function assignOrCreateNewCustomerIfNeeded($booking) { if ($booking->customer_id != null) return; $customer_found = \Alexr\Models\Customer::where('email', $booking->email) ->where('restaurant_id', $booking->restaurant_id) ->first(); if ($customer_found) { $booking->customer_id = $customer_found->id; $customer_found->calculateVisits(); $this->updateCustomerConditions($customer_found); return; } $customer = alexr_create_new_customer($booking); if ($customer){ $booking->customer_id = $customer->id; $customer->calculateVisits(); $this->updateCustomerConditions($customer); } } /** * Update Flags for receiving email marketing and SMS * * @param $customer * * @return void */ protected function updateCustomerConditions($customer) { if (isset($_REQUEST['agree_email_news'])) { $agree_email_news = sanitize_text_field($_REQUEST['agree_email_news']); if ($agree_email_news == 'true') { $customer->agree_receive_email_marketing = 1; $customer->agree_receive_email = 1; } else { $customer->agree_receive_email_marketing = 0; } } if (isset($_REQUEST['agree_sms'])) { $agree_sms = sanitize_text_field($_REQUEST['agree_sms']); if ($agree_sms == 'true') { $customer->agree_receive_sms = 1; } else { $customer->agree_receive_sms = 0; } } $customer->save(); } /** * Admin can change status at the front-end without using the dashboard * * @return void */ public function update_booking_status() { //ray('UPDATE BOOKING STATUS'); $restaurantId = intval($_REQUEST['restaurantId']); // Check restaurant exists $restaurant = \Alexr\Models\Restaurant::find($restaurantId); if (!$restaurant){ wp_send_json_error([ 'message' => 'Wrong restaurant' ]); } $nonce = sanitize_text_field($_REQUEST['nonce']); $uuid = sanitize_text_field($_REQUEST['uuid']); $new_status = sanitize_text_field($_REQUEST['status']); // Check nonce if (!evavel_verify_nonce($nonce, 'booking-'.$uuid)) { wp_send_json_error(['message' => __eva('Invalid nonce booking.')]); } $booking = \Alexr\Models\Booking::where('uuid', $uuid)->first(); if (!$booking) { wp_send_json_error(['message' => __eva('Booking does not exist.')]); } // Check correct status $list = BookingStatus::listing(); if (!in_array($new_status, array_keys($list))){ wp_send_json_error(['message' => __eva('Wrong status.')]); } $email_actions = $booking->getMeta('email_actions'); if ($email_actions == null){ $booking->setMeta('email_actions', 1); } else { wp_send_json_error(['message' => __eva('Cannot change status again.')]); //$booking->setMeta('email_actions', 1 + intval($email_actions)); } $old_status = $booking->status; $booking->status = $new_status; $booking->save(); evavel_event(new \Alexr\Events\EventBookingStatusChanged($booking, $old_status, $new_status, null, true)); $this->sendBookingNotifications($booking, $booking->language, true); wp_send_json_success(['success' => true]); } } new ALEXR_Ajax_Actions;