194 Commits
Author SHA1 Message Date
LizandroandClaude Sonnet 4.6 9749d726fa feat(turnero): cambio de estado y reapertura de turnos desde historial
Agrega botón de cambio de estado en cada fila del historial de turnos.
Admins (sin role_id) pueden reabrir turnos finalizados/ausentes/cancelados.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-28 01:43:29 +00:00
Lizandro GuarnizoandClaude Sonnet 4.6 3dbf40e4fa feat(formulario): firma profesional directa en modal embebido (formularios solo-pro)
- ver_formulario_enviado.php: pre-scan $_soloFirmaPro; muestra canvas pro cuando modoTurnero+embebido+sesión activa+sin firma paciente
- fpw-save JS: recopila campos del form y envía solo_profesional=true; al guardar muestra éxito y postMessage turneroFirmado
- firmar_profesional_consentimiento.php: si solo_profesional=true guarda datos_respuestas y marca estado=firmado

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 12:49:39 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 1e2cfbaa0b refactor(lugar): embebido como botón en fila de consentimiento, no sección separada
- Eliminar sec-form-embebido como sección independiente
- En modo embebido: fila de consentimiento muestra botón "Firmar" que abre modal directamente por token
- En modo link: botones "Firmar presencial" + "WA" como antes
- abrirModalConsentimientoPorToken(token) recibe token directo sin cache

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 12:37:50 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a0189a61eb feat(lugar): formulario embebido como modal en lugar de iframe inline
- Botón "Abrir formulario de firma" en ficha abre modal overlay
- Modal con iframe cargando ver_formulario_enviado.php?embed=1
- postMessage 'turneroFirmado' cierra modal, refresca consentimientos y oculta botón
- Token pre-cargado al abrir ficha para apertura rápida del modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 12:16:22 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 27135e4d2f fix(formulario): múltiples correcciones modo embebido/turnero
- ver_formulario_enviado.php: usar opciones??options??items como fallback de claves del schema
- ver_formulario_enviado.php: marcar _esquemaTieneFirmaPaciente en cualquier campo firma (no solo sin SVG), evita mostrar firma paciente cuando schema solo tiene firma_profesional
- ver_formulario_enviado.php: modo embebido (?embed=1) con layout compacto para iframe
- lugar.php: pasar &embed=1 al iframe src

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 12:15:34 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 7b734195e0 fix(lugar): incluir formulario_modo en query de lugares
La columna no estaba en el SELECT, siempre quedaba 'link'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 12:01:59 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 5dc2b0efa8 fix(turnero): corregir envío WA desde recepcion
- recepcion.php: quitar guard !solicitudActiva en enviarConsentimientosTodos (bloqueaba silenciosamente antes de guardar solicitud)
- send_consentimiento.php: eliminar requisito de solicitud y exámenes para poder reenviar; usar WhatsAppService('turnero') con rawComponents correctos (1 body param=codigo, button param=token); JOIN lab_pacientes también via t.paciente_id como fallback de teléfono

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:59:40 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 2dec300f3a Fix professional signature row only showing when form schema requires it
Only display the 'Falta firma enfermero' row and button when the assigned
consent form actually contains a firma_profesional field in its esquema.
get_consentimientos.php now computes requiere_firma_profesional from the
JSON schema and recepcion.php gates the row on that flag.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:55:20 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f09fcd5b4e fix(turno): no enviar WA si el lugar de recepción está en modo embebido
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:44:59 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f8245b4d6f feat: modo embebido de formulario por lugar (link vs iframe)
- Nueva columna turnero_lugares.formulario_modo (link|embebido)
- Config: radio en modal de edición para elegir el modo
- lugar.php: muestra iframe con ver_formulario_enviado al activar turno
- API get_consent_token.php: crea/obtiene token para turno+lugar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:35:45 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 538af86407 fix(wa): enviar solo el token como parámetro del botón URL, no la URL completa
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:11:54 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 b47f6019cd fix(turno): no prepender +57 si el tel ya tiene código de país
573168950803 quedaba como +57573168950803 — WhatsAppService lo normaliza solo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:47:51 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 735d70dc50 fix(wa): enviar botón URL como componente button/url, no como header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:34:55 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 7a56ec25a0 fix(wa): usar language_code real de la plantilla (es, no es_CO)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:32:15 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f18104dd5d fix: quitar creado_at (columna no existe en turnero_consentimientos)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:28:43 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 434df7b741 fix(turno): crear consentimiento siempre, enviar WA solo si hay teléfono
Estado queda 'pendiente' si no hay cel; se actualiza a 'enviado' al enviar WA.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:17:16 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 1a92707e3e create_turno: corregir params plantilla (solo {{1}}=código) + fix debug test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:09:52 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 707ef24572 configuracion: sección perfil WhatsApp Business (foto, about, dirección, email, webs, categoría)
- wa_profile.php: GET carga perfil desde Graph API, POST guardar campos, POST foto sube imagen
- configuracion.php tab sesión: UI con foto de perfil editable, campos del negocio y botón guardar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:08:41 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d232cf69f5 create_turno: usar canal 'turnero' para envío de WA desde kiosko
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 09:57:13 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 6fec24f850 create_turno: enviar turno + consentimiento en un solo WA desde el kiosko
- Al crear turno busca el formulario configurado en el desk de recepción
- Crea token de consentimiento y lo marca como 'enviado'
- Envía plantilla consentimiento_turno con nombre real, nombre formulario y link
- Fallback texto plano incluye el link si está disponible
- Tipo F (solo muestra) sigue usando plantilla sin consentimiento

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 09:41:44 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 9d57bbac5c recepcion: historial paciente muestra 5 visitas por página (antes 15)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 09:16:44 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 4d04fea1de fix(turnero): save outgoing messages with canal='turnero' so they appear in chat
saveOutgoingMessage() now reads __app_meta.canal and stores it in conversations.
sendMediaById() accepts a $meta param and forwards it to saveOutgoingMessage.
chat_upload_media.php passes $extra (canal=turnero) to sendMediaById.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:32:23 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 00aee615c5 lugar: cambiar label 'TOMA DE MUESTRAS' → 'ENTREGA DE MUESTRAS'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:25:30 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 17703f0157 fix(chat-turnero): prevent messages mixing between contacts on fast switching
Capture activeUserId at the start of each async function (fetchMessages,
loadMoreMessages, pollMessages) and discard the response if the user changed
contacts while the request was in-flight.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:19:52 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a0979e31e7 recepcion: quitar botón duplicar del historial (va en sección formatos)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:19:27 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 78e71d5926 recepcion: mostrar kiosko + paciente vinculado en dos líneas separadas
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:15:03 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 c511da18bd recepcion: fix solo_muestras, reorder fields, duplicar visita, kiosko label
- create_solicitud.php: evitar SQL `IN ()` vacío cuando solo_muestras=1 sin exámenes
- recepcion.php: mover embarazada+médico después del historial del paciente
- recepcion.php: actualizar label kiosko con nombre real al vincular paciente
- recepcion.php: botón "Duplicar" en historial para copiar exámenes y pago de última visita
- recepcion.php: omitir validación de consentimientos pendientes cuando es solo_muestras
- recepcion.php: agregar alias esc() = escHtml() usado en buscarMedico

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:13:38 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d3826972ad feat(turnero): selector de médico tratante en recepción, visible en toma de muestras
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:55:32 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 ec614c2a89 feat(chat-turnero): backend APIs for media upload, reactions, and template messages
- chat_upload_media.php: multipart upload to WhatsApp Media API, sends image/video/audio/document
- chat_react.php: sends emoji reaction to a message via WhatsApp, updates reaction_emoji in DB
- chat_send_message.php: extended to support type=template with lang+params

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:53:23 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a7ab91615f feat(chat-turnero): rich messaging UI — images, video, audio, reactions, emoji, templates
- Attach button with file preview (image thumb for images, name+size for others)
- Audio recording via MediaRecorder API with live timer; sends as voice note
- Emoji panel with 35 common emojis (medical/comms focused)
- Reaction picker on message hover — sends via chat_react.php API
- Template modal (name, lang, JSON params) — sends via chat_send_message.php type=template
- buildBubble() now renders: inline images, <video> player, <audio> player, doc links with type icon
- Shows reaction_emoji below bubble and status tick on outgoing messages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:53:23 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 3b378c0d75 feat(medicos): seed 444 médicos + columnas telefonos/email en tabla y modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:51:57 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 1574f12275 feat(medicos): módulo CRUD de médicos con tabla, búsqueda y modal edición
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:42:36 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 665fee99a9 fix(turnero): restaurar APIs del chat perdidas por force push del servidor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:41:40 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d93dccf006 feat(turnero): agregar Verificar Paciente al menú admin/supervisor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:39:00 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 cb77425ca2 feat(turnero): vista verificar_paciente dentro del ERP con Layout
- Crea modules/turnero/views/verificar_paciente.php con Layout::open/close
- Flujo completo: cédula → OTP → éxito, mismo JS que verificar.php público
- Link del módulo ahora apunta a erp.php?m=turnero&v=verificar_paciente

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:35:00 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 ff0fd3284e fix(turnero): usar plantilla correcta según tipo de turno y ajustar sidebar
- create_turno.php: tipo F usa turnero_wa_template_muestra, resto usa turnero_wa_template
- styles.css: has-active ya incluye font-size 0.82rem (verificado)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:30:06 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 fd95e7b38a fix: restaurar todas las optimizaciones móvil/tablet perdidas por force push
- chat.php: recuperado y re-aplicado panel-switch móvil, viewport iOS,
  safe-area, sticky topbar, link ← Menú, botón volver
