feat(#71): Implementar dashboards para administrador del laboratorio
- Dashboard de Estado de Órdenes: Vista gráfica y pivot de órdenes por estado - Dashboard de Productividad de Técnicos: Análisis de pruebas por técnico - Dashboard de Muestras: Estado y distribución de muestras por tipo - Dashboard de Parámetros Fuera de Rango: Identificación de resultados críticos - Dashboard de Análisis Más Solicitados: Top de análisis por período - Dashboard de Distribución Demográfica: Tests por género y rango de edad - Agregar campos computed age_range, patient_gender y patient_age_range - Configurar menú de Dashboards solo para administradores 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
34f3b0aa14
commit
d51d3b5d69
78
dashboard_analysis.md
Normal file
78
dashboard_analysis.md
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Análisis de Dashboards para LIMS - Issue #71
|
||||
|
||||
## Dashboards Implementables sin Módulos Adicionales ni Cambios Estructurales
|
||||
|
||||
### 1. ✅ Dashboard de Estado de Órdenes
|
||||
**Factibilidad**: Alta
|
||||
- Usar vistas graph y pivot nativas de Odoo
|
||||
- Datos disponibles: sale.order con is_lab_request=True
|
||||
- Métricas: órdenes por estado, por fecha, por paciente
|
||||
|
||||
### 2. ✅ Dashboard de Productividad de Técnicos
|
||||
**Factibilidad**: Alta
|
||||
- Datos disponibles: lims.test (technician_id, state, create_date, validation_date)
|
||||
- Métricas: pruebas procesadas por técnico, tiempos promedio, estados
|
||||
|
||||
### 3. ✅ Dashboard de Muestras
|
||||
**Factibilidad**: Alta
|
||||
- Datos disponibles: stock.lot con is_lab_sample=True
|
||||
- Métricas: muestras por estado, rechazos, re-muestreos
|
||||
|
||||
### 4. ✅ Dashboard de Parámetros Fuera de Rango
|
||||
**Factibilidad**: Alta
|
||||
- Datos disponibles: lims.result (is_out_of_range, is_critical)
|
||||
- Métricas: resultados críticos, fuera de rango por parámetro
|
||||
|
||||
### 5. ✅ Dashboard de Análisis Más Solicitados
|
||||
**Factibilidad**: Alta
|
||||
- Datos disponibles: sale.order.line con productos is_analysis=True
|
||||
- Métricas: top análisis, tendencias por período
|
||||
|
||||
### 6. ⚠️ Dashboard de Tiempos de Respuesta
|
||||
**Factibilidad**: Media
|
||||
- Requiere campos calculados (no almacenados actualmente)
|
||||
- Necesitaría agregar campos store=True para métricas de tiempo
|
||||
|
||||
### 7. ❌ Dashboard de Facturación
|
||||
**Factibilidad**: Baja
|
||||
- Requiere módulo account (facturación)
|
||||
- No está en las dependencias actuales
|
||||
|
||||
### 8. ❌ Dashboard de Inventario de Reactivos
|
||||
**Factibilidad**: Baja
|
||||
- Requiere configuración adicional de stock
|
||||
- No hay modelo específico para reactivos
|
||||
|
||||
## Implementación Técnica
|
||||
|
||||
### Herramientas Disponibles en Odoo 18:
|
||||
1. **Vistas Graph**: Gráficos de barras, líneas, pie
|
||||
2. **Vistas Pivot**: Tablas dinámicas
|
||||
3. **Vistas Cohort**: Análisis de cohortes
|
||||
4. **Filtros y Agrupaciones**: Para segmentar datos
|
||||
5. **Acciones de Servidor**: Para cálculos complejos
|
||||
|
||||
### Estructura Propuesta:
|
||||
```xml
|
||||
<!-- Menú principal de Dashboards -->
|
||||
<menuitem id="menu_lims_dashboards"
|
||||
name="Dashboards"
|
||||
parent="lims_management.menu_lims_root"
|
||||
sequence="5"
|
||||
groups="group_lims_admin,group_lims_manager"/>
|
||||
```
|
||||
|
||||
## Recomendación
|
||||
|
||||
Sugiero comenzar con los 5 dashboards marcados con ✅ ya que:
|
||||
1. Utilizan datos existentes
|
||||
2. No requieren cambios en modelos
|
||||
3. Usan herramientas nativas de Odoo
|
||||
4. Proveen valor inmediato al administrador
|
||||
|
||||
Orden de implementación sugerido:
|
||||
1. Dashboard de Estado de Órdenes (más básico)
|
||||
2. Dashboard de Productividad de Técnicos
|
||||
3. Dashboard de Muestras
|
||||
4. Dashboard de Parámetros Fuera de Rango
|
||||
5. Dashboard de Análisis Más Solicitados
|
|
@ -45,6 +45,7 @@
|
|||
'views/analysis_parameter_views.xml',
|
||||
'views/product_template_parameter_config_views.xml',
|
||||
'views/parameter_dashboard_views.xml',
|
||||
'views/dashboard_views.xml',
|
||||
'views/menus.xml',
|
||||
'views/lims_config_views.xml',
|
||||
'report/sample_label_report.xml',
|
||||
|
|
Binary file not shown.
|
@ -116,6 +116,21 @@ class LimsTest(models.Model):
|
|||
default=lambda self: self.env.company
|
||||
)
|
||||
|
||||
# Campos para dashboards demográficos
|
||||
patient_gender = fields.Selection(
|
||||
related='patient_id.gender',
|
||||
string='Género del Paciente',
|
||||
store=True,
|
||||
readonly=True
|
||||
)
|
||||
|
||||
patient_age_range = fields.Selection(
|
||||
related='patient_id.age_range',
|
||||
string='Rango de Edad',
|
||||
store=True,
|
||||
readonly=True
|
||||
)
|
||||
|
||||
@api.depends('company_id')
|
||||
def _compute_require_validation(self):
|
||||
"""Calcula si la prueba requiere validación basado en configuración."""
|
||||
|
|
|
@ -29,6 +29,17 @@ class ResPartner(models.Model):
|
|||
help="Edad calculada en años basada en la fecha de nacimiento"
|
||||
)
|
||||
|
||||
age_range = fields.Selection([
|
||||
('0-10', '0-10 años'),
|
||||
('11-20', '11-20 años'),
|
||||
('21-30', '21-30 años'),
|
||||
('31-40', '31-40 años'),
|
||||
('41-50', '41-50 años'),
|
||||
('51-60', '51-60 años'),
|
||||
('61-70', '61-70 años'),
|
||||
('71+', 'Más de 70 años')
|
||||
], string="Rango de Edad", compute='_compute_age_range', store=True)
|
||||
|
||||
is_pregnant = fields.Boolean(
|
||||
string="Embarazada",
|
||||
help="Marcar si la paciente está embarazada (solo aplica para género femenino)"
|
||||
|
@ -54,6 +65,34 @@ class ResPartner(models.Model):
|
|||
else:
|
||||
partner.age = 0
|
||||
|
||||
@api.depends('birthdate_date')
|
||||
def _compute_age_range(self):
|
||||
"""Calcula el rango de edad basado en la edad"""
|
||||
for partner in self:
|
||||
if partner.birthdate_date:
|
||||
today = date.today()
|
||||
delta = relativedelta(today, partner.birthdate_date)
|
||||
age = delta.years
|
||||
|
||||
if age <= 10:
|
||||
partner.age_range = '0-10'
|
||||
elif age <= 20:
|
||||
partner.age_range = '11-20'
|
||||
elif age <= 30:
|
||||
partner.age_range = '21-30'
|
||||
elif age <= 40:
|
||||
partner.age_range = '31-40'
|
||||
elif age <= 50:
|
||||
partner.age_range = '41-50'
|
||||
elif age <= 60:
|
||||
partner.age_range = '51-60'
|
||||
elif age <= 70:
|
||||
partner.age_range = '61-70'
|
||||
else:
|
||||
partner.age_range = '71+'
|
||||
else:
|
||||
partner.age_range = False
|
||||
|
||||
@api.constrains('is_pregnant', 'gender')
|
||||
def _check_pregnant_gender(self):
|
||||
"""Valida que solo pacientes de género femenino puedan estar embarazadas"""
|
||||
|
|
321
lims_management/views/dashboard_views.xml
Normal file
321
lims_management/views/dashboard_views.xml
Normal file
|
@ -0,0 +1,321 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- ================================================================
|
||||
DASHBOARD 1: Estado de Órdenes de Laboratorio
|
||||
================================================================ -->
|
||||
|
||||
<!-- Vista Graph para Estado de Órdenes -->
|
||||
<record id="view_lab_order_dashboard_graph" model="ir.ui.view">
|
||||
<field name="name">sale.order.lab.dashboard.graph</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Estado de Órdenes" type="pie">
|
||||
<field name="state"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vista Pivot para Estado de Órdenes -->
|
||||
<record id="view_lab_order_dashboard_pivot" model="ir.ui.view">
|
||||
<field name="name">sale.order.lab.dashboard.pivot</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Análisis de Órdenes">
|
||||
<field name="date_order" interval="month" type="col"/>
|
||||
<field name="state" type="row"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Acción para Dashboard de Estado de Órdenes -->
|
||||
<record id="action_lab_order_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Estado de Órdenes</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">graph,pivot,tree,form</field>
|
||||
<field name="domain">[('is_lab_request', '=', True)]</field>
|
||||
<field name="context">{'search_default_group_by_state': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No hay órdenes de laboratorio registradas
|
||||
</p>
|
||||
<p>
|
||||
Este dashboard muestra el estado actual de todas las órdenes de laboratorio.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================
|
||||
DASHBOARD 2: Productividad de Técnicos
|
||||
================================================================ -->
|
||||
|
||||
<!-- Vista Graph para Productividad de Técnicos -->
|
||||
<record id="view_test_technician_productivity_graph" model="ir.ui.view">
|
||||
<field name="name">lims.test.technician.productivity.graph</field>
|
||||
<field name="model">lims.test</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Productividad de Técnicos" type="bar">
|
||||
<field name="technician_id"/>
|
||||
<field name="state"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vista Pivot para Productividad de Técnicos -->
|
||||
<record id="view_test_technician_productivity_pivot" model="ir.ui.view">
|
||||
<field name="name">lims.test.technician.productivity.pivot</field>
|
||||
<field name="model">lims.test</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Análisis por Técnico">
|
||||
<field name="technician_id" type="row"/>
|
||||
<field name="state" type="col"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Acción para Dashboard de Productividad de Técnicos -->
|
||||
<record id="action_technician_productivity_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Productividad de Técnicos</field>
|
||||
<field name="res_model">lims.test</field>
|
||||
<field name="view_mode">graph,pivot,tree,form</field>
|
||||
<field name="context">{'search_default_group_by_technician': 1, 'search_default_this_month': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No hay pruebas registradas
|
||||
</p>
|
||||
<p>
|
||||
Este dashboard muestra la productividad de cada técnico del laboratorio.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================
|
||||
DASHBOARD 3: Estado de Muestras
|
||||
================================================================ -->
|
||||
|
||||
<!-- Vista Graph para Estado de Muestras -->
|
||||
<record id="view_sample_status_graph" model="ir.ui.view">
|
||||
<field name="name">stock.lot.sample.status.graph</field>
|
||||
<field name="model">stock.lot</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Estado de Muestras" type="pie">
|
||||
<field name="state"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vista Pivot para Muestras por Tipo -->
|
||||
<record id="view_sample_type_pivot" model="ir.ui.view">
|
||||
<field name="name">stock.lot.sample.type.pivot</field>
|
||||
<field name="model">stock.lot</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Muestras por Tipo">
|
||||
<field name="sample_type_product_id" type="row"/>
|
||||
<field name="state" type="col"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Acción para Dashboard de Muestras -->
|
||||
<record id="action_sample_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Dashboard de Muestras</field>
|
||||
<field name="res_model">stock.lot</field>
|
||||
<field name="view_mode">graph,pivot,tree,form</field>
|
||||
<field name="domain">[('is_lab_sample', '=', True)]</field>
|
||||
<field name="context">{'search_default_group_by_state': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No hay muestras registradas
|
||||
</p>
|
||||
<p>
|
||||
Este dashboard muestra el estado de todas las muestras del laboratorio.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================
|
||||
DASHBOARD 4: Parámetros Fuera de Rango
|
||||
================================================================ -->
|
||||
|
||||
<!-- Vista Graph para Parámetros Fuera de Rango -->
|
||||
<record id="view_result_out_of_range_graph" model="ir.ui.view">
|
||||
<field name="name">lims.result.out.of.range.graph</field>
|
||||
<field name="model">lims.result</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Parámetros Fuera de Rango" type="bar">
|
||||
<field name="parameter_id"/>
|
||||
<field name="is_out_of_range" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vista Pivot para Resultados Críticos -->
|
||||
<record id="view_result_critical_pivot" model="ir.ui.view">
|
||||
<field name="name">lims.result.critical.pivot</field>
|
||||
<field name="model">lims.result</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Resultados Críticos">
|
||||
<field name="parameter_id" type="row"/>
|
||||
<field name="is_critical" type="col"/>
|
||||
<field name="is_out_of_range" type="col"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Acción para Dashboard de Parámetros Fuera de Rango -->
|
||||
<record id="action_out_of_range_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Parámetros Fuera de Rango</field>
|
||||
<field name="res_model">lims.result</field>
|
||||
<field name="view_mode">graph,pivot,tree,form</field>
|
||||
<field name="domain">[('test_id.state', '=', 'validated')]</field>
|
||||
<field name="context">{'search_default_out_of_range': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No hay resultados fuera de rango
|
||||
</p>
|
||||
<p>
|
||||
Este dashboard muestra los parámetros que están fuera de los rangos normales.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================
|
||||
DASHBOARD 5: Análisis Más Solicitados
|
||||
================================================================ -->
|
||||
|
||||
<!-- Vista Graph para Top Análisis -->
|
||||
<record id="view_top_analysis_graph" model="ir.ui.view">
|
||||
<field name="name">sale.order.line.top.analysis.graph</field>
|
||||
<field name="model">sale.order.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Análisis Más Solicitados" type="bar">
|
||||
<field name="product_id"/>
|
||||
<field name="product_uom_qty" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vista Pivot para Análisis por Período -->
|
||||
<record id="view_analysis_period_pivot" model="ir.ui.view">
|
||||
<field name="name">sale.order.line.analysis.period.pivot</field>
|
||||
<field name="model">sale.order.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Análisis por Período">
|
||||
<field name="create_date" interval="month" type="col"/>
|
||||
<field name="product_id" type="row"/>
|
||||
<field name="product_uom_qty" type="measure"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Acción para Dashboard de Análisis Más Solicitados -->
|
||||
<record id="action_top_analysis_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Análisis Más Solicitados</field>
|
||||
<field name="res_model">sale.order.line</field>
|
||||
<field name="view_mode">graph,pivot,tree</field>
|
||||
<field name="domain">[('order_id.is_lab_request', '=', True), ('product_id.is_analysis', '=', True)]</field>
|
||||
<field name="context">{'search_default_group_by_product': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No hay análisis registrados
|
||||
</p>
|
||||
<p>
|
||||
Este dashboard muestra los análisis más solicitados en el laboratorio.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================
|
||||
DASHBOARD 6: Distribución de Tests por Demografía
|
||||
================================================================ -->
|
||||
|
||||
<!-- Vista Graph para Distribución por Sexo -->
|
||||
<record id="view_test_gender_distribution_graph" model="ir.ui.view">
|
||||
<field name="name">lims.test.gender.distribution.graph</field>
|
||||
<field name="model">lims.test</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Distribución por Género" type="pie">
|
||||
<field name="patient_gender"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vista Pivot para Tests por Edad y Sexo -->
|
||||
<record id="view_test_demographics_pivot" model="ir.ui.view">
|
||||
<field name="name">lims.test.demographics.pivot</field>
|
||||
<field name="model">lims.test</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Tests por Demografía">
|
||||
<field name="patient_age_range" type="row"/>
|
||||
<field name="patient_gender" type="col"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Acción para Dashboard de Distribución Demográfica -->
|
||||
<record id="action_test_demographics_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Distribución Demográfica de Tests</field>
|
||||
<field name="res_model">lims.test</field>
|
||||
<field name="view_mode">graph,pivot,tree</field>
|
||||
<field name="domain">[('state', '=', 'validated')]</field>
|
||||
<field name="context">{'search_default_this_year': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No hay tests validados
|
||||
</p>
|
||||
<p>
|
||||
Este dashboard muestra la distribución de tests por características demográficas de los pacientes.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================
|
||||
FILTROS DE BÚSQUEDA PARA DASHBOARDS
|
||||
================================================================ -->
|
||||
|
||||
<!-- Filtros para Tests -->
|
||||
<record id="view_lims_test_dashboard_search" model="ir.ui.view">
|
||||
<field name="name">lims.test.dashboard.search</field>
|
||||
<field name="model">lims.test</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<!-- Filtros de Estado -->
|
||||
<filter string="En Proceso" name="in_process" domain="[('state', '=', 'in_process')]"/>
|
||||
<filter string="Validados" name="validated" domain="[('state', '=', 'validated')]"/>
|
||||
|
||||
<!-- Filtros de Tiempo -->
|
||||
<filter string="Hoy" name="today" domain="[('create_date', '>=', datetime.datetime.now().replace(hour=0, minute=0, second=0))]"/>
|
||||
<filter string="Esta Semana" name="this_week" domain="[('create_date', '>=', (datetime.datetime.now() - datetime.timedelta(days=7)).strftime('%Y-%m-%d'))]"/>
|
||||
<filter string="Este Mes" name="this_month" domain="[('create_date', '>=', datetime.datetime.now().replace(day=1).strftime('%Y-%m-%d'))]"/>
|
||||
<filter string="Este Año" name="this_year" domain="[('create_date', '>=', datetime.datetime.now().replace(month=1, day=1).strftime('%Y-%m-%d'))]"/>
|
||||
|
||||
<!-- Agrupaciones -->
|
||||
<group expand="0" string="Agrupar Por">
|
||||
<filter string="Técnico" name="group_by_technician" context="{'group_by': 'technician_id'}"/>
|
||||
<filter string="Estado" name="group_by_state" context="{'group_by': 'state'}"/>
|
||||
<filter string="Paciente" name="group_by_patient" context="{'group_by': 'patient_id'}"/>
|
||||
<filter string="Análisis" name="group_by_product" context="{'group_by': 'product_id'}"/>
|
||||
<filter string="Fecha" name="group_by_date" context="{'group_by': 'create_date:month'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Filtros para Resultados -->
|
||||
<record id="view_lims_result_dashboard_search" model="ir.ui.view">
|
||||
<field name="name">lims.result.dashboard.search</field>
|
||||
<field name="model">lims.result</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<!-- Filtros de Rango -->
|
||||
<filter string="Fuera de Rango" name="out_of_range" domain="[('is_out_of_range', '=', True)]"/>
|
||||
<filter string="Críticos" name="critical" domain="[('is_critical', '=', True)]"/>
|
||||
|
||||
<!-- Agrupaciones -->
|
||||
<group expand="0" string="Agrupar Por">
|
||||
<filter string="Parámetro" name="group_by_parameter" context="{'group_by': 'parameter_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
|
@ -155,6 +155,51 @@
|
|||
action="action_lims_result"
|
||||
sequence="30"/>
|
||||
|
||||
<!-- Submenú de Dashboards -->
|
||||
<menuitem
|
||||
id="menu_lims_dashboards"
|
||||
name="Dashboards"
|
||||
parent="lims_menu_root"
|
||||
sequence="85"
|
||||
groups="lims_management.group_lims_admin"/>
|
||||
|
||||
<!-- Dashboards individuales -->
|
||||
<menuitem id="menu_lab_order_dashboard"
|
||||
name="Estado de Órdenes"
|
||||
parent="menu_lims_dashboards"
|
||||
action="action_lab_order_dashboard"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_technician_productivity_dashboard"
|
||||
name="Productividad de Técnicos"
|
||||
parent="menu_lims_dashboards"
|
||||
action="action_technician_productivity_dashboard"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem id="menu_sample_dashboard"
|
||||
name="Dashboard de Muestras"
|
||||
parent="menu_lims_dashboards"
|
||||
action="action_sample_dashboard"
|
||||
sequence="30"/>
|
||||
|
||||
<menuitem id="menu_out_of_range_dashboard"
|
||||
name="Parámetros Fuera de Rango"
|
||||
parent="menu_lims_dashboards"
|
||||
action="action_out_of_range_dashboard"
|
||||
sequence="40"/>
|
||||
|
||||
<menuitem id="menu_top_analysis_dashboard"
|
||||
name="Análisis Más Solicitados"
|
||||
parent="menu_lims_dashboards"
|
||||
action="action_top_analysis_dashboard"
|
||||
sequence="50"/>
|
||||
|
||||
<menuitem id="menu_test_demographics_dashboard"
|
||||
name="Distribución Demográfica"
|
||||
parent="menu_lims_dashboards"
|
||||
action="action_test_demographics_dashboard"
|
||||
sequence="60"/>
|
||||
|
||||
<!-- Submenú de Reportes -->
|
||||
<menuitem
|
||||
id="lims_menu_reports"
|
||||
|
|
Loading…
Reference in New Issue
Block a user