From 2ef3091260281d7680e6141474e21b152af4764e Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Thu, 20 Aug 2026 22:48:19 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20ausentismo=20en=20dos=20pasos=20?= =?UTF-8?q?=E2=80=94=20tipo=20y=20despues=20motivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 17 motivos en una sola lista llegaban con el nombre cortado a 24 caracteres, el limite de WhatsApp, y costaban de entender. Ahora primero se elige el tipo —Incapacidad, Permiso, Licencia, Ausencia, Vacaciones...— y despues solo los motivos de ese tipo. Quitar el prefijo del grupo libera los caracteres que faltaban: "INCAPACIDAD ENFERMEDAD < 3 DIAS" queda en "ENFERMEDAD < 3 DIAS". Sin siglas, que era la otra opcion pero empeoraba justo lo que el cliente pidio arreglar. El nombre completo va en la descripcion de la fila, asi no se pierde nada. El ERP agrupa por nombre y no por id, para que una novedad nueva caiga sola en su grupo; lo que no reconoce queda en 'Otros', visible. desc_field es nuevo en los select: antes solo el multi_select podia describir. Co-Authored-By: Claude Sonnet 4.6 --- services/NormalBot.php | 14 ++++++++++++-- setup/seed_palmas.php | 18 ++++++++++++++++-- setup/tests/fixtures_api.php | 17 ++++++++++++++++- setup/tests/test_flujos.php | 23 ++++++++++++++--------- 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/services/NormalBot.php b/services/NormalBot.php index ad8cc86..5506683 100644 --- a/services/NormalBot.php +++ b/services/NormalBot.php @@ -711,6 +711,7 @@ class NormalBot $labelField = $flow['label_field'] ?? 'name'; // Auto-detect multi-section if items carry a 'section' key $sectionField = $flow['section_field'] ?? (isset($items[0]['section']) ? 'section' : null); + $descField = $flow['desc_field'] ?? (isset($items[0]['descripcion']) ? 'descripcion' : null); if ($sectionField !== null) { $grouped = []; @@ -719,7 +720,12 @@ class NormalBot if ($id === '') continue; $title = mb_substr((string)($item[$labelField] ?? $id), 0, 24); $sec = mb_substr((string)($item[$sectionField] ?? 'Opciones'), 0, 24); - $grouped[$sec][] = ['id' => $id, 'title' => $title]; + $fila = ['id' => $id, 'title' => $title]; + // El titulo se corta a 24: la descripcion lleva el nombre entero + if ($descField !== null && !empty($item[$descField])) { + $fila['description'] = mb_substr((string)$item[$descField], 0, 72); + } + $grouped[$sec][] = $fila; } $sections = []; foreach (array_slice($grouped, 0, 10, true) as $secTitle => $rows) { @@ -737,7 +743,11 @@ class NormalBot foreach ($visibles as $item) { $id = (string)($item[$valueField] ?? ''); if ($id === '') continue; - $rows[] = ['id' => $id, 'title' => mb_substr((string)($item[$labelField] ?? $id), 0, 24)]; + $fila = ['id' => $id, 'title' => mb_substr((string)($item[$labelField] ?? $id), 0, 24)]; + if ($descField !== null && !empty($item[$descField])) { + $fila['description'] = mb_substr((string)$item[$descField], 0, 72); + } + $rows[] = $fila; } $restantes = count($items) - (($pagina + 1) * $porPagina); diff --git a/setup/seed_palmas.php b/setup/seed_palmas.php index 4841bde..63e1afe 100644 --- a/setup/seed_palmas.php +++ b/setup/seed_palmas.php @@ -444,12 +444,25 @@ $configJson = [ 'display_field' => 'nombre', 'not_found_text' => '⚠️ No encontré ese trabajador. Escribe el nombre de nuevo:', ], + [ + // Primero el grupo general: 17 motivos en una sola lista + // llegaban con el nombre cortado y costaban de entender + 'key' => 'grupo_novedad', + 'label' => 'Tipo', + 'type' => 'select', + 'prompt' => '¿Qué tipo de ausentismo?', + 'source_endpoint_key' => 'novedades_grupos_dn', + 'value_field' => 'id', + 'label_field' => 'nombre', + 'desc_field' => 'descripcion', + ], [ 'key' => 'novedad_id', 'label' => 'Motivo', 'type' => 'select', - 'prompt' => '¿Cuál es el motivo del ausentismo?', + 'prompt' => '¿Cuál es el motivo?', 'source_endpoint_key' => 'novedades_ausentismo_dn', + 'desc_field' => 'descripcion', 'value_field' => 'id', 'label_field' => 'nombre', ], @@ -902,7 +915,8 @@ $endpoints = [ // ── Carga de datos (POST) — Fase 1: Ausentismo ────────────────────────── // El lookup agrega &filtro= a esta URL; estado=1 restringe a activos. ['key' => 'empleados_buscar_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=empleados&estado=1&items=10'], - ['key' => 'novedades_ausentismo_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=novedades_ausentismo_dn'], + ['key' => 'novedades_grupos_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=novedades_ausentismo_dn&grupos=1'], + ['key' => 'novedades_ausentismo_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=novedades_ausentismo_dn&grupo_novedad={grupo_novedad}'], ['key' => 'ausentismos_up', 'dir' => 'upload', 'url' => $BASE . '?peticion=ausentismos_up'], ['key' => 'pluvio_upload', 'dir' => 'upload', 'url' => $BASE . '?peticion=pluvio_upload'], diff --git a/setup/tests/fixtures_api.php b/setup/tests/fixtures_api.php index 1e9b171..b1243d8 100644 --- a/setup/tests/fixtures_api.php +++ b/setup/tests/fixtures_api.php @@ -55,7 +55,22 @@ $fixtures = [ ['id' => '415', 'nombre' => 'JULIO CESAR RAMIREZ'], ['id' => '418', 'nombre' => 'MARIA GOMEZ RUIZ'], ], - 'novedades_ausentismo_dn' => $novedades17, + 'novedades_ausentismo_dn' => (function () { + // Como el ERP: ?grupos=1 devuelve los grupos, ?grupo_novedad=X los suyos + $porGrupo = [ + 'Incapacidad' => [['id'=>'46','nombre'=>'ENFERMEDAD < 3 DIAS','descripcion'=>'INCAPACIDAD ENFERMEDAD < 3 DIAS'], + ['id'=>'47','nombre'=>'ACCIDENTE DE TRANSITO','descripcion'=>'INCAPACIDAD ACCIDENTE DE TRANSITO']], + 'Permiso' => [['id'=>'50','nombre'=>'CITA MEDICA','descripcion'=>'PERMISO CITA MEDICA']], + 'Vacaciones' => [['id'=>'57','nombre'=>'DISFRUTADAS','descripcion'=>'VACACIONES DISFRUTADAS']], + ]; + if (!empty($_GET['grupos'])) { + $out = []; + foreach ($porGrupo as $g => $i) $out[] = ['id'=>$g,'nombre'=>$g,'descripcion'=>count($i).' opcion(es)']; + return $out; + } + $g = trim((string)($_GET['grupo_novedad'] ?? '')); + return $g !== '' ? ($porGrupo[$g] ?? []) : array_merge(...array_values($porGrupo)); + })(), 'novedades_labor_dn' => !empty($_GET['grupo']) ? [['id' => '77', 'nombre' => 'PLATEO MANUAL']] : [ diff --git a/setup/tests/test_flujos.php b/setup/tests/test_flujos.php index ea80153..f9ee913 100644 --- a/setup/tests/test_flujos.php +++ b/setup/tests/test_flujos.php @@ -47,15 +47,20 @@ check('con los tres del catálogo', count(filasDe($r)), 3); $r = NormalBot::processInteractive($co, $ctx, '412'); $filas = filasDe($r); -check('sigue el motivo, paginado: 9 + "Ver más"', count($filas), 10); -check('la última fila es "Ver más"', isset($filas['__mas'])); +check('sigue el tipo, no los 17 motivos de una', + array_keys($filas), ['Incapacidad', 'Permiso', 'Vacaciones']); -$r = NormalBot::processInteractive($co, $ctx, '__mas'); +$r = NormalBot::processInteractive($co, $ctx, 'Incapacidad'); $filas = filasDe($r); -check('la página 2 trae las 8 restantes', count($filas), 8); -check('y ya sin "Ver más"', !isset($filas['__mas'])); +check('el motivo se acota al tipo elegido', array_map('strval', array_keys($filas)), ['46', '47']); +check('sin el prefijo del grupo, entra en los 24 de WhatsApp', + max(array_map('mb_strlen', $filas)) <= 24); +$p = json_decode($r['payload'], true); +$fila0 = $p['interactive']['action']['sections'][0]['rows'][0]; +check('y el nombre completo va en la descripción', + $fila0['description'] ?? null, 'INCAPACIDAD ENFERMEDAD < 3 DIAS'); -$r = NormalBot::processInteractive($co, $ctx, '112'); +$r = NormalBot::processInteractive($co, $ctx, '46'); check('sigue la fecha inicial', str_contains(textoDe($r), 'Desde qué fecha')); $hoy = date('Y-m-d'); $ayer = date('Y-m-d', strtotime('-1 day')); @@ -78,7 +83,7 @@ check('el POST llegó al ERP', $post !== null); check('con el contrato exacto del procesador', [$post['body']['empleado_id'] ?? null, $post['body']['novedad_id'] ?? null, $post['body']['fecha_inicial'] ?? null, $post['body']['fecha_final'] ?? null], - ['412', '112', $hoy, $hoy]); + ['412', '46', $hoy, $hoy]); check('y la trazabilidad', $post['body']['telefono'] ?? null, '57300AUSEN'); // ════ 3. Ausentismo según el perfil del número ═══════════════════════════════ @@ -89,8 +94,8 @@ fakePhone('57300JEFE', 412, 1); $ctx = contexto('57300TRABAJADOR'); $r = NormalBot::processInteractive($co, $ctx, 'registrar_ausentismo'); -check('el trabajador vinculado no se pregunta: arranca por el motivo', - str_contains(textoDe($r), 'motivo del ausentismo')); +check('el trabajador vinculado no se pregunta: arranca por el tipo', + str_contains(textoDe($r), 'tipo de ausentismo')); $ctx = contexto('57300JEFE'); $r = NormalBot::processInteractive($co, $ctx, 'registrar_ausentismo');