api_key contiene el token ERP de PALMAS360 configurado manualmente.
Se retira del ON DUPLICATE KEY UPDATE para que cada seed run no lo pise.
Solo aplica al INSERT inicial de una empresa nueva.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
La fecha que pasan estos nodos al endpoint es un punto de corte (hoy),
no un rango mensual. current_month enviaba fecha_desde=primer-día-mes
que el controller pasaba al modelo como referencia de días.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Eliminada entrada duplicada 'ciclo_mantenimiento' tipo menu (reemplazada
por el dynamic_list de abajo en el mismo array)
- Eliminado endpoint 'mantenimiento_top_texto_bot_dn' (nunca referenciado
por ningún nodo de flujo)
- Eliminado endpoint duplicado 'mantenimiento_todos_dn' (URL idéntica a
mantenimiento_todos_bot_dn, sin usos)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ciclo_mantenimiento → dynamic_list top 3 grupos más usados + "Otro grupo"
- "Otro grupo" → lista grupos 4-13 (append_options redirect)
- Tras seleccionar grupo → menú 3 botones: más largos, todos, histórico 30d
- Endpoints con {grupo_id} dinámico en URL
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cada ciclo (cosecha, polinización, plagas, censo, palmarum,
tratamientos, mantenimiento) ahora presenta un menú de botones con:
1. Más largos — texto top 10 con fecha actual
2. Todos los lotes — PDF filtrado por finca
3. Histórico 30d — PDF matriz (excepto mantenimiento)
Se agregan endpoints *_todos_dn apuntando a ciclos_*_dn (PDF).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ask_finca como dynamic_list con meta_group=finca
- ciclos usan api_report con next_endpoint_key para texto+PDF
- produccion_total encadena texto → PDF
- ausentismos usan date_mode en vez de funcion inexistente
- URLs de endpoints sin {fecha_desde}/{fecha_hasta} (date_mode los agrega)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AiLogger.php: new service, inserts into ai_logs on every AI call
- ai_logs table: added to migrate.php (provider, model, call_type, tokens, duration_ms)
- AiBot: logs chat, media_response, nlu calls with timing and token counts
- MediaTranscriber: logs whisper, geminiAudio, openaiVision, geminiVision, claudeVision
- /admin/ai-logs: paginated table with provider/company filter
- Layout.php: added IA Logs nav link
- index.php: require AiLogger before AiBot; added GET /admin/ai-logs route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Global settings: custom AI panel with OpenAI/Gemini/Claude each with
API key, model selector, and live test-connection button (no save needed)
- Per-company IA tab: same three providers + fallback to global when empty
- AiBot: reads per-company config_json first, falls back to env() global
- Added callClaude() for Anthropic Messages API
- More OpenAI models: gpt-4.1, gpt-4.1-mini
- test-ai endpoint: accepts provider/api_key/model from POST for live test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added gemini-2.5-flash to the admin panel selector (first/default option)
and updated the fallback default in AiBot and migrate seed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cuando un número pertenece a más de una empresa, el bot muestra un
menú interactivo "¿Con cuál empresa deseas comunicarte?" antes de
cualquier flujo normal. La selección se cachea 8h en la tabla
multi_company_sessions. Keywords de reinicio (salir, inicio, menú...)
limpian la sesión y vuelven a mostrar el pre-menú.
Números de una sola empresa: flujo intacto.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Settings: agrega Gemini al selector de proveedor, campos gemini_api_key y gemini_model
- Modelos: gemini-2.0-flash, gemini-1.5-flash, gemini-1.5-pro
- AiBot::callGemini(): llama generateContent API con system_instruction y historial
- migrate.php: seed defaults gemini_api_key y gemini_model
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- El número WA Business es global (configuración general), no por empresa
- OutboundWorker usa fallback a WHATSAPP_DEFAULT_PHONE_NUMBER_ID si la empresa no tiene
- CompanyRepository::save() ya no requiere phone_number_id
- phone_number_id permite DEFAULT '' en schema
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El routing ahora es por número remitente (company_phones), no por phone_number_id.
phone_number_id solo se usa para enviar mensajes salientes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>