clinical_laboratory/lims_management/views/stock_lot_views.xml
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

140 lines
9.2 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Vista de Lista para Muestras de Laboratorio -->
<record id="view_lab_sample_list" model="ir.ui.view">
<field name="name">lab.sample.list</field>
<field name="model">stock.lot</field>
<field name="arch" type="xml">
<list string="Muestras de Laboratorio">
<field name="name" string="Código"/>
<field name="patient_id" string="Paciente"/>
<field name="product_id" string="Tipo de Muestra"/>
<field name="sample_type_product_id" string="Tipo de Muestra"/>
<field name="collection_date" string="Fecha de Recolección"/>
<field name="collector_id" string="Recolectado por"/>
<field name="container_type" optional="hide" string="Tipo Contenedor (Obsoleto)"/>
<field name="state" string="Estado" decoration-success="state == 'analyzed'" decoration-info="state == 'in_process'" decoration-danger="state == 'rejected'" decoration-muted="state == 'stored' or state == 'disposed' or state == 'cancelled'" widget="badge"/>
</list>
</field>
</record>
<!-- Vista de Formulario para Muestras de Laboratorio -->
<record id="view_lab_sample_form" model="ir.ui.view">
<field name="name">lab.sample.form</field>
<field name="model">stock.lot</field>
<field name="arch" type="xml">
<form string="Muestra de Laboratorio">
<header>
<button name="action_collect" string="Recolectar" type="object" class="oe_highlight" invisible="state != 'pending_collection'"/>
<button name="action_receive" string="Recibir" type="object" class="oe_highlight" invisible="state != 'collected'"/>
<button name="action_start_analysis" string="Iniciar Análisis" type="object" class="oe_highlight" invisible="state != 'received'"/>
<button name="action_complete_analysis" string="Completar Análisis" type="object" class="oe_highlight" invisible="state != 'in_process'"/>
<button name="action_store" string="Almacenar" type="object" invisible="state not in ['analyzed', 'in_process', 'received']"/>
<button name="action_dispose" string="Desechar" type="object" invisible="state == 'disposed'"/>
<button name="action_open_rejection_wizard"
string="Rechazar Muestra"
type="object"
class="btn-danger"
invisible="state in ['completed', 'rejected', 'disposed', 'cancelled']"/>
<button name="action_cancel" string="Cancelar" type="object" invisible="state in ['cancelled', 'rejected', 'disposed']"/>
<field name="state" widget="statusbar" statusbar_visible="pending_collection,collected,received,in_process,analyzed,stored,rejected"/>
</header>
<sheet>
<div class="oe_title">
<h1>
<field name="name"/>
</h1>
</div>
<group>
<group>
<field name="patient_id" readonly="state not in ['pending_collection', 'collected']"/>
<field name="doctor_id" readonly="state not in ['pending_collection', 'collected']"/>
<field name="origin" readonly="1"/>
<field name="request_id"
readonly="state not in ['pending_collection', 'collected']"
domain="[('is_lab_request', '=', True), '|', ('partner_id', '=', False), ('partner_id', '=', patient_id)]"/>
<field name="product_id"
string="Sample Type"
domain="[('is_sample_type', '=', True)]"
options="{'no_create': True, 'no_create_edit': True}"
readonly="state not in ['pending_collection', 'collected']"/>
</group>
<group>
<field name="barcode" readonly="1"/>
<field name="collection_date" readonly="state not in ['pending_collection', 'collected']"/>
<field name="collector_id" readonly="state not in ['pending_collection', 'collected']"/>
<field name="sample_type_product_id"
readonly="state not in ['pending_collection', 'collected']"
options="{'no_create': True, 'no_create_edit': True}"/>
<field name="volume_ml" readonly="1"/>
<field name="analysis_names" readonly="1"/>
<field name="container_type"
readonly="state not in ['pending_collection', 'collected']"
invisible="sample_type_product_id != False"/>
</group>
</group>
<group string="Información de Rechazo" invisible="state != 'rejected'" col="4">
<field name="rejection_reason_id" readonly="1"/>
<field name="rejected_by" readonly="1"/>
<field name="rejection_date" readonly="1"/>
<field name="rejection_notes" readonly="1" colspan="4"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Search View for Lab Samples -->
<record id="view_lab_sample_search" model="ir.ui.view">
<field name="name">lab.sample.search</field>
<field name="model">stock.lot</field>
<field name="arch" type="xml">
<search string="Buscar Muestras">
<field name="name" string="Código"/>
<field name="patient_id"/>
<field name="barcode"/>
<field name="analysis_names"/>
<filter string="Pendientes" name="pending" domain="[('state', 'in', ['pending_collection', 'collected', 'received'])]"/>
<filter string="En Proceso" name="in_process" domain="[('state', '=', 'in_process')]"/>
<filter string="Analizadas" name="analyzed" domain="[('state', '=', 'analyzed')]"/>
<filter string="Rechazadas" name="rejected" domain="[('state', '=', 'rejected')]"/>
<separator/>
<filter string="Hoy" name="today" domain="[('collection_date', '&gt;=', datetime.datetime.now().strftime('%Y-%m-%d 00:00:00')), ('collection_date', '&lt;=', datetime.datetime.now().strftime('%Y-%m-%d 23:59:59'))]"/>
<filter string="Esta Semana" name="this_week" domain="[('collection_date', '&gt;=', (datetime.datetime.now() - datetime.timedelta(days=7)).strftime('%Y-%m-%d'))]"/>
<separator/>
<filter string="Rechazadas - Alta Severidad" name="rejected_high"
domain="[('state', '=', 'rejected'), ('rejection_reason_id.severity', 'in', ['high', 'critical'])]"/>
<group expand="0" string="Agrupar por">
<filter string="Estado" name="group_state" context="{'group_by': 'state'}"/>
<filter string="Paciente" name="group_patient" context="{'group_by': 'patient_id'}"/>
<filter string="Fecha de Recolección" name="group_collection" context="{'group_by': 'collection_date:day'}"/>
<filter string="Motivo de Rechazo" name="group_rejection" context="{'group_by': 'rejection_reason_id'}"/>
</group>
</search>
</field>
</record>
<!-- Action for Rejected Samples -->
<record id="action_lab_sample_rejected" model="ir.actions.act_window">
<field name="name">Muestras Rechazadas</field>
<field name="res_model">stock.lot</field>
<field name="view_mode">list,form</field>
<field name="domain">[('is_lab_sample', '=', True), ('state', '=', 'rejected')]</field>
<field name="context">{'search_default_rejected': 1, 'default_is_lab_sample': True}</field>
<field name="search_view_id" ref="view_lab_sample_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No hay muestras rechazadas
</p>
<p>
Las muestras rechazadas aparecerán aquí con información
sobre el motivo del rechazo y las acciones tomadas.
</p>
</field>
</record>
</data>
</odoo>