feat(#3): Setup core files #23
11
.env
Normal file
11
.env
Normal 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
17
Dockerfile
Normal 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.
|
86
GEMINI.md
86
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.
|
||||
- `--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
63
docker-compose.yml
Normal 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
68
init_odoo.py
Normal 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)
|
3
lims_management/__init__.py
Normal file
3
lims_management/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
28
lims_management/__manifest__.py
Normal file
28
lims_management/__manifest__.py
Normal 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,
|
||||
}
|
BIN
lims_management/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
lims_management/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
1
lims_management/models/__init__.py
Normal file
1
lims_management/models/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# -*- coding: utf-8 -*-
|
BIN
lims_management/models/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
lims_management/models/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
1
lims_management/security/ir.model.access.csv
Normal file
1
lims_management/security/ir.model.access.csv
Normal file
|
@ -0,0 +1 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
|
37
lims_management/security/lims_security.xml
Normal file
37
lims_management/security/lims_security.xml
Normal 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>
|
40
lims_management/views/menus.xml
Normal file
40
lims_management/views/menus.xml
Normal 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
10
odoo.conf
Normal 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
46
wait_and_start_odoo.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user