prefix . 'twp_phone_schedules'; // Use WordPress timezone $wp_timezone = wp_timezone(); $current_datetime = new DateTime('now', $wp_timezone); $current_time = $current_datetime->format('H:i:s'); $current_day = strtolower($current_datetime->format('l')); $schedules = $wpdb->get_results($wpdb->prepare( "SELECT * FROM $table_name WHERE is_active = 1 AND days_of_week LIKE %s AND start_time <= %s AND end_time >= %s", '%' . $current_day . '%', $current_time, $current_time )); foreach ($schedules as $schedule) { $this->apply_schedule($schedule); } } /** * Apply schedule to phone number */ private function apply_schedule($schedule) { $twilio = new TWP_Twilio_API(); // Get phone numbers $numbers = $twilio->get_phone_numbers(); if ($numbers['success']) { foreach ($numbers['data']['incoming_phone_numbers'] as $number) { if ($number['phone_number'] == $schedule->phone_number) { // Configure webhook based on schedule $webhook_url = home_url('/wp-json/twilio-webhook/v1/voice'); $webhook_url = add_query_arg('schedule_id', $schedule->id, $webhook_url); $twilio->configure_phone_number( $number['sid'], $webhook_url ); break; } } } } /** * Create schedule */ public static function create_schedule($data) { global $wpdb; $table_name = $wpdb->prefix . 'twp_phone_schedules'; // Debug logging - ensure tables exist and columns are correct TWP_Activator::ensure_tables_exist(); // Force column update check global $wpdb; $table_schedules = $wpdb->prefix . 'twp_phone_schedules'; $column_info = $wpdb->get_results("SHOW COLUMNS FROM $table_schedules LIKE 'days_of_week'"); if (!empty($column_info)) { error_log('TWP Create Schedule: Current days_of_week column type: ' . $column_info[0]->Type); if ($column_info[0]->Type === 'varchar(20)') { error_log('TWP Create Schedule: Expanding days_of_week column to varchar(100)'); $wpdb->query("ALTER TABLE $table_schedules MODIFY COLUMN days_of_week varchar(100) NOT NULL"); } } error_log('TWP Create Schedule: Input data: ' . print_r($data, true)); error_log('TWP Create Schedule: Table name: ' . $table_name); $insert_data = array( 'schedule_name' => sanitize_text_field($data['schedule_name']), 'days_of_week' => sanitize_text_field($data['days_of_week']), 'start_time' => sanitize_text_field($data['start_time']), 'end_time' => sanitize_text_field($data['end_time']), 'is_active' => isset($data['is_active']) ? 1 : 0 ); $format = array('%s', '%s', '%s', '%s', '%d'); // Add workflow_id if provided if ($data['workflow_id']) { $insert_data['workflow_id'] = sanitize_text_field($data['workflow_id']); $format[] = '%s'; } // Add optional fields if provided if (!empty($data['phone_number'])) { $insert_data['phone_number'] = sanitize_text_field($data['phone_number']); $format[] = '%s'; } if (!empty($data['forward_number'])) { $insert_data['forward_number'] = sanitize_text_field($data['forward_number']); $format[] = '%s'; } if (!empty($data['after_hours_action'])) { $insert_data['after_hours_action'] = sanitize_text_field($data['after_hours_action']); $format[] = '%s'; } if (!empty($data['after_hours_workflow_id'])) { $insert_data['after_hours_workflow_id'] = sanitize_text_field($data['after_hours_workflow_id']); $format[] = '%s'; } if (!empty($data['after_hours_forward_number'])) { $insert_data['after_hours_forward_number'] = sanitize_text_field($data['after_hours_forward_number']); $format[] = '%s'; } if (isset($data['holiday_dates'])) { $insert_data['holiday_dates'] = sanitize_textarea_field($data['holiday_dates']); $format[] = '%s'; } error_log('TWP Create Schedule: Insert data: ' . print_r($insert_data, true)); error_log('TWP Create Schedule: Insert format: ' . print_r($format, true)); $result = $wpdb->insert($table_name, $insert_data, $format); error_log('TWP Create Schedule: Insert result: ' . ($result ? 'true' : 'false')); if ($result === false) { error_log('TWP Create Schedule: Database error: ' . $wpdb->last_error); } else { $new_id = $wpdb->insert_id; error_log('TWP Create Schedule: New schedule ID: ' . $new_id); } return $result !== false; } /** * Update schedule */ public static function update_schedule($id, $data) { global $wpdb; $table_name = $wpdb->prefix . 'twp_phone_schedules'; $update_data = array(); $update_format = array(); if (isset($data['phone_number'])) { $update_data['phone_number'] = sanitize_text_field($data['phone_number']); $update_format[] = '%s'; } if (isset($data['schedule_name'])) { $update_data['schedule_name'] = sanitize_text_field($data['schedule_name']); $update_format[] = '%s'; } if (isset($data['days_of_week'])) { $update_data['days_of_week'] = sanitize_text_field($data['days_of_week']); $update_format[] = '%s'; } if (isset($data['start_time'])) { $update_data['start_time'] = sanitize_text_field($data['start_time']); $update_format[] = '%s'; } if (isset($data['end_time'])) { $update_data['end_time'] = sanitize_text_field($data['end_time']); $update_format[] = '%s'; } if (isset($data['workflow_id'])) { $update_data['workflow_id'] = sanitize_text_field($data['workflow_id']); $update_format[] = '%s'; } if (isset($data['forward_number'])) { $update_data['forward_number'] = sanitize_text_field($data['forward_number']); $update_format[] = '%s'; } if (isset($data['after_hours_action'])) { $update_data['after_hours_action'] = sanitize_text_field($data['after_hours_action']); $update_format[] = '%s'; } if (isset($data['after_hours_workflow_id'])) { $update_data['after_hours_workflow_id'] = sanitize_text_field($data['after_hours_workflow_id']); $update_format[] = '%s'; } if (isset($data['after_hours_forward_number'])) { $update_data['after_hours_forward_number'] = sanitize_text_field($data['after_hours_forward_number']); $update_format[] = '%s'; } if (isset($data['holiday_dates'])) { $update_data['holiday_dates'] = sanitize_textarea_field($data['holiday_dates']); $update_format[] = '%s'; } if (isset($data['is_active'])) { $update_data['is_active'] = $data['is_active'] ? 1 : 0; $update_format[] = '%d'; } $result = $wpdb->update( $table_name, $update_data, array('id' => $id), $update_format, array('%d') ); return $result !== false; } /** * Delete schedule */ public static function delete_schedule($id) { global $wpdb; $table_name = $wpdb->prefix . 'twp_phone_schedules'; return $wpdb->delete( $table_name, array('id' => $id), array('%d') ); } /** * Get schedules */ public static function get_schedules($phone_number = null) { global $wpdb; $table_name = $wpdb->prefix . 'twp_phone_schedules'; if ($phone_number) { return $wpdb->get_results($wpdb->prepare( "SELECT * FROM $table_name WHERE phone_number = %s ORDER BY created_at DESC", $phone_number )); } else { return $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC"); } } /** * Get schedule by ID */ public static function get_schedule($id) { global $wpdb; $table_name = $wpdb->prefix . 'twp_phone_schedules'; return $wpdb->get_row($wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id )); } /** * Check if schedule is active now */ public static function is_schedule_active($schedule_id) { $schedule = self::get_schedule($schedule_id); if (!$schedule || !$schedule->is_active) { error_log('TWP Schedule: Schedule not found or inactive - ID: ' . $schedule_id); return false; } // Use WordPress timezone for all date/time operations $wp_timezone = wp_timezone(); $current_datetime = new DateTime('now', $wp_timezone); $current_time = $current_datetime->format('H:i:s'); $current_day = strtolower($current_datetime->format('l')); // Monday, Tuesday, etc. $current_date = $current_datetime->format('Y-m-d'); error_log('TWP Schedule: Checking schedule "' . $schedule->schedule_name . '" - Current time: ' . $current_time . ', Current day: ' . $current_day . ', WP Timezone: ' . $wp_timezone->getName()); error_log('TWP Schedule: Schedule days: ' . $schedule->days_of_week . ', Schedule time: ' . $schedule->start_time . ' - ' . $schedule->end_time); // Check if today is a holiday if (self::is_holiday($schedule, $current_date)) { error_log('TWP Schedule: Today is a holiday - treating as after-hours'); return false; // Treat holidays as after-hours } // Check if current day is in schedule if (strpos($schedule->days_of_week, $current_day) === false) { error_log('TWP Schedule: Current day (' . $current_day . ') not in schedule days (' . $schedule->days_of_week . ')'); return false; } // Check if current time is within schedule $is_within_hours = $current_time >= $schedule->start_time && $current_time <= $schedule->end_time; error_log('TWP Schedule: Time check - Current: ' . $current_time . ', Start: ' . $schedule->start_time . ', End: ' . $schedule->end_time . ', Within hours: ' . ($is_within_hours ? 'YES' : 'NO')); return $is_within_hours; } /** * Check if today is a holiday for this schedule */ private static function is_holiday($schedule, $current_date = null) { if (empty($schedule->holiday_dates)) { return false; } if ($current_date === null) { // Use WordPress timezone $wp_timezone = wp_timezone(); $current_datetime = new DateTime('now', $wp_timezone); $current_date = $current_datetime->format('Y-m-d'); } $holidays = array_map('trim', explode(',', $schedule->holiday_dates)); return in_array($current_date, $holidays); } /** * Get appropriate routing for schedule */ public static function get_schedule_routing($schedule_id) { $schedule = self::get_schedule($schedule_id); if (!$schedule || !$schedule->is_active) { return array( 'action' => 'default', 'data' => null ); } $is_within_hours = self::is_schedule_active($schedule_id); if ($is_within_hours) { // Within business hours - use main workflow return array( 'action' => 'workflow', 'data' => array( 'workflow_id' => $schedule->workflow_id ) ); } else { // After hours - use after hours routing if ($schedule->after_hours_action === 'forward' && $schedule->after_hours_forward_number) { return array( 'action' => 'forward', 'data' => array( 'forward_number' => $schedule->after_hours_forward_number ) ); } else if ($schedule->after_hours_action === 'workflow' && $schedule->after_hours_workflow_id) { return array( 'action' => 'workflow', 'data' => array( 'workflow_id' => $schedule->after_hours_workflow_id ) ); } else { // Default to main workflow if no after hours action specified return array( 'action' => 'workflow', 'data' => array( 'workflow_id' => $schedule->workflow_id ) ); } } } }