Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 222 additions & 46 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,256 @@

# 🧠 Instrucciones optimizadas para Copilot – Revisión de código Odoo (v18.0)
# Instrucciones para Copilot – Revisión de código Odoo (v18.0)

## Contexto
- El repositorio contiene **módulos Odoo** compatibles con la versión **v18.0** (o versiones compatibles cercanas).
- El objetivo es **revisar cambios de código** y **sugerir mejoras seguras y relevantes**, sin hacer revisiones excesivamente estrictas.

* El repositorio contiene **módulos Odoo** compatibles con la versión **v18.0** (o versiones compatibles cercanas).
* El objetivo es **revisar cambios de código** y **sugerir mejoras seguras y relevantes**, sin hacer revisiones excesivamente estrictas.

---

## 🔍 Reglas generales
## Reglas generales

1. **Responder siempre en español.**
2. Detectar y corregir **errores de tipeo u ortografía evidentes** en nombres de variables, métodos o comentarios (cuando sean claros).
3. No sugerir traducciones de docstrings o comentarios entre idiomas (no proponer pasar del inglés al español o viceversa).
4. No proponer agregar docstrings si el método no tiene uno.
- Si ya existe un docstring, puede sugerirse un estilo básico acorde a PEP8, pero **no será un error** si faltan `return`, tipos o parámetros documentados.
2. Detectar y corregir **errores de tipeo u ortografía evidentes** en nombres de variables, métodos o comentarios (cuando sean claros).
3. No sugerir traducciones de docstrings o comentarios entre idiomas (no proponer pasar del inglés al español o viceversa).
4. No proponer agregar docstrings si el método no tiene uno.

* Si ya existe un docstring, puede sugerirse un estilo básico acorde a PEP8, pero **no será un error** si faltan `return`, tipos o parámetros documentados.
5. No proponer cambios puramente estéticos (espacios, comillas simples vs dobles, orden de imports, etc.).

---

## 🧩 Revisión de modelos (`models/*.py`)
## Revisión de modelos (`models/*.py`)

- Verificar que:
- Los campos (`fields.*`) tengan nombres claros, consistentes y no entren en conflicto con otros módulos.
- Las relaciones (`Many2one`, `One2many`, `Many2many`) estén bien definidas y referencien modelos válidos.
- Las constraints declaradas con `_sql_constraints` o `@api.constrains` mantengan la integridad esperada.
- Sugerir uso de `@api.depends` si un campo compute carece de dependencias explícitas.
- Si se redefine un método de Odoo, asegurar que se llama correctamente `super()`, manteniendo el contrato original.
- Si hay lógica nueva, evitar loops costosos con búsquedas dentro de iteraciones; sugerir `mapped`, `filtered` u otras formas más eficientes.
* Verificar que:

* Los campos (`fields.*`) tengan nombres claros, consistentes y no entren en conflicto con otros módulos.
* Las relaciones (`Many2one`, `One2many`, `Many2many`) estén bien definidas y referencien modelos válidos.
* Las constraints declaradas con `_sql_constraints` o `@api.constrains` mantengan la integridad esperada.
* NOTA: En v19 se definen con `models.Constraint`
* Los índices tradicionalmente se definían en `_sql_constraints = [('unique_name', 'UNIQUE(name)', 'mensaje')]`.
* NOTA: En v19 usar `models.Index("campo")` para índices normales y `models.UniqueIndex("campo", "mensaje")` para únicos.
* Sugerir uso de `@api.depends` si un campo compute carece de dependencias explícitas.
* Si se redefine un método de Odoo, asegurar que se llama correctamente `super()`, manteniendo el contrato original.
* Si hay lógica nueva, evitar loops costosos con búsquedas dentro de iteraciones; sugerir `mapped`, `filtered` u otras formas más eficientes.

---

## 🧾 Revisión del manifest (`__manifest__.py`)

