run(); } } private static function createTables(): void { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; // 1. vizyt_categories $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_categories ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, name varchar(200) NOT NULL, slug varchar(200) NOT NULL, description text NULL, sort_order int NOT NULL DEFAULT 0, created_at datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY slug (slug) ) {$charset_collate};" ); // 2. vizyt_services $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_services ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, category_id bigint(20) unsigned NULL, name varchar(200) NOT NULL, description text NULL, duration int NOT NULL, price decimal(10,2) NOT NULL DEFAULT 0.00, currency varchar(3) NOT NULL DEFAULT 'UAH', buffer_before int NOT NULL DEFAULT 0, buffer_after int NOT NULL DEFAULT 0, min_capacity int NOT NULL DEFAULT 1, max_capacity int NOT NULL DEFAULT 1, status varchar(20) NOT NULL DEFAULT 'active', sort_order int NOT NULL DEFAULT 0, color varchar(7) NULL, image_url text NULL, created_at datetime NOT NULL, updated_at datetime NOT NULL, PRIMARY KEY (id), KEY category_id (category_id), KEY status (status) ) {$charset_collate};" ); // 3. vizyt_staff $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_staff ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, wp_user_id bigint(20) unsigned NULL, name varchar(100) NOT NULL, email varchar(255) NULL, phone varchar(20) NULL, job_title varchar(150) NULL, description text NULL, avatar_url text NULL, status varchar(20) NOT NULL DEFAULT 'active', sort_order int NOT NULL DEFAULT 0, created_at datetime NOT NULL, updated_at datetime NOT NULL, PRIMARY KEY (id), KEY wp_user_id (wp_user_id), KEY status (status) ) {$charset_collate};" ); // 4. vizyt_staff_services $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_staff_services ( staff_id bigint(20) unsigned NOT NULL, service_id bigint(20) unsigned NOT NULL, custom_price decimal(10,2) NULL, custom_duration int NULL, PRIMARY KEY (staff_id,service_id) ) {$charset_collate};" ); // 5. vizyt_schedules $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_schedules ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, staff_id bigint(20) unsigned NOT NULL, day_of_week tinyint(4) NOT NULL, start_time time NOT NULL, end_time time NOT NULL, PRIMARY KEY (id), KEY staff_id (staff_id) ) {$charset_collate};" ); // 6. vizyt_schedule_breaks $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_schedule_breaks ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, schedule_id bigint(20) unsigned NOT NULL, start_time time NOT NULL, end_time time NOT NULL, PRIMARY KEY (id), KEY schedule_id (schedule_id) ) {$charset_collate};" ); // 7. vizyt_special_days $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) // staff_id NULL = the whole business (closure or hours for everybody), 1.5.0. dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_special_days ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, staff_id bigint(20) unsigned NULL, date date NOT NULL, is_working tinyint(1) NOT NULL DEFAULT 0, start_time time NULL, end_time time NULL, description varchar(255) NULL, PRIMARY KEY (id), KEY staff_id (staff_id), KEY date_idx (date) ) {$charset_collate};" ); // 8. vizyt_locations $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_locations ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, name varchar(200) NOT NULL, address text NULL, phone varchar(20) NULL, email varchar(255) NULL, status varchar(20) NOT NULL DEFAULT 'active', sort_order int NOT NULL DEFAULT 0, created_at datetime NOT NULL, updated_at datetime NOT NULL, PRIMARY KEY (id) ) {$charset_collate};" ); // 9. vizyt_customers $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_customers ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, first_name varchar(100) NOT NULL, last_name varchar(100) NULL, email varchar(255) NULL, phone varchar(20) NULL, date_of_birth date NULL, status varchar(20) NOT NULL DEFAULT 'active', notes text NULL, tags varchar(500) NULL, created_at datetime NOT NULL, updated_at datetime NOT NULL, PRIMARY KEY (id), KEY email (email), KEY phone (phone) ) {$charset_collate};" ); // 10. vizyt_bookings $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_bookings ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, customer_id bigint(20) unsigned NOT NULL, service_id bigint(20) unsigned NOT NULL, staff_id bigint(20) unsigned NOT NULL, location_id bigint(20) unsigned NULL, start_datetime datetime NOT NULL, end_datetime datetime NOT NULL, status varchar(20) NOT NULL DEFAULT 'pending', price decimal(10,2) NOT NULL DEFAULT 0.00, currency varchar(3) NOT NULL DEFAULT 'UAH', payment_status varchar(20) NOT NULL DEFAULT 'not_required', cancel_reason text NULL, internal_note text NULL, token varchar(64) NOT NULL, source varchar(20) NOT NULL DEFAULT 'widget', lang varchar(20) NOT NULL DEFAULT '', idempotency_key varchar(64) NULL DEFAULT NULL, ics_sequence int(10) unsigned NOT NULL DEFAULT 0, created_at datetime NOT NULL, updated_at datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY token (token), KEY customer_id (customer_id), KEY staff_booking (staff_id,start_datetime,end_datetime), KEY status (status), KEY status_start (status,start_datetime), KEY idempotency_key (idempotency_key), KEY customer_agg (customer_id,currency,status,start_datetime,price) ) {$charset_collate};" ); // 11. vizyt_customer_notes $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_customer_notes ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, customer_id bigint(20) unsigned NOT NULL, staff_id bigint(20) unsigned NULL, note text NOT NULL, created_at datetime NOT NULL, PRIMARY KEY (id), KEY customer_id (customer_id) ) {$charset_collate};" ); // 12. vizyt_payments $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_payments ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, booking_id bigint(20) unsigned NOT NULL, amount decimal(10,2) NOT NULL, currency varchar(3) NOT NULL DEFAULT 'UAH', provider varchar(50) NOT NULL, provider_transaction_id varchar(255) NULL, status varchar(20) NOT NULL DEFAULT 'pending', created_at datetime NOT NULL, updated_at datetime NOT NULL, PRIMARY KEY (id), KEY booking_id (booking_id) ) {$charset_collate};" ); // 13. vizyt_coupons $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_coupons ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, code varchar(50) NOT NULL, type varchar(20) NOT NULL, value decimal(10,2) NOT NULL, min_order decimal(10,2) NULL, max_uses int NULL, used_count int NOT NULL DEFAULT 0, valid_from datetime NULL, valid_to datetime NULL, status varchar(20) NOT NULL DEFAULT 'active', created_at datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY code (code) ) {$charset_collate};" ); // 14. vizyt_notifications_log $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_notifications_log ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, booking_id bigint(20) unsigned NOT NULL, channel varchar(20) NOT NULL, recipient varchar(255) NOT NULL, subject varchar(255) NULL, status varchar(20) NOT NULL DEFAULT 'sent', sent_at datetime NOT NULL, PRIMARY KEY (id), KEY booking_id (booking_id) ) {$charset_collate};" ); // 15. vizyt_custom_fields $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_custom_fields ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, name varchar(200) NOT NULL, type varchar(50) NOT NULL, options text NULL, required tinyint(1) NOT NULL DEFAULT 0, sort_order int NOT NULL DEFAULT 0, status varchar(20) NOT NULL DEFAULT 'active', created_at datetime NOT NULL, PRIMARY KEY (id) ) {$charset_collate};" ); // 16. vizyt_custom_field_values $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_custom_field_values ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, booking_id bigint(20) unsigned NOT NULL, field_id bigint(20) unsigned NOT NULL, value text NULL, PRIMARY KEY (id), KEY booking_id (booking_id), KEY field_id (field_id) ) {$charset_collate};" ); self::createBookingEventsTable(); } /** * 17. vizyt_booking_events — booking history (3e): status changes, emails, * reminders. Also called by the 1.4.0 migration. */ public static function createBookingEventsTable(): void { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $charset_collate = DbEngine::table_options(); // ENGINE=InnoDB + charset (Vizyt\Support\Tx needs InnoDB) dbDelta( "CREATE TABLE {$wpdb->prefix}vizyt_booking_events ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, booking_id bigint(20) unsigned NOT NULL, type varchar(32) NOT NULL, actor_id bigint(20) unsigned NULL, meta text NULL, created_at datetime NOT NULL, PRIMARY KEY (id), KEY booking_id (booking_id) ) {$charset_collate};" ); } private static function seedDefaults(): void { global $wpdb; $table = $wpdb->prefix . 'vizyt_categories'; $exists = $wpdb->get_var( $wpdb->prepare( 'SELECT id FROM %i WHERE slug = %s LIMIT 1', $table, 'general' ) ); if ( ! $exists ) { $wpdb->insert( $table, [ 'name' => 'General', 'slug' => 'general', 'sort_order' => 0, 'created_at' => current_time( 'mysql', true ), ], [ '%s', '%s', '%d', '%s' ] ); } } private static function addCapabilities(): void { $role = get_role( 'administrator' ); if ( $role ) { $role->add_cap( 'manage_vizyt' ); } } }