mcpField
F
frappe-impl-integrations

frappe-impl-integrations

github.com/impertio-studio開発198111 回インストール30 週間前に更新
リポジトリ

frappe-impl-integrations について

Frappe 開発者向けの連携手順ガイドです。OAuth、Webhook、外部 API 呼び出し、データのインポートとエクスポートを扱い、用途に応じた連携方式の選択も支援します。

主な機能

  1. 01OAuth プロバイダーとクライアントの設定
  2. 02署名検証付き Webhook の作成
  3. 03外部 API 呼び出しと非同期処理
  4. 04UI またはコードによるデータ取り込み
  5. 05UI、CLI、コードによるデータ出力

活用シーン

  1. 01OAuth で外部アプリから Frappe にアクセス
  2. 02ドキュメントイベントを外部サービスへ通知
  3. 03Frappe から外部 API を呼び出す
  4. 04DocType データの一括インポートまたはエクスポート

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/impertio-studio/frappe_claude_skill_package --skill frappe-impl-integrations

インストール後、Claude Code で/frappe-impl-integrationsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
.gitkeep
anti-patterns.md
decision-tree.md
examples.md
workflows.md

詳細

Frappe 連携

OAuth、Webhook、決済ゲートウェイ、データのインポート/エクスポート、外部 API 呼び出しの手順を紹介します。

バージョン:v14/v15/v16


判断ツリー:どの連携パターンを選ぶか

WHAT ARE YOU INTEGRATING?
│
├─► External service needs to call YOUR Frappe site?
│   ├─► On document events → Webhook (push to external)
│   ├─► External sends data to you → Whitelisted API endpoint
│   └─► External needs user auth → OAuth 2.0 Provider
│
├─► YOUR Frappe site calls an external service?
│   ├─► Needs user-level OAuth consent → Connected App
│   ├─► Server-to-server with API key → make_request / requests
│   └─► Recurring sync → Scheduler + API calls
│
├─► Bulk data in/out?
│   ├─► Import CSV/XLSX → Data Import DocType
│   ├─► Export data → Report Builder / export-csv / API
│   └─► Programmatic bulk → frappe.get_doc().insert()
│
├─► Payment processing?
│   └─► Payment Request + Payment Gateway controller
│
└─► Real-time vs batch?
    ├─► Real-time → Webhook or API endpoint
    ├─► Near real-time → frappe.enqueue() after event
    └─► Batch → Scheduler task (hourly/daily)

ワークフロー 1:OAuth 2.0:プロバイダーとしての Frappe

外部アプリケーションで「Frappe でサインイン」を利用する場合や、ユーザーに代わって API にアクセスする場合に使用します。

ステップ 1:OAuth プロバイダーの設定を構成する

Setup > Integrations > OAuth Provider Settings に移動します。

  • Force:常にユーザーに確認を求めます
  • Auto:有効なトークンが存在しない場合にのみ確認を求めます
ステップ 2:OAuth クライアントを作成する

Setup > Integrations > OAuth Client に移動します。

フィールド値
App Name外部アプリの識別子
Scopesスペース区切り(例:openid all)
Redirect URIsスペース区切りのコールバック URL
Default Redirect URIメインのコールバック URL
Grant TypeAuthorization Code(推奨)または Implicit
Response TypeCode(Auth Code の場合)または Token(Implicit の場合)
Skip Authorization信頼できるファーストパーティアプリの場合のみチェックします
ステップ 3:生成されたエンドポイントを使用する
エンドポイントURL
認可/api/method/frappe.integrations.oauth2.authorize
トークン/api/method/frappe.integrations.oauth2.get_token
プロフィール/api/method/frappe.integrations.oauth2.openid_profile
ステップ 4:外部アプリを構成する
# Example: Grafana generic_oauth config
client_id = <generated_client_id>
client_secret = <generated_client_secret>
auth_url = https://your-frappe.com/api/method/frappe.integrations.oauth2.authorize
token_url = https://your-frappe.com/api/method/frappe.integrations.oauth2.get_token
api_url = https://your-frappe.com/api/method/frappe.integrations.oauth2.openid_profile
scopes = openid all
重要なルール
  • サーバーサイドアプリでは、Implicit グラントタイプは絶対に使用せず、Authorization Code を使用してください
  • 本番環境では、すべての OAuth エンドポイントで必ず HTTPS を使用してください
  • クライアントサイドの JavaScript で client_secret を絶対に公開しないでください

ワークフロー 2:Connected App:OAuth クライアントとしての Frappe

Frappe インスタンスから、ユーザーに代わって外部サービス(Google、Microsoft など)にアクセスする場合に使用します。

