erpnext-syntax-serverscripts

ERPNext Server Scripts Syntax

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "erpnext-syntax-serverscripts" with this command: npx skills add openaec-foundation/erpnext_anthropic_claude_development_skill_package/openaec-foundation-erpnext-anthropic-claude-development-skill-package-erpnext-syntax-serverscripts

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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

erpnext-code-interpreter

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-syntax-jinja

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-impl-controllers

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-database

No summary provided by upstream source.

Repository SourceNeeds Review