p
This commit is contained in:
@@ -88,6 +88,12 @@ try {
|
|||||||
$menuData['is_active'] = (($input['status'] ?? 'active') === 'active') ? 1 : 0;
|
$menuData['is_active'] = (($input['status'] ?? 'active') === 'active') ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guardar tipo de menú (main | no_advisor)
|
||||||
|
if (in_array('menu_type', $availableColumns)) {
|
||||||
|
$rawType = $input['menu_type'] ?? 'main';
|
||||||
|
$menuData['menu_type'] = in_array($rawType, ['main', 'no_advisor'], true) ? $rawType : 'main';
|
||||||
|
}
|
||||||
|
|
||||||
if (in_array('order_position', $availableColumns) && !$isUpdate) {
|
if (in_array('order_position', $availableColumns) && !$isUpdate) {
|
||||||
// Solo establecer order_position para menús nuevos
|
// Solo establecer order_position para menús nuevos
|
||||||
$maxOrder = $db->fetch("SELECT COALESCE(MAX(order_position), 0) as max_order FROM menus");
|
$maxOrder = $db->fetch("SELECT COALESCE(MAX(order_position), 0) as max_order FROM menus");
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* API - Cambiar modo de disponibilidad del asesor
|
||||||
|
* POST { "available": true|false }
|
||||||
|
* GET → devuelve estado actual
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once '../config/config.php';
|
||||||
|
requireAuthentication();
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||||
|
$row = $db->fetch(
|
||||||
|
"SELECT config_value FROM system_config WHERE config_key = 'advisor_available' LIMIT 1"
|
||||||
|
);
|
||||||
|
$available = $row ? (bool)(int)$row['config_value'] : true;
|
||||||
|
echo json_encode(['success' => true, 'available' => $available]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Método no permitido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
|
if (!isset($input['available'])) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Falta el campo "available"']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $input['available'] ? '1' : '0';
|
||||||
|
|
||||||
|
// Upsert en system_config
|
||||||
|
$existing = $db->fetch(
|
||||||
|
"SELECT id FROM system_config WHERE config_key = 'advisor_available' LIMIT 1"
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
$db->update(
|
||||||
|
'system_config',
|
||||||
|
['config_value' => $value, 'updated_at' => date('Y-m-d H:i:s')],
|
||||||
|
'config_key = :k',
|
||||||
|
['k' => 'advisor_available']
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$db->insert('system_config', [
|
||||||
|
'config_key' => 'advisor_available',
|
||||||
|
'config_value' => $value,
|
||||||
|
'description' => 'Indica si hay asesores disponibles (1=sí, 0=no).',
|
||||||
|
'created_at' => date('Y-m-d H:i:s'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$label = $value === '1' ? 'disponible' : 'ausente';
|
||||||
|
error_log("[AdvisorMode] Modo asesor cambiado a '{$label}' por usuario=" . ($_SESSION['user_id'] ?? 'unknown'));
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'available' => (bool)(int)$value, 'label' => $label]);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('[set_advisor_mode] Error: ' . $e->getMessage());
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Error interno del servidor']);
|
||||||
|
}
|
||||||
+2
-1
@@ -785,7 +785,8 @@ class WhatsAppBotManager {
|
|||||||
title: document.getElementById('menu-title').value,
|
title: document.getElementById('menu-title').value,
|
||||||
description: document.getElementById('menu-description').value,
|
description: document.getElementById('menu-description').value,
|
||||||
parent_id: document.getElementById('menu-parent').value || null,
|
parent_id: document.getElementById('menu-parent').value || null,
|
||||||
is_active: document.getElementById('menu-active').checked ? 1 : 0
|
is_active: document.getElementById('menu-active').checked ? 1 : 0,
|
||||||
|
menu_type: document.getElementById('menu-type')?.value || 'main'
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
+13
-3
@@ -1147,7 +1147,8 @@ class SimpleWhatsAppManager {
|
|||||||
menu_key: document.getElementById('menu-key')?.value || '',
|
menu_key: document.getElementById('menu-key')?.value || '',
|
||||||
description: document.getElementById('menu-description')?.value || '',
|
description: document.getElementById('menu-description')?.value || '',
|
||||||
welcome_message: document.getElementById('menu-welcome-message')?.value || '',
|
welcome_message: document.getElementById('menu-welcome-message')?.value || '',
|
||||||
status: document.getElementById('menu-status')?.value || 'active'
|
status: document.getElementById('menu-status')?.value || 'active',
|
||||||
|
menu_type: document.getElementById('menu-type')?.value || 'main'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validar campos requeridos
|
// Validar campos requeridos
|
||||||
@@ -3841,6 +3842,13 @@ function showEditMenuModal(menuData) {
|
|||||||
<option value="active" ${menuData.status === 'active' ? 'selected' : ''}>Activo</option>
|
<option value="active" ${menuData.status === 'active' ? 'selected' : ''}>Activo</option>
|
||||||
<option value="inactive" ${menuData.status === 'inactive' ? 'selected' : ''}>Inactivo</option>
|
<option value="inactive" ${menuData.status === 'inactive' ? 'selected' : ''}>Inactivo</option>
|
||||||
</select>
|
</select>
|
||||||
|
<label for="editMenuType" class="form-label mt-2">
|
||||||
|
<i class="fas fa-layer-group"></i> Tipo de Menú
|
||||||
|
</label>
|
||||||
|
<select class="form-control" id="editMenuType">
|
||||||
|
<option value="main" ${(menuData.menu_type || 'main') === 'main' ? 'selected' : ''}>Principal (normal)</option>
|
||||||
|
<option value="no_advisor" ${menuData.menu_type === 'no_advisor' ? 'selected' : ''}>🔴 Asesor ausente (secundario)</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -4007,13 +4015,14 @@ window.saveMenuEdit = async function() {
|
|||||||
const menuDescription = document.getElementById('editMenuDescription').value.trim();
|
const menuDescription = document.getElementById('editMenuDescription').value.trim();
|
||||||
const menuWelcome = document.getElementById('editMenuWelcome').value.trim();
|
const menuWelcome = document.getElementById('editMenuWelcome').value.trim();
|
||||||
const menuStatus = document.getElementById('editMenuStatus').value;
|
const menuStatus = document.getElementById('editMenuStatus').value;
|
||||||
|
const menuType = document.getElementById('editMenuType')?.value || 'main';
|
||||||
|
|
||||||
if (!menuName || !menuKey) {
|
if (!menuName || !menuKey) {
|
||||||
window.whatsappManager.showError('Nombre y clave del menú son obligatorios');
|
window.whatsappManager.showError('Nombre y clave del menú son obligatorios');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Guardando menú editado:', { menuId, menuName, menuKey, menuStatus });
|
console.log('Guardando menú editado:', { menuId, menuName, menuKey, menuStatus, menuType });
|
||||||
|
|
||||||
const menuData = {
|
const menuData = {
|
||||||
id: menuId,
|
id: menuId,
|
||||||
@@ -4021,7 +4030,8 @@ window.saveMenuEdit = async function() {
|
|||||||
menu_key: menuKey,
|
menu_key: menuKey,
|
||||||
description: menuDescription,
|
description: menuDescription,
|
||||||
welcome_message: menuWelcome,
|
welcome_message: menuWelcome,
|
||||||
status: menuStatus
|
status: menuStatus,
|
||||||
|
menu_type: menuType
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -879,6 +879,17 @@ if (!isUserLoggedIn()) {
|
|||||||
v1.4.0-<?php echo substr(time(), -4); ?>
|
v1.4.0-<?php echo substr(time(), -4); ?>
|
||||||
</span>
|
</span>
|
||||||
</h5>
|
</h5>
|
||||||
|
<!-- Toggle disponibilidad de asesor -->
|
||||||
|
<div style="margin-top:6px; display:flex; align-items:center; gap:8px;">
|
||||||
|
<span style="font-size:11px; color:rgba(255,255,255,0.8);">Asesor:</span>
|
||||||
|
<button id="advisor-mode-btn"
|
||||||
|
onclick="toggleAdvisorMode()"
|
||||||
|
style="font-size:11px; padding:2px 10px; border-radius:20px; border:none; cursor:pointer; font-weight:600; transition:all 0.2s;"
|
||||||
|
title="Activar/desactivar menú de asesor ausente">
|
||||||
|
…
|
||||||
|
</button>
|
||||||
|
<span id="advisor-mode-label" style="font-size:10px; color:rgba(255,255,255,0.7);"></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="index.php" class="text-white text-decoration-none">
|
<a href="index.php" class="text-white text-decoration-none">
|
||||||
@@ -8032,5 +8043,56 @@ const citasModal = (() => {
|
|||||||
<!-- Barra de sesiones minimizadas (agendamientos en paralelo) -->
|
<!-- Barra de sesiones minimizadas (agendamientos en paralelo) -->
|
||||||
<div id="labdom-pills-bar"></div>
|
<div id="labdom-pills-bar"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// ── Disponibilidad del asesor (menú secundario no_advisor) ────────────────
|
||||||
|
(function() {
|
||||||
|
var btn = document.getElementById('advisor-mode-btn');
|
||||||
|
var label = document.getElementById('advisor-mode-label');
|
||||||
|
|
||||||
|
function applyState(available) {
|
||||||
|
if (available) {
|
||||||
|
btn.textContent = '🟢 Disponible';
|
||||||
|
btn.style.background = '#25d366';
|
||||||
|
btn.style.color = '#fff';
|
||||||
|
if (label) label.textContent = 'El bot usa el menú principal';
|
||||||
|
} else {
|
||||||
|
btn.textContent = '🔴 Ausente';
|
||||||
|
btn.style.background = '#dc3545';
|
||||||
|
btn.style.color = '#fff';
|
||||||
|
if (label) label.textContent = 'El bot usa el menú de asesor ausente';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cargar estado inicial
|
||||||
|
fetch('api/set_advisor_mode.php', { credentials: 'same-origin' })
|
||||||
|
.then(function(r){ return r.json(); })
|
||||||
|
.then(function(d){ if (d && d.success !== undefined) applyState(d.available); })
|
||||||
|
.catch(function(){});
|
||||||
|
|
||||||
|
window.toggleAdvisorMode = function() {
|
||||||
|
var current = btn.textContent.indexOf('Disponible') !== -1;
|
||||||
|
var next = !current;
|
||||||
|
fetch('api/set_advisor_mode.php', {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'same-origin',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ available: next })
|
||||||
|
})
|
||||||
|
.then(function(r){ return r.json(); })
|
||||||
|
.then(function(d){
|
||||||
|
if (d && d.success) {
|
||||||
|
applyState(d.available);
|
||||||
|
var msg = d.available
|
||||||
|
? '✅ Modo asesor disponible activado. El bot usará el menú principal.'
|
||||||
|
: '⚠️ Asesor marcado como ausente. El bot usará el menú secundario.';
|
||||||
|
if (window.showToast) showToast(msg);
|
||||||
|
else alert(msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(){ alert('Error al cambiar el modo de asesor.'); });
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1769,12 +1769,26 @@ try {
|
|||||||
<label class="form-label">Mensaje de Bienvenida</label>
|
<label class="form-label">Mensaje de Bienvenida</label>
|
||||||
<textarea class="form-control" id="menu-welcome-message" rows="3" placeholder="¡Hola! Bienvenido. Por favor selecciona una opción:"></textarea>
|
<textarea class="form-control" id="menu-welcome-message" rows="3" placeholder="¡Hola! Bienvenido. Por favor selecciona una opción:"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="row">
|
||||||
<label class="form-label">Estado</label>
|
<div class="col-md-6">
|
||||||
<select class="form-control" id="menu-status">
|
<div class="mb-3">
|
||||||
<option value="active">Activo</option>
|
<label class="form-label">Estado</label>
|
||||||
<option value="inactive">Inactivo</option>
|
<select class="form-control" id="menu-status">
|
||||||
</select>
|
<option value="active">Activo</option>
|
||||||
|
<option value="inactive">Inactivo</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Tipo de Menú</label>
|
||||||
|
<select class="form-control" id="menu-type">
|
||||||
|
<option value="main">Principal (normal)</option>
|
||||||
|
<option value="no_advisor">🔴 Asesor ausente (secundario)</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">El menú <em>Asesor ausente</em> se muestra cuando el asesor está marcado como no disponible.</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- =====================================================
|
||||||
|
-- MIGRACIÓN: Menú secundario para asesor ausente
|
||||||
|
-- Fecha: 27 de mayo de 2026
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 1. Agregar columna menu_type a la tabla menus
|
||||||
|
-- Valores: 'main' (menú principal normal), 'no_advisor' (menú cuando no hay asesor)
|
||||||
|
ALTER TABLE menus
|
||||||
|
ADD COLUMN IF NOT EXISTS menu_type ENUM('main','no_advisor') NOT NULL DEFAULT 'main'
|
||||||
|
COMMENT 'Tipo de menú: main=principal, no_advisor=aparece cuando no hay asesor disponible';
|
||||||
|
|
||||||
|
-- 2. Insertar config de disponibilidad de asesores (1=disponibles, 0=ausentes)
|
||||||
|
INSERT INTO system_config (config_key, config_value, description, created_at)
|
||||||
|
VALUES ('advisor_available', '1', 'Indica si hay asesores disponibles (1=sí, 0=no). Cuando es 0, el bot muestra el menú secundario no_advisor.', NOW())
|
||||||
|
ON DUPLICATE KEY UPDATE description = VALUES(description);
|
||||||
|
|
||||||
|
SELECT '✅ Migración 20260527 completada: menu_type y advisor_available' AS status;
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Runner de migración: 20260527_add_menu_type_advisor_mode
|
||||||
|
* Agrega la columna menu_type a la tabla menus y el config advisor_available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/config/config.php';
|
||||||
|
|
||||||
|
header('Content-Type: text/plain; charset=utf-8');
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$conn = $db->getConnection();
|
||||||
|
|
||||||
|
$steps = [];
|
||||||
|
|
||||||
|
// 1. Agregar columna menu_type a menus (si no existe)
|
||||||
|
try {
|
||||||
|
$cols = $db->fetchAll("SHOW COLUMNS FROM menus LIKE 'menu_type'");
|
||||||
|
if (empty($cols)) {
|
||||||
|
$conn->exec("ALTER TABLE menus ADD COLUMN menu_type ENUM('main','no_advisor') NOT NULL DEFAULT 'main' COMMENT 'Tipo de menú: main=principal, no_advisor=aparece cuando no hay asesor'");
|
||||||
|
$steps[] = "✅ Columna menu_type agregada a menus";
|
||||||
|
} else {
|
||||||
|
$steps[] = "⚠️ Columna menu_type ya existe en menus (omitida)";
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$steps[] = "❌ Error agregando menu_type: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Insertar/actualizar system_config advisor_available
|
||||||
|
try {
|
||||||
|
$existing = $db->fetch("SELECT id FROM system_config WHERE config_key = 'advisor_available' LIMIT 1");
|
||||||
|
if ($existing) {
|
||||||
|
$steps[] = "⚠️ Config advisor_available ya existe (omitida)";
|
||||||
|
} else {
|
||||||
|
$db->insert('system_config', [
|
||||||
|
'config_key' => 'advisor_available',
|
||||||
|
'config_value' => '1',
|
||||||
|
'description' => 'Indica si hay asesores disponibles (1=sí, 0=no). Cuando es 0, el bot muestra el menú secundario no_advisor.',
|
||||||
|
'created_at' => date('Y-m-d H:i:s'),
|
||||||
|
]);
|
||||||
|
$steps[] = "✅ Config advisor_available insertada (valor inicial: 1)";
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$steps[] = "❌ Error insertando config advisor_available: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($steps as $s) {
|
||||||
|
echo $s . "\n";
|
||||||
|
}
|
||||||
|
echo "\n✔ Migración 20260527 completada.\n";
|
||||||
+24
-10
@@ -267,18 +267,32 @@ if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== tru
|
|||||||
preview = `<strong>Plantilla:</strong> ${msg.template_display_name || msg.template_name}`;
|
preview = `<strong>Plantilla:</strong> ${msg.template_display_name || msg.template_name}`;
|
||||||
if (msg.template_body) {
|
if (msg.template_body) {
|
||||||
let bodyPreview = msg.template_body;
|
let bodyPreview = msg.template_body;
|
||||||
if (msg.template_parameters && Array.isArray(msg.template_parameters)) {
|
|
||||||
// Reemplazar todas las variables en orden de aparición
|
|
||||||
// Soporta tanto {{1}}, {{2}} como {{nombre_tema}}, {{fecha}}
|
|
||||||
const regex = /\{\{[^\}]+\}\}/g;
|
|
||||||
let paramIndex = 0;
|
|
||||||
|
|
||||||
bodyPreview = bodyPreview.replace(regex, (match) => {
|
if (msg.template_parameters) {
|
||||||
const value = msg.template_parameters[paramIndex] || match;
|
const isArray = Array.isArray(msg.template_parameters);
|
||||||
paramIndex++;
|
const isObject = typeof msg.template_parameters === 'object' && !isArray;
|
||||||
return `<strong>${value}</strong>`;
|
|
||||||
});
|
if (isArray) {
|
||||||
|
// Array indexado: [0] => "valor1", [1] => "valor2"
|
||||||
|
const regex = /\{\{[^\}]+\}\}/g;
|
||||||
|
let paramIndex = 0;
|
||||||
|
|
||||||
|
bodyPreview = bodyPreview.replace(regex, (match) => {
|
||||||
|
const value = msg.template_parameters[paramIndex] || match;
|
||||||
|
paramIndex++;
|
||||||
|
return `<strong>${value}</strong>`;
|
||||||
|
});
|
||||||
|
} else if (isObject) {
|
||||||
|
// Objeto asociativo: {nombre_tema: "valor1", fecha: "valor2"}
|
||||||
|
const regex = /\{\{([^\}]+)\}\}/g;
|
||||||
|
|
||||||
|
bodyPreview = bodyPreview.replace(regex, (match, varName) => {
|
||||||
|
const value = msg.template_parameters[varName] || match;
|
||||||
|
return `<strong>${value}</strong>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preview += `<div class="message-preview">${bodyPreview}</div>`;
|
preview += `<div class="message-preview">${bodyPreview}</div>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+67
-2
@@ -790,10 +790,57 @@ class BotService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mostrar menú principal
|
* Mostrar menú principal.
|
||||||
|
* Si no hay asesores disponibles (advisor_available=0) y existe un menú de tipo
|
||||||
|
* 'no_advisor' activo, lo muestra primero en lugar del menú raíz.
|
||||||
*/
|
*/
|
||||||
private function showMainMenu($phoneNumber) {
|
private function showMainMenu($phoneNumber) {
|
||||||
try { error_log("[BotService] showMainMenu - phone={$phoneNumber} fetching root menu"); } catch (Throwable $t) {}
|
try { error_log("[BotService] showMainMenu - phone={$phoneNumber} fetching root menu"); } catch (Throwable $t) {}
|
||||||
|
|
||||||
|
// Verificar disponibilidad de asesores
|
||||||
|
$advisorAvailable = true;
|
||||||
|
try {
|
||||||
|
$cfg = $this->db->fetch(
|
||||||
|
"SELECT config_value FROM system_config WHERE config_key = 'advisor_available' LIMIT 1"
|
||||||
|
);
|
||||||
|
if ($cfg !== null && $cfg !== false) {
|
||||||
|
$advisorAvailable = (bool)(int)$cfg['config_value'];
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('[BotService] showMainMenu - failed to read advisor_available: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no hay asesor disponible, intentar mostrar el menú secundario primero
|
||||||
|
if (!$advisorAvailable) {
|
||||||
|
try {
|
||||||
|
// Verificar que la columna menu_type ya existe (puede no existir si la migración aún no corrió).
|
||||||
|
// Se cachea en static para no hacer SHOW COLUMNS en cada mensaje.
|
||||||
|
static $menuTypeColChecked = null;
|
||||||
|
if ($menuTypeColChecked === null) {
|
||||||
|
$colExists = $this->db->fetchAll("SHOW COLUMNS FROM menus LIKE 'menu_type'");
|
||||||
|
$menuTypeColChecked = !empty($colExists);
|
||||||
|
if (!$menuTypeColChecked) {
|
||||||
|
error_log('[BotService] showMainMenu - column menu_type not yet migrated, run run_20260527_menu_type.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($menuTypeColChecked) {
|
||||||
|
$noAdvisorMenu = $this->db->fetch(
|
||||||
|
"SELECT * FROM menus WHERE menu_type = 'no_advisor' AND is_active = 1 ORDER BY order_position, id LIMIT 1"
|
||||||
|
);
|
||||||
|
if ($noAdvisorMenu) {
|
||||||
|
try { error_log("[BotService] showMainMenu - no advisor available, showing no_advisor menu id={$noAdvisorMenu['id']} phone={$phoneNumber}"); } catch (Throwable $t) {}
|
||||||
|
$this->showMenu($phoneNumber, $noAdvisorMenu['id']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
error_log('[BotService] showMainMenu - advisor absent but no no_advisor menu configured, falling back to root');
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('[BotService] showMainMenu - error fetching no_advisor menu: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menú raíz principal (comportamiento normal)
|
||||||
$mainMenu = $this->db->fetch(
|
$mainMenu = $this->db->fetch(
|
||||||
"SELECT * FROM menus WHERE is_root = 1 AND is_active = 1 ORDER BY order_position LIMIT 1"
|
"SELECT * FROM menus WHERE is_root = 1 AND is_active = 1 ORDER BY order_position LIMIT 1"
|
||||||
);
|
);
|
||||||
@@ -1224,9 +1271,27 @@ class BotService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enviar mensaje por defecto cuando no hay coincidencias
|
* Enviar mensaje por defecto cuando no hay coincidencias.
|
||||||
|
* Si el asesor está marcado como ausente (advisor_available=0), muestra el menú
|
||||||
|
* secundario en lugar del mensaje genérico, para que todos los clientes que escriban
|
||||||
|
* vean el menú de asesor ausente hasta que se reactive la disponibilidad.
|
||||||
*/
|
*/
|
||||||
private function sendDefaultNoMatch($phoneNumber) {
|
private function sendDefaultNoMatch($phoneNumber) {
|
||||||
|
// Si el asesor está ausente, redirigir al menú secundario
|
||||||
|
try {
|
||||||
|
$cfg = $this->db->fetch(
|
||||||
|
"SELECT config_value FROM system_config WHERE config_key = 'advisor_available' LIMIT 1"
|
||||||
|
);
|
||||||
|
$advisorAbsent = ($cfg !== null && $cfg !== false) && !(bool)(int)$cfg['config_value'];
|
||||||
|
if ($advisorAbsent) {
|
||||||
|
error_log("[BotService] sendDefaultNoMatch - advisor absent, redirecting to showMainMenu for phone={$phoneNumber}");
|
||||||
|
$this->showMainMenu($phoneNumber);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('[BotService] sendDefaultNoMatch - failed to read advisor_available: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$defaultMessage = "🤖 No entendí su mensaje. Escriba *MENU* para ver las opciones disponibles o *ASESOR* para obtener ayuda.";
|
$defaultMessage = "🤖 No entendí su mensaje. Escriba *MENU* para ver las opciones disponibles o *ASESOR* para obtener ayuda.";
|
||||||
$this->whatsappService->sendTextMessage($phoneNumber, $defaultMessage);
|
$this->whatsappService->sendTextMessage($phoneNumber, $defaultMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user