ステップ 1:Connected App DocType を作成する
フィールド目的
Name接続の識別子
OpenID Configuration URLエンドポイントを自動取得します(例:/.well-known/openid-configuration)
Authorization URI同意画面の URL(OpenID から自動入力)
Token URIトークン交換 URL(OpenID から自動入力)
Redirect URI自動生成されます。これを外部プロバイダーにコピーしてください
Client ID外部プロバイダーから取得
Client Secret外部プロバイダーから取得
Scopes必要な権限(例:https://mail.google.com/)
ステップ 2:プロバイダーにリダイレクト URI を登録する

自動生成された Redirect URI をコピーし、外部プロバイダーの OAuth コンソールに登録します。

ステップ 3:追加パラメーターを追加する(必要な場合)
access_type=offline    # Google: enables refresh tokens
prompt=consent         # Google: forces re-consent for refresh token
ステップ 4:コードで使用する
import frappe

connected_app = frappe.get_doc("Connected App", "My Google App")
# Initiates OAuth flow — user clicks "Connect to..." button
# After consent, tokens are stored automatically

# Making authenticated calls:
session = connected_app.get_oauth2_session()
response = session.get("https://www.googleapis.com/gmail/v1/users/me/messages")
重要なルール
  • Google API でリフレッシュトークンを取得するには、access_type=offline を必ず追加してください
  • トークンを手動で保存することは絶対に避けてください。トークンのライフサイクルは Connected App が管理します
  • TokenExpiredError を必ず処理してください。session.refresh_token() を呼び出すか、再接続してください

ワークフロー 3:Webhook:外部サービスへのプッシュ通知

ステップ 1:Webhook DocType を作成する

Integrations > Webhook に移動します。

フィールド値
DocType対象のドキュメントタイプ
Doc Eventon_update、after_insert、on_submit、on_cancel、on_trash
Request URL外部エンドポイント
Request MethodPOST(デフォルト)
Conditions任意の Jinja フィルター(例:doc.status == "Approved")
Enabled有効にするにはチェックします
ステップ 2:ヘッダーを構成する

認証用のカスタムヘッダーを追加します。

Authorization: Bearer <api_token>
Content-Type: application/json
ステップ 3:データ形式を選択する

フォーム URL エンコード:テーブルから特定のフィールドを選択します。

JSON:構造化ペイロードには Jinja テンプレートを使用します。

{
  "id": "{{ doc.name }}",
  "total": "{{ doc.grand_total }}",
  "items": {{ doc.items | tojson }},
  "event": "{{ event }}"
}
ステップ 4:Webhook Secret を有効にする(HMAC 検証)

Webhook Secret を設定します。Frappe は、ペイロードの HMAC-SHA256 ハッシュを Base64 エンコードした値を X-Frappe-Webhook-Signature ヘッダーに追加します。

受信側での検証(Python の例):

import hmac, hashlib, base64

def verify_webhook(payload_body, secret, signature_header):
    expected = base64.b64encode(
        hmac.new(secret.encode(), payload_body, hashlib.sha256).digest()
    ).decode()
    return hmac.compare_digest(expected, signature_header)
重要なルール
  • 本番環境のWebhookでは、必ずWebhook Secretを有効にしてください
  • 配信が保証される手段としてWebhookに絶対に依存しないでください。受信側で冪等性を実装してください
  • JSONペイロード内の子テーブルデータには、必ず| tojsonフィルターを使用してください
  • 配信ごとにWebhookログが作成されます。デバッグにはWebhook Request Logを確認してください

ワークフロー 4:Frappe からの外部 API 呼び出し

frappe.integrations.utils の使用
from frappe.integrations.utils import make_get_request, make_post_request

# GET request
response = make_get_request(
    "https://api.example.com/data",
    headers={"Authorization": "Bearer token123"}
)

# POST request
response = make_post_request(
    "https://api.example.com/submit",
    data={"key": "value"},
    headers={"Content-Type": "application/json"}
)
requests ライブラリを直接使用
import requests
import frappe

def sync_to_external():
    try:
        response = requests.post(
            "https://api.example.com/endpoint",
            json={"data": "value"},
            timeout=30
        )
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        frappe.log_error(f"API call failed: {e}", "Integration Error")
        raise
重要なルール
  • 外部リクエストには必ずtimeoutを設定してください(30秒を推奨)
  • 外部呼び出しは必ずtry/exceptで囲み、frappe.log_error()でエラーを記録してください
  • validateやbefore_save内で外部APIを絶対に呼び出さないでください。on_updateとfrappe.enqueue()を使用してください
  • Webリクエストをブロックしないよう、時間のかかる外部呼び出しには必ずfrappe.enqueue()を使用してください

ワークフロー 5:データのインポート

UI 経由(Data Import DocType)
  1. Home > Data Import > Newに移動します
  2. DocTypeとImport Type(InsertまたはUpdate)を選択します
  3. テンプレートCSV/XLSXをダウンロードします
  4. テンプレートの形式に従ってデータを入力します
  5. アップロードしてプレビューします
  6. インポートを開始します
CSV 形式のルール
ID,Item Name,Item Group,Stock UOM
,Widget A,Products,Nos
,Widget B,Raw Material,Kg
  • 1行目:フィールドラベルまたはAPIフィールド名
  • Insertの場合、ID/nameは空欄にします(自動生成)
  • Updateの場合、ID列には既存のドキュメント名を必ず含めてください
  • 子テーブル:親行のデータを繰り返し、子フィールドを追加列として加えます
プログラムによるインポート
import frappe
from frappe.core.doctype.data_import.data_import import DataImport

# Create Data Import document
di = frappe.get_doc({
    "doctype": "Data Import",
    "reference_doctype": "Item",
    "import_type": "Insert New Records",
    "import_file": "/path/to/file.csv"
})
di.insert()
di.start_import()
重要なルール
  • テンプレートを必ずダウンロードして使用してください。列の順序と名前は完全に一致している必要があります
  • 一度に5,000行を超えてインポートしないでください。バッチに分割してください
  • 一括インポートの前に、必ず5~10行でテストしてください
  • インポート完了後、必ずImport Logで行ごとのエラーを確認してください

ワークフロー 6:データのエクスポート

Report Builder 経由
  1. 任意のDocTypeリストビューを開きます
  2. フィルターを適用します
  3. メニュー > Export(CSV/Excel)を選択します
CLI 経由
bench --site mysite export-csv "Sales Invoice"
bench --site mysite export-doc "Sales Invoice" "INV-001"
bench --site mysite export-json "Sales Invoice" "INV-001"
bench --site mysite export-fixtures --app myapp
プログラムによるエクスポート
import frappe

# Export filtered data
data = frappe.get_all("Sales Invoice",
    filters={"status": "Paid", "posting_date": [">", "2024-01-01"]},
    fields=["name", "customer", "grand_total", "posting_date"],
    order_by="posting_date desc",
    limit_page_length=0  # No limit
)

# Convert to CSV
import csv, io
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=["name", "customer", "grand_total", "posting_date"])
writer.writeheader()
writer.writerows(data)
csv_content = output.getvalue()

