Commit Graph
805 Commits
Author SHA1 Message Date
Lizandro GuarnizoandClaude Sonnet 4.6 794db4f0d5 fix: botones Descargar PDF y Cerrar tras firmar consentimiento
Después de firmar (y en carga cuando ya está firmado) no había ninguna
acción disponible — solo texto "Puede cerrar esta ventana" sin botón.

Ahora aparecen dos botones:
- Descargar PDF → window.print() (permite guardar como PDF)
- Cerrar → window.close() (solo cuando no está en iframe)

En modo embebido (iframe desde lugar.php) solo aparece Descargar PDF;
el cierre lo maneja el postMessage ya existente al padre.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 18:01:33 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 99bfaa4c2f fix: convertir audio webm → ogg con ffmpeg antes de subir a WhatsApp en turnero
El archivo grabado por el browser es WebM (no soportado por WhatsApp).
conversations.php usa ffmpeg para convertirlo; chat_upload_media.php solo
cambiaba el string del MIME pero enviaba el archivo WebM real, causando que
el audio no llegara al destinatario. Ahora se convierte con los mismos
parámetros que upload_media.php (libopus 32k mono 48kHz).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:56:15 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a526a29a68 feat: botón Ver paciente con historial en vista lugar
Agrega botón "Ver" en la sección Paciente de la ficha del turno.
Abre modal con datos completos del paciente (nombre, doc, fecha nac,
celular, médico, embarazo) y timeline de historial de visitas anterior
(misma lógica que recepción), cargado desde get_historial.php.

El botón solo aparece cuando hay un paciente vinculado al turno.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:55:51 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 282c372de3 fix: corregir reproducción de audio en chat turnero
- URL absoluta para local_file y media_url_external (igual que conversations.php)
- Múltiples <source> con MIME types (ogg, mpeg, wav, webm) para compatibilidad
- onerror handler cuando el archivo no está disponible
- Fallback visible cuando mediaSrc es null ("Audio pendiente de descarga")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:50:43 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 53dc492b5e feat: auto-rellenar variable {{name}} con nombre del paciente en nuevo mensaje
Al seleccionar un paciente de la lista, si la plantilla tiene una variable
llamada 'name', se pre-rellena automáticamente con su nombre. Si se ingresa
un número directo, el campo queda vacío para llenarlo manualmente.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:48:02 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 e88fb4cc86 fix: mensajes automáticos del turnero registrados en canal principal
create_turno.php y send_consentimiento.php enviaban por WhatsAppService('turnero')
(número correcto) pero sin pasar meta canal='turnero', por lo que saveOutgoingMessage
defaulteaba a canal='bot' y quedaban registrados en las conversaciones del principal.

Agregado $waMeta = ['canal'=>'turnero'] en ambos archivos para sendTemplateMessage
y sendTextMessage (fallback).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:42:39 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 1bd799a501 fix: corregir envío de plantillas con variables nombradas en chat turnero
El parámetro_name enviado a WhatsApp era el índice numérico ("1") en vez
del nombre real de la variable ("name", "fecha", etc.), causando el error
#100 Invalid parameter. Ahora se detecta si las variables son nombradas o
numéricas y se construye el payload correctamente, igual que conversations.php.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:37:33 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 34c6d2e643 fix: documentos recibidos en chat devuelven 401
Las URLs de CDN de WhatsApp (lookaside.fbsbx.com) requieren Authorization Bearer.
chat_get_messages.php las exponía directamente al browser, que no puede añadir
ese header, resultando en 401 "Authentication Error".

Ahora siempre se enrutan por /api/version/media-url.php (proxy existente) que:
- Sirve el archivo local si existe en disco
- Hace fetch con el token de WA si no está en local
- No requiere sesión para peticiones GET del browser

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:30:02 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 12c790fb5c fix: mover CSS del modal nuevo-mensaje fuera del media query mobile
Los estilos de #nuevo-modal y .nv-* estaban dentro de @media (max-width: 680px),
por lo que el modal no tenía diseño en desktop.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:28:08 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f975844d9d fix: reacciones y audio en chat turnero
- chat_react: guardaba en tabla `messages` en lugar de `conversations` (tabla real del chat)
- chat_react: columna era `whatsapp_message_id`; la correcta es `message_id`
- chat.php: sendReactionEmoji actualiza la burbuja DOM inmediatamente sin esperar poll
- chat_upload_media: mime_content_type() devuelve video/webm en Linux para audio grabado;
  ahora cualquier mime con "webm" se remapea a audio/ogg antes de determinar mediaType

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:24:35 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 ab72750410 feat(chat): botón Nuevo mensaje con búsqueda de paciente y picker de plantilla
- chat_buscar_paciente.php: GET ?q= busca en lab_pacientes por nombre,
  documento o teléfono (mín. 2 chars, máx. 20 resultados)
