# Instrucciones para el uso de `tea` CLI Este proyecto utiliza `tea` para interactuar con el repositorio de Gitea. ## Gestión de Gitea con `gitea_cli_helper.py` Para interactuar con el repositorio de Gitea (crear issues, pull requests, comentar y cerrar issues) de forma robusta y con soporte para contenido multilínea, se recomienda utilizar el script de Python `gitea_cli_helper.py`. Este script lee la configuración sensible directamente desde el archivo `.env`. ### Configuración Asegúrate de que las siguientes variables estén definidas en tu archivo `.env`: - `GITEA_API_KEY`: Tu Token de Acceso Personal (PAT) de Gitea. - `GITEA_API_KEY_URL`: La URL base de la API de tu instancia de Gitea (ej. `https://gitea.grupoconsiti.com/api/v1/`). - `GITEA_USERNAME`: Tu nombre de usuario de Gitea (propietario del repositorio). - `GITEA_REPO_NAME`: El nombre del repositorio (ej. `clinical_laboratory`). ### Uso El script `gitea_cli_helper.py` utiliza `argparse` para diferentes comandos: **IMPORTANTE**: Los archivos descriptivos (como `pr_description.txt`) creados para usar con el helper de Gitea: - Pueden crearse dentro del proyecto temporalmente - NO deben versionarse en git - Deben eliminarse después de ser utilizados por el helper - Se recomienda usar nombres descriptivos que faciliten su identificación para eliminación posterior #### 1. Crear un Issue ```bash python gitea_cli_helper.py create-issue --title "Título del Issue" --body "Descripción detallada del issue.\nSoporta múltiples líneas." ``` - `--title`: Título del issue. - `--body`: Cuerpo o descripción del issue. Los saltos de línea (`\n`) se interpretarán correctamente. #### 2. Crear un Pull Request ```bash python gitea_cli_helper.py create-pr --head "tu-rama" --base "rama-destino" --title "Título del PR" --body "Descripción del Pull Request.\nSoporta múltiples líneas." ``` - `--head`: Rama de origen (tu rama actual). - `--base`: Rama de destino (ej. `dev`, `main`). - `--title`: Título del Pull Request. - `--body`: Cuerpo o descripción del Pull Request. #### 3. Comentar en un Issue ```bash python gitea_cli_helper.py comment-issue --issue-number 123 --body "Este es un nuevo comentario.\nTambién soporta múltiples líneas." ``` - `--issue-number`: Número del issue al que se desea añadir el comentario. - `--body`: Contenido del comentario. #### 4. Cerrar un Issue ```bash python gitea_cli_helper.py close-issue --issue-number 123 ``` - `--issue-number`: Número del issue a cerrar. #### 5. Hacer Merge de un Pull Request ```bash python gitea_cli_helper.py merge-pr --pr-number 46 --merge-method merge ``` - `--pr-number`: Número del Pull Request a mergear. - `--merge-method`: Método de merge a utilizar. Opciones disponibles: `merge` (default), `squash`, `rebase`. **IMPORTANTE**: Solo se permite hacer merge a la rama `dev`. El script validará automáticamente que el PR tenga como destino la rama `dev` antes de proceder. Si el PR apunta a otra rama (como `main`), el merge será rechazado con un mensaje de error. **Ejemplo de uso:** ```bash # Merge estándar (commit de merge) python gitea_cli_helper.py merge-pr --pr-number 46 # Merge con squash (un solo commit con todos los cambios) python gitea_cli_helper.py merge-pr --pr-number 46 --merge-method squash # Merge con rebase (aplica commits individualmente sobre la rama base) python gitea_cli_helper.py merge-pr --pr-number 46 --merge-method rebase ``` El script también verifica: - Si el PR ya fue mergeado (mostrará mensaje informativo) - Si el PR está cerrado sin mergear (error) - Si el PR tiene conflictos o no es mergeable (error) #### 6. Listar Issues Abiertos ```bash python gitea_cli_helper.py list-open-issues ``` Lista todos los issues abiertos del repositorio, mostrando: - Número del issue - Título - Etiquetas (si las tiene) - Autor y fecha de creación - URL del issue **Ejemplo de salida:** ``` Issues abiertos (3): -------------------------------------------------------------------------------- #15: [Extensión Opcional] Integración con Calendario para Citas Autor: luis_portillo | Creado: 2025-07-12 URL: https://gitea.grupoconsiti.com/luis_portillo/clinical_laboratory/issues/15 #14: [Extensión Opcional] Portal Web para Pacientes/Médicos Autor: luis_portillo | Creado: 2025-07-12 URL: https://gitea.grupoconsiti.com/luis_portillo/clinical_laboratory/issues/14 -------------------------------------------------------------------------------- Total: 2 issues abiertos ``` --- ## Contexto del Proyecto Al iniciar cada sesión de trabajo, es **mandatorio** leer los siguientes documentos para comprender el contexto completo de los requerimientos y el diseño técnico: - `documents/requirements/RequerimientoInicial.md` - `documents/requirements/ToBeDesing.md` ## Levantamiento de la Instancia de Odoo 18 Para levantar la instancia efímera de Odoo 18 junto con la base de datos de PostgreSQL, se utiliza Docker Compose. **Comando de inicio:** ```bash docker-compose up -d ``` Este comando levantará los servicios definidos en el archivo `docker-compose.yml` en modo "detached" (`-d`). **Comando de detención y limpieza:** Para detener los servicios y asegurar un estado limpio, **siempre se deben eliminar los volúmenes**, a menos que se indique lo contrario. ```bash docker-compose down -v ``` ### Verificación de la Inicialización Después de levantar la instancia, es **mandatorio** verificar los registros del contenedor de inicialización para confirmar que los módulos se instalaron o actualizaron correctamente. **Comando para ver los logs:** ```bash docker-compose logs odoo_init ``` Busca errores en la salida. Si encuentras alguno, debes presentar un resumen del problema y sus posibles causas, como: - **Dependencias faltantes:** Un módulo no se puede instalar porque requiere otro que no está presente. - **Errores de sintaxis:** Problemas en archivos Python (`.py`) o XML (`.views`, `.xml`). - **Permisos incorrectos:** Problemas de acceso a archivos o directorios. - **Datos incorrectos:** Errores en los archivos de datos de demostración o iniciales. ### Política de Persistencia de la Instancia Después de una instalación o actualización exitosa, la instancia de Odoo **debe permanecer activa** para permitir la validación manual por parte del usuario. **No se debe detener la instancia** (`docker-compose down -v`) hasta que el usuario confirme explícitamente que ha finalizado sus pruebas. --- ## Convenciones de Desarrollo en Odoo 18 Para evitar errores recurrentes, es **mandatorio** seguir las siguientes convenciones específicas para Odoo 18, especialmente en lo que respecta a la definición de vistas. ### Uso de Vistas de Lista (Tree Views) En Odoo 18, la etiqueta `` ha sido **reemplazada por ``**. El uso de `` provocará un error de validación (`ValueError: Wrong value for ir.ui.view.type: 'tree'`). **Forma Incorrecta (Odoo < 18):** ```xml ``` **Forma Correcta (Odoo 18):** ```xml ``` ### Definición de Acciones de Ventana (`view_mode`) Consecuente con el cambio anterior, al definir una acción de ventana (`ir.actions.act_window`) que deba mostrar una vista de lista, el `view_mode` debe ser `'list,form'` en lugar de `'tree,form'`. **Forma Incorrecta:** ```xml Ejemplo example.model tree,form ``` **Forma Correcta:** ```xml Ejemplo example.model list,form ### Atributos de Visibilidad (`attrs`) A partir de Odoo 17, el atributo `attrs` para controlar la visibilidad de los elementos ha sido **reemplazado por el uso directo de `invisible`**. **Forma Incorrecta (Odoo < 17):** ```xml ``` **Forma Correcta (Odoo 18):** Se utiliza el atributo `invisible` con una expresión de dominio simplificada. La expresión se evalúa como verdadera para ocultar el campo. ```xml ``` O, de forma equivalente: ```xml ``` ### Uso de `ref()` en el Contexto de Acciones de Ventana La función `ref('module.xml_id')` se utiliza para obtener el ID de base de datos de un registro a partir de su ID XML. Sin embargo, esta función **solo existe en el servidor**. Cuando se define el `context` de una acción de ventana (`ir.actions.act_window`), este se evalúa en el cliente (navegador), donde `ref()` no está definido, causando un error `Name 'ref' is not defined`. Para solucionar esto, el `context` debe ser evaluado en el servidor utilizando el atributo `eval`. **Forma Incorrecta:** ```xml { 'default_categ_id': ref('lims_management.product_category_analysis') } ``` Esto envía la cadena `"{'default_categ_id': ref(...)}"` al cliente, que no puede procesarla. **Forma Correcta:** ```xml ``` Al usar `eval`, Odoo ejecuta la expresión en el servidor, reemplaza `ref(...)` por el ID numérico correspondiente, y envía un diccionario JSON válido al cliente. ### Herencia de Vistas y XPath Al heredar vistas para modificarlas, es crucial que las expresiones `XPath` sean precisas. Un error común es hacer referencia a campos o estructuras que han cambiado en la nueva versión de Odoo. **Ejemplo de Error:** Al intentar modificar las líneas de una orden de venta (`sale.order`), una expresión XPath que funcionaba en versiones anteriores puede fallar en Odoo 18. **Expresión Incorrecta (para Odoo < 18):** ```xml [('is_analysis', '=', True)] ``` Esta expresión falla por dos razones: 1. La vista de líneas ahora usa `` en lugar de ``. 2. El campo del producto en las líneas de venta es `product_id`, no `product_template_id`. **Expresión Correcta (para Odoo 18):** Para hacer la expresión más robusta y compatible, se puede usar `//` para buscar en cualquier nivel descendiente. ```xml [('is_analysis', '=', True)] ``` Esta expresión busca el campo `product_id` dentro del campo `order_line`, sin importar si está dentro de una etiqueta `` o ``, haciendo la herencia más resistente a cambios menores de estructura. --- ## Consultar la Base de Datos con un Script Interactuar con la base de datos directamente usando `psql` a través de `docker-compose exec` puede ser complicado debido a la forma en que el shell maneja las comillas. Una alternativa más robusta y confiable es utilizar un script de Python que aproveche el ORM de Odoo. ### Procedimiento 1. **Crear un Script de Python:** Crea un script que se conecte a la base de datos y ejecute la consulta deseada. **Ejemplo (`verify_products.py`):** ```python import odoo import json def verify_lab_order_products(cr): cr.execute(""" SELECT so.name AS order_name, sol.id AS line_id, pt.name->>'en_US' AS product_name, pt.is_analysis FROM sale_order so JOIN sale_order_line sol ON so.id = sol.order_id JOIN product_product pp ON sol.product_id = pp.id JOIN product_template pt ON pp.product_tmpl_id = pt.id WHERE so.is_lab_request = TRUE; """) 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. **Copiar el Script al Contenedor:** Usa el comando `docker cp` para copiar el script al contenedor de Odoo. ```bash docker cp verify_products.py lims_odoo:/tmp/verify_products.py ``` 3. **Ejecutar el Script:** Ejecuta el script dentro del contenedor usando `docker-compose exec`. ```bash docker-compose exec odoo python3 /tmp/verify_products.py ``` Este método evita los problemas de entrecomillado y permite ejecutar consultas complejas de manera confiable. --- ## Creación de Datos de Demostración Complejos Cuando los datos de demostración tienen dependencias complejas o requieren lógica de negocio (por ejemplo, cambiar el estado de un registro, o crear registros relacionados que dependen de otros), el uso de archivos XML puede ser limitado y propenso a errores de carga. En estos casos, es preferible utilizar un script de Python para crear los datos de demostración. ### Procedimiento 1. **Crear un Script de Python:** Crea un script que utilice el ORM de Odoo para crear los registros de demostración. Esto permite utilizar la lógica de negocio de los modelos, como los métodos `create` y `write`, y buscar registros existentes con `search` y `ref`. **Ejemplo (`create_lab_requests.py`):** ```python import odoo def create_lab_requests(cr): env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {}) # Eliminar órdenes de venta de demostración no deseadas unwanted_orders = env['sale.order'].search([('name', 'in', ['S00001', ...])]) for order in unwanted_orders: try: order.action_cancel() except Exception: pass try: unwanted_orders.unlink() except Exception: pass # Crear solicitudes de laboratorio patient1 = env.ref('lims_management.demo_patient_1') doctor1 = env.ref('lims_management.demo_doctor_1') hemograma = env.ref('lims_management.analysis_hemograma') env['sale.order'].create({ 'partner_id': patient1.id, 'doctor_id': doctor1.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. **Integrar el Script en la Inicialización:** Modifica el script `init_odoo.py` para que ejecute el script de creación de datos después de que Odoo haya terminado de instalar los módulos. **En `docker-compose.yml`**, asegúrate de que el script esté disponible en el contenedor `odoo_init`: ```yaml volumes: - ./create_lab_requests.py:/app/create_lab_requests.py ``` **En `init_odoo.py`**, añade la lógica para ejecutar el script: ```python # --- Lógica para crear datos de demostración personalizados --- print("Creando datos de demostración complejos...") sys.stdout.flush() with open("/app/create_lab_requests.py", "r") as f: script_content = f.read() create_requests_command = f""" odoo shell -c {ODOO_CONF} -d {DB_NAME} <<'EOF' {script_content} EOF """ result = subprocess.run( create_requests_command, shell=True, capture_output=True, text=True, check=False ) ``` Este enfoque proporciona un control total sobre la creación de datos de demostración y evita los problemas de dependencia y orden de carga de los archivos XML.