Events and hooks
Standard business addons automate cross-module behavior through the in-process event bus and ORM extension points.
Event subscription
Package: sumeru/core/event
event.Subscribe("record.updated", func(ctx context.Context, ev event.Event) error {
if ev.Payload["model"] != "crm.lead" {
return nil
}
// read ev.Payload["id"], ev.Payload["values"]
return nil
})
Common events:
| Event | When |
|---|---|
record.created | After insert commit |
record.updated | After update commit |
cron.tick | Scheduler tick (from sys.cron) |
| Custom names | From cron row event_name field |
Register subscriptions in init.go or a services/ package imported from init.go.
Privileged writes
Use orm.ContextWithBypass(ctx) when the handler must write records the triggering user cannot access (e.g. auto-creating a quotation).
Object actions
UI buttons on forms call registered handlers:
orm.RegisterObjectAction("crm.lead", "action_set_won", handler)
Handler returns redirect URL or sets vals["next"]. See sumeru_addons/crm/services/hooks.go and account/services/actions.go.
Kanban expanders
Package: sumeru/core/engine/swcmeta
swcmeta.RegisterKanbanGroupExpander("crm.lead", "stage_id", expandFn)
Used for CRM pipeline and forecast kanbans in the SWC workspace.
Cron handlers
Register a Go handler keyed by a sys.cron row’s code field that you seed yourself:
scheduler.RegisterCronHandler("my_module.nightly_digest", func(ctx context.Context, payload map[string]interface{}) error {
// run periodic work
return nil
})
The scheduler still publishes cron.tick and any custom event_name on the cron row.
CRM subscribes to crm.cron_assign_leads in crm/services/hooks.go for round-robin assignment, but does not seed a sys.cron row. Shipped UX is the Assign Leads object button on the team form. Subscribe to that event (or add your own cron that publishes it) only if you want a schedule.
Alternatively, subscribe to cron.tick or a custom event name — the automation addon uses the same bus.
Declarative server actions
Define sys.server.action rows in data XML with declarative code (no Go required for simple flows):
publish:— chain a follow-up eventwrite:— write fields on the triggering record
See Events & automation for XML examples.
HTTP routes
router.Register(http.MethodGet, "/account/invoice/print", router.AuthSession, handler)
See Custom HTTP route.
Service layer
Keep heavy logic in services/ packages:
account/services/invoice.go— create/post movesaccount/services/payment.go— paymentsaccount/services/reconcile.go— reconciliation
Export functions like CreateCustomerInvoiceFromSale for custom addons to call.