- chat_start_conversation.php: POST {phone, template_name, lang, params}
  — normaliza teléfono, busca/crea usuario en users, envía plantilla
  vía WhatsAppService('turnero'), devuelve {ok, user_id}
- chat.php: botón "+ Nuevo" en sidebar header; modal 3 pasos:
  1) buscar paciente (debounce 350ms) o ingresar número libre
  2) lista de plantillas habilitadas
  3) variables de la plantilla + Enviar
  Al enviar recarga el sidebar y abre la conversación automáticamente

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:19:18 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 67efd470de feat(firma): integración Topaz SigWeb en ver_formulario_enviado.php
- CSS/HTML: mismo overlay #topaz-overlay con modal de estado
- JS: módulo topaz con target={canvas, onAccept} para canvas
  del profesional (.fpw-canvas) y del paciente turnero (.turnero-cv)
- Botón "Tableta" en canvas del paciente (.turnero-topaz) y del
  profesional (.fpw-topaz); el usuario sigue confirmando manualmente

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:11:29 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 9e19c1c8c7 feat(firma): integración pad biométrico Topaz SigWeb
- CSS: overlay #topaz-overlay con modal centrado, estado has-sig
- HTML: modal con área de estado, contador de trazos, botones
  Cancelar / Limpiar / Aceptar
- JS: módulo topaz — carga SigWebTablet.js desde localhost:47289,
  compatible con SigWeb v1 (globals+ctx) y v2 (métodos en objeto),
  soporta fid='__global' para canvas principal e inline (fw-*)
- Botón "Tableta" agregado en canvas area global y en renderFirmaInline
  para campos tipo firma/firma_profesional

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 17:06:47 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 3d6147bf0d fix(template): send parameter_name for named-variable templates
WhatsApp API returns "(#100) Invalid parameter — Parameter name is
missing or empty" for templates that use named variables.

- chat.php sendTemplate(): collect params as [{name, value}] objects
  using data-var-index as the parameter name
- WhatsAppService::sendTemplateMessage(): handle {name, value} objects
  in the indexed-array path by emitting {type, parameter_name, text}
  (backward-compatible — plain strings still work as positional params)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 15:04:31 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a8380ddc81 debug(template): expose Meta error subcode/details, add canal meta
- WhatsAppService::makeRequest: include error_subcode and error_data.details
  in the thrown exception message to surface the real reason for #100 errors
- chat_send_message: log template name/lang/params before sending;
  pass canal+operator_id meta so outgoing templates are tagged correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 14:54:10 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f60df038d8 fix(chat): capture template name/lang before closing modal in sendTemplate
closeTemplatePicker() sets _tplSelected = null, so accessing
_tplSelected.template_name after the call threw a TypeError caught
as "Error de red al enviar plantilla".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 14:47:31 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 ccdc35932d feat(turnero): add chat plantillas API endpoints
- chat_get_plantillas.php: GET — returns enabled templates from
  turnero_chat_plantillas JOIN message_templates; auto-creates table
- chat_save_plantillas.php: POST {ids:[...]} — replaces all rows in
  turnero_chat_plantillas using DELETE + INSERT IGNORE in a transaction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 14:41:24 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 548ad3140d feat(turnero): template whitelist checklist + 2-step picker in chat
- configuracion.php (sesion tab): loads approved message_templates and
  enabled turnero_chat_plantillas; renders styled checklist; guardarPlantillasChat()
  POSTs to chat_save_plantillas.php
- chat.php: replaces free-text template modal with 2-step modal —
  step 1 lists enabled templates (chat_get_plantillas.php), step 2
  fetches variables via get_template_details.php and renders labeled
  inputs; sendTemplate() builds params array and POSTs to chat_send_message.php

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 14:37:21 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 8a7e7a6658 Fix chat media upload: extract id from uploadMedia result, remap audio/webm
uploadMedia() returns the full API response array, not just the id string.
chat_upload_media.php was passing the whole array as $mediaId, producing
{"image": {"id": {"id": "...", "messaging_product": "..."}}} which
violated WhatsApp JSON schema for the media id field.

