/** * WPML compatibility functions * * @global array $duplicated_posts Array to store the posts being duplicated. * * @package Yoast\WP\Duplicate_Post * @since 3.2 */ add_action( 'admin_init', 'duplicate_post_wpml_init' ); /** * Add handlers for WPML compatibility. */ function duplicate_post_wpml_init() { if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { add_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'shutdown', 'duplicate_wpml_string_packages', 11 ); } } global $duplicated_posts; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: Renaming a global variable is a BC break. $duplicated_posts = []; /** * Copy post translations. * * @global SitePress $sitepress Instance of the Main WPML class. * @global array $duplicated_posts Array of duplicated posts. * * @param int $post_id ID of the copy. * @param WP_Post $post Original post object. * @param string $status Status of the new post. */ function duplicate_post_wpml_copy_translations( $post_id, $post, $status = '' ) { global $sitepress; global $duplicated_posts; remove_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10 ); remove_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10 ); $current_language = $sitepress->get_current_language(); $trid = $sitepress->get_element_trid( $post->ID ); if ( ! empty( $trid ) ) { $translations = $sitepress->get_element_translations( $trid ); $new_trid = $sitepress->get_element_trid( $post_id ); foreach ( $translations as $code => $details ) { if ( $code !== $current_language ) { if ( $details->element_id ) { $translation = get_post( $details->element_id ); if ( ! $translation ) { continue; } $new_post_id = duplicate_post_create_duplicate( $translation, $status ); if ( ! is_wp_error( $new_post_id ) ) { $sitepress->set_element_language_details( $new_post_id, 'post_' . $translation->post_type, $new_trid, $code, $current_language ); } } } } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: see above. $duplicated_posts[ $post->ID ] = $post_id; } } /** * Duplicate string packages. * * @global array() $duplicated_posts Array of duplicated posts. */ function duplicate_wpml_string_packages() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: renaming the function would be a BC-break. global $duplicated_posts; foreach ( $duplicated_posts as $original_post_id => $duplicate_post_id ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $original_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $original_post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $new_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $duplicate_post_id ); if ( is_array( $original_string_packages ) ) { foreach ( $original_string_packages as $original_string_package ) { $translated_original_strings = $original_string_package->get_translated_strings( [] ); foreach ( $new_string_packages as $new_string_package ) { $cache = new WPML_WP_Cache( 'WPML_Package' ); $cache->flush_group_cache(); $new_strings = $new_string_package->get_package_strings(); foreach ( $new_strings as $new_string ) { if ( isset( $translated_original_strings[ $new_string->name ] ) ) { foreach ( $translated_original_strings[ $new_string->name ] as $language => $translated_string ) { do_action( // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. 'wpml_add_string_translation', $new_string->id, $language, $translated_string['value'], $translated_string['status'] ); } } } } } } } } Odoo AI開発環境Odoo開発ポータル+AI活用 提案資料(ドラフト) – Raqqa

Odoo AI開発環境Odoo開発ポータル+AI活用 提案資料(ドラフト)


1. モデルと機能変更を例とした Odoo 開発ポータル

開発ポータルのコンセプト:

  • コンサルタントが自然文で要件を記述
    → AI(OpenAI+LangChain)が Python/XMLコードを自動生成
  • モデル単位で機能・処理を紐付けて管理
    → モデル(例:sale.order)に フィールド追加や処理概要を記録
  • オフショア開発者が英訳仕様+生成コードを確認
    → 適用・テストのみを実施することで作業効率化

開発ポータル画面イメージ(例):

  • TOPページ
    • モデル一覧(sale.order, res.partner など)
    • 新規機能要望入力フォーム(自然文)
  • モデル詳細ページ
    • フィールド追加/変更履歴
    • 関連するコード(Python/XML)
    • 自動生成されたコードプレビュー

2. それ以外の開発項目も対応可能

モデルと機能管理以外にも:

  • ビュー(XML)
    • フォームビュー、リストビュー、ダッシュボード改修
  • 帳票(QWeb)
    • 見積書・請求書PDFレイアウト変更
  • ワークフロー/アクション
    • ボタン処理、トリガー処理、サーバーアクション
  • 外部API連携
    • REST/JSON-RPCのエンドポイント仕様
  • セキュリティ設定
    • アクセス制御、グループ設定

これらを 「モデル/機能タブ」+「ビュータブ」+「レポートタブ」 で一元管理。


3. Webで作られたデータをOpenAIで活用するメリット

コンサルタントのメリット

  • 要件を自然文で記述するだけで AIが統一された仕様文・タグ・英訳を自動生成
  • Odoo標準モデル名と業務用語(日本語)を自動マッピング → 表記ゆれゼロ
  • 過去のカスタマイズ履歴を自然文で即検索(RAG活用)

ユーザー(顧客企業)のメリット

  • 自然文で仕様を確認
    「この画面の改修内容は?」→ AIがわかりやすく説明
  • プロジェクト終了後も 仕様ナレッジが残る
    SQLやBIでのデータ抽出支援にそのまま使える

開発会社(オフショア含む)のメリット

  • コードと仕様が英語で整備されるため、英語だけで開発可能
  • コンサルとオフショアの コミュニケーションロスが激減
  • 自動生成コードを起点に、レビュー・テスト作業だけに集中可能

4. DXできる金額的メリットと工数削減効果

5000万円規模のOdoo導入開発を例に試算:

項目従来工数削減率削減額(目安)
要件定義・確認15% = 750万円30%約225万円
UI・機能レビュー20% = 1000万円25%約250万円
コードレビュー20% = 1000万円20%約200万円
UAT (受入テスト)25% = 1250万円20%約250万円
Q&A/ナレッジ共有10% = 500万円40%約200万円
合計90% = 4500万円約1125万円削減(約20〜25%)

TOP画面 仕様

目的

  • すべてのモデル・カスタマイズ対象を一覧し、
    新しい機能要望を自然文で登録できるエントリーポイントにする。

構成要素

1. モデル一覧(テーブル表示)

項目説明
モデル名 (英)Odoo標準モデル名 (sale.order)
モデル名 (日)日本語表示(販売見積)
機能変更数紐づくカスタマイズ機能の数
最終更新日最後に変更があった日
ステータス開発中 / 承認済 / 適用済
詳細ボタン詳細ページへリンク

2. 新規機能追加フォーム

  • 入力項目
    • 対象モデル(選択 or 自然文から自動サジェスト)
    • 機能概要(日本語)
    • タグ選択(AIサジェスト)
  • 機能
    • AIサジェストボタン
      → 「この要件には sale.order モデルが適しています」と提示
    • 登録ボタン
      → 詳細画面の編集モードへ遷移

3. 検索・フィルタ

  • モデル名・タグで検索
  • 開発ステータス(開発中、レビュー待ち、適用済み)でフィルタ


詳細画面 仕様

目的

  • モデル単位で、カスタマイズされた機能・コード・帳票などを一元管理する。

構成要素

1. モデル情報エリア

  • モデル名 (英日併記)
    例:sale.order / 販売見積
  • モデル概要(AIサジェスト生成)
  • 関連モデル一覧sale.order.line, res.partner

2. カスタマイズ機能一覧

項目説明
機能名カスタマイズ機能のタイトル
概要処理概要(日本語+英語併記)
タグ機能分類タグ
ステータス下書き / 承認済 / 適用済
詳細リンク機能の詳細・コード画面へ

3. 機能詳細(ポップアップ or 下部タブ)

  • 処理概要(日本語・英語)
  • AI生成コード
    • Pythonタブ:モデル拡張やビジネスロジック
    • XMLタブ:ビュー・帳票
    • 再生成ボタン:AIに再リクエスト
  • レビューコメントエリア
  • 承認ボタン

4. ビュー・帳票タブ

  • 関連ビュー一覧sale.order.form, sale.order.tree
  • 帳票一覧report_saleorder_document
  • 各アイテムには「AI生成コード」と「改修履歴」を表示

5. オフショア向け表示

  • 英語専用ビュー(概要+コード)
  • 承認状況をステータスバーで表示
flowchart TD
    %% TOP画面
    A[TOP画面<br>モデル一覧<br>・モデル名 英日<br>・機能変更数<br>・最終更新日<br>・詳細ボタン] --> B[詳細画面<br>モデル情報<br>・モデル概要<br>・関連モデル]
    A --> C[新規機能追加フォーム<br>・対象モデル選択<br>・機能概要入力<br>・AIサジェストボタン]

    %% 詳細画面
    B --> D[カスタマイズ機能一覧<br>・機能名<br>・概要<br>・タグ<br>・詳細リンク]
    D --> E[機能詳細タブ<br>処理概要<br>AI生成コードプレビュー]

    %% 機能コードタブ
    E --> F[コードタブ<br>Pythonコード<br>XMLコード<br>再生成ボタン<br>承認ボタン]
    E --> G[レビューコメントタブ<br>レビュー履歴<br>コメント入力]
    E --> H[ビュー帳票タブ<br>関連ビュー一覧<br>帳票一覧]
  • TOP画面
    • 変更済みモデル一覧
    • Chatboxで標準モデル検索 → 新規モデル追加の導線
  • モデル詳細画面
    • カスタマイズ機能とフィールド一覧
    • カスタマイズ追加ボタンから詳細設定
  • カスタマイズ追加
    • コンサルが概要を書く
    • AIがフィールド・カスタマイズコードを提案
    • 保存で英訳され、オフショアが即参照可能
  • オフショア
    • 英訳仕様とAI生成コードを確認して適用

この仕組みで 開発情報を体系的に蓄積することで、OpenAIを用いた自然言語→SQL生成は ほぼ確実に高精度で動作する基盤が整うと思います。理由を以下に整理します。


なぜ高精度化が実現できるか

1. モデル・フィールド情報の明確化

  • 各モデルの フィールド追加・データ型・関連モデル(Many2one, One2many) がWeb基盤に記録される。
  • 自然言語で「顧客別売上ランキング」といった問い合わせが来た場合でも、
    OpenAIは カスタマイズ済みフィールドを正確に把握してSQLを構築できる。

2. 業務用語とDB用語のマッピング

  • コンサルタントが書いた 業務用語(日本語)とモデル/フィールド(英語) が対になって蓄積される。
    → これを ベクトル化してRetrieverに組み込むことで、
    「顧客ランクを条件に受注を抽出」という自然文が x_customer_rank フィールドを自動解決。

3. 履歴データの学習効果

  • 過去の自然文検索(「今月の売上」など)と、それに対応するSQLが 辞書として記録される。
  • 新しいクエリが来ても、過去クエリの類似検索により 安定したSQLパターンを再利用

4. OpenAI + LangChain の強み

  • PromptTemplateでSQL生成用プロンプトを標準化することで、
    SQLだけを返すように制御(OutputParser)。
  • 必要に応じて、SQL生成後に 「不足パラメータの確認(期間、顧客名)」を対話で補完できる。

開発ポータルとSQL生成の連携例

  1. Web基盤に蓄積される情報
    • モデル:sale.order
    • フィールド:amount_total (合計金額), date_order (受注日), x_customer_rank (顧客ランク)
  2. ユーザーの自然文入力
    「直近3ヶ月の顧客別売上ランキングを見たい」
  3. Retrieverが構造化情報を提供
    • モデル: sale.order
    • フィールド: amount_total, partner_id, date_order
  4. OpenAIがSQL生成 sqlコピーする編集するSELECT rp.name AS customer, SUM(so.amount_total) AS total_sales FROM sale_order AS so JOIN res_partner AS rp ON so.partner_id = rp.id WHERE so.date_order >= CURRENT_DATE - INTERVAL '3 months' GROUP BY rp.name ORDER BY total_sales DESC;

結論

「モデル・機能の履歴DB」=「SQL生成の強力な基盤」 となります。
開発ポータルを育てれば育てるほど、OpenAIは Odooカスタマイズ済み環境に特化したSQLを精密に作成できます。


Comments

コメントを残す

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