194 Commits
Author SHA1 Message Date
Lizandro GuarnizoandClaude Sonnet 4.6 03f02d2788 fix(webhook): skip SSE notification and DB notification for canal=turnero messages
Turnero messages were triggering the SSE event that conversations.php listens to,
causing the contact to flash briefly at the top of the list before disappearing
on the next poll (since get_conversations.php filters them out by canal).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:43:20 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 3f964b424a fix(conversations): filter canal='turnero' out of individual chat message views
get_user_messages.php and get_recent_messages.php now exclude canal='turnero'
so the main bot chat only shows bot messages even for users who also have
turnero conversations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:39:07 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 7eea2ff7ba fix(conversations): exclude canal='turnero' messages from main conversations list
All queries in get_conversations.php now filter (canal IS NULL OR canal='bot')
so the main chat only shows bot conversations and the turnero chat stays isolated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:35:49 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 5acd46df5a fix(turnero): route incoming messages by phone_number_id and fix WhatsAppService canal
- WhatsAppService($canal): when 'turnero', swaps phoneNumberId to whatsapp_phone_number_id_turnero
  so outgoing messages actually go from the turnero number (not the main bot)
- webhook.php: reads metadata.phone_number_id from the payload and compares it to
  whatsapp_phone_number_id_turnero; if it matches, saves canal='turnero' and skips bot processing
- Previously all incoming messages had canal=NULL/bot so Chat Turnero never saw them,
  and all outgoing messages from Chat Turnero were sent via the wrong (main bot) number

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:26:11 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 20146535c7 formularios: agregar botón Clonar para duplicar plantillas
- save_formulario.php: manejo de {clonar:true} → crea copia con "Copia de [nombre]"
- lab_formularios.php: botón icono copy en cada tarjeta + función clonarFormulario()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:21:50 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a592ddb30d fix: restaurar cambios revertidos por rebase del servidor
- verificar.php: BASE_URL absoluta en fetch, fix paste multi-dígito
- send_otp.php: mensaje SMS correcto sin dos puntos ni expiración
- module.php: Chat Turnero y Verificar Paciente para recepcionistas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:13:39 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 6d63112d76 fix(api): convertir user_id vacío a null antes de guardar paciente
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 09:28:43 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 9e7637582d fix(api): agregar db() helper, corregir requireAuth() en check_whatsapp
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 09:27:03 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 af584bcc26 feat(pacientes): verificar WhatsApp al ingresar teléfono, vincular user_id al guardar
fix(recepcion): mostrar nombre_completo en resultados de búsqueda de paciente

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 08:44:48 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 ae8d2cb13a feat: página pública de verificación de paciente por OTP (SMS)
verificar.php:
- Pública, sin autenticación ni menú lateral
- Diseño moderno: card glassmorphism sobre gradiente brand
- Flujo en 3 pasos con indicador animado
- Paso 1: ingresa cédula → busca paciente
- Paso 2: inputs OTP de 6 dígitos con navegación automática
  y pegado desde portapapeles; cuenta regresiva + reenvío a los 60s
- Paso 3: pantalla de éxito con animación

api/public/send_otp.php:
- Busca paciente por cédula, genera OTP aleatorio de 6 dígitos
- Guarda en lab_otp_tokens con expiración 5 min
- Envía SMS via WEBSms usando config de lab_config
- Retorna teléfono enmascarado (3**1234**67)

api/public/verify_otp.php:
- Valida cedula+codigo contra lab_otp_tokens activos
- Marca OTP como usado y paciente como verificado
  (telefono_verificado=1, verificado_at=NOW())

DB:
- lab_pacientes: +telefono_verificado, +verificado_at
- lab_otp_tokens: tabla nueva para almacenar OTPs temporales

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 00:39:30 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 21e7c6a836 feat: integración WEBSms en configuración
- Nueva sección WEBSms en lab_configuracion.php con:
  - Switch activo/inactivo (sms_activo)
  - Campo URL base de la API (sms_url)
  - Campo API key / Bearer token (sms_api_key)
  - Campos de prueba: número + mensaje + botón Enviar
- api/lab/test_sms.php: proxy al endpoint POST /api/sms/send
  con Authorization: Bearer, valida respuesta ok/error
- save_config.php: permite guardar sms_url, sms_api_key, sms_activo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 23:27:24 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 cd3d3bb9c0 feat: IA configurable — probar conexión, activar/inactivar
- Toggle activo/inactivo en configuración → guarda ia_activa en lab_config
- Botón "Probar" llama api/lab/test_gemini.php con la clave actual
- test_gemini.php envía pregunta mínima a Gemini y confirma respuesta
- Dashboard oculta botón y panel IA cuando ia_activa != '1'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 23:16:06 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d0152e37ce feat: asistente IA Gemini Flash en dashboard turnero + config token
- ai_chat.php: contexto completo (tiempos, facturación, franjas, turnos detallados)
- Preguntas soportadas: demoras por recepcionista, total facturado, horas pico,
  tiempo total por paciente, exámenes, búsqueda por cédula
