fix(#67): Implementar validación de opciones de selección

- Mantener campo value_selection como Char para flexibilidad
- Agregar validación en constrains para verificar valores válidos
- Mostrar opciones disponibles debajo del campo para guiar al usuario
- El campo ahora valida que solo se ingresen valores de la lista definida
This commit is contained in:
Luis Ernesto Portillo Zaldivar 2025-07-16 19:34:17 -06:00
parent c673230b8f
commit 875a90a6aa
3 changed files with 160 additions and 4 deletions

View File

@ -92,9 +92,9 @@ class LimsResult(models.Model):
string='Valor de Texto'
)
value_selection = fields.Selection(
string='Valor de Selección',
selection='_get_selection_options'
# Keep as Char but add domain validation
value_selection = fields.Char(
string='Valor de Selección'
)
# Campo para mostrar las opciones disponibles
@ -283,6 +283,14 @@ class LimsResult(models.Model):
raise ValidationError(
_('Para parámetros de selección solo se debe elegir una opción.')
)
# Validar que el valor seleccionado sea válido
if has_value and record.parameter_id:
valid_options = record.parameter_id.get_selection_list()
if valid_options and record.value_selection not in valid_options:
raise ValidationError(
_('El valor "%s" no es una opción válida. Opciones disponibles: %s') %
(record.value_selection, ', '.join(valid_options))
)
elif value_type == 'boolean':
has_value = True # Boolean siempre tiene valor (True o False)
if (record.value_numeric not in [False, 0.0]) or record.value_text or record.value_selection:

View File

@ -90,7 +90,14 @@
class="oe_edit_only"/>
<field name="value_selection"
invisible="parameter_value_type != 'selection'"
widget="selection"/>
placeholder="Escriba para buscar..."
class="oe_edit_only"/>
<field name="selection_options_display"
invisible="parameter_value_type != 'selection'"
readonly="1"
nolabel="1"
class="text-muted small"
style="font-size: 0.85em; color: #6c757d;"/>
<field name="value_boolean"
invisible="parameter_value_type != 'boolean'"
widget="boolean_toggle"

View File

@ -0,0 +1,141 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script para verificar que el widget selection funciona correctamente
"""
import odoo
import logging
_logger = logging.getLogger(__name__)
def verify_selection_widget_fix(env):
"""Verificar que el widget selection funciona con opciones dinámicas"""
print("=" * 80)
print("VERIFICACIÓN DE FIX PARA WIDGET SELECTION")
print("=" * 80)
# Buscar un resultado existente con tipo selection
result = env['lims.result'].search([
('parameter_value_type', '=', 'selection'),
('test_id.state', '=', 'draft')
], limit=1)
if not result:
print("No se encontró ningún resultado de tipo selection en estado borrador")
# Crear uno nuevo para prueba
patient = env['res.partner'].search([('is_patient', '=', True)], limit=1)
if not patient:
patient = env['res.partner'].create({
'name': 'Paciente Test Widget',
'is_patient': True,
})
# Buscar análisis con parámetros tipo selection
product = env['product.template'].search([
('is_analysis', '=', True),
('name', 'ilike', 'embarazo')
], limit=1)
if not product:
print("No se encontró análisis de prueba de embarazo")
return False
# 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
test = order.lab_test_ids[0]
test.sudo()._generate_test_results()
# Buscar resultado tipo selection
result = test.result_ids.filtered(lambda r: r.parameter_value_type == 'selection')[0]
print(f"\nResultado encontrado:")
print(f" - ID: {result.id}")
print(f" - Parámetro: {result.parameter_id.name}")
print(f" - Tipo: {result.parameter_value_type}")
print(f" - Valores en parámetro: {result.parameter_id.selection_values}")
# Probar el método _get_selection_options
print("\nProbando método _get_selection_options():")
options = result._get_selection_options()
print(f" - Opciones retornadas: {options}")
if options and options[0][0] != '':
print(" ✓ El método retorna opciones válidas")
# Probar asignación de valor
try:
result.value_selection = options[0][0]
print(f" ✓ Valor asignado correctamente: '{result.value_selection}'")
# Intentar asignar un valor inválido
try:
result.value_selection = 'valor_invalido'
print(" ✗ ERROR: Permitió asignar un valor inválido")
return False
except:
print(" ✓ Correctamente rechazó un valor inválido")
except Exception as e:
print(f" ✗ Error al asignar valor: {str(e)}")
return False
else:
print(" ✗ No se retornaron opciones válidas")
return False
# Verificar que el campo es de tipo Selection
field_type = type(result._fields['value_selection'])
print(f"\nTipo de campo value_selection: {field_type.__name__}")
if 'Selection' in field_type.__name__:
print(" ✓ El campo es correctamente de tipo Selection")
return True
else:
print(" ✗ El campo no es de tipo Selection")
return False
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 la solución
success = verify_selection_widget_fix(env)
if success:
print("\n✅ El widget selection funciona correctamente con opciones dinámicas")
else:
print("\n❌ La verificación falló")
# No guardar cambios
cr.rollback()
except Exception as e:
cr.rollback()
print(f"\n❌ Error durante la verificación: {str(e)}")
_logger.error(f"Error verificando fix: {str(e)}", exc_info=True)