Ein Major-Version-Upgrade bei Odoo ist mehr als nur ein Knopfdruck – besonders wenn Custom Modules im Spiel sind. Hier ein Praxisbericht vom Upgrade einer Odoo.sh-Instanz von v18 auf v19.

Wie der Odoo.sh Upgrade-Prozess funktioniert

Das Besondere an diesem Upgrade: Ich habe es nicht per Hand gemacht, sondern mit Claude Opus 4.6 in der Cursor IDE automatisiert. Ich habe dem Agenten Zugriff auf das Repo gegeben, eine klare Liste von Regeln definiert (Tests müssen grün sein, keine neuen Abhängigkeiten, keine uncommitteten Dateien), und dann den Odoo.sh Upgrade-Branch mehrfach durchlaufen lassen. Claude kümmerte sich um die Fixes, ich nur noch um die Code Reviews.

Odoo.sh stellt einen speziellen Upgrade-Branch bereit. Bei jedem Push passiert folgendes:

  1. Das letzte Produktions-Backup wird von der Odoo Upgrade-Plattform konvertiert (v18 → v19)
  2. Das konvertierte Backup wird wiederhergestellt
  3. Alle Custom Modules werden mit --update all aktualisiert

Das klingt einfach – die Herausforderung liegt in Schritt 3.

Die häufigsten Stolpersteine

1. Manifest-Versionen bumpen

Jedes Custom Module braucht eine aktualisierte Version in der __manifest__.py:

# vorher
"version": "18.0.1.12.0",
# nachher
"version": "19.0.1.12.0",

2. Deprecations im ORM

Odoo v19 verschärft einige API-Patterns. Ein klassisches Beispiel:

# v18 (deprecated)
db_name = self._cr.dbname
# v19 (korrekt)
db_name = self.env.cr.dbname

3. Feld-Umbenennungen

Manche Felder wurden umbenannt. Wer product_uom in Sale-Order-Lines verwendet, muss auf product_uom_id umstellen.

4. Inkonsistente Modul-Zustände

Module, die in v18 installiert waren aber in v19 nicht mehr existieren, verursachen den gefürchteten Fehler:

Some modules have inconsistent states, some dependencies may be missing

Die Lösung: Stub-Module als Platzhalter erstellen oder per Migration Script die DB-Einträge bereinigen.

Wichtig: Odoo v19 validiert jetzt Modul-Namen strikt. Verzeichnisse mit Bindestrichen (z.B. modul-name-mit-bindestrich) werden mit FileNotFoundError: Invalid module name abgelehnt. Solche Module können nur per SQL in ir_module_module auf uninstalled gesetzt werden.

5. Kaputte QWeb-Views aus dem Website Builder

Website-Builder-Anpassungen werden als ir.ui.view-Einträge in der Datenbank gespeichert. Wenn v19 ein Template-Element entfernt (z.B. <div itemprop="description"> auf der Produktseite), brechen alle darauf aufbauenden Customizations:

ValueError: Element kann nicht in der übergeordneten Ansicht lokalisiert werden

Diese Views müssen per Migration Script deaktiviert werden. Beachte: arch_db ist in v19 ein JSONB-Feld (übersetzbare Felder), daher muss bei SQL-Queries mit arch_db::text LIKE ... gearbeitet werden.

6. Accessibility-Anforderungen

v19 verlangt, dass alle <i>-Tags mit FontAwesome-Klassen ein title-Attribut haben:

<!-- v18 -->
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
<!-- v19 -->
<i class="fa fa-exclamation-triangle" aria-hidden="true" title="Warning"></i>

Mein Ansatz: Migration Scripts + Claude Opus 4.6

Da die base/upgrades/-Scripts nur beim initialen Upgrade laufen (nicht bei jedem Push), habe ich die DB-Bereinigung in die Migration Scripts unserer eigenen Module verlagert. Das Zusammenspiel war wie folgt:

  • Claude Opus 4.6 lief in Cursor IDE mit vollem Zugriff auf das Repo
  • Der Agent bekam Tasks wie "Stub-Modul anlegen", "QWeb-View deaktivieren", "arch_db Query schreiben"
  • Migration Scripts wurden automatisch erzeugt und ich habe sie nur noch reviewed
  • Jede Iteration endete mit einem Push auf den Upgrade-Branch, ohne dass ich die Shell anfassen musste
custom_module/
  migrations/
    19.0.1.12.0/
      pre-migrate.py   ← bereinigt inkonsistente Module
      post-migrate.py  ← deaktiviert kaputte QWeb-Views

Diese laufen bei jedem Build, weil das Backup die Module immer im v18-Zustand wiederherstellt.

Fazit

Ein Odoo-Upgrade erfordert Geduld und einen iterativen Ansatz: pushen, Build-Log lesen, fixen, wiederholen. Die wichtigsten Learnings:

  • Stub-Module helfen bei fehlenden Abhängigkeiten
  • Migration Scripts in Custom Modules sind zuverlässiger als base/upgrades/
  • JSONB-Felder erfordern angepasste SQL-Queries
  • Jeden Build-Log genau lesen – Warnings von heute sind die Errors von morgen