# GitHub Copilot Instructions - Kidekoop Addons Custom ## Project Overview Este repositorio contiene addons personalizados y modificados de Odoo 18.0. El proyecto combina: - **OCB (Odoo Community Backports)**: Base de Odoo 18.0 community en `/ocb` - **Addons OCA**: Módulos de la comunidad OCA de los que heredan nuestros addons, modificados para adaptarse a nuestras necesidades - **Addons Custom**: Módulos desarrollados por este proyecto ## Architecture & Stack - **Odoo Version**: 18.0 (OCB) - **Python Version**: 3.10+ - **Framework**: Odoo ORM - **Deployment**: Docker Compose - **DB**: PostgreSQL - **Languages**: Python, XML, JavaScript, QWeb ## Code Standards ### Python Style - Seguir **OCA guidelines** estrictamente - Usar **black** para formateo (configurado en `pyproject.toml`) - **isort** para ordenar imports (perfil black) - **flake8** para linting - **pylint** con pylint-odoo para verificaciones específicas de Odoo - Pre-commit hooks activos (ver `.pre-commit-config.yaml`) ### Odoo Conventions - **Model names**: snake_case con punto (`product.price.category`) - **Class names**: PascalCase (`ProductPriceCategory`) - **File names**: snake_case (`product_price_category.py`) - **XML IDs**: módulo.nombre_descriptivo (`product_price_category.view_form`) - **Manifest**: Siempre `__manifest__.py`, nunca `__openerp__.py` ### XML/View Standards - **Indent**: 4 espacios (no tabs) - **XPath**: Usar `position` explícito (`before`, `after`, `inside`, `replace`, `attributes`) - **Groups**: Referenciar grupos con módulo.xml_id (`sales_team.group_sale_manager`) - **Sequence**: Usar `sequence` attribute para ordenar campos en vistas ### Translation System **IMPORTANTE**: El sistema de traducciones está funcionando correctamente. Seguir estas reglas: 1. **Estructura de carpeta i18n/**: ``` addon_name/ ├── i18n/ │ ├── es.po # Español (obligatorio) │ ├── eu.po # Euskera (obligatorio) │ └── addon_name.pot # Template (generado) ``` 2. **NO usar `_()` en definiciones de campos a nivel de módulo**: ```python # ❌ INCORRECTO - causa warnings from odoo import _ name = fields.Char(string=_("Name")) # ✅ CORRECTO - traducción se maneja por .po files name = fields.Char(string="Name") ``` 3. **Usar `_()` solo en métodos y código ejecutable**: ```python def action_confirm(self): message = _("Confirmed successfully") return {'warning': {'message': message}} ``` 4. **Generar/actualizar traducciones**: ```bash # Exportar términos a traducir Pedir al usuario generar a través de UI, no sabemos el método correcto para exportar SÓLO las cadenas del addon sin incluir todo el sistema. ``` Usar sólo polib y apend cadenas en los archivos .po, msmerge corrompe los archivos. ``` 5. **Formato de archivos .po**: - Encoding: UTF-8 - Content-Type: text/plain; charset=UTF-8 - Language codes: `es`, `eu`, `ca`, `gl`, `pt`, `fr`, `it` ## Project Structure ``` addons-cm/ ├── .github/ # GitHub configs │ └── copilot-instructions.md # Este archivo ├── ocb/ # Odoo Community Backports (18.0) │ └── addons/ # Addons core de Odoo ├── oca_dependencies.txt # Dependencias OCA ├── requirements.txt # Dependencias Python ├── docker-compose.yml # Configuración Docker ├── Makefile # Comandos útiles │ ├── # === ADDONS OCA NO MODIFICADOS === ├── account_invoice_triple_discount/ # Triple descuento en facturas (OCA) ├── purchase_triple_discount/ # Triple descuento en compras (OCA) ├── product_origin/ # Origen del producto (OCA) ├── product_get_price_helper/ # Helper de precios (OCA) ├── product_main_seller/ # Proveedor principal (OCA) ├── product_price_category/ # Categorías de precio (OCA) │ ├── # === ADDONS CUSTOM === ├── account_invoice_triple_discount_readonly/ # Fix para triple descuento ├── product_price_category_supplier/ # Extensión categorías precio ├── product_sale_price_from_pricelist/ # Auto-cálculo precio venta └── website_sale_aplicoop/ # Sistema eskaera (compras grupo) ```` ## Addon References **Para arquitectura, detalles de implementación y uso específico de cada addon, consultar su `README.md` individual.** ### Addons OCA No Modificados - [account_invoice_triple_discount](../account_invoice_triple_discount/README.rst) - [purchase_triple_discount](../purchase_triple_discount/README.rst) - [product_origin](../product_origin/README.rst) - [product_get_price_helper](../product_get_price_helper/README.rst) - [product_main_seller](../product_main_seller/README.rst) - [product_price_category](../product_price_category/README.rst) ### Addons Custom Propios - [account_invoice_triple_discount_readonly](../account_invoice_triple_discount_readonly/README.md) - Fix bug descuentos - [product_price_category_supplier](../product_price_category_supplier/README.md) - Gestión categorías por proveedor - [product_sale_price_from_pricelist](../product_sale_price_from_pricelist/README.md) - Auto-precio basado en compra - [website_sale_aplicoop](../website_sale_aplicoop/README.md) - Sistema eskaera completo ## Development Workflow ### Local Development ```bash # Iniciar entorno (puertos: 8070=web, 8073=longpolling) docker-compose up -d # Actualizar addon docker-compose exec odoo odoo -d odoo -u addon_name --stop-after-init # Ver logs docker-compose logs -f odoo # Ejecutar tests docker-compose exec odoo odoo -d odoo --test-enable --stop-after-init -u addon_name # Acceder a shell de Odoo docker-compose exec odoo bash # Acceder a PostgreSQL docker-compose exec db psql -U odoo -d odoo ```` ### Quality Checks ```bash # Ejecutar todos los checks (usa .pre-commit-config.yaml) pre-commit run --all-files # O usar Makefile (ver `make help` para todos los comandos) make lint # Solo linting (pre-commit) make format # Formatear código (black + isort) make check-format # Verificar formateo sin modificar make flake8 # Ejecutar flake8 make pylint # Ejecutar pylint (todos) make pylint-required # Solo verificaciones mandatorias make clean # Limpiar archivos temporales ``` ### Tools Configuration - **black**: Line length 88, target Python 3.10+ (ver `pyproject.toml`) - **isort**: Profile black, sections: STDLIB > THIRDPARTY > ODOO > ODOO_ADDONS > FIRSTPARTY > LOCALFOLDER - **flake8**: Ver `.flake8` para reglas específicas - **pylint**: Configurado para Odoo con `pylint-odoo` plugin ### Testing - Tests en `tests/` de cada addon - Naming: `test_*.py` - Herencia: `odoo.tests.common.TransactionCase` - Ejecutar: `--test-enable` flag ## Critical Architecture Patterns ### Product Variants Architecture **IMPORTANTE**: Los campos de lógica de negocio SIEMPRE van en `product.product` (variantes), no en `product.template`: ```python # ✅ CORRECTO - Lógica en product.product class ProductProduct(models.Model): _inherit = 'product.product' last_purchase_price_updated = fields.Boolean(default=False) list_price_theoritical = fields.Float(default=0.0) def _compute_theoritical_price(self): for product in self: # Cálculo real por variante pass # ✅ CORRECTO - Template solo tiene campos related class ProductTemplate(models.Model): _inherit = 'product.template' last_purchase_price_updated = fields.Boolean( related='product_variant_ids.last_purchase_price_updated', readonly=False ) ``` **Por qué**: Evita problemas con pricelists y reportes que operan a nivel de variante. Ver `product_sale_price_from_pricelist` como ejemplo. ## Common Patterns ### Extending Models ```python from odoo import models, fields, api class ResPartner(models.Model): _inherit = 'res.partner' custom_field = fields.Char(string="Custom Field") @api.depends('field1', 'field2') def _compute_custom(self): for record in self: record.custom_computed = record.field1 + record.field2 ``` ### Creating Wizards (Transient Models) ```python class WizardModel(models.TransientModel): _name = 'wizard.model.name' _description = "Wizard Description" def action_confirm(self): # Business logic return {'type': 'ir.actions.act_window_close'} ``` ### Bulk Updates ```python # Prefer SQL-level updates for performance self.env['product.template'].search([ ('default_supplier_id', '=', partner_id) ]).write({'price_category_id': category_id}) ``` ### Notifications ```python return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _('Success'), 'message': _('Operation completed'), 'type': 'success', # or 'warning', 'danger', 'info' 'sticky': False, } } ``` ### Logging Pattern ```python import logging _logger = logging.getLogger(__name__) # En métodos de cálculo de precios, usar logging detallado: _logger.info( "[PRICE DEBUG] Product %s [%s]: base_price=%.2f, tax_amount=%.2f", product.default_code or product.name, product.id, base_price, tax_amount, ) ``` ### Price Calculation Pattern ```python # Usar product_get_price_helper para cálculos consistentes partial_price = product._get_price(qty=1, pricelist=pricelist) base_price = partial_price.get('value', 0.0) or 0.0 # Siempre validar taxes if not product.taxes_id: raise UserError(_("No taxes defined for product %s") % product.name) ``` ## Dependencies Management ### OCA Dependencies (`oca_dependencies.txt`) ``` account-invoicing product-attribute purchase-workflow sale-workflow ``` ### Python Dependencies (`requirements.txt`) - Versiones específicas para evitar breaking changes - Incluir herramientas de desarrollo (linters, etc) ## Security & Access Rights ### Grupos Comunes - `base.group_user` - Usuario interno - `base.group_system` - Administrador - `sales_team.group_sale_manager` - Manager de ventas - `sales_team.group_sale_salesman` - Vendedor - `purchase.group_purchase_manager` - Manager de compras ### Security Files ```xml id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_model_user,model.name.user,model_model_name,base.group_user,1,1,1,0 ``` ## Common Issues & Solutions ### Translation Warnings **Problem**: `WARNING: _() called at import time at module...` **Solution**: Remove `_()` from field definitions, use only in methods ### XPath Not Found **Problem**: `Element ... not found in parent view` **Solution**: Check view inheritance chain, verify XML IDs are correct ### Discount Reset Issue **Problem**: Multiple discounts being accumulated in discount1 **Solution**: Use `account_invoice_triple_discount_readonly` addon ### Price Calculation **Problem**: Prices not updating from pricelist **Solution**: 1. Use `product_sale_price_from_pricelist` with proper configuration 2. Set pricelist in Settings > Sales > Automatic Price Configuration 3. Ensure `last_purchase_price_compute_type` is NOT set to `manual_update` 4. Verify product has taxes configured (required for price calculation) ### Product Variant Issues **Problem**: Computed fields not working in pricelists/reports **Solution**: Move business logic from `product.template` to `product.product` and use `related` fields in template ### Manifest Dependencies **Problem**: Module not loading, dependency errors **Solution**: Check both `__manifest__.py` depends AND `oca_dependencies.txt` for OCA repos ## Testing Guidelines ### Unit Tests - Test business logic in isolation - Mock external dependencies - Use `TransactionCase` for DB tests ### Integration Tests - Test workflow end-to-end - Verify computed fields - Check access rights ### UI Tests (Tours) ```javascript odoo.define("module.tour", function (require) { "use strict"; var tour = require("web_tour.tour"); tour.register( "tour_name", { test: true, url: "/web", }, [ // Tour steps ], ); }); ``` ## Debugging Tips ### Enable Developer Mode ``` Settings > Activate Developer Mode ``` ### Check Logs ```bash docker-compose logs -f odoo | grep ERROR docker-compose logs -f odoo | grep addon_name ``` ### Python Debugger ```python import pdb; pdb.set_trace() # Set breakpoint ``` ### Performance Profiling ```bash --log-level=debug_sql # Show SQL queries ``` ## Documentation Standards ### README.md Structure Cada addon debe tener un README.md con: 1. **Title & Summary**: Qué hace el addon 2. **Features**: Lista de funcionalidades 3. **Dependencies**: Addons requeridos 4. **Installation**: Comandos de instalación 5. **Configuration**: Settings necesarios 6. **Usage**: Flujo de trabajo típico 7. **Technical Details**: Modelos, campos, métodos 8. **Translations**: Estado de traducciones (si aplica) ### **manifest**.py Structure Todos los addons custom deben seguir esta estructura: ```python # Copyright YEAR - Today AUTHOR # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { # noqa: B018 "name": "Addon Name", "version": "18.0.X.Y.Z", # X=major, Y=minor, Z=patch "category": "category_name", "summary": "Short description", "author": "Odoo Community Association (OCA), Your Company", "maintainers": ["maintainer_github"], "website": "https://github.com/OCA/repo", "license": "AGPL-3", "depends": [ "base", # Lista ordenada alfabéticamente ], "data": [ "security/ir.model.access.csv", "views/actions.xml", "views/menu.xml", "views/model_views.xml", ], } ``` ### Code Comments - Docstrings en clases y métodos públicos - Comentarios inline para lógica compleja - TODOs con contexto completo - Logging detallado en operaciones de precios/descuentos ## Version Control ### Commit Messages ``` [TAG] module: Brief description Longer explanation if needed ``` Tags: `[ADD]`, `[FIX]`, `[IMP]`, `[REF]`, `[REM]`, `[I18N]`, `[DOC]` ### Branch Strategy - `main` - Production ready - `dev` - Development - `feature/*` - New features - `fix/*` - Bug fixes ## Performance Considerations - Use `@api.depends` correctamente para computed fields - Prefer `search()` + `write()` sobre loops con `write()` - Use `create()` con lista de vals para bulk creates - Indexes en campos frecuentemente buscados - Avoid N+1 queries con `prefetch` ## Key Business Features ### Eskaera System (website_sale_aplicoop) Sistema completo de compras colaborativas para cooperativas de consumo: - **Group Orders**: Pedidos grupales con estados (draft → confirmed → collected → completed) - **Separate Carts**: Carrito independiente por miembro y por grupo - **Cutoff Dates**: Validación de fechas límite para pedidos - **Pickup Management**: Gestión de días de recogida - **Multi-language**: ES, EU, CA, GL, PT, FR, IT - **Member Tracking**: Gestión de miembros activos/inactivos por grupo **Flujo típico**: 1. Administrador crea grupo order con fechas (collection, cutoff, pickup) 2. Miembros añaden productos a su carrito individual 3. Sistema valida cutoff date antes de confirmar 4. Notificaciones automáticas al cambiar estados 5. Tracking de fulfillment por miembro Ver [website_sale_aplicoop/README.md](../website_sale_aplicoop/README.md) para detalles. ### Triple Discount System Todos los documentos de compra/venta soportan 3 descuentos consecutivos: ```python # Ejemplo: Precio = 600.00 # Desc. 1 = 50% → 300.00 # Desc. 2 = 50% → 150.00 # Desc. 3 = 50% → 75.00 ``` **IMPORTANTE**: Usar `account_invoice_triple_discount_readonly` para evitar bug de acumulación de descuentos. ### Automatic Pricing System `product_sale_price_from_pricelist` calcula automáticamente precio de venta basado en: - Último precio de compra (`last_purchase_price_received`) - Tipo de cálculo de descuentos (`last_purchase_price_compute_type`) - Pricelist configurado en Settings - Impuestos del producto **Configuración crítica**: ```python # En Settings > Sales > Automatic Price Configuration product_pricelist_automatic = [ID_pricelist] # En producto last_purchase_price_compute_type != "manual_update" # Para auto-cálculo ``` ## Resources - **OCA Guidelines**: https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst - **Odoo Documentation**: https://www.odoo.com/documentation/18.0/ - **OCB Repository**: https://github.com/OCA/OCB - **OCA Repositories**: https://github.com/OCA/ --- **Last Updated**: 2026-02-16 **Odoo Version**: 18.0 **Python Version**: 3.10+