up
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
require_once '../config/config.php';
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
requireAuthentication();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
|
||||||
|
$userId = isset($input['user_id']) ? intval($input['user_id']) : 0;
|
||||||
|
if (!$userId) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['success' => false, 'error' => 'user_id required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$user = $db->fetch('SELECT phone_number FROM users WHERE id = :id', ['id' => $userId]);
|
||||||
|
if (!$user) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo json_encode(['success' => false, 'error' => 'User not found']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$operator = $_SESSION['admin_user'] ?? null;
|
||||||
|
$operatorId = $operator['id'] ?? null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
require_once __DIR__ . '/../services/BotService.php';
|
||||||
|
$bot = new BotService();
|
||||||
|
$bot->finishAttendConversation($user['phone_number'], $operatorId);
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Fallback: clear in_service and log activity
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$db->update('users', ['in_service' => 0, 'in_service_by' => null, 'in_service_at' => null, 'advisor_requested' => 0], 'id = :id', ['id' => $userId]);
|
||||||
|
$db->insert('operator_activity', ['user_id' => $userId, 'operator_id' => $operatorId, 'action' => 'finish', 'details' => 'Finished attending via fallback', 'created_at' => $now]);
|
||||||
|
echo json_encode(['success' => true, 'warning' => 'BotService failed, fallback applied']);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -477,6 +477,7 @@
|
|||||||
<small id="chat-phone">+1234567890</small>
|
<small id="chat-phone">+1234567890</small>
|
||||||
<div style="font-size:12px; margin-top:4px;">
|
<div style="font-size:12px; margin-top:4px;">
|
||||||
<button id="attend-btn" class="btn btn-sm btn-outline-success" style="display:none; margin-right:6px;">Atender</button>
|
<button id="attend-btn" class="btn btn-sm btn-outline-success" style="display:none; margin-right:6px;">Atender</button>
|
||||||
|
<button id="finish-attend-btn" class="btn btn-sm btn-outline-warning" style="display:none; margin-right:6px;">Finalizar atención</button>
|
||||||
<button id="release-hold-btn" class="btn btn-sm btn-outline-primary" style="display:none">Liberar espera</button>
|
<button id="release-hold-btn" class="btn btn-sm btn-outline-primary" style="display:none">Liberar espera</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -892,6 +893,7 @@
|
|||||||
|
|
||||||
// Attender (marcar 'en servicio' sin liberar)
|
// Attender (marcar 'en servicio' sin liberar)
|
||||||
const attendBtn = document.getElementById('attend-btn');
|
const attendBtn = document.getElementById('attend-btn');
|
||||||
|
const finishBtn = document.getElementById('finish-attend-btn');
|
||||||
if (attendBtn) {
|
if (attendBtn) {
|
||||||
attendBtn.style.display = (conv.advisor_requested && !conv.in_service) ? 'inline-block' : 'none';
|
attendBtn.style.display = (conv.advisor_requested && !conv.in_service) ? 'inline-block' : 'none';
|
||||||
attendBtn.onclick = async () => {
|
attendBtn.onclick = async () => {
|
||||||
@@ -915,6 +917,8 @@
|
|||||||
attendBtn.style.display = 'none';
|
attendBtn.style.display = 'none';
|
||||||
// keep release available
|
// keep release available
|
||||||
releaseBtn.style.display = 'inline-block';
|
releaseBtn.style.display = 'inline-block';
|
||||||
|
// show finish button
|
||||||
|
if (finishBtn) finishBtn.style.display = 'inline-block';
|
||||||
await this.loadConversations();
|
await this.loadConversations();
|
||||||
} else {
|
} else {
|
||||||
alert('Error al marcar como atendida');
|
alert('Error al marcar como atendida');
|
||||||
@@ -925,6 +929,40 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finalizar atención: enviar encuesta y limpiar estado
|
||||||
|
if (finishBtn) {
|
||||||
|
finishBtn.style.display = conv.in_service ? 'inline-block' : 'none';
|
||||||
|
finishBtn.onclick = async () => {
|
||||||
|
if (!confirm('¿Finalizar atención y enviar encuesta al usuario?')) return;
|
||||||
|
try {
|
||||||
|
const resp = await fetch('api/finish_attend.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ user_id: userId })
|
||||||
|
});
|
||||||
|
if (resp.status === 401) {
|
||||||
|
alert('Sesión expirada. Por favor inicie sesión de nuevo.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const json = await resp.json();
|
||||||
|
if (json && json.success) {
|
||||||
|
conv.in_service = false;
|
||||||
|
conv.advisor_requested = 0;
|
||||||
|
holdIndicator.style.display = 'none';
|
||||||
|
finishBtn.style.display = 'none';
|
||||||
|
releaseBtn.style.display = 'none';
|
||||||
|
attendBtn.style.display = 'none';
|
||||||
|
await this.loadConversations();
|
||||||
|
} else {
|
||||||
|
alert('Error al finalizar la atención');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error finalizing attend', e);
|
||||||
|
alert('Error al finalizar la atención');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../config/config.php';
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$id = $db->insert('operator_activity', ['user_id' => 1, 'operator_id' => 1, 'action' => 'test', 'details' => 'test insert', 'created_at' => $now]);
|
||||||
|
var_dump($id);
|
||||||
|
$rows = $db->fetchAll('SELECT * FROM operator_activity ORDER BY created_at DESC LIMIT 5');
|
||||||
|
var_dump($rows);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../config/config.php';
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$rows = $db->fetchAll('SELECT * FROM operator_activity ORDER BY created_at DESC LIMIT 10');
|
||||||
|
foreach ($rows as $r) {
|
||||||
|
echo json_encode($r) . PHP_EOL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../config/config.php';
|
||||||
|
require_once __DIR__ . '/../services/BotService.php';
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$phone = '573000000999';
|
||||||
|
// Cleanup
|
||||||
|
$db->execute('DELETE FROM users WHERE phone_number = :p', ['p' => $phone]);
|
||||||
|
$id = $db->insert('users', ['phone_number' => $phone, 'status' => 'active', 'created_at' => date('Y-m-d H:i:s')]);
|
||||||
|
$db->update('users', ['advisor_requested' => 1], 'id = :id', ['id' => $id]);
|
||||||
|
|
||||||
|
$bot = new BotService();
|
||||||
|
$bot->attendConversation($phone, 1);
|
||||||
|
|
||||||
|
$user = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $id]);
|
||||||
|
$activity = $db->fetch('SELECT * FROM operator_activity WHERE user_id = :uid ORDER BY created_at DESC LIMIT 1', ['uid' => $id]);
|
||||||
|
|
||||||
|
echo "User in_service: " . ($user['in_service'] ?? 'NULL') . PHP_EOL;
|
||||||
|
echo "in_service_by: " . ($user['in_service_by'] ?? 'NULL') . PHP_EOL;
|
||||||
|
echo "in_service_at: " . ($user['in_service_at'] ?? 'NULL') . PHP_EOL;
|
||||||
|
|
||||||
|
if ($activity) {
|
||||||
|
echo "Activity: action={$activity['action']} operator_id={$activity['operator_id']} details={$activity['details']}\n";
|
||||||
|
} else {
|
||||||
|
echo "No operator activity found\n";
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../config/config.php';
|
||||||
|
require_once __DIR__ . '/../services/BotService.php';
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$phone = '573000000998';
|
||||||
|
// Cleanup
|
||||||
|
$db->execute('DELETE FROM users WHERE phone_number = :p', ['p' => $phone]);
|
||||||
|
$id = $db->insert('users', ['phone_number' => $phone, 'status' => 'active', 'created_at' => date('Y-m-d H:i:s')]);
|
||||||
|
$db->update('users', ['advisor_requested' => 1], 'id = :id', ['id' => $id]);
|
||||||
|
|
||||||
|
$bot = new BotService();
|
||||||
|
$bot->attendConversation($phone, 1);
|
||||||
|
$user = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $id]);
|
||||||
|
echo "After attend: in_service={$user['in_service']} in_service_by={$user['in_service_by']}\n";
|
||||||
|
|
||||||
|
$bot->finishAttendConversation($phone, 1);
|
||||||
|
$user2 = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $id]);
|
||||||
|
echo "After finish: in_service={$user2['in_service']} in_service_by={$user2['in_service_by']}\n";
|
||||||
|
$activity = $db->fetch('SELECT * FROM operator_activity WHERE user_id = :uid ORDER BY created_at DESC LIMIT 1', ['uid' => $id]);
|
||||||
|
if ($activity) {
|
||||||
|
echo "Activity: action={$activity['action']} details={$activity['details']}\n";
|
||||||
|
} else {
|
||||||
|
echo "No activity\n";
|
||||||
|
}
|
||||||
@@ -545,6 +545,50 @@ class BotService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalizar la atención: limpiar estado 'in_service' y enviar plantilla de encuesta
|
||||||
|
*/
|
||||||
|
public function finishAttendConversation($phoneNumber, $operatorId = null) {
|
||||||
|
try {
|
||||||
|
// Limpiar estado de 'in_service'
|
||||||
|
$this->db->update('users', ['in_service' => 0, 'in_service_by' => null, 'in_service_at' => null, 'advisor_requested' => 0], 'phone_number = :phone', ['phone' => $phoneNumber]);
|
||||||
|
|
||||||
|
// Enviar plantilla de encuesta (configurable)
|
||||||
|
$template = getConfigFromDB('survey_template', 'encuesta_satisfaccin');
|
||||||
|
$lang = getConfigFromDB('survey_template_language', 'es');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->whatsappService->sendTemplateMessage($phoneNumber, $template, $lang, []);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Ignorar errores de envío de plantilla pero loguear
|
||||||
|
error_log('Failed to send survey template: ' . $e->getMessage());
|
||||||
|
if (function_exists('writeLog')) writeLog('WARN', 'Failed to send survey template: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registrar actividad del operador
|
||||||
|
$user = $this->db->fetch('SELECT id FROM users WHERE phone_number = :phone', ['phone' => $phoneNumber]);
|
||||||
|
$userId = $user['id'] ?? null;
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$activity = [
|
||||||
|
'user_id' => $userId,
|
||||||
|
'operator_id' => $operatorId,
|
||||||
|
'action' => 'finish',
|
||||||
|
'details' => "Finished attend and sent survey: {$template}",
|
||||||
|
'created_at' => $now
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
$this->db->insert('operator_activity', $activity);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('Failed to insert operator_activity on finish: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('writeLog')) writeLog('INFO', "Operator {$operatorId} finished attending for {$phoneNumber}, survey={$template}");
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('finishAttendConversation failed: ' . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actualizar estado del menú del usuario
|
* Actualizar estado del menú del usuario
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user