| name | odoo-upgrade |
| description | Comprehensive Odoo ERP upgrade assistant for migrating modules between Odoo versions (14-19). Handles XML views, Python API changes, JavaScript/OWL components, theme SCSS variables, manifest updates, security implementations, and database migrations. Use when user asks to upgrade Odoo modules, fix version compatibility issues, migrate themes between versions, or resolve Odoo 17/18/19 migration errors. Specializes in frontend RPC service migrations, view XML transformations, theme variable restructuring, and portal template XPath fixes. |
| version | 4.0.0 |
| author | TAQAT Techno |
| license | MIT |
| allowed-tools | ["Read","Write","Edit","Bash","Glob","Grep"] |
| metadata | {"odoo-versions":["14","15","16","17","18","19"],"transformation-patterns":150,"auto-fixes":75} |
Odoo Upgrade Assistant v4.0
A comprehensive skill for upgrading Odoo modules between versions, with extensive pattern recognition, automated fixes, and deep integration with Odoo's architecture for common migration issues.
Version Compatibility Matrix
| Odoo Version | Python | PostgreSQL | Bootstrap | Owl | Status |
|---|
| 14.0 | 3.7-3.10 | 13+ | 4.5.0 | experimental | Legacy |
| 15.0 | 3.8-3.11 | 13+ | 5.0.2 | experimental | Legacy |
| 16.0 | 3.9-3.12 | 13+ | 5.1.3 | v1 | Stable |
| 17.0 | 3.10-3.13 | 13+ | 5.1.3 | v1 | Active |
| 18.0 | 3.10-3.13 | 13+ | 5.1.3 | v2 | Active |
| 19.0 | 3.10-3.13 | 13+ | 5.1.3 | v2 | Latest |
When to Use This Skill
Activate this skill when:
- User requests upgrading Odoo modules between versions (14→19)
- Fixing Odoo version compatibility errors
- Migrating themes or custom modules to newer versions
- Resolving RPC service errors in frontend components
- Converting XML views for newer Odoo versions (tree→list, search groups)
- Updating SCSS variables for Odoo 18/19 themes
- Fixing portal view XPath inheritance errors
- Updating mail template helper functions
- Migrating JavaScript from Owl v1 to v2
Upgrade Workflow
1. Initial Analysis
- Check __manifest__.py version
- Identify module dependencies
- List all file types (XML, Python, JS, SCSS)
- Create backup before changes
2. Manifest Updates
Standard Manifest Fields (Odoo 19 TaqaTechno Standard)
{
'name': 'Module Display Name',
'version': '19.0.1.0.0',
'summary': 'Brief description',
'category': 'Category Name',
'author': 'TaqaTechno',
'website': 'https://www.taqatechno.com/',
'support': 'support@example.com',
'license': 'LGPL-3',
'contributors': [
'Developer Name',
],
'depends': ['base', 'other_module'],
'data': [
'security/group_*.xml',
'security/ir.model.access.csv',
'security/rules_*.xml',
'views/*.xml',
'data/*.xml',
],
'assets': {
'web.assets_frontend': [
'module_name/static/src/js/*.js',
'module_name/static/src/scss/*.scss',
],
'web._assets_primary_variables': [
'module_name/static/src/scss/primary_variables.scss',
],
'web._assets_frontend_helpers': [
'module_name/static/src/scss/bootstrap_overridden.scss',
],
},
'installable': True,
'auto_install': False,
'application': False,
}
Version String Migration
3. XML/View Transformations
Search Views (Odoo 19)
<search>
<group expand="0" string="Group By">
<filter name="type" string="Type"/>
</group>
</search>
<search>
<filter name="type" string="Type"/>
</search>
Tree to List Views (Comprehensive)
<tree string="Title" edit="1" editable="top">
<field name="name"/>
</tree>
<list string="Title" editable="top">
<field name="name"/>
</list>
<record id="action_my_model" model="ir.actions.act_window">
<field name="view_mode">tree,form,kanban</field>
</record>
<record id="action_my_model" model="ir.actions.act_window">
<field name="view_mode">list,form,kanban</field>
</record>
<xpath expr="//tree" position="inside">
<field name="new_field"/>
</xpath>
<xpath expr="//tree/field[@name='name']" position="after">
<field name="other_field"/>
</xpath>
<xpath expr="//list" position="inside">
<field name="new_field"/>
</xpath>
<xpath expr="//list/field[@name='name']" position="after">
<field name="other_field"/>
</xpath>
<group expand="0" string="Group By">
<filter name="group_status" context="{'group_by': 'state'}"/>
</group>
<group string="Group By">
<filter name="group_status" context="{'group_by': 'state'}"/>
</group>
Python view_mode Dictionary (Odoo 18/19)
def action_view_records(self):
return {
'type': 'ir.actions.act_window',
'res_model': 'my.model',
'view_mode': 'tree,form',
'view_type': 'tree',
}
def action_view_records(self):
return {
'type': 'ir.actions.act_window',
'res_model': 'my.model',
'view_mode': 'list,form',
}
Kanban Templates (Odoo 19)
<t t-name="kanban-box">
<t t-name="card">
Form View Context (Odoo 19)
context="{'search_default_type_id': active_id}"
context="{'search_default_type_id': id}"
Cron Jobs (Odoo 19)
Remove numbercall field - no longer supported:
<field name="numbercall">-1</field>
4. Python API Migrations
Slug Function (Odoo 18+)
from odoo.http import request
def slug(value):
"""Compatibility wrapper for slug function"""
return request.env['ir.http']._slug(value)
def unslug(value):
"""Compatibility wrapper for unslug function"""
return request.env['ir.http']._unslug(value)
URL For Function (Odoo 19)
from odoo.addons.http_routing.models.ir_http import url_for
url = url_for('/path')
url = self.env['ir.http']._url_for('/path')
5. JavaScript/OWL Frontend Migrations
RPC Service Replacement (Odoo 19)
The RPC service is NOT available in Odoo 19 frontend/public components.
import {useService} from "@web/core/utils/hooks";
export class MyComponent extends Component {
setup() {
this.rpc = useService("rpc");
}
async fetchData() {
const data = await this.rpc("/api/endpoint", params);
}
}
export class MyComponent extends Component {
setup() {
}
async _jsonRpc(endpoint, params = {}) {
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Csrf-Token': document.querySelector('meta[name="csrf-token"]')?.content || '',
},
body: JSON.stringify({
jsonrpc: "2.0",
method: "call",
params: params,
id: Math.floor(Math.random() * 1000000)
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.error) {
throw new Error(data.error.message || 'RPC call failed');
}
return data.result;
} catch (error) {
console.error('JSON-RPC call failed:', error);
throw error;
}
}
async fetchData() {
const data = await this._jsonRpc("/api/endpoint", params);
}
}
OWL 1.x → OWL 2.0 Lifecycle Hook Migration (Odoo 18+)
OWL 2.0 (used in Odoo 18+) renames all lifecycle hooks and changes the constructor signature. This is a breaking change — old method names simply won't be called.
Lifecycle Hook Rename Table:
| OWL 1.x (Odoo 14-17) | OWL 2.0 (Odoo 18-19) | Notes |
|---|
constructor(parent, props) | setup() | No super() needed |
willStart() | onWillStart(callback) | Now uses onWillStart hook function |
mounted() | onMounted(callback) | Now uses onMounted hook function |
willUpdateProps(nextProps) | onWillUpdateProps(callback) | Callback receives nextProps |
patched() | onPatched(callback) | Now uses onPatched hook function |
willUnmount() | onWillUnmount(callback) | Now uses onWillUnmount hook function |
willPatch() | onWillPatch(callback) | Now uses onWillPatch hook function |
destroyed() | onDestroyed(callback) | Now uses onDestroyed hook function |
Before (OWL 1.x — Odoo 14-17):
import { Component } from "@odoo/owl";
export class MyWidget extends Component {
constructor(parent, props) {
super(...arguments);
this.state = { count: 0 };
}
async willStart() {
this.data = await this._loadData();
}
mounted() {
this._setupListeners();
}
patched() {
this._updateDOM();
}
willUnmount() {
this._cleanupListeners();
}
}
After (OWL 2.0 — Odoo 18-19):
import { Component, onMounted, onPatched, onWillStart, onWillUnmount, useState } from "@odoo/owl";
export class MyWidget extends Component {
setup() {
this.state = useState({ count: 0 });
onWillStart(async () => {
this.data = await this._loadData();
});
onMounted(() => {
this._setupListeners();
});
onPatched(() => {
this._updateDOM();
});
onWillUnmount(() => {
this._cleanupListeners();
});
}
}
Key OWL 2.0 Import Changes:
import { Component } from "@odoo/owl";
import {
Component,
useState,
useRef,
useEnv,
onMounted,
onPatched,
onWillStart,
onWillUpdateProps,
onWillPatch,
onWillUnmount,
onDestroyed,
} from "@odoo/owl";
Auto-fix command:
python scripts/auto_fix_library.py --fix owl_lifecycle <project_path>
Detection command:
python scripts/odoo19_precheck.py <project_path>
6. Theme SCSS Variables (Odoo 19)
Proper Structure
$o-theme-h1-font-size-multiplier: (64 / 16);
$o-theme-headings-font-weight: 700;
$o-website-values-palettes: (
(
'color-palettes-name': 'my_theme',
'font': 'Inter',
'headings-font': 'Inter',
'btn-padding-y': 1rem, // Use rem not px
'btn-padding-x': 2rem,
),
);
$o-color-palettes: map-merge($o-color-palettes, (
'my_theme': (
'o-color-1': #124F81,
'o-color-2': #B1025D,
'o-color-3': #f8fafc,
'o-color-4': #ffffff,
'o-color-5': #1e293b,
'menu': 1, // IMPORTANT: Specify which color for menu
'footer': 4, // IMPORTANT: Specify which color for footer
'copyright': 5, // IMPORTANT: Specify which color for copyright
),
));
$o-theme-font-configs: map-merge($o-theme-font-configs, (
'Inter': (
'family': ('Inter', sans-serif),
'url': 'Inter:300,400,500,600,700&display=swap',
'properties': ( // IMPORTANT: Add properties section
'base': (
'font-size-base': 1rem,
'line-height-base': 1.6,
),
)
),
));
7. Theme Snippet System (Odoo 19)
Remove incompatible website.snippet_options inheritance:
<template id="custom_footer_op" inherit_id="website.snippet_options">
</template>
Common Errors and Solutions
Error: "Service rpc is not available"
- Cause: Using
useService("rpc") in frontend components
- Solution: Replace with
_jsonRpc helper method using fetch API
Error: "Invalid field 'numbercall' in 'ir.cron'"
- Cause: Field removed in Odoo 19
- Solution: Remove
<field name="numbercall"> from cron definitions
Error: "Invalid view definition" (search views)
- Cause:
<group> tags not allowed in search views (Odoo 19)
- Solution: Remove
<group> tags, keep filters at root level
Error: "Missing 'card' template"
- Cause: Kanban template name changed in Odoo 19
- Solution: Change
t-name="kanban-box" to t-name="card"
Error: "cannot import name 'slug'"
- Cause: Import location changed in Odoo 18+
- Solution: Add compatibility wrapper function
Error: "External ID not found: website.snippet_options"
- Cause: Snippet system changed in Odoo 19
- Solution: Remove the incompatible template
Error: "field 'active_id' does not exist"
- Cause:
active_id not available in form view contexts (Odoo 19)
- Solution: Replace
active_id with id
Testing Checklist
After upgrade, test:
Helper Commands
python -m odoo -d [DB] -i [MODULE] --addons-path=odoo/addons,projects/[PROJECT] --stop-after-init
python -m odoo -d [DB] -u [MODULE] --stop-after-init
python -m odoo -d [DB] --dev=xml,css,js
pip install geopy spacy hachoir
Migration Report Template
Generate comprehensive reports documenting:
- Files modified count
- Lines changed
- Patterns applied
- Manual fixes needed
- External dependencies added
- Testing status
- Known issues
- Rollback instructions
Advanced Patterns
Multi-Module Projects
When upgrading projects with multiple interdependent modules:
- Analyze dependency tree
- Upgrade in dependency order
- Test each module individually
- Test integrated functionality
Theme Migrations
Special considerations for themes:
- SCSS variable structure changes
- Bootstrap version compatibility
- Snippet system updates
- Asset bundling changes
Performance Optimization
After upgrade:
- Regenerate assets
- Clear caches
- Recompile Python files
- Optimize database indexes
Version-Specific Notes
Odoo 14 → 15
- Bootstrap 4.x → 5.x (major CSS class changes)
- QWeb syntax:
t-use-call removed, use t-call
- Payment Provider API changes
- Left/Right classes → Start/End for RTL support
Odoo 15 → 16
- Bootstrap 5.1.3 standardization
- Web framework module reorganization
- Website page template changes
- Payment flow updates
- Owl v1 adoption begins
Odoo 16 → 17
- OWL framework v1 fully adopted
- Widget system changes
- Asset pipeline updates
- publicWidget API stabilization
- Theme color palette improvements
Odoo 17 → 18
- Owl v1 → v2 migration starts
- Minor XML changes
- Python API mostly compatible
- JavaScript minor updates
- Snippet group system introduced
Odoo 18 → 19
- Major frontend architecture changes
- RPC service REMOVED from public components
- Snippet system overhaul (groups required)
- Kanban template:
kanban-box → card
- Search view:
<group> tags NOT allowed
<tree> views → <list> views
- XPath expressions:
//tree → //list
- Portal view templates completely restructured
- Mail template helpers: remove
env parameter
- Cron jobs:
numbercall field removed
Security Implementation (Required for All Versions)
1. Model Access (ir.model.access.csv)
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_model_user,my.model.user,model_my_model,base.group_user,1,1,1,0
access_my_model_admin,my.model.admin,model_my_model,base.group_erp_manager,1,1,1,1
2. User Groups (security/group_*.xml)
<record id="group_my_manager" model="res.groups">
<field name="name">My Manager</field>
<field name="category_id" ref="base.module_category_services"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
3. Record Rules (security/rules_*.xml)
<record id="my_model_rule" model="ir.rule">
<field name="name">My Model: User own records</field>
<field name="model_id" ref="model_my_model"/>
<field name="domain_force">[('user_id', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
Portal View XPath Migration (Odoo 19)
Sale Portal Template Changes
The sale portal templates have been completely restructured in Odoo 19:
Table Header XPaths
<xpath expr="//table[@id='sales_order_table']/thead/tr/th[3]" position="attributes">
<xpath expr="//table[@id='sales_order_table']/thead/tr/th[@id='product_unit_price_header']" position="attributes">
Available Header IDs:
th[@id='product_qty_header'] - Quantity
th[@id='product_unit_price_header'] - Unit Price
th[@id='product_discount_header'] - Discount %
th[@id='taxes_header'] - Taxes
th[@id='subtotal_header'] - Amount/Subtotal
Table Body XPaths
<xpath expr="//table[@id='sales_order_table']/tbody//t[@t-foreach='lines_to_report']//tr/t[@t-if='not line.display_type']/td[3]" position="attributes">
<xpath expr="//table[@id='sales_order_table']/tbody//tr[@name='tr_product']/td[@name='td_product_priceunit']" position="attributes">
Available Body Element Names:
tr[@name='tr_product'] - Product row
tr[@name='tr_section'] - Section row
tr[@name='tr_note'] - Note row
td[@name='td_product_name'] - Product name
td[@name='td_product_quantity'] - Quantity
td[@name='td_product_priceunit'] - Unit price
td[@name='td_product_discount'] - Discount %
td[@name='td_product_taxes'] - Taxes
td[@name='td_product_subtotal'] - Subtotal
Mail Template Migration (Odoo 19)
Helper Function Changes
<t t-out="format_datetime(env, object.date_start, dt_format='long')"/>
<t t-out="format_date(env, object.date_start)"/>
<t t-out="format_amount(env, object.amount, object.currency_id)"/>
<t t-out="format_datetime(object.date_start, dt_format='long')"/>
<t t-out="format_date(object.date_start)"/>
<t t-out="format_amount(object.amount, object.currency_id)"/>
XML Entity Encoding
<p>© 2025 Company Name</p>
<p>Company Name</p>
<p>© 2025 Company Name</p>
<p>Company Name</p>
Common Character Codes:
© → © (copyright)
→   (non-breaking space)
— → — (em dash)
™ → ™ (trademark)
€ → € (euro)
Bootstrap 4 → 5 Class Migration
| Bootstrap 4 | Bootstrap 5 | Description |
|---|
ml-* | ms-* | Margin Left → Start |
mr-* | me-* | Margin Right → End |
pl-* | ps-* | Padding Left → Start |
pr-* | pe-* | Padding Right → End |
text-left | text-start | Text align left |
text-right | text-end | Text align right |
float-left | float-start | Float left |
float-right | float-end | Float right |
form-group | mb-3 | Form group spacing |
custom-select | form-select | Custom select |
close | btn-close | Close button |
badge-primary | bg-primary | Primary badge |
font-weight-bold | fw-bold | Bold text |
sr-only | visually-hidden | Screen reader only |
no-gutters | g-0 | No gutters in grid |
Helper Commands
python scripts/odoo19_precheck.py <project_path>
python scripts/quick_fix_odoo19.py <project_path>
python scripts/upgrade_to_odoo19.py <project_path>
python scripts/upgrade_manifest.py <project_path> 19.0
python scripts/fix_rpc_service.py <project_path>
python -m odoo -d [DB] -i [MODULE] --addons-path=odoo/addons,projects/[PROJECT] --stop-after-init
python -m odoo -d [DB] -u [MODULE] --stop-after-init
python -m odoo -d [DB] --dev=all
Migration Report Template
Generate comprehensive reports documenting:
- Files modified count
- Lines changed
- Patterns applied
- Manual fixes needed
- External dependencies added
- Testing status
- Known issues
- Rollback instructions
References