feature/4-patient-doctor-management #24
BIN
.gitignore
vendored
Normal file
BIN
.gitignore
vendored
Normal file
Binary file not shown.
61
GEMINI.md
61
GEMINI.md
|
@ -21,10 +21,13 @@ tea issue create --title "Título del Issue" --description "Descripción detalla
|
|||
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"
|
||||
```
|
||||
|
@ -37,22 +40,45 @@ tea comment 3 "Comentario de prueba"
|
|||
|
||||
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`).
|
||||
|
||||
### Política de Mensajes de Commit
|
||||
|
||||
**Es mandatorio que el título de cada commit referencie el número del issue que resuelve.** Esto se hace para mantener una trazabilidad clara entre el código y las tareas.
|
||||
|
||||
**Formato del Título:**
|
||||
```
|
||||
<tipo>(#<issue_id>): <descripción breve>
|
||||
```
|
||||
- **`<tipo>`:** `feat` (nueva funcionalidad), `fix` (corrección de bug), `docs` (cambios en documentación), `style` (formato), `refactor`, `test`, `chore` (otras tareas).
|
||||
- **`(<issue_id>)`:** El número del issue entre paréntesis y precedido de `#`.
|
||||
|
||||
**Ejemplo:**
|
||||
```
|
||||
feat(#4): Agregar campos de género y fecha de nacimiento al paciente
|
||||
```
|
||||
|
||||
### 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 -
|
||||
echo "feat(#4): 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`):
|
||||
Para mensajes de commit multilínea, la forma más segura es usar `printf` que maneja mejor los saltos de línea (`
|
||||
`):
|
||||
|
||||
```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 -
|
||||
printf "feat(#4): Título del commit
|
||||
|
||||
Cuerpo del mensaje con descripción detallada." | git commit -F -
|
||||
```
|
||||
|
||||
Esto asegura que el formato del mensaje del commit se preserve correctamente.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Crear un Pull Request
|
||||
|
@ -60,11 +86,13 @@ Esto asegura que el formato del mensaje del commit se preserve correctamente.
|
|||
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"
|
||||
```
|
||||
|
@ -86,14 +114,29 @@ Al iniciar cada sesión de trabajo, es **mandatorio** leer los siguientes docume
|
|||
|
||||
Para levantar la instancia efímera de Odoo 18 junto con la base de datos de PostgreSQL, se utiliza Docker Compose.
|
||||
|
||||
**Comando:**
|
||||
**Comando de inicio:**
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
Este comando levantará los servicios definidos en el archivo `docker-compose.yml` en modo "detached" (`-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:
|
||||
**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
|
||||
```
|
||||
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.
|
||||
|
|
|
@ -16,13 +16,19 @@
|
|||
'website': "https://gitea.grupoconsiti.com/luis_portillo/clinical_laboratory",
|
||||
'category': 'Industries',
|
||||
'version': '18.0.1.0.0',
|
||||
'depends': ['base', 'sale_management', 'stock', 'account'],
|
||||
'depends': ['base'],
|
||||
'data': [
|
||||
'security/lims_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/ir_sequence.xml',
|
||||
'views/partner_views.xml',
|
||||
'views/menus.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/lims_demo.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
|
|
13
lims_management/data/ir_sequence.xml
Normal file
13
lims_management/data/ir_sequence.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Secuencia para el Identificador de Paciente -->
|
||||
<record id="seq_patient_identifier" model="ir.sequence">
|
||||
<field name="name">Patient Identifier Sequence</field>
|
||||
<field name="code">res.partner.patient_identifier</field>
|
||||
<field name="prefix">P</field>
|
||||
<field name="padding">6</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
63
lims_management/data/lims_demo.xml
Normal file
63
lims_management/data/lims_demo.xml
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Datos de Demostración para Pacientes -->
|
||||
<record id="demo_patient_1" model="res.partner">
|
||||
<field name="name">Ana Torres</field>
|
||||
<field name="is_patient" eval="True"/>
|
||||
<field name="patient_identifier">P-A87B01</field>
|
||||
<field name="origin">Carga Inicial</field>
|
||||
<field name="birthdate_date">1985-05-15</field>
|
||||
<field name="gender">female</field>
|
||||
<field name="phone">+1-202-555-0174</field>
|
||||
<field name="email">ana.torres@example.com</field>
|
||||
</record>
|
||||
|
||||
<record id="demo_patient_2" model="res.partner">
|
||||
<field name="name">Carlos Ruiz</field>
|
||||
<field name="is_patient" eval="True"/>
|
||||
<field name="patient_identifier">P-C45D02</field>
|
||||
<field name="origin">Carga Inicial</field>
|
||||
<field name="birthdate_date">1992-11-20</field>
|
||||
<field name="gender">male</field>
|
||||
<field name="phone">+1-202-555-0192</field>
|
||||
<field name="email">carlos.ruiz@example.com</field>
|
||||
</record>
|
||||
|
||||
<!-- Datos de Demostración para Médicos -->
|
||||
<record id="demo_doctor_1" model="res.partner">
|
||||
<field name="name">Dr. Luis Herrera</field>
|
||||
<field name="is_doctor" eval="True"/>
|
||||
<field name="doctor_license">L-98765</field>
|
||||
<field name="phone">+1-202-555-0145</field>
|
||||
<field name="email">luis.herrera@hospital.com</field>
|
||||
</record>
|
||||
|
||||
<record id="demo_doctor_2" model="res.partner">
|
||||
<field name="name">Dra. Sofia Vargas</field>
|
||||
<field name="is_doctor" eval="True"/>
|
||||
<field name="doctor_license">L-54321</field>
|
||||
<field name="phone">+1-202-555-0133</field>
|
||||
<field name="email">sofia.vargas@clinic.com</field>
|
||||
</record>
|
||||
|
||||
<!-- Datos de Demostración para Tutor y Paciente Menor de Edad -->
|
||||
<record id="demo_tutor_1" model="res.partner">
|
||||
<field name="name">Laura Mendoza</field>
|
||||
<field name="phone">+1-202-555-0188</field>
|
||||
<field name="email">laura.mendoza@example.com</field>
|
||||
</record>
|
||||
|
||||
<record id="demo_patient_minor_1" model="res.partner">
|
||||
<field name="name">Pedro Infante Jr.</field>
|
||||
<field name="is_patient" eval="True"/>
|
||||
<field name="patient_identifier">P-M12E03</field>
|
||||
<field name="origin">Carga Inicial</field>
|
||||
<field name="birthdate_date" eval="(datetime.now() - relativedelta(years=5)).strftime('%Y-%m-%d')"/>
|
||||
<field name="gender">male</field>
|
||||
<field name="parent_id" ref="demo_tutor_1"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
|
@ -1 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import partner
|
Binary file not shown.
34
lims_management/models/partner.py
Normal file
34
lims_management/models/partner.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
is_patient = fields.Boolean(string="Es Paciente")
|
||||
patient_identifier = fields.Char(string="Identificador de Paciente", copy=False)
|
||||
origin = fields.Char(
|
||||
string="Origen",
|
||||
default='Manual',
|
||||
help="Este campo indica el origen del registro del paciente (ej. Manual, Carga Inicial)."
|
||||
)
|
||||
birthdate_date = fields.Date(string="Fecha de Nacimiento")
|
||||
gender = fields.Selection([
|
||||
('male', 'Masculino'),
|
||||
('female', 'Femenino'),
|
||||
('other', 'Otro')
|
||||
], string="Género")
|
||||
|
||||
is_doctor = fields.Boolean(string="Es Médico")
|
||||
doctor_license = fields.Char(string="Licencia Médica", copy=False)
|
||||
|
||||
_sql_constraints = [
|
||||
('patient_identifier_unique', 'unique(patient_identifier)', 'El identificador del paciente debe ser único.'),
|
||||
('doctor_license_unique', 'unique(doctor_license)', 'La licencia médica debe ser única.')
|
||||
]
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('is_patient') and not vals.get('patient_identifier'):
|
||||
vals['patient_identifier'] = self.env['ir.sequence'].next_by_code('res.partner.patient_identifier')
|
||||
return super(ResPartner, self).create(vals_list)
|
|
@ -7,34 +7,50 @@
|
|||
name="Laboratorio"
|
||||
sequence="10"/>
|
||||
|
||||
<!-- Submenú de Órdenes de Laboratorio -->
|
||||
<menuitem
|
||||
id="lims_menu_orders"
|
||||
name="Órdenes de Laboratorio"
|
||||
parent="lims_menu_root"
|
||||
sequence="10"/>
|
||||
<!-- Acción de Ventana para Pacientes -->
|
||||
<record id="action_lims_patient" model="ir.actions.act_window">
|
||||
<field name="name">Pacientes</field>
|
||||
<field name="res_model">res.partner</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="view_id" ref="lims_management.view_patient_tree"/>
|
||||
<field name="domain">[('is_patient', '=', True)]</field>
|
||||
<field name="context">{'default_is_patient': True}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Crea un nuevo paciente
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Submenú de Pacientes -->
|
||||
<menuitem
|
||||
id="lims_menu_patients"
|
||||
name="Pacientes"
|
||||
parent="lims_menu_root"
|
||||
action="base.action_partner_customer_form"
|
||||
action="action_lims_patient"
|
||||
sequence="20"/>
|
||||
|
||||
<!-- Submenú de Configuración -->
|
||||
<!-- Acción de Ventana para Doctores -->
|
||||
<record id="action_lims_doctor" model="ir.actions.act_window">
|
||||
<field name="name">Doctores</field>
|
||||
<field name="res_model">res.partner</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="view_id" ref="lims_management.view_doctor_tree"/>
|
||||
<field name="domain">[('is_doctor', '=', True)]</field>
|
||||
<field name="context">{'default_is_doctor': True}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Crea un nuevo doctor
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Submenú de Doctores -->
|
||||
<menuitem
|
||||
id="lims_menu_config"
|
||||
name="Configuración"
|
||||
id="lims_menu_doctors"
|
||||
name="Doctores"
|
||||
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"/>
|
||||
|
||||
action="action_lims_doctor"
|
||||
sequence="30"/>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
62
lims_management/views/partner_views.xml
Normal file
62
lims_management/views/partner_views.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Vista de árbol para Pacientes -->
|
||||
<record id="view_patient_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.tree.patient</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Pacientes">
|
||||
<field name="patient_identifier"/>
|
||||
<field name="name"/>
|
||||
<field name="gender"/>
|
||||
<field name="birthdate_date"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vista de lista para Doctores -->
|
||||
<record id="view_doctor_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.tree.doctor</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Doctores">
|
||||
<field name="name"/>
|
||||
<field name="doctor_license"/>
|
||||
<field name="phone"/>
|
||||
<field name="email"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Hereda la vista de formulario para añadir una pestaña de "Información Clínica" -->
|
||||
<record id="view_partner_form_lims" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.lims</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='internal_notes']" position="before">
|
||||
<page string="Información Clínica" name="clinical_info">
|
||||
<group>
|
||||
<group>
|
||||
<field name="is_patient"/>
|
||||
<field name="patient_identifier" invisible="not is_patient" readonly="patient_identifier"/>
|
||||
<field name="origin" readonly="id" invisible="not is_patient"/>
|
||||
<field name="birthdate_date" invisible="not is_patient"/>
|
||||
<field name="gender" invisible="not is_patient"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="is_doctor"/>
|
||||
<field name="doctor_license" invisible="not is_doctor"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Relación Tutor/Paciente" name="tutor_info">
|
||||
<field name="parent_id" string="Tutor / Responsable"/>
|
||||
<field name="child_ids" string="Pacientes a Cargo"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
Loading…
Reference in New Issue
Block a user