getInputs(); $title = $this->resolve_service_title( $inputs['service_id'] ?? 0 ); $service_name = '' !== $title ? $title : ( 'service #' . ( $inputs['service_id'] ?? '?' ) ); $member = $this->team_member_name( $inputs['team_member_id'] ?? 0 ); $member = '' !== $member ? $member : ( 'team member #' . ( $inputs['team_member_id'] ?? '?' ) ); $when = trim( ( $inputs['date'] ?? '' ) . ' ' . ( $inputs['start_time'] ?? '' ) ); return "Book \"{$service_name}\" with {$member} on {$when}"; } /** * Human-readable inputs shown in the approval card table. * * @return array */ public function get_approval_inputs(): array { $inputs = $this->getInputs(); if ( ! empty( $inputs['service_id'] ) ) { $title = $this->resolve_service_title( $inputs['service_id'] ); if ( '' !== $title ) { $inputs['service_id'] = $title . ' (ID: ' . $inputs['service_id'] . ')'; } } if ( ! empty( $inputs['team_member_id'] ) ) { $name = $this->team_member_name( $inputs['team_member_id'] ); if ( '' !== $name ) { $inputs['team_member_id'] = $name . ' (ID: ' . $inputs['team_member_id'] . ')'; } } return $inputs; } /** * Resolve a service's title from its ID for the approval card. * * @param int|string $service_id Service ID. * @return string Title, or '' when the service is missing. */ private function resolve_service_title( $service_id ): string { $service_id = (int) $service_id; if ( $service_id <= 0 ) { return ''; } $service = \Booktics\Models\Service_Model::find( $service_id ); return $service ? (string) $service->title : ''; } /** * Execute the tool after human approval. * * @param int $service_id Service ID. * @param int $team_member_id Team-member (WP user) ID. * @param string $date Date (Y-m-d). * @param string $start_time Start time (HH:MM). * @param string $end_time End time (HH:MM). * @param int|null $customer_id Existing customer (guest) ID. * @param string|null $customer_name Customer name. * @param string|null $status Initial status. * @param int|null $total_attendees Attendee count. * @param string|null $note Internal note. * @return array */ public function __invoke( int $service_id, int $team_member_id, string $date, string $start_time, string $end_time, ?int $customer_id = null, ?string $customer_name = null, ?string $status = null, ?int $total_attendees = null, ?string $note = null ): array { $check = $this->guard_admin(); if ( $check ) { return $check; } $validation = $this->validate_core_fields( $service_id, $team_member_id, $date, $start_time, $end_time ); if ( $validation ) { return $validation; } if ( null !== $status && ! in_array( $status, self::ALLOWED_STATUSES, true ) ) { return [ 'error' => "Invalid status '{$status}'. Accepted values: " . implode( ', ', self::ALLOWED_STATUSES ) . '.' ]; } try { $body = [ 'service_id' => $service_id, 'team_member_id' => $team_member_id, 'date' => $date, 'start_time' => $start_time, 'end_time' => $end_time, 'status' => $status ?? 'active', 'total_attendees' => null !== $total_attendees ? max( 1, $total_attendees ) : 1, ]; if ( null !== $customer_id ) { $body['customer_id'] = $customer_id; } if ( null !== $customer_name ) { $body['customer_name'] = sanitize_text_field( $customer_name ); } if ( null !== $note ) { $body['note'] = sanitize_textarea_field( $note ); } $request = $this->build_json_request( 'POST', '/booktics/v1/appointments', $body ); if ( is_array( $request ) ) { return $request; } $controller = new \Booktics\Appointment\Controllers\Appointment_Controller(); $data = $this->extract_response( $controller->create_item( $request ), 'Failed to create appointment.' ); if ( isset( $data['error'] ) ) { return $data; } $id = (int) ( $data['id'] ?? 0 ); if ( $id <= 0 ) { Log::error( 'Booktics_Create_Appointment_Tool got a success response without an ID', [ 'data_keys' => array_keys( $data ) ] ); return [ 'error' => 'The appointment may not have been created; Booktics returned no ID. Please verify in Booktics before retrying.' ]; } return [ 'success' => true, 'appointment_id' => $id, 'message' => "Appointment booked successfully (ID: {$id}) on {$date} at {$start_time}.", ]; } catch ( \Throwable $e ) { Log::error( 'Booktics_Create_Appointment_Tool error', [ 'error' => $e->getMessage() ] ); return [ 'error' => 'Failed to create appointment: ' . $e->getMessage() ]; } } /** * Validate the required booking fields and referenced records. * * @param int $service_id Service ID. * @param int $team_member_id Team-member ID. * @param string $date Date (Y-m-d). * @param string $start_time Start time (HH:MM). * @param string $end_time End time (HH:MM). * @return array|null Error array on failure, null when valid. */ private function validate_core_fields( int $service_id, int $team_member_id, string $date, string $start_time, string $end_time ): ?array { if ( $service_id <= 0 || $team_member_id <= 0 ) { return [ 'error' => 'A valid service_id and team_member_id are required.' ]; } $datetime_error = $this->validate_appointment_datetime( $date, $start_time, $end_time ); if ( $datetime_error ) { return $datetime_error; } if ( ! \Booktics\Models\Service_Model::find( $service_id ) ) { return [ 'error' => "Service #{$service_id} was not found. Use booktics-list-services to find a valid ID." ]; } if ( ! get_userdata( $team_member_id ) ) { return [ 'error' => "Team member #{$team_member_id} was not found. Provide the WordPress user ID of a Booktics team member." ]; } return null; } }