Fix extension transfer system and browser phone compatibility

Major Fixes:
- Fixed extension transfers going directly to voicemail for available agents
- Resolved browser phone call disconnections during transfers
- Fixed voicemail transcription placeholder text issue
- Added Firefox compatibility with automatic media permissions

Extension Transfer Improvements:
- Changed from active client dialing to proper queue-based system
- Fixed client name generation consistency (user_login vs display_name)
- Added 2-minute timeout with automatic voicemail fallback
- Enhanced agent availability detection for browser phone users

Browser Phone Enhancements:
- Added automatic microphone/speaker permission requests
- Improved Firefox compatibility with explicit getUserMedia calls
- Fixed client naming consistency across capability tokens and call acceptance
- Added comprehensive error handling for permission denials

Database & System Updates:
- Added auto_busy_at column for automatic agent status reversion
- Implemented 1-minute auto-revert system for busy agents with cron job
- Updated database version to 1.6.2 for automatic migration
- Fixed voicemail user_id association for extension voicemails

Call Statistics & Logging:
- Fixed browser phone calls not appearing in agent statistics
- Enhanced call logging with proper agent_id association in JSON format
- Improved customer number detection for complex call topologies
- Added comprehensive debugging for call leg detection

Voicemail & Transcription:
- Replaced placeholder transcription with real Twilio API integration
- Added manual transcription request capability for existing voicemails
- Enhanced voicemail callback handling with user_id support
- Fixed transcription webhook processing for extension voicemails

Technical Improvements:
- Standardized client name generation across all components
- Added ElevenLabs TTS integration to agent connection messages
- Enhanced error handling and logging throughout transfer system
- Fixed TwiML generation syntax errors in dial() methods

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-02 11:03:33 -07:00
parent ae92ea2c81
commit 7cd7f036ff
14 changed files with 1312 additions and 194 deletions

View File

@@ -46,7 +46,7 @@ class TWP_User_Queue_Manager {
'user_id' => $user_id,
'extension' => $extension,
'max_size' => 10,
'timeout_seconds' => 300, // 5 minutes for logged-in users
'timeout_seconds' => 120, // 2 minutes timeout
'voicemail_prompt' => sprintf('You have reached %s. Please leave a message after the tone.', $user->display_name),
'is_hold_queue' => 0
),
@@ -288,23 +288,49 @@ class TWP_User_Queue_Manager {
), 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(
// Call not in queue yet (browser phone calls), create a new entry
error_log("TWP: Call not in queue, creating hold queue entry for SID: {$call_sid}");
// Check if enqueued_at column exists
$calls_table = $wpdb->prefix . 'twp_queued_calls';
$columns = $wpdb->get_col("DESCRIBE $calls_table");
$insert_data = 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');
'call_sid' => $call_sid,
'from_number' => '', // Will be populated by Twilio webhooks
'to_number' => '', // Will be populated by Twilio webhooks
'position' => 1,
'status' => 'waiting'
);
if (in_array('enqueued_at', $columns)) {
$insert_data['enqueued_at'] = current_time('mysql');
} else {
$insert_data['joined_at'] = current_time('mysql');
}
$result = $wpdb->insert($calls_table, $insert_data);
if ($result === false) {
return array('success' => false, 'error' => 'Failed to create hold queue entry');
}
} else {
// Move existing 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(
@@ -340,7 +366,9 @@ class TWP_User_Queue_Manager {
), ARRAY_A);
if (!$held_call) {
return array('success' => false, 'error' => 'Call not found in hold queue');
// Call might not be in database (browser phone), but we can still resume it
error_log("TWP: Call not found in hold queue database, will resume anyway for SID: {$call_sid}");
// Continue with resume process even without database entry
}
// Determine target queue
@@ -356,20 +384,22 @@ class TWP_User_Queue_Manager {
$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');
// Move call to target queue if it exists in database
if ($held_call) {
$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(