fix(#67): Simplificar implementación de campo selection
- Mantener campo value_selection como Char con validación - Remover campos y métodos no utilizados (value_selection_field, _get_selection_values) - Mostrar opciones disponibles debajo del campo para guiar al usuario - La validación se mantiene en el constraint para asegurar valores válidos
This commit is contained in:
parent
22082965d0
commit
c959878a23
|
@ -92,17 +92,10 @@ class LimsResult(models.Model):
|
||||||
string='Valor de Texto'
|
string='Valor de Texto'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Keep as Char but add domain validation
|
|
||||||
value_selection = fields.Char(
|
value_selection = fields.Char(
|
||||||
string='Valor de Selección'
|
string='Valor de Selección'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add Selection field with dynamic options
|
|
||||||
value_selection_field = fields.Selection(
|
|
||||||
selection='_get_selection_options',
|
|
||||||
string='Valor de Selección'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Campo para mostrar las opciones disponibles
|
# Campo para mostrar las opciones disponibles
|
||||||
selection_options_display = fields.Char(
|
selection_options_display = fields.Char(
|
||||||
string='Opciones disponibles',
|
string='Opciones disponibles',
|
||||||
|
@ -321,7 +314,6 @@ class LimsResult(models.Model):
|
||||||
self.value_numeric = False
|
self.value_numeric = False
|
||||||
self.value_text = False
|
self.value_text = False
|
||||||
self.value_selection = False
|
self.value_selection = False
|
||||||
self.value_selection_field = False
|
|
||||||
self.value_boolean = False
|
self.value_boolean = False
|
||||||
|
|
||||||
# Si es selección, obtener las opciones
|
# Si es selección, obtener las opciones
|
||||||
|
@ -329,19 +321,6 @@ class LimsResult(models.Model):
|
||||||
# Esto se usará en las vistas para mostrar las opciones dinámicamente
|
# Esto se usará en las vistas para mostrar las opciones dinámicamente
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@api.onchange('value_selection_field')
|
|
||||||
def _onchange_value_selection_field(self):
|
|
||||||
"""Sincroniza el campo de selección con el campo char."""
|
|
||||||
if self.parameter_value_type == 'selection':
|
|
||||||
self.value_selection = self.value_selection_field
|
|
||||||
|
|
||||||
def _get_selection_options(self):
|
|
||||||
"""Retorna las opciones de selección basadas en el parámetro."""
|
|
||||||
options = []
|
|
||||||
if self.parameter_id and self.parameter_value_type == 'selection':
|
|
||||||
param_options = self.parameter_id.get_selection_list()
|
|
||||||
options = [(opt, opt) for opt in param_options]
|
|
||||||
return options or [('', 'Sin opciones')]
|
|
||||||
|
|
||||||
@api.depends('parameter_id', 'parameter_id.selection_values')
|
@api.depends('parameter_id', 'parameter_id.selection_values')
|
||||||
def _compute_selection_options_display(self):
|
def _compute_selection_options_display(self):
|
||||||
|
|
|
@ -88,16 +88,18 @@
|
||||||
<field name="value_text"
|
<field name="value_text"
|
||||||
invisible="parameter_value_type != 'text'"
|
invisible="parameter_value_type != 'text'"
|
||||||
class="oe_edit_only"/>
|
class="oe_edit_only"/>
|
||||||
|
<field name="parameter_id" invisible="1" force_save="1"/>
|
||||||
<field name="value_selection"
|
<field name="value_selection"
|
||||||
invisible="parameter_value_type != 'selection'"
|
invisible="parameter_value_type != 'selection'"
|
||||||
placeholder="Escriba para buscar..."
|
placeholder="Seleccione una opción"
|
||||||
class="oe_edit_only"/>
|
options="{'no_create': True, 'no_edit': True}"/>
|
||||||
<field name="selection_options_display"
|
<field name="selection_options_display"
|
||||||
invisible="parameter_value_type != 'selection'"
|
invisible="parameter_value_type != 'selection'"
|
||||||
readonly="1"
|
readonly="1"
|
||||||
nolabel="1"
|
nolabel="1"
|
||||||
class="text-muted small"
|
class="text-muted small"
|
||||||
style="font-size: 0.85em; color: #6c757d;"/>
|
widget="text"
|
||||||
|
style="font-size: 0.85em; color: #6c757d; margin-top: -5px;"/>
|
||||||
<field name="value_boolean"
|
<field name="value_boolean"
|
||||||
invisible="parameter_value_type != 'boolean'"
|
invisible="parameter_value_type != 'boolean'"
|
||||||
widget="boolean_toggle"
|
widget="boolean_toggle"
|
||||||
|
|
101
test/check_selection_issue.py
Normal file
101
test/check_selection_issue.py
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Script para diagnosticar por qué el selection muestra "Sin Opciones"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import odoo
|
||||||
|
import logging
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def check_selection_issue(env):
|
||||||
|
"""Verificar el problema con las opciones de selección"""
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print("DIAGNÓSTICO DE PROBLEMA CON SELECTION")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
# Buscar el resultado específico mencionado por el usuario
|
||||||
|
result = env['lims.result'].browse(43)
|
||||||
|
if not result.exists():
|
||||||
|
print("No se encontró el resultado con ID 43")
|
||||||
|
# Buscar cualquier resultado de tipo selection
|
||||||
|
result = env['lims.result'].search([
|
||||||
|
('parameter_value_type', '=', 'selection')
|
||||||
|
], limit=1)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
print(f"\nResultado encontrado:")
|
||||||
|
print(f" - ID: {result.id}")
|
||||||
|
print(f" - Parámetro: {result.parameter_id.name}")
|
||||||
|
print(f" - Tipo de valor: {result.parameter_value_type}")
|
||||||
|
print(f" - Valor actual: '{result.value_selection}'")
|
||||||
|
|
||||||
|
# Verificar el parámetro
|
||||||
|
param = result.parameter_id
|
||||||
|
print(f"\nInformación del parámetro:")
|
||||||
|
print(f" - ID: {param.id}")
|
||||||
|
print(f" - Nombre: {param.name}")
|
||||||
|
print(f" - Tipo de valor: {param.value_type}")
|
||||||
|
print(f" - Valores de selección (campo): '{param.selection_values}'")
|
||||||
|
|
||||||
|
# Probar get_selection_list()
|
||||||
|
print(f"\nProbando get_selection_list():")
|
||||||
|
selection_list = param.get_selection_list()
|
||||||
|
print(f" - Resultado: {selection_list}")
|
||||||
|
print(f" - Tipo: {type(selection_list)}")
|
||||||
|
print(f" - Longitud: {len(selection_list) if selection_list else 0}")
|
||||||
|
|
||||||
|
# Probar _get_selection_options() en el resultado
|
||||||
|
print(f"\nProbando _get_selection_options() en el resultado:")
|
||||||
|
options = result._get_selection_options()
|
||||||
|
print(f" - Opciones: {options}")
|
||||||
|
|
||||||
|
# Verificar si el método está siendo llamado correctamente
|
||||||
|
print(f"\nVerificando contexto:")
|
||||||
|
print(f" - result.parameter_id existe: {bool(result.parameter_id)}")
|
||||||
|
print(f" - result.parameter_value_type: '{result.parameter_value_type}'")
|
||||||
|
print(f" - Condición completa: {result.parameter_id and result.parameter_value_type == 'selection'}")
|
||||||
|
|
||||||
|
# Buscar todos los parámetros de tipo selection
|
||||||
|
print(f"\n\nBuscando todos los parámetros de tipo selection:")
|
||||||
|
selection_params = env['lims.analysis.parameter'].search([
|
||||||
|
('value_type', '=', 'selection')
|
||||||
|
])
|
||||||
|
|
||||||
|
for sp in selection_params:
|
||||||
|
print(f"\n Parámetro: {sp.name}")
|
||||||
|
print(f" - selection_values: '{sp.selection_values}'")
|
||||||
|
print(f" - get_selection_list(): {sp.get_selection_list()}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("No se encontraron resultados de tipo selection")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Configuración
|
||||||
|
db_name = 'lims_demo'
|
||||||
|
|
||||||
|
# Conectar a Odoo
|
||||||
|
odoo.tools.config.parse_config(['--database', db_name])
|
||||||
|
|
||||||
|
# Obtener el registro de la base de datos
|
||||||
|
registry = odoo.registry(db_name)
|
||||||
|
|
||||||
|
# Crear cursor y environment
|
||||||
|
with registry.cursor() as cr:
|
||||||
|
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Verificar el problema
|
||||||
|
check_selection_issue(env)
|
||||||
|
|
||||||
|
# No guardar cambios
|
||||||
|
cr.rollback()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
cr.rollback()
|
||||||
|
print(f"\n❌ Error durante el diagnóstico: {str(e)}")
|
||||||
|
_logger.error(f"Error: {str(e)}", exc_info=True)
|
132
test/create_test_selection_data.py
Normal file
132
test/create_test_selection_data.py
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Script para crear datos de prueba con parámetros de tipo selection
|
||||||
|
"""
|
||||||
|
|
||||||
|
import odoo
|
||||||
|
import logging
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_selection_data(env):
|
||||||
|
"""Crear datos de prueba para verificar el widget selection"""
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print("CREANDO DATOS DE PRUEBA PARA SELECTION")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
# Buscar o crear paciente
|
||||||
|
patient = env['res.partner'].search([('is_patient', '=', True)], limit=1)
|
||||||
|
if not patient:
|
||||||
|
patient = env['res.partner'].create({
|
||||||
|
'name': 'Paciente Test Selection Widget',
|
||||||
|
'is_patient': True,
|
||||||
|
})
|
||||||
|
print(f"Paciente creado: {patient.name}")
|
||||||
|
|
||||||
|
# Buscar análisis con parámetros tipo selection
|
||||||
|
# Por ejemplo: Prueba de Embarazo
|
||||||
|
product = env['product.template'].search([
|
||||||
|
('is_analysis', '=', True),
|
||||||
|
('name', 'ilike', 'embarazo')
|
||||||
|
], limit=1)
|
||||||
|
|
||||||
|
if product:
|
||||||
|
print(f"\nAnálisis encontrado: {product.name}")
|
||||||
|
|
||||||
|
# Verificar parámetros asociados
|
||||||
|
print("\nParámetros del análisis:")
|
||||||
|
for param_link in product.parameter_ids:
|
||||||
|
param = param_link.parameter_id
|
||||||
|
print(f" - {param.name} (Tipo: {param.value_type})")
|
||||||
|
if param.value_type == 'selection':
|
||||||
|
print(f" Valores: '{param.selection_values}'")
|
||||||
|
print(f" Lista: {param.get_selection_list()}")
|
||||||
|
else:
|
||||||
|
print("No se encontró análisis de Prueba de Embarazo")
|
||||||
|
|
||||||
|
# Buscar cualquier análisis con parámetros selection
|
||||||
|
sql = """
|
||||||
|
SELECT DISTINCT pt.id, pt.name
|
||||||
|
FROM product_template pt
|
||||||
|
JOIN product_template_parameter ptp ON ptp.product_template_id = pt.id
|
||||||
|
JOIN lims_analysis_parameter lap ON lap.id = ptp.parameter_id
|
||||||
|
WHERE pt.is_analysis = true
|
||||||
|
AND lap.value_type = 'selection'
|
||||||
|
LIMIT 5
|
||||||
|
"""
|
||||||
|
env.cr.execute(sql)
|
||||||
|
results = env.cr.fetchall()
|
||||||
|
|
||||||
|
if results:
|
||||||
|
print("\nAnálisis con parámetros selection encontrados:")
|
||||||
|
for prod_id, prod_name in results:
|
||||||
|
print(f" - {prod_name} (ID: {prod_id})")
|
||||||
|
product = env['product.template'].browse(prod_id)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("No se encontraron análisis con parámetros selection")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Crear orden
|
||||||
|
order = env['sale.order'].create({
|
||||||
|
'partner_id': patient.id,
|
||||||
|
'is_lab_request': True,
|
||||||
|
'order_line': [(0, 0, {
|
||||||
|
'product_id': product.product_variant_id.id,
|
||||||
|
'product_uom_qty': 1,
|
||||||
|
})]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Confirmar orden
|
||||||
|
order.action_confirm()
|
||||||
|
print(f"\nOrden creada: {order.name}")
|
||||||
|
|
||||||
|
# Obtener la prueba generada
|
||||||
|
if order.lab_test_ids:
|
||||||
|
test = order.lab_test_ids[0]
|
||||||
|
print(f"Prueba generada: {test.name} (ID: {test.id})")
|
||||||
|
|
||||||
|
# Generar resultados si no existen
|
||||||
|
if not test.result_ids:
|
||||||
|
test.sudo()._generate_test_results()
|
||||||
|
|
||||||
|
print(f"\nResultados generados:")
|
||||||
|
for result in test.result_ids:
|
||||||
|
print(f" - {result.parameter_id.name} (Tipo: {result.parameter_value_type})")
|
||||||
|
if result.parameter_value_type == 'selection':
|
||||||
|
print(f" ID del resultado: {result.id}")
|
||||||
|
print(f" Valores en parámetro: '{result.parameter_id.selection_values}'")
|
||||||
|
print(f" get_selection_list(): {result.parameter_id.get_selection_list()}")
|
||||||
|
print(f" _get_selection_options(): {result._get_selection_options()}")
|
||||||
|
print(f" selection_options_display: '{result.selection_options_display}'")
|
||||||
|
|
||||||
|
# Guardar cambios
|
||||||
|
env.cr.commit()
|
||||||
|
print("\n✅ Datos de prueba creados exitosamente")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Configuración
|
||||||
|
db_name = 'lims_demo'
|
||||||
|
|
||||||
|
# Conectar a Odoo
|
||||||
|
odoo.tools.config.parse_config(['--database', db_name])
|
||||||
|
|
||||||
|
# Obtener el registro de la base de datos
|
||||||
|
registry = odoo.registry(db_name)
|
||||||
|
|
||||||
|
# Crear cursor y environment
|
||||||
|
with registry.cursor() as cr:
|
||||||
|
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Crear datos de prueba
|
||||||
|
create_test_selection_data(env)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
cr.rollback()
|
||||||
|
print(f"\n❌ Error: {str(e)}")
|
||||||
|
_logger.error(f"Error: {str(e)}", exc_info=True)
|
100
test/verify_selection_fix.py
Normal file
100
test/verify_selection_fix.py
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import odoo
|
||||||
|
import json
|
||||||
|
|
||||||
|
def verify_selection_fix(cr):
|
||||||
|
"""Verify that the selection widget fix is working correctly."""
|
||||||
|
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
||||||
|
|
||||||
|
print("="*80)
|
||||||
|
print("VERIFYING SELECTION WIDGET FIX")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
# 1. Find a parameter with selection type
|
||||||
|
param = env['lims.analysis.parameter'].search([
|
||||||
|
('value_type', '=', 'selection'),
|
||||||
|
('selection_values', '!=', False)
|
||||||
|
], limit=1)
|
||||||
|
|
||||||
|
if not param:
|
||||||
|
print("ERROR: No selection parameters found!")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\nUsing parameter: {param.name} (ID: {param.id})")
|
||||||
|
print(f"Selection values: {param.selection_values}")
|
||||||
|
print(f"get_selection_list(): {param.get_selection_list()}")
|
||||||
|
|
||||||
|
# 2. Create a test and result
|
||||||
|
print("\n\nCreating test data...")
|
||||||
|
|
||||||
|
# Get a patient
|
||||||
|
patient = env['res.partner'].search([('is_patient', '=', True)], limit=1)
|
||||||
|
if not patient:
|
||||||
|
print("ERROR: No patient found!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create a test
|
||||||
|
test = env['lims.test'].create({
|
||||||
|
'name': 'Test Selection Widget',
|
||||||
|
'patient_id': patient.id,
|
||||||
|
'analysis_id': param.analysis_id.id if param.analysis_id else False,
|
||||||
|
})
|
||||||
|
print(f"Created test: {test.name} (ID: {test.id})")
|
||||||
|
|
||||||
|
# Create a result
|
||||||
|
result = env['lims.result'].create({
|
||||||
|
'test_id': test.id,
|
||||||
|
'parameter_id': param.id,
|
||||||
|
})
|
||||||
|
print(f"Created result: ID {result.id}")
|
||||||
|
|
||||||
|
# 3. Check the selection field
|
||||||
|
print("\n\nChecking selection field...")
|
||||||
|
print(f"Parameter value type: {result.parameter_value_type}")
|
||||||
|
print(f"Selection options display: {result.selection_options_display}")
|
||||||
|
|
||||||
|
# Get selection options through the method
|
||||||
|
options = result._get_selection_options()
|
||||||
|
print(f"\n_get_selection_options() returns: {options}")
|
||||||
|
|
||||||
|
# 4. Test setting a value
|
||||||
|
if options and len(options) > 1: # Skip the empty option
|
||||||
|
test_value = options[1][0] # Get the key of the first real option
|
||||||
|
print(f"\nTesting with value: '{test_value}'")
|
||||||
|
|
||||||
|
result.value_selection_field = test_value
|
||||||
|
print(f"Set value_selection_field = '{test_value}'")
|
||||||
|
print(f"After onchange, value_selection = '{result.value_selection}'")
|
||||||
|
print(f"Value display: '{result.value_display}'")
|
||||||
|
|
||||||
|
# Save and check
|
||||||
|
cr.commit()
|
||||||
|
|
||||||
|
# Re-read
|
||||||
|
result = env['lims.result'].browse(result.id)
|
||||||
|
print(f"\nAfter save and re-read:")
|
||||||
|
print(f" value_selection_field: '{result.value_selection_field}'")
|
||||||
|
print(f" value_selection: '{result.value_selection}'")
|
||||||
|
print(f" value_display: '{result.value_display}'")
|
||||||
|
|
||||||
|
# 5. Check field definition
|
||||||
|
print("\n\nChecking field definitions...")
|
||||||
|
Result = env['lims.result']
|
||||||
|
|
||||||
|
if 'value_selection_field' in Result._fields:
|
||||||
|
field = Result._fields['value_selection_field']
|
||||||
|
print(f"value_selection_field:")
|
||||||
|
print(f" Type: {field.type}")
|
||||||
|
print(f" String: {field.string}")
|
||||||
|
print(f" Selection: {field.selection if hasattr(field, 'selection') else 'N/A'}")
|
||||||
|
else:
|
||||||
|
print("ERROR: value_selection_field not found in model!")
|
||||||
|
|
||||||
|
print("\n" + "="*80)
|
||||||
|
print("VERIFICATION COMPLETE")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
db_name = 'lims_demo'
|
||||||
|
registry = odoo.registry(db_name)
|
||||||
|
with registry.cursor() as cr:
|
||||||
|
verify_selection_fix(cr)
|
Loading…
Reference in New Issue
Block a user