
- Added generated_sample_ids field to sale.order model - Override action_confirm() to intercept lab order confirmation - Implemented _generate_lab_samples() main logic method - Implemented _group_analyses_by_sample_type() for grouping - Implemented _create_sample_for_group() for sample creation - Added necessary fields to stock.lot model (doctor_id, origin, volume_ml, analysis_names) - Updated state field to include 'pending_collection' state - Added proper error handling and user notifications via message_post - Successful test with ephemeral instance restart
115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import models, fields, api
|
|
|
|
class StockLot(models.Model):
|
|
_inherit = 'stock.lot'
|
|
|
|
is_lab_sample = fields.Boolean(string='Is a Laboratory Sample')
|
|
|
|
patient_id = fields.Many2one(
|
|
'res.partner',
|
|
string='Patient',
|
|
domain="[('is_patient', '=', True)]"
|
|
)
|
|
|
|
request_id = fields.Many2one(
|
|
'sale.order',
|
|
string='Lab Request',
|
|
domain="[('is_lab_request', '=', True)]"
|
|
)
|
|
|
|
collection_date = fields.Datetime(string='Collection Date')
|
|
|
|
container_type = fields.Selection([
|
|
('serum_tube', 'Serum Tube'),
|
|
('edta_tube', 'EDTA Tube'),
|
|
('swab', 'Swab'),
|
|
('urine', 'Urine Container'),
|
|
('other', 'Other')
|
|
], string='Container Type (Legacy)', help='Deprecated field, use sample_type_product_id instead')
|
|
|
|
sample_type_product_id = fields.Many2one(
|
|
'product.template',
|
|
string='Tipo de Muestra',
|
|
domain="[('is_sample_type', '=', True)]",
|
|
help="Producto que representa el tipo de contenedor/muestra"
|
|
)
|
|
|
|
collector_id = fields.Many2one(
|
|
'res.users',
|
|
string='Collected by',
|
|
default=lambda self: self.env.user
|
|
)
|
|
|
|
doctor_id = fields.Many2one(
|
|
'res.partner',
|
|
string='Médico Referente',
|
|
domain="[('is_doctor', '=', True)]",
|
|
help="Médico que ordenó los análisis"
|
|
)
|
|
|
|
origin = fields.Char(
|
|
string='Origen',
|
|
help="Referencia a la orden de laboratorio que generó esta muestra"
|
|
)
|
|
|
|
volume_ml = fields.Float(
|
|
string='Volumen (ml)',
|
|
help="Volumen total de muestra requerido"
|
|
)
|
|
|
|
analysis_names = fields.Char(
|
|
string='Análisis',
|
|
help="Lista de análisis que se realizarán con esta muestra"
|
|
)
|
|
|
|
state = fields.Selection([
|
|
('pending_collection', 'Pendiente de Recolección'),
|
|
('collected', 'Recolectada'),
|
|
('received', 'Recibida en Laboratorio'),
|
|
('in_process', 'En Proceso'),
|
|
('analyzed', 'Analizada'),
|
|
('stored', 'Almacenada'),
|
|
('disposed', 'Desechada')
|
|
], string='Estado', default='collected', tracking=True)
|
|
|
|
def action_receive(self):
|
|
self.write({'state': 'received'})
|
|
|
|
def action_start_analysis(self):
|
|
self.write({'state': 'in_process'})
|
|
|
|
def action_complete_analysis(self):
|
|
self.write({'state': 'analyzed'})
|
|
|
|
def action_store(self):
|
|
self.write({'state': 'stored'})
|
|
|
|
def action_dispose(self):
|
|
self.write({'state': 'disposed'})
|
|
|
|
@api.onchange('sample_type_product_id')
|
|
def _onchange_sample_type_product_id(self):
|
|
"""Synchronize container_type when sample_type_product_id changes"""
|
|
if self.sample_type_product_id:
|
|
# Try to map product name to legacy container type
|
|
product_name = self.sample_type_product_id.name.lower()
|
|
if 'suero' in product_name or 'serum' in product_name:
|
|
self.container_type = 'serum_tube'
|
|
elif 'edta' in product_name:
|
|
self.container_type = 'edta_tube'
|
|
elif 'hisopo' in product_name or 'swab' in product_name:
|
|
self.container_type = 'swab'
|
|
elif 'orina' in product_name or 'urine' in product_name:
|
|
self.container_type = 'urine'
|
|
else:
|
|
self.container_type = 'other'
|
|
|
|
def get_container_name(self):
|
|
"""Get container name from product or legacy field"""
|
|
if self.sample_type_product_id:
|
|
return self.sample_type_product_id.name
|
|
elif self.container_type:
|
|
return dict(self._fields['container_type'].selection).get(self.container_type)
|
|
return 'Unknown'
|