Generate Document Hooks
Create document lifecycle hooks using frappe-microservice-lib hook system.
When to Use
- Need code on document lifecycle events
- Want to avoid modifying Frappe core
- Prefer function-based hooks over controllers
- Need global hooks for all doctypes
Core Patterns
1. Hook Registration
# Global hook - runs for ALL doctypes
@app.tenant_db.on('*', 'before_insert')
def ensure_tenant_id(doc):
from flask import g
if not doc.tenant_id and hasattr(g, 'tenant_id'):
doc.tenant_id = g.tenant_id
# DocType-specific hook
@app.tenant_db.on('Sales Order', 'before_insert')
def set_order_defaults(doc):
if not doc.status:
doc.status = 'Draft'
if not doc.transaction_date:
doc.transaction_date = frappe.utils.today()
@app.tenant_db.on('Sales Order', 'validate')
def validate_order(doc):
if not doc.customer:
frappe.throw("Customer is required")
if doc.grand_total and doc.grand_total < 0:
frappe.throw("Order total cannot be negative")
2. Available Events
before_validate,validate,before_insert,after_insertbefore_update,after_update,before_save,after_savebefore_delete,after_delete
3. Multiple Hooks
# All hooks run in registration order
@app.tenant_db.on('Sales Order', 'before_insert')
def set_defaults(doc):
if not doc.status:
doc.status = 'Draft'
@app.tenant_db.on('Sales Order', 'before_insert')
def calculate_totals(doc):
# Runs after set_defaults
doc.calculate_totals()
4. Error Handling
@app.tenant_db.on('Sales Order', 'validate')
def validate_order(doc):
try:
if not doc.customer:
frappe.throw("Customer is required")
except frappe.ValidationError:
raise
except Exception as e:
frappe.log_error(f"Validation error: {e}")
Key Patterns
- Global hooks first: Use
'*'for hooks applying to all doctypes - DocType-specific after: Register specific hooks after global ones
- Validation in validate: Use
validatehook for business rules - Defaults in before_insert: Set defaults before document is saved
- Notifications in after_insert: Send notifications after successful creation
- Error handling: Use
frappe.throw()for validation errors
Remember: This skill is model-invoked. Claude will use it autonomously when detecting hook development needs.