diff --git a/services/NormalBot.php b/services/NormalBot.php index 4f816b1..13ce3be 100644 --- a/services/NormalBot.php +++ b/services/NormalBot.php @@ -623,7 +623,7 @@ class NormalBot $lf = $cfg['label_field'] ?? 'label'; $pagina = max(0, (int)($cfg['__page'] ?? 0)); - $porPagina = self::LISTA_MAX_FILAS - 2; + $porPagina = self::LISTA_MAX_FILAS - (empty($cfg['__ver_todos']) ? 2 : 3); $hayMas = count($items) > $porPagina; $visibles = $hayMas ? array_slice($items, $pagina * $porPagina, $porPagina) : $items; @@ -640,6 +640,10 @@ class NormalBot $rows[] = ['id' => '__mas', 'title' => '➕ Ver más', 'description' => "Faltan {$restantes}"]; } + if (!empty($cfg['__ver_todos'])) { + $rows[] = ['id' => '__todos', 'title' => '🔎 Otro lote', 'description' => 'Ver el listado completo']; + } + $n = count($elegidos); $rows[] = [ 'id' => '__listo', @@ -1145,6 +1149,14 @@ class NormalBot $key = $field['key']; $elegidos = $cap['__multi'][$key] ?? []; + if ($value === '__todos') { + $cap['__todos'][$key] = true; + $cap['__page'][$key] = 0; + $meta['__cap'] = $cap; + ConversationContext::updateMetadata($ctxId, $meta); + return self::capAskNext($cap, $context['from'], $company, $ctxId); + } + if ($value === '__listo') { if (empty($elegidos)) { WhatsAppSender::sendText($context['from'], '⚠️ Elige al menos una opción.', (string)($context['phone_number_id'] ?? '')); @@ -1153,7 +1165,7 @@ class NormalBot // strval explícito: PHP convierte a int las claves numéricas $cap['collected'][$key] = array_map('strval', array_keys($elegidos)); $cap['collected_labels'][$key] = implode(', ', array_values($elegidos)); - unset($cap['__multi'][$key], $cap['__page'][$key]); + unset($cap['__multi'][$key], $cap['__page'][$key], $cap['__todos'][$key]); $cap['index'] = $idx + 1; while ($cap['index'] < count($fields) && self::capShouldSkip($fields[$cap['index']], $cap['collected'])) { $cap['index']++; } $meta['__cap'] = $cap; @@ -1375,8 +1387,16 @@ class NormalBot // ── multi_select: acumula varias opciones antes de continuar ───────── if ($type === 'multi_select') { + // Por defecto llega una lista corta con los mas relevantes; "Otro" + // cambia al catalogo completo sin perder lo ya marcado. + $verTodos = !empty($cap['__todos'][$field['key']]); + $claveSrc = $verTodos && !empty($field['full_endpoint_key']) + ? $field['full_endpoint_key'] + : ($field['source_endpoint_key'] ?? ''); + $items = self::fetchDynamicList( - self::resolverPorCampos($field['source_endpoint_key'] ?? '', $cap['collected'] ?? []), + self::resolverPorCampos($claveSrc, + $cap['collected'] ?? []), $company, ['__ep_vars_combined' => $cap['collected'] ?? []], $to @@ -1402,6 +1422,7 @@ class NormalBot 'body' => $field['prompt'] ?? 'Puedes elegir varios:', 'section_title' => $field['label'] ?? $field['key'], '__page' => (int)($cap['__page'][$field['key']] ?? 0), + '__ver_todos' => !$verTodos && !empty($field['full_endpoint_key']), ], $cap['__multi'][$field['key']] ?? [], $to, $company); } diff --git a/setup/seed_palmas.php b/setup/seed_palmas.php index ba81de0..2ae9729 100644 --- a/setup/seed_palmas.php +++ b/setup/seed_palmas.php @@ -541,6 +541,8 @@ $configJson = [ 'prompt' => 'Elige los lotes (puedes marcar varios):', // Apertura ofrece los lotes de la finca; cierre, solo los abiertos 'source_endpoint_key' => 'lotes_{accion}_dn', + // "Otro lote" cambia al listado completo + 'full_endpoint_key' => 'lotes_{accion}_todos_dn', 'value_field' => 'id', 'label_field' => 'label', 'empty_text' => '⚠️ No hay lotes disponibles para esta combinación.', @@ -690,8 +692,11 @@ $endpoints = [ // ── Carga de ciclos ───────────────────────────────────────────────────── // {ciclo} y {accion} se resuelven con lo que el usuario ya eligió, así los // seis tipos y las dos acciones comparten estas tres entradas. - ['key' => 'lotes_apertura_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_x_finca&finca_id={finca_id}'], + // Los 10 mas atrasados; con todos=1, el listado completo para "Otro lote" + ['key' => 'lotes_apertura_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_apertura_dn&ciclo={ciclo}&finca_id={finca_id}'], ['key' => 'lotes_cierre_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_abiertos_dn&ciclo={ciclo}&finca_id={finca_id}'], + ['key' => 'lotes_apertura_todos_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_apertura_dn&ciclo={ciclo}&finca_id={finca_id}&todos=1'], + ['key' => 'lotes_cierre_todos_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_abiertos_dn&ciclo={ciclo}&finca_id={finca_id}&todos=1'], ['key' => 'ciclos_up', 'dir' => 'upload', 'url' => $BASE . '?peticion=ciclos_{ciclo}_up'], // Todos los lotes (PDF) por ciclo ['key' => 'cosecha_todos_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=ciclos_cosecha_dn&finca_id={finca_id}'], diff --git a/setup/test_navegacion.php b/setup/test_navegacion.php index d901f48..afaa223 100644 --- a/setup/test_navegacion.php +++ b/setup/test_navegacion.php @@ -509,6 +509,39 @@ foreach (['show_main_menu', 'descargar_informes', 'enviar_informacion'] as $k) { check('el bot ya no reordena por su cuenta', isset(flowsDe($config, '3')['registrar_ausentismo']['fields'][1]['frecuentes']), false); +echo "\nLotes para abrir y cerrar ciclos\n"; + +$cfl = array_column($flows['registrar_ciclo']['fields'], null, 'key')['lote_ids']; +check('apertura y cierre usan catálogos distintos', + $cfl['source_endpoint_key'], 'lotes_{accion}_dn'); +check('y "Otro lote" trae el listado completo', + $cfl['full_endpoint_key'], 'lotes_{accion}_todos_dn'); + +$resolver = function (string $t, array $c): string { + foreach ($c as $k => $v) $t = str_replace('{' . $k . '}', (string)$v, $t); + return $t; +}; +foreach (['apertura', 'cierre'] as $acc) { + check("{$acc}: catálogo corto", $resolver($cfl['source_endpoint_key'], ['accion' => $acc]), "lotes_{$acc}_dn"); + check("{$acc}: catálogo completo", $resolver($cfl['full_endpoint_key'], ['accion' => $acc]), "lotes_{$acc}_todos_dn"); + foreach ([$acc . '_dn', $acc . '_todos_dn'] as $sufijo) { + check("endpoint lotes_{$sufijo} registrado", isset($eps['lotes_' . $sufijo]), true); + } +} + +// Con "Otro" visible se reservan tres filas: paginar, ver todos y listo +$filas = function (int $total, bool $verTodos): int { + $max = 10; + $porPagina = $max - ($verTodos ? 3 : 2); + $hayMas = $total > $porPagina; + $n = min($total, $porPagina); + if ($hayMas) $n++; + if ($verTodos) $n++; + return $n + 1; +}; +check('la lista corta entra en el límite de WhatsApp', $filas(10, true) <= 10, true); +check('el listado completo también', $filas(40, false) <= 10, true); + echo "\nAlcance de fincas por número\n"; /**