- skeen_citas: campo sala en skeen.lista.espera (consultoria/cabina, indexado)
- frontend.py: sala en _lista_espera_to_dict, create y update (toggle desde
la etiqueta; valor invalido vuelve a sin sala; cambio queda en historial)
- ListaEspera.tsx: toggle Todas/Consultoria/Cabina con conteo, etiqueta
clicable en cada tarjeta que alterna de sala, selector en el modal de alta
- Agenda.tsx: cambiarSala() conectado al panel
- WacrmMessages.tsx: el auto-refresco ya no empuja el scroll abajo si el
usuario esta leyendo mensajes anteriores (solo baja al cambiar de
conversacion, por deep-link o al enviar respuesta propia)
Verificacion API: 7/7 tests OK (alta con sala, toggle, valor invalido, GET)
Auditoria de 260 visitas (26 rutas x 10 roles) sobre el build actual: 0 hallazgos.
Dos defectos reales que salieron del barrido anterior se corrigen aqui.
1) Reportes: la matriz guarda claves '/reportes?tab=x' y puede conceder una
pestana suelta (Horas agenda al medico, Exportar a cosmetologia) sin dar el
modulo. Nadie la respetaba:
- App.tsx: nuevo ReportesRoute que evalua la pestana del URL; si el rol no
tiene '/reportes' pero si alguna pestana, aterriza en la primera permitida.
- Reportes.tsx: familias, favoritos y el boton "Exportar datos" se filtran
por canSee('/reportes?tab=x'). 'exportar' no pertenece a ninguna familia,
por eso se lista en TABS_FUERA_DE_FAMILIA (si no, el guard lo reescribia a
'general' y admin perdia la vista). El query se sincroniza con lo renderizado.
- SkeenLayout/HomeNestLayout: "Horas agenda" y "Exportar datos" aparecen en
Analitica para que el permiso sea alcanzable desde el menu, no solo a
mano. Clasico ya los traia.
- auth.py: _medico_reporte_permitido consulta la matriz antes de vetar
/reports/ al medico. Sin ese puente el menu ofrecia la opcion y la API
respondia 403. Las demas rutas vetadas (sales, payments, wallets, pos)
siguen cerradas: verificado comisiones=403, horas-agenda=200.
2) skeen_chat/_touch: 211 "could not serialize access due to concurrent update"
en un barrido. Bandeja, badge y heartbeat salen en paralelo y cada uno
emitia el UPDATE de last_seen aunque no aplicara cambios, abortando la
transaccion de otra peticion. Se corta antes de tocar la fila cuando el
registro es reciente; el savepoint queda para el caso de empate exacto.
Ráfaga de 128 peticiones concurrentes: todas 200, presencia sigue
actualizando (online=true, last_seen avanza) y el ruido bajo de 211 a 5.
El modelo tenia el campo price y el POS lo usa para cobrar, pero ni el
formulario de alta lo capturaba ni existia modal de edicion: los 170
articulos tenian precio en 0 y recepcion tecleaba el precio a mano en
cada venta.
- Backend: inventory_create acepta price; inventory_update lo permite
entre los campos editables (con conversion float).
- Frontend: columna 'Precio venta' en la tabla, campo en el alta y
modal nuevo 'Editar articulo' (nombre, precio, costo, SKU, categoria,
unidad, niveles y notas). La existencia sigue cambiando solo via
Ajustar para dejar registro del movimiento.
Recorrido dinamico de las 26 rutas con los 10 roles (260 visitas con
navegador real) mas revision estatica de endpoints FE vs BE. Hallazgos
y correcciones:
- frontend.py: expedientes_recientes no tenia @http.route (el endpoint
/expedientes-recientes respondia 404). Se expone con GET + lectura.
- auth.py: MEDICO_BLOCKED_PREFIXES hacia match por startswith, asi que
/sales_goal quedaba bloqueado para medicos (403 en consola en todas
las pantallas por el widget de meta del mes). Ahora el match exige
frontera de path (/sales bloquea /sales/x pero no /sales_goal).
- Reportes: getCommissions (endpoint admin-only) iba dentro de un
Promise.all; el 403 tumbaba todo el tab General para recepcion,
gerencia, enfermeria, psicologa, farmacia y lectura. Ahora va en
peticion aislada y solo se llama para admin; la seccion de comisiones
del tab General solo se renderiza para admin.
- Matriz de menus guardada: medico habia quedado fuera de /pacientes
y /visitas (los defaults del codigo lo incluyen y los medicos lo
necesitan para ver clientes e historial). Restaurado via PUT
/roles/permissions (queda en skeen_config_audit).
Verificado con navegador: medico entra a /pacientes y /visitas sin
403; recepcion y gerencia cargan /reportes sin error; admin sigue
viendo la seccion de comisiones. Usuarios temporales de auditoria
eliminados.
- Nuevo modelo skeen.ticket.config (AbstractModel) con layout, datos de clinica
y logo en ir.config_parameter; _mezclar() hace que layouts viejos hereden las
secciones nuevas; _validar() rechaza valores imposibles y textos largos.
- Endpoints GET/PUT /ticket_config, PUT /ticket_config/clinica,
POST /ticket_config/reset (reset solo admin) con auditoria en skeen_config_audit.
- Los datos de la clinica pasan de localStorage (cada caja imprimia distinto)
a configuracion compartida en el servidor.
- TicketDoc.tsx renderiza segun el diseno: ancho 58/80mm, fuente, tamano de letra,
separador, mayusculas, orden de bloques y 29 secciones activables.
- TicketDesigner.tsx: editor completo con vista previa en vivo, reorden de bloques,
textos personalizables y carga de logo.
- TicketPrint.tsx ahora es un wrapper de TicketDoc; ReciboPrint, EstadoCuentaPrint,
RecetaPrint, CortePrint y ConteoPrint usan useClinicaPrint().
- _sale_to_dict expone telefono del paciente, medico que atendio y datos de paquete;
pos_checkout devuelve recibido/cambio en MXN y USD para imprimirlos.
- Columna 'Estado' con switch Activo/Baja (confirmación previa) y checkbox
'Mostrar dados de baja' para poder reactivar.
- GET /doctors solo devuelve activos; include_inactive=1 para la pantalla de
Médicos. Cada médico expone su campo 'active'.
- Reglas en modelo: un empleado dado de baja no admite citas nuevas
(skeen.cita), ni asignación de pacientes (res.partner.primary_doctor_id),
ni líneas de venta (skeen.venta.line.prescribed_by_id). El historial
existente no se toca: los constraints solo corren cuando cambia la
asignación.
- ValidationError se responde 400 con mensaje legible en pacientes y ventas.
- fix: badges de estado de cita en agenda y dashboard usan la etiqueta de la
clínica en lugar del valor técnico.
- BloqueosModal: alta multi-médico, rango repetible por día de la semana,
motivos predefinidos, edición/borrado y cierre rápido desde la cabecera
de cada columna (todo el día / resto del día / rango).
- skeen.lista.espera + panel y modal en la agenda: prioridad, franja, rango
de fechas, agendar precargado, avisar por WhatsApp y aviso cuando se
libera un hueco compatible.
- duration en skeen.cita (0 = la del servicio): la cita ocupa sus bloques de
15 min reales en las 4 vistas, con celdas de continuación.
- Checklist de estados (Agendada → Confirmada → En cabina → En consulta →
Completada) con avance/retroceso, cancelación y no-show con confirmación,
y bitácora de quién/cuándo en skeen.cita.state.log.
- Etiquetas del sistema legacy alineadas (Canceló / Lista de espera / En
cabina) en badges de agenda y dashboard.
- Auto refresco silencioso cada 30 s (pausable, se pospone con modales,
escritura o drag) en citas + bloqueos + lista de espera en un solo request.
- Píldora verde 'N ventas' + gris 'N recomendaciones' y píldoras
índigo apiladas (usd / m.n. / tarjeta m.n.) en una sola columna
- recomendaciones_30d: pacientes captados con 'recomendado por'
- card_amount en ventas (pagos con terminal física)
- Stats por médico vía líneas recetadas, métrica consistente con comisiones
- 4 columnas nuevas en la página de Médicos
- Campo genera_monedero (default true) en servicios e items de inventario
- Puntos proporcionales a las líneas elegibles al liquidar la venta
- Toggle con icono Wallet en Servicios e Inventario
- Equivalente USD en totales del ticket (TC configurable)
- Selector MXN/USD al cobrar: recibido en dólares convertido a MXN,
cambio en ambas monedas, referencia 'USD X @ TC Y' en el pago
- Validación de TC antes de crear la venta (sin ventas huérfanas)
- Toggle Servicios|Artículos en el catálogo del POS
- Líneas de venta con item_id (service_id opcional), stock descargado
con movimiento 'venta' al cobrar, advertencias de sobreventa
- Campo precio de venta en artículos de inventario (backend Odoo)
- Módulo Visitas completo (auto desde agenda, insumos con descargo de
inventario, fotos antes/después y documentos, receta imprimible)
- Punto de Venta (catálogo + ticket sticky, cobro con cambio, pago con
puntos monedero, ticket imprimible)
- WACRM: leads automáticos desde WhatsApp, asignación de conversaciones
y leads a agentes, conversión lead→paciente, ficha del paciente en chat
- Pacientes: completitud de expediente, alertas clínicas, historial
unificado con detalle, foto, WhatsApp, estado de cuenta, filtros
rápidos (VIP/recientes/médico), documentos (expediente escaneado + galería)
- Agenda: vistas por médico y por hora, filtros rápidos (libres, primera
vez, check-in, no-show), modal de acciones, bloqueos por médico,
drag&drop para mover citas
- Reportes: 18 pestañas (diario, cortes, ingresos, inventario, adeudos,
comisiones, pagos, devoluciones, top clientes, horas, paquetes,
vendedores, concentrado, recomendaciones, KPIs) con exportación Excel
- Temas: nuevo tema Clásico (look legacy AdminLTE) con submenús tipo
treeview, selector de tema; accesos rápidos personalizables con 3
presentaciones; búsqueda global; notificaciones reales
- Configuración: secciones (clínica, usuarios con permisos por sección,
recetas, catálogos de diagnósticos y procedimientos)
- Inventario: alertas de caducidad y sugerencia de compra, cron diario
que descuenta artículos caducados, compras/bajas
- Consultas Médicas, página Expedientes, importadores delta
(citas/visitas legacy idempotentes), depuración de duplicados
- Infra: tema Tailwind conectado (@config), gzip en nginx, secuencias
Odoo corregidas (noupdate, company_id), rollback en validaciones