guard_admin(); if ( $check ) { return $check; } if ( $meeting_id <= 0 || ! class_exists( '\Timetics\Core\Appointments\Appointment' ) ) { return [ 'error' => 'A valid meeting_id is required.' ]; } try { $meeting = new \Timetics\Core\Appointments\Appointment( $meeting_id ); if ( ! $meeting->is_appointment() ) { return [ 'error' => "Meeting #{$meeting_id} was not found." ]; } $staff_ids = $meeting->get_staff_ids(); $staff_id = ( null !== $staff_id && $staff_id > 0 ) ? $staff_id : (int) ( $staff_ids[0] ?? 0 ); if ( $staff_id <= 0 ) { return [ 'error' => "Meeting #{$meeting_id} has no assigned staff to check availability for." ]; } $start_date = ( null !== $start_date && '' !== trim( $start_date ) ) ? sanitize_text_field( $start_date ) : current_time( 'Y-m-d' ); $end_date = ( null !== $end_date && '' !== trim( $end_date ) ) ? sanitize_text_field( $end_date ) : $start_date; $timezone = $this->resolve_timezone( ( null !== $timezone && '' !== trim( $timezone ) ) ? $timezone : $meeting->get_timezone() ); // Cap the span: one row per day, so an unbounded range floods the model. $note = null; $start_ts = strtotime( $start_date ); $end_ts = strtotime( $end_date ); $max_span = 31; if ( false === $start_ts ) { return [ 'error' => 'start_date is not a valid date. Use YYYY-MM-DD.' ]; } if ( false === $end_ts || $end_ts < $start_ts ) { // Missing/reversed end collapses to a single day. $end_ts = $start_ts; $end_date = gmdate( 'Y-m-d', $end_ts ); } $max_ts = strtotime( "+{$max_span} days", $start_ts ); if ( false !== $max_ts && $end_ts > $max_ts ) { $end_date = gmdate( 'Y-m-d', $max_ts ); $note = "end_date was clamped to {$end_date} (at most {$max_span} days from start_date). Narrow the range or page forward for later dates."; } $query = [ 'meeting_id' => $meeting_id, 'staff_id' => $staff_id, 'start_date' => $start_date, 'end_date' => $end_date, 'timezone' => $timezone, ]; $request = $this->build_request( 'GET', '/timetics/v1/bookings/entries', $query ); if ( is_array( $request ) ) { return $request; } $controller = \Timetics\Core\Bookings\Api_Booking::instance(); $data = $this->extract_response( $controller->get_entries( $request ), 'Failed to get available slots.' ); if ( isset( $data['error'] ) ) { return $data; } $result = [ 'meeting_id' => $meeting_id, 'staff_id' => $staff_id, 'timezone' => $data['availability_timezone'] ?? $timezone, 'days' => $this->shape_slots( $data['days'] ?? [] ), ]; if ( null !== $note ) { $result['note'] = $note; } return $result; } catch ( \Throwable $e ) { Log::error( 'Timetics_Get_Available_Slots_Tool error', [ 'error' => $e->getMessage() ] ); return [ 'error' => 'Failed to get available slots: ' . $e->getMessage() ]; } } }