testing progress
This commit is contained in:
@@ -101,7 +101,7 @@ class TWP_Activator {
|
||||
$sql_queues = "CREATE TABLE $table_queues (
|
||||
id int(11) NOT NULL AUTO_INCREMENT,
|
||||
queue_name varchar(100) NOT NULL,
|
||||
phone_number varchar(20),
|
||||
notification_number varchar(20),
|
||||
agent_group_id int(11),
|
||||
max_size int(11) DEFAULT 10,
|
||||
wait_music_url varchar(255),
|
||||
@@ -110,7 +110,7 @@ class TWP_Activator {
|
||||
created_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY agent_group_id (agent_group_id),
|
||||
KEY phone_number (phone_number)
|
||||
KEY notification_number (notification_number)
|
||||
) $charset_collate;";
|
||||
|
||||
// Queued calls table
|
||||
@@ -304,20 +304,29 @@ class TWP_Activator {
|
||||
$wpdb->query("ALTER TABLE $table_schedules MODIFY COLUMN days_of_week varchar(100) NOT NULL");
|
||||
}
|
||||
|
||||
// Add new columns to call queues table
|
||||
// Add new columns to call queues table and migrate phone_number to notification_number
|
||||
$table_queues = $wpdb->prefix . 'twp_call_queues';
|
||||
|
||||
// Check if phone_number column exists in queues table
|
||||
// Check if phone_number column exists and notification_number doesn't - need migration
|
||||
$phone_column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'phone_number'");
|
||||
if (empty($phone_column_exists)) {
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN phone_number varchar(20) AFTER queue_name");
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD INDEX phone_number (phone_number)");
|
||||
$notification_column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'notification_number'");
|
||||
|
||||
if (!empty($phone_column_exists) && empty($notification_column_exists)) {
|
||||
// Migrate phone_number to notification_number
|
||||
$wpdb->query("ALTER TABLE $table_queues CHANGE phone_number notification_number varchar(20)");
|
||||
// Update the index name
|
||||
$wpdb->query("ALTER TABLE $table_queues DROP INDEX phone_number");
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD INDEX notification_number (notification_number)");
|
||||
} elseif (empty($phone_column_exists) && empty($notification_column_exists)) {
|
||||
// Fresh installation - add notification_number column
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN notification_number varchar(20) AFTER queue_name");
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD INDEX notification_number (notification_number)");
|
||||
}
|
||||
|
||||
// Check if agent_group_id column exists in queues table
|
||||
$group_column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'agent_group_id'");
|
||||
if (empty($group_column_exists)) {
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN agent_group_id int(11) AFTER phone_number");
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN agent_group_id int(11) AFTER notification_number");
|
||||
$wpdb->query("ALTER TABLE $table_queues ADD INDEX agent_group_id (agent_group_id)");
|
||||
}
|
||||
|
||||
|
@@ -243,18 +243,18 @@ class TWP_Agent_Manager {
|
||||
// Make a new call to the agent with proper caller ID
|
||||
$twilio = new TWP_Twilio_API();
|
||||
|
||||
// Get the queue's phone number for proper caller ID (same logic as SMS webhook)
|
||||
// Get the queue's notification number for proper caller ID (same logic as SMS webhook)
|
||||
$queues_table = $wpdb->prefix . 'twp_call_queues';
|
||||
$queue_info = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT phone_number FROM $queues_table WHERE id = %d",
|
||||
"SELECT notification_number FROM $queues_table WHERE id = %d",
|
||||
$call->queue_id
|
||||
));
|
||||
|
||||
// Priority: 1) Queue's phone number, 2) Call's original to_number, 3) Default SMS number
|
||||
// Priority: 1) Queue's notification number, 2) Call's original to_number, 3) Default SMS number
|
||||
$workflow_number = null;
|
||||
if (!empty($queue_info->phone_number)) {
|
||||
$workflow_number = $queue_info->phone_number;
|
||||
error_log('TWP Web Accept: Using queue phone number: ' . $workflow_number);
|
||||
if (!empty($queue_info->notification_number)) {
|
||||
$workflow_number = $queue_info->notification_number;
|
||||
error_log('TWP Web Accept: Using queue notification number: ' . $workflow_number);
|
||||
} elseif (!empty($call->to_number)) {
|
||||
$workflow_number = $call->to_number;
|
||||
error_log('TWP Web Accept: Using original workflow number: ' . $workflow_number);
|
||||
|
@@ -435,7 +435,7 @@ class TWP_Call_Queue {
|
||||
|
||||
$insert_data = array(
|
||||
'queue_name' => sanitize_text_field($data['queue_name']),
|
||||
'phone_number' => !empty($data['phone_number']) ? sanitize_text_field($data['phone_number']) : '',
|
||||
'notification_number' => !empty($data['notification_number']) ? sanitize_text_field($data['notification_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']),
|
||||
@@ -463,7 +463,7 @@ class TWP_Call_Queue {
|
||||
|
||||
$update_data = array(
|
||||
'queue_name' => sanitize_text_field($data['queue_name']),
|
||||
'phone_number' => !empty($data['phone_number']) ? sanitize_text_field($data['phone_number']) : '',
|
||||
'notification_number' => !empty($data['notification_number']) ? sanitize_text_field($data['notification_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']),
|
||||
@@ -585,8 +585,8 @@ class TWP_Call_Queue {
|
||||
|
||||
$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();
|
||||
// Use the queue's notification number as the from number, or fall back to default
|
||||
$from_number = !empty($queue->notification_number) ? $queue->notification_number : TWP_Twilio_API::get_sms_from_number();
|
||||
|
||||
if (empty($from_number)) {
|
||||
error_log("TWP: No SMS from number available for queue notifications");
|
||||
|
@@ -767,57 +767,121 @@ class TWP_Webhooks {
|
||||
/**
|
||||
* Handle IVR response
|
||||
*/
|
||||
private function handle_ivr_response() {
|
||||
$digits = isset($_POST['Digits']) ? $_POST['Digits'] : '';
|
||||
$workflow_id = isset($_GET['workflow_id']) ? intval($_GET['workflow_id']) : 0;
|
||||
$step_id = isset($_GET['step_id']) ? intval($_GET['step_id']) : 0;
|
||||
public function handle_ivr_response($request) {
|
||||
$digits = $request->get_param('Digits') ?: '';
|
||||
$workflow_id = intval($request->get_param('workflow_id') ?: 0);
|
||||
$step_id = intval($request->get_param('step_id') ?: 0);
|
||||
|
||||
// Debug logging
|
||||
error_log('TWP IVR: Received digits="' . $digits . '", workflow_id=' . $workflow_id . ', step_id=' . $step_id);
|
||||
error_log('TWP IVR: All request params: ' . json_encode($request->get_params()));
|
||||
|
||||
if (!$workflow_id || !$step_id) {
|
||||
$this->send_default_response();
|
||||
return;
|
||||
return $this->send_twiml_response($this->get_default_twiml());
|
||||
}
|
||||
|
||||
$workflow = TWP_Workflow::get_workflow($workflow_id);
|
||||
|
||||
if (!$workflow) {
|
||||
$this->send_default_response();
|
||||
return;
|
||||
return $this->send_twiml_response($this->get_default_twiml());
|
||||
}
|
||||
|
||||
$workflow_data = json_decode($workflow->workflow_data, true);
|
||||
|
||||
// Debug: log all steps in workflow
|
||||
error_log('TWP IVR: Looking for step_id ' . $step_id . ' in workflow ' . $workflow_id);
|
||||
foreach ($workflow_data['steps'] as $index => $step) {
|
||||
error_log('TWP IVR: Step ' . $index . ' has ID: ' . (isset($step['id']) ? $step['id'] : 'NO ID'));
|
||||
}
|
||||
|
||||
// Find the step and its options
|
||||
foreach ($workflow_data['steps'] as $step) {
|
||||
if ($step['id'] == $step_id && isset($step['options'][$digits])) {
|
||||
$option = $step['options'][$digits];
|
||||
if ($step['id'] == $step_id) {
|
||||
error_log('TWP IVR: Found matching step with ID ' . $step_id);
|
||||
// Options can be in step['data']['options'] or step['options']
|
||||
$options = isset($step['data']['options']) ? $step['data']['options'] :
|
||||
(isset($step['options']) ? $step['options'] : array());
|
||||
|
||||
switch ($option['action']) {
|
||||
// Debug: log all available options
|
||||
error_log('TWP IVR: All available options for step ' . $step_id . ': ' . json_encode($options));
|
||||
|
||||
if (isset($options[$digits])) {
|
||||
$option = $options[$digits];
|
||||
|
||||
// Log for debugging
|
||||
error_log('TWP IVR: Found option for digit ' . $digits . ': ' . json_encode($option));
|
||||
|
||||
switch ($option['action']) {
|
||||
case 'forward':
|
||||
$twiml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><Response></Response>');
|
||||
$dial = $twiml->addChild('Dial');
|
||||
$dial->addChild('Number', $option['number']);
|
||||
echo $twiml->asXML();
|
||||
return;
|
||||
return $this->send_twiml_response($twiml->asXML());
|
||||
|
||||
case 'queue':
|
||||
// Determine queue ID - could be in queue_id field or legacy queue_name field
|
||||
$queue_id = null;
|
||||
if (isset($option['queue_id']) && is_numeric($option['queue_id']) && $option['queue_id'] > 0) {
|
||||
$queue_id = intval($option['queue_id']);
|
||||
} elseif (isset($option['queue_name']) && is_numeric($option['queue_name']) && $option['queue_name'] > 0) {
|
||||
// Legacy format where queue_name contains the queue ID
|
||||
$queue_id = intval($option['queue_name']);
|
||||
} elseif (isset($option['number']) && is_numeric($option['number']) && $option['number'] > 0) {
|
||||
// Another legacy format where number contains the queue ID
|
||||
$queue_id = intval($option['number']);
|
||||
}
|
||||
|
||||
error_log('TWP IVR Queue: Determined queue_id=' . ($queue_id ? $queue_id : 'NULL') . ' from option: ' . json_encode($option));
|
||||
|
||||
// Use the TWP queue system if we have a valid queue_id
|
||||
if ($queue_id && $queue_id > 0) {
|
||||
$call_data = array(
|
||||
'call_sid' => $request->get_param('CallSid'),
|
||||
'from_number' => $request->get_param('From'),
|
||||
'to_number' => $request->get_param('To')
|
||||
);
|
||||
|
||||
error_log('TWP IVR Queue: Adding call to queue_id=' . $queue_id . ', call_sid=' . $call_data['call_sid']);
|
||||
$position = TWP_Call_Queue::add_to_queue($queue_id, $call_data);
|
||||
|
||||
if ($position) {
|
||||
error_log('TWP IVR Queue: Call added to position ' . $position);
|
||||
// Generate TwiML for queue wait with proper callback URL
|
||||
$twiml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><Response></Response>');
|
||||
$enqueue = $twiml->addChild('Enqueue');
|
||||
$enqueue->addAttribute('waitUrl', home_url('/wp-json/twilio-webhook/v1/queue-wait?queue_id=' . $queue_id));
|
||||
$enqueue->addChild('Task', json_encode(array('queue_id' => $queue_id, 'position' => $position)));
|
||||
return $this->send_twiml_response($twiml->asXML());
|
||||
} else {
|
||||
error_log('TWP IVR Queue: Failed to add call to queue');
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach here, no valid queue was found - provide helpful message
|
||||
error_log('TWP IVR Queue: No valid queue_id found, providing error message to caller');
|
||||
$twiml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><Response></Response>');
|
||||
$enqueue = $twiml->addChild('Enqueue', $option['queue_name']);
|
||||
echo $twiml->asXML();
|
||||
return;
|
||||
$say = $twiml->addChild('Say', 'Sorry, that option is not currently available. Please try again or hang up.');
|
||||
$say->addAttribute('voice', 'alice');
|
||||
$twiml->addChild('Redirect'); // Redirect back to IVR menu
|
||||
return $this->send_twiml_response($twiml->asXML());
|
||||
|
||||
case 'voicemail':
|
||||
$elevenlabs = new TWP_ElevenLabs_API();
|
||||
$twiml = TWP_Workflow::create_voicemail_twiml($option, $elevenlabs);
|
||||
echo $twiml;
|
||||
return;
|
||||
return $this->send_twiml_response($twiml);
|
||||
|
||||
case 'message':
|
||||
$twiml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><Response></Response>');
|
||||
$say = $twiml->addChild('Say', $option['message']);
|
||||
$say->addAttribute('voice', 'alice');
|
||||
$twiml->addChild('Hangup');
|
||||
echo $twiml->asXML();
|
||||
return;
|
||||
return $this->send_twiml_response($twiml->asXML());
|
||||
}
|
||||
} else {
|
||||
// Log for debugging when option not found
|
||||
error_log('TWP IVR: No option found for digit "' . $digits . '" in step ' . $step_id);
|
||||
error_log('TWP IVR: Available options: ' . json_encode(array_keys($options)));
|
||||
error_log('TWP IVR: Full step data: ' . json_encode($step));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -827,7 +891,7 @@ class TWP_Webhooks {
|
||||
$say = $twiml->addChild('Say', 'Invalid option. Please try again.');
|
||||
$say->addAttribute('voice', 'alice');
|
||||
$twiml->addChild('Redirect');
|
||||
echo $twiml->asXML();
|
||||
return $this->send_twiml_response($twiml->asXML());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1308,6 +1372,13 @@ class TWP_Webhooks {
|
||||
echo $response->asXML();
|
||||
}
|
||||
|
||||
private function get_default_twiml() {
|
||||
$response = new \Twilio\TwiML\VoiceResponse();
|
||||
$response->say('Thank you for calling. Goodbye.', ['voice' => 'alice']);
|
||||
$response->hangup();
|
||||
return $response->asXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send status SMS
|
||||
*/
|
||||
@@ -1764,7 +1835,7 @@ class TWP_Webhooks {
|
||||
// Find waiting calls from queues assigned to this agent's groups
|
||||
$placeholders = implode(',', array_fill(0, count($agent_groups), '%d'));
|
||||
$waiting_call = $wpdb->get_row($wpdb->prepare("
|
||||
SELECT qc.*, q.phone_number as queue_phone_number, q.agent_group_id
|
||||
SELECT qc.*, q.notification_number as queue_notification_number, q.agent_group_id
|
||||
FROM $calls_table qc
|
||||
LEFT JOIN $queues_table q ON qc.queue_id = q.id
|
||||
WHERE qc.status = 'waiting'
|
||||
@@ -1775,7 +1846,7 @@ class TWP_Webhooks {
|
||||
} else {
|
||||
// Agent not in any group - can only handle calls from queues with no assigned group
|
||||
$waiting_call = $wpdb->get_row($wpdb->prepare("
|
||||
SELECT qc.*, q.phone_number as queue_phone_number, q.agent_group_id
|
||||
SELECT qc.*, q.notification_number as queue_notification_number, q.agent_group_id
|
||||
FROM $calls_table qc
|
||||
LEFT JOIN $queues_table q ON qc.queue_id = q.id
|
||||
WHERE qc.status = %s
|
||||
@@ -1796,12 +1867,12 @@ class TWP_Webhooks {
|
||||
error_log('TWP Debug: Waiting call data: ' . print_r($waiting_call, true));
|
||||
|
||||
// Detailed debugging of phone number selection
|
||||
error_log('TWP Debug: Queue workflow_number field: ' . (empty($waiting_call->queue_phone_number) ? 'EMPTY' : $waiting_call->queue_phone_number));
|
||||
error_log('TWP Debug: Queue notification_number field: ' . (empty($waiting_call->queue_notification_number) ? 'EMPTY' : $waiting_call->queue_notification_number));
|
||||
error_log('TWP Debug: Original workflow_number field: ' . (empty($waiting_call->to_number) ? 'EMPTY' : $waiting_call->to_number));
|
||||
|
||||
if (!empty($waiting_call->queue_phone_number)) {
|
||||
$workflow_number = $waiting_call->queue_phone_number;
|
||||
error_log('TWP Debug: SELECTED queue workflow_number: ' . $workflow_number);
|
||||
if (!empty($waiting_call->queue_notification_number)) {
|
||||
$workflow_number = $waiting_call->queue_notification_number;
|
||||
error_log('TWP Debug: SELECTED queue notification_number: ' . $workflow_number);
|
||||
} elseif (!empty($waiting_call->to_number)) {
|
||||
$workflow_number = $waiting_call->to_number;
|
||||
error_log('TWP Debug: SELECTED original workflow_number: ' . $workflow_number);
|
||||
|
@@ -72,6 +72,8 @@ class TWP_Workflow {
|
||||
break;
|
||||
|
||||
case 'ivr_menu':
|
||||
// Add workflow_id to the step data
|
||||
$step['workflow_id'] = $workflow_id;
|
||||
$step_twiml = self::create_ivr_menu_twiml($step, $elevenlabs);
|
||||
$stop_after_step = true; // IVR menu needs user input, stop here
|
||||
break;
|
||||
@@ -301,8 +303,12 @@ class TWP_Workflow {
|
||||
$gather->addAttribute('action', $step['action_url']);
|
||||
} else {
|
||||
$webhook_url = home_url('/wp-json/twilio-webhook/v1/ivr-response');
|
||||
$webhook_url = add_query_arg('workflow_id', $step['workflow_id'], $webhook_url);
|
||||
$webhook_url = add_query_arg('step_id', $step['id'], $webhook_url);
|
||||
if (isset($step['workflow_id'])) {
|
||||
$webhook_url = add_query_arg('workflow_id', $step['workflow_id'], $webhook_url);
|
||||
}
|
||||
if (isset($step['id'])) {
|
||||
$webhook_url = add_query_arg('step_id', $step['id'], $webhook_url);
|
||||
}
|
||||
$gather->addAttribute('action', $webhook_url);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user