Also remap audio/webm (browser MediaRecorder default) to audio/ogg at
upload time since WhatsApp's media API rejects webm but accepts ogg/opus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 14:28:33 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 0cef678848 Add server-side pagination to medicos list (25 per page)
list.php now accepts page/limit params and returns total count.
View shows X-Y de N label, page buttons with ellipsis for large ranges,
and prev/next arrows. Search resets to page 1; save/delete stay on
current page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 14:24:55 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 00725ccd11 Redesign lugar.php UI/UX: patient-first, better cola, sticky actions
Bloque 1 - Cola:
- Separate sections for "en servicio" vs "en espera" with headers
- Time-in-queue badges (green <10min, amber <25min, red 25min+) from creado_at
- Prominent EN SERVICIO pill (solid green) instead of subtle border
- Larger touch targets on queue cards, bigger bell button
- Count chips show espera + servicio counts separately

Bloque 2 - Ficha header + action bar:
- Patient name is now the dominant element (1.35rem bold) with skeleton
  loader animation while async data loads; turno code becomes a secondary chip
- Action bar restructured: full-width primary button (blue "Anunciar turno" /
  green "Finalizar atención") + smaller secondary row (Re-llamar, Regresar, Ausente)
- Consent warning strip added inside action bar showing pending count;
  blocks Finalizar visually and functionally

Bloque 3 - Sections + mobile:
- Section headers use consistent .ficha-sec-hdr style with icon
- Mobile: fixed sticky "← Cola" top bar inside ficha panel (always visible,
  no hunting for back button)
- ficha-turno uses flex-column so action bar sticks to bottom without scroll

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 14:21:42 -05: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 b399c3710e fix(formulario): no mostrar firma paciente si schema tiene firma_profesional
Usar _esquemaTieneFirmaAlguna (cualquier tipo firma) en lugar de
_esquemaTieneFirmaPaciente para suprimir el widget fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 12:32:01 -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 05c7230eda fix(formularios): pre-fill fecha_hoy and edad in ver_formulario_enviado
- Modo editar: fecha_hoy → type=date prefilled with today; edad → type=number prefilled from paciente.fecha_nacimiento
- Modo vista: if no saved value, fecha_hoy shows today's date; edad calculates from DOB instead of skipping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:47:33 -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 e1f0fe3450 refactor(formularios): split 'calculado' into two direct field types
Instead of one field with a sub-option, there are now two independent palette
items under a 'Calculados' section:
- fecha_hoy: renders type=date pre-filled with today's date (YYYY-MM-DD)
- edad: renders type=number pre-filled with age calculated from paciente.fecha_nacimiento

Both are editable by the patient and have a yellow tint.
Preview in the builder also shows the live date value for fecha_hoy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:44:11 -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 daa9827d93 feat(builder): tablet-friendly drag — pointer events + tap-to-add palette
- Palette items: onclick adds field directly (tap on tablet, no drag needed)
- Canvas reorder: PointerEvents drag (touchstart/move/end) with visual ghost
  and blue line indicator; HTML5 drag kept for mouse/desktop
- CSS: drop-above/drop-below indicators, ghost element, larger touch targets
  for handle and action buttons on coarse pointer devices
- Hide preview panel on ≤680px to give more canvas space on small tablets
- calculado added to TIPO_ICON map

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:28:28 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 1385c25b30 feat(formularios): add 'calculado' field type with fecha_hoy and edad sub-types
Builder:
- New palette item 'Campo calculado' (fa-calculator)
- Editor modal lets user pick: Fecha de hoy / Edad del paciente
- Preview shows yellow-tinted input with calculator badge

form_cliente.php:
- fecha_hoy: pre-fills today's date (YYYY-MM-DD), editable by patient
- edad: calculates age from patient's fecha_nacimiento, editable
- Collected on submit like any normal input

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:23:36 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 0c68dff307 fix: mostrar canvas para todos los campos firma en modo turnero
Antes solo el primer campo (consentimiento) tenía canvas; el segundo
(desistimiento) se omitía. Ahora cada campo firma tiene su propio widget
usando clases CSS en vez de IDs hardcodeados.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:22:18 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 597ec87964 fix: redirigir UUID tokens de form_cliente.php a ver_formulario_enviado.php
El botón WA del template apunta a form_cliente.php?t={{1}}; si el token
es UUID (turnero) se redirige al flujo de consentimiento correcto.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:16:13 -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 Guarnizo 9d34c6b984 debug: mostrar teléfono de paciente por documento 2026-07-03 10:42:08 -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 Guarnizo 61c8c0b9ca fix debug: quitar creado_at del test INSERT 2026-07-03 10:30:39 -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 Guarnizo ad0eefe31f debug: marker [usite] para verificar deploy 2026-07-03 10:26:38 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 1bb520ef3f debug: agregar diagnóstico tabla consentimientos y turnos del día
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:24:46 -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 eddfe4d16c debug_turno_wa: corregir tabla system_config para token/phone WA
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:02:34 -05:00