はい、その割り切りはかなり有力です。
少なくとも、あなたの今の構想には合っています。
結論から言うと、基本方針はこうです。
業務ワークフローは自作
Odoo は最終反映先・計算先・台帳先
この分担のほうが、たぶんあなたには向いています。
なぜそのほうが良いか
Odoo の標準ワークフローや各アプリ内の状態遷移は、もちろん便利です。
ただ、あなたが今やりたいのは単なる承認ではなく、
- 部署 × 役職
- ownership
- 組織変更
- SQL 制御
- Neo4j 正本
- 独自ポータル
- 将来の説明可能性
までまとめて扱うことですよね。
そうなると、Odoo 側のワークフローに寄せるほど、逆にこうなりやすいです。
- Odoo の都合に設計が引っ張られる
- 承認ロジックが Odoo 内に閉じる
- Neo4j 正本と二重管理になる
- 画面もロジックも Odoo 依存が強くなる
- あとで変えにくい
なので、あなたのケースでは
承認・申請・差戻し・次承認者決定は自作
Odoo は結果を受けて必要データを更新するだけ
のほうが筋がいいです。
どう分けるのがよいか
自作側で持つもの
- 申請状態
- 承認経路
- 誰が次に承認できるか
- ownership
- 部署・役職
- 差戻し履歴
- 監査ログ
- 表示制御
- SQL 制御
Odoo に任せるもの
- 会計転記
- 在庫反映
- 請求・支払など標準業務処理
- マスタ更新
- 必要最小限の台帳保持
つまり、
DevPortal/Neo4j = workflow brain
Odoo = business engine / ledger engine
です。
この方式の一番良い点
ワークフローの主語が Odoo ではなく、あなたの業務モデルになることです。
たとえば稟議なら、Odoo の都合で考えるのではなく、
- 誰の申請か
- どの部署案件か
- いくらか
- 誰が承認すべきか
- 今どの状態か
で完結できます。
その結果として、
最後に
- Odoo の注文を作る
- 支払依頼を作る
- 仕訳を切る
- ステータスだけ更新する
で済みます。
このほうが自然です。
ただし、全部を最後まで貯めて「最後に一括反映」だけにするのも危ない
ここは少し注意です。
「最後にデータだけ更新」という考え方は良いのですが、
全部を最後の1回だけで反映すると、Odoo 側で途中状態が見えなくなります。
なので実務的には、2段に分けるのがよいです。
1. 業務進行中
自作側が正本
- draft
- submitted
- manager_approved
- director_approved
- rejected
2. 確定時
Odoo に反映
- 伝票作成
- 注文確定
- 会計計上
- 支払依頼登録
必要なら途中でも最小限の mirror はしていいです。
たとえば
- Odoo に reference id だけ作る
- 最終承認後に正式レコード化する
- 途中状態は自作側だけ持つ
などです。
向いているもの/向いていないもの
自作に向いている
- 申請
- 稟議
- 承認
- 差戻し
- 所有・責任範囲
- 組織ベースの閲覧制御
- 独自 UI
- 監査ログ
Odoo に任せたほうがよい
- 会計仕訳
- 在庫引当
- 販売・購買の標準確定処理
- Odoo標準帳票に乗る処理
私ならこうします
方針
ワークフロー本体は自作
- Neo4j で定義
- DevPortal で実行
- Postgres に履歴保存
Odoo は確定処理だけ担当
- 最終承認後に create/write
- 必要なら status sync
- 仕訳や受発注など標準ロジック利用
一番しっくりくる整理
あなたの構想を一文で言うとこうです。
Odoo を“業務画面付きERP”として使うのではなく、
“標準業務エンジン”として使い、
業務ワークフロー・権限・所有・承認は外で持つ。
この整理ならかなりぶれません。
なので答えは
はい、基本はその方向でよいと思います。
Odoo のワークフローに寄せず、自作して、最後に必要データだけ Odoo を更新する。
そのほうが、Neo4j 正本・ownership・部署役職ベース権限というあなたの設計思想に合っています。
ただし、
Odoo 側に何を“最後に更新する対象”として残すか は最初に決めたほうがいいです。
次はそこを整理すると進みます。
「Odoo に残すべきデータ」と「外で完結させるべきデータ」 を切り分けましょう。
では、そのまま設計の土台にできる形で、Neo4j を正本にした承認ワークフロー設計をまとめます。
目的は次の3つです。
- Odoo に依存しない承認基盤を作る
- Neo4j の組織構造・権限制約と自然につなげる
- 将来 Odoo Importer / Adapter で反映先を増やせるようにする
1. 全体思想
承認ワークフローは、Odoo の state 遷移や mail.activity を中心に組むのではなく、Neo4j 上の関係定義として持ちます。
役割分担はこうです。
- Neo4j
- 組織構造
- 権限構造
- 承認フロー定義
- 承認条件
- 承認履歴の主索引
- UI
- 申請
- 差分表示
- 承認・却下・差戻し
- フロー定義編集
- 履歴表示
- Execution Engine
- 承認済みリクエストを実行
- 反映先は Adapter に委譲
- Adapter
- Odoo Adapter
- SQL Adapter
- API Adapter
- Neo4j Adapter
この構成なら、承認の定義とUIは Odoo 非依存で伸ばせます。
2. 基本アーキテクチャ
処理の流れはこの形です。
Step 1. Request 作成
ユーザーが「こう変えたい」を送る
Step 2. Policy Resolve
Neo4j から、そのユーザーが
- 申請できるか
- 即時実行か
- 承認必要か
- どのフローを使うか
を判定する
Step 3. Approval Instance 生成
適用フローを固定し、承認ステップ列を作る
Step 4. UI で承認
承認者が各 step を処理する
Step 5. Execution
最終承認後に Adapter 経由で反映する
Step 6. Audit
申請〜承認〜実行結果を監査ログ化する
3. ノード設計
まずはノードです。
最小構成で十分使える形に絞ります。
3-1. 組織・権限系
User
{
"user_id": "u10",
"name": "Kenji",
"email": "kenji@example.com",
"active": true
}
Role
{
"role_key": "sales_manager",
"name": "Sales Manager"
}
OrgUnit
{
"org_key": "sales_east",
"name": "Sales East",
"org_type": "department"
}
Company
{
"company_id": "c001",
"name": "Demo Company"
}
3-2. リソース・操作系
Resource
{
"resource_key": "crm.lead",
"table_name": "fact_opportunity",
"resource_type": "model"
}
Action
{
"action_key": "write",
"name": "Write"
}
もしくはより細かく
{
"action_key": "update_stage",
"base_action": "write",
"name": "Update Opportunity Stage"
}
3-3. 承認定義系
ApprovalFlow
{
"flow_key": "opp_update_standard",
"name": "Opportunity Standard Update Flow",
"active": true,
"version": 1
}
ApprovalStep
{
"step_key": "opp_update_standard_step_1",
"step_order": 1,
"step_type": "role_approval",
"approval_mode": "any_one",
"required_count": 1
}
step_type の例:
role_approvalorg_manager_approvalspecific_user_approvalauto_approvalpolicy_check
ApprovalCondition
{
"condition_key": "amount_over_1m",
"condition_type": "expr",
"expr_lang": "jsonlogic",
"expr": {
">=": [ { "var": "payload.amount" }, 1000000 ]
}
}
ここは後で DSL を固定します。
3-4. 実行・履歴系
Request
{
"request_id": "req_20260405_0001",
"status": "pending",
"resource_key": "crm.lead",
"action_key": "write",
"created_at": "2026-04-05T10:00:00Z",
"requested_by": "u10"
}
ApprovalInstance
{
"instance_id": "ai_20260405_0001",
"flow_key": "opp_update_standard",
"status": "in_progress",
"started_at": "2026-04-05T10:01:00Z"
}
ApprovalDecision
{
"decision_id": "dec_0001",
"decision": "approved",
"comment": "OK",
"decided_at": "2026-04-05T10:10:00Z"
}
ExecutionJob
{
"job_id": "job_20260405_0001",
"adapter_type": "odoo",
"status": "queued",
"created_at": "2026-04-05T10:11:00Z"
}
4. リレーション設計
次に関係です。
4-1. 組織・権限
(u:User)-[:HAS_ROLE]->(r:Role)(u:User)-[:BELONGS_TO]->(o:OrgUnit)(o:OrgUnit)-[:PARENT_OF]->(child:OrgUnit)(u:User)-[:BELONGS_TO_COMPANY]->(c:Company)
4-2. ポリシー・操作
(r:Role)-[:CAN_REQUEST]->(a:Action)(a:Action)-[:ON_RESOURCE]->(res:Resource)(a:Action)-[:REQUIRES_FLOW]->(f:ApprovalFlow)
必要なら
(r:Role)-[:CAN_APPROVE]->(f:ApprovalFlow)
4-3. フロー定義
(f:ApprovalFlow)-[:HAS_STEP {order:1}]->(s1:ApprovalStep)(f:ApprovalFlow)-[:HAS_STEP {order:2}]->(s2:ApprovalStep)(f:ApprovalFlow)-[:HAS_CONDITION]->(cond:ApprovalCondition)
step の承認者候補はこう結びます。
(s:ApprovalStep)-[:APPROVED_BY_ROLE]->(r:Role)(s:ApprovalStep)-[:APPROVED_BY_USER]->(u:User)(s:ApprovalStep)-[:APPROVED_BY_ORG_MANAGER]->(o:OrgUnit)
4-4. 申請・承認インスタンス
(req:Request)-[:REQUESTED_BY]->(u:User)(req:Request)-[:USES_FLOW]->(f:ApprovalFlow)(req:Request)-[:HAS_APPROVAL_INSTANCE]->(ai:ApprovalInstance)(ai:ApprovalInstance)-[:HAS_STEP_INSTANCE]->(si:ApprovalStepInstance)(si:ApprovalStepInstance)-[:BASED_ON]->(s:ApprovalStep)(si:ApprovalStepInstance)-[:DECIDED_BY]->(u:User)(si:ApprovalStepInstance)-[:HAS_DECISION]->(d:ApprovalDecision)(req:Request)-[:EXECUTED_AS]->(job:ExecutionJob)
5. 実務で使いやすい status 設計
Request.status
draftpendingin_approvalapprovedrejectedreturnedexecutingexecutedexecution_failedcancelled
ApprovalInstance.status
in_progressapprovedrejectedreturnedcancelled
StepInstance.status
waitingcurrentapprovedrejectedskippedreturned
ExecutionJob.status
queuedrunningsucceededfailed
6. Request の中身
承認の実体は Request です。
ここに「何をどう変えたいか」を保持します。
おすすめは payload を分けることです。
{
"request_id": "req_20260405_0001",
"resource_key": "crm.lead",
"action_key": "write",
"target_ids": ["op0262"],
"change_set": {
"before": {
"stage": "proposal",
"memo": null
},
"after": {
"stage": "won",
"memo": "受注確定"
}
},
"context": {
"company_id": "c001",
"org_key": "sales_east",
"requested_by": "u10"
},
"reason": "受注確定のため",
"status": "pending"
}
ポイントは before/after を持つことです。
UI で差分表示しやすく、監査にも強いです。
7. 承認条件 DSL
ここはあとで重要になります。
まずは複雑にしすぎず、JSON DSL にした方が良いです。
7-1. シンプル条件
{
"all": [
{ "field": "resource_key", "op": "eq", "value": "crm.lead" },
{ "field": "action_key", "op": "eq", "value": "write" }
]
}
7-2. 金額条件
{
"all": [
{ "field": "change_set.after.amount", "op": "gte", "value": 1000000 }
]
}
7-3. 組織条件
{
"all": [
{ "field": "context.org_key", "op": "in_descendants_of", "value": "sales_head" }
]
}
7-4. 列変更条件
{
"any": [
{ "field": "changed_fields", "op": "contains", "value": "margin_rate" },
{ "field": "changed_fields", "op": "contains", "value": "internal_score" }
]
}
この DSL を ApprovalFlow や ApprovalStep に紐づけます。
8. 承認者解決ルール
承認者を毎回固定 user で持つと組織変更に弱いです。
なので原則は Role / OrgUnit から解決 です。
8-1. Role ベース
「sales_manager の誰か1人」
8-2. Org manager ベース
「申請者の所属部門の manager」
8-3. 上位組織 manager
「申請者の所属部門の親部門長」
8-4. 固定 user
例外的にシステム管理者や法務責任者
推奨
基本は
APPROVED_BY_ROLEAPPROVED_BY_ORG_MANAGER
この2つを主軸にするのが強いです。
9. フロー例
例1: 軽微な案件更新
- 対象:
crm.lead - action:
write - 条件:
changed_fieldsがmemo,next_actionのみ - 承認: 不要 or 自動承認
例2: ステージ更新
- 対象:
crm.lead - action:
write - 条件:
stageを変更 - 承認: 所属部門 manager 1名
例3: 金額変更
- 対象:
crm.lead - action:
write - 条件:
amount >= 1000000 - 承認:
- step1: 所属 manager
- step2: 部長
例4: 顧客マスタ変更
- 対象:
res.partner - action:
write - 条件:
changed_fieldsにcompany_registry,payment_terms - 承認:
- step1: 営業責任者
- step2: 管理部
10. UI 要件
UI は軽くで良いとのことですが、設計上必要な画面はあります。
10-1. 申請画面
- resource
- target
- 変更前後差分
- 申請理由
- 想定承認フローのプレビュー
10-2. 承認待ち一覧
- 自分が今処理すべき step
- 優先度
- resource
- 申請者
- 差分要約
10-3. 承認詳細
- before / after diff
- 申請理由
- フロー全体図
- 現在 step
- approve / reject / return
10-4. フロー定義画面
- flow 作成
- step 並び替え
- 条件編集
- 承認者ロジック編集
11. 実行 Adapter 設計
ここが Odoo 非依存拡張の鍵です。
共通インターフェース
class ExecutionAdapter:
def validate(self, request): ...
def dry_run(self, request): ...
def execute(self, request): ...
def rollback_hint(self, request): ...
11-1. Odoo Adapter
- ORM / XML-RPC / JSON-RPC / 専用API
- モデルごとの write/create
- Odoo 業務ロジックを活かす
11-2. SQL Adapter
- 制約付き SQL 実行
- Odoo 非依存テーブル向け
- 影響件数制限
- column 制限
11-3. API Adapter
- 外部SaaS や社内API
推奨
Odoo に書く時は、長期的には Odoo Adapter 優先 がよいです。
承認は Odoo 非依存でよいですが、反映は Odoo のロジックを使った方が安全です。
12. 監査設計
これはかなり大事です。
承認ワークフローは監査が価値になります。
最低限残すものはこれです。
- 誰が申請したか
- いつ申請したか
- 何を変えようとしたか
- 承認フローは何か
- 誰がいつ承認/却下したか
- 実行結果はどうだったか
- 失敗時のエラー内容
- 実際に反映された target_id
おすすめは、Neo4j に索引的に持ちつつ、詳細は別の RDB テーブルに逃がしてもよいです。
例:
approval_request_logapproval_decision_logexecution_job_log
13. Importer との関係
将来 Odoo Importer を作る前提なら、承認定義も Odoo 互換を意識しておくとよいです。
ただし、承認そのものは Odoo 標準に無理に寄せなくてよいです。
寄せるべきはこの部分だけです。
- Role / Group
- Resource / Model
- Action / CRUD
- Row scope
- Field scope
承認フローは Neo4j 独自でよく、必要なら Odoo には結果だけ渡せば十分です。
14. 最初の実装範囲
いきなり全部は広いので、最初はここまでで十分です。
Phase A
- User / Role / OrgUnit / Resource / Action
- ApprovalFlow / ApprovalStep
- Request / ApprovalInstance / StepInstance
- approve / reject / return API
Phase B
- 条件 DSL
- 承認者自動解決
- フロープレビュー
- 監査ログ
Phase C
- Execution Adapter
- Odoo Adapter
- dry_run
- 実行結果反映
Phase D
- フロー編集UI
- バージョン管理
- 履歴比較
- 申請テンプレート
15. 一番重要な設計原則
最後に、ぶれないように原則だけ固定します。
原則1
承認定義は Neo4j が正本
原則2
承認と実行は分離
承認されたからといって即 DB 更新ロジックを直書きしない
原則3
Request は before/after 差分を持つ
監査・UI・再実行のため
原則4
承認者は user 直指定より Role / OrgUnit 解決を優先
組織変更に強くするため
原則5
反映先は Adapter 化
Odoo 依存を閉じ込めるため
16. あなた向けの最終形
あなたの全体構成に合わせて言い切ると、こうです。
- Neo4j
- 組織
- 権限
- 承認フロー
- 条件
- 履歴索引
- UI
- 申請
- 承認
- フロー編集
- 履歴参照
- Execution Engine
- 承認済み request を adapter に渡す
- Odoo
- 受け先の1つ
- ワークフロー定義の正本ではない
この形なら、Odoo を超えて拡張できます。
次は、これをさらに実装寄りにして、
Neo4j の具体 Cypher スキーマ案
Request / Approval API の JSON 契約
を、そのまま使える形で出すのがよいです。
はい、かなりの部分は Odoo 画面で確認できます。
なので、最初から Neo4j 側に権限可視化UIを全部作らなくても、確認用UIは Odoo をかなり流用可能です。
ただし、全部がそのまま見やすく確認できるわけではありません。
結論だけ先に言うと、こうです。
- Group: Odoo 画面で確認しやすい
- ACL: Odoo 画面で確認できる
- Record Rule: Odoo 画面で確認できる
- User と Group の紐付け: Odoo 画面で確認できる
- Menu / View groups: ある程度確認できる
- Field groups: 技術者向け画面なら確認できるが、少し見づらい
- 「このユーザーには最終的に何が見えるか」の一覧: 標準では弱い
つまり、定義そのものは Odoo で見えるが、
ユーザー目線の effective permission 一覧は標準だと見づらい、という整理です。
Chapter 11 でも、group / ACL / record rule / field groups / groups on views がそれぞれ別レイヤで定義される前提になっていて、確認も同じく分散します。
1. Odoo で確認できるもの
A. Group
Importer で res.groups を作れば、Odoo のユーザー・権限系画面で見えます。
ここでは少なくとも次が確認できます。
- group 名
- implied group
- どのユーザーが属しているか
- アクセス権の関連
これは比較的見やすいです。
Neo4j から作った group を neo.group_sales_user みたいな体系で入れておけば、管理画面で追えます。
B. ACL
ir.model.access に入れた model 単位 CRUD は、技術者向け画面で確認できます。
見える内容はおおむね次です。
- 対象 model
- 対象 group
- read / create / write / delete
つまり、「この group はこの model に何ができるか」は Odoo 画面で見られます。
これはあなたの言う「テーブル相当の権限確認」に当たります。
C. Record Rule
ir.rule に入れれば、これも Odoo で確認できます。
見える内容は例えば次です。
- rule 名
- model
- group
- domain_force
- active
- read/write/create/delete の適用
つまり「どの行に制限がかかるか」の定義は見えます。
なので、Neo4j から Importer で入れた row 制約は、Odoo 側でも確認可能です。
D. User と Group の紐付け
res.users に group を付けたなら、ユーザー画面から確認できます。
- このユーザーがどの group を持つか
- implied により何が入っているか
ここも実務ではかなり使います。
「Kenji が sales_manager だから sales_user も持つ」などの確認はしやすいです。
E. Menu / View groups
menu や view に group 制御を入れた場合も、技術者モードなら追えます。
ただし、ACL や rule ほど一覧性は高くありません。
確認できるのは
- この menu はどの group に見せるか
- この view 要素はどの group か
です。
UI を隠す制御の確認には使えます。
F. Field groups
これは確認できますが、少し面倒です。
field 自体に groups が付いていれば、開発者向け画面やモデル定義側で追えます。
ただし、標準画面で
- model ごとに
- field ごとに
- group がどう付いているか
を一覧で気持ちよく見るのは弱いです。
つまり 「存在確認」はできるが、「運用確認UI」としては弱い です。
2. Odoo 標準で弱いところ
ここが大事です。
Importer で流したものが Odoo に入っていても、ユーザー目線の最終結果は標準ではやや追いにくいです。
たとえば、あなたが本当に見たいのは多分こういうものです。
- ユーザー A は
crm.leadを読めるか - ユーザー A はどの行まで見えるか
- ユーザー A は
margin_rateを見えるか - ユーザー A がこの menu を開けるか
これは Odoo では、定義が分散しているので、標準で一画面にまとまりません。
理由は単純で、最終権限は
- group
- implied group
- ACL
- record rule
- field groups
- menu/view groups
の合成結果だからです。
つまり Odoo で見えるのは主に 定義 であって、
合成後の effective permission ではありません。
3. なので実務的なおすすめ
答えは「Odoo だけで十分か」「Neo4j 側にも描画が必要か」の二択ではなく、
最初は Odoo を確認UIとして使い、足りないところだけ補助表示する が一番現実的です。
おすすめ方針
まず Odoo に任せるもの
- group 一覧
- user-group 紐付け
- model ACL
- record rule
- menu/view groups
これは Odoo で確認できます。
補助が欲しいもの
- field groups 一覧
- ある user に対する最終可視範囲
- Neo4j 定義との対応表
- Import 差分の確認
この部分だけを Neo4j 側、または Portal 側で軽く持つとよいです。
4. 一番コスパがよい方法
あなたが「Neo4j に描画させるのは結構手間」と言うなら、最初は Odoo を確認用に使う前提で問題ありません。
ただし、1つだけ追加するとかなり楽になります。
それは Importer が同時に “権限サマリ表” を出力すること です。
例えば Importer 実行時に、Odoo へ流し込むだけでなく、別途こんな CSV/JSON を出します。
{
"groups": [
{
"group_xmlid": "neo.group_sales_manager",
"implies": ["neo.group_sales_user"],
"models": [
{
"model": "crm.lead",
"read": true,
"create": true,
"write": true,
"delete": false,
"record_rules": [
"company_id = user.company_id",
"team_id in user.team_ids"
],
"restricted_fields": [
"margin_rate"
]
}
]
}
]
}
これがあると、
- 詳細確認は Odoo
- 全体俯瞰は Importer サマリ
で十分回ります。
Neo4j に本格的な権限UIを作らなくてもかなり楽です。
5. 実際にどう見えるかのイメージ
Importer 後、Odoo では次のように追えます。
管理者が見る流れ
1. Group 画面
「sales user」「sales manager」がある
→ implied group も見える
2. User 画面
Kenji に sales_manager が付いている
→ 実質 sales_user も持つ
3. Access Rights 画面
crm.lead に対して sales_manager は read/create/write
sales_user は read only
4. Record Rules 画面
sales_user / sales_manager に company_id = user.company_id と team_id in user.team_ids
5. モデル/フィールド確認
margin_rate に manager group が付いている
これでかなり追えます。
6. Odoo だけで十分か
運用初期はかなり十分です。
特にあなたが今ほしいのは
- Importer で流し込んだ内容を確認したい
- Neo4j の権限定義と Odoo の定義がずれていないか見たい
ということなので、これは Odoo 画面でかなり対応できます。
ただし将来的に次をやりたくなるなら、補助UIが欲しくなります。
- 「ユーザー X の最終権限を一画面で見たい」
- 「Neo4j 定義との差分を見たい」
- 「この field はなぜ見えないか説明したい」
- 「ある行が見えない理由を説明したい」
ここは Odoo 標準では弱いです。
7. なので最終判断
結論としてはこうです。
すぐにやるなら
Odoo に表示させるで十分です。
Neo4j 側に重い描画UIを急いで作る必要はありません。
ただし
Odoo で見えるのは主に 定義単位 です。
ユーザー最終結果の可視化 は弱いです。
一番良い落とし所
- 権限定義の確認は Odoo
- Importer が権限サマリ JSON/CSV を出す
- 後で必要なら Neo4j/Portal 側に effective permission 画面を足す
これがコスパが高いです。
一言で答えると
はい、Importer で流した権限設定の多くは Odoo 画面で確認できます。
特に group、ACL、record rule、user-group 紐付けは確認しやすいです。
なので最初は Odoo を確認UIとして使う方針で問題ありません。
不足するのは「ユーザー最終権限の見える化」なので、そこだけ Importer のサマリ出力で補うのが現実的です。
必要なら次に、
「Odoo でどの画面で何を確認するか」の確認マップ を、管理者向けチェックリストとして整理します。
コメントを残す