- lugar.php: panel-switch tablet (≤860px), botón ← Cola, JS mobile
- recepcion.php: panel-switch tablet (≤900px), botón ← Cola, JS mobile
- sidebar.php: soporte atributo target en links de módulo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:25:47 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 be4cb88420 fix(turnero): restaurar Chat Turnero en menú admin/supervisor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:19:32 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 98507ad1a5 fix(turnero): restaurar dos plantillas WhatsApp en tab Sesión
- Plantilla con consentimiento (turnero_wa_template)
- Plantilla muestra pendiente (turnero_wa_template_muestra)
- sesion_turno.php guarda ambas en lab_config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:17:17 -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 34004b4d98 feat(turnero): opción solo entrega de muestras con prioridad y badge naranja en cola
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:07:05 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 76dda4722a feat(turnero): pago combinado con desglose por efectivo, transferencia y tarjeta
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 00:02:48 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 4626ca3f28 feat(display): nombre paciente más grande y visible en overlay de llamada
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:58:09 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 38bd211ca6 feat(kiosko): mostrar nombre/cédula en ticket y quitar posición en cola
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:53:39 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 c9e5744de4 feat(turnero): campo embarazada en recepción y badge en toma de muestras
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:48:03 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 7475f3c58e fix(turnero): mostrar nombre del paciente en cola al vincularlo en recepción
Al vincular un paciente al turno, actualiza paciente_nombre con el
nombre_completo real de lab_pacientes. El siguiente poll de la cola
muestra el nombre en lugar de la cédula del kiosko.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:35:45 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 8074f33b32 fix(turnero): eliminar duplicados en pantalla TV al llamar turno
callKey usaba id+llamado_at: si llamado_at llegaba null en el primer
poll y con valor en el segundo, se generaban dos claves distintas para
el mismo evento y el turno se anunciaba dos veces.

