Skip to content

Event Mixin

EventMixin

The EventMixin class enables plugins to respond to certain triggered events.

When a certain (server-side) event occurs, the background worker passes the event information to any plugins which inherit from the EventMixin base class.

Enable Event Integration

The Enable Event Integration option must first be enabled to allow plugins to respond to events.

Enable event integration Enable event integration

Events

Events are passed through using a string identifier, e.g. build.completed

The arguments (and keyword arguments) passed to the receiving function depend entirely on the type of event.

Read the Code

Implementing a response to a particular event requires a working knowledge of the InvenTree code base, especially related to that event being received. While the available events are documented here, to implement a response to a particular event you will need to read the code to understand what data is passed to the event handler.

Generic Events

There are a number of generic events which are generated on certain database actions. Whenever a database object is created, updated, or deleted, a corresponding event is generated.

Object Created

When a new object is created in the database, an event is generated with the following event name: <app>_<model>.created, where <model> is the name of the model class (e.g. part, stockitem, etc).

The event is called with the following keywords arguments:

  • model: The model class of the object that was created
  • id: The primary key of the object that was created

Example:

A new Part object is created with primary key 123, resulting in the following event being generated:

trigger_event('part_part.created', model='part', id=123)

Object Updated

When an object is updated in the database, an event is generated with the following event name: <app>_<model>.saved, where <model> is the name of the model class (e.g. part, stockitem, etc).

The event is called with the following keywords arguments:

  • model: The model class of the object that was updated
  • id: The primary key of the object that was updated

Example:

A Part object with primary key 123 is updated, resulting in the following event being generated:

trigger_event('part_part.saved', model='part', id=123)

Object Deleted

When an object is deleted from the database, an event is generated with the following event name: <app>_<model>.deleted, where <model> is the name of the model class (e.g. part, stockitem, etc).

The event is called with the following keywords arguments:

  • model: The model class of the object that was deleted
  • id: The primary key of the object that was deleted (if available)

Example:

A Part object with primary key 123 is deleted, resulting in the following event being generated:

trigger_event('part_part.deleted', model='part', id=123)

Object Deleted

Note that the event is triggered after the object has been deleted from the database, so the object itself is no longer available.

Specific Events

In addition to the generic events listed above, there are a number of other events which are triggered by specific actions within the InvenTree codebase.

The available events are provided in the enumerations listed below. Note that while the names of the events are documented here, the exact arguments passed to the event handler will depend on the specific event being triggered.

Build Events

Event enumeration for the Build app.

Source code in src/backend/InvenTree/build/events.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class BuildEvents(BaseEventEnum):
    """Event enumeration for the Build app."""

    # Build order events
    HOLD = 'build.hold'
    ISSUED = 'build.issued'
    CANCELLED = 'build.cancelled'
    COMPLETED = 'build.completed'
    OVERDUE = 'build.overdue_build_order'

    # Build output events
    OUTPUT_CREATED = 'buildoutput.created'
    OUTPUT_COMPLETED = 'buildoutput.completed'

Part Events

Event enumeration for the Part models.

Source code in src/backend/InvenTree/part/events.py
6
7
class PartEvents(BaseEventEnum):
    """Event enumeration for the Part models."""

Stock Events

Event enumeration for the Stock app.

Source code in src/backend/InvenTree/stock/events.py
 6
 7
 8
 9
10
11
12
13
14
15
16
class StockEvents(BaseEventEnum):
    """Event enumeration for the Stock app."""

    # StockItem events
    ITEM_ASSIGNED_TO_CUSTOMER = 'stockitem.assignedtocustomer'
    ITEM_RETURNED_FROM_CUSTOMER = 'stockitem.returnedfromcustomer'
    ITEM_SPLIT = 'stockitem.split'
    ITEM_MOVED = 'stockitem.moved'
    ITEM_COUNTED = 'stockitem.counted'
    ITEM_QUANTITY_UPDATED = 'stockitem.quantityupdated'
    ITEM_INSTALLED_INTO_ASSEMBLY = 'stockitem.installed'