- Confirmar que todos los archivos usados (vistas, seguridad, datos) estén referenciados en el manifest.
- Si se agregan o modifican modelos, vistas o datos nuevos, sugerir incrementar la versión del módulo (por ejemplo: `version: “1.0.0” → “1.0.1”).
- Verificar dependencias declaradas: que no falten módulos requeridos ni se declaren innecesarios.
* Confirmar que todos los archivos usados (vistas, seguridad, datos, reportes, wizards) estén referenciados en el manifest.
* Verificar dependencias declaradas: que no falten módulos requeridos ni se declaren innecesarios.
* **Regla de versión (obligatoria):**
Siempre que el diff incluya **modificaciones en**:

* definición de campos o modelos (`models/*.py`),
* vistas o datos XML (`views/*.xml`, `data/*.xml`, `report/*.xml`),
* seguridad (`security/*.csv`, `security/*.xml`),
**y el `__manifest__.py` no incrementa `version`, sugerir el bump de versión** (por ejemplo, `1.0.0 → 1.0.1`).
* Cambios funcionales mínimos → **patch** (`x.y.Z`).
* Cambios de esquema o de compatibilidad → **minor** (`x.Y.0`).
* Cambios disruptivos (breaking changes) → **major** (`X.0.0`).

---

## Revisión de vistas XML (`views/*.xml`)

* Confirmar que uses herencias (`inherit_id`, `xpath`) efectivamente, no redefiniciones completas innecesarias.
* Validar que los campos referenciados en la vista existan en los modelos correspondientes.
* Atento a cambios en versiones nuevas de Odoo:

* En Odoo 18, el elemento `<tree>` fue reemplazado por `<list>` en vistas de tipo lista.
* Odoo 18 simplificó atributos condicionales: `attrs`/`states` pueden reemplazarse por condiciones directas (`invisible="..."`, `readonly="..."`) cuando aplique.
* Sugerir no duplicar vistas ni redefinir todo el `arch` si puede hacerse con `xpath`.

---

## Seguridad y acceso

* Verificar los archivos `ir.model.access.csv` para nuevos modelos: deben tener permisos mínimos necesarios.
* No proponer abrir acceso global sin justificación.
* Si se agregan nuevos modelos o campos de control de acceso, **recordar el bump de versión** (ver sección de manifest).

---

## Detección de cambios estructurales (esquema / datos)

Cuando el diff sugiera **cambios de estructura de datos**, **siempre proponer** un **script de migración** en la carpeta `scripts/`, usando pre/post/end según corresponda (ver mapeo más abajo) **y recordar el bump de versión**.
Ejemplos de cambios estructurales:

* Renombrar campos o modelos.
* Cambiar tipos de campo (e.g. `Char → Many2one`, `Selection → Many2one`, `Float → Monetary`).
* Quitar campos para reestructurar información en otros (split/merge).
* Agregar campos `compute` **almacenados** (`store=True`) que requieren backfill.
* Cambiar dominios/valores de `selection` (añadir/eliminar/renombrar keys).
* Añadir `required=True` a campos existentes sin default en datos históricos.
* Cambiar o añadir `_sql_constraints` (unique/index) que puedan fallar con datos existentes.
* Cambios en `ir.model.data`/XML IDs (renombres, `no_update="1"`, cambios de `module`/`name`).
* Cambios de reglas de acceso que requieran recalcular propiedad/propagación.

---

## Scripts de migración en `scripts/`: pre / post / end

> **Objetivo:** preservar datos y mantener instalabilidad/actualizabilidad segura.

- **pre**: Se ejecutan antes de actualizar el módulo. Útiles para preparar datos o estructuras que eviten fallos durante el upgrade.
- **post**: Se ejecutan justo después de actualizar el módulo. Ideales para recalcular datos, limpiar residuos o ajustar referencias tras el cambio.
- **end**: Se ejecutan al final de la actualización de todos los módulos. Indicados para tareas globales que dependen de múltiples módulos o para ajustes finales.

### Mapeo de cambio → acción recomendada

* **Rename de campo (mismo modelo)**

* **Pre-script**: copiar datos del campo viejo al nuevo (o crear alias temporal) para no perder datos tras el upgrade.
* **Post-script**: limpieza de residuos, recomputes si aplica.

* **Eliminar campo y mover datos a otros campos (split/merge)**

* **Pre-script**: crear campos destino (si es viable vía SQL/DDL) y migrar datos intermedios.
* **Post-script**: normalizar referencias, recalcular computes, borrar helpers.

* **Cambios en registros XML con `no_update="1"`**

* **Post-script**: usar **force upgrade** (reaplicar datos) o actualizar esos registros por API (respetando `xml_id`) para reflejar cambios.

* **Agregar campo `compute` con `store=True`**

* **Pre-script (opcional si alto volumen/incidencia)**: crear columna en DB para evitar lock prolongado en upgrade.
* **Post-script**: backfill **en lotes** (batch) para poblar el valor almacenado.

* **Cambiar tipo de campo**

* **Pre-script**: crear columna temporal con tipo nuevo y migrar datos (con conversión).
* **Post-script**: swap/renombrar columnas, borrar columna vieja, recomputes.

* **Cambios en `selection` (renombre/elim./nuevo valor default)**

* **Pre-script**: mapear valores antiguos → nuevos (tabla de mapeo).
* **Post-script**: validar que no quedan valores huérfanos.

* **Agregar `required=True` a campo existente**

* **Pre-script**: asignar default consistente a registros históricos (en lote) o rellenar desde lógica derivada.
* **Post-script**: constraint check.

* **Nuevas `_sql_constraints` (unique) / índices**

* **Pre-script**: detectar y resolver duplicados o inconsistencias.
* **Post-script**: crear índice/constraint y verificar.

* **Renombrar modelo**

* **Pre-script**: crear `ir.model.data`/mapeos, migrar `model` en `ir.model.data` y tablas rel.
* **Post-script**: re-enlazar vistas, acciones, reglas y volver a chequear accesos.

* **Cambios en XML IDs o modularización**

* **Pre-script**: preparar mapeo `old_xmlid → new_xmlid`.
* **Post-script**: actualizar referencias dependientes; si está marcado `no_update`, aplicar actualización manual.

> **Regla general:** si el cambio puede **romper durante el upgrade**, prepara **pre-script**; si requiere **recalcular o reaplicar** después del código nuevo, usa **post-script**. Si se necesita una acción global al final, usa **end-script**.

---

## 🪶 Revisión de vistas XML (`views/*.xml`)
## Convenciones de scripts en `scripts/`

* Ubicación: `scripts/`
* Nombres sugeridos:

* `pre_<version>_<breve-descripcion>.py`
* `post_<version>_<breve-descripcion>.py`
* Requisitos:

- Confirmar que uses herencias (`inherit_id`, `xpath`) efectivamente, no redefiniciones completas innecesarias.
- Validar que los campos referenciados en la vista existan en los modelos correspondientes.
- Atento a cambios en las versiones nuevas de Odoo:
- En Odoo 18, el elemento `<tree>` fue reemplazado por `<list>` en vistas de tipo lista.
- Odoo 18 ha simplificado atributos condicionales: `attrs` o `states` pueden ser reemplazados por condiciones directas (`invisible="..."`, `readonly="..."`)
- Sugerir no duplicar vistas ni redefinir todo el `arch` si puede hacerse con un `xpath`.
* Idempotentes (seguros si se ejecutan más de una vez).
* En lotes (`batch_size` razonable) para datasets grandes.
* Logs claros (uso de `_logger.info`).
* Manejo de transacciones cuando aplique (evitar locks largos).
* Documentar al inicio **qué suponen** y **qué garantizan**.

**Esqueleto mínimo (ejemplo):**

```python
# scripts/pre_18.0_rename_partner_ref.py
from odoo import api, SUPERUSER_ID

def migrate(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {})
# Ejemplo: copiar datos de 'old_ref' a 'new_ref' antes del upgrade
partners = env['res.partner'].with_context(active_test=False).search([('old_ref', '!=', False)])
for batch in range(0, len(partners), 500):
sub = partners[batch:batch+500]
for p in sub:
if not p.new_ref:
p.new_ref = p.old_ref
```

```python
# scripts/post_18.0_backfill_stored_amount_total.py
from odoo import api, SUPERUSER_ID

def migrate(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {})
Orders = env['sale.order'].with_context(active_test=False)
ids = Orders.search([]).ids
for i in range(0, len(ids), 200):
batch = Orders.browse(ids[i:i+200])
# Forzar recompute del stored
batch._compute_amount_total()
```

---

## 🔒 Seguridad y acceso
## Checklist rápida para el review

- Verificar los archivos `ir.model.access.csv` para nuevos modelos: deben tener permisos mínimos necesarios.
- Revisar reglas (`ir.rule`): que no otorguen accesos innecesarios (especialmente `write`, `unlink`).
- No proponer abrir acceso global sin justificación.
| Categoría | Qué comprobar Copilot |
| ------------------ | -------------------------------------------------------------------------------------------------------- |
| Modelos | Relaciones válidas; constraints; uso adecuado de `@api.depends`; `super()` correcto |
| Vistas XML | Herencias correctas; campos válidos; adaptación a cambios de versión (p.ej. `<list>` vs `<tree>`) |
| Manifest | **Bump de versión obligatorio** si hay cambios en modelos/vistas/seguridad/datos; archivos referenciados |
| Seguridad | Accesos mínimos necesarios; reglas revisadas |
| Migraciones | **Si hay cambios estructurales, exigir script en `scripts/` (pre/post/end)** y describir qué hace |
| Rendimiento / ORM | Evitar loops costosos; no SQL innecesario; aprovechar mejoras de v18.0 |
| Ortografía & typos | Errores evidentes corregibles sin modificar idioma ni estilo |

---

## ✅ Checklist rápida para el review
## Heurística práctica para el bump de versión

* **SI** el diff toca cualquiera de: `models/`, `views/`, `data/`, `report/`, `security/`, `wizards/`
**Y** `__manifest__.py` no cambia `version` → **Sugerir bump**.
* **SI** hay scripts `scripts/pre_*.py` o `scripts/post_*.py` nuevos → **Sugerir al menos minor bump**.
* **SI** hay cambios que rompen compatibilidad (renombres, tipos, required sin default) → **Sugerir minor/major** según impacto.

---

## Casos adicionales a cubrir (sugiere migración si aplica)

* Introducción de **nuevos defaults** que dependen de datos existentes.
* Cambio en **nombres técnicos** de vistas/acciones/menús (asegurar que `xml_id` no cambie o mapearlo).
* **Indexaciones** nuevas (agregar índices en post para minimizar locks; validar cardinalidad).
* Normalización de **monedas/impuestos** (migrar valores legacy; recalcular montos).
* Cambios en **multi-company** o **multi-website** (poblar valores por compañía/sitio).
* Ajustes en **traducciones** críticas de `selection` (asegurar mapping por key, no por etiqueta traducida).

---

## Estilo del feedback

* Ser breve, claro y útil. Ejemplos:

* “El campo `partner_id` no se encuentra referenciado en la vista.”
* “Este método redefine `write()` sin usar `super()`.”
* “En v18.0, `<tree>` ya no se usa; reemplazar por `<list>`.”
* “Tip: hay un error ortográfico en el nombre del parámetro.”
* **Bump + migración:** “Se renombra `old_ref` → `new_ref`: falta **bump de versión** y **pre-script** en `scripts/` para copiar valores antes del upgrade; añadir **post-script** para recompute del stored.”

| Categoría | Qué comprobar Copilot |
|---------|--------------------------|
| Modelos | Relaciones válidas; constraints; uso adecuado de `@api.depends`; `super()` correcto |
| Vistas XML | Herencias correctas; campos válidos; adaptación a cambios de versión (p.ej. `<list>` vs `<tree>`) |
| Manifest | Archivos referenciados; versión del módulo incrementada si hay cambios relevantes |
| Seguridad | Accesos mínimos necesarios; reglas revisadas |
| Rendimiento / ORM | Evitar loops costosos; no SQL innecesario; aprovechar mejoras de la versión v18.0 |
| Ortografía & typos | Errores evidentes corregibles sin modificar idioma ni estilo |
* Evitar explicaciones largas o reescrituras completas salvo que el cambio sea claro y necesario.

---

## 💡 Estilo del feedback
## Resumen operativo para Copilot

- Ser breve, claro y útil:
👉 “El campo `partner_id` no se encuentra referenciado en la vista.”
👉 “Este método redefine `write()` sin usar `super()`.”
👉 “En v18.0, `<tree>` ya no se usa; reemplazar por `<list>`.”
👉 “Tip: hay un error ortográfico en el nombre del parámetro.”
- Evitar explicaciones largas o reescrituras completas salvo que el cambio sea claro y necesario.
1. **Detecta cambios en modelos/vistas/seguridad/datos → exige bump de `version` en `__manifest__.py`.**
2. **Si hay cambio estructural → propone y describe script(s) de migración en `scripts/` (pre/post/inline),** con enfoque idempotente y en lotes.
3. Mantén el feedback **concreto, breve y accionable**.
10 changes: 10 additions & 0 deletions purchase_stock_ux/models/purchase_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,13 @@ def _compute_invoice_status(self):
line.invoice_status = "invoiced"
else:
line.invoice_status = "no"

@api.depends()
def _compute_price_unit_and_date_planned_and_name(self):
# Esto lo hacemos por un caso raro de cancelacion de remanentes,
# Odoo cambia el price_unit del move antes de commitear a 0 la qty y hace que cree contraentregas
all_lines = self
for line in all_lines:
if not line.product_qty:
all_lines -= line
super(PurchaseOrderLine, all_lines)._compute_price_unit_and_date_planned_and_name()
11 changes: 10 additions & 1 deletion purchase_stock_ux/models/stock_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo import fields, models
from odoo import api, fields, models


class StockMove(models.Model):
Expand All @@ -17,3 +17,12 @@ def _compute_origin_description(self):
for rec in self:
if rec.purchase_line_id:
rec.origin_description = rec.purchase_line_id.name

@api.model
def _prepare_merge_moves_distinct_fields(self):
# Esto lo hacemos porque si por ejemplo el replenishment_cost del producto cambió, este cambia el price unit al momento
# de ver si mergea moves o no, y como siempre queremos que mergee lo sacamos, no es elegante pero resuelve.
distinct_fields = super()._prepare_merge_moves_distinct_fields()
if self.env.context.get("cancel_from_order") and "price_unit" in distinct_fields:
distinct_fields.remove("price_unit")
return distinct_fields