casos practicos
Odoo 20 sin ir.rule: migra tus módulos con upgrade_code
Odoo 20 reemplaza ir.model.access e ir.rule por un único modelo, ir.access. Migramos un módulo real con el comando upgrade_code de Odoo, lo instalamos en Odoo 20 y te contamos qué falló en el camino.
Focuz Academy · 29 de setiembre de 2026 · 5 min
Odoo 20 se presentó en Odoo Experience 2026, del 24 al 26 de septiembre en Bruselas. Las notas de versión traen muchas funciones nuevas, pero hay una línea que todo desarrollador de módulos debe leer: "Access rights have been simplified by removing record rules and adding a domain directly at the access right level".
En la práctica, ir.model.access e ir.rule dejan de existir. Si tu módulo trae un ir.model.access.csv o reglas de registro, no se instalará en Odoo 20 tal como está. La buena noticia es que Odoo incluye una herramienta para migrar ese código. La probamos.
El nuevo modelo: ir.access
En la rama 20.0 de github.com/odoo/odoo, el modelo ir.access (en odoo/addons/base/models/ir_access.py) une los permisos y las reglas en un solo registro:
model_idygroup_id(el grupo es opcional).operation: un subconjunto decrud(por ejemplo,cruor).domain: los registros a los que aplica.kind(calculado): permission si tiene grupo y restriction si no lo tiene.
Otros cambios que te afectan de 19.0 a 20.0
El changelog del ORM registra cuatro versiones de Odoo Online entre 19.0 y 20.0 (19.1 a 19.4). Si saltas de 19.0 on-premise a 20.0, heredas todos sus cambios. Según el changelog del ORM:
- Campos binarios: su tipo pasa a ser
BinaryValuey ya no se codifica en base64 en todo el flujo (19.3). En el código fuente,BinaryValueofrececontent,open()yto_base64(). Revisa cadabase64.b64decode(record.campo). requestsale del código de los modelos y se agregaenv.website(19.4).- Se elimina
Model._table_query(20.0). - Nueva API para
ir.config_parameteryField.compute_sql(19.1). - Nuevo script
populatepara generar datos de prueba (20.0).
Dos datos más del código: odoo/release.py exige Python 3.12 a 3.14, y el cliente web incluye OWL 3 en web/static/lib/owl/owl.js (en el commit que usamos, la versión 3.0.0-alpha.49).
La herramienta: upgrade_code
odoo/cli/upgrade_code.py reescribe tu código fuente con los scripts de odoo/upgrade_code/, cuyos nombres siguen el formato {versión}-{nombre}.py. Opciones: --script (un solo script), --from/--to (un rango de versiones), --glob, --addons-path y --dry-run. Su propia documentación advierte que los scripts hacen un esfuerzo razonable, pero que "no son balas de plata".
Para pasar de 19.0 a 20.0 nos interesan, entre otros, 19.4-00-ir-access.py, 19.4-00-ormcache-on-transaction.py, 19.5-00-tuple-rec_names_search.py y owl3-migration.py (para JavaScript y plantillas OWL).
Caso práctico: el módulo focuz_garantia
Creamos un módulo al estilo de Odoo 19 con lo que suele tener un módulo real: un ir.model.access.csv con dos permisos, una regla multiempresa en XML y este modelo:
class FocuzGarantia(models.Model):
_name = 'focuz.garantia'
_description = 'Garantía de producto'
_rec_names_search = ['name', 'serie']
name = fields.Char(required=True)
serie = fields.Char()
company_id = fields.Many2one('res.company', default=lambda self: self.env.company)
def write(self, vals):
res = super().write(vals)
if 'serie' in vals:
self.env.registry.clear_cache()
return res
Desde la raíz de un clon de la rama 20.0 (en nuestro caso, el commit del 28 de septiembre), ejecutamos los scripts uno por uno. Primero, en modo de prueba:
PYTHONPATH=. python odoo/cli/upgrade_code.py --script ir-access --addons-path odoo/addons,../mis_addons --dry-run
updated: .../focuz_garantia/__manifest__.py
deleted: .../focuz_garantia/security/garantia_security.xml
updated: .../focuz_garantia/security/ir.access.csv
deleted: .../focuz_garantia/security/ir.model.access.csv
Luego, sin --dry-run, con ir-access, ormcache-on-transaction y tuple-rec_names_search. El resultado de seguridad fue este security/ir.access.csv:
id,name,model_id,group_id/id,operation,domain
access_focuz_garantia_user,focuz.garantia.user,focuz.garantia,base.group_user,cru,
access_focuz_garantia_manager,focuz.garantia.manager,focuz.garantia,base.group_system,crud,
focuz_garantia_company_rule,Garantías: multiempresa,focuz.garantia,,crud,"[('company_id', 'in', company_ids)]"
El script también actualizó el manifiesto, cambió _rec_names_search a una tupla y reemplazó self.env.registry.clear_cache() por self.env.transaction.invalidate_ormcache().
Después instalamos el módulo en Odoo 20 sobre una base de datos limpia y lo revisamos desde odoo shell:
focuz.garantia.manager | Role / Administrator | crud | permission |
focuz.garantia.user | Role / User | cru | permission |
Garantías: multiempresa | - | crud | restriction | [('company_id', 'in', company_ids)]
La regla global se convirtió en una restriction sin grupo, y 'ir.model.access' in env devolvió False.
Lo que aprendimos (y no está en las notas)
- Ejecuta los scripts de uno en uno con
--script. En nuestra prueba (commit del 28 de septiembre),--from 19.0con los addons del núcleo en la ruta se detuvo con unKeyErrordentro de19.3-00-account-groups.py, un script de contabilidad que nuestro módulo ni siquiera usa. Ejecutar solo los scripts que necesitas evita el problema. - Incluye
odoo/addonsen--addons-path. Sin el módulobase, el scriptir-accessfalla conKeyError: 'base.group_user'porque necesita las definiciones de grupos. - La versión del manifiesto no se actualiza sola. Con
'version': '19.0.1.0.0', Odoo 20 marcó el módulo como versión incompatible (installable=False). Cámbiala a20.0.x.y.z. - Revisa el CSV generado con alguien de negocio. La conversión es mecánica: confirma que cada restriction refleja la regla que querías.
Ejercicio
- Clona la rama 20.0 y crea una rama de migración en tu repositorio de módulos.
- Ejecuta
--dry-runconir-accessy lee la lista de archivos que cambiarían. - Aplica los scripts de uno en uno, haciendo un commit después de cada uno para revisar los diffs.
- Si tienes JavaScript propio, ejecuta
--script owl3-migrationen otro commit. - Busca
b64decodeyb64encodeen el código que lee campos binarios. - Sube la versión del manifiesto, instala en una base limpia de Odoo 20 y ejecuta tus tests.
Fuentes: Notas de versión de Odoo 20, Changelog del ORM (Odoo 20.0), upgrade_code.py en odoo/odoo 20.0, Script 19.4-00-ir-access.py, Odoo Experience 2026.
Guía gratuita: 5 agentes Python para Odoo
Casos de Junior a Senior, con código verificado contra Odoo 20.
Descargar →¿Empiezas desde cero? Lee qué es el agent loop y sigue las lecciones gratuitas.