- 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