diff --git a/lims_management/__manifest__.py b/lims_management/__manifest__.py index 761494f..68fe505 100644 --- a/lims_management/__manifest__.py +++ b/lims_management/__manifest__.py @@ -36,6 +36,7 @@ 'views/lims_test_views.xml', 'views/res_config_settings_views.xml', 'views/menus.xml', + 'views/product_template_parameter_views.xml', 'views/analysis_parameter_views.xml', ], 'demo': [ diff --git a/lims_management/models/__init__.py b/lims_management/models/__init__.py index 4e5f5d0..f50d315 100644 --- a/lims_management/models/__init__.py +++ b/lims_management/models/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from . import analysis_parameter +from . import product_template_parameter from . import analysis_range from . import product from . import partner diff --git a/lims_management/models/__pycache__/__init__.cpython-312.pyc b/lims_management/models/__pycache__/__init__.cpython-312.pyc index e5d6de6..7f68a96 100644 Binary files a/lims_management/models/__pycache__/__init__.cpython-312.pyc and b/lims_management/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/lims_management/models/__pycache__/product.cpython-312.pyc b/lims_management/models/__pycache__/product.cpython-312.pyc index a2b65f2..6f3e4b1 100644 Binary files a/lims_management/models/__pycache__/product.cpython-312.pyc and b/lims_management/models/__pycache__/product.cpython-312.pyc differ diff --git a/lims_management/models/analysis_parameter.py b/lims_management/models/analysis_parameter.py index e469789..26300d4 100644 --- a/lims_management/models/analysis_parameter.py +++ b/lims_management/models/analysis_parameter.py @@ -54,12 +54,12 @@ class LimsAnalysisParameter(models.Model): help='Si está desmarcado, el parámetro no estará disponible para nuevas configuraciones' ) - # Relaciones - Se agregarán cuando se creen los modelos relacionados - # template_parameter_ids = fields.One2many( - # 'product.template.parameter', - # 'parameter_id', - # string='Análisis que usan este parámetro' - # ) + # Relaciones + template_parameter_ids = fields.One2many( + 'product.template.parameter', + 'parameter_id', + string='Análisis que usan este parámetro' + ) # range_ids = fields.One2many( # 'lims.parameter.range', @@ -67,6 +67,18 @@ class LimsAnalysisParameter(models.Model): # string='Rangos de Referencia' # ) + # Campos computados + analysis_count = fields.Integer( + string='Cantidad de Análisis', + compute='_compute_analysis_count', + store=True + ) + + @api.depends('template_parameter_ids') + def _compute_analysis_count(self): + for record in self: + record.analysis_count = len(record.template_parameter_ids) + @api.constrains('code') def _check_code_unique(self): for record in self: diff --git a/lims_management/models/product.py b/lims_management/models/product.py index 0f23f1c..a60c044 100644 --- a/lims_management/models/product.py +++ b/lims_management/models/product.py @@ -27,6 +27,13 @@ class ProductTemplate(models.Model): 'analysis_id', string="Rangos de Referencia" ) + + parameter_ids = fields.One2many( + 'product.template.parameter', + 'product_tmpl_id', + string="Parámetros del Análisis", + help="Parámetros que se medirán en este análisis" + ) is_sample_type = fields.Boolean( string="Es Tipo de Muestra", diff --git a/lims_management/models/product_template_parameter.py b/lims_management/models/product_template_parameter.py new file mode 100644 index 0000000..2646998 --- /dev/null +++ b/lims_management/models/product_template_parameter.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields, api +from odoo.exceptions import ValidationError + + +class ProductTemplateParameter(models.Model): + _name = 'product.template.parameter' + _description = 'Parámetros por Análisis' + _order = 'product_tmpl_id, sequence, id' + _rec_name = 'parameter_id' + + product_tmpl_id = fields.Many2one( + 'product.template', + string='Análisis', + required=True, + ondelete='cascade', + domain=[('is_analysis', '=', True)], + help='Análisis al que pertenece este parámetro' + ) + + parameter_id = fields.Many2one( + 'lims.analysis.parameter', + string='Parámetro', + required=True, + ondelete='restrict', + help='Parámetro de laboratorio' + ) + + sequence = fields.Integer( + string='Secuencia', + default=10, + help='Orden en que aparecerá el parámetro en los resultados' + ) + + required = fields.Boolean( + string='Obligatorio', + default=True, + help='Si está marcado, este parámetro debe tener un valor en los resultados' + ) + + instructions = fields.Text( + string='Instrucciones específicas', + help='Instrucciones especiales para este parámetro en este análisis' + ) + + # Campos relacionados para facilitar búsquedas y vistas + 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', + store=True, + readonly=True + ) + + parameter_value_type = fields.Selection( + related='parameter_id.value_type', + string='Tipo de Valor', + store=True, + readonly=True + ) + + parameter_unit = fields.Char( + related='parameter_id.unit', + string='Unidad', + readonly=True + ) + + _sql_constraints = [ + ('unique_param_per_analysis', + 'UNIQUE(product_tmpl_id, parameter_id)', + 'El parámetro ya está configurado para este análisis. Cada parámetro solo puede aparecer una vez por análisis.') + ] + + @api.constrains('sequence') + def _check_sequence(self): + for record in self: + if record.sequence < 0: + raise ValidationError('La secuencia debe ser un número positivo.') + + def name_get(self): + result = [] + for record in self: + name = f"{record.product_tmpl_id.name} - [{record.parameter_code}] {record.parameter_name}" + if record.parameter_unit: + name += f" ({record.parameter_unit})" + result.append((record.id, name)) + return result + + @api.model + def create(self, vals): + # Si no se especifica secuencia, asignar la siguiente disponible + if 'sequence' not in vals and 'product_tmpl_id' in vals: + max_sequence = self.search([ + ('product_tmpl_id', '=', vals['product_tmpl_id']) + ], order='sequence desc', limit=1).sequence + vals['sequence'] = (max_sequence or 0) + 10 + return super(ProductTemplateParameter, self).create(vals) + + def copy_data(self, default=None): + default = dict(default or {}) + # Al duplicar, incrementar la secuencia + default['sequence'] = self.sequence + 10 + return super(ProductTemplateParameter, self).copy_data(default) \ No newline at end of file diff --git a/lims_management/security/ir.model.access.csv b/lims_management/security/ir.model.access.csv index 41f33a9..cbd70a9 100644 --- a/lims_management/security/ir.model.access.csv +++ b/lims_management/security/ir.model.access.csv @@ -1,6 +1,8 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_lims_analysis_parameter_user,lims.analysis.parameter.user,model_lims_analysis_parameter,base.group_user,1,0,0,0 access_lims_analysis_parameter_manager,lims.analysis.parameter.manager,model_lims_analysis_parameter,group_lims_admin,1,1,1,1 +access_product_template_parameter_user,product.template.parameter.user,model_product_template_parameter,base.group_user,1,0,0,0 +access_product_template_parameter_manager,product.template.parameter.manager,model_product_template_parameter,group_lims_admin,1,1,1,1 access_lims_analysis_range_user,lims.analysis.range.user,model_lims_analysis_range,base.group_user,1,1,1,1 access_sale_order_receptionist,sale.order.receptionist,sale.model_sale_order,group_lims_receptionist,1,1,1,0 access_stock_lot_user,stock.lot.user,stock.model_stock_lot,base.group_user,1,1,1,1 diff --git a/lims_management/views/analysis_parameter_views.xml b/lims_management/views/analysis_parameter_views.xml index 3eb8f09..defa737 100644 --- a/lims_management/views/analysis_parameter_views.xml +++ b/lims_management/views/analysis_parameter_views.xml @@ -8,6 +8,13 @@
+