Hooks
Hooks laten een app Frappe en andere apps uitbreiden zonder hun code te forken. Elke app declareert hooks in hooks.py. Deze pagina dekt zowel het concept als de volledige referentie.
Waarom hooks
Frappes filosofie: uitbreiden, niet forken. Wilt u reageren op een ingediende Verkoopfactuur — wijzig dan ERPNext niet. Schrijf een hook in uw eigen app. Updates van ERPNext botsen niet met uw code, en uw aanpassing overleeft elke upgrade.
Hoe hooks worden uitgevoerd
Meerdere apps kunnen dezelfde event hooken. Frappe draait ze in install-volgorde. Geen blokkeert de ander — tenzij er een exception is, dan abort de operatie voor allemaal. Ontwerp uw hooks idempotent (veilig opnieuw te draaien) en licht.
Referentie: alle beschikbare hooks
Installatie-lifecycle
before_install = "my_app.install.before_install"
after_install = "my_app.install.after_install"
after_migrate = "my_app.install.after_migrate"
before_uninstall = "my_app.install.before_uninstall"
after_uninstall = "my_app.install.after_uninstall"
Document-events
doc_events = {
"Sales Invoice": {
"validate": "my_app.custom.sales_invoice.validate",
"before_save": "my_app.custom.sales_invoice.before_save",
"on_update": "my_app.custom.sales_invoice.on_update",
"before_submit": "my_app.custom.sales_invoice.before_submit",
"on_submit": "my_app.custom.sales_invoice.on_submit",
"before_cancel": "my_app.custom.sales_invoice.before_cancel",
"on_cancel": "my_app.custom.sales_invoice.on_cancel",
"on_trash": "my_app.custom.sales_invoice.on_trash",
},
"*": {
"on_update": "my_app.audit.log_change", # spaarzaam — vuurt op elk DocType
}
}
Scheduler
scheduler_events = {
"all": ["my_app.tasks.all"], # Elke minuut
"hourly": ["my_app.tasks.hourly"],
"daily": ["my_app.tasks.daily"],
"weekly": ["my_app.tasks.weekly"],
"monthly": ["my_app.tasks.monthly"],
"cron": {
"0 9 * * 1-5": ["my_app.tasks.weekday_morning"]
}
}
Permissies
permission_query_conditions = {
"Sales Invoice": "my_app.permissions.sales_invoice_query",
}
has_permission = {
"Sales Invoice": "my_app.permissions.sales_invoice_has_permission",
}
DocType override
override_doctype_class = {
"Sales Invoice": "my_app.overrides.CustomSalesInvoice"
}
UI inclusion
app_include_js = "my_app.bundle.js" # Alleen desk
app_include_css = "my_app.bundle.css"
web_include_js = "my_portal.bundle.js" # Alleen portal
web_include_css = "my_portal.bundle.css"
doctype_js = {
"Customer": "public/js/customer.js"
}
doctype_list_js = {
"Sales Invoice": "public/js/sales_invoice_list.js"
}
Routing & website
website_route_rules = [
{"from_route": "/orders/<name>", "to_route": "order-detail"},
]
update_website_context = ["my_app.context.update_context"]
Fixtures
fixtures = [
{"dt": "Role", "filters": [["name", "in", ["My Custom Role"]]]},
{"dt": "Custom Field", "filters": [["dt", "in", ["Customer", "Supplier"]]]},
]
Whitelisted methods
override_whitelisted_methods = {
"frappe.client.get_count": "my_app.custom.get_count"
}
Boot-sessie
boot_session = "my_app.boot.boot_session" # Voeg data toe aan frappe.boot
Voor canonieke updates en eventuele nieuwere hooks: frappeframework.com/docs/v15/user/en/python-api/hooks.