From b9d43838da9528feb30bf491481993239b207932 Mon Sep 17 00:00:00 2001 From: Luis Ernesto Portillo Zaldivar Date: Sat, 12 Jul 2025 16:15:02 -0600 Subject: [PATCH 1/5] \"feat(lims): Initial scaffolding for LIMS module\" --- lims_management/__init__.py | 3 ++ lims_management/__manifest__.py | 28 ++++++++++++++ lims_management/models/__init__.py | 1 + lims_management/security/ir.model.access.csv | 1 + lims_management/security/lims_security.xml | 37 ++++++++++++++++++ lims_management/views/menus.xml | 40 ++++++++++++++++++++ 6 files changed, 110 insertions(+) create mode 100644 lims_management/__init__.py create mode 100644 lims_management/__manifest__.py create mode 100644 lims_management/models/__init__.py create mode 100644 lims_management/security/ir.model.access.csv create mode 100644 lims_management/security/lims_security.xml create mode 100644 lims_management/views/menus.xml diff --git a/lims_management/__init__.py b/lims_management/__init__.py new file mode 100644 index 0000000..cde864b --- /dev/null +++ b/lims_management/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/lims_management/__manifest__.py b/lims_management/__manifest__.py new file mode 100644 index 0000000..3e68aef --- /dev/null +++ b/lims_management/__manifest__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Gestión de Laboratorio Clínico (LIMS)", + 'summary': """ + Módulo para la gestión integral de un laboratorio clínico, desde la + recepción de pacientes hasta la entrega de resultados.""", + 'description': """ + Este módulo cubre todo el flujo de trabajo de un laboratorio clínico: + - Registro de pacientes y órdenes de laboratorio. + - Gestión y trazabilidad de muestras. + - Ingreso y validación de resultados. + - Generación de informes en PDF. + - Integración con Facturación, Ventas e Inventario de Odoo. + """, + 'author': "Gemini", + 'website': "https://gitea.grupoconsiti.com/luis_portillo/clinical_laboratory", + 'category': 'Industries', + 'version': '18.0.1.0.0', + 'depends': ['base', 'sale_management', 'stock', 'account'], + 'data': [ + 'security/lims_security.xml', + 'security/ir.model.access.csv', + 'views/menus.xml', + ], + 'installable': True, + 'application': True, + 'auto_install': False, +} diff --git a/lims_management/models/__init__.py b/lims_management/models/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/lims_management/models/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/lims_management/security/ir.model.access.csv b/lims_management/security/ir.model.access.csv new file mode 100644 index 0000000..97dd8b9 --- /dev/null +++ b/lims_management/security/ir.model.access.csv @@ -0,0 +1 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink diff --git a/lims_management/security/lims_security.xml b/lims_management/security/lims_security.xml new file mode 100644 index 0000000..c72d725 --- /dev/null +++ b/lims_management/security/lims_security.xml @@ -0,0 +1,37 @@ + + + + + Laboratorio + Permisos y roles para el módulo de Laboratorio Clínico. + 20 + + + + Laboratorio / Recepcionista + + + + El usuario puede registrar pacientes, crear órdenes de laboratorio y generar facturas. No tiene acceso a los resultados clínicos. + + + + + Laboratorio / Técnico + + + + El usuario puede gestionar muestras, registrar la toma e ingresar resultados de los análisis. No puede validar resultados. + + + + + Laboratorio / Administrador + + + + El usuario tiene acceso completo al módulo LIMS, incluyendo la validación de resultados, configuración y reportes. + + + + diff --git a/lims_management/views/menus.xml b/lims_management/views/menus.xml new file mode 100644 index 0000000..9b9876a --- /dev/null +++ b/lims_management/views/menus.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + From 00db7e7b735504a51e65f58a1adcca672bd64d97 Mon Sep 17 00:00:00 2001 From: Luis Ernesto Portillo Zaldivar Date: Sat, 12 Jul 2025 16:17:27 -0600 Subject: [PATCH 2/5] \"docs: Update GEMINI.md with commit message instructions\" --- GEMINI.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/GEMINI.md b/GEMINI.md index 0942cbd..8b40a3c 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -12,4 +12,26 @@ tea issue create --title "Título del Issue" --description "Descripción detalla - `--title`: Especifica el título del issue. - `--description`: Especifica la descripción o cuerpo del issue. -- `--labels`: Especifica una o más etiquetas separadas por comas. \ No newline at end of file +- `--labels`: Especifica una o más etiquetas separadas por comas. + +--- + +## Realizar Commits + +Debido a problemas de interpretación de comillas en el shell de ejecución, el uso de `git commit -m "mensaje"` puede fallar. Para evitar estos problemas, se debe pasar el mensaje del commit a través de la entrada estándar (`stdin`). + +### Método Recomendado + +Utiliza el comando `echo` y una tubería (`|`) para enviar el mensaje a `git commit -F -`. + +**Commit de una sola línea:** +```bash +echo "feat(scope): Tu mensaje de commit conciso" | git commit -F - +``` + +**Commit multilínea:** +Para mensajes de commit multilínea, la forma más segura es usar `printf` que maneja mejor los saltos de línea (`\n`): +```bash +printf "feat(scope): Título del commit\n\nCuerpo del mensaje con una descripción más detallada.\n\n- Un punto importante.\n- Otro punto importante.\n\nResolves: #123" | git commit -F - +``` +Esto asegura que el formato del mensaje del commit se preserve correctamente. From f7b92025bfd6d79bc54676000af6db139b40ea76 Mon Sep 17 00:00:00 2001 From: Luis Ernesto Portillo Zaldivar Date: Sat, 12 Jul 2025 17:02:45 -0600 Subject: [PATCH 3/5] \"docs(gemini): Aclarar uso del comando 'tea comment'\" --- GEMINI.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/GEMINI.md b/GEMINI.md index 8b40a3c..f8866bb 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -16,6 +16,23 @@ tea issue create --title "Título del Issue" --description "Descripción detalla --- +## Comentar en un Issue + +Para agregar un comentario a un issue existente, se utiliza el comando `comment` seguido del número del issue y el texto del comentario entre comillas. + +**Formato correcto:** +```bash +tea comment "Tu comentario aquí" +``` +**Ejemplo:** +```bash +tea comment 3 "Comentario de prueba" +``` + +**Nota:** No se deben utilizar flags como `-i` o `--message`. El formato es directo. + +--- + ## Realizar Commits Debido a problemas de interpretación de comillas en el shell de ejecución, el uso de `git commit -m "mensaje"` puede fallar. Para evitar estos problemas, se debe pasar el mensaje del commit a través de la entrada estándar (`stdin`). @@ -35,3 +52,28 @@ Para mensajes de commit multilínea, la forma más segura es usar `printf` que m printf "feat(scope): Título del commit\n\nCuerpo del mensaje con una descripción más detallada.\n\n- Un punto importante.\n- Otro punto importante.\n\nResolves: #123" | git commit -F - ``` Esto asegura que el formato del mensaje del commit se preserve correctamente. + +--- + +## 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:** +```bash +docker-compose up -d +``` + +Este comando levantará los servicios definidos en el archivo `docker-compose.yml` en modo "detached" (`-d`), lo que significa que se ejecutarán en segundo plano. + +Para detener los servicios, utiliza: +```bash +docker-compose down +``` \ No newline at end of file From f9a3e3e7f27aef4b7d862ecf68970acdb622e5a2 Mon Sep 17 00:00:00 2001 From: Luis Ernesto Portillo Zaldivar Date: Sun, 13 Jul 2025 17:00:15 -0600 Subject: [PATCH 4/5] \"docs(#3): Actualizar instrucciones de PR en GEMINI.md\" --- GEMINI.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/GEMINI.md b/GEMINI.md index f8866bb..ce926f7 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -55,6 +55,26 @@ Esto asegura que el formato del mensaje del commit se preserve correctamente. --- +## Crear un Pull Request + +Para crear un pull request (PR), se utiliza el comando `tea pulls create`. Debes especificar la rama base (hacia donde van los cambios) y la rama `head` (tu rama actual), junto con un título que referencie el issue que resuelve. + +**Formato del comando:** +```bash +tea pulls create --base "" --head "" --title "(#issue): Título descriptivo" +``` + +**Ejemplo:** +```bash +tea pulls create --base "dev" --head "feature/3-core-setup" --title "feat(#3): Actualiza instrucciones en GEMINI.md" +``` + +- `--base`: La rama de destino (ej. `dev`, `main`). +- `--head`: Tu rama de trabajo actual. +- `--title`: Un título claro que incluya el tipo de cambio (`feat`, `fix`, `docs`) y el número de issue. + +--- + ## 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: From 38365e6e413c40f4d0773dcf9181a3f92b1f6675 Mon Sep 17 00:00:00 2001 From: Luis Ernesto Portillo Zaldivar Date: Sun, 13 Jul 2025 17:07:59 -0600 Subject: [PATCH 5/5] configuraciones instancia efimera odoo 18 --- .env | 11 +++ Dockerfile | 17 +++++ docker-compose.yml | 63 ++++++++++++++++ init_odoo.py | 68 ++++++++++++++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 178 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 149 bytes odoo.conf | 10 +++ wait_and_start_odoo.py | 46 ++++++++++++ 8 files changed, 215 insertions(+) create mode 100644 .env create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 init_odoo.py create mode 100644 lims_management/__pycache__/__init__.cpython-312.pyc create mode 100644 lims_management/models/__pycache__/__init__.cpython-312.pyc create mode 100644 odoo.conf create mode 100644 wait_and_start_odoo.py diff --git a/.env b/.env new file mode 100644 index 0000000..ca51609 --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +# Variables de entorno para el entorno de Docker de Odoo + +# PostgreSQL +POSTGRES_DB=postgres +POSTGRES_USER=odoo +POSTGRES_PASSWORD=supersegura + +# Odoo +ODOO_DB_NAME=lims_demo +ODOO_MASTER_PASSWORD=admin +ODOO_WEB_PORT=8069 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..813c087 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# Usa la imagen oficial de Odoo 18 +FROM odoo:18.0 + +# Establece la variable de entorno para el archivo de configuración +ENV ODOO_RC /etc/odoo/odoo.conf + +# Copia el archivo de configuración de Odoo al contenedor +COPY odoo.conf /etc/odoo/odoo.conf + +# Opcional: Cambia los permisos del archivo de configuración +USER root +RUN chown odoo:odoo /etc/odoo/odoo.conf +USER odoo + +# El CMD por defecto de la imagen de Odoo usará ODOO_RC +# y los parámetros del docker-compose para iniciar. +# No es necesario sobreescribir el CMD si pasamos las variables correctas. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3538b1c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,63 @@ + +services: + # ──────────────────────────────────────────── + # PostgreSQL + # ──────────────────────────────────────────── + db: + image: postgres:15 + container_name: lims_db + environment: + POSTGRES_DB: postgres # BD catálogo + POSTGRES_USER: odoo # rol que usará Odoo + POSTGRES_PASSWORD: supersegura # contraseña del rol + volumes: + - db_data:/var/lib/postgresql/data + restart: unless-stopped + + # ──────────────────────────────────────────── + # Job de inicialización (se ejecuta una vez) + # ──────────────────────────────────────────── + odoo_init: + image: odoo:18.0 + depends_on: [db] + volumes: + - ./lims_management:/mnt/extra-addons/lims_management + - ./odoo.conf:/etc/odoo/odoo.conf + - ./init_odoo.py:/app/init_odoo.py + command: ["/usr/bin/python3", "/app/init_odoo.py"] + environment: + HOST: db + PORT: "5432" + USER: odoo + PASSWORD: supersegura + restart: "no" + + + # ──────────────────────────────────────────── + # Odoo (servicio de larga vida) + # ──────────────────────────────────────────── + odoo: + image: odoo:18.0 + container_name: lims_odoo + depends_on: + db: + condition: service_started + odoo_init: + condition: service_completed_successfully + environment: + HOST: db + PORT: "5432" + USER: odoo + PASSWORD: supersegura + MASTER_PASSWORD: admin123 + command: ["/usr/bin/python3", "/app/wait_and_start_odoo.py"] + ports: + - "8069:8069" + volumes: + - ./lims_management:/mnt/extra-addons/lims_management + - ./odoo.conf:/etc/odoo/odoo.conf + - ./wait_and_start_odoo.py:/app/wait_and_start_odoo.py + restart: unless-stopped + +volumes: + db_data: {} diff --git a/init_odoo.py b/init_odoo.py new file mode 100644 index 0000000..ba8762c --- /dev/null +++ b/init_odoo.py @@ -0,0 +1,68 @@ +import socket +import time +import subprocess +import sys +import os + +# --- Configuración --- +DB_HOST = os.environ.get("HOST", "db") +DB_PORT = int(os.environ.get("PORT", 5432)) +ODOO_CONF = "/etc/odoo/odoo.conf" +DB_NAME = "lims_demo" +MODULES_TO_INSTALL = "base,sale_management,stock,account,lims_management" + +# --- Lógica de espera de PostgreSQL --- +print(f"Esperando a PostgreSQL en {DB_HOST}:{DB_PORT}...") +sys.stdout.flush() + +while True: + try: + with socket.create_connection((DB_HOST, DB_PORT), timeout=2): + print("PostgreSQL está listo.") + sys.stdout.flush() + break + except (socket.timeout, ConnectionRefusedError, OSError) as e: + print(f"PostgreSQL no está listo todavía ({e}), esperando...") + sys.stdout.flush() + time.sleep(2) + +# --- Lógica de inicialización de Odoo --- +print(f"Creando base de datos '{DB_NAME}' e instalando módulos...") +sys.stdout.flush() + +odoo_command = [ + "odoo", + "-c", ODOO_CONF, + "-d", DB_NAME, + "-i", MODULES_TO_INSTALL, + "--stop-after-init" +] + +# Usamos subprocess.run para tener mejor control sobre la salida +try: + result = subprocess.run( + odoo_command, + capture_output=True, + text=True, + check=False + ) + + print("--- Odoo stdout ---") + print(result.stdout) + print("--- Odoo stderr ---") + print(result.stderr) + sys.stdout.flush() + + if result.returncode != 0: + print(f"Odoo falló con código de salida {result.returncode}") + sys.exit(result.returncode) + + print("Inicialización de Odoo completada exitosamente.") + sys.exit(0) + +except FileNotFoundError: + print("Error: El comando 'odoo' no se encontró. Asegúrate de que la imagen del contenedor es correcta y odoo está en el PATH.") + sys.exit(1) +except Exception as e: + print(f"Ocurrió un error inesperado al ejecutar Odoo: {e}") + sys.exit(1) diff --git a/lims_management/__pycache__/__init__.cpython-312.pyc b/lims_management/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52b6a3e2af34465b7b5ec203af1f61b7abb0dacc GIT binary patch literal 178 zcmX@j%ge<81ds0)W$1xu5C;aBpp4G~K*n^26owSW9EM!RC`LwxN+wO_myAGRO~zYn zx%nxnImLdOOt%<{n1Ny|89sw_{?gUY%`4GQttcr<)J;rD$umKuWnv-f*!~xU|GQ1e%whzpVjEvvd7#Ky1*nnIBzK$xV literal 0 HcmV?d00001 diff --git a/lims_management/models/__pycache__/__init__.cpython-312.pyc b/lims_management/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6650407c7a1bc7ea24c5d8cc549137c6024116f6 GIT binary patch literal 149 zcmX@j%ge<81kdgkWk>+&#~=-5!pP83g5+AQuQ2C3)1}IpXlWJGQ V3N(Zfh>JmtkIamWj77{q761c1B%=TT literal 0 HcmV?d00001 diff --git a/odoo.conf b/odoo.conf new file mode 100644 index 0000000..b4a8c54 --- /dev/null +++ b/odoo.conf @@ -0,0 +1,10 @@ +[options] +admin_passwd = admin123 +db_host = db +db_port = 5432 +db_user = odoo +db_password = supersegura +addons_path = /mnt/extra-addons,/usr/lib/python3/dist-packages/odoo/addons +demo = True +dbfilter = ^lims_demo$ +log_level = info diff --git a/wait_and_start_odoo.py b/wait_and_start_odoo.py new file mode 100644 index 0000000..b2f9edb --- /dev/null +++ b/wait_and_start_odoo.py @@ -0,0 +1,46 @@ +import socket +import time +import os +import sys + +# --- Configuración de la base de datos (leída desde el entorno) --- +DB_HOST = os.environ.get("HOST", "db") +DB_PORT = int(os.environ.get("PORT", 5432)) + +# --- Lógica de espera de PostgreSQL --- +print(f"Servicio Odoo: Esperando a PostgreSQL en {DB_HOST}:{DB_PORT}...") +sys.stdout.flush() + +# Usamos un bucle para intentar la conexión hasta que tenga éxito +while True: + try: + # Intenta crear una conexión de socket + with socket.create_connection((DB_HOST, DB_PORT), timeout=5): + print("Servicio Odoo: PostgreSQL está listo y aceptando conexiones.") + sys.stdout.flush() + break # Sale del bucle si la conexión es exitosa + except (socket.timeout, ConnectionRefusedError, OSError) as e: + print(f"Servicio Odoo: PostgreSQL no está listo todavía ({e}). Reintentando en 2 segundos...") + sys.stdout.flush() + time.sleep(2) + +# --- Iniciar Odoo --- +print("Servicio Odoo: PostgreSQL listo. Iniciando Odoo...") +sys.stdout.flush() + +# Argumentos para Odoo. Odoo leerá la configuración principal +# desde /etc/odoo/odoo.conf y las variables de entorno. +# El db-filter se pasa como argumento explícito. +odoo_args = ["odoo", "--db-filter=^lims_demo$"] + +# Reemplaza el proceso actual con Odoo. +# Esto es crucial para que Odoo sea el proceso principal (PID 1) +# y reciba las señales del sistema (ej. para detenerse). +try: + os.execvp("odoo", odoo_args) +except FileNotFoundError: + print("Error fatal: El comando 'odoo' no se encontró en el PATH del contenedor.", file=sys.stderr) + sys.exit(127) +except Exception as e: + print(f"Error fatal al intentar ejecutar Odoo: {e}", file=sys.stderr) + sys.exit(1)