mcpField
F
frappe-syntax-serverscripts

frappe-syntax-serverscripts

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

frappe-syntax-serverscripts について

RestrictedPython サンドボックスで Frappe Server Scripts を作成するための実用リファレンススキルです。スクリプトの種類、利用可能な API、ライフサイクルイベント、制約を解説します。

主な機能

  1. 01Document Event、API、Scheduler、Permission Query スクリプト
  2. 02RestrictedPython のサンドボックス規則と利用可能なメソッド
  3. 03ドキュメントのライフサイクルイベント対応表
  4. 04バージョンごとの有効化に関する説明
  5. 05セキュリティと安全なクエリの指針

活用シーン

  1. 01ドキュメントイベントへの検証処理の追加
  2. 02Frappe での API または定期実行スクリプトの作成
  3. 03ユーザー権限に応じたドキュメント一覧の絞り込み

インストール

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

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

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

同梱ファイル

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

references/
anti-patterns.md
events.md
examples.md
hooks.md
methods.md
patterns.md
syntax.md

詳細

Frappe Server Scripts — 完全リファレンス

Server Scripts は、Frappe/ERPNext の UI で Setup > Server Script を通じて管理する Python スクリプトです。 RestrictedPython サンドボックス内で実行されます。

重要:サンドボックスのルール

┌──────────────────────────────────────────────────────────────────┐
│  ALL import STATEMENTS ARE BLOCKED                               │
│                                                                  │
│  import json             → ImportError: __import__ not found     │
│  from datetime import *  → ImportError: __import__ not found     │
│  import frappe           → ImportError (even frappe itself!)     │
│                                                                  │
│  EVERYTHING you need is pre-loaded in the frappe namespace.      │
│  NEVER write an import line. ALWAYS use frappe.utils.*, etc.     │
└──────────────────────────────────────────────────────────────────┘

インポートの代わりに、あらかじめ読み込まれている名前空間を必ず使用してください。

ブロックされるインポート代わりに使用するもの
import jsonfrappe.parse_json() / frappe.as_json()
from datetime import datefrappe.utils.today() / frappe.utils.now_datetime()
from frappe.utils import cintfrappe.utils.cint()(すでに読み込み済み)
import requestsfrappe.make_get_request() / frappe.make_post_request()
import re使用不可 — 正規表現を使わずにロジックを組み立て直してください
import os / import sys使用不可 — 代わりにカスタムアプリを使用してください

Server Scripts の有効化

# v14: enabled by default
# v15+: DISABLED by default — you MUST enable explicitly:
bench set-config -g server_script_enabled 1
# Or set server_script_enabled: true in site_config.json

Frappe Cloud の共有ベンチでは Server Scripts が動作することを絶対に想定しないでください。プライベートベンチが必要です。

スクリプトの種類

種類トリガー主な変数
Document Eventドキュメントのライフサイクル(保存、送信、キャンセル)doc
API/api/method/{name} への HTTP リクエストfrappe.form_dict
Scheduler EventCron スケジュール(なし)
Permission Queryドキュメント一覧のフィルタリングuser, conditions

イベント名の対応関係(Document Events)

重要:UI 上の名前は内部のフック名とは異なります。

Server Script UI内部フック実行されるタイミング
Before Insertbefore_insert新しいドキュメントが DB に保存される前
After Insertafter_insert最初の DB 挿入後
Before Validatebefore_validateフレームワークによる検証の前
Before Savevalidate保存前(新規作成・更新)
After Saveon_update保存成功後
Before Submitbefore_submit送信前(docstatus 0→1)
After Submiton_submit送信完了後
Before Cancelbefore_cancelキャンセル前(docstatus 1→2)
After Cancelon_cancelキャンセル完了後
Before Deleteon_trash完全削除の前
After Deleteafter_delete完全削除後

