<?php class OsServiceModel extends OsModel{ public $id, $name = '', $short_description, $selection_image_id, $description_image_id, $is_price_variable, $price_min, $price_max, $charge_amount, $deposit_amount, $duration_name = '', $duration = 60, $buffer_before, $buffer_after, $category_id, $override_default_booking_status = false, $status, $bg_color, $order_number, $visibility = LATEPOINT_SERVICE_VISIBILITY_VISIBLE, $capacity_min = 1, $capacity_max = 1, $timeblock_interval, $is_custom_price = false, $is_custom_hours = false, $is_custom_duration = false, $meta_class = 'OsServiceMetaModel', $services_agents_table_name, $is_deposit_required, $earliest_possible_booking, $latest_possible_booking, $deposit_value, $updated_at, $created_at; function __construct($id = false){ parent::__construct(); $this->table_name = LATEPOINT_TABLE_SERVICES; $this->services_agents_table_name = LATEPOINT_TABLE_AGENTS_SERVICES; $this->nice_names = array( 'name' => __('Service Name', 'latepoint'), 'short_description' => __('Service Short Description', 'latepoint'), 'selection_image_id' => __('Service Selection Image', 'latepoint'), 'description_image_id' => __('Service Description Image', 'latepoint'), 'is_price_variable' => __('Variable Price', 'latepoint'), 'price_min' => __('Minimum Price', 'latepoint'), 'price_max' => __('Maximum Price', 'latepoint'), 'charge_amount' => __('Charge Amount', 'latepoint'), 'deposit_amount' => __('Deposit Amount', 'latepoint'), 'duration_name' => __('Duration Name', 'latepoint'), 'duration' => __('Service Duration', 'latepoint'), 'buffer_before' => __('Buffer Before', 'latepoint'), 'buffer_after' => __('Buffer After', 'latepoint'), 'bg_color' => __('Background Color', 'latepoint'), 'category_id' => __('Service Category', 'latepoint')); if($id){ $this->load_by_id($id); } } protected function params_to_save($role = 'admin'){ $params_to_save = array('id', 'name', 'short_description', 'category_id', 'selection_image_id', 'is_price_variable', 'price_min', 'price_max', 'charge_amount', 'deposit_amount', 'duration_name', 'duration', 'buffer_before', 'buffer_after', 'bg_color', 'timeblock_interval', 'override_default_booking_status', 'order_number', 'visibility', 'status', 'earliest_possible_booking', 'latest_possible_booking', 'capacity_min', 'capacity_max', 'description_image_id'); return $params_to_save; } protected function allowed_params($role = 'admin'){ $allowed_params = array('id', 'name', 'short_description', 'category_id', 'selection_image_id', 'is_price_variable', 'price_min', 'price_max', 'charge_amount', 'deposit_amount', 'duration_name', 'duration', 'buffer_before', 'buffer_after', 'bg_color', 'timeblock_interval', 'override_default_booking_status', 'order_number', 'visibility', 'earliest_possible_booking', 'latest_possible_booking', 'status', 'capacity_min', 'capacity_max', 'description_image_id'); return $allowed_params; } public function prepare_data_before_it_is_set( $data ) { if ( isset( $data['name'] ) ) { $data['name'] = sanitize_text_field( $data['name'] ); } if ( isset( $data['short_description'] ) ) { $data['short_description'] = wp_kses_post( $data['short_description'] ); } return $data; } public function get_default_booking_status(){ if(!empty($this->override_default_booking_status)){ $all_statuses = OsBookingHelper::get_statuses_list(); if(isset($all_statuses[$this->override_default_booking_status])) return $this->override_default_booking_status; } return OsBookingHelper::get_default_booking_status(); } public function get_category_name(){ if($this->category_id){ $category = new OsServiceCategoryModel($this->category_id); if($category->exists()){ return $category->name; } } return ''; } // determine how much capacity service can accept before the slot is blocked public function get_capacity_needed_before_slot_is_blocked(): int{ $capacity_min = $this->capacity_min ? $this->capacity_min : 1; $capacity_max = $this->capacity_max ? $this->capacity_max : 1; return ($this->get_meta_by_key('block_timeslot_when_minimum_capacity_met', 'off') == 'on') ? $capacity_min : $capacity_max; } public function get_timeblock_interval(){ if(!$this->timeblock_interval){ $this->timeblock_interval = OsSettingsHelper::get_default_timeblock_interval(); } return $this->timeblock_interval; } public function filter_allowed_records(): OsModel{ if(!OsRolesHelper::are_all_records_allowed('service')){ $this->filter_where_conditions(['id' => OsRolesHelper::get_allowed_records('service')]); } return $this; } protected function before_create(){ } public function should_show_capacity_selector(){ return (($this->capacity_max != $this->capacity_min) && ($this->get_meta_by_key('fixed_total_attendees', 'off') != 'on')); } public function is_group_service(){ return ($this->capacity_max > 1); } public function get_all_durations_arr(){ $durations = [['id' => 'default', 'name' => $this->duration_name, 'duration' => $this->duration, 'charge_amount' => $this->charge_amount, 'deposit_amount' => $this->deposit_amount]]; $durations = array_merge($durations, $this->get_extra_durations()); return $durations; } public function get_extra_durations(){ $durations = []; $extra_durations = $this->get_meta_by_key('durations', false); if($extra_durations){ $extra_durations_arr = json_decode($extra_durations, true); if(!empty($extra_durations_arr)){ foreach($extra_durations_arr as $duration_id => $extra_duration){ $durations[] = ['id' => $duration_id, 'name' => ($extra_duration['name'] ?? ''), 'duration' => $extra_duration['duration'], 'charge_amount' => $extra_duration['charge_amount'], 'deposit_amount' => $extra_duration['deposit_amount']]; } } } return $durations; } public function get_full_amount_for_duration($duration = false){ if($duration && $duration != $this->duration){ $extra_durations = $this->get_extra_durations(); foreach($extra_durations as $extra_duration){ if($extra_duration['duration'] == $duration) return $extra_duration['charge_amount']; } } return $this->charge_amount; } public function get_deposit_amount_for_duration($duration = false){ if($duration && $duration != $this->duration){ $extra_durations = $this->get_extra_durations(); foreach($extra_durations as $extra_duration){ if($extra_duration['duration'] == $duration) return $extra_duration['deposit_amount']; } } return $this->deposit_amount; } protected function set_defaults(){ if(empty($this->category_id)) $this->category_id = 0; if(empty($this->buffer_before)) $this->buffer_before = 0; if(empty($this->buffer_after)) $this->buffer_after = 0; if(empty($this->price_min)) $this->price_min = 0; if(empty($this->price_max)) $this->price_max = 0; if(empty($this->charge_amount)) $this->charge_amount = 0; if(empty($this->deposit_amount)) $this->deposit_amount = 0; if(empty($this->is_deposit_required)) $this->is_deposit_required = false; if(empty($this->status)) $this->status = LATEPOINT_SERVICE_STATUS_ACTIVE; if(empty($this->bg_color)) $this->bg_color = $this->generate_new_bg_color(); } public function save_custom_schedule($work_periods){ foreach($work_periods as &$work_period){ $work_period['service_id'] = $this->id; } unset($work_period); OsWorkPeriodsHelper::save_work_periods($work_periods); } public function delete_custom_schedule(){ $work_periods_model = new OsWorkPeriodModel(); $work_periods = $work_periods_model->where(array('service_id' => $this->id, 'agent_id' => 0, 'location_id' => 0, 'custom_date' => 'IS NULL'))->get_results_as_models(); if(is_array($work_periods)){ foreach($work_periods as $work_period){ $work_period->delete(); } } } public function generate_new_bg_color(){ $services = new OsServiceModel(); $service_colors_results = $services->select('bg_color')->group_by('bg_color')->get_results(ARRAY_A); $services_used_colors = array_map(function($service){ return $service['bg_color']; }, $service_colors_results); $default_colors = OsServiceHelper::get_default_colors(); $colors_left = array_diff($default_colors, $services_used_colors); if(!empty($colors_left)){ // reset array $colors_left = array_values($colors_left); $bg_color = $colors_left[0]; }else{ $bg_color = '#3d52ea'; } return $bg_color; } public function delete($id = false){ if(!$id && isset($this->id)){ $id = $this->id; } if($id && $this->db->delete( $this->table_name, array('id' => $id), array( '%d' ))){ $this->db->delete(LATEPOINT_TABLE_AGENTS_SERVICES, array('service_id' => $id), array( '%d' ) ); $this->db->delete(LATEPOINT_TABLE_WORK_PERIODS, array('service_id' => $id), array( '%d' ) ); $this->db->delete(LATEPOINT_TABLE_SERVICE_META, array('object_id' => $id), array( '%d' ) ); $this->db->delete(LATEPOINT_TABLE_BOOKINGS, array('service_id' => $id), array( '%d' ) ); do_action('latepoint_service_deleted', $id); return true; }else{ return false; } } protected function params_to_sanitize(){ return ['charge_amount' => 'money', 'deposit_amount' => 'money', 'price_min' => 'money', 'price_max' => 'money', ]; } public function is_hidden(){ return ($this->visibility == LATEPOINT_SERVICE_VISIBILITY_HIDDEN); } public function should_be_active(){ return $this->where(['status' => LATEPOINT_SERVICE_STATUS_ACTIVE]); } public function should_not_be_hidden(){ return $this->where(['visibility !=' => LATEPOINT_SERVICE_VISIBILITY_HIDDEN]); } public function is_active(){ return ($this->status == LATEPOINT_SERVICE_STATUS_ACTIVE); } protected function get_price_min_formatted(){ if($this->price_min > 0){ return OsMoneyHelper::format_price($this->price_min); }else{ return OsMoneyHelper::format_price(0); } } public function get_selection_image_url(){ $default_service_image_url = LATEPOINT_IMAGES_URL . 'service-image.png'; return OsImageHelper::get_image_url_by_id($this->selection_image_id, 'thumbnail', $default_service_image_url); } public function get_description_image_url(){ $default_service_image_url = LATEPOINT_IMAGES_URL . 'service-image.png'; return OsImageHelper::get_image_url_by_id($this->description_image_id, 'full', $default_service_image_url); } public function connect_to_agent($agent_id, $location_id){ $agent_connection_row = $this->db->get_row($this->db->prepare('SELECT id FROM '.$this->services_agents_table_name.' WHERE service_id = %d AND agent_id = %d AND location_id = %d', array($this->id, $agent_id, $location_id))); if($agent_connection_row){ // update }else{ $insert_data = array('agent_id' => $agent_id, 'service_id' => $this->id, 'location_id' => $location_id); if($this->db->insert($this->services_agents_table_name, $insert_data)){ return $this->db->insert_id; } } } public function save_durations($durations){ foreach($durations as &$duration){ $duration['charge_amount'] = OsParamsHelper::sanitize_param($duration['charge_amount'], 'money'); $duration['deposit_amount'] = OsParamsHelper::sanitize_param($duration['deposit_amount'], 'money'); } unset($duration); $this->save_meta_by_key('durations', wp_json_encode($durations)); return true; } public function delete_meta_by_key($meta_key){ if($this->is_new_record()) return false; $meta = new OsServiceMetaModel(); return $meta->delete_by_key($meta_key, $this->id); } public function get_meta_by_key($meta_key, $default = false){ if($this->is_new_record()) return $default; $meta = new OsServiceMetaModel(); return $meta->get_by_key($meta_key, $this->id, $default); } public function save_meta_by_key($meta_key, $meta_value){ if($this->is_new_record()) return false; $meta = new OsServiceMetaModel(); return $meta->save_by_key($meta_key, $meta_value, $this->id); } public function save_agents(){ foreach($this->agents as $agent){ $agent_connection_row = $this->db->get_row($this->db->prepare('SELECT id FROM '.$this->services_agents_table_name.' WHERE service_id = %d AND agent_id = %d', array($this->id, $agent->id))); if($agent_connection_row){ $update_data = array('is_custom_hours' => $agent->is_custom_hours, 'is_custom_price' => $agent->is_custom_price, 'is_custom_duration' => $agent->is_custom_duration); $this->db->update($this->services_agents_table_name, $update_data, array('id' => $agent_connection_row->id)); }else{ $insert_data = array('agent_id' => $agent->id, 'service_id' => $this->id, 'is_custom_hours' => $agent->is_custom_hours, 'is_custom_price' => $agent->is_custom_price, 'is_custom_duration' => $agent->is_custom_duration); if($this->db->insert($this->services_agents_table_name, $insert_data)){ $agent_connection_row_id = $this->db->insert_id; } } } return true; } public function remove_agents_by_ids($ids_to_remove = array()){ if($ids_to_remove){ $query = $this->db->prepare('DELETE FROM %i WHERE service_id = %d AND agent_id IN ' . OsModel::where_in_array_to_string($ids_to_remove), [$this->services_agents_table_name, $this->id]); $this->db->query( $query ); } } public function get_agent_ids_to_remove($new_agents = array()){ $current_agent_ids = $this->get_current_agent_ids_from_db(); $new_agent_ids = array(); foreach($new_agents as $agent){ if($agent['connected'] == "yes") $new_agent_ids[] = $agent['id']; } $agent_ids_to_remove = array_diff($current_agent_ids, $new_agent_ids); return $agent_ids_to_remove; } public function save_agents_and_locations($agents){ if(!$agents) return true; $connections_to_save = []; $connections_to_remove = []; foreach($agents as $agent_key => $locations){ $agent_id = str_replace('agent_', '', $agent_key); foreach($locations as $location_key => $location){ $location_id = str_replace('location_', '', $location_key); $connection = ['service_id' => $this->id, 'agent_id' => $agent_id, 'location_id' => $location_id]; if($location['connected'] == 'yes'){ $connections_to_save[] = $connection; }else{ $connections_to_remove[] = $connection; } } } if(!empty($connections_to_save)){ foreach($connections_to_save as $connection_to_save){ OsConnectorHelper::save_connection($connection_to_save); } } if(!empty($connections_to_remove)){ foreach($connections_to_remove as $connection_to_remove){ OsConnectorHelper::remove_connection($connection_to_remove); } } return true; } public function get_current_agent_ids_from_db(){ $query = $this->db->prepare('SELECT agent_id FROM '.$this->services_agents_table_name.' WHERE service_id = %d', $this->id); $agent_rows = $this->db->get_results( $query ); $agent_ids = array(); if($agent_rows){ foreach($agent_rows as $agent_row){ $agent_ids[] = $agent_row->agent_id; } } return $agent_ids; } public function get_current_agent_ids(){ $agent_ids = array(); foreach($this->agents as $agent){ $agent_ids[] = $agent->id; } return $agent_ids; } public function get_agents(){ if(!isset($this->agents)){ $query = 'SELECT * FROM '.$this->services_agents_table_name.' WHERE service_id = %d GROUP BY agent_id'; $query_args = array($this->id); $agents_rows = $this->get_query_results( $query, $query_args ); $this->agents = array(); if($agents_rows){ foreach($agents_rows as $agent_row){ $agent = new OsAgentModel($agent_row->agent_id); $agent->is_custom_hours = $agent_row->is_custom_hours; $agent->is_custom_price = $agent_row->is_custom_price; $agent->is_custom_duration = $agent_row->is_custom_duration; $this->agents[] = $agent; } } } return $this->agents; } public function set_agents($agent_datas){ $this->agents = array(); foreach($agent_datas as $agent_data){ if($agent_data['connected'] == "yes"){ $agent = new OsAgentModel(); $agent->id = $agent_data['id']; $agent->is_custom_hours = $agent_data['is_custom_hours']; $agent->is_custom_price = $agent_data['is_custom_price']; $agent->is_custom_duration = $agent_data['is_custom_duration']; $this->agents[] = $agent; } } return $this; } public function has_agent($agent_id){ return OsConnectorHelper::has_connection(['service_id' => $this->id, 'agent_id' => $agent_id]); } public function has_agent_and_location($agent_id, $location_id){ if($this->is_new_record()) return false; return OsConnectorHelper::has_connection(['service_id' => $this->id, 'agent_id' => $agent_id, 'location_id' => $location_id]); } public function count_number_of_connected_locations($agent_id = false){ if($this->is_new_record()) return 0; $args = ['service_id' => $this->id]; if($agent_id) $args['agent_id'] = $agent_id; return OsConnectorHelper::count_connections($args, 'location_id'); } protected function properties_to_validate(){ $validations = array( 'name' => array('presence'), 'duration' => array('presence'), ); return $validations; } }