アップデートしても壊れない — Odoo の拡張の作り方
公式の Odoo には手を入れず、アドオンで足す。そのうえで「やってはいけない 8 つ」を守る。Odoo 19 で実験して確かめた、版上げに耐える拡張の作り方を説明します。
目次
目次
このページには目次がありません

業務システムに手を入れるとき、いちばん心配なのは「直したところが、次の版上げで動かなくなる」ことです。Odoo では、公式の Odoo には手を入れず、アドオンという別の部品として足すのが基本です。ただし Odoo の拡張の道具はとても強く、使い方を誤ると、エラーも出ずに他の部品の処理が消えます。
この記事では、当社が Odoo 19.0-20261015(Community)で行った 11 の実験・28 項目の結果をもとに、版上げに耐える作り方と、やってはいけないことをまとめます。
3 つの層に分けて置く
当社は、足す物を 3 つの層に分けて置きます。
| 層 | 置く物 | 版を上げるとき |
|---|---|---|
| 御社ごとの部品 | 御社だけの項目・帳票・手順 | 新しい版へ移し、御社の業務で動くか確かめる |
| 日本向けの部品 | 締め請求・入金の消込・承認・日本の様式の帳票など、日本の会社に共通の物 | 当社が新しい版へ移す |
| 公式の Odoo(Community) | 公式が配布する本体 | 中身は書き換えず、新しい版に入れ替える |
判断はシンプルです。どの会社にも害の無い物は「日本向け」へ、御社だけの物は「御社ごと」へ。御社の部品で公式の動きを止めたり、見える範囲を広げたりしたくなったときは、先に日本向けの部品に「切り替えのスイッチ」を用意し、御社の側ではそれを入れるだけにします。
Odoo の足し方
Odoo は、公式の部品を書き換えずに足すための道具を、最初から持っています。
- モデルの継承:
_inheritで、公式のモデル(例:受注)に項目や処理を足す - 画面の継承:公式の画面を指して、「この項目の後ろに足す」と書く
- 処理の上書き:公式の処理を上書きし、その中で
super()を呼んで元の処理も動かす - データの初期値:XML で配り、現場で変える値には
noupdate="1"を付ける - 版ごとの移し替え:アドオンの版を上げ、その版のフォルダに移し替えの手順(upgrade script)を置く
たとえば「受注を確定したら、御社のルールで 1 つ処理を足す」なら、次のように書きます。
from odoo import models
class SaleOrder(models.Model):
_inherit = "sale.order"
def action_confirm(self):
res = super().action_confirm() # 公式の確定と、他のアドオンの処理を先に動かす
for order in self:
order._jp_after_confirm() # 足したい処理は、別のメソッドに切り出す
return res
公式の受注の画面にも、公式のアドオンどうしが同じやり方で足し合っています。開発者モードでビューを開くと、継承している画面が並びます。
見積・受注の標準の画面に、CRM・購買・在庫・経費・製造の各アドオンが、継承で 6 つの画面を足しています。上の帯は Odoo 自身の注意書きで、元の画面を直接編集しないよう勧めています。帯の中の Studio は Enterprise の機能です(画面は見本のデータです)
測ってわかったこと:Odoo は「できてしまう」
実験の一番の結論は、Odoo では、公式の処理を取り除くことも、見える範囲を広げることも、アドオンからできてしまうことでした。できる範囲が広いぶん、決まりは「できない」ではなく「やってはいけない」として持つ必要があります。
いくつかの結果を挙げます。
super()を呼ばずに上書きした:先に入っていた 2 つのアドオンの処理が、エラーも出ずに消えました。後からsuper()を呼ぶアドオンを足しても、消えた処理は戻りませんでした- 他のアドオンと同じモデル名を、継承なしで定義した:インストールはそのまま通り、元のモデルの項目が見えなくなりました(データベースの列は残ります)
- 画面の項目を
replaceで消し、別のアドオンがその項目の後ろに足した:入れる順番によっては、後のアドオンのインストールが止まりました - アクセス権を 1 行足した:管理者だけが読めるはずのデータを、一般の利用者が読めるようになりました
- アドオンで足した項目:そのアドオンを外すと、項目のデータも消えました
やってはいけない 8 つ
上の結果から、当社は次の決まりで作ります。
| # | やってはいけないこと | 代わりにすること | 実験で起きたこと |
|---|---|---|---|
| 1 | 他のモジュールと同じモデル名を、_inherit なしで定義する | 必ず _inherit で足す | 元の項目が黙って消えた |
| 2 | super() を呼ばずに上書きする | 止めたい処理は、日本向けの部品の設定スイッチで止める | 他のアドオンの処理が黙って消えた |
| 3 | 他のモジュールの画面やデータを、外部 ID で直接書き換える | 画面は継承で、値は upgrade script で変える | アドオンを外しても元に戻らなかった |
| 4 | 画面の継承で position="replace" を使う | 属性の変更・後ろに足す・中に足す | 入れる順番でインストールが止まった |
| 5 | アクセス権の行や、グループ付きの見える範囲のルールを、軽く足す | 「緩める変更」として別の人が必ず確かめる。sudo() は使った箇所を数えて残す | 1 行で一般の利用者が読めるようになった |
| 6 | 外す前の備えなしにアドオンを外す | 外す前に必ずバックアップ。残したい項目は日本向けの部品に持つ | 外すと項目のデータが消えた |
| 7 | 業務の処理を、モデルの外の関数に置く | モデルのメソッドに細かく切る(そこが後から足せる場所になる) | モデルの外の関数は、他のアドオンから差し替えられなかった |
| 8 | 同じ処理を重ねるアドオンどうしの順番を、成り行きに任せる | depends で順番をはっきり書く | 依存の書き方で、処理の順番が変わった |
ほかに、版ごとの移し替えの手順は「アドオンの版を上げ忘れると走らない」「一度走った手順を別の版のフォルダへ移すと、もう一度走って二重になる」ことも確かめました。現場で変える初期値に noupdate="1" を付けないと、アドオンを更新するたびに元の値へ戻ります。
毎年の版上げには、移す作業が要る
ここまでの作り方で、同じ版の中の更新(公式の修正の取り込み)は、公式の Odoo を入れ替え、アドオンを更新してテストを回す、という手順で進められます。
一方、Odoo の大きな版は毎年のように出ます。大きな版をまたぐと、公式の画面の作りや項目の名前が変わることがあり、アドオンを新しい版へ移す作業が要ります。公式に手を入れていないので、移す範囲は「足した部品」に限られます。それでも、作業そのものは無くなりません。
当社は、日本向けの部品を新しい版へ移し、御社ごとの部品も移したうえで、御社の業務の流れで動くかを確かめてから切り替えます。
まとめ
- 公式の Odoo には手を入れず、日本向けの部品と御社ごとの部品を、アドオンとして足す
- Odoo の道具は強く、取り除く・緩めることもできてしまう。だから「やってはいけない 8 つ」を決まりとして守る
- 同じ版の中の更新は入れ替えとテストで進められる。大きな版をまたぐときは、足した部品を移す作業が要る
足した部品は御社の手元に残り、版を上げても使い続けられます。アドオンの作り方そのものは「本格拡張はアドオンで — Odoo の拡張開発の基本」で説明しています。
