Report Plugins (#4643)

* Add plugin mixin class for extending reports

* Expose report context to the plugin system

* Add an example mixin for adding context data to a report

* Add the 'request' object to the plugin code
This commit is contained in:
Oliver 2023-04-20 14:21:22 +10:00 committed by GitHub
parent a020548c8e
commit 68d1682000
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 0 deletions

View File

@ -0,0 +1,35 @@
"""Plugin mixin class for ReportContextMixin"""
class ReportMixin:
"""Mixin which provides additional context to generated reports.
This plugin mixin acts as a "shim" when generating reports,
can can add extra context data to a report template.
Useful for custom report generation where the report template
needs some extra information which is not provided by default,
or some complex logic to generate the report.
"""
class MixinMeta:
"""Meta options for this mixin."""
MIXIN_NAME = 'ReportContext'
def __init__(self):
"""Register mixin."""
super().__init__()
self.add_mixin('report', True, __class__)
def add_report_context(self, instance, request, context):
"""Add extra context to the provided report instance.
By default, this method does nothing.
Args:
instance: The report instance to add context to
request: The request object which initiated the report generation
context: The context dictionary to add to
"""
pass

View File

@ -10,6 +10,7 @@ from ..base.integration.AppMixin import AppMixin
from ..base.integration.mixins import (APICallMixin, NavigationMixin, from ..base.integration.mixins import (APICallMixin, NavigationMixin,
PanelMixin, SettingsContentMixin, PanelMixin, SettingsContentMixin,
ValidationMixin) ValidationMixin)
from ..base.integration.ReportMixin import ReportMixin
from ..base.integration.ScheduleMixin import ScheduleMixin from ..base.integration.ScheduleMixin import ScheduleMixin
from ..base.integration.SettingsMixin import SettingsMixin from ..base.integration.SettingsMixin import SettingsMixin
from ..base.integration.UrlsMixin import UrlsMixin from ..base.integration.UrlsMixin import UrlsMixin
@ -22,6 +23,7 @@ __all__ = [
'EventMixin', 'EventMixin',
'LabelPrintingMixin', 'LabelPrintingMixin',
'NavigationMixin', 'NavigationMixin',
'ReportMixin',
'ScheduleMixin', 'ScheduleMixin',
'SettingsContentMixin', 'SettingsContentMixin',
'SettingsMixin', 'SettingsMixin',

View File

@ -39,6 +39,7 @@ class PluginsRegistry:
from .base.integration.ScheduleMixin import ScheduleMixin from .base.integration.ScheduleMixin import ScheduleMixin
from .base.integration.SettingsMixin import SettingsMixin from .base.integration.SettingsMixin import SettingsMixin
from .base.integration.UrlsMixin import UrlsMixin from .base.integration.UrlsMixin import UrlsMixin
DEFAULT_MIXIN_ORDER = [SettingsMixin, ScheduleMixin, AppMixin, UrlsMixin] DEFAULT_MIXIN_ORDER = [SettingsMixin, ScheduleMixin, AppMixin, UrlsMixin]
def __init__(self, mixin_order: list = None) -> None: def __init__(self, mixin_order: list = None) -> None:

View File

@ -0,0 +1,38 @@
"""Sample plugin for extending reporting functionality"""
import random
from plugin import InvenTreePlugin
from plugin.mixins import ReportMixin
from report.models import PurchaseOrderReport
class SampleReportPlugin(ReportMixin, InvenTreePlugin):
"""Sample plugin which provides extra context data to a report"""
NAME = "Report Plugin"
SLUG = "reportexample"
TITLE = "Sample Report Plugin"
DESCRIPTION = "A sample plugin which provides extra context data to a report"
VERSION = "1.0"
def some_custom_function(self):
"""Some custom function which is not required for the plugin to function"""
return random.randint(0, 100)
def add_report_context(self, instance, request, context):
"""Add example content to the report instance"""
# We can add any extra context data we want to the report
# Generate a random string of data
context['random_text'] = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=20))
# Call a custom method
context['random_int'] = self.some_custom_function()
# We can also add extra data to the context which is specific to the report type
context['is_purchase_order'] = isinstance(instance, PurchaseOrderReport)
# We can also use the 'request' object to add extra context data
context['request_method'] = request.method

View File

@ -22,6 +22,7 @@ import part.models
import stock.models import stock.models
from InvenTree.helpers import validateFilterString from InvenTree.helpers import validateFilterString
from InvenTree.models import MetadataMixin from InvenTree.models import MetadataMixin
from plugin.registry import registry
try: try:
from django_weasyprint import WeasyTemplateResponseMixin from django_weasyprint import WeasyTemplateResponseMixin
@ -212,6 +213,12 @@ class ReportTemplateBase(MetadataMixin, ReportBase):
context['request'] = request context['request'] = request
context['user'] = request.user context['user'] = request.user
# Pass the context through to any active reporting plugins
plugins = registry.with_mixin('report')
for plugin in plugins:
plugin.add_report_context(self, request, context)
return context return context
def generate_filename(self, request, **kwargs): def generate_filename(self, request, **kwargs):