Adding new functionality
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -455,6 +455,16 @@
|
|||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.twp-btn-warning {
|
||||||
|
background: #ffc107;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.twp-btn-warning:hover {
|
||||||
|
background: #e0a800;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
.twp-btn-success {
|
.twp-btn-success {
|
||||||
background: #007cba;
|
background: #007cba;
|
||||||
color: white;
|
color: white;
|
||||||
|
@@ -277,6 +277,10 @@
|
|||||||
hangupCall();
|
hangupCall();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#twp-resume-btn').on('click', function() {
|
||||||
|
toggleHold(); // Resume the call
|
||||||
|
});
|
||||||
|
|
||||||
// Call control buttons
|
// Call control buttons
|
||||||
$('#twp-hold-btn').on('click', function() {
|
$('#twp-hold-btn').on('click', function() {
|
||||||
toggleHold();
|
toggleHold();
|
||||||
@@ -531,6 +535,10 @@
|
|||||||
$('#twp-hold-btn').text('Hold').removeClass('btn-active');
|
$('#twp-hold-btn').text('Hold').removeClass('btn-active');
|
||||||
$('#twp-record-btn').text('Record').removeClass('btn-active');
|
$('#twp-record-btn').text('Record').removeClass('btn-active');
|
||||||
|
|
||||||
|
// Reset resume button
|
||||||
|
const $resumeBtn = $('#twp-resume-btn');
|
||||||
|
$resumeBtn.hide();
|
||||||
|
|
||||||
// Restart alerts if enabled and there are waiting calls
|
// Restart alerts if enabled and there are waiting calls
|
||||||
if (alertEnabled) {
|
if (alertEnabled) {
|
||||||
const hasWaitingCalls = userQueues.some(q => parseInt(q.current_waiting) > 0);
|
const hasWaitingCalls = userQueues.some(q => parseInt(q.current_waiting) > 0);
|
||||||
@@ -731,23 +739,27 @@
|
|||||||
function updateCallState(state) {
|
function updateCallState(state) {
|
||||||
const $callBtn = $('#twp-call-btn');
|
const $callBtn = $('#twp-call-btn');
|
||||||
const $hangupBtn = $('#twp-hangup-btn');
|
const $hangupBtn = $('#twp-hangup-btn');
|
||||||
|
const $resumeBtn = $('#twp-resume-btn');
|
||||||
const $controlsPanel = $('#twp-call-controls-panel');
|
const $controlsPanel = $('#twp-call-controls-panel');
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'idle':
|
case 'idle':
|
||||||
$callBtn.show().prop('disabled', false);
|
$callBtn.show().prop('disabled', false);
|
||||||
$hangupBtn.hide();
|
$hangupBtn.hide();
|
||||||
|
$resumeBtn.hide();
|
||||||
$controlsPanel.hide();
|
$controlsPanel.hide();
|
||||||
break;
|
break;
|
||||||
case 'connecting':
|
case 'connecting':
|
||||||
case 'ringing':
|
case 'ringing':
|
||||||
$callBtn.hide();
|
$callBtn.hide();
|
||||||
$hangupBtn.show();
|
$hangupBtn.show();
|
||||||
|
$resumeBtn.hide();
|
||||||
$controlsPanel.hide();
|
$controlsPanel.hide();
|
||||||
break;
|
break;
|
||||||
case 'connected':
|
case 'connected':
|
||||||
$callBtn.hide();
|
$callBtn.hide();
|
||||||
$hangupBtn.show();
|
$hangupBtn.show();
|
||||||
|
$resumeBtn.hide(); // Will be shown by hold logic when needed
|
||||||
$controlsPanel.show();
|
$controlsPanel.show();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1596,19 +1608,33 @@
|
|||||||
isOnHold = !currentHoldState;
|
isOnHold = !currentHoldState;
|
||||||
console.log('Hold state updated to:', isOnHold);
|
console.log('Hold state updated to:', isOnHold);
|
||||||
|
|
||||||
|
// Update hold button and show/hide dedicated resume button
|
||||||
|
const $resumeBtn = $('#twp-resume-btn');
|
||||||
|
|
||||||
if (isOnHold) {
|
if (isOnHold) {
|
||||||
console.log('Setting button to Resume state...');
|
console.log('Setting button to Resume state...');
|
||||||
$holdBtn.text('Resume').addClass('btn-active').prop('disabled', false);
|
$holdBtn.text('Resume').addClass('btn-active').prop('disabled', false);
|
||||||
|
|
||||||
|
// Show dedicated resume button
|
||||||
|
$resumeBtn.show();
|
||||||
|
console.log('Resume button shown - visible:', $resumeBtn.is(':visible'));
|
||||||
|
|
||||||
console.log('Button after update - text:', $holdBtn.text(), 'classes:', $holdBtn.attr('class'));
|
console.log('Button after update - text:', $holdBtn.text(), 'classes:', $holdBtn.attr('class'));
|
||||||
showMessage('Call placed on hold - Click Resume to continue', 'info');
|
showMessage('Call placed on hold - Click Resume Call button to continue', 'info');
|
||||||
|
|
||||||
// Verify the button was actually updated
|
// Verify the button was actually updated
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
console.log('Button state after 100ms:', $holdBtn.text(), $holdBtn.hasClass('btn-active'));
|
console.log('Button state after 100ms:', $holdBtn.text(), $holdBtn.hasClass('btn-active'));
|
||||||
|
console.log('Resume button visible after 100ms:', $resumeBtn.is(':visible'));
|
||||||
}, 100);
|
}, 100);
|
||||||
} else {
|
} else {
|
||||||
console.log('Setting button to Hold state...');
|
console.log('Setting button to Hold state...');
|
||||||
$holdBtn.text('Hold').removeClass('btn-active').prop('disabled', false);
|
$holdBtn.text('Hold').removeClass('btn-active').prop('disabled', false);
|
||||||
|
|
||||||
|
// Hide dedicated resume button
|
||||||
|
$resumeBtn.hide();
|
||||||
|
console.log('Resume button hidden');
|
||||||
|
|
||||||
console.log('Button after update - text:', $holdBtn.text(), 'classes:', $holdBtn.attr('class'));
|
console.log('Button after update - text:', $holdBtn.text(), 'classes:', $holdBtn.attr('class'));
|
||||||
showMessage('Call resumed', 'info');
|
showMessage('Call resumed', 'info');
|
||||||
}
|
}
|
||||||
@@ -1676,10 +1702,8 @@
|
|||||||
if (response.success) {
|
if (response.success) {
|
||||||
showMessage('Call transferred successfully', 'success');
|
showMessage('Call transferred successfully', 'success');
|
||||||
hideTransferDialog();
|
hideTransferDialog();
|
||||||
// End the call on our end
|
// Don't disconnect - let the transfer complete naturally
|
||||||
if (currentCall) {
|
// The call will be disconnected by Twilio after successful transfer
|
||||||
currentCall.disconnect();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
showMessage('Failed to transfer call: ' + (response.data || 'Unknown error'), 'error');
|
showMessage('Failed to transfer call: ' + (response.data || 'Unknown error'), 'error');
|
||||||
}
|
}
|
||||||
@@ -1855,28 +1879,33 @@
|
|||||||
/**
|
/**
|
||||||
* Show agent selection transfer dialog
|
* Show agent selection transfer dialog
|
||||||
*/
|
*/
|
||||||
function showAgentTransferDialog() {
|
function showAgentTransferDialog(agents = null) {
|
||||||
// Load available agents for transfer
|
if (agents) {
|
||||||
$.ajax({
|
// Use passed agents data directly
|
||||||
url: twp_frontend_ajax.ajax_url,
|
buildAgentTransferDialog(agents);
|
||||||
method: 'POST',
|
} else {
|
||||||
data: {
|
// Load available agents for transfer
|
||||||
action: 'twp_get_transfer_agents',
|
$.ajax({
|
||||||
nonce: twp_frontend_ajax.nonce
|
url: twp_frontend_ajax.ajax_url,
|
||||||
},
|
method: 'POST',
|
||||||
success: function(response) {
|
data: {
|
||||||
if (response.success) {
|
action: 'twp_get_transfer_agents',
|
||||||
buildAgentTransferDialog(response.data);
|
nonce: twp_frontend_ajax.nonce
|
||||||
} else {
|
},
|
||||||
showMessage('Failed to load agents: ' + (response.data || 'Unknown error'), 'error');
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
buildAgentTransferDialog(response.data);
|
||||||
|
} else {
|
||||||
|
showMessage('Failed to load agents: ' + (response.data || 'Unknown error'), 'error');
|
||||||
|
showManualTransferDialog(); // Fallback to manual entry
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
showMessage('Failed to load agents', 'error');
|
||||||
showManualTransferDialog(); // Fallback to manual entry
|
showManualTransferDialog(); // Fallback to manual entry
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
error: function() {
|
}
|
||||||
showMessage('Failed to load agents', 'error');
|
|
||||||
showManualTransferDialog(); // Fallback to manual entry
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2034,7 +2063,7 @@
|
|||||||
url: twp_frontend_ajax.ajax_url,
|
url: twp_frontend_ajax.ajax_url,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
action: 'twp_get_all_queues',
|
action: 'twp_get_requeue_queues',
|
||||||
nonce: twp_frontend_ajax.nonce
|
nonce: twp_frontend_ajax.nonce
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
|
@@ -45,7 +45,9 @@ class TWP_Activator {
|
|||||||
'twp_group_members',
|
'twp_group_members',
|
||||||
'twp_agent_status',
|
'twp_agent_status',
|
||||||
'twp_callbacks',
|
'twp_callbacks',
|
||||||
'twp_call_recordings'
|
'twp_call_recordings',
|
||||||
|
'twp_user_extensions',
|
||||||
|
'twp_queue_assignments'
|
||||||
);
|
);
|
||||||
|
|
||||||
$missing_tables = array();
|
$missing_tables = array();
|
||||||
@@ -104,21 +106,30 @@ class TWP_Activator {
|
|||||||
KEY phone_number (phone_number)
|
KEY phone_number (phone_number)
|
||||||
) $charset_collate;";
|
) $charset_collate;";
|
||||||
|
|
||||||
// Call queues table
|
// Call queues table (enhanced for user-specific queues)
|
||||||
$table_queues = $wpdb->prefix . 'twp_call_queues';
|
$table_queues = $wpdb->prefix . 'twp_call_queues';
|
||||||
$sql_queues = "CREATE TABLE $table_queues (
|
$sql_queues = "CREATE TABLE $table_queues (
|
||||||
id int(11) NOT NULL AUTO_INCREMENT,
|
id int(11) NOT NULL AUTO_INCREMENT,
|
||||||
queue_name varchar(100) NOT NULL,
|
queue_name varchar(100) NOT NULL,
|
||||||
|
queue_type varchar(20) DEFAULT 'general',
|
||||||
|
user_id bigint(20),
|
||||||
|
extension varchar(10),
|
||||||
notification_number varchar(20),
|
notification_number varchar(20),
|
||||||
agent_group_id int(11),
|
agent_group_id int(11),
|
||||||
max_size int(11) DEFAULT 10,
|
max_size int(11) DEFAULT 10,
|
||||||
wait_music_url varchar(255),
|
wait_music_url varchar(255),
|
||||||
tts_message text,
|
tts_message text,
|
||||||
timeout_seconds int(11) DEFAULT 300,
|
timeout_seconds int(11) DEFAULT 300,
|
||||||
|
voicemail_prompt text,
|
||||||
|
is_hold_queue tinyint(1) DEFAULT 0,
|
||||||
created_at datetime DEFAULT CURRENT_TIMESTAMP,
|
created_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
KEY agent_group_id (agent_group_id),
|
KEY agent_group_id (agent_group_id),
|
||||||
KEY notification_number (notification_number)
|
KEY notification_number (notification_number),
|
||||||
|
KEY user_id (user_id),
|
||||||
|
KEY extension (extension),
|
||||||
|
KEY queue_type (queue_type),
|
||||||
|
UNIQUE KEY user_queue (user_id, queue_type)
|
||||||
) $charset_collate;";
|
) $charset_collate;";
|
||||||
|
|
||||||
// Queued calls table
|
// Queued calls table
|
||||||
@@ -247,12 +258,14 @@ class TWP_Activator {
|
|||||||
UNIQUE KEY group_user (group_id, user_id)
|
UNIQUE KEY group_user (group_id, user_id)
|
||||||
) $charset_collate;";
|
) $charset_collate;";
|
||||||
|
|
||||||
// Agent status table
|
// Agent status table (enhanced with login tracking)
|
||||||
$table_agent_status = $wpdb->prefix . 'twp_agent_status';
|
$table_agent_status = $wpdb->prefix . 'twp_agent_status';
|
||||||
$sql_agent_status = "CREATE TABLE $table_agent_status (
|
$sql_agent_status = "CREATE TABLE $table_agent_status (
|
||||||
id int(11) NOT NULL AUTO_INCREMENT,
|
id int(11) NOT NULL AUTO_INCREMENT,
|
||||||
user_id bigint(20) NOT NULL,
|
user_id bigint(20) NOT NULL,
|
||||||
status varchar(20) DEFAULT 'offline',
|
status varchar(20) DEFAULT 'offline',
|
||||||
|
is_logged_in tinyint(1) DEFAULT 0,
|
||||||
|
logged_in_at datetime,
|
||||||
current_call_sid varchar(100),
|
current_call_sid varchar(100),
|
||||||
last_activity datetime DEFAULT CURRENT_TIMESTAMP,
|
last_activity datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
available_for_queues tinyint(1) DEFAULT 1,
|
available_for_queues tinyint(1) DEFAULT 1,
|
||||||
@@ -260,6 +273,38 @@ class TWP_Activator {
|
|||||||
UNIQUE KEY user_id (user_id)
|
UNIQUE KEY user_id (user_id)
|
||||||
) $charset_collate;";
|
) $charset_collate;";
|
||||||
|
|
||||||
|
// User extensions table
|
||||||
|
$table_user_extensions = $wpdb->prefix . 'twp_user_extensions';
|
||||||
|
$sql_user_extensions = "CREATE TABLE $table_user_extensions (
|
||||||
|
id int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
user_id bigint(20) NOT NULL,
|
||||||
|
extension varchar(10) NOT NULL,
|
||||||
|
direct_dial_number varchar(20),
|
||||||
|
personal_queue_id int(11),
|
||||||
|
hold_queue_id int(11),
|
||||||
|
created_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY user_id (user_id),
|
||||||
|
UNIQUE KEY extension (extension),
|
||||||
|
KEY personal_queue_id (personal_queue_id),
|
||||||
|
KEY hold_queue_id (hold_queue_id)
|
||||||
|
) $charset_collate;";
|
||||||
|
|
||||||
|
// Queue assignments table (many-to-many relationship)
|
||||||
|
$table_queue_assignments = $wpdb->prefix . 'twp_queue_assignments';
|
||||||
|
$sql_queue_assignments = "CREATE TABLE $table_queue_assignments (
|
||||||
|
id int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
user_id bigint(20) NOT NULL,
|
||||||
|
queue_id int(11) NOT NULL,
|
||||||
|
is_primary tinyint(1) DEFAULT 0,
|
||||||
|
assigned_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY user_queue (user_id, queue_id),
|
||||||
|
KEY user_id (user_id),
|
||||||
|
KEY queue_id (queue_id)
|
||||||
|
) $charset_collate;";
|
||||||
|
|
||||||
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
||||||
dbDelta($sql_schedules);
|
dbDelta($sql_schedules);
|
||||||
dbDelta($sql_queues);
|
dbDelta($sql_queues);
|
||||||
@@ -325,6 +370,8 @@ class TWP_Activator {
|
|||||||
dbDelta($sql_agent_status);
|
dbDelta($sql_agent_status);
|
||||||
dbDelta($sql_callbacks);
|
dbDelta($sql_callbacks);
|
||||||
dbDelta($sql_recordings);
|
dbDelta($sql_recordings);
|
||||||
|
dbDelta($sql_user_extensions);
|
||||||
|
dbDelta($sql_queue_assignments);
|
||||||
|
|
||||||
// Add missing columns for existing installations
|
// Add missing columns for existing installations
|
||||||
self::add_missing_columns();
|
self::add_missing_columns();
|
||||||
@@ -336,6 +383,64 @@ class TWP_Activator {
|
|||||||
private static function add_missing_columns() {
|
private static function add_missing_columns() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
|
// Add new queue columns for user-specific queues
|
||||||
|
$table_queues = $wpdb->prefix . 'twp_call_queues';
|
||||||
|
|
||||||
|
// Check and add queue_type column
|
||||||
|
$queue_type_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'queue_type'");
|
||||||
|
if (empty($queue_type_exists)) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN queue_type varchar(20) DEFAULT 'general' AFTER queue_name");
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD INDEX queue_type (queue_type)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and add user_id column
|
||||||
|
$user_id_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'user_id'");
|
||||||
|
if (empty($user_id_exists)) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN user_id bigint(20) AFTER queue_type");
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD INDEX user_id (user_id)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and add extension column
|
||||||
|
$extension_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'extension'");
|
||||||
|
if (empty($extension_exists)) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN extension varchar(10) AFTER user_id");
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD INDEX extension (extension)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and add voicemail_prompt column
|
||||||
|
$voicemail_prompt_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'voicemail_prompt'");
|
||||||
|
if (empty($voicemail_prompt_exists)) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN voicemail_prompt text AFTER timeout_seconds");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and add is_hold_queue column
|
||||||
|
$is_hold_queue_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'is_hold_queue'");
|
||||||
|
if (empty($is_hold_queue_exists)) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD COLUMN is_hold_queue tinyint(1) DEFAULT 0 AFTER voicemail_prompt");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add unique constraint for user queues if it doesn't exist
|
||||||
|
$unique_constraint_exists = $wpdb->get_results("SHOW INDEX FROM $table_queues WHERE Key_name = 'user_queue'");
|
||||||
|
if (empty($unique_constraint_exists)) {
|
||||||
|
// Only add if both columns exist
|
||||||
|
if (!empty($user_id_exists) || $wpdb->get_results("SHOW COLUMNS FROM $table_queues LIKE 'user_id'")) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_queues ADD UNIQUE KEY user_queue (user_id, queue_type)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add login tracking columns to agent_status table
|
||||||
|
$table_agent_status = $wpdb->prefix . 'twp_agent_status';
|
||||||
|
|
||||||
|
$is_logged_in_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_agent_status LIKE 'is_logged_in'");
|
||||||
|
if (empty($is_logged_in_exists)) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_agent_status ADD COLUMN is_logged_in tinyint(1) DEFAULT 0 AFTER status");
|
||||||
|
}
|
||||||
|
|
||||||
|
$logged_in_at_exists = $wpdb->get_results("SHOW COLUMNS FROM $table_agent_status LIKE 'logged_in_at'");
|
||||||
|
if (empty($logged_in_at_exists)) {
|
||||||
|
$wpdb->query("ALTER TABLE $table_agent_status ADD COLUMN logged_in_at datetime AFTER is_logged_in");
|
||||||
|
}
|
||||||
|
|
||||||
$table_schedules = $wpdb->prefix . 'twp_phone_schedules';
|
$table_schedules = $wpdb->prefix . 'twp_phone_schedules';
|
||||||
|
|
||||||
// Check if holiday_dates column exists
|
// Check if holiday_dates column exists
|
||||||
|
@@ -104,16 +104,22 @@ class TWP_Agent_Manager {
|
|||||||
$user_id
|
$user_id
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Preserve login status if not explicitly changing it
|
||||||
|
$is_logged_in = $existing ? $existing->is_logged_in : 0;
|
||||||
|
$logged_in_at = $existing ? $existing->logged_in_at : null;
|
||||||
|
|
||||||
if ($existing) {
|
if ($existing) {
|
||||||
return $wpdb->update(
|
return $wpdb->update(
|
||||||
$table_name,
|
$table_name,
|
||||||
array(
|
array(
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'current_call_sid' => $call_sid,
|
'current_call_sid' => $call_sid,
|
||||||
'last_activity' => current_time('mysql')
|
'last_activity' => current_time('mysql'),
|
||||||
|
'is_logged_in' => $is_logged_in,
|
||||||
|
'logged_in_at' => $logged_in_at
|
||||||
),
|
),
|
||||||
array('user_id' => $user_id),
|
array('user_id' => $user_id),
|
||||||
array('%s', '%s', '%s'),
|
array('%s', '%s', '%s', '%d', '%s'),
|
||||||
array('%d')
|
array('%d')
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -123,13 +129,85 @@ class TWP_Agent_Manager {
|
|||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'current_call_sid' => $call_sid,
|
'current_call_sid' => $call_sid,
|
||||||
'last_activity' => current_time('mysql')
|
'last_activity' => current_time('mysql'),
|
||||||
|
'is_logged_in' => 0,
|
||||||
|
'logged_in_at' => null
|
||||||
),
|
),
|
||||||
array('%d', '%s', '%s', '%s')
|
array('%d', '%s', '%s', '%s', '%d', '%s')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set agent login status
|
||||||
|
*/
|
||||||
|
public static function set_agent_login_status($user_id, $is_logged_in) {
|
||||||
|
global $wpdb;
|
||||||
|
$table_name = $wpdb->prefix . 'twp_agent_status';
|
||||||
|
|
||||||
|
$existing = $wpdb->get_row($wpdb->prepare(
|
||||||
|
"SELECT * FROM $table_name WHERE user_id = %d",
|
||||||
|
$user_id
|
||||||
|
));
|
||||||
|
|
||||||
|
$logged_in_at = $is_logged_in ? current_time('mysql') : null;
|
||||||
|
|
||||||
|
// Update queue timeout based on login status
|
||||||
|
if (class_exists('TWP_User_Queue_Manager')) {
|
||||||
|
TWP_User_Queue_Manager::update_queue_timeout_for_login($user_id, $is_logged_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also ensure user has queues created if logging in
|
||||||
|
if ($is_logged_in && class_exists('TWP_User_Queue_Manager')) {
|
||||||
|
$extension_data = TWP_User_Queue_Manager::get_user_extension_data($user_id);
|
||||||
|
if (!$extension_data) {
|
||||||
|
TWP_User_Queue_Manager::create_user_queues($user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
return $wpdb->update(
|
||||||
|
$table_name,
|
||||||
|
array(
|
||||||
|
'is_logged_in' => $is_logged_in ? 1 : 0,
|
||||||
|
'logged_in_at' => $logged_in_at,
|
||||||
|
'last_activity' => current_time('mysql'),
|
||||||
|
'status' => $is_logged_in ? 'available' : 'offline'
|
||||||
|
),
|
||||||
|
array('user_id' => $user_id),
|
||||||
|
array('%d', '%s', '%s', '%s'),
|
||||||
|
array('%d')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return $wpdb->insert(
|
||||||
|
$table_name,
|
||||||
|
array(
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'status' => $is_logged_in ? 'available' : 'offline',
|
||||||
|
'is_logged_in' => $is_logged_in ? 1 : 0,
|
||||||
|
'logged_in_at' => $logged_in_at,
|
||||||
|
'last_activity' => current_time('mysql')
|
||||||
|
),
|
||||||
|
array('%d', '%s', '%d', '%s', '%s')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if agent is logged in
|
||||||
|
*/
|
||||||
|
public static function is_agent_logged_in($user_id) {
|
||||||
|
global $wpdb;
|
||||||
|
$table_name = $wpdb->prefix . 'twp_agent_status';
|
||||||
|
|
||||||
|
$status = $wpdb->get_row($wpdb->prepare(
|
||||||
|
"SELECT is_logged_in FROM $table_name WHERE user_id = %d",
|
||||||
|
$user_id
|
||||||
|
));
|
||||||
|
|
||||||
|
return $status && $status->is_logged_in == 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get agent status
|
* Get agent status
|
||||||
*/
|
*/
|
||||||
|
@@ -43,6 +43,7 @@ class TWP_Core {
|
|||||||
require_once TWP_PLUGIN_DIR . 'includes/class-twp-agent-groups.php';
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-agent-groups.php';
|
||||||
require_once TWP_PLUGIN_DIR . 'includes/class-twp-agent-manager.php';
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-agent-manager.php';
|
||||||
require_once TWP_PLUGIN_DIR . 'includes/class-twp-callback-manager.php';
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-callback-manager.php';
|
||||||
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-user-queue-manager.php';
|
||||||
require_once TWP_PLUGIN_DIR . 'includes/class-twp-shortcodes.php';
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-shortcodes.php';
|
||||||
|
|
||||||
// Admin classes
|
// Admin classes
|
||||||
@@ -146,6 +147,17 @@ class TWP_Core {
|
|||||||
$this->loader->add_action('wp_ajax_twp_delete_queue', $plugin_admin, 'ajax_delete_queue');
|
$this->loader->add_action('wp_ajax_twp_delete_queue', $plugin_admin, 'ajax_delete_queue');
|
||||||
$this->loader->add_action('wp_ajax_twp_get_dashboard_stats', $plugin_admin, 'ajax_get_dashboard_stats');
|
$this->loader->add_action('wp_ajax_twp_get_dashboard_stats', $plugin_admin, 'ajax_get_dashboard_stats');
|
||||||
|
|
||||||
|
// Queue management actions
|
||||||
|
$this->loader->add_action('wp_ajax_twp_get_queue_calls', $plugin_admin, 'ajax_get_queue_calls');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_toggle_agent_login', $plugin_admin, 'ajax_toggle_agent_login');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_answer_queue_call', $plugin_admin, 'ajax_answer_queue_call');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_monitor_call', $plugin_admin, 'ajax_monitor_call');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_toggle_call_recording', $plugin_admin, 'ajax_toggle_call_recording');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_transfer_call', $plugin_admin, 'ajax_transfer_call');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_send_to_voicemail', $plugin_admin, 'ajax_send_to_voicemail');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_disconnect_call', $plugin_admin, 'ajax_disconnect_call');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_get_transfer_targets', $plugin_admin, 'ajax_get_transfer_targets');
|
||||||
|
|
||||||
// Eleven Labs AJAX
|
// Eleven Labs AJAX
|
||||||
$this->loader->add_action('wp_ajax_twp_get_elevenlabs_voices', $plugin_admin, 'ajax_get_elevenlabs_voices');
|
$this->loader->add_action('wp_ajax_twp_get_elevenlabs_voices', $plugin_admin, 'ajax_get_elevenlabs_voices');
|
||||||
$this->loader->add_action('wp_ajax_twp_get_elevenlabs_models', $plugin_admin, 'ajax_get_elevenlabs_models');
|
$this->loader->add_action('wp_ajax_twp_get_elevenlabs_models', $plugin_admin, 'ajax_get_elevenlabs_models');
|
||||||
@@ -176,6 +188,7 @@ class TWP_Core {
|
|||||||
$this->loader->add_action('wp_ajax_twp_accept_next_queue_call', $plugin_admin, 'ajax_accept_next_queue_call');
|
$this->loader->add_action('wp_ajax_twp_accept_next_queue_call', $plugin_admin, 'ajax_accept_next_queue_call');
|
||||||
$this->loader->add_action('wp_ajax_twp_get_waiting_calls', $plugin_admin, 'ajax_get_waiting_calls');
|
$this->loader->add_action('wp_ajax_twp_get_waiting_calls', $plugin_admin, 'ajax_get_waiting_calls');
|
||||||
$this->loader->add_action('wp_ajax_twp_get_agent_queues', $plugin_admin, 'ajax_get_agent_queues');
|
$this->loader->add_action('wp_ajax_twp_get_agent_queues', $plugin_admin, 'ajax_get_agent_queues');
|
||||||
|
$this->loader->add_action('wp_ajax_twp_get_requeue_queues', $plugin_admin, 'ajax_get_requeue_queues');
|
||||||
$this->loader->add_action('wp_ajax_twp_set_agent_status', $plugin_admin, 'ajax_set_agent_status');
|
$this->loader->add_action('wp_ajax_twp_set_agent_status', $plugin_admin, 'ajax_set_agent_status');
|
||||||
$this->loader->add_action('wp_ajax_twp_get_call_details', $plugin_admin, 'ajax_get_call_details');
|
$this->loader->add_action('wp_ajax_twp_get_call_details', $plugin_admin, 'ajax_get_call_details');
|
||||||
|
|
||||||
|
@@ -158,6 +158,10 @@ class TWP_Shortcodes {
|
|||||||
<span class="hangup-icon">📞</span>
|
<span class="hangup-icon">📞</span>
|
||||||
<span class="hangup-text">Hang Up</span>
|
<span class="hangup-text">Hang Up</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="twp-resume-btn" class="twp-btn twp-btn-warning" style="display: none;">
|
||||||
|
<span class="resume-icon">▶️</span>
|
||||||
|
<span class="resume-text">Resume Call</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Call Info -->
|
<!-- Call Info -->
|
||||||
|
420
includes/class-twp-user-queue-manager.php
Normal file
420
includes/class-twp-user-queue-manager.php
Normal file
@@ -0,0 +1,420 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* User Queue Manager
|
||||||
|
*
|
||||||
|
* Handles user-specific queues, extensions, and hold queues
|
||||||
|
*/
|
||||||
|
class TWP_User_Queue_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create personal and hold queues for a user
|
||||||
|
*
|
||||||
|
* @param int $user_id WordPress user ID
|
||||||
|
* @param string $extension User's extension number
|
||||||
|
* @return array Array with queue IDs and extension info
|
||||||
|
*/
|
||||||
|
public static function create_user_queues($user_id, $extension = null) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$user = get_user_by('id', $user_id);
|
||||||
|
if (!$user) {
|
||||||
|
return array('success' => false, 'error' => 'User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate extension if not provided
|
||||||
|
if (!$extension) {
|
||||||
|
$extension = self::generate_unique_extension();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if extension already exists
|
||||||
|
$existing = $wpdb->get_var($wpdb->prepare(
|
||||||
|
"SELECT extension FROM {$wpdb->prefix}twp_user_extensions WHERE extension = %s",
|
||||||
|
$extension
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
return array('success' => false, 'error' => 'Extension already exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create personal queue
|
||||||
|
$personal_queue_name = sprintf('%s (%s)', $user->display_name, $extension);
|
||||||
|
$personal_queue_id = $wpdb->insert(
|
||||||
|
$wpdb->prefix . 'twp_call_queues',
|
||||||
|
array(
|
||||||
|
'queue_name' => $personal_queue_name,
|
||||||
|
'queue_type' => 'personal',
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'extension' => $extension,
|
||||||
|
'max_size' => 10,
|
||||||
|
'timeout_seconds' => 300, // 5 minutes for logged-in users
|
||||||
|
'voicemail_prompt' => sprintf('You have reached %s. Please leave a message after the tone.', $user->display_name),
|
||||||
|
'is_hold_queue' => 0
|
||||||
|
),
|
||||||
|
array('%s', '%s', '%d', '%s', '%d', '%d', '%s', '%d')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$personal_queue_id) {
|
||||||
|
return array('success' => false, 'error' => 'Failed to create personal queue');
|
||||||
|
}
|
||||||
|
|
||||||
|
$personal_queue_id = $wpdb->insert_id;
|
||||||
|
|
||||||
|
// Create hold queue
|
||||||
|
$hold_queue_name = sprintf('Hold - %s', $user->display_name);
|
||||||
|
$hold_queue_id = $wpdb->insert(
|
||||||
|
$wpdb->prefix . 'twp_call_queues',
|
||||||
|
array(
|
||||||
|
'queue_name' => $hold_queue_name,
|
||||||
|
'queue_type' => 'hold',
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'extension' => null, // Hold queues don't have extensions
|
||||||
|
'max_size' => 5,
|
||||||
|
'timeout_seconds' => 0, // No timeout for hold queues
|
||||||
|
'tts_message' => 'Your call is on hold. Please wait.',
|
||||||
|
'is_hold_queue' => 1
|
||||||
|
),
|
||||||
|
array('%s', '%s', '%d', '%s', '%d', '%d', '%s', '%d')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$hold_queue_id) {
|
||||||
|
// Rollback personal queue creation
|
||||||
|
$wpdb->delete($wpdb->prefix . 'twp_call_queues', array('id' => $personal_queue_id));
|
||||||
|
return array('success' => false, 'error' => 'Failed to create hold queue');
|
||||||
|
}
|
||||||
|
|
||||||
|
$hold_queue_id = $wpdb->insert_id;
|
||||||
|
|
||||||
|
// Create user extension record
|
||||||
|
$extension_result = $wpdb->insert(
|
||||||
|
$wpdb->prefix . 'twp_user_extensions',
|
||||||
|
array(
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'extension' => $extension,
|
||||||
|
'personal_queue_id' => $personal_queue_id,
|
||||||
|
'hold_queue_id' => $hold_queue_id
|
||||||
|
),
|
||||||
|
array('%d', '%s', '%d', '%d')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$extension_result) {
|
||||||
|
// Rollback queue creations
|
||||||
|
$wpdb->delete($wpdb->prefix . 'twp_call_queues', array('id' => $personal_queue_id));
|
||||||
|
$wpdb->delete($wpdb->prefix . 'twp_call_queues', array('id' => $hold_queue_id));
|
||||||
|
return array('success' => false, 'error' => 'Failed to create extension record');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-assign user to their personal queue
|
||||||
|
$wpdb->insert(
|
||||||
|
$wpdb->prefix . 'twp_queue_assignments',
|
||||||
|
array(
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'queue_id' => $personal_queue_id,
|
||||||
|
'is_primary' => 1
|
||||||
|
),
|
||||||
|
array('%d', '%d', '%d')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Auto-assign user to their hold queue
|
||||||
|
$wpdb->insert(
|
||||||
|
$wpdb->prefix . 'twp_queue_assignments',
|
||||||
|
array(
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'queue_id' => $hold_queue_id,
|
||||||
|
'is_primary' => 0
|
||||||
|
),
|
||||||
|
array('%d', '%d', '%d')
|
||||||
|
);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'success' => true,
|
||||||
|
'extension' => $extension,
|
||||||
|
'personal_queue_id' => $personal_queue_id,
|
||||||
|
'hold_queue_id' => $hold_queue_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a unique extension number
|
||||||
|
*
|
||||||
|
* @return string Extension number (3-4 digits)
|
||||||
|
*/
|
||||||
|
private static function generate_unique_extension() {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// Start with 100 for 3-digit extensions
|
||||||
|
$start = 100;
|
||||||
|
$max_attempts = 900; // Up to 999
|
||||||
|
|
||||||
|
for ($i = 0; $i < $max_attempts; $i++) {
|
||||||
|
$extension = (string)($start + $i);
|
||||||
|
|
||||||
|
$exists = $wpdb->get_var($wpdb->prepare(
|
||||||
|
"SELECT extension FROM {$wpdb->prefix}twp_user_extensions WHERE extension = %s",
|
||||||
|
$extension
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!$exists) {
|
||||||
|
return $extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all 3-digit extensions are taken, try 4-digit starting at 1000
|
||||||
|
$start = 1000;
|
||||||
|
$max_attempts = 9000; // Up to 9999
|
||||||
|
|
||||||
|
for ($i = 0; $i < $max_attempts; $i++) {
|
||||||
|
$extension = (string)($start + $i);
|
||||||
|
|
||||||
|
$exists = $wpdb->get_var($wpdb->prepare(
|
||||||
|
"SELECT extension FROM {$wpdb->prefix}twp_user_extensions WHERE extension = %s",
|
||||||
|
$extension
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!$exists) {
|
||||||
|
return $extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // All extensions taken (unlikely)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user's extension and queue information
|
||||||
|
*
|
||||||
|
* @param int $user_id WordPress user ID
|
||||||
|
* @return array|null Extension and queue data
|
||||||
|
*/
|
||||||
|
public static function get_user_extension_data($user_id) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$data = $wpdb->get_row($wpdb->prepare(
|
||||||
|
"SELECT * FROM {$wpdb->prefix}twp_user_extensions WHERE user_id = %d",
|
||||||
|
$user_id
|
||||||
|
), ARRAY_A);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user by extension
|
||||||
|
*
|
||||||
|
* @param string $extension Extension number
|
||||||
|
* @return int|null User ID
|
||||||
|
*/
|
||||||
|
public static function get_user_by_extension($extension) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$user_id = $wpdb->get_var($wpdb->prepare(
|
||||||
|
"SELECT user_id FROM {$wpdb->prefix}twp_user_extensions WHERE extension = %s",
|
||||||
|
$extension
|
||||||
|
));
|
||||||
|
|
||||||
|
return $user_id ? intval($user_id) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all queues assigned to a user
|
||||||
|
*
|
||||||
|
* @param int $user_id WordPress user ID
|
||||||
|
* @return array Array of queue data
|
||||||
|
*/
|
||||||
|
public static function get_user_assigned_queues($user_id) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$query = $wpdb->prepare("
|
||||||
|
SELECT q.*, qa.is_primary,
|
||||||
|
(SELECT COUNT(*) FROM {$wpdb->prefix}twp_queued_calls qc
|
||||||
|
WHERE qc.queue_id = q.id AND qc.status = 'waiting') as waiting_calls
|
||||||
|
FROM {$wpdb->prefix}twp_call_queues q
|
||||||
|
INNER JOIN {$wpdb->prefix}twp_queue_assignments qa ON q.id = qa.queue_id
|
||||||
|
WHERE qa.user_id = %d
|
||||||
|
ORDER BY qa.is_primary DESC, q.queue_name ASC
|
||||||
|
", $user_id);
|
||||||
|
|
||||||
|
$queues = $wpdb->get_results($query, ARRAY_A);
|
||||||
|
|
||||||
|
return $queues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update queue timeout based on user login status
|
||||||
|
*
|
||||||
|
* @param int $user_id WordPress user ID
|
||||||
|
* @param bool $is_logged_in Whether user is logged in
|
||||||
|
*/
|
||||||
|
public static function update_queue_timeout_for_login($user_id, $is_logged_in) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// Get user's personal queue
|
||||||
|
$extension_data = self::get_user_extension_data($user_id);
|
||||||
|
|
||||||
|
if (!$extension_data || !$extension_data['personal_queue_id']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update timeout: 5 minutes if logged in, 0 (immediate voicemail) if logged out
|
||||||
|
$timeout = $is_logged_in ? 300 : 0;
|
||||||
|
|
||||||
|
$wpdb->update(
|
||||||
|
$wpdb->prefix . 'twp_call_queues',
|
||||||
|
array('timeout_seconds' => $timeout),
|
||||||
|
array('id' => $extension_data['personal_queue_id']),
|
||||||
|
array('%d'),
|
||||||
|
array('%d')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer call to user's hold queue
|
||||||
|
*
|
||||||
|
* @param int $user_id WordPress user ID
|
||||||
|
* @param string $call_sid Call SID to transfer
|
||||||
|
* @return array Result array
|
||||||
|
*/
|
||||||
|
public static function transfer_to_hold_queue($user_id, $call_sid) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// Get user's hold queue
|
||||||
|
$extension_data = self::get_user_extension_data($user_id);
|
||||||
|
|
||||||
|
if (!$extension_data || !$extension_data['hold_queue_id']) {
|
||||||
|
return array('success' => false, 'error' => 'Hold queue not found for user');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if call exists in any queue
|
||||||
|
$current_queue = $wpdb->get_row($wpdb->prepare(
|
||||||
|
"SELECT * FROM {$wpdb->prefix}twp_queued_calls WHERE call_sid = %s AND status = 'waiting'",
|
||||||
|
$call_sid
|
||||||
|
), ARRAY_A);
|
||||||
|
|
||||||
|
if (!$current_queue) {
|
||||||
|
return array('success' => false, 'error' => 'Call not found in queue');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move call to hold queue
|
||||||
|
$result = $wpdb->update(
|
||||||
|
$wpdb->prefix . 'twp_queued_calls',
|
||||||
|
array(
|
||||||
|
'queue_id' => $extension_data['hold_queue_id'],
|
||||||
|
'position' => 1 // Reset position in hold queue
|
||||||
|
),
|
||||||
|
array('id' => $current_queue['id']),
|
||||||
|
array('%d', '%d'),
|
||||||
|
array('%d')
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
return array('success' => false, 'error' => 'Failed to transfer to hold queue');
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'success' => true,
|
||||||
|
'hold_queue_id' => $extension_data['hold_queue_id']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer call from hold queue back to original or specified queue
|
||||||
|
*
|
||||||
|
* @param int $user_id WordPress user ID
|
||||||
|
* @param string $call_sid Call SID to transfer
|
||||||
|
* @param int $target_queue_id Optional target queue ID
|
||||||
|
* @return array Result array
|
||||||
|
*/
|
||||||
|
public static function resume_from_hold($user_id, $call_sid, $target_queue_id = null) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// Get user's hold queue
|
||||||
|
$extension_data = self::get_user_extension_data($user_id);
|
||||||
|
|
||||||
|
if (!$extension_data || !$extension_data['hold_queue_id']) {
|
||||||
|
return array('success' => false, 'error' => 'Hold queue not found for user');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if call is in hold queue
|
||||||
|
$held_call = $wpdb->get_row($wpdb->prepare(
|
||||||
|
"SELECT * FROM {$wpdb->prefix}twp_queued_calls
|
||||||
|
WHERE call_sid = %s AND queue_id = %d AND status = 'waiting'",
|
||||||
|
$call_sid,
|
||||||
|
$extension_data['hold_queue_id']
|
||||||
|
), ARRAY_A);
|
||||||
|
|
||||||
|
if (!$held_call) {
|
||||||
|
return array('success' => false, 'error' => 'Call not found in hold queue');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine target queue
|
||||||
|
if (!$target_queue_id) {
|
||||||
|
// Default to user's personal queue
|
||||||
|
$target_queue_id = $extension_data['personal_queue_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get next position in target queue
|
||||||
|
$next_position = $wpdb->get_var($wpdb->prepare(
|
||||||
|
"SELECT COALESCE(MAX(position), 0) + 1 FROM {$wpdb->prefix}twp_queued_calls
|
||||||
|
WHERE queue_id = %d AND status = 'waiting'",
|
||||||
|
$target_queue_id
|
||||||
|
));
|
||||||
|
|
||||||
|
// Move call to target queue
|
||||||
|
$result = $wpdb->update(
|
||||||
|
$wpdb->prefix . 'twp_queued_calls',
|
||||||
|
array(
|
||||||
|
'queue_id' => $target_queue_id,
|
||||||
|
'position' => $next_position
|
||||||
|
),
|
||||||
|
array('id' => $held_call['id']),
|
||||||
|
array('%d', '%d'),
|
||||||
|
array('%d')
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
return array('success' => false, 'error' => 'Failed to resume from hold');
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'success' => true,
|
||||||
|
'target_queue_id' => $target_queue_id,
|
||||||
|
'position' => $next_position
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize user queues for all existing users
|
||||||
|
* This should be called during plugin activation or upgrade
|
||||||
|
*/
|
||||||
|
public static function initialize_all_user_queues() {
|
||||||
|
$users = get_users(array(
|
||||||
|
'fields' => 'ID',
|
||||||
|
'meta_key' => 'twp_phone_number',
|
||||||
|
'meta_compare' => 'EXISTS'
|
||||||
|
));
|
||||||
|
|
||||||
|
$results = array(
|
||||||
|
'success' => 0,
|
||||||
|
'failed' => 0,
|
||||||
|
'skipped' => 0
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($users as $user_id) {
|
||||||
|
// Check if user already has queues
|
||||||
|
$existing = self::get_user_extension_data($user_id);
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
$results['skipped']++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = self::create_user_queues($user_id);
|
||||||
|
|
||||||
|
if ($result['success']) {
|
||||||
|
$results['success']++;
|
||||||
|
} else {
|
||||||
|
$results['failed']++;
|
||||||
|
error_log('TWP: Failed to create queues for user ' . $user_id . ': ' . $result['error']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
}
|
@@ -15,8 +15,8 @@ if (!defined('WPINC')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Plugin constants
|
// Plugin constants
|
||||||
define('TWP_VERSION', '2.2.0');
|
define('TWP_VERSION', '2.4.2');
|
||||||
define('TWP_DB_VERSION', '1.1.0'); // Track database version separately
|
define('TWP_DB_VERSION', '1.6.0'); // Track database version separately
|
||||||
define('TWP_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
define('TWP_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||||
define('TWP_PLUGIN_URL', plugin_dir_url(__FILE__));
|
define('TWP_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||||
define('TWP_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
define('TWP_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
||||||
|
Reference in New Issue
Block a user