progress made
This commit is contained in:
@@ -32,7 +32,13 @@ class TWP_Call_Queue {
|
||||
array('%d', '%s', '%s', '%s', '%d', '%s')
|
||||
);
|
||||
|
||||
return $result !== false ? $position : false;
|
||||
if ($result !== false) {
|
||||
// Notify agents via SMS when a new call enters the queue
|
||||
self::notify_agents_for_queue($queue_id, $call_data['from_number']);
|
||||
return $position;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,10 +126,17 @@ class TWP_Call_Queue {
|
||||
$table_name = $wpdb->prefix . 'twp_queued_calls';
|
||||
$queue_table = $wpdb->prefix . 'twp_call_queues';
|
||||
|
||||
error_log('TWP Queue Process: Starting queue processing');
|
||||
|
||||
// Get all active queues
|
||||
$queues = $wpdb->get_results("SELECT * FROM $queue_table");
|
||||
|
||||
foreach ($queues as $queue) {
|
||||
error_log('TWP Queue Process: Processing queue ' . $queue->queue_name . ' (ID: ' . $queue->id . ')');
|
||||
|
||||
// First, try to assign agents to waiting calls
|
||||
$this->assign_agents_to_waiting_calls($queue);
|
||||
|
||||
// Check for timed out calls
|
||||
$timeout_time = date('Y-m-d H:i:s', strtotime('-' . $queue->timeout_seconds . ' seconds'));
|
||||
|
||||
@@ -137,6 +150,7 @@ class TWP_Call_Queue {
|
||||
));
|
||||
|
||||
foreach ($timed_out_calls as $call) {
|
||||
error_log('TWP Queue Process: Handling timeout for call ' . $call->call_sid);
|
||||
// Handle timeout
|
||||
$this->handle_timeout($call, $queue);
|
||||
}
|
||||
@@ -144,6 +158,8 @@ class TWP_Call_Queue {
|
||||
// Update caller positions and play position messages
|
||||
$this->update_queue_positions($queue->id);
|
||||
}
|
||||
|
||||
error_log('TWP Queue Process: Finished queue processing');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,13 +186,152 @@ class TWP_Call_Queue {
|
||||
|
||||
$twilio = new TWP_Twilio_API();
|
||||
$twilio->update_call($call->call_sid, array(
|
||||
'Twiml' => $callback_twiml
|
||||
'twiml' => $callback_twiml
|
||||
));
|
||||
|
||||
// Reorder queue
|
||||
self::reorder_queue($queue->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign agents to waiting calls
|
||||
*/
|
||||
private function assign_agents_to_waiting_calls($queue) {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'twp_queued_calls';
|
||||
|
||||
// Get waiting calls in order
|
||||
$waiting_calls = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT * FROM $table_name
|
||||
WHERE queue_id = %d AND status = 'waiting'
|
||||
ORDER BY position ASC",
|
||||
$queue->id
|
||||
));
|
||||
|
||||
if (empty($waiting_calls)) {
|
||||
return;
|
||||
}
|
||||
|
||||
error_log('TWP Queue Process: Found ' . count($waiting_calls) . ' waiting calls in queue ' . $queue->queue_name);
|
||||
|
||||
// Get available agents for this queue
|
||||
$available_agents = $this->get_available_agents_for_queue($queue);
|
||||
|
||||
if (empty($available_agents)) {
|
||||
error_log('TWP Queue Process: No available agents for queue ' . $queue->queue_name);
|
||||
return;
|
||||
}
|
||||
|
||||
error_log('TWP Queue Process: Found ' . count($available_agents) . ' available agents');
|
||||
|
||||
// Assign agents to calls (one agent per call)
|
||||
$assignments = 0;
|
||||
foreach ($waiting_calls as $call) {
|
||||
if ($assignments >= count($available_agents)) {
|
||||
break; // No more agents available
|
||||
}
|
||||
|
||||
$agent = $available_agents[$assignments];
|
||||
error_log('TWP Queue Process: Attempting to assign call ' . $call->call_sid . ' to agent ' . $agent['phone']);
|
||||
|
||||
// Try to bridge the call to the agent
|
||||
if ($this->bridge_call_to_agent($call, $agent, $queue)) {
|
||||
$assignments++;
|
||||
error_log('TWP Queue Process: Successfully initiated bridge for call ' . $call->call_sid);
|
||||
} else {
|
||||
error_log('TWP Queue Process: Failed to bridge call ' . $call->call_sid . ' to agent');
|
||||
}
|
||||
}
|
||||
|
||||
error_log('TWP Queue Process: Made ' . $assignments . ' call assignments');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available agents for a queue
|
||||
*/
|
||||
private function get_available_agents_for_queue($queue) {
|
||||
// If queue has assigned agent groups, get agents from those groups
|
||||
if (!empty($queue->agent_groups)) {
|
||||
$group_ids = explode(',', $queue->agent_groups);
|
||||
$agents = array();
|
||||
|
||||
foreach ($group_ids as $group_id) {
|
||||
$group_agents = TWP_Agent_Manager::get_available_agents(intval($group_id));
|
||||
if ($group_agents) {
|
||||
$agents = array_merge($agents, $group_agents);
|
||||
}
|
||||
}
|
||||
|
||||
return $agents;
|
||||
}
|
||||
|
||||
// Fallback to all available agents
|
||||
return TWP_Agent_Manager::get_available_agents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge call to agent
|
||||
*/
|
||||
private function bridge_call_to_agent($call, $agent, $queue) {
|
||||
$twilio = new TWP_Twilio_API();
|
||||
|
||||
try {
|
||||
// Create a new call to the agent
|
||||
$agent_call_data = array(
|
||||
'to' => $agent['phone'],
|
||||
'from' => $queue->caller_id ?: $call->to_number, // Use queue caller ID or original number
|
||||
'url' => home_url('/wp-json/twilio-webhook/v1/agent-connect?' . http_build_query(array(
|
||||
'customer_call_sid' => $call->call_sid,
|
||||
'customer_number' => $call->from_number,
|
||||
'queue_id' => $queue->id,
|
||||
'agent_phone' => $agent['phone'],
|
||||
'queued_call_id' => $call->id
|
||||
))),
|
||||
'method' => 'POST',
|
||||
'timeout' => 20,
|
||||
'statusCallback' => home_url('/wp-json/twilio-webhook/v1/agent-call-status'),
|
||||
'statusCallbackEvent' => array('answered', 'completed', 'busy', 'no-answer'),
|
||||
'statusCallbackMethod' => 'POST'
|
||||
);
|
||||
|
||||
error_log('TWP Queue Bridge: Creating agent call with data: ' . json_encode($agent_call_data));
|
||||
|
||||
$agent_call_response = $twilio->create_call($agent_call_data);
|
||||
|
||||
if ($agent_call_response['success']) {
|
||||
// Update call status to indicate agent is being contacted
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'twp_queued_calls';
|
||||
|
||||
$updated = $wpdb->update(
|
||||
$table_name,
|
||||
array(
|
||||
'status' => 'connecting',
|
||||
'agent_phone' => $agent['phone'],
|
||||
'agent_call_sid' => $agent_call_response['data']['sid']
|
||||
),
|
||||
array('call_sid' => $call->call_sid),
|
||||
array('%s', '%s', '%s'),
|
||||
array('%s')
|
||||
);
|
||||
|
||||
if ($updated) {
|
||||
error_log('TWP Queue Bridge: Updated call status to connecting');
|
||||
return true;
|
||||
} else {
|
||||
error_log('TWP Queue Bridge: Failed to update call status');
|
||||
}
|
||||
} else {
|
||||
error_log('TWP Queue Bridge: Failed to create agent call: ' . ($agent_call_response['error'] ?? 'Unknown error'));
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('TWP Queue Bridge: Exception bridging call: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update queue positions
|
||||
*/
|
||||
@@ -241,7 +396,7 @@ class TWP_Call_Queue {
|
||||
}
|
||||
|
||||
$twilio->update_call($call->call_sid, array(
|
||||
'Twiml' => $twiml->asXML()
|
||||
'twiml' => $twiml->asXML()
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -278,16 +433,58 @@ class TWP_Call_Queue {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'twp_call_queues';
|
||||
|
||||
return $wpdb->insert(
|
||||
$insert_data = array(
|
||||
'queue_name' => sanitize_text_field($data['queue_name']),
|
||||
'phone_number' => !empty($data['phone_number']) ? sanitize_text_field($data['phone_number']) : '',
|
||||
'agent_group_id' => !empty($data['agent_group_id']) ? intval($data['agent_group_id']) : null,
|
||||
'max_size' => intval($data['max_size']),
|
||||
'wait_music_url' => esc_url_raw($data['wait_music_url']),
|
||||
'tts_message' => sanitize_textarea_field($data['tts_message']),
|
||||
'timeout_seconds' => intval($data['timeout_seconds'])
|
||||
);
|
||||
|
||||
$insert_format = array('%s', '%s');
|
||||
if ($insert_data['agent_group_id'] === null) {
|
||||
$insert_format[] = null;
|
||||
} else {
|
||||
$insert_format[] = '%d';
|
||||
}
|
||||
$insert_format = array_merge($insert_format, array('%d', '%s', '%s', '%d'));
|
||||
|
||||
return $wpdb->insert($table_name, $insert_data, $insert_format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update queue
|
||||
*/
|
||||
public static function update_queue($queue_id, $data) {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'twp_call_queues';
|
||||
|
||||
$update_data = array(
|
||||
'queue_name' => sanitize_text_field($data['queue_name']),
|
||||
'phone_number' => !empty($data['phone_number']) ? sanitize_text_field($data['phone_number']) : '',
|
||||
'agent_group_id' => !empty($data['agent_group_id']) ? intval($data['agent_group_id']) : null,
|
||||
'max_size' => intval($data['max_size']),
|
||||
'wait_music_url' => esc_url_raw($data['wait_music_url']),
|
||||
'tts_message' => sanitize_textarea_field($data['tts_message']),
|
||||
'timeout_seconds' => intval($data['timeout_seconds'])
|
||||
);
|
||||
|
||||
$update_format = array('%s', '%s');
|
||||
if ($update_data['agent_group_id'] === null) {
|
||||
$update_format[] = null;
|
||||
} else {
|
||||
$update_format[] = '%d';
|
||||
}
|
||||
$update_format = array_merge($update_format, array('%d', '%s', '%s', '%d'));
|
||||
|
||||
return $wpdb->update(
|
||||
$table_name,
|
||||
array(
|
||||
'queue_name' => sanitize_text_field($data['queue_name']),
|
||||
'max_size' => intval($data['max_size']),
|
||||
'wait_music_url' => esc_url_raw($data['wait_music_url']),
|
||||
'tts_message' => sanitize_textarea_field($data['tts_message']),
|
||||
'timeout_seconds' => intval($data['timeout_seconds'])
|
||||
),
|
||||
array('%s', '%d', '%s', '%s', '%d')
|
||||
$update_data,
|
||||
array('id' => intval($queue_id)),
|
||||
$update_format,
|
||||
array('%d')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -358,4 +555,56 @@ class TWP_Call_Queue {
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify agents via SMS when a call enters the queue
|
||||
*/
|
||||
private static function notify_agents_for_queue($queue_id, $caller_number) {
|
||||
global $wpdb;
|
||||
|
||||
// Get queue information including assigned agent group and phone number
|
||||
$queue_table = $wpdb->prefix . 'twp_call_queues';
|
||||
$queue = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM $queue_table WHERE id = %d",
|
||||
$queue_id
|
||||
));
|
||||
|
||||
if (!$queue || !$queue->agent_group_id) {
|
||||
error_log("TWP: No agent group assigned to queue {$queue_id}, skipping SMS notifications");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get members of the assigned agent group
|
||||
require_once dirname(__FILE__) . '/class-twp-agent-groups.php';
|
||||
$members = TWP_Agent_Groups::get_group_members($queue->agent_group_id);
|
||||
|
||||
if (empty($members)) {
|
||||
error_log("TWP: No members found in agent group {$queue->agent_group_id} for queue {$queue_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
$twilio = new TWP_Twilio_API();
|
||||
|
||||
// Use the queue's phone number as the from number, or fall back to default
|
||||
$from_number = !empty($queue->phone_number) ? $queue->phone_number : TWP_Twilio_API::get_sms_from_number();
|
||||
|
||||
if (empty($from_number)) {
|
||||
error_log("TWP: No SMS from number available for queue notifications");
|
||||
return;
|
||||
}
|
||||
|
||||
$message = "Call waiting in queue '{$queue->queue_name}' from {$caller_number}. Text '1' to this number to receive the next available call.";
|
||||
|
||||
foreach ($members as $member) {
|
||||
$agent_phone = get_user_meta($member->user_id, 'twp_phone_number', true);
|
||||
|
||||
if (!empty($agent_phone)) {
|
||||
// Send SMS notification using the queue's phone number
|
||||
$twilio->send_sms($agent_phone, $message, $from_number);
|
||||
|
||||
// Log the notification
|
||||
error_log("TWP: Queue SMS notification sent to agent {$member->user_id} at {$agent_phone} from {$from_number} for queue {$queue_id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user