← Back to list

erpnext-syntax-serverscripts
by OpenAEC-Foundation
28 deterministic Claude AI skills for flawless ERPNext/Frappe v14-16 development. Agent Skills standard compliant.
⭐ 1🍴 1📅 Jan 23, 2026
SKILL.md
name: erpnext-syntax-serverscripts description: Complete syntax reference for Frappe Server Scripts. Use this skill when Claude needs to write Python code for Server Scripts in ERPNext/Frappe, including Document Events, API endpoints, Scheduler Events, and Permission Queries. Covers sandbox limitations, available frappe.* methods, event name mapping, and correct syntax for v14/v15/v16.
ERPNext Server Scripts Syntax
Server Scripts are Python scripts that run within Frappe's secure sandbox environment. They are managed via Setup → Server Script in the ERPNext UI.
CRITICAL: Sandbox Limitations
┌─────────────────────────────────────────────────────────────────────┐
│ ⚠️ NO IMPORTS ALLOWED │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ The sandbox blocks ALL import statements: │
│ import json → ImportError: __import__ not found │
│ from datetime import date → ImportError │
│ │
│ SOLUTION: Use Frappe's pre-loaded namespace: │
│ frappe.utils.nowdate() not: from frappe.utils import nowdate │
│ frappe.parse_json(data) not: import json; json.loads(data) │
│ │
└─────────────────────────────────────────────────────────────────────┘
Server Script Types
| Type | Usage | Trigger |
|---|---|---|
| Document Event | React to document lifecycle | Save, Submit, Cancel, etc. |
| API | Custom REST endpoint | HTTP request to /api/method/{name} |
| Scheduler Event | Scheduled tasks | Cron schedule |
| Permission Query | Dynamic list filtering | Document list view |
Event Name Mapping (Document Event)
IMPORTANT: The UI event names differ from the internal hook names:
| UI Name (Server Script) | Internal Hook | When |
|---|---|---|
| Before Insert | before_insert | Before new doc to DB |
| After Insert | after_insert | After new doc saved |
| Before Validate | before_validate | Before validation |
| Before Save | validate | Before save (new or update) |
| After Save | on_update | After successful save |
| Before Submit | before_submit | Before submit |
| After Submit | on_submit | After submit |
| Before Cancel | before_cancel | Before cancel |
| After Cancel | on_cancel | After cancel |
| Before Delete | on_trash | Before delete |
| After Delete | after_delete | After delete |
Quick Reference: Available API
Always available in sandbox
# Document object (in Document Event scripts)
doc # Current document
doc.name # Document name
doc.doctype # DocType name
doc.fieldname # Field value
doc.get("fieldname") # Safe field access
doc.items # Child table (list)
# Frappe namespace
frappe.db # Database operations
frappe.get_doc() # Fetch document
frappe.get_all() # Multiple documents
frappe.throw() # Validation error
frappe.msgprint() # User message
frappe.log_error() # Error logging
frappe.utils.* # Utility functions
frappe.session.user # Current user
frappe.form_dict # Request parameters (API)
frappe.response # Response object (API)
Decision Tree: Which Script Type?
What do you want to achieve?
│
├─► React to document save/submit/cancel?
│ └─► Document Event script
│
├─► Create REST API endpoint?
│ └─► API script
│
├─► Run task on schedule?
│ └─► Scheduler Event script
│
└─► Filter document list view per user/role?
└─► Permission Query script
Basic Syntax per Type
Document Event
# Configuration:
# Reference DocType: Sales Invoice
# DocType Event: Before Save (= validate)
if doc.grand_total < 0:
frappe.throw("Total cannot be negative")
if doc.grand_total > 10000:
doc.requires_approval = 1
API
# Configuration:
# API Method: get_customer_info
# Allow Guest: No
# Endpoint: /api/method/get_customer_info
customer = frappe.form_dict.get("customer")
if not customer:
frappe.throw("Customer parameter required")
data = frappe.get_all(
"Sales Order",
filters={"customer": customer, "docstatus": 1},
fields=["name", "grand_total"],
limit=10
)
frappe.response["message"] = data
Scheduler Event
# Configuration:
# Event Frequency: Cron
# Cron Format: 0 9 * * * (daily at 9:00)
overdue = frappe.get_all(
"Sales Invoice",
filters={"status": "Unpaid", "due_date": ["<", frappe.utils.today()]},
fields=["name", "customer"]
)
for inv in overdue:
frappe.log_error(f"Overdue: {inv.name}", "Invoice Reminder")
frappe.db.commit()
Permission Query
# Configuration:
# Reference DocType: Sales Invoice
# Output: conditions string for WHERE clause
user_roles = frappe.get_roles(user)
if "System Manager" in user_roles:
conditions = "" # Full access
elif "Sales User" in user_roles:
conditions = f"`tabSales Invoice`.owner = {frappe.db.escape(user)}"
else:
conditions = "1=0" # No access
References
- references/events.md - Complete event mapping and execution order
- references/methods.md - All available frappe.* methods in sandbox
- references/examples.md - 10+ working examples per script type
- references/anti-patterns.md - Sandbox limitations and common mistakes
Version Information
- Frappe v14+: Server Scripts fully supported
- Activation required:
bench --site [site] set-config server_script_enabled true - Frappe v15: No significant syntax changes for Server Scripts
Score
Total Score
75/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
✓説明文
100文字以上の説明がある
+10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

