mirror of
https://github.com/inventree/inventree-docs.git
synced 2025-04-27 21:26:43 +00:00
Merge pull request #292 from matmair/plugin-updates
Plugin docs updates
This commit is contained in:
commit
bc000f8c8d
@ -36,32 +36,61 @@ If you want to make your life easier, try to follow these guidelines; break wher
|
||||
- keep it simple - more that 1000 LOC are normally to much for a plugin
|
||||
- use mixins where possible - we try to keep coverage high for them so they are not likely to break
|
||||
- do not use internal functions - if a functions name starts with `_` it is internal and might change at any time
|
||||
- keep you imports clean - the APIs for plugins and mixins are young and evolving. Use
|
||||
- keep you imports clean - the APIs for plugins and mixins are young and evolving (see [here](plugins.md#imports)). Use
|
||||
```
|
||||
from plugin import IntegrationPluginBase, registry
|
||||
from plugin import InvenTreePlugin, registry
|
||||
from plugin.mixins import APICallMixin, SettingsMixin, ScheduleMixin, BarcodeMixin
|
||||
```
|
||||
- deliver as a package - pip is great for dependency management and pypi can serve as a transparent and reliable delivery infrastructure
|
||||
- deliver as a package (see [below](#packaging))
|
||||
- if you need to use a private infrastructure, use the 'Releases' functions in GitHub or Gitlab. Point to the 'latest' release endpoint when installing to make sure the update function works
|
||||
- tag your GitHub repo with 'inventree' and 'inventreeplugins' to make discovery easier
|
||||
- tag your GitHub repo with `inventree` and `inventreeplugins` to make discovery easier. A discovery mechanism using these tags is on the roadmap.
|
||||
- use GitHub actions to test your plugin regularly (you can [schedule actions](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule)) against the 'latest' [docker-build](https://hub.docker.com/r/inventree/inventree) of InvenTree
|
||||
- if you use the AppMixin pin your plugin against the stable branch of InvenTree, your migrations might get messed up otherwise
|
||||
|
||||
### Packaging
|
||||
|
||||
The recommended way of distribution is as a [PEP 561](https://peps.python.org/pep-0561/) compliant package. If you can use the official Package Index (PyPi - [official website](https://pypi.org/)) as a registry.
|
||||
Please follow PyPAs official [packaging guide](https://packaging.python.org/en/latest/tutorials/packaging-projects/) to ensure your package installs correctly suing InvenTrees install mechanisms.
|
||||
|
||||
Your package must expose you plugin class as an [entrypoint](https://setuptools.pypa.io/en/latest/userguide/entry_point.html) with the name `inventree_plugins` to work with InvenTree.
|
||||
|
||||
```setup.cfg
|
||||
# Example setup.cfg
|
||||
[options.entry_points]
|
||||
inventree_plugins =
|
||||
ShopifyIntegrationPlugin = path.to.source:ShopifyIntegrationPluginClass
|
||||
```
|
||||
|
||||
```setup.py
|
||||
# Example setup.py
|
||||
|
||||
import setuptools
|
||||
|
||||
# ...
|
||||
|
||||
setuptools.setup(
|
||||
name='ShopifyIntegrationPlugin'
|
||||
.# ..
|
||||
|
||||
entry_points={"inventree_plugins": ["ShopifyIntegrationPlugin = path.to.source:ShopifyIntegrationPluginClass"]}
|
||||
```
|
||||
|
||||
|
||||
### A simple example
|
||||
This example adds a new action under `/api/action/sample` using the ActionMixin.
|
||||
``` py
|
||||
# -*- coding: utf-8 -*-
|
||||
"""sample implementation for ActionPlugin"""
|
||||
from plugin import IntegrationPluginBase
|
||||
from plugin import InvenTreePlugin
|
||||
from plugin.mixins import ActionMixin
|
||||
|
||||
|
||||
class SampleActionPlugin(ActionMixin, IntegrationPluginBase):
|
||||
class SampleActionPlugin(ActionMixin, InvenTreePlugin):
|
||||
"""
|
||||
Use docstrings for everything... pls
|
||||
"""
|
||||
|
||||
PLUGIN_NAME = "SampleActionPlugin"
|
||||
NAME = "SampleActionPlugin"
|
||||
ACTION_NAME = "sample"
|
||||
|
||||
# metadata
|
||||
|
@ -22,15 +22,52 @@ Note: Plugins are discovered and loaded only when the server is started.
|
||||
|
||||
### Plugin Base Class
|
||||
|
||||
Custom plugins must inherit from the [IntegrationPluginBase class](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/integration.py). Any plugins installed via the methods outlined above will be "discovered" when the InvenTree server launches.
|
||||
Custom plugins must inherit from the [InvenTreePlugin class](https://github.com/inventree/InvenTree/blob/2d1776a151721d65d0ae007049d358085b2fcfd5/InvenTree/plugin/plugin.py#L204). Any plugins installed via the methods outlined above will be "discovered" when the InvenTree server launches.
|
||||
|
||||
!!! warning "Namechange"
|
||||
The name of the base class was changed with `0.7.0` from `IntegrationPluginBase` to `InvenTreePlugin`. While the old name is still available till `0.8.0` we strongly suggest upgrading your plugins. Deprecation warnings are raised if the old name is used.
|
||||
|
||||
### Imports
|
||||
|
||||
As the code base is evolving import paths might change. Therefore we provide stable import targets for important python APIs.
|
||||
Please read all release notes and watch out for warnings - we generally provide backports for depreciated interfaces for at least one minor release.
|
||||
|
||||
#### Plugins
|
||||
|
||||
Generall classes an mechanisms are provided under the `plugin` [namespaces](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/__init__.py). These include:
|
||||
|
||||
```python
|
||||
# Management objects
|
||||
registry # Object that manages all plugin states and integrations
|
||||
|
||||
# Base classes
|
||||
InvenTreePlugin # Base class for all plugins
|
||||
|
||||
# Errors
|
||||
MixinImplementationError # Is raised if a mixin is implemented wrong (default not overwritten for example)
|
||||
MixinNotImplementedError # Is raised if a mixin was not implemented (core mechanisms are missing from the plugin)
|
||||
```
|
||||
|
||||
#### Mixins
|
||||
|
||||
Mixins are split up internally to keep the source tree clean and enable better testing seperation. All public APIs that should be used are exposed under `plugin.mixins`. These include all built-in mixins and notification methods. An up-to-date reference can be found in the source code (current master can be [found here](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/mixins/__init__.py)).
|
||||
|
||||
#### Models and other internal InvenTree APIs
|
||||
|
||||
!!! warning "Danger Zone"
|
||||
The APIs outside of the `plugin` namespace are not structured for public usage and require a more in-depth knowledge of the Django framework. Please ask in GitHub discussions of the `ÌnvenTree` org if you are not sure you are using something the intended way.
|
||||
|
||||
We do not provide stable interfaces to models or any other internal python APIs. If you need to integrate into these parts please make yourself familiar with the codebase. We follow general Django patterns and only stray from them in limited, special cases.
|
||||
If you need to react to state changes please use the [EventMixin](./plugins/event.md).
|
||||
|
||||
### Plugin Options
|
||||
|
||||
Some metadata options can be defined as constants in the plugins class
|
||||
Some metadata options can be defined as constants in the plugins class.
|
||||
|
||||
``` python
|
||||
PLUGIN_SLUG = None # Used in URLs, setting-names etc. when a unique slug as a reference is needed -> the plugin name is used if not set
|
||||
PLUGIN_TITLE = None # A nice human friendly name for the plugin -> used in titles, as plugin name etc.
|
||||
NAME = '' # Used as a general reference to the plugin
|
||||
SLUG = None # Used in URLs, setting-names etc. when a unique slug as a reference is needed -> the plugin name is used if not set
|
||||
TITLE = None # A nice human friendly name for the plugin -> used in titles, as plugin name etc.
|
||||
|
||||
AUTHOR = None # Author of the plugin, git commit information is used if not present
|
||||
PUBLISH_DATE = None # Publishing date of the plugin, git commit information is used if not present
|
||||
|
@ -11,7 +11,7 @@ When a certain (server-side) event occurs, the background worker passes the even
|
||||
Implementing classes must provide a `process_event` function:
|
||||
|
||||
```python
|
||||
class EventPlugin(EventMixin, IntegrationPluginBase):
|
||||
class EventPlugin(EventMixin, InvenTreePlugin):
|
||||
"""
|
||||
A simple example plugin which responds to events on the InvenTree server.
|
||||
|
||||
@ -19,9 +19,9 @@ class EventPlugin(EventMixin, IntegrationPluginBase):
|
||||
A more complex plugin could respond to specific events however it wanted.
|
||||
"""
|
||||
|
||||
PLUGIN_NAME = "EventPlugin"
|
||||
PLUGIN_SLUG = "event"
|
||||
PLUGIN_TITLE = "Triggered Events"
|
||||
NAME = "EventPlugin"
|
||||
SLUG = "event"
|
||||
TITLE = "Triggered Events"
|
||||
|
||||
def process_event(self, event, *args, **kwargs):
|
||||
print(f"Processing triggered event: '{event}'")
|
||||
|
@ -1,110 +0,0 @@
|
||||
---
|
||||
title: Integration Plugins
|
||||
---
|
||||
|
||||
### Integration Plugins
|
||||
|
||||
Integration Plugins provide a wide area of deep integration into the interface of InvenTree.
|
||||
|
||||
For an example of a pretty much full Integration Plugin, refer to `/InvenTree/plugin/samples/integration/sample.py`
|
||||
|
||||
#### Plugin Options
|
||||
|
||||
Some metadata options can be defined as constants in the plugins class.
|
||||
|
||||
``` python
|
||||
PLUGIN_SLUG = None # Used in URLs, setting-names etc. when a unique slug as a reference is needed -> the plugin name is used if not set
|
||||
PLUGIN_TITLE = None # A nice human friendly name for the plugin -> used in titles, as plugin name etc.
|
||||
|
||||
AUTHOR = None # Author of the plugin, git commit information is used if not present
|
||||
PUBLISH_DATE = None # Publishing date of the plugin, git commit information is used if not present
|
||||
VERSION = None # Version of the plugin
|
||||
WEBSITE = None # Website for the plugin, developer etc. -> is shown in plugin overview if set
|
||||
```
|
||||
|
||||
|
||||
|
||||
##
|
||||
#### Mixins
|
||||
|
||||
Common use cases are covered by pre-supplied modules in the form of mixins (similar to how [django](https://docs.djangoproject.com/en/stable/topics/class-based-views/mixins/) does it). Each mixin enables the integration into a specific area of InvenTree. Sometimes it also enhances the plugin with helper functions to supply often used functions out-of-the-box.
|
||||
|
||||
##### Basic Mixin Functions
|
||||
|
||||
All mixins are registered with the plugin on start-up so you can access all added mixins as a dict with the `plugin.registered_mixins` property that is added to each plugin.
|
||||
|
||||
The function `plugin.mixin_enabled(key)` returns if a mixin is present in a plugin and configured correctly.
|
||||
|
||||
##### Initialisation
|
||||
|
||||
Each mixin must call `super().__init__()` in it's `__init__` function and register itself with a call to `self.add_mixin()`. Check out the built-in mixins for examples.
|
||||
|
||||
``` python
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.add_mixin('settings', 'has_settings', __class__)
|
||||
```
|
||||
|
||||
##### Meta Options
|
||||
|
||||
Each mixin can define additional options as a Meta subclass. These are used to describe the mixin.
|
||||
|
||||
|
||||
#### SettingsMixin
|
||||
|
||||
Use the class constant `SETTINGS` for a dict of settings that should be added as global database settings.
|
||||
The dict must be formatted similar to the following sample. Take a look at the settings defined in `InvenTree.common.models.InvenTreeSetting` for all possible parameters.
|
||||
|
||||
|
||||
``` python
|
||||
SETTINGS = {
|
||||
'PO_FUNCTION_ENABLE': {
|
||||
'name': _('Enable PO'),
|
||||
'description': _('Enable PO functionality in InvenTree interface'),
|
||||
'default': True,
|
||||
'validator': bool,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
!!! note "Use carefully"
|
||||
All global and user settings are exposed to the frontend code and can be read out via the browsers developer tools. You can protect a setting from export by adding `'protected': True` to sensitive settings.
|
||||
You can access settings in frontend JS code under the global variable `global_settings`.
|
||||
|
||||
This mixin defines the helper functions `plugin.get_setting` and `plugin.set_seting` to access all plugin specific settings.
|
||||
|
||||
|
||||
#### UrlsMixin
|
||||
|
||||
Use the class constant `URLS` for a array of URLs that should be added to InvenTrees URL paths or override the `plugin.setup_urls` function.
|
||||
The array has to contain valid URL patterns as defined in the [django documentation](https://docs.djangoproject.com/en/stable/topics/http/urls/).
|
||||
|
||||
``` python
|
||||
URLS = [
|
||||
url(r'increase/(?P<location>\d+)/(?P<pk>\d+)/', self.view_increase, name='increase-level'),
|
||||
]
|
||||
```
|
||||
|
||||
The URLs get exposed under `/plugin/{plugin.slug}/*` and get exposed to the template engine with the prefix `plugin:{plugin.slug}:` (for usage with the [url tag](https://docs.djangoproject.com/en/stable/ref/templates/builtins/#url)).
|
||||
|
||||
|
||||
#### NavigationMixin
|
||||
|
||||
Use the class constant `NAVIGATION` for a array of links that should be added to InvenTrees navigation header.
|
||||
The array must contain at least one dict that at least define a name and a link for each element. The link must be formatted for a URL pattern name lookup - links to external sites are not possible directly. The optional icon must be a class reference to an icon (InvenTree ships with fontawesome 4 by default).
|
||||
|
||||
``` python
|
||||
NAVIGATION = [
|
||||
{'name': 'SampleIntegration', 'link': 'plugin:sample:hi', 'icon': 'fas fa-box'},
|
||||
]
|
||||
```
|
||||
|
||||
The optional class constants `NAVIGATION_TAB_NAME` and `NAVIGATION_TAB_ICON` can be used to change the name and icon for the parent navigation node.
|
||||
|
||||
|
||||
#### AppMixin
|
||||
|
||||
If this mixin is added to a plugin the directory the plugin class is defined in is added to InvenTrees `INSTALLED_APPS`.
|
||||
|
||||
!!! warning "Danger Zone"
|
||||
Only use this mixin if you have an understanding of djangos [app system](https://docs.djangoproject.com/en/stable/ref/applications). Plugins with this mixin are deeply integrated into InvenTree and can cause difficult to reproduce or long-running errors. Use the built-in testing functions of django to make sure your code does not cause unwanted behaviour in InvenTree before releasing.
|
@ -27,16 +27,16 @@ Plugins which implement the `LabelPrintingMixin` mixin class must provide a `pri
|
||||
```python
|
||||
from dummy_printer import printer_backend
|
||||
|
||||
class MyLabelPrinter(LabelPrintingMixin, IntegrationPluginBase):
|
||||
class MyLabelPrinter(LabelPrintingMixin, InvenTreePlugin):
|
||||
"""
|
||||
A simple example plugin which provides support for a dummy printer.
|
||||
|
||||
A more complex plugin would communicate with an actual printer!
|
||||
"""
|
||||
|
||||
PLUGIN_NAME = "MyLabelPrinter"
|
||||
PLUGIN_SLUG = "mylabel"
|
||||
PLUGIN_TITLE = "A dummy printer"
|
||||
NAME = "MyLabelPrinter"
|
||||
SLUG = "mylabel"
|
||||
TITLE = "A dummy printer"
|
||||
|
||||
def print_label(self, label, **kwargs):
|
||||
"""
|
||||
|
@ -8,9 +8,9 @@ Use the class constant `NAVIGATION` for a array of links that should be added to
|
||||
The array must contain at least one dict that at least define a name and a link for each element. The link must be formatted for a URL pattern name lookup - links to external sites are not possible directly. The optional icon must be a class reference to an icon (InvenTree ships with fontawesome 4 by default).
|
||||
|
||||
``` python
|
||||
class MyNavigationPlugin(NavigationMixin, IntegrationPluginBase):
|
||||
class MyNavigationPlugin(NavigationMixin, InvenTreePlugin):
|
||||
|
||||
PLUGIN_NAME = "NavigationPlugin"
|
||||
NAME = "NavigationPlugin"
|
||||
|
||||
NAVIGATION = [
|
||||
{'name': 'SampleIntegration', 'link': 'plugin:sample:hi', 'icon': 'fas fa-box'},
|
||||
|
@ -16,13 +16,13 @@ The ScheduleMixin class provides a plugin with the ability to call functions at
|
||||
An example of a plugin which supports scheduled tasks:
|
||||
|
||||
```python
|
||||
class ScheduledTaskPlugin(ScheduleMixin, SettingsMixin, IntegrationPluginBase):
|
||||
class ScheduledTaskPlugin(ScheduleMixin, SettingsMixin, InvenTreePlugin):
|
||||
"""
|
||||
Sample plugin which runs a scheduled task, and provides user configuration.
|
||||
"""
|
||||
|
||||
PLUGIN_NAME = "Scheduled Tasks"
|
||||
PLUGIN_SLUG = 'schedule'
|
||||
NAME = "Scheduled Tasks"
|
||||
SLUG = 'schedule'
|
||||
|
||||
SCHEDULED_TASKS = {
|
||||
'global': {
|
||||
|
@ -15,9 +15,9 @@ The dict must be formatted similar to the following sample. Take a look at the s
|
||||
|
||||
|
||||
``` python
|
||||
class PluginWithSettings(SettingsMixin, IntegrationPluginBase):
|
||||
class PluginWithSettings(SettingsMixin, InvenTreePlugin):
|
||||
|
||||
PLUGIN_NAME = "PluginWithSettings"
|
||||
NAME = "PluginWithSettings"
|
||||
|
||||
SETTINGS = {
|
||||
'API_ENABLE': {
|
||||
|
@ -9,9 +9,9 @@ Use the class constant `URLS` for a array of URLs that should be added to InvenT
|
||||
The array has to contain valid URL patterns as defined in the [django documentation](https://docs.djangoproject.com/en/stable/topics/http/urls/).
|
||||
|
||||
``` python
|
||||
class MyUrlsPlugin(URLsMixin, IntegrationPluginBase):
|
||||
class MyUrlsPlugin(URLsMixin, InvenTreePlugin):
|
||||
|
||||
PLUGIN_NAME = "UrlsMixin"
|
||||
NAME = "UrlsMixin"
|
||||
|
||||
URLS = [
|
||||
url(r'increase/(?P<location>\d+)/(?P<pk>\d+)/', self.view_increase, name='increase-level'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user