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/GEMINI.md b/GEMINI.md index 0942cbd..ce926f7 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -12,4 +12,88 @@ 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. + +--- + +## 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`). + +### 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. + +--- + +## 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: + +- `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 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/__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/__pycache__/__init__.cpython-312.pyc b/lims_management/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..52b6a3e Binary files /dev/null and b/lims_management/__pycache__/__init__.cpython-312.pyc differ 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/models/__pycache__/__init__.cpython-312.pyc b/lims_management/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..6650407 Binary files /dev/null and b/lims_management/models/__pycache__/__init__.cpython-312.pyc differ 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 @@ + + + + + + + + + + + + + + + + + + + + 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)