Skip to content

AI Coding Agent for Odoo Version Migration

DeployMonkey Team · March 23, 2026 14 min read

The Migration Problem

Migrating custom Odoo modules between versions is one of the most dreaded tasks in the Odoo ecosystem. Each major version introduces breaking changes: removed APIs, renamed methods, changed view syntax, new ORM behaviors, and restructured base modules. A module that works perfectly on Odoo 17 might have dozens of issues on Odoo 18 or 19. AI coding agents can analyze your custom modules, identify every breaking change, and generate the fixes — turning a multi-week migration into a multi-day project.

What Changes Between Versions

# Common breaking changes AI detects:

# 1. API Changes
# Odoo 17 → 18: attrs removal
# Before: attrs="{'invisible': [('state', '!=', 'draft')]}"
# After:  invisible="state != 'draft'"

# 2. Import Path Changes
# Before: from odoo.exceptions import except_orm
# After:  from odoo.exceptions import UserError

# 3. Method Removals
# Before: record.message_post_with_view(...)
# After:  record.message_post_with_source(...)

# 4. Field Changes
# Before: fields.Many2one('res.users', oldname='user_id')
# After:  oldname parameter removed in newer versions

# 5. View Syntax
# Before: <tree string="Orders">
# After:  <list string="Orders"> (Odoo 17+)

# 6. Widget Changes
# Before: widget="many2many_tags" options="{'color_field': 'color'}"
# After:  widget="many2many_tags" color_field="color"

AI Migration Workflow

# Step 1: AI scans all custom modules
"Scanning 12 custom modules...
  Total Python files: 89
  Total XML files: 124
  Total JS files: 15
  Total CSV/data files: 34"

# Step 2: AI identifies breaking changes
"Migration Report: Odoo 17 → 19

  Critical (will crash):
  ├── 23 × attrs= usage in XML views → convert to new syntax
  ├── 5 × removed method calls → replace with alternatives
  ├── 3 × removed import paths → update imports
  └── 2 × removed field parameters → clean up

  Warning (may cause issues):
  ├── 12 × deprecated method usage → will be removed next version
  ├── 8 × tree → list view tag change
  ├── 4 × JavaScript widget API changes
  └── 3 × changed default values

  Info (style/convention):
  ├── 15 × old-style string formatting → f-strings recommended
  ├── 7 × missing type hints on public methods
  └── 5 × deprecated coding patterns

  Total issues: 87 (33 critical, 27 warning, 27 info)"

Automatic Fixes

1. attrs Conversion (Odoo 17 → 18+)

# AI converts all attrs to new syntax:

# Before (Odoo 17):
<field name="amount"
  attrs="{'invisible': [('state', '!=', 'draft')],
          'required': [('type', '=', 'invoice')]}"/>

# After (Odoo 18+):
<field name="amount"
  invisible="state != 'draft'"
  required="type == 'invoice'"/>

# Complex domain conversion:
# Before: attrs="{'invisible': [('a', '=', 'x'), ('b', '!=', 'y')]}"
# After:  invisible="a == 'x' and b != 'y'"

# OR domain conversion:
# Before: attrs="{'invisible': ['|', ('a', '=', 1), ('b', '=', 2)]}"
# After:  invisible="a == 1 or b == 2"

# AI handles all domain operators: =, !=, >, <, in, not in, like, ilike

2. Method Migration

# AI replaces deprecated/removed methods:

# Before:
def write(self, vals):
    result = super(MyModel, self).write(vals)
    self.message_post_with_view(
        'module.mail_template_view',
        subject='Updated',
    )
    return result

# After (AI-generated):
def write(self, vals):
    result = super().write(vals)  # simplified super() call
    self.message_post_with_source(
        'module.mail_template_view',
        subject='Updated',
    )
    return result

3. Import Fixes

# AI updates all import paths:

# Before:
from odoo.exceptions import except_orm, Warning
from odoo.tools import pycompat
from odoo import SUPERUSER_ID, api, fields, models, _

# After:
from odoo.exceptions import UserError, ValidationError
# pycompat removed — use standard Python 3
from odoo import api, fields, models, _, SUPERUSER_ID

Migration Script Generation

# AI generates pre-migration and post-migration scripts:

# pre-migrate.py (runs before module update)
def migrate(cr, version):
    """Pre-migration: rename columns before ORM loads."""
    # Renamed field: old_field → new_field
    cr.execute("""
        ALTER TABLE my_model
        RENAME COLUMN old_field TO new_field
    """)
    # Removed field: archive data before column drops
    cr.execute("""
        CREATE TABLE IF NOT EXISTS _migration_backup_my_model AS
        SELECT id, removed_field FROM my_model
    """)

# post-migrate.py (runs after module update)
def migrate(cr, version):
    """Post-migration: data transformations."""
    from odoo import api, SUPERUSER_ID
    env = api.Environment(cr, SUPERUSER_ID, {})
    
    # Convert old state values to new ones
    records = env['my.model'].search([
        ('state', '=', 'old_state')
    ])
    records.write({'state': 'new_state'})
    
    # Recompute stored fields that changed formula
    env['my.model'].search([])._compute_total_amount()

JavaScript/OWL Migration

  • Widget API changes between versions
  • OWL component lifecycle method renames
  • Template syntax updates
  • Asset bundle restructuring
  • New hook patterns replacing old patterns

Migration Checklist AI Generates

CheckStatusDetails
Python API changesAuto-fixed5 methods updated
View attrs removalAuto-fixed23 views converted
Import pathsAuto-fixed3 files updated
Field changesAuto-fixed2 parameters removed
JavaScript widgetsNeeds review4 files flagged
Data migrationScript readyReview before running
Test updatesAuto-fixed8 test methods updated
Manifest versionAuto-fixed19.0.x.x.x

Migration Speed

Module SizeManual MigrationAI-Assisted
Small (5-10 files)1-2 days2-4 hours
Medium (20-50 files)3-5 days1-2 days
Large (100+ files)2-4 weeks3-5 days

DeployMonkey AI Migration

DeployMonkey's AI coding agent scans your custom Odoo modules and generates migration patches for version upgrades. Upload your module, specify the target version, and get a detailed migration report with auto-generated fixes for most breaking changes.