fix: resolveMenu usa menus fusionados de per_type + bugs de $endpoint y tipo de retorno

- resolveMenu ahora recibe los menus ya fusionados (global + per_type) para
  que flujos que referencian menús de otro per_type se resuelvan correctamente
- handleFlow y processInteractive propagan el array de menus fusionados
- Corrige variable indefinida $endpoint → $endpointKey en 3 logs de executeApiReport
- buildMenuResponse cambia tipo de retorno a ?array para evitar TypeError en PHP 8
- BD: flow global show_main_menu apunta a menú show_main_menu (completo) en lugar
  de show_menu_cat2 (solo existía en per_type[2]), fix para usuarios permission_type=3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-27 19:09:24 -05:00
co-authored by Claude Sonnet 4.6
parent 932a7a78a7
commit e4841e2741
+20 -17
View File
@@ -21,7 +21,7 @@ class NormalBot
$normalized = self::normalize($input);
if ($currentNode !== null && isset($flows[$currentNode])) {
return self::handleFlow($flows[$currentNode], $context, $company, $ctxId);
return self::handleFlow($flows[$currentNode], $context, $company, $ctxId, $menus);
}
$matchedCommand = null;
@@ -36,7 +36,7 @@ class NormalBot
ConversationContext::updateNode($ctxId, $matchedCommand);
if (isset($flows[$matchedCommand])) {
return self::handleFlow($flows[$matchedCommand], $context, $company, $ctxId);
return self::handleFlow($flows[$matchedCommand], $context, $company, $ctxId, $menus);
}
if (isset($menus[$matchedCommand])) {
@@ -51,7 +51,7 @@ class NormalBot
$greetingFlowId = $perType['greeting_flow'] ?? 'greeting';
if (isset($flows[$greetingFlowId])) {
ConversationContext::updateNode($ctxId, $greetingFlowId);
return self::handleFlow($flows[$greetingFlowId], $context, $company, $ctxId);
return self::handleFlow($flows[$greetingFlowId], $context, $company, $ctxId, $menus);
}
$response = self::sendText($greeting, $context['from'], $company);
@@ -62,7 +62,7 @@ class NormalBot
$fallbackFlowId = $perType['fallback_flow'] ?? $config['fallback_flow'] ?? null;
if ($fallbackFlowId !== null && isset($flows[$fallbackFlowId])) {
ConversationContext::updateNode($ctxId, $fallbackFlowId);
return self::handleFlow($flows[$fallbackFlowId], $context, $company, $ctxId);
return self::handleFlow($flows[$fallbackFlowId], $context, $company, $ctxId, $menus);
}
$fallback = $perType['fallback'] ?? $config['fallback'] ?? null;
@@ -74,24 +74,26 @@ class NormalBot
return null;
}
private static function resolveMenu($menuRef, array $company): array
private static function resolveMenu($menuRef, array $company, array $allMenus = []): array
{
if (is_string($menuRef)) {
if (isset($allMenus[$menuRef])) {
return $allMenus[$menuRef];
}
$config = self::getConfig($company);
$menus = $config['menus'] ?? [];
return $menus[$menuRef] ?? [];
return ($config['menus'] ?? [])[$menuRef] ?? [];
}
return is_array($menuRef) ? $menuRef : [];
}
private static function handleFlow(array $flow, array $context, array $company, int $ctxId): ?array
private static function handleFlow(array $flow, array $context, array $company, int $ctxId, array $menus = []): ?array
{
$type = $flow['type'] ?? 'text';
return match ($type) {
'text' => self::sendText($flow['message'] ?? '', $context['from'], $company),
'image' => self::sendImage($flow['media_id'] ?? '', $flow['caption'] ?? null, $context['from'], $company),
'menu' => self::buildMenuResponse(self::resolveMenu($flow['menu'] ?? [], $company), $context['from'], $company),
'menu' => self::buildMenuResponse(self::resolveMenu($flow['menu'] ?? [], $company, $menus), $context['from'], $company),
'function' => self::executeFunction($flow['function'] ?? '', $flow['params'] ?? [], $context, $company, $ctxId),
default => null,
};
@@ -167,12 +169,12 @@ class NormalBot
curl_close($ch);
if ($error) {
self::log("API report error [{$endpoint}]: {$error}");
self::log("API report error [{$endpointKey}]: {$error}");
return self::sendText('Error al obtener el reporte. Intenta de nuevo.', $context['from'], $company);
}
if ($httpCode >= 400) {
self::log("API report HTTP {$httpCode} [{$endpoint}]: " . mb_substr($content, 0, 200));
self::log("API report HTTP {$httpCode} [{$endpointKey}]: " . mb_substr($content, 0, 200));
return self::sendText('Error al obtener el reporte. Intenta de nuevo.', $context['from'], $company);
}
@@ -205,7 +207,7 @@ class NormalBot
$upload = WhatsAppSender::uploadMedia($tmpFile, $mime, $phoneNumberId);
if (!$upload['success'] || !$upload['media_id']) {
self::log("API report upload failed [{$endpoint}]: " . ($upload['error'] ?? 'unknown'));
self::log("API report upload failed [{$endpointKey}]: " . ($upload['error'] ?? 'unknown'));
return self::sendText('Error al enviar el reporte. Intenta de nuevo.', $context['from'], $company);
}
@@ -219,7 +221,7 @@ class NormalBot
return null;
}
private static function buildMenuResponse(array $menu, string $to, array $company): array
private static function buildMenuResponse(array $menu, string $to, array $company): ?array
{
$menuType = $menu['type'] ?? 'list';
@@ -283,7 +285,7 @@ class NormalBot
return self::enqueueInteractive($to, $interactive, $company);
}
return null;
return null; // tipo de menú desconocido
}
private static function sendText(string $text, string $to, array $company): array
@@ -339,19 +341,20 @@ class NormalBot
$permType = (string)($company['_permission_type'] ?? 1);
$perType = $config['per_type'][$permType] ?? [];
$flows = array_merge($config['flows'] ?? [], $perType['flows'] ?? []);
$menus = array_merge($config['menus'] ?? [], $perType['menus'] ?? []);
$botCtx = ConversationContext::getOrCreate((int)$company['id'], $context['from'], 'normal');
$ctxId = (int)$botCtx['id'];
foreach ($flows as $flowId => $flow) {
if (($flow['type'] ?? '') === 'menu') {
$menu = self::resolveMenu($flow['menu'] ?? [], $company);
$menu = self::resolveMenu($flow['menu'] ?? [], $company, $menus);
foreach ($menu['sections'] ?? [] as $section) {
foreach ($section['rows'] ?? [] as $row) {
if (($row['id'] ?? '') === $input) {
ConversationContext::updateNode($ctxId, $row['id']);
if (isset($flows[$row['id']])) {
return self::handleFlow($flows[$row['id']], $context, $company, $ctxId);
return self::handleFlow($flows[$row['id']], $context, $company, $ctxId, $menus);
}
return null;
}
@@ -361,7 +364,7 @@ class NormalBot
if (($btn['id'] ?? '') === $input) {
ConversationContext::updateNode($ctxId, $btn['id']);
if (isset($flows[$btn['id']])) {
return self::handleFlow($flows[$btn['id']], $context, $company, $ctxId);
return self::handleFlow($flows[$btn['id']], $context, $company, $ctxId, $menus);
}
return null;
}