Merge pull request 'feature/31-sample-lifecycle' (#34) from feature/31-sample-lifecycle into dev
Reviewed-on: luis_portillo/clinical_laboratory#34
This commit is contained in:
commit
c51e3b3096
43
create_lifecycle_issues.sh
Normal file
43
create_lifecycle_issues.sh
Normal file
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Script para crear issues específicos sobre el ciclo de vida y automatización de muestras.
|
||||
|
||||
# Issue 8: Implementar Ciclo de Vida para Muestras de Laboratorio
|
||||
tea issue create --title "feat: Implementar Ciclo de Vida para Muestras de Laboratorio" --labels "feature,enhancement" --description "$(cat <<'EOT'
|
||||
**Objetivo:** Implementar una máquina de estados para el modelo de muestra (`stock.lot`) que permita seguir su ciclo de vida desde la recolección hasta el descarte.
|
||||
|
||||
**Tareas:**
|
||||
|
||||
1. **Modelo (`stock.lot`):**
|
||||
* Añadir un campo `state` de tipo `Selection` con los siguientes estados:
|
||||
- `collected` (Recolectada)
|
||||
- `received` (Recibida en Laboratorio)
|
||||
- `in_process` (En Proceso)
|
||||
- `analyzed` (Analizada)
|
||||
- `stored` (Almacenada)
|
||||
- `disposed` (Desechada)
|
||||
* Definir métodos para las transiciones de estado (ej. `action_receive`, `action_start_analysis`, etc.).
|
||||
|
||||
2. **Vistas (`stock_lot_views.xml`):**
|
||||
* Añadir un `statusbar` en la vista de formulario para visualizar y gestionar el estado.
|
||||
* Incorporar botones en el `header` para ejecutar las acciones de cambio de estado.
|
||||
* Mostrar el campo `state` en la vista de lista y añadirlo a los filtros.
|
||||
* Aplicar `readonly` a campos clave en función del estado para prevenir modificaciones no deseadas.
|
||||
EOT
|
||||
)"
|
||||
|
||||
# Issue 9: Automatizar Creación de Muestras desde la Solicitud de Laboratorio
|
||||
tea issue create --title "feat: Automatizar Creación de Muestras desde la Solicitud" --labels "feature,automation" --description "$(cat <<'EOT'
|
||||
**Objetivo:** Automatizar la generación de registros de muestra (`stock.lot`) cuando una Solicitud de Laboratorio (`sale.order`) es confirmada.
|
||||
|
||||
**Tareas:**
|
||||
|
||||
1. **Lógica de Negocio (`sale_order.py`):**
|
||||
* Heredar y extender el método `action_confirm` del modelo `sale.order`.
|
||||
* Dentro del método, añadir la lógica para crear un nuevo registro en `stock.lot` por cada tipo de muestra requerido en la solicitud.
|
||||
* Asociar la muestra creada con la solicitud (`request_id`) y el paciente (`patient_id`) correspondientes.
|
||||
* Asegurarse de que la muestra se cree en el estado inicial correcto (ej. 'Recolectada' o 'Pendiente de Recolección').
|
||||
EOT
|
||||
)"
|
||||
|
||||
echo "Script 'create_lifecycle_issues.sh' generado. Ejecútalo para crear los nuevos issues."
|
70
documents/plans/ISSUE31_PLAN.md
Normal file
70
documents/plans/ISSUE31_PLAN.md
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Plan de Actividades: Issue #31 - Ciclo de Vida de la Muestra
|
||||
|
||||
## Objetivo
|
||||
|
||||
Implementar una máquina de estados completa para el modelo `stock.lot` con el fin de gestionar y trazar el ciclo de vida de una muestra de laboratorio, desde su recolección hasta su descarte.
|
||||
|
||||
---
|
||||
|
||||
## Plan de Ejecución
|
||||
|
||||
### 1. Modificación del Modelo (`stock.lot`)
|
||||
|
||||
- **Archivo:** `lims_management/models/stock_lot.py`
|
||||
- **Tareas:**
|
||||
- [ ] **Añadir campo `state`:**
|
||||
- Tipo: `Selection`
|
||||
- Nombre técnico: `state`
|
||||
- String: "Estado"
|
||||
- Opciones:
|
||||
- `collected`: 'Recolectada' (Estado por defecto)
|
||||
- `received`: 'Recibida en Laboratorio'
|
||||
- `in_process`: 'En Proceso'
|
||||
- `analyzed`: 'Analizada'
|
||||
- `stored`: 'Almacenada'
|
||||
- `disposed`: 'Desechada'
|
||||
- Atributos: `tracking=True` para registrar cambios en el chatter.
|
||||
- [ ] **Definir métodos para transiciones:**
|
||||
- `action_receive()`: Cambia el estado a `received`.
|
||||
- `action_start_analysis()`: Cambia el estado a `in_process`.
|
||||
- `action_complete_analysis()`: Cambia el estado a `analyzed`.
|
||||
- `action_store()`: Cambia el estado a `stored`.
|
||||
- `action_dispose()`: Cambia el estado a `disposed`.
|
||||
- Cada método debe realizar una transición de estado simple y registrar un mensaje en el chatter.
|
||||
|
||||
### 2. Adaptación de las Vistas (`stock_lot_views.xml`)
|
||||
|
||||
- **Archivo:** `lims_management/views/stock_lot_views.xml`
|
||||
- **Tareas:**
|
||||
- [ ] **Vista de Formulario:**
|
||||
- [ ] **Añadir `header`:**
|
||||
- Incorporar botones para las acciones (`action_receive`, `action_start_analysis`, etc.).
|
||||
- Controlar la visibilidad de los botones según el estado actual (ej. el botón "Recibir" solo debe ser visible si el estado es 'Recolectada').
|
||||
- [ ] **Añadir `statusbar`:**
|
||||
- Visualizar el campo `state` usando el widget `statusbar`.
|
||||
- Definir el `statusbar_visible` para mostrar los estados clave del flujo principal.
|
||||
- [ ] **Hacer campos `readonly`:**
|
||||
- Campos como `patient_id`, `request_id`, `collection_date` deben volverse de solo lectura después de que la muestra es recibida para asegurar la integridad de los datos. Se usará el atributo `attrs` con el nuevo formato `invisible` o `readonly` basado en el campo `state`.
|
||||
- [ ] **Vista de Lista:**
|
||||
- [ ] Añadir el campo `state` para que sea visible.
|
||||
- [ ] Añadir el campo `state` a los filtros por defecto en el `search` para poder agrupar por estado fácilmente.
|
||||
|
||||
### 3. Seguridad (Opcional, si es necesario)
|
||||
|
||||
- **Archivo:** `lims_management/security/lims_security.xml` o `ir.model.access.csv`
|
||||
- **Tareas:**
|
||||
- [ ] Evaluar si se necesitan reglas de seguridad específicas para controlar quién puede ejecutar las transiciones de estado. Por ahora, se asumirá que los grupos existentes (`group_lims_technician`, `group_lims_admin`) tienen los permisos.
|
||||
|
||||
### 4. Verificación y Pruebas
|
||||
|
||||
- **Pasos:**
|
||||
- [ ] Reiniciar la instancia de Odoo con el módulo actualizado.
|
||||
- [ ] Crear una nueva muestra de laboratorio manualmente.
|
||||
- [ ] Verificar que el estado por defecto sea 'Recolectada'.
|
||||
- [ ] Probar cada uno de los botones de transición de estado en la vista de formulario.
|
||||
- [ ] Confirmar que el `statusbar` se actualiza correctamente.
|
||||
- [ ] Revisar el chatter para asegurarse de que los cambios de estado se están registrando.
|
||||
- [ ] Verificar la visibilidad condicional de los botones y el modo de solo lectura de los campos.
|
||||
- [ ] Filtrar y agrupar por estado en la vista de lista.
|
||||
|
||||
---
|
|
@ -33,3 +33,27 @@ class StockLot(models.Model):
|
|||
string='Collected by',
|
||||
default=lambda self: self.env.user
|
||||
)
|
||||
|
||||
state = fields.Selection([
|
||||
('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'})
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<field name="collection_date"/>
|
||||
<field name="collector_id"/>
|
||||
<field name="container_type"/>
|
||||
<field name="state" decoration-success="state == 'analyzed'" decoration-info="state == 'in_process'" decoration-muted="state == 'stored' or state == 'disposed'" widget="badge"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -24,6 +25,14 @@
|
|||
<field name="model">stock.lot</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Lab Sample">
|
||||
<header>
|
||||
<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 == 'stored' or state == 'disposed'"/>
|
||||
<button name="action_dispose" string="Desechar" type="object" invisible="state == 'disposed'"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="collected,received,in_process,analyzed,stored"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
|
@ -32,17 +41,20 @@
|
|||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="patient_id"/>
|
||||
<field name="request_id"/>
|
||||
<field name="patient_id" readonly="state != 'collected'"/>
|
||||
<field name="request_id"
|
||||
readonly="state != '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}"/>
|
||||
options="{'no_create': True, 'no_create_edit': True}"
|
||||
readonly="state != 'collected'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="collection_date"/>
|
||||
<field name="collector_id"/>
|
||||
<field name="container_type"/>
|
||||
<field name="collection_date" readonly="state != 'collected'"/>
|
||||
<field name="collector_id" readonly="state != 'collected'"/>
|
||||
<field name="container_type" readonly="state != 'collected'"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
|
Loading…
Reference in New Issue
Block a user