Skip to main content
ClaudeWave
Skill125 estrellas del repoactualizado 2mo ago

frappe-syntax-hooks-events

>

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/Impertio-Studio/Frappe_Claude_Skill_Package /tmp/frappe-syntax-hooks-events && cp -r /tmp/frappe-syntax-hooks-events/skills/source/syntax/frappe-syntax-hooks-events ~/.claude/skills/frappe-syntax-hooks-events
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# Document Lifecycle Hooks (doc_events)

## Quick Reference: Event Execution Order

### Insert (new document)

| Order | Event               | Purpose                              | Can Raise? |
|-------|---------------------|--------------------------------------|------------|
| 1     | `before_insert`     | Set defaults before naming           | YES        |
| 2     | `before_naming`     | Modify naming logic                  | YES        |
| 3     | `autoname`          | Set the `name` property              | YES        |
| 4     | `before_validate`   | Auto-set missing values              | YES        |
| 5     | `validate`          | Validation logic — throw to abort    | YES        |
| 6     | `before_save`       | Final mutations before DB write      | YES        |
| 7     | `db_insert`         | *Internal* — writes row to DB        | —          |
| 8     | `after_insert`      | Post-insert logic (runs once ever)   | YES        |
| 9     | `on_update`         | Post-save logic (runs on every save) | YES        |
| 10    | `on_change`         | Fires if any field value changed     | YES        |

### Save (existing document)

| Order | Event             | Purpose                           |
|-------|-------------------|-----------------------------------|
| 1     | `before_validate` | Auto-set missing values           |
| 2     | `validate`        | Validation logic — throw to abort |
| 3     | `before_save`     | Final mutations before DB write   |
| 4     | `db_update`       | *Internal* — updates row in DB    |
| 5     | `on_update`       | Post-save logic                   |
| 6     | `on_change`       | Fires if any field value changed  |

### Submit

| Order | Event             | Purpose                            |
|-------|-------------------|------------------------------------|
| 1     | `before_validate` | Auto-set missing values            |
| 2     | `validate`        | Validation logic                   |
| 3     | `before_save`     | Final mutations before DB write    |
| 4     | `before_submit`   | Pre-submit logic — throw to abort  |
| 5     | `db_update`       | *Internal* — updates row in DB     |
| 6     | `on_submit`       | Post-submit logic (GL entries etc) |
| 7     | `on_update`       | Post-save logic                    |
| 8     | `on_change`       | Fires if any field value changed   |

### Cancel

| Order | Event             | Purpose                             |
|-------|-------------------|-------------------------------------|
| 1     | `before_cancel`   | Pre-cancel validation               |
| 2     | `db_update`       | *Internal* — updates row in DB      |
| 3     | `on_cancel`       | Post-cancel logic (reverse GL etc)  |
| 4     | `on_change`       | Fires if any field value changed    |

### Delete

| Order | Event          | Purpose                        |
|-------|----------------|--------------------------------|
| 1     | `on_trash`     | Pre-delete cleanup             |
| 2     | `after_delete` | Post-delete logic              |

### Other Operations

| Operation              | Events (in order)                                        |
|------------------------|----------------------------------------------------------|
| Rename                 | `before_rename` → `after_rename`                         |
| Amend                  | `before_insert` chain runs on the new amended doc        |
| Update After Submit    | `before_update_after_submit` → `db_update` → `on_update_after_submit` → `on_change` |

---

## doc_events in hooks.py: Syntax

### Basic Structure

```python
# hooks.py
doc_events = {
    "Sales Invoice": {
        "on_submit": "myapp.events.sales_invoice.on_submit",
        "on_cancel": "myapp.events.sales_invoice.on_cancel",
    },
    "Purchase Order": {
        "validate": "myapp.events.purchase_order.validate",
    }
}
```

### Wildcard: Apply to ALL DocTypes

```python
doc_events = {
    "*": {
        "after_insert": "myapp.events.global_handler.after_insert_all",
        "on_update": "myapp.events.global_handler.track_changes",
    }
}
```

ALWAYS use `"*"` (string with asterisk) as the key. This fires the handler for every DocType.

### Multiple Handlers per Event

```python
doc_events = {
    "Sales Invoice": {
        "on_submit": [
            "myapp.events.accounting.create_gl_entries",
            "myapp.events.notifications.send_invoice_email",
        ]
    }
}
```

### Handler Function Signature

```python
# myapp/events/sales_invoice.py
def on_submit(doc, method=None):
    """
    doc    — the Document instance (e.g., Sales Invoice)
    method — string name of the event (e.g., "on_submit"), or None
    """
    if doc.grand_total > 10000:
        frappe.sendmail(...)
```

ALWAYS accept `method` as the second parameter (with default `None`). Frappe passes it automatically.

---

## Decision Tree: Which Event to Use

### "I need to validate data before saving"
→ Use `validate`. ALWAYS raise `frappe.throw()` here to block invalid saves.

### "I need to set default values automatically"
→ Use `before_validate`. This runs before `validate`, so your defaults are set before validation checks.

### "I need to run logic only on first creation"
→ Use `after_insert`. This fires ONLY on insert, NEVER on subsequent saves.

### "I need to run logic on every save (insert + update)"
→ Use `on_update`. This fires on both insert and save operations.

### "I need to create linked documents after submit"
→ Use `on_submit`. NEVER create linked docs in `validate` — the document is not yet committed.

### "I need to reverse linked documents on cancel"
→ Use `on_cancel`. ALWAYS clean up GL entries, stock ledger entries, and linked docs here.

### "I need to modify the document name"
→ Use `autoname` in the controller, or `before_naming` for conditional logic.

### "I need to prevent deletion under certain conditions"
→ Use `on_trash`. Raise `frappe.throw()` to block deletion.

### "I need to update a submitted document's fields"
→