Purchase Order Events

Event enumeration for the PurchaseOrder models.

Source code in src/backend/InvenTree/order/events.py
 6
 7
 8
 9
10
11
12
13
14
15
16
class PurchaseOrderEvents(BaseEventEnum):
    """Event enumeration for the PurchaseOrder models."""

    PLACED = 'purchaseorder.placed'
    COMPLETED = 'purchaseorder.completed'
    CANCELLED = 'purchaseorder.cancelled'
    HOLD = 'purchaseorder.hold'

    OVERDUE = 'order.overdue_purchase_order'

    ITEM_RECEIVED = 'purchaseorderitem.received'

Sales Order Events

Event enumeration for the SalesOrder models.

Source code in src/backend/InvenTree/order/events.py
19
20
21
22
23
24
25
26
27
28
29
class SalesOrderEvents(BaseEventEnum):
    """Event enumeration for the SalesOrder models."""

    ISSUED = 'salesorder.issued'
    HOLD = 'salesorder.onhold'
    COMPLETED = 'salesorder.completed'
    CANCELLED = 'salesorder.cancelled'

    OVERDUE = 'order.overdue_sales_order'

    SHIPMENT_COMPLETE = 'salesordershipment.completed'

Return Order Events

Event enumeration for the Return models.

Source code in src/backend/InvenTree/order/events.py
32
33
34
35
36
37
38
39
class ReturnOrderEvents(BaseEventEnum):
    """Event enumeration for the Return models."""

    ISSUED = 'returnorder.issued'
    RECEIVED = 'returnorder.received'
    COMPLETED = 'returnorder.completed'
    CANCELLED = 'returnorder.cancelled'
    HOLD = 'returnorder.hold'

Plugin Events

Event enumeration for the Plugin app.

Source code in src/backend/InvenTree/plugin/events.py
 7
 8
 9
10
11
class PluginEvents(BaseEventEnum):
    """Event enumeration for the Plugin app."""

    PLUGINS_LOADED = 'plugins_loaded'
    PLUGIN_ACTIVATED = 'plugin_activated'

Samples

Sample Plugin - All events

Implementing classes must at least provide a process_event function:

A sample plugin which provides supports for triggered events.

Source code in src/backend/InvenTree/plugin/samples/event/event_sample.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class EventPluginSample(EventMixin, InvenTreePlugin):
    """A sample plugin which provides supports for triggered events."""

    NAME = 'EventPlugin'
    SLUG = 'sampleevent'
    TITLE = 'Triggered Events'

    def process_event(self, event, *args, **kwargs):
        """Custom event processing."""
        print(f"Processing triggered event: '{event}'")
        print('args:', str(args))
        print('kwargs:', str(kwargs))

        # Issue warning that we can test for
        if settings.PLUGIN_TESTING:
            logger.debug('Event `%s` triggered in sample plugin', event)

Sample Plugin - Specific Events

If you want to process just some specific events, you can also implement the wants_process_event function to decide if you want to process this event or not. This function will be executed synchronously, so be aware that it should contain simple logic.

Overall this function can reduce the workload on the background workers significantly since less events are queued to be processed.

A sample plugin which provides supports for triggered events.

Source code in src/backend/InvenTree/plugin/samples/event/filtered_event_sample.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class FilteredEventPluginSample(EventMixin, InvenTreePlugin):
    """A sample plugin which provides supports for triggered events."""

    NAME = 'FilteredEventPlugin'
    SLUG = 'filteredsampleevent'
    TITLE = 'Triggered by test.event only'

    def wants_process_event(self, event):
        """Return whether given event should be processed or not."""
        return event == 'test.event'

    def process_event(self, event, *args, **kwargs):
        """Custom event processing."""
        print(f"Processing triggered event: '{event}'")
        print('args:', str(args))
        print('kwargs:', str(kwargs))

        # Issue warning that we can test for
        if settings.PLUGIN_TESTING:
            logger.debug('Event `%s` triggered in sample plugin', event)