From 5ee2cfe2e6e968376395d72093a6708ed0c73224 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Wed, 19 Aug 2026 22:50:48 -0500 Subject: [PATCH] fix: los lotes de ciclos mezclaban fincas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Los catalogos de los campos select y multi_select pedian la lista mandando solo lo recolectado en el formulario, nunca el metadata de la conversacion: la finca elegida no viajaba, {finca_id} quedaba sin resolver en la URL y el ERP lo leia como 0 —todas las fincas—. Elegir REPOSO y ver lotes de otras fincas, tal cual lo reporto el usuario. Ahora el metadata acompana lo recolectado en ambos puntos. Los fixtures delatan la fuga —sin finca_id valido cuelan un lote ajeno— y dos casos nuevos verifican que a los catalogos de ciclos y labores solo lleguen lotes de la finca elegida. De paso el select simple gana resolverPorCampos en su clave, que el multi ya tenia: un catalogo por campo puede depender de lo elegido antes. Co-Authored-By: Claude Sonnet 4.6 --- services/NormalBot.php | 18 ++++++++++++++++-- setup/tests/fixtures_api.php | 11 +++++++---- setup/tests/test_flujos.php | 5 +++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/services/NormalBot.php b/services/NormalBot.php index 8fc9931..ad8cc86 100644 --- a/services/NormalBot.php +++ b/services/NormalBot.php @@ -1447,7 +1447,13 @@ class NormalBot self::resolverPorCampos($claveSrc, $cap['collected'] ?? []), $company, - ['__ep_vars_combined' => $cap['collected'] ?? []], + // La finca elegida vive en el metadata de la conversación, no en + // lo recolectado: sin esto {finca_id} quedaba sin resolver y el + // ERP devolvía los lotes de todas las fincas. + array_merge( + $ctxId > 0 ? ConversationContext::getMetadata($ctxId) : [], + ['__ep_vars_combined' => $cap['collected'] ?? []] + ), $to ); if (empty($items)) { @@ -1479,7 +1485,15 @@ class NormalBot if ($type === 'select') { $vf = $field['value_field'] ?? 'id'; $lf = $field['label_field'] ?? 'label'; - $items = self::fetchDynamicList($field['source_endpoint_key'] ?? '', $company, ['__ep_vars_combined' => $cap['collected'] ?? []], $to); + $items = self::fetchDynamicList( + self::resolverPorCampos($field['source_endpoint_key'] ?? '', $cap['collected'] ?? []), + $company, + array_merge( + $ctxId > 0 ? ConversationContext::getMetadata($ctxId) : [], + ['__ep_vars_combined' => $cap['collected'] ?? []] + ), + $to + ); if (!empty($items)) { diff --git a/setup/tests/fixtures_api.php b/setup/tests/fixtures_api.php index f394bf0..1e9b171 100644 --- a/setup/tests/fixtures_api.php +++ b/setup/tests/fixtures_api.php @@ -43,6 +43,10 @@ foreach (range(1, 17) as $i) $novedades17[] = ['id' => (string)(100 + $i), 'nomb $lotes12 = []; foreach (range(1, 12) as $i) $lotes12[] = ['id' => (string)$i, 'label' => "REPOSO {$i}A (" . (50 - $i) . "d)"]; +// Como el ERP real: sin finca_id valida, el catalogo mezcla fincas +if (intval($_GET['finca_id'] ?? 0) !== 4) { + array_unshift($lotes12, ['id' => '99', 'label' => 'ROSA BLANCA 9Z (60d)']); +} $fixtures = [ 'fincas' => $fincas, @@ -60,10 +64,9 @@ $fixtures = [ ], 'lotes_apertura_dn' => $lotes12, 'lotes_abiertos_dn' => array_slice($lotes12, 0, 3), - 'lotes_x_finca' => [ - ['id' => '4', 'label' => 'REPOSO 1A'], - ['id' => '9', 'label' => 'REPOSO 2A'], - ], + 'lotes_x_finca' => intval($_GET['finca_id'] ?? 0) === 4 + ? [['id' => '4', 'label' => 'REPOSO 1A'], ['id' => '9', 'label' => 'REPOSO 2A']] + : [['id' => '99', 'label' => 'ROSA BLANCA 9Z']], 'grupos_mantenimiento' => [ ['id' => '5', 'label' => 'PLATEO'], ['id' => '6', 'label' => 'CORONA'], diff --git a/setup/tests/test_flujos.php b/setup/tests/test_flujos.php index 2040388..ea80153 100644 --- a/setup/tests/test_flujos.php +++ b/setup/tests/test_flujos.php @@ -102,6 +102,8 @@ capturas(); echo "\nCiclos — apertura de varios lotes\n"; $ctx = contexto('57300CICLOS'); +$id = ConversationContext::getOrCreate(1, '57300CICLOS')['id']; +ConversationContext::updateMetadata($id, ['finca' => ['finca_id' => '4', 'finca_label' => 'REPOSO']]); $r = NormalBot::processInteractive($co, $ctx, 'registrar_ciclo'); check('pregunta el tipo de ciclo', str_contains(textoDe($r), 'Qué ciclo')); @@ -113,6 +115,8 @@ $r = NormalBot::processInteractive($co, $ctx, $hoy); $filas = filasDe($r); check('lista de lotes con "Otro lote" y "Listo"', isset($filas['__todos']) && isset($filas['__listo'])); +check('solo lotes de la finca elegida, ninguno ajeno', + !isset($filas['99']) && !str_contains(implode(' ', $filas), 'ROSA BLANCA')); $r = NormalBot::processInteractive($co, $ctx, '1'); check('marcar redibuja con el check', str_contains(filasDe($r)['1'] ?? '', '✅')); @@ -181,6 +185,7 @@ check('el catálogo viene filtrado por fase', filasDe($r), ['42' => 'TRACTORISTA $r = NormalBot::processInteractive($co, $ctx, '42'); check('los lotes son los de su finca', isset(filasDe($r)['4']) && isset(filasDe($r)['9'])); +check('sin lotes de otras fincas', !isset(filasDe($r)['99'])); $r = NormalBot::processInteractive($co, $ctx, '4'); $r = NormalBot::processInteractive($co, $ctx, '412');