import odoo import json import random from datetime import datetime # Diccionario de notas médicas para parámetros críticos CRITICAL_NOTES = { 'glucosa': { 'high': 'Valor elevado de glucosa. Posible prediabetes o diabetes. Se recomienda repetir la prueba en ayunas y consultar con endocrinología.', 'low': 'Hipoglucemia detectada. Riesgo de síntomas neuroglucogénicos. Evaluar causas: medicamentos, insuficiencia hepática o endocrinopatías.' }, 'hemoglobina': { 'high': 'Policitemia. Evaluar posibles causas: deshidratación, tabaquismo, cardiopatía o policitemia vera.', 'low': 'Anemia severa. Investigar origen: deficiencia de hierro, pérdida sanguínea, hemólisis o enfermedad crónica.' }, 'hematocrito': { 'high': 'Hemoconcentración. Correlacionar con hemoglobina. Descartar deshidratación o policitemia.', 'low': 'Valor compatible con anemia. Evaluar junto con hemoglobina e índices eritrocitarios.' }, 'leucocitos': { 'high': 'Leucocitosis marcada. Descartar proceso infeccioso, inflamatorio o hematológico.', 'low': 'Leucopenia severa. Riesgo de infecciones. Evaluar causas: viral, medicamentosa o hematológica.' }, 'plaquetas': { 'high': 'Trombocitosis. Riesgo trombótico. Descartar causa primaria vs reactiva.', 'low': 'Trombocitopenia severa. Riesgo de sangrado. Evaluar PTI, hiperesplenismo o supresión medular.' }, 'neutrofilos': { 'high': 'Neutrofilia. Sugiere infección bacteriana o proceso inflamatorio agudo.', 'low': 'Neutropenia. Alto riesgo de infección bacteriana. Evaluar urgentemente.' }, 'linfocitos': { 'high': 'Linfocitosis. Considerar infección viral o proceso linfoproliferativo.', 'low': 'Linfopenia. Evaluar inmunodeficiencia o efecto de corticoides.' }, 'colesterol total': { 'high': 'Hipercolesterolemia. Riesgo cardiovascular elevado. Iniciar medidas dietéticas y evaluar tratamiento con estatinas.', 'low': 'Hipocolesterolemia. Evaluar malnutrición, hipertiroidismo o enfermedad hepática.' }, 'trigliceridos': { 'high': 'Hipertrigliceridemia severa. Riesgo de pancreatitis aguda. Considerar tratamiento farmacológico urgente.', 'low': 'Valor bajo, generalmente sin significado patológico.' }, 'hdl': { 'high': 'HDL elevado, factor protector cardiovascular.', 'low': 'HDL bajo. Factor de riesgo cardiovascular. Recomendar ejercicio y cambios en estilo de vida.' }, 'ldl': { 'high': 'LDL elevado. Alto riesgo aterogénico. Evaluar inicio de estatinas según riesgo global.', 'low': 'LDL bajo, generalmente favorable.' }, 'glucosa en sangre': { 'high': 'Hiperglucemia. Si en ayunas >126 mg/dL sugiere diabetes. Confirmar con segunda muestra.', 'low': 'Hipoglucemia. Evaluar síntomas y causas. Riesgo neurológico si <50 mg/dL.' } } def get_critical_note(param_name, value, normal_min=None, normal_max=None): """Obtiene la nota apropiada para un resultado crítico""" param_lower = param_name.lower() # Buscar el parámetro en el diccionario for key in CRITICAL_NOTES: if key in param_lower: if normal_max and value > normal_max: return CRITICAL_NOTES[key].get('high', f'Valor crítico alto para {param_name}. Requiere evaluación médica inmediata.') elif normal_min and value < normal_min: return CRITICAL_NOTES[key].get('low', f'Valor crítico bajo para {param_name}. Requiere evaluación médica inmediata.') # Nota genérica si no se encuentra el parámetro if normal_max and value > normal_max: return f'Valor significativamente elevado. Rango normal: {normal_min}-{normal_max}. Se recomienda evaluación médica.' elif normal_min and value < normal_min: return f'Valor significativamente bajo. Rango normal: {normal_min}-{normal_max}. Se recomienda evaluación médica.' return 'Valor fuera de rango normal. Requiere interpretación clínica.' def process_order_tests(env, order): """Process all tests for a given order: regenerate results, fill values, and validate""" print(f"\nProcessing tests for order {order.name}...") # First, update sample states to allow processing samples = order.generated_sample_ids.sudo() for sample in samples: if sample.state == 'pending_collection': sample.action_collect() print(f" - Sample {sample.name} collected") if sample.state == 'collected': sample.action_receive() print(f" - Sample {sample.name} received") if sample.state == 'received': sample.action_start_analysis() print(f" - Sample {sample.name} analysis started") # Find all tests associated with this order tests = env['lims.test'].search([('sale_order_id', '=', order.id)]) print(f"Found {len(tests)} tests for order {order.name}") # Ensure we have the right permissions by using sudo() tests = tests.sudo() for test in tests: try: print(f"\nProcessing test {test.name} - {test.product_id.name}") # First, mark the test as in_process if it's in draft state if test.state == 'draft': test.write({'state': 'in_process'}) # Manually create results if they don't exist if not test.result_ids: # Get analysis parameters from product template product_tmpl = test.product_id.product_tmpl_id for param_link in product_tmpl.parameter_ids: param = param_link.parameter_id result = env['lims.result'].create({ 'test_id': test.id, 'parameter_id': param.id, }) # Immediately set a value to avoid validation errors if param.value_type == 'numeric': # Generar valor que a veces esté fuera de rango if random.random() < 0.3: # 30% de valores críticos # Obtener rangos normales del parámetro normal_min = param_link.normal_min if hasattr(param_link, 'normal_min') and param_link.normal_min else 10 normal_max = param_link.normal_max if hasattr(param_link, 'normal_max') and param_link.normal_max else 100 # Decidir si será alto o bajo if random.random() < 0.5: # Valor alto value = round(random.uniform(normal_max * 1.2, normal_max * 1.5), 2) else: # Valor bajo value = round(random.uniform(normal_min * 0.5, normal_min * 0.8), 2) result.value_numeric = value else: result.value_numeric = 50.0 elif param.value_type == 'text': result.value_text = "Normal" elif param.value_type == 'boolean': result.value_boolean = False elif param.value_type == 'selection' and param.selection_options: options = param.selection_options.split(',') result.value_selection = options[0].strip() print(f" - Created {len(product_tmpl.parameter_ids)} result fields") # Evaluar resultados críticos y agregar notas for result in test.result_ids: # Leer el registro para actualizar campos computados result.read(['is_critical']) # Si el resultado es crítico, agregar nota if result.is_critical and result.parameter_id.value_type == 'numeric': value = result.value_numeric param_name = result.parameter_id.name # Obtener rangos del rango aplicable si existe normal_min = normal_max = None if result.applicable_range_id: normal_min = result.applicable_range_id.normal_min normal_max = result.applicable_range_id.normal_max # Obtener la nota apropiada note = get_critical_note(param_name, value, normal_min, normal_max) result.write({'notes': note}) print(f" - Agregada nota crítica para {param_name}: valor {value}") print(f" - Results ready with values and critical notes") # Update test state directly to bypass permission checks if test.state == 'in_process': # Mark as results entered test.write({ 'state': 'result_entered' }) print(f" - Results entered") # Then validate the test if test.state == 'result_entered': test.write({ 'state': 'validated', 'validator_id': env.user.id, 'validation_date': datetime.now() }) print(f" - Test validated successfully") except Exception as e: print(f" - Error processing test {test.name}: {str(e)}") import traceback traceback.print_exc() print(f" - Test state: {test.state}") print(f" - Product template: {test.product_id.product_tmpl_id.name}") print(f" - Parameters: {len(test.product_id.product_tmpl_id.parameter_ids)}") print(f"\nCompleted processing tests for order {order.name}") def create_lab_requests(cr): env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {}) # Delete unwanted demo sale orders unwanted_orders = env['sale.order'].search([('name', 'in', ['S00001', 'S00002', 'S00003', 'S00004', 'S00005', 'S00006', 'S00007', 'S00008', 'S00009', 'S00010', 'S00011', 'S00012', 'S00013', 'S00014', 'S00015', 'S00016', 'S00017', 'S00018', 'S00019', 'S00020', 'S00021', 'S00022'])]) for order in unwanted_orders: try: order.action_cancel() except Exception: pass try: unwanted_orders.unlink() except Exception: pass try: # Get patients and doctors - using search instead of ref to be more robust patient1 = env['res.partner'].search([('patient_identifier', '=', 'P-A87B01'), ('is_patient', '=', True)], limit=1) patient2 = env['res.partner'].search([('patient_identifier', '=', 'P-C45D02'), ('is_patient', '=', True)], limit=1) doctor1 = env['res.partner'].search([('doctor_license', '=', 'L-98765'), ('is_doctor', '=', True)], limit=1) if not patient1: print("Warning: Patient 1 not found, skipping lab requests creation") return # Get analysis products - using search instead of ref hemograma = env['product.template'].search([('name', '=', 'Hemograma Completo'), ('is_analysis', '=', True)], limit=1) perfil_lipidico = env['product.template'].search([('name', '=', 'Perfil Lipídico'), ('is_analysis', '=', True)], limit=1) glucosa = env['product.template'].search([('name', '=', 'Glucosa en Sangre'), ('is_analysis', '=', True)], limit=1) urocultivo = env['product.template'].search([('name', '=', 'Urocultivo'), ('is_analysis', '=', True)], limit=1) # Create Lab Request 1 - Multiple analyses with same sample type if patient1 and hemograma and perfil_lipidico: order1 = env['sale.order'].create({ 'partner_id': patient1.id, 'doctor_id': doctor1.id if doctor1 else False, 'is_lab_request': True, 'order_line': [ (0, 0, {'product_id': hemograma.product_variant_id.id, 'product_uom_qty': 1}), (0, 0, {'product_id': perfil_lipidico.product_variant_id.id, 'product_uom_qty': 1}) ] }) print(f"Created Lab Order 1: {order1.name}") # Confirm the order to test automatic sample generation order1.action_confirm() print(f"Confirmed Lab Order 1. Generated samples: {len(order1.generated_sample_ids)}") # Process tests for order1 process_order_tests(env, order1) # Create Lab Request 2 - Different sample types if patient2 and glucosa and urocultivo: order2 = env['sale.order'].create({ 'partner_id': patient2.id, 'is_lab_request': True, 'order_line': [ (0, 0, {'product_id': glucosa.product_variant_id.id, 'product_uom_qty': 1}), (0, 0, {'product_id': urocultivo.product_variant_id.id, 'product_uom_qty': 1}) ] }) print(f"Created Lab Order 2: {order2.name}") # Confirm to test automatic sample generation with different types order2.action_confirm() print(f"Confirmed Lab Order 2. Generated samples: {len(order2.generated_sample_ids)}") # Process tests for order2 process_order_tests(env, order2) except Exception as e: print(f"Error creating lab requests: {str(e)}") import traceback traceback.print_exc() if __name__ == '__main__': db_name = 'lims_demo' registry = odoo.registry(db_name) with registry.cursor() as cr: create_lab_requests(cr) cr.commit()