- Panel flotante de chat en dashboard (botón robot azul)
- Búsqueda de tabla ahora filtra por cédula/documento
- Ícono de fila gira al expandir detalle (flecha → rotada)
- lab_configuracion.php: nueva sección IA con campo token Gemini
- save_config.php: permite guardar gemini_api_key

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 20:28:43 -05:00
Lizandro Guarnizo 56f30f1c6d fix: firma profesional guarda solo en el campo firmado, no en todos 2026-06-23 19:54:22 -05:00
Lizandro Guarnizo ff8454fa5a up 2026-06-16 16:55:22 -05:00
Lizandro Guarnizo 415ea3ef56 up 2026-06-16 12:06:26 -05:00
Lizandro GuarnizoandClaude Haiku 4.5 d7b1aea5a4 fix: signature fields deduplicate and share across same-type fields
- PHP pre-computes one shared SVG per type (firma/firma_profesional)
- Schema loop skips duplicate firma fields of same type already rendered
- Patient signature from turnero widget propagates to all 'firma' schema fields
- firmar_profesional.php saves nurse signature to ALL firma_profesional fields

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-16 11:41:20 -05:00
Lizandro Guarnizo b317639258 up 2026-05-27 21:39:53 -05:00
Lizandro Guarnizo 2f72d87c3b cambios 2026-05-27 20:40:17 -05:00
Lizandro Guarnizo b8de9ee666 up 2026-05-27 11:44:07 -05:00
Lizandro Guarnizo 313e57aace p 2026-05-27 10:30:47 -05:00
Lizandro Guarnizo 0de3e6e281 up 2026-05-11 14:55:17 -05:00
Lizandro Guarnizo 00232b3513 up 2026-05-11 13:45:36 -05:00
Lizandro Guarnizo f197118acb cambios importates 2026-05-11 12:21:56 -05:00
Lizandro Guarnizo 4bf9d99f8b Update _helpers.php 2026-04-21 16:07:30 -05:00
Lizandro Guarnizo 0164c51c1a up 2026-04-16 23:07:53 -05:00
Lizandro Guarnizo 50b7f7f8ca up 2026-04-16 21:24:01 -05:00
Lizandro Guarnizo c8bef9d9c4 up 2026-04-10 23:04:28 -05:00
Lizandro Guarnizo 5e58b14eba reportes 2026-04-09 16:38:03 -05:00
Lizandro Guarnizo c68a79a3a7 subir mas de un archivo, reprogramados 2026-04-08 10:31:12 -05:00
Lizandro Guarnizo 882ce56e96 multiples documentos 2026-04-08 09:58:08 -05:00
Lizandro Guarnizo db254ca02f direccion 2026-04-08 09:47:47 -05:00
Lizandro Guarnizo d38b5936ca actividades 2026-04-08 09:02:32 -05:00
Lizandro Guarnizo cbf7a8c296 up 2026-04-08 08:31:21 -05:00
Lizandro Guarnizo 4f1b2e146c up 2026-04-07 15:57:53 -05:00
Lizandro Guarnizo ded060e161 lab_formularios 2026-04-07 15:12:22 -05:00
Lizandro Guarnizo 400ff3d615 fix: get_pacientes.php soporta ?id=X para retornar paciente específico con phone_number correcto 2026-04-06 16:45:24 -05:00
Lizandro Guarnizo ca90f79625 up 2026-04-06 12:30:37 -05:00
Lizandro Guarnizo 7956d5431b fix: columna activa → is_active en lab_enfermeras (get_reporte_enfermero) 2026-04-02 11:54:37 -05:00
Lizandro Guarnizo 3516f6e229 fix: permitir crear/editar formularios a roles con permiso write en lab_formularios
- _helpers.php: nueva función requireModuleWrite() que verifica session module_permissions
- save_formulario.php: reemplaza requireAdmin() por requireModuleWrite('lab_formularios')
2026-04-02 10:50:18 -05:00
Lizandro Guarnizo d8ceb3f822 feat: 6 nuevas funcionalidades - notas obligatorias turno, reporte enfermero, plantilla WhatsApp, adjuntar orden modal, roles solo lectura, fix valores copago 2026-04-02 09:41:49 -05:00
Lizandro Guarnizo 3b92f47b54 feat: enlaces de formulario sin vencimiento + PDF descargable sin sesión vía token público 2026-03-25 16:14:26 -05:00
Lizandro Guarnizo 5f695b5604 feat: sistema de notas clínicas para enfermero (ficha + notas libres) y fix lab_reportes métricas 2026-03-25 13:14:25 -05:00
Lizandro Guarnizo 4ba890a0d5 feat: métricas completas, export Excel domicilios con filtros, hora llegada/salida visible 2026-03-25 11:48:24 -05:00
Lizandro Guarnizo 2abce6d4c2 feat: multi-archivo órdenes visible en enfermero, domicilios y órdenes médicas
- OrdenMedica::filtrarCampos(): agrega domicilio_id al whitelist
- Domicilio::obtener(): consulta secundaria archivos_ordenes[] con fallback
- Enfermera::agenda(): bulk-query archivos_ordenes[] por domicilio_id
- api/lab/link_ordenes_domicilio.php: API POST vincula orden_ids a domicilio_id
- conversations.php guardar(): trackea allOrdenIds[], llama link API post-save
- lab_domicilios.php: renderOrdenesDetail() multi-archivo en detalle
- enfermero_portal.php: renderOrdenesEnfermero() multi-archivo en cards
- lab_ordenes.php: botón 'Ver domicilio' cuando domicilio_id está vinculado
- migrations/: ALTER TABLE lab_ordenes_medicas ADD domicilio_id + índice
2026-03-24 21:51:29 -05:00
Lizandro Guarnizo 8e62c29ca9 firma_profesional: canvas en ver_formulario_enviado + endpoint firmar_profesional 2026-03-17 15:55:56 -05:00
Lizandro Guarnizo d757bba23f descargar_orden: reescribir sin _helpers para evitar ob_start y Content-Type:json; fix .bin -> extension real 2026-03-17 15:25:26 -05:00
Lizandro Guarnizo 8e15ccc6b4 descargar_orden: detección MIME por magic bytes (fix .bin) 2026-03-17 15:09:02 -05:00
Lizandro Guarnizo 262009f4e5 Update descargar_orden.php 2026-03-16 22:02:11 -05:00
Lizandro Guarnizo 0fddff6c5b up 2026-03-16 21:55:23 -05:00