Files
twilio-wp-plugin/includes/class-twp-scheduler.php

388 lines
14 KiB
PHP
Raw Normal View History

2025-08-06 15:25:47 -07:00
<?php
/**
* Phone schedule management class
*/
class TWP_Scheduler {
/**
* Check active schedules
*/
public function check_active_schedules() {
global $wpdb;
$table_name = $wpdb->prefix . 'twp_phone_schedules';
2025-08-11 20:31:48 -07:00
// 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'));
2025-08-06 15:25:47 -07:00
$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
2025-08-11 20:31:48 -07:00
$webhook_url = home_url('/wp-json/twilio-webhook/v1/voice');
2025-08-06 15:25:47 -07:00
$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';
2025-08-11 20:31:48 -07:00
// 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);
2025-08-06 15:25:47 -07:00
$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
);
2025-08-11 20:31:48 -07:00
$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';
}
2025-08-06 15:25:47 -07:00
// 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';
}
2025-08-11 20:31:48 -07:00
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));
2025-08-06 15:25:47 -07:00
$result = $wpdb->insert($table_name, $insert_data, $format);
2025-08-11 20:31:48 -07:00
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);
}
2025-08-06 15:25:47 -07:00
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';
}
2025-08-11 20:31:48 -07:00
if (isset($data['holiday_dates'])) {
$update_data['holiday_dates'] = sanitize_textarea_field($data['holiday_dates']);
$update_format[] = '%s';
}
2025-08-06 15:25:47 -07:00
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) {
2025-08-11 20:31:48 -07:00
error_log('TWP Schedule: Schedule not found or inactive - ID: ' . $schedule_id);
2025-08-06 15:25:47 -07:00
return false;
}
2025-08-11 20:31:48 -07:00
// 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
}
2025-08-06 15:25:47 -07:00
// Check if current day is in schedule
if (strpos($schedule->days_of_week, $current_day) === false) {
2025-08-11 20:31:48 -07:00
error_log('TWP Schedule: Current day (' . $current_day . ') not in schedule days (' . $schedule->days_of_week . ')');
2025-08-06 15:25:47 -07:00
return false;
}
// Check if current time is within schedule
2025-08-11 20:31:48 -07:00
$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);
2025-08-06 15:25:47 -07:00
}
/**
* 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
)
);
}
}
}
}