Odoo portal モデルの新規追加

やり方は「モデル(model_id)を1つ渡したら、Fields / Views / Tabs / Smart Buttons の“空の器”を一括で冪等に作る」スキャフォールド(雛形生成)を用意する、という設計が安全です。まずは手順と方針を固めましょう(コードはこのあとでOK)。


ゴール

  • 新しい model_id を追加 → すぐ編集できるように
    portal_view(各 view_type)+ *portal_view_common / _settings / permissions / action / menu
    portal_fields(不可視の初期行)
    tabs(フォーム用の空タブ)
    smart_buttons(ワイヤ未設定のプレースホルダ)
    1トランザクションで生成。
  • 既に存在するものは作らない(冪等)。

いつ動かす?(トリガー)

  • 推奨:明示APIPOST /models/scaffold(引数:model または model_id、オプション多数)
    • UIボタンやSwaggerから実行できるようにする
    • 将来の条件分岐(kanban/calendarを作るか 等)を柔軟に制御しやすい
  • 代替:portal_model に insert されたら DB トリガーで最小雛形だけ作る(高度な判定はアプリ側)

スキャフォールドの中身(何を作る?)

以下は model 単位でまとめて作成します(既存があれば skip)。

1) Fields(portal_fields

  • データ源:
    1. Odoo の ir_model_fields(推奨)
    2. 既に持っている portal_fields(別モデルからのコピーや再取込)
    3. 最終手段:DBテーブルからの反射(列名→粗い型推定)
  • 全フィールドを行として作成(まだ表示しないので OK)
    • model = 追加モデル、field_name, ttype, relation_model, label_i18n など
    • 既定は不可視の方針に沿うため、view側では display_fields=[] のままにします(可視制御は view 側)

これで「既存が持っているフィールドはデフォルトで invisible」の下地が整います。

2) Views(portal_view と 1:1 付随)

各 view_type ごとに“空”の1行を作成(最低 list, form, search。必要なら kanban, calendar は条件付き)。

  • portal_view
    • (model_id, model, view_type, view_name, enabled=true, priority_ui='standard', priority_num=16, ai_purpose=NULL, notes=NULL)
    • 一意制約イメージ:UNIQUE(model_id, view_type)
  • portal_view_common
    • display_fields = [])/sort_*, default_* = NULL
  • portal_view_permissions
    • can_create=true, can_edit=true, can_delete=false, inline_edit=false, mass_edit=false, show_invisible=false
  • portal_list_settingsinline_edit=false, page_hint=NULL, export_policy='inherit'
  • portal_form_settingsshow_header=true, show_footer=true
  • portal_search_settingspriority_ui/num=NULL, search_fields=NULL, filters=NULL, group_by_filters=NULL
  • portal_actionview_mode='tree,form', domain=NULL, context=NULL, target='current'
  • portal_menucreate_menu=false(既定は作らない)

kanban は画像やカード表現が決まってから、calendar は date/datetime が選べてから後追いで生成にするのが安定です。

3) Tabs(フォーム用)

  • 空タブを雛形として複数行作成(例:main, relations, notes
    • 例:{"tab_key":"main","label_i18n":{"ja_JP":"基本"},"sequence":10},
      {"tab_key":"relations","label_i18n":{"ja_JP":"関連"},"sequence":20},
      {"tab_key":"notes","label_i18n":{"ja_JP":"メモ"},"sequence":30}
  • 中身(どのフィールドをどのタブへ)は未割当。UI で後から移動可能に。
  • タブ関連のテーブル(portal_tabs 等)の実 DDL に従い、最低限の必須列だけ埋めます。

4) Smart Buttons

  • プレースホルダとして作成(すぐ動かないが配置の器だけ作る):
    • button_key: to_<relation> など
    • label_i18n: 関連名(例:「見積」「請求書」)
    • origin='portal', action_type='other', action_ref=NULL, target='current', show_count=false, sequence=10 から採番
  • 候補の決め方(自動):
    • モデルの one2many / many2many を列挙 → 代表的な関連だけ雛形化
    • many2one の逆参照は後で要件次第。最初は x2many系だけで十分

作成順序(1トランザクション)

  1. アドバイザリロックhashtext(model))で競合を抑止(任意)
  2. portal_model を upsert(あれば取得だけ)
  3. portal_fields を投入(存在確認して差分のみ)
  4. 各 view_type の portal_view を upsert
  5. 4で作った view_id に対して、1:1 付随テーブルを upsert(空値)
  6. tabs 雛形(フォーム view のみ)を upsert
  7. smart_buttons 雛形を upsert
  8. コミット
  9. (任意)Chroma エクスポート/views/export/chroma & /fields/export/chroma)を直後に実行

各 upsert は 冪等(既にあれば何もしない)。ON CONFLICT DO NOTHING または事前 SELECT を使用。


オプション(APIパラメータで制御)

  • view_types=["list","form","search"](追加で "kanban","calendar"
  • make_tabs=true/false(既定 true)
  • make_buttons=true/false(既定 true)
  • fields_source="odoo"|"reflect"|"none"(取得の仕方)
  • also_export_to_chroma=true/false(完了後に自動エクスポート)
  • dry_run=true/false(作成予定のプレビューだけ返す)

期待できる“空の器”の状態

  • 画面定義は すべて1行ずつ存在(まだ何も表示しない)
  • display_fields は空既存フィールドは不可視の運用と整合
  • タブやスマートボタンは 見出し/順序だけ決まっている(ワイヤは未接続)
  • 以後は UI で
    • display_fields を追加(見せたいフィールドだけ)
    • search_fields/filters を設定
    • 必要に応じて smart button の action_ref を配線
    • タブにフィールドをドラッグ配置
  • 最後に Chroma エクスポートで検索・NL2SQL に即反映

失敗しないための注意

  • 全部まとめてトランザクションにする(失敗時は何も残さない)
  • 競合(同時実行)はアドバイザリロック or UNIQUEON CONFLICT で抑止
  • 権限:生成系は管理者のみ実行
  • ログnotes に「scaffolded at <ts> by <user>」を追記しておくと監査に便利

Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です