
- Agregar estado 'cancelled' a stock.lot para muestras - Implementar método action_cancel() en stock.lot - Override action_cancel() en sale.order para: * Cancelar muestras en estados: pending_collection, collected, received, in_process * Cancelar pruebas asociadas que no estén validadas * Registrar mensajes en el chatter de cada elemento cancelado * Mostrar resumen de elementos cancelados en la orden - Agregar tests unitarios completos para verificar: * Cancelación correcta de muestras y pruebas * No cancelación de elementos en estados finales * Generación de mensajes en chatter * Órdenes normales no afectadas La funcionalidad asegura que no queden muestras o pruebas "huérfanas" cuando se cancela una orden de laboratorio. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
149 lines
5.6 KiB
Python
149 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Script para probar la funcionalidad de cancelación en cascada
|
|
"""
|
|
|
|
import odoo
|
|
import traceback
|
|
from datetime import datetime
|
|
|
|
|
|
def test_cancel_cascade(cr):
|
|
"""Probar la cancelación en cascada de órdenes"""
|
|
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
|
|
|
print("🧪 Probando cancelación en cascada de órdenes de laboratorio\n")
|
|
|
|
try:
|
|
# Buscar un paciente y doctor de prueba
|
|
patient = env['res.partner'].search([('is_patient', '=', True)], limit=1)
|
|
doctor = env['res.partner'].search([('is_doctor', '=', True)], limit=1)
|
|
|
|
if not patient or not doctor:
|
|
print("❌ No se encontraron pacientes o doctores de prueba")
|
|
return
|
|
|
|
# Buscar un análisis
|
|
analysis = env['product.product'].search([
|
|
('is_analysis', '=', True),
|
|
('required_sample_type_id', '!=', False)
|
|
], limit=1)
|
|
|
|
if not analysis:
|
|
print("❌ No se encontró un análisis con tipo de muestra requerido")
|
|
return
|
|
|
|
print(f"📋 Creando orden de laboratorio de prueba...")
|
|
print(f" Paciente: {patient.name}")
|
|
print(f" Doctor: {doctor.name}")
|
|
print(f" Análisis: {analysis.name}")
|
|
|
|
# Crear orden de laboratorio
|
|
order = env['sale.order'].create({
|
|
'partner_id': patient.id,
|
|
'doctor_id': doctor.id,
|
|
'is_lab_request': True,
|
|
'order_line': [(0, 0, {
|
|
'product_id': analysis.id,
|
|
'product_uom_qty': 1.0
|
|
})]
|
|
})
|
|
|
|
print(f"\n✓ Orden creada: {order.name}")
|
|
print(f" Estado inicial: {order.state}")
|
|
|
|
# Confirmar la orden
|
|
print("\n🔄 Confirmando orden...")
|
|
order.action_confirm()
|
|
|
|
print(f"✓ Orden confirmada")
|
|
print(f" Estado: {order.state}")
|
|
print(f" Muestras generadas: {len(order.generated_sample_ids)}")
|
|
|
|
# Mostrar muestras generadas
|
|
if order.generated_sample_ids:
|
|
print("\n📦 Muestras generadas:")
|
|
for sample in order.generated_sample_ids:
|
|
print(f" - {sample.name}: {sample.sample_type_product_id.name} (Estado: {sample.state})")
|
|
|
|
# Buscar pruebas generadas
|
|
tests = env['lims.test'].search([
|
|
('sale_order_line_id.order_id', '=', order.id)
|
|
])
|
|
|
|
print(f"\n🔬 Pruebas generadas: {len(tests)}")
|
|
if tests:
|
|
for test in tests:
|
|
print(f" - {test.name}: {test.product_id.name} (Estado: {test.state})")
|
|
|
|
# Iniciar proceso en una prueba para hacerlo más realista
|
|
if tests and order.generated_sample_ids:
|
|
print("\n🔄 Iniciando proceso en primera prueba...")
|
|
test = tests[0]
|
|
test.sample_id = order.generated_sample_ids[0]
|
|
test.action_start_process()
|
|
print(f" ✓ Prueba {test.name} en proceso")
|
|
|
|
# CANCELAR LA ORDEN
|
|
print("\n❌ Cancelando la orden de laboratorio...")
|
|
order.action_cancel()
|
|
|
|
print(f"\n✓ Orden cancelada")
|
|
print(f" Estado de la orden: {order.state}")
|
|
|
|
# Verificar estado de las muestras
|
|
print("\n📦 Estado final de las muestras:")
|
|
for sample in order.generated_sample_ids:
|
|
print(f" - {sample.name}: {sample.state}")
|
|
# Verificar si hay mensaje en el chatter
|
|
last_msg = sample.message_ids[0] if sample.message_ids else None
|
|
if last_msg and "cancelada automáticamente" in last_msg.body:
|
|
print(f" ✓ Mensaje de cancelación registrado")
|
|
|
|
# Verificar estado de las pruebas
|
|
print("\n🔬 Estado final de las pruebas:")
|
|
for test in tests:
|
|
test_updated = env['lims.test'].browse(test.id)
|
|
print(f" - {test_updated.name}: {test_updated.state}")
|
|
# Verificar mensaje
|
|
last_msg = test_updated.message_ids[0] if test_updated.message_ids else None
|
|
if last_msg and "cancelada automáticamente" in last_msg.body:
|
|
print(f" ✓ Mensaje de cancelación registrado")
|
|
|
|
# Verificar mensaje en la orden
|
|
print("\n📝 Mensajes en la orden:")
|
|
for msg in order.message_ids[:3]: # Últimos 3 mensajes
|
|
if "cancelaron automáticamente" in msg.body:
|
|
print(f" ✓ Mensaje de resumen de cancelación encontrado")
|
|
# Extraer números del mensaje
|
|
import re
|
|
samples_match = re.search(r'(\d+) muestras', msg.body)
|
|
tests_match = re.search(r'(\d+) pruebas', msg.body)
|
|
if samples_match:
|
|
print(f" - Muestras canceladas: {samples_match.group(1)}")
|
|
if tests_match:
|
|
print(f" - Pruebas canceladas: {tests_match.group(1)}")
|
|
break
|
|
|
|
print("\n✅ Prueba completada exitosamente!")
|
|
|
|
# Hacer rollback para no dejar datos de prueba
|
|
cr.rollback()
|
|
print("\n⚠️ Cambios revertidos (rollback)")
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ Error durante la prueba: {str(e)}")
|
|
traceback.print_exc()
|
|
cr.rollback()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
db_name = 'lims_demo'
|
|
try:
|
|
registry = odoo.modules.registry.Registry(db_name)
|
|
with registry.cursor() as cr:
|
|
test_cancel_cascade(cr)
|
|
except Exception as e:
|
|
print(f"Error general: {e}")
|
|
traceback.print_exc() |