Merge pull request 'feat(#3): Setup core files' (#23) from feature/3-core-setup into dev

Reviewed-on: luis_portillo/clinical_laboratory#23
This commit is contained in:
luis_portillo 2025-07-13 23:17:50 +00:00
commit 07d381d453
15 changed files with 410 additions and 1 deletions

11
.env Normal file
View File

@ -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

17
Dockerfile Normal file
View File

@ -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.

View File

@ -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.
- `--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 <NÚMERO_ISSUE> "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 "<rama_base>" --head "<tu_rama>" --title "<Tipo>(#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
```

63
docker-compose.yml Normal file
View File

@ -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: {}

68
init_odoo.py Normal file
View File

@ -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)

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import models

View File

@ -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,
}

Binary file not shown.

View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@ -0,0 +1 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="module_category_lims" model="ir.module.category">
<field name="name">Laboratorio</field>
<field name="description">Permisos y roles para el módulo de Laboratorio Clínico.</field>
<field name="sequence">20</field>
</record>
<record id="group_lims_receptionist" model="res.groups">
<field name="name">Laboratorio / Recepcionista</field>
<field name="category_id" ref="module_category_lims"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
<field name="comment">
El usuario puede registrar pacientes, crear órdenes de laboratorio y generar facturas. No tiene acceso a los resultados clínicos.
</field>
</record>
<record id="group_lims_technician" model="res.groups">
<field name="name">Laboratorio / Técnico</field>
<field name="category_id" ref="module_category_lims"/>
<field name="implied_ids" eval="[(4, ref('group_lims_receptionist'))]"/>
<field name="comment">
El usuario puede gestionar muestras, registrar la toma e ingresar resultados de los análisis. No puede validar resultados.
</field>
</record>
<record id="group_lims_admin" model="res.groups">
<field name="name">Laboratorio / Administrador</field>
<field name="category_id" ref="module_category_lims"/>
<field name="implied_ids" eval="[(4, ref('group_lims_technician'))]"/>
<field name="comment">
El usuario tiene acceso completo al módulo LIMS, incluyendo la validación de resultados, configuración y reportes.
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<!-- Menú Principal -->
<menuitem
id="lims_menu_root"
name="Laboratorio"
sequence="10"/>
<!-- Submenú de Órdenes de Laboratorio -->
<menuitem
id="lims_menu_orders"
name="Órdenes de Laboratorio"
parent="lims_menu_root"
sequence="10"/>
<!-- Submenú de Pacientes -->
<menuitem
id="lims_menu_patients"
name="Pacientes"
parent="lims_menu_root"
action="base.action_partner_customer_form"
sequence="20"/>
<!-- Submenú de Configuración -->
<menuitem
id="lims_menu_config"
name="Configuración"
parent="lims_menu_root"
sequence="100"/>
<!-- Submenú de Catálogo de Pruebas -->
<menuitem
id="lims_menu_tests_catalog"
name="Catálogo de Pruebas"
parent="lims_menu_config"
sequence="10"/>
</data>
</odoo>

10
odoo.conf Normal file
View File

@ -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

46
wait_and_start_odoo.py Normal file
View File

@ -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)