ワークフロー 7:Frappe REST API の認証

API Key + Secret(サーバー間)
# Generate via User > API Access > Generate Keys
curl -H "Authorization: token api_key:api_secret" \
  https://your-site.com/api/resource/Sales%20Invoice
OAuth Bearer Token
curl -H "Authorization: Bearer access_token" \
  https://your-site.com/api/resource/Sales%20Invoice
セッションベース(ログイン)
# Login first
curl -X POST https://your-site.com/api/method/login \
  -d "[email protected]&pwd=password"
# Subsequent requests use session cookie

統合パターン:同期と非同期

パターン使用する場面実装
同期レスポンスがすぐに必要な場合コントローラー内で直接APIを呼び出す
非同期(enqueue)外部呼び出しに5秒以上かかる場合frappe.enqueue("myapp.api.sync_record", doc_name=doc.name)
Webhookイベント発生時にプッシュする場合Webhook DocTypeの設定
スケジュール同期定期的なバッチ処理hooks.pyのscheduler_events
リアルタイムライブ更新Socket.IO + frappe.publish_realtime()
リトライパターン
import frappe
from frappe.utils.background_jobs import get_jobs

def sync_with_retry(doc_name, retry_count=0, max_retries=3):
    try:
        result = call_external_api(doc_name)
        frappe.db.set_value("Sales Invoice", doc_name, "sync_status", "Success")
        frappe.db.commit()
    except Exception as e:
        if retry_count < max_retries:
            frappe.enqueue(
                "myapp.integrations.sync_with_retry",
                doc_name=doc_name,
                retry_count=retry_count + 1,
                queue="short",
                enqueue_after_commit=True
            )
        else:
            frappe.log_error(f"Sync failed after {max_retries} retries: {e}")
            frappe.db.set_value("Sales Invoice", doc_name, "sync_status", "Failed")
            frappe.db.commit()

バージョンごとの差異

機能V14V15V16
Webhook DocTypeありありあり
Connected Appありありあり
OAuth 2.0 Providerありありあり
Data Import(新しいUI)ありありあり
Print Designerなしありあり
make_get_requestありありあり
Webhook HMACありありあり

参考ファイル

ファイル内容
workflows.md統合ワークフローの完全なパターン集
examples.mdすべての統合タイプに対応した動作するコード例
anti-patterns.mdよくある統合の間違いと修正方法
decision-tree.md統合方法の選択に関する詳細な判断ツリー

コメント