clinical_laboratory/lims_management/wizards/sample_rejection_wizard.py
Luis Ernesto Portillo Zaldivar 87640b48e0 feat(#58): Implementar flujo de rechazo de muestras
- Agregar estado 'rejected' al ciclo de vida de la muestra
- Crear modelo lims.rejection.reason para gestionar motivos de rechazo
- Agregar campos de rechazo en stock.lot (reason, notes, rejected_by, date)
- Crear wizard para proceso de rechazo con validaciones
- Implementar acción de rechazo con notificaciones
- Crear vistas para muestras rechazadas con filtros y búsquedas
- Agregar 10 motivos de rechazo predefinidos (hemolizada, coagulada, etc.)
- Incluir permisos de seguridad para los nuevos modelos
- Agregar menús para gestión de rechazos y muestras rechazadas
- Corregir compatibilidad con Odoo 18 en vistas existentes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-15 22:49:43 -06:00

94 lines
3.1 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.exceptions import ValidationError
class SampleRejectionWizard(models.TransientModel):
_name = 'lims.sample.rejection.wizard'
_description = 'Wizard para Rechazo de Muestras'
sample_id = fields.Many2one(
'stock.lot',
string='Muestra',
required=True,
readonly=True,
domain=[('is_lab_sample', '=', True)]
)
rejection_reason_id = fields.Many2one(
'lims.rejection.reason',
string='Motivo de Rechazo',
required=True,
domain=[('active', '=', True)]
)
rejection_notes = fields.Text(
string='Notas Adicionales',
help="Información adicional sobre el rechazo"
)
requires_new_sample = fields.Boolean(
string='Requiere Nueva Muestra',
related='rejection_reason_id.requires_new_sample',
readonly=True
)
create_new_sample = fields.Boolean(
string='Crear Nueva Solicitud',
help="Crear automáticamente una nueva solicitud de muestra"
)
@api.model
def default_get(self, fields):
res = super(SampleRejectionWizard, self).default_get(fields)
active_id = self.env.context.get('active_id')
if active_id:
sample = self.env['stock.lot'].browse(active_id)
res['sample_id'] = sample.id
return res
@api.onchange('rejection_reason_id')
def _onchange_rejection_reason_id(self):
if self.rejection_reason_id and self.rejection_reason_id.requires_new_sample:
self.create_new_sample = True
def action_reject_sample(self):
"""Reject the sample with the provided reason"""
self.ensure_one()
if not self.sample_id:
raise ValidationError('No se ha seleccionado ninguna muestra')
if self.sample_id.state == 'completed':
raise ValidationError('No se puede rechazar una muestra ya completada')
# Update sample with rejection information
self.sample_id.write({
'rejection_reason_id': self.rejection_reason_id.id,
'rejection_notes': self.rejection_notes
})
# Call the rejection method on the sample
self.sample_id.action_reject()
# Create new sample request if needed
if self.create_new_sample and self.sample_id.request_id:
self._create_new_sample_request()
return {'type': 'ir.actions.act_window_close'}
def _create_new_sample_request(self):
"""Create a new sample request based on the rejected one"""
original_order = self.sample_id.request_id
# Create a note in the original order
original_order.message_post(
body=f'Se solicitará una nueva muestra debido al rechazo. Motivo: {self.rejection_reason_id.name}',
subject='Nueva Muestra Solicitada',
message_type='notification'
)
# Here you could implement logic to create a new sale.order
# or a specific request for a new sample
# For now, we'll just add a note
return True