# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Notifications When tasks complete, or you need autorizathion for an action notify me using: powershell.exe -c "[System.Media.SystemSounds]::Beep.Play()" ## Project Overview This is a Laboratory Information Management System (LIMS) module for Odoo 18 ERP, specifically designed for clinical laboratories. The module manages patients, samples, analyses, and test results. ## Key Technologies - **Odoo 18**: ERP framework (Python-based) - **PostgreSQL 15**: Database - **Docker & Docker Compose**: Containerization - **Gitea**: Version control and issue tracking ## Development Commands ### Starting the Environment ```bash # Start all services docker-compose up -d # MANDATORY: View initialization logs to check for errors docker-compose logs odoo_init # Stop and clean everything (removes volumes) docker-compose down -v ``` **IMPORTANT**: Odoo initialization takes approximately 5 minutes. When using docker-compose commands, set timeout to 5 minutes (300000ms) to avoid premature timeouts. ### Instance Persistence Policy After successful installation/update, the instance must remain active for user validation. Do NOT stop the instance until user explicitly confirms testing is complete. ### MANDATORY Testing Rule **CRITICAL**: After EVERY task that modifies code, models, views, or data: 1. Restart the ephemeral instance: `docker-compose down -v && docker-compose up -d` 2. Check initialization logs for errors: `docker-compose logs odoo_init | grep -i "error\|traceback\|exception"` 3. Verify successful completion: `docker-compose logs odoo_init | tail -30` 4. Only proceed to next task if no errors are found 5. If errors are found, fix them before continuing ### Development Workflow per Task When implementing issues with multiple tasks, follow this workflow for EACH task: 1. **Stop instance**: `docker-compose down -v` 2. **Implement the task**: Make code changes 3. **Start instance**: `docker-compose up -d` (timeout: 300000ms) 4. **Validate logs**: Check for errors in initialization 5. **Commit & Push**: `git add -A && git commit -m "feat(#X): Task description" && git push` 6. **Comment on issue**: Update issue with task completion 7. **Mark task completed**: Update todo list 8. **Proceed to next task**: Only if no errors found ### Database Operations #### Direct PostgreSQL Access ```bash # Connect to PostgreSQL docker exec -it lims_db psql -U odoo -d odoo ``` #### Python Script Method (Recommended) For complex queries, use Python scripts with Odoo ORM: 1. Create script (e.g., `test/verify_products.py`): ```python import odoo import json def verify_lab_order_products(cr): cr.execute("""SELECT ... FROM sale_order ...""") return cr.fetchall() if __name__ == '__main__': db_name = 'lims_demo' registry = odoo.registry(db_name) with registry.cursor() as cr: results = verify_lab_order_products(cr) print(json.dumps(results, indent=4)) ``` 2. Copy to container: ```bash docker cp test/verify_products.py lims_odoo:/tmp/verify_products.py ``` 3. Execute: ```bash docker-compose exec odoo python3 /tmp/verify_products.py ``` ### Gitea Integration ```bash # Create issue python utils/gitea_cli_helper.py create-issue --title "Title" --body "Description\nSupports multiple lines" # Create PR with inline description python utils/gitea_cli_helper.py create-pr --head "feature-branch" --base "dev" --title "Title" --body "Description" # Create PR with description from file python utils/gitea_cli_helper.py create-pr dev --title "feat(#31): Sample lifecycle" --description-file pr_description.txt # Comment on issue python utils/gitea_cli_helper.py comment-issue --issue-number 123 --body "Comment text" # Close issue python utils/gitea_cli_helper.py close-issue --issue-number 123 # Get issue details and comments python utils/gitea_cli_helper.py get-issue --issue-number 8 # List all open issues python utils/gitea_cli_helper.py list-open-issues ``` ## Mandatory Reading At the start of each work session, read these documents to understand requirements and technical design: - `documents/requirements/RequerimientoInicial.md` - `documents/requirements/ToBeDesing.md` ## Code Architecture ### Module Structure - **lims_management/models/**: Core business logic - `partner.py`: Patient and healthcare provider management - `product.py`: Analysis types and categories - `sale_order.py`: Analysis orders and sample management - `stock_lot.py`: Sample tracking and lifecycle - `analysis_range.py`: Normal ranges for test results ### Odoo 18 Specific Conventions #### View Definitions - **CRITICAL**: Use `` instead of `` in view XML - using `` causes error "El nodo raíz de una vista list debe ser , no " - View mode in actions must be `tree,form` not `list,form` (paradójicamente, el modo se llama "tree" pero el XML debe usar ``) #### Visibility Attributes - Use `invisible` attribute directly instead of `attrs`: ```xml ``` #### Context with ref() - Use `eval` attribute when using `ref()` in action contexts: ```xml {'default_categ_id': ref('module.xml_id')} ``` #### XPath in View Inheritance - Use flexible XPath expressions for robustness: ```xml [('is_analysis', '=', True)] ``` ### Data Management - **Initial Data**: `lims_management/data/` - Sequences, categories, basic configuration - **Demo Data**: - XML files in `lims_management/demo/` - Python scripts in `test/` directory for complex demo data creation - Use `noupdate="1"` for demo data to prevent reloading ### Security Model - Access rights defined in `security/ir.model.access.csv` - Field-level security in `security/security.xml` - Group-based permissions: Laboratory Technician, Manager, etc. ## Environment Variables Required in `.env` file: - `GITEA_API_KEY`: Personal Access Token for Gitea - `GITEA_API_KEY_URL`: Gitea API base URL (e.g., `https://gitea.grupoconsiti.com/api/v1/`) - `GITEA_USERNAME`: Gitea username (repository owner) - `GITEA_REPO_NAME`: Repository name (e.g., `clinical_laboratory`) ## Important Patterns ### Sample Lifecycle States ```python STATE_PENDING_COLLECTION = 'pending_collection' STATE_COLLECTED = 'collected' STATE_IN_ANALYSIS = 'in_analysis' STATE_COMPLETED = 'completed' STATE_CANCELLED = 'cancelled' ``` ### Barcode Generation - 13-digit format: YYMMDDNNNNNNC - Uses `barcode` Python library for Code-128 generation - Stored as PDF with human-readable text ### Demo Data Creation #### XML Files (Simple Data) - Use for basic records without complex dependencies - Place in `lims_management/demo/` - Use `noupdate="1"` to prevent reloading - **IMPORTANT**: Do NOT create sale.order records in XML demo files - use Python scripts instead #### Python Scripts (Complex Data) For data with dependencies or business logic: #### Test Scripts - **IMPORTANT**: Always create test scripts inside the `test/` folder within the project directory - Example: `test/test_sample_generation.py` - This ensures scripts are properly organized and accessible 1. Create script: ```python import odoo def create_lab_requests(cr): env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {}) # Use ref() to get existing records patient1 = env.ref('lims_management.demo_patient_1') hemograma = env.ref('lims_management.analysis_hemograma') # Create records with business logic env['sale.order'].create({ 'partner_id': patient1.id, 'is_lab_request': True, 'order_line': [(0, 0, { 'product_id': hemograma.product_variant_id.id, 'product_uom_qty': 1 })] }) if __name__ == '__main__': db_name = 'lims_demo' registry = odoo.registry(db_name) with registry.cursor() as cr: create_lab_requests(cr) cr.commit() ``` 2. Integrate in initialization or run separately ## Git Workflow ### Pre-commit Hook Automatically installed via `scripts/install_hooks.sh`: - Prevents commits to 'main' or 'dev' branches - Enforces feature branch workflow ### Branch Naming - Feature branches: `feature/XX-description` (where XX is issue number) - Always create PRs to 'dev' branch, not 'main' ## Desarrollo de nuevos modelos y vistas ### Orden de carga en **manifest**.py Al agregar archivos al manifest, seguir SIEMPRE este orden: 1. security/\*.xml (grupos y categorías) 2. security/ir.model.access.csv 3. data/\*.xml (secuencias, categorías, datos base) 4. views/\*\_views.xml en este orden específico: - Modelos base (sin dependencias) - Modelos dependientes - Vistas que referencian acciones - menus.xml (SIEMPRE al final de views) 5. wizards/\*.xml 6. reports/\*.xml 7. demo/\*.xml ### Desarrollo de modelos relacionados Cuando crees modelos que se relacionan entre sí en el mismo issue: #### Fase 1: Modelos base 1. Crear modelos SIN campos One2many 2. Solo incluir campos básicos y Many2one si el modelo referenciado ya existe 3. Probar que la instancia levante #### Fase 2: Relaciones 1. Agregar campos One2many en los modelos padre 2. Verificar que todos los inverse_name existan 3. Probar nuevamente #### Fase 3: Vistas complejas 1. Agregar vistas con referencias a acciones 2. Verificar que las acciones referenciadas ya estén definidas ### Contextos en vistas XML - En formularios: usar `id` (NO `active_id`) - En acciones de ventana: usar `active_id` - En campos One2many: usar `parent` para referenciar el registro padre ### Checklist antes de reiniciar instancia - [ ] ¿Los modelos referenciados en relaciones ya existen? - [ ] ¿Las acciones/vistas referenciadas se cargan ANTES? - [ ] ¿Los grupos en ir.model.access.csv coinciden con los de security.xml? - [ ] ¿Usaste `id` en lugar de `active_id` en contextos de formulario? - [ ] ¿Verificaste que todos los campos en las vistas existen en los modelos? - [ ] ¿Los nombres de métodos/acciones coinciden exactamente con los definidos en Python? - [ ] ¿Los widgets utilizados son válidos en Odoo 18? ### Desarrollo de vistas - Mejores prácticas #### Antes de crear vistas: 1. **Verificar campos del modelo**: SIEMPRE revisar qué campos existen con `grep "fields\." models/archivo.py` 2. **Verificar métodos disponibles**: Buscar métodos con `grep "def action_" models/archivo.py` 3. **Verificar campos relacionados**: Confirmar que los campos related tienen la ruta correcta #### Orden de creación de vistas: 1. **Primero**: Definir todas las acciones (ir.actions.act_window) en un solo lugar 2. **Segundo**: Crear las vistas (form, list, search, etc.) 3. **Tercero**: Crear los menús que referencian las acciones 4. **Cuarto**: Si hay referencias cruzadas entre archivos, considerar consolidar en un solo archivo #### Widgets válidos en Odoo 18: - Numéricos: `float`, `integer`, `monetary` (NO `float_time` para datos generales) - Texto: `text`, `char`, `html` (NO `text_emojis`) - Booleanos: `boolean`, `boolean_toggle`, `boolean_button` - Selección: `selection`, `radio`, `selection_badge` - Relaciones: `many2one`, `many2many_tags` - Estado: `statusbar`, `badge`, `progressbar` #### Errores comunes y soluciones: ##### Error: "External ID not found" - **Causa**: Referencia a un ID que aún no fue cargado - **Solución**: Reorganizar orden en **manifest**.py o mover definición al mismo archivo ##### Error: "Field 'X' does not exist" - **Causa**: Vista referencia campo inexistente en el modelo - **Solución**: Verificar modelo y agregar campo o corregir nombre en vista ##### Error: "action_X is not a valid action" - **Causa**: Nombre de método incorrecto en botón - **Solución**: Verificar nombre exacto del método en el modelo Python ##### Error: "Invalid widget" - **Causa**: Uso de widget no existente o deprecated - **Solución**: Usar widgets estándar de Odoo 18 #### Estrategia de depuración: 1. Leer el error completo en los logs 2. Identificar archivo y línea exacta del problema 3. Verificar que el elemento referenciado existe y está accesible 4. Si es necesario, simplificar la vista temporalmente para aislar el problema ### Manejo de códigos de barras en reportes QWeb (Odoo 18) #### Generación de códigos de barras Para mostrar códigos de barras en reportes PDF, usar el widget nativo de Odoo: ```xml ``` #### Consideraciones importantes: 1. **NO usar** rutas directas como `/report/barcode/Code128/` - esta sintaxis está deprecated 2. **Usar siempre** `t-field` con el widget barcode para renderizado correcto 3. **Parámetros disponibles** en t-options: - `type`: Tipo de código ('Code128', 'EAN13', 'QR', etc.) - `width`: Ancho en píxeles - `height`: Alto en píxeles - `humanreadable`: 1 para mostrar texto legible, 0 para ocultarlo #### Problemas comunes y soluciones: ##### Código de barras vacío en PDF - **Causa**: Campo computed sin store=True o sintaxis incorrecta - **Solución**: Asegurar que el campo esté almacenado y usar widget barcode ##### Caracteres especiales en reportes (tildes, ñ) - **Problema**: Aparecen como "ñ" o "í" en lugar de "ñ" o "í" - **Solución**: Usar referencias numéricas de caracteres XML: ```xml

LABORATORIO CLÍNICO

LABORATORIO CLÍNICO

``` - í = í - Í = Í - á = á - Á = Á - é = é - É = É - ó = ó - Ó = Ó - ú = ú - Ú = Ú - ñ = ñ - Ñ = Ñ ##### Layout de etiquetas múltiples por página ```xml
```