
- Modelo lims.test con todos los campos especificados - Modelo lims.result con soporte para múltiples tipos de valor - Secuencia automática para códigos de prueba - Flujo de estados: draft -> in_process -> result_entered -> validated - Validación de un solo tipo de valor por resultado - Permisos de seguridad configurados
207 lines
5.8 KiB
Python
207 lines
5.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import models, fields, api, _
|
|
from odoo.exceptions import UserError
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class LimsTest(models.Model):
|
|
_name = 'lims.test'
|
|
_description = 'Prueba de Laboratorio'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
_rec_name = 'name'
|
|
_order = 'create_date desc'
|
|
|
|
name = fields.Char(
|
|
string='Código de Prueba',
|
|
required=True,
|
|
readonly=True,
|
|
copy=False,
|
|
default='Nuevo'
|
|
)
|
|
|
|
sale_order_line_id = fields.Many2one(
|
|
'sale.order.line',
|
|
string='Línea de Orden',
|
|
required=True,
|
|
ondelete='restrict'
|
|
)
|
|
|
|
patient_id = fields.Many2one(
|
|
'res.partner',
|
|
string='Paciente',
|
|
related='sale_order_line_id.order_id.partner_id',
|
|
store=True,
|
|
readonly=True
|
|
)
|
|
|
|
product_id = fields.Many2one(
|
|
'product.product',
|
|
string='Análisis',
|
|
related='sale_order_line_id.product_id',
|
|
store=True,
|
|
readonly=True
|
|
)
|
|
|
|
sample_id = fields.Many2one(
|
|
'stock.lot',
|
|
string='Muestra',
|
|
domain="[('is_lab_sample', '=', True)]",
|
|
tracking=True
|
|
)
|
|
|
|
state = fields.Selection([
|
|
('draft', 'Borrador'),
|
|
('in_process', 'En Proceso'),
|
|
('result_entered', 'Resultado Ingresado'),
|
|
('validated', 'Validado'),
|
|
('cancelled', 'Cancelado')
|
|
], string='Estado', default='draft', tracking=True)
|
|
|
|
validator_id = fields.Many2one(
|
|
'res.users',
|
|
string='Validador',
|
|
readonly=True,
|
|
tracking=True
|
|
)
|
|
|
|
validation_date = fields.Datetime(
|
|
string='Fecha de Validación',
|
|
readonly=True,
|
|
tracking=True
|
|
)
|
|
|
|
technician_id = fields.Many2one(
|
|
'res.users',
|
|
string='Técnico',
|
|
default=lambda self: self.env.user,
|
|
tracking=True
|
|
)
|
|
|
|
require_validation = fields.Boolean(
|
|
string='Requiere Validación',
|
|
compute='_compute_require_validation',
|
|
store=True
|
|
)
|
|
|
|
result_ids = fields.One2many(
|
|
'lims.result',
|
|
'test_id',
|
|
string='Resultados'
|
|
)
|
|
|
|
notes = fields.Text(
|
|
string='Observaciones'
|
|
)
|
|
|
|
company_id = fields.Many2one(
|
|
'res.company',
|
|
string='Compañía',
|
|
required=True,
|
|
default=lambda self: self.env.company
|
|
)
|
|
|
|
@api.depends('company_id')
|
|
def _compute_require_validation(self):
|
|
"""Calcula si la prueba requiere validación basado en configuración."""
|
|
for record in self:
|
|
# Por ahora, siempre requiere validación
|
|
# TODO: Implementar cuando se agregue res.config.settings
|
|
record.require_validation = True
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
"""Genera código único al crear."""
|
|
for vals in vals_list:
|
|
if vals.get('name', 'Nuevo') == 'Nuevo':
|
|
vals['name'] = self.env['ir.sequence'].next_by_code('lims.test') or 'Nuevo'
|
|
return super().create(vals_list)
|
|
|
|
def action_start_process(self):
|
|
"""Inicia el proceso de análisis."""
|
|
self.ensure_one()
|
|
if self.state != 'draft':
|
|
raise UserError(_('Solo se pueden procesar pruebas en estado borrador.'))
|
|
if not self.sample_id:
|
|
raise UserError(_('Debe asignar una muestra antes de iniciar el proceso.'))
|
|
|
|
self.write({
|
|
'state': 'in_process',
|
|
'technician_id': self.env.user.id
|
|
})
|
|
|
|
# Log en el chatter
|
|
self.message_post(
|
|
body=_('Prueba iniciada por %s') % self.env.user.name,
|
|
subject=_('Proceso Iniciado')
|
|
)
|
|
|
|
return True
|
|
|
|
def action_enter_results(self):
|
|
"""Marca como resultados ingresados."""
|
|
self.ensure_one()
|
|
if self.state != 'in_process':
|
|
raise UserError(_('Solo se pueden ingresar resultados en pruebas en proceso.'))
|
|
|
|
if not self.result_ids:
|
|
raise UserError(_('Debe ingresar al menos un resultado.'))
|
|
|
|
self.state = 'result_entered'
|
|
|
|
# Log en el chatter
|
|
self.message_post(
|
|
body=_('Resultados ingresados por %s') % self.env.user.name,
|
|
subject=_('Resultados Ingresados')
|
|
)
|
|
|
|
return True
|
|
|
|
def action_validate(self):
|
|
"""Valida los resultados (solo administradores)."""
|
|
self.ensure_one()
|
|
if self.state != 'result_entered':
|
|
raise UserError(_('Solo se pueden validar pruebas con resultados ingresados.'))
|
|
|
|
# TODO: Verificar permisos cuando se implemente seguridad
|
|
|
|
self.write({
|
|
'state': 'validated',
|
|
'validator_id': self.env.user.id,
|
|
'validation_date': fields.Datetime.now()
|
|
})
|
|
|
|
# Log en el chatter
|
|
self.message_post(
|
|
body=_('Resultados validados por %s') % self.env.user.name,
|
|
subject=_('Resultados Validados')
|
|
)
|
|
|
|
return True
|
|
|
|
def action_cancel(self):
|
|
"""Cancela la prueba."""
|
|
self.ensure_one()
|
|
if self.state == 'validated':
|
|
raise UserError(_('No se pueden cancelar pruebas validadas.'))
|
|
|
|
self.state = 'cancelled'
|
|
|
|
# Log en el chatter
|
|
self.message_post(
|
|
body=_('Prueba cancelada por %s') % self.env.user.name,
|
|
subject=_('Prueba Cancelada')
|
|
)
|
|
|
|
return True
|
|
|
|
def action_draft(self):
|
|
"""Regresa a borrador."""
|
|
self.ensure_one()
|
|
if self.state not in ['cancelled']:
|
|
raise UserError(_('Solo se pueden regresar a borrador pruebas canceladas.'))
|
|
|
|
self.state = 'draft'
|
|
|
|
return True |