Back to list
OpenAEC-Foundation

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

TypeUsageTrigger
Document EventReact to document lifecycleSave, Submit, Cancel, etc.
APICustom REST endpointHTTP request to /api/method/{name}
Scheduler EventScheduled tasksCron schedule
Permission QueryDynamic list filteringDocument list view

Event Name Mapping (Document Event)

IMPORTANT: The UI event names differ from the internal hook names:

UI Name (Server Script)Internal HookWhen
Before Insertbefore_insertBefore new doc to DB
After Insertafter_insertAfter new doc saved
Before Validatebefore_validateBefore validation
Before SavevalidateBefore save (new or update)
After Saveon_updateAfter successful save
Before Submitbefore_submitBefore submit
After Submiton_submitAfter submit
Before Cancelbefore_cancelBefore cancel
After Cancelon_cancelAfter cancel
Before Deleteon_trashBefore delete
After Deleteafter_deleteAfter 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

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