Add FCM push notifications, queue alerts, caller ID fixes, and auto-revert agent status
All checks were successful
Create Release / build (push) Successful in 6s
All checks were successful
Create Release / build (push) Successful in 6s
Server-side: - Add push credential auto-creation for FCM incoming call notifications - Add queue alert FCM notifications (data-only for background delivery) - Add queue alert cancellation on call accept/disconnect - Fix caller ID to show caller's number instead of Twilio number - Fix FCM token storage when refresh_token is null - Add pre_call_status tracking to revert agent status 30s after call ends - Add SSE fallback polling for mobile app connectivity Mobile app: - Add Android telecom permissions and phone account registration - Add VoiceFirebaseMessagingService for incoming call push handling - Add insistent queue alert notifications with custom sound - Fix caller number display on active call screen - Add caller ID selection dropdown on dashboard - Add phone numbers endpoint and provider support - Add unit tests for CallInfo, QueueState, and CallProvider - Remove local.properties from tracking, add .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -329,7 +329,13 @@ class TWP_Webhooks {
|
||||
*/
|
||||
public function handle_browser_voice($request) {
|
||||
$params = $request->get_params();
|
||||
|
||||
error_log('TWP browser-voice webhook params: ' . json_encode(array(
|
||||
'From' => $params['From'] ?? '',
|
||||
'To' => $params['To'] ?? '',
|
||||
'CallerId' => $params['CallerId'] ?? '',
|
||||
'CallSid' => $params['CallSid'] ?? '',
|
||||
)));
|
||||
|
||||
$call_data = array(
|
||||
'CallSid' => isset($params['CallSid']) ? $params['CallSid'] : '',
|
||||
'From' => isset($params['From']) ? $params['From'] : '',
|
||||
@@ -371,23 +377,45 @@ class TWP_Webhooks {
|
||||
|
||||
if (isset($params['To']) && !empty($params['To'])) {
|
||||
$to_number = $params['To'];
|
||||
// Mobile SDK sends CallerId via extraOptions; browser sends From as phone number
|
||||
// Mobile SDK sends From as identity (e.g. "agent2jknapp"), browser sends From as phone number
|
||||
// Only use CallerId/From if it looks like a phone number (starts with + or is all digits)
|
||||
$from_number = '';
|
||||
if (!empty($params['CallerId']) && strpos($params['CallerId'], 'client:') !== 0) {
|
||||
if (!empty($params['CallerId']) && preg_match('/^\+?\d+$/', $params['CallerId'])) {
|
||||
$from_number = $params['CallerId'];
|
||||
} elseif (!empty($params['From']) && strpos($params['From'], 'client:') !== 0) {
|
||||
} elseif (!empty($params['From']) && preg_match('/^\+?\d+$/', $params['From'])) {
|
||||
$from_number = $params['From'];
|
||||
}
|
||||
|
||||
|
||||
// Fall back to default caller ID if no valid one provided
|
||||
if (empty($from_number)) {
|
||||
$from_number = get_option('twp_caller_id_number', '');
|
||||
}
|
||||
if (empty($from_number)) {
|
||||
$from_number = get_option('twp_default_sms_number', '');
|
||||
}
|
||||
// Last resort: fetch first Twilio number from API
|
||||
if (empty($from_number)) {
|
||||
try {
|
||||
require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-twp-twilio-api.php';
|
||||
$twilio = new TWP_Twilio_API();
|
||||
$numbers = $twilio->get_phone_numbers();
|
||||
if (!empty($numbers['data']['incoming_phone_numbers'][0]['phone_number'])) {
|
||||
$from_number = $numbers['data']['incoming_phone_numbers'][0]['phone_number'];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
error_log('TWP browser-voice: failed to fetch default number: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// If it's an outgoing call to a phone number
|
||||
if (strpos($to_number, 'client:') !== 0) {
|
||||
$twiml .= '<Dial timeout="30"';
|
||||
|
||||
// Add caller ID if provided
|
||||
if (!empty($from_number) && strpos($from_number, 'client:') !== 0) {
|
||||
|
||||
// Add caller ID (required for outbound calls to phone numbers)
|
||||
if (!empty($from_number)) {
|
||||
$twiml .= ' callerId="' . htmlspecialchars($from_number) . '"';
|
||||
}
|
||||
|
||||
|
||||
$twiml .= '>';
|
||||
$twiml .= '<Number>' . htmlspecialchars($to_number) . '</Number>';
|
||||
$twiml .= '</Dial>';
|
||||
@@ -400,9 +428,11 @@ class TWP_Webhooks {
|
||||
} else {
|
||||
$twiml .= '<Say voice="alice">No destination number provided.</Say>';
|
||||
}
|
||||
|
||||
|
||||
$twiml .= '</Response>';
|
||||
|
||||
|
||||
error_log('TWP browser-voice TwiML: ' . $twiml);
|
||||
|
||||
return $this->send_twiml_response($twiml);
|
||||
}
|
||||
|
||||
@@ -914,11 +944,36 @@ class TWP_Webhooks {
|
||||
// Update call status in queue if applicable
|
||||
// Remove from queue for any terminal call state
|
||||
if (in_array($status_data['CallStatus'], ['completed', 'busy', 'failed', 'canceled', 'no-answer'])) {
|
||||
// Get queue_id before removing so we can send cancel notifications
|
||||
global $wpdb;
|
||||
$calls_table = $wpdb->prefix . 'twp_queued_calls';
|
||||
$queued_call = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT queue_id FROM $calls_table WHERE call_sid = %s",
|
||||
$status_data['CallSid']
|
||||
));
|
||||
|
||||
$queue_removed = TWP_Call_Queue::remove_from_queue($status_data['CallSid']);
|
||||
if ($queue_removed) {
|
||||
TWP_Call_Logger::log_action($status_data['CallSid'], 'Call removed from queue due to status: ' . $status_data['CallStatus']);
|
||||
error_log('TWP Status Webhook: Removed call ' . $status_data['CallSid'] . ' from queue (status: ' . $status_data['CallStatus'] . ')');
|
||||
|
||||
// Cancel queue alert notifications on agents' devices
|
||||
if ($queued_call) {
|
||||
require_once plugin_dir_path(__FILE__) . 'class-twp-fcm.php';
|
||||
$fcm = new TWP_FCM();
|
||||
$fcm->cancel_queue_alert_for_queue($queued_call->queue_id, $status_data['CallSid']);
|
||||
}
|
||||
}
|
||||
|
||||
// Set auto_busy_at for agents whose call just ended, so they revert after 30s
|
||||
$agent_status_table = $wpdb->prefix . 'twp_agent_status';
|
||||
$wpdb->query($wpdb->prepare(
|
||||
"UPDATE $agent_status_table
|
||||
SET auto_busy_at = %s, current_call_sid = NULL
|
||||
WHERE current_call_sid = %s AND status = 'busy'",
|
||||
current_time('mysql'),
|
||||
$status_data['CallSid']
|
||||
));
|
||||
}
|
||||
|
||||
// Empty response
|
||||
|
||||
Reference in New Issue
Block a user