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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Los menus se filtraban por modulo pero el texto libre no: un perfil limitado a
pluviometria podia escribir "registrar ausentismo" y el NLU lo llevaba igual.
El mismo agujero que ya cerramos con las fincas.
moduloDeFlow() decide por convencion de nombre a que modulo pertenece cada
flow —'modulo' explicito manda— y se aplica en dos puntos: el catalogo que ve
el modelo llega filtrado, y el ruteo verifica igual la clave devuelta por si
el modelo alucina una que no le ofrecieron.
Lo permitido sigue directo: "subir pluviometria" cae en la fecha con un solo
mensaje, "subir labores diarias" arranca el flujo. Cinco casos nuevos.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El servidor no trae el driver de SQLite y el arnes reventaba al arrancar.
NormalBot solo hace dos consultas —el endpoint por clave y el perfil por
numero— asi que dos mapas en memoria alcanzan y el arnes deja de depender de
cualquier driver de PDO.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
setup/tests/ corre NormalBot de verdad —no un espejo—: SQLite en memoria con
los endpoints del seed reescritos hacia fixtures_api.php servido con php -S,
asi el curl real se ejecuta y los POST capturados se comparan contra el
contrato del procesador. ConversationContext, WhatsAppSender y AiBot son
falsos en memoria; el resto es el codigo de produccion.
51 casos: finca restringida que entra sola, ausentismo completo con rango
invertido rechazado, perfiles trabajador/supervisor, ciclos con multi-select
paginado, mantenimiento con requires/resolver, labores con cuadrilla, y NLU
que resuelve "plateo" por entity hasta el informe.
Destaparon dos errores reales:
- registrar_mantenimiento posteaba a labores_up sin novedad_id ni empleados,
que el procesador exige: el ERP lo habria rechazado siempre. Ahora pide la
labor del grupo elegido (endpoint nuevo novedades_mant_dn) y la cuadrilla.
- resolverPorCampos reventaba con warning al sustituir arreglos en la URL.
Uso: bash setup/tests/run.sh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>