Cambia callKey a String(id) — cada turno se anuncia una sola vez
por sesión de pantalla, sin importar cambios en el timestamp.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:32:31 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 c4154b5b61 fix(turnero): deduplicar historial de llamados por turno en pantalla TV
El array 'llamados' acumulaba una entrada por cada lugar al que pasaba
un turno (recepción + toma de muestras). Al insertar un nuevo llamado
se elimina la entrada previa del mismo turno, dejando solo el último lugar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:28:21 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 910edeb876 feat(turnero): botón de llamado por registro en lugar/toma de muestras
- Agrega botón campana por cada card en cola (solo turnos en_espera_lugar)
- Click en card abre ficha sin llamar; campana llama ese turno específico
- Llamar siguiente ahora también llama de verdad (antes solo abría ficha)
- Cards en_servicio mantienen indicador de estetoscopio sin botón

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:25:34 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 6adbcc3059 feat(turnero): modal completo de paciente en recepción
- Reemplaza window.open a lab_pacientes.php por modal Bootstrap inline
- Modal incluye campos completos: datos personales, contacto (con verificador WA), ubicación y EPS
- Botón Ver/Editar en paciente vinculado carga datos desde API y abre modal en modo edición
- Botón Cambiar desvincula y enfoca el buscador
- Al crear: seleccionarPaciente() auto-vincula al turno y cierra modal
- Al editar: actualiza labels en pantalla sin perder el turno activo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 23:02:24 -05:00