「Before Save」と before_save を絶対に混同しないでください。UI ラベルの「Before Save」は validate フックに対応します。実際の before_save フックは validate の後に実行されます。

判断フロー:Server Script と Document Controller の使い分け

Need custom Python logic for a DocType?
│
├─► Can you install a custom Frappe app?
│   ├─► YES: Use a Document Controller when you need:
│   │   • import statements (any Python library)
│   │   • File system access
│   │   • Complex class inheritance
│   │   • autoname / before_naming hooks
│   │   • Unit-testable code
│   │
│   └─► NO: Use a Server Script when:
│       • You only have UI access (no bench CLI)
│       • Logic is simple validation / field calculation
│       • You need a quick API endpoint
│       • You need dynamic permission filtering
│
└─► Is logic > 50 lines or needs external libraries?
    ├─► YES → Document Controller in a custom app
    └─► NO  → Server Script is fine

クイックリファレンス:サンドボックスで利用可能なもの

あらかじめ読み込まれているオブジェクト
doc                         # Current document (Document Event only)
frappe                      # Core namespace — ALWAYS available
frappe.db                   # Database operations
frappe.utils                # Date, number, string utilities
frappe.session              # Current session (user, csrf_token)
frappe.form_dict            # Request parameters (API scripts)
frappe.response             # Response object (API scripts)
frappe.request              # Werkzeug request object
frappe.qb                   # Query Builder (v14+)
json                        # Python json module (pre-loaded)
主なメソッド
# Documents
frappe.get_doc(doctype, name)           # Fetch document
frappe.new_doc(doctype)                 # Create new document
frappe.get_cached_doc(doctype, name)    # Cached fetch (read-only)
frappe.get_last_doc(doctype)            # Most recent document
frappe.get_mapped_doc(...)              # Map fields between DocTypes
frappe.delete_doc(doctype, name)        # Delete document
frappe.rename_doc(doctype, old, new)    # Rename document

# Querying
frappe.get_all(doctype, filters, fields, order_by, limit)   # No permission check
frappe.get_list(doctype, filters, fields, order_by, limit)  # With permission check
frappe.db.get_value(doctype, name, fieldname)
frappe.db.get_single_value(doctype, fieldname)
frappe.db.set_value(doctype, name, fieldname, value)
frappe.db.exists(doctype, name_or_filters)
frappe.db.count(doctype, filters)
frappe.db.sql(query, values, as_dict)   # ALWAYS parameterize!
frappe.db.escape(value)                 # SQL escape
frappe.db.commit()                      # ONLY in Scheduler scripts
frappe.db.rollback()                    # ONLY in Scheduler scripts

# Messaging
frappe.throw(msg, exc, title)           # Stop execution + show error
frappe.msgprint(msg, title, indicator)  # User notification
frappe.log_error(message, title)        # Error Log entry

# HTTP (yes, these work in sandbox!)
frappe.make_get_request(url, params, headers)
frappe.make_post_request(url, data, headers)
frappe.make_put_request(url, data, headers)

# Email
frappe.sendmail(recipients, sender, subject, message)

# Utilities
frappe.utils.today()                    # "2024-01-15"
frappe.utils.now()                      # "2024-01-15 10:30:00"
frappe.utils.now_datetime()             # datetime object
frappe.utils.add_days(date, n)          # Date arithmetic
frappe.utils.add_months(date, n)
frappe.utils.date_diff(d1, d2)          # Days between dates
frappe.utils.flt(val)                   # Safe float (None → 0.0)
frappe.utils.cint(val)                  # Safe int (None → 0)
frappe.utils.cstr(val)                  # Safe string (None → "")
frappe.parse_json(string)               # JSON string → dict/list
frappe.as_json(obj)                     # dict/list → JSON string
frappe.render_template(template, ctx)   # Jinja rendering
frappe.get_url()                        # Site URL
frappe.get_hooks(hook)                  # Read app hooks
run_script(script_name, **kwargs)       # Call another Server Script

