Skill125 estrellas del repoactualizado 2mo ago
frappe-syntax-serverscripts
>
Instalar en Claude Code
Copiargit clone --depth 1 https://github.com/Impertio-Studio/Frappe_Claude_Skill_Package /tmp/frappe-syntax-serverscripts && cp -r /tmp/frappe-syntax-serverscripts/skills/source/syntax/frappe-syntax-serverscripts ~/.claude/skills/frappe-syntax-serverscriptsDespués abre una sesión nueva de Claude Code; el skill carga automáticamente.
Definición
SKILL.md
# Frappe Server Scripts — Complete Reference
Server Scripts are Python scripts managed via **Setup > Server Script** in the
Frappe/ERPNext UI. They run inside a **RestrictedPython sandbox**.
## CRITICAL: The Sandbox Rule
```
┌──────────────────────────────────────────────────────────────────┐
│ ALL import STATEMENTS ARE BLOCKED │
│ │
│ import json → ImportError: __import__ not found │
│ from datetime import * → ImportError: __import__ not found │
│ import frappe → ImportError (even frappe itself!) │
│ │
│ EVERYTHING you need is pre-loaded in the frappe namespace. │
│ NEVER write an import line. ALWAYS use frappe.utils.*, etc. │
└──────────────────────────────────────────────────────────────────┘
```
**ALWAYS** use the pre-loaded namespace instead of imports:
| Blocked import | Use instead |
|---|---|
| `import json` | `frappe.parse_json()` / `frappe.as_json()` |
| `from datetime import date` | `frappe.utils.today()` / `frappe.utils.now_datetime()` |
| `from frappe.utils import cint` | `frappe.utils.cint()` (already loaded) |
| `import requests` | `frappe.make_get_request()` / `frappe.make_post_request()` |
| `import re` | Not available — restructure logic without regex |
| `import os` / `import sys` | Not available — use a custom app instead |
## Enabling Server Scripts
```bash
# v14: enabled by default
# v15+: DISABLED by default — you MUST enable explicitly:
bench set-config -g server_script_enabled 1
# Or set server_script_enabled: true in site_config.json
```
**NEVER** expect Server Scripts to work on Frappe Cloud shared benches — they
require a private bench.
## Script Types
| Type | Trigger | Key Variable |
|---|---|---|
| **Document Event** | Document lifecycle (save, submit, cancel) | `doc` |
| **API** | HTTP request to `/api/method/{name}` | `frappe.form_dict` |
| **Scheduler Event** | Cron schedule | (none) |
| **Permission Query** | Document list filtering | `user`, `conditions` |
## Event Name Mapping (Document Events)
**CRITICAL**: The UI names differ from internal hook names:
| Server Script UI | Internal Hook | Fires When |
|---|---|---|
| Before Insert | `before_insert` | Before new doc saved to DB |
| After Insert | `after_insert` | After first DB insert |
| Before Validate | `before_validate` | Before framework validation |
| **Before Save** | **`validate`** | Before save (new + update) |
| After Save | `on_update` | After successful save |
| Before Submit | `before_submit` | Before submit (docstatus 0→1) |
| After Submit | `on_submit` | After submit completes |
| Before Cancel | `before_cancel` | Before cancel (docstatus 1→2) |
| After Cancel | `on_cancel` | After cancel completes |
| Before Delete | `on_trash` | Before permanent delete |
| After Delete | `after_delete` | After permanent delete |
**NEVER** confuse "Before Save" with `before_save` — the UI label "Before Save"
maps to the `validate` hook. The actual `before_save` hook runs AFTER `validate`.
## Decision Tree: Server Script vs Document Controller
```
Need custom Python logic for a DocType?
│
├─► Can you install a custom Frappe app?
│ ├─► YES: Use a Document Controller when you need:
│ │ • import statements (any Python library)
│ │ • File system access
│ │ • Complex class inheritance
│ │ • autoname / before_naming hooks
│ │ • Unit-testable code
│ │
│ └─► NO: Use a Server Script when:
│ • You only have UI access (no bench CLI)
│ • Logic is simple validation / field calculation
│ • You need a quick API endpoint
│ • You need dynamic permission filtering
│
└─► Is logic > 50 lines or needs external libraries?
├─► YES → Document Controller in a custom app
└─► NO → Server Script is fine
```
## Quick Reference: Available in Sandbox
### Pre-loaded Objects
```python
doc # Current document (Document Event only)
frappe # Core namespace — ALWAYS available
frappe.db # Database operations
frappe.utils # Date, number, string utilities
frappe.session # Current session (user, csrf_token)
frappe.form_dict # Request parameters (API scripts)
frappe.response # Response object (API scripts)
frappe.request # Werkzeug request object
frappe.qb # Query Builder (v14+)
json # Python json module (pre-loaded)
```
### Core Methods
```python
# Documents
frappe.get_doc(doctype, name) # Fetch document
frappe.new_doc(doctype) # Create new document
frappe.get_cached_doc(doctype, name) # Cached fetch (read-only)
frappe.get_last_doc(doctype) # Most recent document
frappe.get_mapped_doc(...) # Map fields between DocTypes
frappe.delete_doc(doctype, name) # Delete document
frappe.rename_doc(doctype, old, new) # Rename document
# Querying
frappe.get_all(doctype, filters, fields, order_by, limit) # No permission check
frappe.get_list(doctype, filters, fields, order_by, limit) # With permission check
frappe.db.get_value(doctype, name, fieldname)
frappe.db.get_single_value(doctype, fieldname)
frappe.db.set_value(doctype, name, fieldname, value)
frappe.db.exists(doctype, name_or_filters)
frappe.db.count(doctype, filters)
frappe.db.sql(query, values, as_dict) # ALWAYS parameterize!
frappe.db.escape(value) # SQL escape
frappe.db.commit() # ONLY in Scheduler scripts
frappe.db.rollback() # ONLY in Scheduler scripts
# Messaging
frappe.throw(msg, exc, title) # Stop execution + show error
frappe.msgprint(msg, title, indicator) # User notification
frappe.log_error(message, title) # Error Log entry
# HTTP (yes, these work in sandbox!)
frappe.make_get_request(url, params