# -*- coding: utf-8 -*- from odoo import models, fields, api from odoo.exceptions import ValidationError class LimsParameterRange(models.Model): _name = 'lims.parameter.range' _description = 'Rangos de Referencia por Parámetro' _order = 'parameter_id, gender desc, age_min' _rec_name = 'name' parameter_id = fields.Many2one( 'lims.analysis.parameter', string='Parámetro', required=True, ondelete='cascade', help='Parámetro al que aplica este rango de referencia' ) name = fields.Char( string='Descripción', compute='_compute_name', store=True, help='Descripción automática del rango' ) # Condiciones gender = fields.Selection([ ('male', 'Masculino'), ('female', 'Femenino'), ('both', 'Ambos') ], string='Género', default='both', required=True, help='Género al que aplica este rango' ) age_min = fields.Integer( string='Edad Mínima', default=0, help='Edad mínima en años (inclusive)' ) age_max = fields.Integer( string='Edad Máxima', default=150, help='Edad máxima en años (inclusive)' ) pregnant = fields.Boolean( string='Embarazada', default=False, help='Marcar si este rango es específico para mujeres embarazadas' ) # Valores de referencia normal_min = fields.Float( string='Valor Normal Mínimo', help='Límite inferior del rango normal' ) normal_max = fields.Float( string='Valor Normal Máximo', help='Límite superior del rango normal' ) critical_min = fields.Float( string='Valor Crítico Mínimo', help='Por debajo de este valor es crítico' ) critical_max = fields.Float( string='Valor Crítico Máximo', help='Por encima de este valor es crítico' ) # Información adicional interpretation = fields.Text( string='Interpretación', help='Guía de interpretación clínica para este rango' ) # Campos relacionados para facilitar búsquedas parameter_name = fields.Char( related='parameter_id.name', string='Nombre del Parámetro', store=True, readonly=True ) parameter_code = fields.Char( related='parameter_id.code', string='Código del Parámetro', store=True, readonly=True ) parameter_unit = fields.Char( related='parameter_id.unit', string='Unidad', readonly=True ) @api.depends('parameter_id', 'gender', 'age_min', 'age_max', 'pregnant') def _compute_name(self): for record in self: if not record.parameter_id: record.name = 'Nuevo rango' continue parts = [record.parameter_id.name] # Agregar género si no es ambos if record.gender != 'both': gender_name = dict(self._fields['gender'].selection).get(record.gender, '') parts.append(gender_name) # Agregar rango de edad if record.age_min == 0 and record.age_max == 150: parts.append('Todas las edades') else: parts.append(f"{record.age_min}-{record.age_max} años") # Agregar indicador de embarazo if record.pregnant: parts.append('Embarazada') record.name = ' - '.join(parts) @api.constrains('age_min', 'age_max') def _check_age_range(self): for record in self: if record.age_min < 0: raise ValidationError('La edad mínima no puede ser negativa.') if record.age_max < record.age_min: raise ValidationError('La edad máxima debe ser mayor o igual a la edad mínima.') if record.age_max > 150: raise ValidationError('La edad máxima no puede ser mayor a 150 años.') @api.constrains('normal_min', 'normal_max') def _check_normal_range(self): for record in self: if record.normal_min and record.normal_max and record.normal_min > record.normal_max: raise ValidationError('El valor normal mínimo debe ser menor o igual al valor normal máximo.') @api.constrains('critical_min', 'critical_max', 'normal_min', 'normal_max') def _check_critical_range(self): for record in self: # Validar que crítico mínimo sea menor que normal mínimo if record.critical_min and record.normal_min and record.critical_min > record.normal_min: raise ValidationError('El valor crítico mínimo debe ser menor o igual al valor normal mínimo.') # Validar que crítico máximo sea mayor que normal máximo if record.critical_max and record.normal_max and record.critical_max < record.normal_max: raise ValidationError('El valor crítico máximo debe ser mayor o igual al valor normal máximo.') @api.constrains('gender', 'pregnant') def _check_pregnant_gender(self): for record in self: if record.pregnant and record.gender == 'male': raise ValidationError('No se puede marcar "Embarazada" para rangos masculinos.') @api.constrains('parameter_id', 'gender', 'age_min', 'age_max', 'pregnant') def _check_unique_range(self): for record in self: # Buscar rangos duplicados domain = [ ('parameter_id', '=', record.parameter_id.id), ('gender', '=', record.gender), ('age_min', '=', record.age_min), ('age_max', '=', record.age_max), ('pregnant', '=', record.pregnant), ('id', '!=', record.id) ] if self.search_count(domain) > 0: raise ValidationError('Ya existe un rango con estas mismas condiciones para este parámetro.') def is_value_normal(self, value): """Verifica si un valor está dentro del rango normal""" self.ensure_one() if not value or not self.normal_min or not self.normal_max: return True return self.normal_min <= value <= self.normal_max def is_value_critical(self, value): """Verifica si un valor está en rango crítico""" self.ensure_one() if not value: return False # Crítico por debajo if self.critical_min and value < self.critical_min: return True # Crítico por encima if self.critical_max and value > self.critical_max: return True return False def get_value_status(self, value): """Devuelve el estado del valor: 'normal', 'abnormal', 'critical'""" self.ensure_one() if not value: return 'normal' if self.is_value_critical(value): return 'critical' elif not self.is_value_normal(value): return 'abnormal' else: return 'normal'