# booktics/1.0.15/core/appointment/services/appointment-validator.php

Booktics – Appointment Booking Calendar for Service Businesses, version 1.0.15. 146 lines.

- Page: https://pluginprobe.com/plugins/booktics/1.0.15/code/core/appointment/services/appointment-validator.php
- Raw: https://pluginprobe.com/plugins/booktics/1.0.15/raw/core/appointment/services/appointment-validator.php
- Modified: 2026-01-31T15:58:06+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/booktics/1.0.15/code/core/appointment/services/appointment-validator.php#L10-L20`.

```php
<?php
namespace Booktics\Appointment\Services;

use Booktics\Models\Appointment_Model;
use Booktics\Utils\Singleton;
use WP_Error;

class Appointment_Validator {

    use Singleton;

    /**
     * Validate data for creating an appointment.
     * @param array $data
     * @return WP_Error|null
     */
    public static function validate_create( array $data ) {
        if ( empty( $data['start_time'] ) ) {
            return new WP_Error( 'missing_start_time', __( 'Start time is required', 'booktics' ) );
        }
        if ( empty( $data['end_time'] ) ) {
            return new WP_Error( 'missing_end_time', __( 'End time is required', 'booktics' ) );
        }
        if ( empty( $data['date'] ) ) {
            return new WP_Error( 'missing_date', __( 'Date is required', 'booktics' ) );
        }
        if ( empty( $data['service_id'] ) ) {
            return new WP_Error( 'missing_service_id', __( 'Service ID is required', 'booktics' ) );
        }
        if ( empty( $data['team_member_id'] ) ) {
            return new WP_Error( 'missing_team_member_id', __( 'Team member ID is required', 'booktics' ) );
        }
        // Add more validation as needed
        return null;
    }

    /**
     * Validate data for updating an appointment.
     * @param array $data
     * @return WP_Error|null
     */
    public static function validate_update( array $data ): ?WP_Error {
        if ( empty( $data ) ) {
            return new WP_Error( 'no_data', __( 'No data provided for update', 'booktics' ) );
        }
        // Optionally, check for required fields on update
        return null;
    }

    /**
     * Validate data for rescheduling an appointment.
     * @param array $data
     * @return WP_Error|null
     */
    public static function validate_reschedule( array $data, $id ) {
        if ( empty( $data['start_time'] ) ) {
            return new WP_Error( 'missing_start_time', __( 'Start time is required for reschedule', 'booktics' ) );
        }
        if ( empty( $data['end_time'] ) ) {
            return new WP_Error( 'missing_end_time', __( 'End time is required for reschedule', 'booktics' ) );
        }
        if ( empty( $data['date'] ) ) {
            return new WP_Error( 'missing_date', __( 'Date is required for reschedule', 'booktics' ) );
        }
        if ( ! booktics_get_option( 'allow_customer_rescheduling', false ) ) {
            return new WP_Error( 'reschedule_setting', __( 'Customer rescheduling is not allowed', 'booktics' ) );
        }

        if ( empty( $data['security_token'] ) ) {
            return new WP_Error( 'missing_appointment_token', __( 'Appointment token is required for reschedule', 'booktics' ) );
        }

        $appointment = Appointment_Model::find( $id );

        if ( ! $appointment ) {
            return new WP_Error( 'appointment_not_found', __( 'Appointment not found', 'booktics' ) );
        }

        if ( $appointment->status === 'canceled' ) {
            return new WP_Error( 'appointment_cancelled', __( 'This Appointment has already been cancelled', 'booktics' ) );
        }

        if ( $appointment->security_token !== $data['security_token'] && ! current_user_can('manage_options')) {
            return new WP_Error( 'invalid_security_token', __( 'You dont have permission for rescheduling this appointment', 'booktics' ) );
        }

        $reschedule_restrictions = booktics_get_option( 'reschedule_restriction', array( 'enable' => false ) );
        if ( isset( $reschedule_restrictions['enable'] ) && $reschedule_restrictions['enable'] ) {
            $restricted_time = $reschedule_restrictions['restricted_time'] ?? 0;
            $restricted_unit = $reschedule_restrictions['restricted_unit'] ?? 'hr';
            $restricted_min  = $restricted_unit === 'min' ? $restricted_time : $restricted_time * 60;

            $current_time = (int) wp_date( 'U' );
            $appointment_time = strtotime( $appointment->date . ' ' . $appointment->start_time );
            if ( $appointment_time < $current_time + $restricted_min ) {
                return new WP_Error(
                    'reschedule_restricted', sprintf(
                        __( 'You can only reschedule appointments at least %1$d %2$s before the appointment time.', 'booktics' ),
                        $restricted_time,
                        $restricted_unit
                    )
                );
            }
        }

        return null;
    }

    /**
     * Validate data for canceling an appointment.
     * @param int $id
     * @return WP_Error|null
     */
    public function validate_cancel( $id ) {
        if ( ! booktics_get_option( 'allow_customer_cancellation', false ) ) {
            return new WP_Error( 'cancellation_setting', __( 'Customer cancellation is not allowed', 'booktics' ) );
        }

        $cancellation_restrictions = booktics_get_option( 'cancellation_restriction', array( 'enable' => false ) );
        if ( isset( $cancellation_restrictions['enable'] ) && $cancellation_restrictions['enable'] ) {
            $restricted_time = $cancellation_restrictions['restricted_time'] ?? 0;
            $restricted_unit = $cancellation_restrictions['restricted_unit'] ?? 'hr';
            $restricted_min  = $restricted_unit === 'min' ? $restricted_time : $restricted_time * 60;
            $appointment = Appointment_Model::find( $id );

            if ( ! $appointment ) {
                return new WP_Error( 'appointment_not_found', __( 'Appointment not found', 'booktics' ) );
            }

            $current_time = (int) wp_date( 'U' );
            $appointment_time = strtotime( $appointment->date . ' ' . $appointment->start_time );
            if ( $appointment_time < $current_time + $restricted_min ) {
                return new WP_Error(
                    'cancellation_restricted', sprintf(
                        __( 'You can only cancel appointments at least %1$d %2$s before the appointment time.', 'booktics' ),
                        $restricted_time,
                        $restricted_unit
                    )
                );
            }
        }

        return null;
    }
}

```
