Loading...
Loading...
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.
npx skill4agent add openaec-foundation/erpnext_anthropic_claude_development_skill_package erpnext-syntax-serverscripts┌─────────────────────────────────────────────────────────────────────┐
│ ⚠️ 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) │
│ │
└─────────────────────────────────────────────────────────────────────┘| Type | Usage | Trigger |
|---|---|---|
| Document Event | React to document lifecycle | Save, Submit, Cancel, etc. |
| API | Custom REST endpoint | HTTP request to |
| Scheduler Event | Scheduled tasks | Cron schedule |
| Permission Query | Dynamic list filtering | Document list view |
| UI Name (Server Script) | Internal Hook | When |
|---|---|---|
| Before Insert | | Before new doc to DB |
| After Insert | | After new doc saved |
| Before Validate | | Before validation |
| Before Save | | Before save (new or update) |
| After Save | | After successful save |
| Before Submit | | Before submit |
| After Submit | | After submit |
| Before Cancel | | Before cancel |
| After Cancel | | After cancel |
| Before Delete | | Before delete |
| After Delete | | After delete |
# 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)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# 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# 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# 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()# 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 accessbench --site [site] set-config server_script_enabled true