# Session / Permissions
frappe.session.user                     # Current user email
frappe.get_roles(user)                  # User's roles list
frappe.has_permission(doctype, ptype, doc)
frappe.get_fullname(user)               # User's display name
_("translatable string")               # Translation function
使用可能な Python 組み込み関数
str, int, float, bool, list, dict, tuple, set  # Types
range, enumerate, zip, map, filter              # Iteration
sum, min, max, len, sorted, reversed            # Aggregation
isinstance, type, hasattr, getattr              # Introspection
all, any, abs, round, divmod                    # Math/logic
print                                           # → server log
True, False, None                               # Constants
ブロックされる Python 組み込み関数
open, file          # No file I/O
eval, exec, compile # No dynamic code execution
__import__          # No imports (this is the root cause)
globals, locals     # No scope introspection

スクリプトの種類ごとの構文

Document Event
# Config: Reference DocType = Sales Invoice, Event = Before Save
if doc.grand_total < 0:
    frappe.throw("Total MUST NOT be negative")

doc.requires_approval = 1 if doc.grand_total > 10000 else 0
API
# Config: API Method = get_customer_orders, Allow Guest = No
# Endpoint: /api/method/get_customer_orders
customer = frappe.form_dict.get("customer")
if not customer:
    frappe.throw("Parameter 'customer' is required")

orders = frappe.get_all("Sales Order",
    filters={"customer": customer, "docstatus": 1},
    fields=["name", "grand_total", "status"],
    order_by="creation desc",
    limit=20
)
frappe.response["message"] = {"orders": orders, "count": len(orders)}
Scheduler Event
# Config: Event Frequency = Cron, Cron Format = 0 9 * * *
overdue = frappe.get_all("Sales Invoice",
    filters={"status": "Unpaid", "due_date": ["<", frappe.utils.today()], "docstatus": 1},
    fields=["name", "customer", "grand_total"]
)
for inv in overdue:
    frappe.log_error(f"Overdue: {inv.name} ({inv.customer})", "Invoice Reminder")

frappe.db.commit()  # ALWAYS commit in Scheduler scripts
Permission Query
# Config: Reference DocType = Sales Invoice
# Variables available: user, conditions
roles = frappe.get_roles(user)
if "System Manager" in roles:
    conditions = ""
elif "Sales User" in roles:
    conditions = f"`tabSales Invoice`.owner = {frappe.db.escape(user)}"
else:
    conditions = "1=0"

バージョン間の違い

機能v14v15v16
Server Scripts の有効化デフォルトで有効デフォルトで無効デフォルトで無効
有効化コマンド不要bench set-config -g server_script_enabled 1v15 と同じ
frappe.qb(Query Builder)利用可能利用可能利用可能
ライブラリ向けの run_script()v13+利用可能利用可能
frappe.make_get_request()利用可能利用可能利用可能
Frappe Cloud の共有ベンチサポート対象サポート対象外サポート対象外

重要なルール 5 つ

  1. import は絶対に記述しないでください。すべて frappe 名前空間にあります。
  2. Before Save スクリプト内で doc.save() を絶対に呼び出さないでください。無限ループの原因になります。
  3. Document Event スクリプト内で frappe.db.commit() を絶対に呼び出さないでください。フレームワークが処理します。
  4. Scheduler スクリプトの最後では、frappe.db.commit() を必ず呼び出してください。
  5. パラメーター化クエリを必ず使用してください。辞書と %(var)s を使い、SQL 内で f-string は絶対に使用しないでください。

参考資料

相互参照

  • frappe-syntax-api — Frappe REST API とホワイトリスト登録されたメソッド
  • frappe-syntax-doctype — DocType のフィールド型とスキーマ
  • frappe-core-database — frappe.db の詳細解説
  • frappe-core-permissions — 権限システムのアーキテクチャ
  • frappe-errors-common — エラー処理のパターン

コメント