[Back] <?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'OsBookingsController' ) ) :
class OsBookingsController extends OsController {
private $booking;
function __construct() {
parent::__construct();
$this->views_folder = LATEPOINT_VIEWS_ABSPATH . 'bookings/';
$this->vars['page_header'] = OsMenuHelper::get_menu_items_by_id( 'appointments' );
$this->vars['breadcrumbs'][] = array( 'label' => __( 'Appointments', 'latepoint' ), 'link' => OsRouterHelper::build_link( [ 'bookings', 'pending_approval' ] ) );
}
public function view_booking_log() {
$activities = new OsActivityModel();
$activities = $activities->where( [ 'booking_id' => absint( $this->params['booking_id'] ) ] )->order_by( 'id desc' )->get_results_as_models();
$booking = new OsBookingModel( $this->params['booking_id'] );
$this->vars['booking'] = $booking;
$this->vars['activities'] = $activities;
$this->format_render( __FUNCTION__ );
}
public function grouped_bookings_quick_view() {
if ( ! isset( $this->params['booking_id'] ) ) {
return false;
}
$booking = new OsBookingModel( $this->params['booking_id'] );
$this->vars['booking'] = $booking;
$group_bookings = new OsBookingModel();
$group_bookings = $group_bookings->where( [
'start_time' => $booking->start_time,
'start_date' => $booking->start_date,
'service_id' => $booking->service_id,
'location_id' => $booking->location_id,
'agent_id' => $booking->agent_id
] )->should_not_be_cancelled()->get_results_as_models();
$total_attendees = 0;
if ( $group_bookings ) {
foreach ( $group_bookings as $group_booking ) {
$total_attendees = $total_attendees + $group_booking->total_attendees;
}
}
$this->vars['total_attendees'] = $total_attendees;
$this->vars['group_bookings'] = $group_bookings;
$this->format_render( __FUNCTION__ );
}
public function pending_approval() {
$this->vars['page_header'] = __( 'Pending Appointments', 'latepoint' );
$this->vars['breadcrumbs'][] = array( 'label' => __( 'Pending Appointments', 'latepoint' ), 'link' => false );
$page_number = isset( $this->params['page_number'] ) ? $this->params['page_number'] : 1;
$per_page = OsSettingsHelper::get_number_of_records_per_page();
$offset = ( $page_number > 1 ) ? ( ( $page_number - 1 ) * $per_page ) : 0;
$bookings = new OsBookingModel();
$query_args = [ 'status' => OsBookingHelper::get_booking_statuses_for_pending_page() ];
$bookings->where( $query_args )->filter_allowed_records();
$count_total_bookings = clone $bookings;
$total_bookings = $count_total_bookings->count();
$this->vars['bookings'] = $bookings->set_limit( $per_page )->set_offset( $offset )->order_by( 'id desc' )->get_results_as_models();
$total_pages = ceil( $total_bookings / $per_page );
$this->vars['total_pages'] = $total_pages;
$this->vars['total_bookings'] = $total_bookings;
$this->vars['per_page'] = $per_page;
$this->vars['current_page_number'] = $page_number;
$this->vars['showing_from'] = ( ( $page_number - 1 ) * $per_page ) ? ( ( $page_number - 1 ) * $per_page ) : 1;
$this->vars['showing_to'] = min( $page_number * $per_page, $this->vars['total_bookings'] );
$this->format_render( __FUNCTION__ );
}
public function customize_table() {
$this->vars['selected_columns'] = OsSettingsHelper::get_selected_columns_for_bookings_table();
$this->vars['available_columns'] = OsSettingsHelper::get_available_columns_for_bookings_table();
$this->format_render( __FUNCTION__ );
}
public function index() {
$this->vars['page_header'] = false;
$this->vars['breadcrumbs'][] = array( 'label' => __( 'All', 'latepoint' ), 'link' => false );
$page_number = isset( $this->params['page_number'] ) ? $this->params['page_number'] : 1;
$per_page = OsSettingsHelper::get_number_of_records_per_page();
$offset = ( $page_number > 1 ) ? ( ( $page_number - 1 ) * $per_page ) : 0;
$customer = new OsCustomerModel();
$bookings = new OsBookingModel();
$query_args = [];
$selected_columns = OsSettingsHelper::get_selected_columns_for_bookings_table();
$available_columns = OsSettingsHelper::get_available_columns_for_bookings_table();
$filter = $this->params['filter'] ?? false;
$order_by = [ 'key' => 'booking_id', 'direction' => 'desc', 'column' => 'id' ];
// TABLE SEARCH FILTERS
if ( $filter ) {
if ( ! empty( $filter['records_ordered_by_key'] ) && ! empty( $filter['records_ordered_by_direction'] ) ) {
if ( in_array( $filter['records_ordered_by_direction'], [ 'desc', 'asc' ] ) ) {
$order_by['direction'] = $filter['records_ordered_by_direction'];
}
$order_by['key'] = $filter['records_ordered_by_key'];
switch ( $filter['records_ordered_by_key'] ) {
case 'booking_id':
$order_by['column'] = 'id';
break;
case 'booking_start_datetime':
$order_by['column'] = 'start_datetime_utc';
break;
case 'booking_created_on':
$order_by['column'] = 'created_at';
break;
case 'booking_time_left':
$order_by['column'] = 'start_datetime_utc';
break;
}
}
if ( ! empty( $filter['service_id'] ) ) {
$query_args['service_id'] = $filter['service_id'];
}
if ( ! empty( $filter['agent_id'] ) ) {
$query_args['agent_id'] = $filter['agent_id'];
}
if ( ! empty( $filter['location_id'] ) ) {
$query_args['location_id'] = $filter['location_id'];
}
if ( ! empty( $filter['time_status'] ) ) {
switch ( $filter['time_status'] ) {
case 'now':
$query_args['start_datetime_utc <='] = OsTimeHelper::now_datetime_utc_in_db_format();
$query_args['end_datetime_utc >='] = OsTimeHelper::now_datetime_utc_in_db_format();
break;
case 'upcoming':
$query_args['start_datetime_utc >='] = OsTimeHelper::now_datetime_utc_in_db_format();
break;
case 'past':
$query_args['end_datetime_utc <='] = OsTimeHelper::now_datetime_utc_in_db_format();
break;
}
}
if ( ! empty( $filter['status'] ) ) {
$query_args[ LATEPOINT_TABLE_BOOKINGS . '.status' ] = $filter['status'];
}
if ( ! empty( $filter['payment_status'] ) ) {
$query_args[ LATEPOINT_TABLE_BOOKINGS . '.payment_status' ] = $filter['payment_status'];
}
if ( ! empty( $filter['id'] ) ) {
$query_args[ LATEPOINT_TABLE_BOOKINGS . '.id' ] = $filter['id'];
}
if ( ! empty( $filter['created_date_from'] ) && ! empty( $filter['created_date_to'] ) ) {
$query_args[ LATEPOINT_TABLE_BOOKINGS . '.created_at >=' ] = $filter['created_date_from'] . ' 00:00:00';
$query_args[ LATEPOINT_TABLE_BOOKINGS . '.created_at <=' ] = $filter['created_date_to'] . ' 23:59:59';
}
if ( ! empty( $filter['booking_date_from'] ) && ! empty( $filter['booking_date_to'] ) ) {
$query_args[ LATEPOINT_TABLE_BOOKINGS . '.start_date >=' ] = $filter['booking_date_from'];
$query_args[ LATEPOINT_TABLE_BOOKINGS . '.start_date <=' ] = $filter['booking_date_to'];
}
$selected_columns = OsSettingsHelper::get_selected_columns_for_bookings_table();
if ( ! empty( $filter['order'] ) ) {
$bookings->select( LATEPOINT_TABLE_BOOKINGS . '.*' );
$bookings->join( LATEPOINT_TABLE_ORDER_ITEMS, [ 'id' => LATEPOINT_TABLE_BOOKINGS . '.order_item_id' ] );
$bookings->join( LATEPOINT_TABLE_ORDERS, [ 'id' => LATEPOINT_TABLE_ORDER_ITEMS . '.order_id' ] );
if ( ! empty( $filter['order']['payment_status'] ) ) {
$bookings->select( LATEPOINT_TABLE_ORDERS . '.payment_status' );
$query_args[ LATEPOINT_TABLE_ORDERS . '.payment_status' ] = $filter['order']['payment_status'];
}
}
if ( ! empty( $filter['customer'] ) ) {
$bookings->select( LATEPOINT_TABLE_BOOKINGS . '.*' );
if ( ! empty( $filter['customer']['full_name'] ) ) {
$bookings->select( LATEPOINT_TABLE_CUSTOMERS . '.first_name, ' . LATEPOINT_TABLE_CUSTOMERS . '.last_name' );
$query_args[ 'concat_ws(" ", ' . LATEPOINT_TABLE_CUSTOMERS . '.first_name,' . LATEPOINT_TABLE_CUSTOMERS . '.last_name) LIKE' ] = '%' . $filter['customer']['full_name'] . '%';
$this->vars['customer_name_query'] = $filter['customer']['full_name'];
}
$bookings->join( LATEPOINT_TABLE_CUSTOMERS, [ 'id' => LATEPOINT_TABLE_BOOKINGS . '.customer_id' ] );
if ( ! empty( $selected_columns['customer'] ) ) {
$meta_filter = [];
foreach ( $selected_columns['customer'] as $customer_column_key ) {
if ( isset( $available_columns['customer'][ $customer_column_key ] ) && ! empty( $filter['customer'][ $customer_column_key ] ) ) {
if ( in_array( $customer_column_key, $customer->get_params_to_save() ) ) {
// native field
$bookings->select( LATEPOINT_TABLE_CUSTOMERS . '.' . $customer_column_key );
$query_args[ LATEPOINT_TABLE_CUSTOMERS . '.' . $customer_column_key . ' LIKE' ] = '%' . $filter['customer'][ $customer_column_key ] . '%';
} else {
// meta field
$meta_filter[ $customer_column_key ] = $filter['customer'][ $customer_column_key ];
}
}
}
if ( count( $meta_filter ) ) {
$customers_ids = OsMetaHelper::get_customers_by_filter( $meta_filter ) ?: [ - 1 ];
$query_args[ LATEPOINT_TABLE_CUSTOMERS . '.id IN' ] = $customers_ids;
}
}
}
// filters for custom selected columns, only related to booking fields
if ( ! empty( $selected_columns['booking'] ) ) {
foreach ( $selected_columns['booking'] as $booking_column_key ) {
if ( ! empty( $available_columns['booking'][ $booking_column_key ] ) && ! empty( $filter[ $booking_column_key ] ) ) {
$query_args[ $booking_column_key . ' LIKE' ] = '%' . $filter[ $booking_column_key ] . '%';
}
}
}
}
$this->vars['agents_list'] = OsAgentHelper::get_agents_list( true );
$this->vars['locations_list'] = OsLocationHelper::get_locations_list( true );
$this->vars['services_list'] = OsServiceHelper::get_services_list( true );
$this->vars['selected_columns'] = $selected_columns;
$this->vars['available_columns'] = $available_columns;
$this->vars['records_ordered_by_key'] = $order_by['key'];
$this->vars['records_ordered_by_direction'] = $order_by['direction'];
// OUTPUT CSV IF REQUESTED
if ( isset( $this->params['download'] ) && $this->params['download'] == 'csv' ) {
$csv_filename = 'all_bookings_' . OsUtilHelper::random_text() . '.csv';
header( "Content-Type: text/csv" );
header( "Content-Disposition: attachment; filename={$csv_filename}" );
$labels_row = [
__( 'ID', 'latepoint' ),
__( 'Service', 'latepoint' ),
__( 'Start Date & Time', 'latepoint' ),
__( 'Duration', 'latepoint' ),
__( 'Customer', 'latepoint' ),
__( 'Customer Phone', 'latepoint' ),
__( 'Customer Email', 'latepoint' ),
__( 'Agent', 'latepoint' ),
__( 'Agent Phone', 'latepoint' ),
__( 'Agent Email', 'latepoint' ),
__( 'Status', 'latepoint' ),
__( 'Price', 'latepoint' ),
__( 'Booked On', 'latepoint' )
];
$bookings_data = [];
$bookings_data[] = $labels_row;
$bookings_arr = $bookings->where( $query_args )->filter_allowed_records()->order_by( $order_by['column'] . ' ' . $order_by['direction'] )->get_results_as_models();
if ( $bookings_arr ) {
foreach ( $bookings_arr as $booking ) {
$order_item = new OsOrderItemModel( $booking->order_item_id );
$values_row = [
$booking->id,
$booking->service->name,
$booking->nice_start_datetime,
$booking->get_total_duration(),
$booking->customer->full_name,
$booking->customer->phone,
$booking->customer->email,
$booking->agent->full_name,
$booking->agent->phone,
$booking->agent->email,
$booking->nice_status,
OsMoneyHelper::format_price( $order_item->get_total(), true, false ),
$booking->nice_created_at
];
$values_row = apply_filters( 'latepoint_booking_row_for_csv_export', $values_row, $booking, $this->params );
$bookings_data[] = $values_row;
}
}
$bookings_data = apply_filters( 'latepoint_bookings_data_for_csv_export', $bookings_data, $this->params );
OsCSVHelper::array_to_csv( $bookings_data );
return;
}
$query_args = OsRolesHelper::filter_allowed_records_from_arguments_or_filter( $query_args );
$bookings->where( $query_args )->filter_allowed_records();
$count_total_bookings = clone $bookings;
$total_bookings = $count_total_bookings->count();
$this->vars['bookings'] = $bookings->set_limit( $per_page )->set_offset( $offset )->order_by( $order_by['column'] . ' ' . $order_by['direction'] )->get_results_as_models();
$this->vars['total_bookings'] = $total_bookings;
$total_pages = ceil( $total_bookings / $per_page );
$this->vars['total_pages'] = $total_pages;
$this->vars['per_page'] = $per_page;
$this->vars['current_page_number'] = $page_number;
$this->vars['total_records'] = $total_bookings;
$this->vars['showing_from'] = ( ( $page_number - 1 ) * $per_page ) ? ( ( $page_number - 1 ) * $per_page ) : 1;
$this->vars['showing_to'] = min( $page_number * $per_page, $this->vars['total_bookings'] );
$this->format_render( [ 'json_view_name' => '_table_body', 'html_view_name' => __FUNCTION__ ], [], [ 'total_pages' => $total_pages,
'showing_from' => $this->vars['showing_from'],
'showing_to' => $this->vars['showing_to'],
'total_records' => $total_bookings
] );
}
function quick_availability() {
$trigger_form_booking_id = $this->params['trigger_form_booking_id'];
$trigger_form_order_item_id = $this->params['trigger_form_order_item_id'];
$booking = OsOrdersHelper::create_booking_object_from_booking_data_form( $this->params['order_items'][ $trigger_form_order_item_id ]['bookings'][ $trigger_form_booking_id ] );
$calendar_start_date = isset( $this->params['start_date'] ) ? new OsWpDateTime( $this->params['start_date'] ) : new OsWpDateTime( $booking->start_date );
// show one more day before so the current selection does not look weird
if ( isset( $this->params['previous_days'] ) ) {
$calendar_end_date = clone $calendar_start_date;
$calendar_start_date->modify( '-60 days' );
} else {
if ( ! isset( $this->params['show_days_only'] ) ) {
$calendar_start_date->modify( '-1 day' );
}
$calendar_end_date = clone $calendar_start_date;
$calendar_end_date->modify( '+60 days' );
}
if ( OsAuthHelper::get_current_user()->is_single_record_allowed( 'agent' ) ) {
$booking->agent_id = OsRolesHelper::get_allowed_records( 'agent' )[0];
}
$work_periods = OsWorkPeriodsHelper::get_work_periods( new \LatePoint\Misc\Filter( [
'date_from' => $calendar_start_date->format( 'Y-m-d' ),
'date_to' => $calendar_end_date->format( 'Y-m-d' ),
'service_id' => $booking->service_id,
'agent_id' => $booking->agent_id,
'location_id' => $booking->location_id
] ) );
$work_start_end = OsWorkPeriodsHelper::get_work_start_end_time( $work_periods );
$booking_request = \LatePoint\Misc\BookingRequest::create_from_booking_model( $booking );
$settings = [];
$settings['accessed_from_backend'] = true;
if ( ! $booking->is_new_record() ) {
$settings['exclude_booking_ids'] = [ $booking->id ];
}
$resources = OsResourceHelper::get_resources_grouped_by_day( $booking_request, $calendar_start_date, $calendar_end_date, $settings );
$work_boundaries = OsResourceHelper::get_work_boundaries_for_groups_of_resources( $resources );
$this->vars['trigger_form_booking_id'] = $trigger_form_booking_id;
$this->vars['trigger_form_order_item_id'] = $trigger_form_order_item_id;
$this->vars['booking'] = $booking;
$this->vars['work_boundaries'] = $work_boundaries;
$this->vars['show_days_only'] = isset( $this->params['show_days_only'] ) ? true : false;
$this->vars['timeblock_interval'] = $booking->service->get_timeblock_interval();
$this->vars['calendar_start_date'] = $calendar_start_date;
$this->vars['calendar_end_date'] = $calendar_end_date;
$this->vars['booking_request'] = $booking_request;
$this->vars['resources'] = $resources;
$agents = new OsAgentModel();
$this->vars['agents'] = $agents->filter_allowed_records()->get_results_as_models();
$this->format_render( __FUNCTION__ );
}
function change_status() {
if ( filter_var( $this->params['id'], FILTER_VALIDATE_INT ) ) {
$this->check_nonce( 'change_status_booking_' . $this->params['id'] );
$booking_id = $this->params['id'];
$new_status = $this->params['status'];
$booking = new OsBookingModel( $booking_id );
if ( ! OsRolesHelper::can_user_make_action_on_model_record( $booking, 'edit' ) ) {
exit;
}
if ( $booking->update_status( $new_status ) ) {
$status = LATEPOINT_STATUS_SUCCESS;
$response_html = __( 'Appointment Status Updated', 'latepoint' );
} else {
$status = LATEPOINT_STATUS_ERROR;
$response_html = __( 'Error Updating Booking Status!', 'latepoint' ) . ' ' . implode( ',', $booking->get_error_messages() );
}
} else {
$status = LATEPOINT_STATUS_ERROR;
$response_html = __( 'Error Updating Booking Status! Invalid ID', 'latepoint' );
}
if ( $this->get_return_format() == 'json' ) {
$this->send_json( array( 'status' => $status, 'message' => $response_html ) );
}
}
}
endif;