diff --git a/CLAUDE.md b/CLAUDE.md index 064b638..182134f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -94,6 +94,12 @@ python gitea_cli_helper.py comment-issue --issue-number 123 --body "Comment text # Close issue python gitea_cli_helper.py close-issue --issue-number 123 + +# Get issue details and comments +python gitea_cli_helper.py get-issue --issue-number 8 + +# List all open issues +python gitea_cli_helper.py list-open-issues ``` ## Mandatory Reading diff --git a/documents/plans/ISSUE8_PLAN.md b/documents/plans/ISSUE8_PLAN.md index ea1634e..40edc6c 100644 --- a/documents/plans/ISSUE8_PLAN.md +++ b/documents/plans/ISSUE8_PLAN.md @@ -1,225 +1,163 @@ # Plan de Implementación - Issue #8: Gestión de Pruebas y Resultados ## Objetivo -Implementar el sistema completo de gestión de pruebas de laboratorio, incluyendo definición de parámetros, entrada de resultados, validación y generación de reportes. +Implementar los modelos y la interfaz básica para la gestión de pruebas y resultados de laboratorio, específicamente los modelos `lims.test` y `lims.result` con entrada dinámica de resultados. ## Análisis de Requisitos -### Funcionalidad Esperada -1. **Catálogo de Pruebas con Parámetros**: Cada análisis debe tener parámetros configurables con unidades y rangos de referencia -2. **Entrada de Resultados**: Interfaz dinámica para captura de resultados según el tipo de análisis -3. **Validación de Resultados**: Flujo de dos pasos (técnico ingresa, administrador valida) -4. **Generación de Reportes**: PDF con formato profesional y resultados fuera de rango resaltados -5. **Control de Acceso**: Permisos basados en roles para técnicos y administradores +### Funcionalidad Esperada (según Issue #8) +1. **Modelo lims.test**: Representar la ejecución de un análisis con estados +2. **Modelo lims.result**: Almacenar cada valor de resultado con soporte para múltiples tipos +3. **Interfaz de entrada dinámica**: Vista formulario con lista editable de resultados +4. **Resaltado visual**: Mostrar en rojo los resultados fuera de rango +5. **Validación opcional**: Permitir configurar si se requiere validación por administrador -### Modelos de Datos Requeridos -1. **lims.test**: Representa una prueba de laboratorio en progreso -2. **lims.test.parameter**: Define parámetros para cada tipo de prueba -3. **lims.result**: Almacena los resultados reales de las pruebas +### Modelos de Datos Requeridos (según Issue #8) +1. **lims.test**: Representa la ejecución de un análisis +2. **lims.result**: Almacena cada valor de resultado +3. **lims.test.parameter**: Modelo referenciado (asumimos ya existe o se creará) ## Tareas de Implementación -### 1. Crear modelo lims.test.parameter -**Archivo:** `lims_management/models/test_parameter.py` -- [ ] Definir modelo con campos: - ```python - name = fields.Char(string='Parámetro', required=True) - product_id = fields.Many2one('product.product', string='Análisis', - domain=[('is_analysis', '=', True)]) - unit = fields.Char(string='Unidad de Medida') - value_type = fields.Selection([ - ('numeric', 'Numérico'), - ('text', 'Texto'), - ('selection', 'Selección'), - ('boolean', 'Sí/No') - ], string='Tipo de Valor', required=True) - normal_min = fields.Float(string='Valor Normal Mínimo') - normal_max = fields.Float(string='Valor Normal Máximo') - selection_options = fields.Text(string='Opciones (para tipo selección)') - sequence = fields.Integer(string='Secuencia', default=10) - ``` -- [ ] Agregar validaciones y constraints -- [ ] Crear vista de configuración - -### 2. Crear modelo lims.test +### 1. Crear modelo lims.test **Archivo:** `lims_management/models/lims_test.py` -- [ ] Definir modelo principal: +- [ ] Definir modelo según especificación del issue: ```python - name = fields.Char(string='Código de Prueba', required=True, readonly=True) - sale_order_id = fields.Many2one('sale.order', string='Orden de Laboratorio') - order_line_id = fields.Many2one('sale.order.line', string='Línea de Orden') - product_id = fields.Many2one('product.product', string='Análisis') - patient_id = fields.Many2one('res.partner', string='Paciente') + sale_order_line_id = fields.Many2one('sale.order.line', string='Línea de Orden') + patient_id = fields.Many2one('res.partner', string='Paciente', + related='sale_order_line_id.order_id.partner_id') + product_id = fields.Many2one('product.product', string='Análisis', + related='sale_order_line_id.product_id') sample_id = fields.Many2one('stock.lot', string='Muestra') state = fields.Selection([ - ('pending', 'Pendiente'), + ('draft', 'Borrador'), ('in_process', 'En Proceso'), ('result_entered', 'Resultado Ingresado'), ('validated', 'Validado'), ('cancelled', 'Cancelado') - ], string='Estado', default='pending') - technician_id = fields.Many2one('res.users', string='Técnico') + ], string='Estado', default='draft') validator_id = fields.Many2one('res.users', string='Validador') validation_date = fields.Datetime(string='Fecha de Validación') + require_validation = fields.Boolean(string='Requiere Validación', + compute='_compute_require_validation') ``` -- [ ] Implementar generación automática de código de prueba +- [ ] Implementar _compute_require_validation basado en configuración - [ ] Agregar métodos de transición de estados -- [ ] Implementar creación automática desde orden confirmada -### 3. Crear modelo lims.result +### 2. Crear modelo lims.result **Archivo:** `lims_management/models/lims_result.py` -- [ ] Definir modelo de resultados: +- [ ] Definir modelo según especificación: ```python - test_id = fields.Many2one('lims.test', string='Prueba', required=True) + test_id = fields.Many2one('lims.test', string='Prueba', required=True, ondelete='cascade') parameter_id = fields.Many2one('lims.test.parameter', string='Parámetro') value_numeric = fields.Float(string='Valor Numérico') - value_text = fields.Text(string='Valor de Texto') - value_selection = fields.Char(string='Valor de Selección') - value_boolean = fields.Boolean(string='Valor Sí/No') - is_normal = fields.Boolean(string='Dentro de Rango Normal', compute='_compute_is_normal') - observations = fields.Text(string='Observaciones') - attachment_ids = fields.Many2many('ir.attachment', string='Archivos Adjuntos') + value_text = fields.Char(string='Valor de Texto') + value_selection = fields.Selection([], string='Valor de Selección') + is_out_of_range = fields.Boolean(string='Fuera de Rango', compute='_compute_is_out_of_range') + notes = fields.Text(string='Notas del Técnico') ``` -- [ ] Implementar cálculo automático de is_normal -- [ ] Agregar validaciones según tipo de valor +- [ ] Implementar _compute_is_out_of_range para detectar valores anormales +- [ ] Agregar validación para asegurar que solo un tipo de valor esté lleno -### 4. Implementar generación automática de pruebas -**Archivo:** `lims_management/models/sale_order.py` (extender) -- [ ] Al confirmar orden con análisis, crear registros lims.test -- [ ] Vincular con muestras generadas automáticamente -- [ ] Notificar en el chatter sobre pruebas creadas - -### 5. Crear vistas de entrada de resultados +### 3. Desarrollar interfaz de ingreso de resultados **Archivo:** `lims_management/views/lims_test_views.xml` -- [ ] Vista kanban por estado para gestión de pruebas -- [ ] Vista formulario con: - - Información del paciente y muestra (readonly) - - Lista editable de resultados por parámetro - - Destacar valores fuera de rango con color rojo - - Botones de acción según estado -- [ ] Vista lista con filtros y agrupaciones +- [ ] Crear vista formulario para lims.test con: + - Información de cabecera (paciente, análisis, muestra) + - Lista editable (One2many) de lims.result + - Campos dinámicos según parámetros del análisis +- [ ] Implementar widget o CSS para resaltar en rojo valores fuera de rango +- [ ] Agregar botones de acción según estado -### 6. Implementar flujo de validación -**Archivo:** `lims_management/models/lims_test.py` (extender) -- [ ] Método action_enter_results() - marca como resultado ingresado -- [ ] Método action_validate() - valida resultados (solo administradores) -- [ ] Método action_request_review() - solicita revisión -- [ ] Agregar validaciones de permisos +### 4. Implementar lógica visual para valores fuera de rango +**Archivo:** `lims_management/static/src/` (CSS/JS) +- [ ] Crear CSS para clase .out-of-range con color rojo +- [ ] Implementar widget o computed field que aplique la clase +- [ ] Asegurar que funcione en vista formulario y lista -### 7. Crear informe PDF de resultados -**Archivos:** -- `lims_management/report/test_results_report.xml` -- `lims_management/report/test_results_template.xml` -- [ ] Diseñar plantilla QWeb con: - - Encabezado con logo del laboratorio - - Información del paciente y orden - - Tabla de resultados con formato: - | Parámetro | Resultado | Unidad | Rango de Referencia | - - Resaltar valores anormales - - Sección de observaciones - - Firma del validador -- [ ] Configurar paper format A4 +### 5. Agregar configuración de validación opcional +**Archivo:** `lims_management/models/res_config_settings.py` +- [ ] Agregar campo booleano lims_require_validation +- [ ] Extender res.config.settings para incluir esta configuración +- [ ] Modificar lims.test para usar esta configuración en flujo de trabajo -### 8. Implementar seguridad y permisos -**Archivos:** -- `lims_management/security/ir.model.access.csv` (actualizar) -- `lims_management/security/security.xml` (actualizar) -- [ ] Definir grupos: - - Técnico de Laboratorio: crear/editar resultados - - Administrador de Laboratorio: validar resultados -- [ ] Crear reglas de registro para cada modelo -- [ ] Implementar campo-nivel de seguridad para validación +### 6. Crear vistas básicas +**Archivo:** `lims_management/views/lims_test_views.xml` +- [ ] Vista lista de pruebas con campos básicos +- [ ] Vista kanban agrupada por estado +- [ ] Menú de acceso en Laboratorio > Pruebas -### 9. Crear datos de demostración -**Archivo:** `lims_management/demo/test_parameters_demo.xml` -- [ ] Parámetros para hemograma completo -- [ ] Parámetros para química sanguínea -- [ ] Parámetros para uroanálisis -- [ ] Crear algunas pruebas de ejemplo con resultados +### 7. Crear datos de demostración básicos +**Archivo:** `lims_management/demo/lims_test_demo.xml` +- [ ] Crear algunos registros lims.test de ejemplo +- [ ] Agregar resultados de demostración +- [ ] Incluir casos con valores dentro y fuera de rango -### 10. Implementar notificaciones -**Archivo:** `lims_management/models/lims_test.py` (extender) -- [ ] Email al paciente cuando resultados están validados -- [ ] Notificación al médico referente -- [ ] Plantillas de email profesionales ## Consideraciones Técnicas ### Performance -- Usar compute fields con store=True donde sea apropiado -- Índices en campos de búsqueda frecuente (patient_id, state) -- Lazy loading para attachments +- Usar compute fields con store=True para is_out_of_range +- Carga eficiente de parámetros relacionados ### Usabilidad -- Interfaz intuitiva para entrada rápida de resultados -- Atajos de teclado para navegación entre campos -- Autocompletado donde sea aplicable -- Vista previa del PDF antes de enviar +- Interfaz clara para entrada de resultados +- Feedback visual inmediato para valores fuera de rango +- Navegación intuitiva entre estados ### Validación de Datos -- Validar rangos numéricos según parámetros -- Prevenir modificación de resultados validados -- Log de auditoría para cambios en resultados - -### Integración -- API REST para consulta de resultados (futuro) -- Webhook para notificaciones externas -- Exportación de resultados en formato HL7 (opcional) +- Solo un tipo de valor debe estar lleno por resultado +- Validar que el parámetro corresponda al análisis +- Estados coherentes con el flujo de trabajo ## Flujo de Trabajo ```mermaid graph TD - A[Orden Confirmada] --> B[Generar Pruebas] - B --> C[Estado: Pendiente] - C --> D[Muestra Recibida] - D --> E[Estado: En Proceso] - E --> F[Técnico Ingresa Resultados] - F --> G[Estado: Resultado Ingresado] - G --> H{Validación por Admin} - H -->|Aprobado| I[Estado: Validado] - H -->|Rechazado| J[Solicitar Corrección] - J --> F - I --> K[Generar PDF] - K --> L[Enviar Notificaciones] + A[Línea de Orden] --> B[Crear lims.test] + B --> C[Estado: draft] + C --> D[Estado: in_process] + D --> E[Técnico Ingresa Resultados] + E --> F[Estado: result_entered] + F --> G{¿Requiere Validación?} + G -->|Sí| H[Esperar Validación] + G -->|No| I[Proceso Completo] + H --> J[Estado: validated] ``` -## Criterios de Aceptación +## Criterios de Aceptación (según Issue #8) -1. [ ] Los análisis tienen parámetros configurables con unidades y rangos -2. [ ] La entrada de resultados es dinámica según el tipo de análisis -3. [ ] Los valores fuera de rango se destacan visualmente -4. [ ] El flujo de validación respeta los permisos por rol -5. [ ] El PDF generado tiene formato profesional y es descargable -6. [ ] Las notificaciones se envían automáticamente -7. [ ] Existe trazabilidad completa de cambios -8. [ ] La interfaz es intuitiva y eficiente +1. [ ] Modelo lims.test creado con todos los campos especificados +2. [ ] Modelo lims.result creado con soporte para múltiples tipos de valor +3. [ ] Interfaz de formulario con lista editable de resultados +4. [ ] Valores fuera de rango se muestran en rojo +5. [ ] La validación por administrador es configurable +6. [ ] Los campos relacionados (patient_id, product_id) funcionan correctamente ## Estimación de Tiempo -- Tareas 1-3: 3-4 horas (modelos y estructura) -- Tarea 4: 1 hora (integración con órdenes) -- Tarea 5: 2-3 horas (vistas complejas) -- Tarea 6: 2 horas (flujo de validación) -- Tarea 7: 3-4 horas (reporte PDF) -- Tarea 8: 1-2 horas (seguridad) -- Tareas 9-10: 2 horas (demo y notificaciones) +- Tarea 1: 2 horas (modelo lims.test) +- Tarea 2: 1.5 horas (modelo lims.result) +- Tarea 3: 2 horas (interfaz de entrada) +- Tarea 4: 1 hora (lógica visual) +- Tarea 5: 1 hora (configuración) +- Tareas 6-7: 1.5 horas (vistas y demo) -**Total estimado: 15-18 horas** +**Total estimado: 9 horas** ## Dependencias - Issue #31: Configuración inicial del módulo ✓ - Issue #32: Generación automática de muestras ✓ -- Módulos de Odoo: sale, stock, mail, report +- Modelo lims.test.parameter (debe existir o crearse) +- Módulos de Odoo: sale, stock ## Riesgos y Mitigaciones -1. **Riesgo**: Complejidad en la entrada dinámica de resultados - - **Mitigación**: Comenzar con tipos básicos y expandir gradualmente +1. **Riesgo**: El modelo lims.test.parameter no está definido + - **Mitigación**: Crear modelo básico o usar product.product temporalmente -2. **Riesgo**: Performance con muchos parámetros por prueba - - **Mitigación**: Implementar paginación y carga diferida +2. **Riesgo**: Complejidad en la detección de valores fuera de rango + - **Mitigación**: Implementar lógica simple inicialmente -3. **Riesgo**: Formato de PDF no cumple expectativas - - **Mitigación**: Revisar ejemplos tempranos con usuario \ No newline at end of file +3. **Riesgo**: Integración con flujo existente de órdenes + - **Mitigación**: Crear pruebas manualmente en primera versión \ No newline at end of file diff --git a/gitea_cli_helper.py b/gitea_cli_helper.py index 4049758..97a2412 100644 --- a/gitea_cli_helper.py +++ b/gitea_cli_helper.py @@ -110,6 +110,60 @@ def close_issue(issue_number): _make_gitea_request("PATCH", endpoint, payload) print(f"Issue #{issue_number} cerrado exitosamente.") +def get_issue_details(issue_number): + """Gets details and comments for a specific issue.""" + # Get issue details + endpoint = f"repos/{GITEA_USERNAME}/{GITEA_REPO_NAME}/issues/{issue_number}" + print(f"Obteniendo detalles del issue #{issue_number}...") + + try: + issue = _make_gitea_request("GET", endpoint) + + # Display issue information + print(f"\n{'=' * 80}") + print(f"Issue #{issue.get('number', 'N/A')}: {issue.get('title', 'Sin título')}") + print(f"{'=' * 80}") + print(f"Estado: {'Abierto' if issue.get('state') == 'open' else 'Cerrado'}") + print(f"Autor: {issue.get('user', {}).get('login', 'Desconocido')}") + print(f"Creado: {issue.get('created_at', '').replace('T', ' ').split('+')[0] if issue.get('created_at') else 'N/A'}") + + if issue.get('closed_at'): + print(f"Cerrado: {issue.get('closed_at', '').replace('T', ' ').split('+')[0]}") + + labels = [label.get('name', '') for label in issue.get('labels', [])] + if labels: + print(f"Etiquetas: {', '.join(labels)}") + + print(f"URL: {issue.get('html_url', 'N/A')}") + + print(f"\nDescripción:") + print("-" * 40) + print(issue.get('body', 'Sin descripción')) + + # Get comments + comments_endpoint = f"{endpoint}/comments" + comments = _make_gitea_request("GET", comments_endpoint) + + if comments: + print(f"\nComentarios ({len(comments)}):") + print("-" * 40) + for i, comment in enumerate(comments, 1): + author = comment.get('user', {}).get('login', 'Desconocido') + created = comment.get('created_at', '').replace('T', ' ').split('+')[0] if comment.get('created_at') else 'N/A' + body = comment.get('body', '') + + print(f"\nComentario {i} - {author} ({created}):") + print(body) + if i < len(comments): + print("-" * 40) + else: + print(f"\nNo hay comentarios en este issue.") + + print(f"\n{'=' * 80}\n") + + except Exception as e: + print(f"Error al obtener el issue #{issue_number}: {e}") + def list_open_issues(): """Lists all open issues in the repository.""" endpoint = f"repos/{GITEA_USERNAME}/{GITEA_REPO_NAME}/issues" @@ -223,6 +277,10 @@ def main(): # Subparser para listar issues abiertos list_issues_parser = subparsers.add_parser("list-open-issues", help="Lista todos los issues abiertos del repositorio.") + + # Subparser para obtener detalles de un issue + get_issue_parser = subparsers.add_parser("get-issue", help="Obtiene detalles y comentarios de un issue específico.") + get_issue_parser.add_argument("--issue-number", type=int, required=True, help="Número del issue a consultar.") args = parser.parse_args() @@ -238,6 +296,8 @@ def main(): merge_pull_request(args.pr_number, args.merge_method) elif args.command == "list-open-issues": list_open_issues() + elif args.command == "get-issue": + get_issue_details(args.issue_number) else: parser.print_help()