Fix FCM token registration and add queue reminder alerts
- Fix silent insert failure in FCM token registration (missing NOT NULL refresh_token column) so WebView app tokens are actually stored - Add 1-minute queue reminder cron that re-sends FCM alerts for calls still waiting, with transient-based throttle to prevent duplicates - Send FCM cancel on queue dequeue (answered/hangup/timeout), not just on final call status webhook - Clean up new cron hook on plugin deactivation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -577,6 +577,69 @@ class TWP_Call_Queue {
|
|||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cron callback: re-send FCM queue alerts every minute for calls still waiting.
|
||||||
|
* Only alerts for calls that have been waiting > 60 seconds (initial alert
|
||||||
|
* already sent on entry). Skips re-alerting for the same call within 55 seconds
|
||||||
|
* using a short transient to avoid overlap with the 60-second cron.
|
||||||
|
*/
|
||||||
|
public static function send_queue_reminders() {
|
||||||
|
global $wpdb;
|
||||||
|
$calls_table = $wpdb->prefix . 'twp_queued_calls';
|
||||||
|
$queue_table = $wpdb->prefix . 'twp_call_queues';
|
||||||
|
|
||||||
|
// Find calls waiting longer than 60 seconds
|
||||||
|
$waiting_calls = $wpdb->get_results(
|
||||||
|
"SELECT c.*, q.queue_name, q.user_id AS queue_owner_id, q.agent_group_id
|
||||||
|
FROM $calls_table c
|
||||||
|
JOIN $queue_table q ON q.id = c.queue_id
|
||||||
|
WHERE c.status = 'waiting'
|
||||||
|
AND c.joined_at <= DATE_SUB(NOW(), INTERVAL 60 SECOND)"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (empty($waiting_calls)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once dirname(__FILE__) . '/class-twp-fcm.php';
|
||||||
|
$fcm = new TWP_FCM();
|
||||||
|
|
||||||
|
foreach ($waiting_calls as $call) {
|
||||||
|
// Throttle: skip if we reminded for this call within the last 55 seconds
|
||||||
|
$transient_key = 'twp_queue_remind_' . $call->call_sid;
|
||||||
|
if (get_transient($transient_key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
set_transient($transient_key, 1, 55);
|
||||||
|
|
||||||
|
$waiting_minutes = max(1, round((time() - strtotime($call->joined_at)) / 60));
|
||||||
|
$title = 'Call Still Waiting';
|
||||||
|
$body = "Call from {$call->from_number} waiting {$waiting_minutes}m in {$call->queue_name}";
|
||||||
|
|
||||||
|
$notified_users = array();
|
||||||
|
|
||||||
|
// Notify queue owner
|
||||||
|
if (!empty($call->queue_owner_id)) {
|
||||||
|
$fcm->notify_queue_alert($call->queue_owner_id, $call->from_number, $call->queue_name, $call->call_sid);
|
||||||
|
$notified_users[] = $call->queue_owner_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify agent group members
|
||||||
|
if (!empty($call->agent_group_id)) {
|
||||||
|
require_once dirname(__FILE__) . '/class-twp-agent-groups.php';
|
||||||
|
$members = TWP_Agent_Groups::get_group_members($call->agent_group_id);
|
||||||
|
foreach ($members as $member) {
|
||||||
|
if (!in_array($member->user_id, $notified_users)) {
|
||||||
|
$fcm->notify_queue_alert($member->user_id, $call->from_number, $call->queue_name, $call->call_sid);
|
||||||
|
$notified_users[] = $member->user_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("TWP Queue Reminder: Re-alerted " . count($notified_users) . " user(s) for call {$call->call_sid} waiting {$waiting_minutes}m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify agents via SMS when a call enters the queue
|
* Notify agents via SMS when a call enters the queue
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -266,6 +266,9 @@ class TWP_Core {
|
|||||||
$queue = new TWP_Call_Queue();
|
$queue = new TWP_Call_Queue();
|
||||||
$this->loader->add_action('twp_process_queue', $queue, 'process_waiting_calls');
|
$this->loader->add_action('twp_process_queue', $queue, 'process_waiting_calls');
|
||||||
|
|
||||||
|
// Queue reminder alerts (re-send FCM every minute for waiting calls)
|
||||||
|
add_action('twp_queue_reminders', array('TWP_Call_Queue', 'send_queue_reminders'));
|
||||||
|
|
||||||
// Callback processing
|
// Callback processing
|
||||||
$this->loader->add_action('twp_process_callbacks', 'TWP_Callback_Manager', 'process_callbacks');
|
$this->loader->add_action('twp_process_callbacks', 'TWP_Callback_Manager', 'process_callbacks');
|
||||||
|
|
||||||
@@ -281,6 +284,10 @@ class TWP_Core {
|
|||||||
wp_schedule_event(time(), 'twp_every_30_seconds', 'twp_process_queue');
|
wp_schedule_event(time(), 'twp_every_30_seconds', 'twp_process_queue');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wp_next_scheduled('twp_queue_reminders')) {
|
||||||
|
wp_schedule_event(time(), 'twp_every_minute', 'twp_queue_reminders');
|
||||||
|
}
|
||||||
|
|
||||||
if (!wp_next_scheduled('twp_process_callbacks')) {
|
if (!wp_next_scheduled('twp_process_callbacks')) {
|
||||||
wp_schedule_event(time(), 'twp_every_minute', 'twp_process_callbacks');
|
wp_schedule_event(time(), 'twp_every_minute', 'twp_process_callbacks');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class TWP_Deactivator {
|
|||||||
// Clear scheduled events
|
// Clear scheduled events
|
||||||
wp_clear_scheduled_hook('twp_check_schedules');
|
wp_clear_scheduled_hook('twp_check_schedules');
|
||||||
wp_clear_scheduled_hook('twp_process_queue');
|
wp_clear_scheduled_hook('twp_process_queue');
|
||||||
|
wp_clear_scheduled_hook('twp_queue_reminders');
|
||||||
wp_clear_scheduled_hook('twp_auto_revert_agents');
|
wp_clear_scheduled_hook('twp_auto_revert_agents');
|
||||||
|
|
||||||
// Flush rewrite rules
|
// Flush rewrite rules
|
||||||
|
|||||||
@@ -55,17 +55,32 @@ class TWP_Mobile_Phone_Page {
|
|||||||
$user_id, $fcm_token
|
$user_id, $fcm_token
|
||||||
));
|
));
|
||||||
|
|
||||||
if (!$existing) {
|
if ($existing) {
|
||||||
|
// Refresh the expiry on existing session
|
||||||
|
$wpdb->update($table,
|
||||||
|
array('expires_at' => date('Y-m-d H:i:s', time() + 7 * DAY_IN_SECONDS)),
|
||||||
|
array('id' => $existing->id),
|
||||||
|
array('%s'),
|
||||||
|
array('%d')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
$wpdb->insert($table, array(
|
$wpdb->insert($table, array(
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
|
'refresh_token' => 'webview-' . wp_generate_password(32, false),
|
||||||
'fcm_token' => $fcm_token,
|
'fcm_token' => $fcm_token,
|
||||||
'device_info' => 'WebView Mobile App',
|
'device_info' => 'WebView Mobile App',
|
||||||
'is_active' => 1,
|
'is_active' => 1,
|
||||||
'created_at' => current_time('mysql'),
|
'created_at' => current_time('mysql'),
|
||||||
'expires_at' => date('Y-m-d H:i:s', time() + 7 * DAY_IN_SECONDS),
|
'expires_at' => date('Y-m-d H:i:s', time() + 7 * DAY_IN_SECONDS),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if ($wpdb->last_error) {
|
||||||
|
error_log('TWP FCM: Failed to insert token: ' . $wpdb->last_error);
|
||||||
|
wp_send_json_error('Failed to store token');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_log("TWP FCM: Token registered for user $user_id");
|
||||||
wp_send_json_success('FCM token registered');
|
wp_send_json_success('FCM token registered');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1276,6 +1276,20 @@ class TWP_Webhooks {
|
|||||||
|
|
||||||
if ($updated) {
|
if ($updated) {
|
||||||
error_log('TWP Queue Action: Updated call status to ' . $status);
|
error_log('TWP Queue Action: Updated call status to ' . $status);
|
||||||
|
|
||||||
|
// Cancel FCM queue alerts when call leaves the queue for any reason
|
||||||
|
if (in_array($status, array('answered', 'hangup', 'transferred', 'timeout', 'completed'))) {
|
||||||
|
$queued_call = $wpdb->get_row($wpdb->prepare(
|
||||||
|
"SELECT queue_id FROM $table_name WHERE call_sid = %s",
|
||||||
|
$call_sid
|
||||||
|
));
|
||||||
|
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, $call_sid);
|
||||||
|
error_log('TWP Queue Action: Sent FCM cancel for call ' . $call_sid);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
error_log('TWP Queue Action: No call found to update with SID ' . $call_sid);
|
error_log('TWP Queue Action: No call found to update with SID ' . $call_sid);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user