Skip to content

Commit

Permalink
Report printing refactor (#7074)
Browse files Browse the repository at this point in the history
* Adds a new "generic" ReportTemplate model

* expose API endpoints

* Update model / migrations / serializer

* Add new mixin class to existing database models

* - Add detail view for report template
- Revert filters field behaviour

* Filter report list by provided item IDs

- Greatly simplify filtering logic compared to existing implemetation
- Expose to API schema

* Create data migration for converting *old* report templates

* Ignore internal reports for data migration

* Add report mixin to StockLocation model

* Provide model choices in admin interface

* Offload context data generation to the model classes

* Remove old report template models

* Refactor JS code in CUI

* Fix for API filtering

* Add data migration to delete old models

* Remove dead URL

* Updates

* Construct sample report templates on app start

* Bump API version

* Typo fix

* Fix incorrect context calls

* Add new LabelTemplate model

- ReportTemplate and LabelTemplate share common base
- Refactor previous migration

* Expose to admin interface

* Add in extra context from existing label models

* Add migration to create LabelTemplate instances from existing labels

* Add API endpoints for listing and updating LabelTemplate objects

* Adjust 'upload_to' path

* Refactor label printing

* Move default label templates

* Update API endpoints

* Update migrations

* Handle LookupError in migration

* Redirect the "label" API endpoint

* Add new model for handling result of template printing

* Refactor LabelPrinting mixin

* Unlink "labels" app entirely

* Fix typo

* Record 'plugin' used to generate a particular output

* Fix imports

* Generate label print response

- Still not good yet

* Refactoring label printing in CUI

* add "items" count to TemplateOutput model

* Fix for InvenTreeLabelSheetPlugin

* Remove old "label" app

* Make request object optional

* Fix filename generation

* Add help text for "model_type"

* Simplify TemplateTable

* Tweak TemplateTable

* Get template editor to display template data again

* Stringify template name

- Important, otherwise you get a TypeError instead of TemplateDoesNotExist

* Add hooks to reset plugin state

* fix context for StockLocation model

* Tweak log messages

* Fix incorrect serializer

* Cleanup TemplateTable

* Fix broken import

* Filter by target model type

* Remove manual file operations

* Update old migrations

- Remove references to functions that no longer exist

* Refactor asset / snippet uploading

* Update comments

* Retain original filename when editing templatese

* Cleanup

* Refactor model type filter to use new hook

* Add placeholder actions for printing labels and reports

* Improve hookiness

* Add new ReportOutput class

* Report printing works from PUI now!

* More inspired filename pattern for generated reports

* Fix template preview window

- Use new "output" response field across the board

* Remove outdated task

* Update data migration to use raw SQL

- If the 'labels' app is no longer available, this will fail
- So, use raw SQL instead

* Add more API endpoint defs

* Adds placeholder API endpoint for label printing

* Expose plugin field to the printing endpoint

* Adds plugin model type

* Hook to print labels

* Refactor action dropdown items

* Refactor report printing for CUI

* Refactor label print for CUI

- Still needs to handle custom printing options for plugin

* Fix migration

* Update ModelType dict

* playwright test fix

* Unit test fixes

* Fix model ruleset associations

* Fix for report.js

* Add support for "dynamic" fields in metadata.py

* Add in custom fields based on plugin

* Refactoring

* Reset plugin on form close

* Set custom timeout values

* Update migration

- Not atomic

* Cleanup

* Implement more printing actions

* Reduce timeout

* Unit test updates

* Fix part serializers

* Label printing works in CUI again

* js linting

* Update <ActionDropdown>

* Fix for label printing API endpoint

* Fix filterselectdrawer

* Improve button rendering

* Allow printing from StockLocationTable

* Add aria-labels to modal form fields

* Add test for printing stock item labels from table

* Add test for report printing

* Add unit testing for report template editing / preview

* Message refactor

* Refactor InvenTreeReportMixin class

* Update playwright test

* Update 'verbose_name' for a number of models

* Additional admin filtering

* Playwright test updates

* Run checks against new python lib branch

(temporary, will be reverted)

* remove old app reference

* fix testing ref

* fix app init

* remove old tests

* Revert custom target branch

* Expose label and report output objects to API

* refactor

* fix a few tests

* factor plugin_ref out

* fix options testing

* Update table field header

* re-enable full options testing

* fix missing plugin matching

* disable call assert

* Add custom related field for PluginConfig

- Uses 'key' rather than 'pk'
- Revert label print plugin to use slug

* Add support for custom pk field in metadata

* switch to labels for testing

* re-align report testing code

* disable version check

* fix url

* Implement lazy loading

* Allow blank plugin for printing

- Uses the builtin label printer if not specified

* Add printing actions for StockItem

* Fix for metadata helper

* Use key instead of pk in printing actions

* Support non-standard pk values in RelatedModelField

* pass context data to report serializers

* disable template / item discovery

* fix call

* Tweak unit test

* Run python checks against specific branch

* Add task for running docs server

- Option to compile schema as part of task

* Custom branch no longer needed

* Starting on documentation updates

* fix tests for reports

* fix label testing

* Update template context variables

* Refactor report context documentation

* Documentation cleanup

* Docs cleanup

* Include sample report files

* Fix links

* Link cleanup

* Integrate plugin example code into docs

* Code cleanup

* Fix type annotation

* Revert deleted variable

* remove templatetype

* remove unused imports

* extend context testing

* test if plg can print

* re-enable version check

* Update unit tests

* Fix test

* Adjust unit test

* Add debug statement to test

* Fix unit test

- Labels get printed against LabelTemplate items, duh

* Unit test update

* Unit test updates

* Test update

* Patch fix for <PartColumn> component

* Fix ReportSerialierBase class

- Re-initialize field options if not already set

* Fix unit test for sqlite

* Fix kwargs for non-blocking label printing

* Update playwright tests

* Tweak unit test

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
  • Loading branch information
SchrodingersGat and matmair authored May 22, 2024
1 parent d99b6ae commit aa39582
Show file tree
Hide file tree
Showing 217 changed files with 4,383 additions and 6,638 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,6 @@ src/backend/InvenTree/web/static
InvenTree/web/static

# Generated docs files
docs/schema.yml
docs/docs/api/*.yml
docs/docs/api/schema/*.yml
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion docs/docs/extend/plugins/action.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,14 @@ POST {
}
```

For an example of a very simple action plugin, refer to `/src/backend/InvenTree/plugin/samples/integratoni/simpleactionplugin.py`
### Sample Plugin

A sample action plugin is provided in the `InvenTree` source code, which can be used as a template for creating custom action plugins:

::: plugin.samples.integration.simpleactionplugin.SimpleActionPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
12 changes: 12 additions & 0 deletions docs/docs/extend/plugins/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,15 @@ title: Schedule Mixin
## APICallMixin

The APICallMixin class provides basic functionality for integration with an external API.

### Sample Plugin

The following example demonstrates how to use the `APICallMixin` class to make a simple API call:

::: plugin.samples.integration.api_caller.SampleApiCallerPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
18 changes: 16 additions & 2 deletions docs/docs/extend/plugins/barcode.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Barcode Mixin
---

### Barcode Plugins
## Barcode Plugins

InvenTree supports decoding of arbitrary barcode data via a **Barcode Plugin** interface. Barcode data POSTed to the `/api/barcode/` endpoint will be supplied to all loaded barcode plugins, and the first plugin to successfully interpret the barcode data will return a response to the client.

Expand All @@ -24,7 +24,21 @@ POST {
}
```

### Example
### Builtin Plugin

The InvenTree server includes a builtin barcode plugin which can decode QR codes generated by the server. This plugin is enabled by default.

::: plugin.builtin.barcodes.inventree_barcode.InvenTreeInternalBarcodePlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []


### Example Plugin

Please find below a very simple example that is executed each time a barcode is scanned.

```python
Expand Down
19 changes: 18 additions & 1 deletion docs/docs/extend/plugins/currency.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,24 @@ title: Currency Exchange Mixin

The `CurrencyExchangeMixin` class enabled plugins to provide custom backends for updating currency exchange rate information.

Any implementing classes must provide the `update_exchange_rates` method. A simple example is shown below (with fake data).
Any implementing classes must provide the `update_exchange_rates` method.

### Builtin Plugin

The default builtin plugin for handling currency exchange rates is the `InvenTreeCurrencyExchangePlugin` class.

::: plugin.builtin.integration.currency_exchange.InvenTreeCurrencyExchange
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []


### Sample Plugin

A simple example is shown below (with fake data).

```python

Expand Down
56 changes: 17 additions & 39 deletions docs/docs/extend/plugins/event.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,56 +15,34 @@ When a certain (server-side) event occurs, the background worker passes the even
{% include 'img.html' %}
{% endwith %}

### Example (all events)
### Sample Plugin - All events

Implementing classes must at least provide a `process_event` function:

```python
class EventPlugin(EventMixin, InvenTreePlugin):
"""
A simple example plugin which responds to events on the InvenTree server.
::: plugin.samples.event.event_sample.EventPluginSample
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

This example simply prints out the event information.
A more complex plugin could respond to specific events however it wanted.
"""

NAME = "EventPlugin"
SLUG = "event"
TITLE = "Triggered Events"

def process_event(self, event, *args, **kwargs):
print(f"Processing triggered event: '{event}'")
```

### Example (specific events)
### 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.

```python
class EventPlugin(EventMixin, InvenTreePlugin):
"""
A simple example plugin which responds to 'salesordershipment.completed' event on the InvenTree server.
This example simply prints out the event information.
A more complex plugin can run enhanced logic on this event.
"""

NAME = "EventPlugin"
SLUG = "event"
TITLE = "Triggered Events"

def wants_process_event(self, event):
"""Here you can decide if this event should be send to `process_event` or not."""
return event == "salesordershipment.completed"
::: plugin.samples.event.filtered_event_sample.FilteredEventPluginSample
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

def process_event(self, event, *args, **kwargs):
"""Here you can run you'r specific logic."""
print(f"Sales order was completely shipped: '{args}' '{kwargs}'")
```

### Events
## Events

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

Expand Down
8 changes: 8 additions & 0 deletions docs/docs/extend/plugins/label.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ InvenTree supplies the `InvenTreeLabelPlugin` out of the box, which generates a

The default plugin also features a *DEBUG* mode which generates a raw HTML output, rather than PDF. This can be handy for tracking down any template rendering errors in your labels.

::: plugin.builtin.labels.inventree_label.InvenTreeLabelPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

### Available Data

The *label* data are supplied to the plugin in both `PDF` and `PNG` formats. This provides compatibility with a great range of label printers "out of the box". Conversion to other formats, if required, is left as an exercise for the plugin developer.
Expand Down
12 changes: 12 additions & 0 deletions docs/docs/extend/plugins/locate.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,15 @@ If a locate plugin is installed and activated, the [InvenTree mobile app](../../
### Implementation

Refer to the [InvenTree source code](https://github.com/inventree/InvenTree/blob/master/src/backend/InvenTree/plugin/samples/locate/locate_sample.py) for a simple implementation example.

### Sample Plugin

A simple example is provided in the InvenTree code base:

::: plugin.samples.locate.locate_sample.SampleLocatePlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
12 changes: 12 additions & 0 deletions docs/docs/extend/plugins/panel.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ Or to add a template file that will be rendered as javascript code, from the plu

Note : see convention for template directory above.

## Sample Plugin

A sample plugin is provided in the InvenTree code base:

::: plugin.samples.integration.custom_panel_sample.CustomPanelSample
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

## Example Implementations

Refer to the `CustomPanelSample` example class in the `./plugin/samples/integration/` directory, for a fully worked example of how custom UI panels can be implemented.
Expand Down
52 changes: 9 additions & 43 deletions docs/docs/extend/plugins/report.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,14 @@ A plugin which implements the ReportMixin mixin can define the `add_report_conte

Additionally the `add_label_context` method, allowing custom context data to be added to a label template at time of printing.

### Example
### Sample Plugin

A sample plugin which provides additional context data to the report templates can be found [in the InvenTree source code](https://github.com/inventree/InvenTree/blob/master/src/backend/InvenTree/plugin/samples/integration/report_plugin_sample.py):
A sample plugin which provides additional context data to the report templates is available:

```python
"""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 = "Sample 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, report_instance, model_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(report_instance, PurchaseOrderReport)

# We can also use the 'request' object to add extra context data
context['request_method'] = request.method
```
::: plugin.samples.integration.report_plugin_sample.SampleReportPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
47 changes: 8 additions & 39 deletions docs/docs/extend/plugins/schedule.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,14 @@ The ScheduleMixin class provides a plugin with the ability to call functions at
{% include 'img.html' %}
{% endwith %}

### Example
### SamplePlugin

An example of a plugin which supports scheduled tasks:

```python
class ScheduledTaskPlugin(ScheduleMixin, SettingsMixin, InvenTreePlugin):
"""
Sample plugin which runs a scheduled task, and provides user configuration.
"""

NAME = "Scheduled Tasks"
SLUG = 'schedule'

SCHEDULED_TASKS = {
'global': {
'func': 'some_module.function',
'schedule': 'H', # Run every hour
},
'member': {
'func': 'foo',
'schedule': 'I', # Minutes
'minutes': 15,
},
}

SETTINGS = {
'SECRET': {
'name': 'A secret',
'description': 'User configurable value',
},
}

def foo(self):
"""
This function runs every 15 minutes
"""
secret_value = self.get_setting('SECRET')
print(f"foo - SECRET = {secret_value})
```
!!! info "More Info"
For more information on any of the methods described below, refer to the InvenTree source code. [A working example is available as a starting point](https://github.com/inventree/InvenTree/blob/master/src/backend/InvenTree/plugin/samples/integration/scheduled_task.py).
::: plugin.samples.integration.scheduled_task.ScheduledTaskPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
2 changes: 1 addition & 1 deletion docs/docs/extend/plugins/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The dict must be formatted similar to the following sample that shows how to use

Take a look at the settings defined in `InvenTree.common.models.InvenTreeSetting` for all possible parameters.

### Example
### Example Plugin

Below is a simple example of how a plugin can implement settings:

Expand Down
14 changes: 13 additions & 1 deletion docs/docs/extend/plugins/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ To indicate a *field* validation error (i.e. the validation error applies only t

Note that an error can be which corresponds to multiple model instance fields.

### Example
### Example Plugin

Presented below is a simple working example for a plugin which implements the `validate_model_instance` method:

Expand Down Expand Up @@ -188,3 +188,15 @@ def increment_serial_number(self, serial: str):

return val
```

## Sample Plugin

A sample plugin which implements custom validation routines is provided in the InvenTree source code:

::: plugin.samples.integration.validation_sample.SampleValidatorPlugin
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []
2 changes: 1 addition & 1 deletion docs/docs/extend/themes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Navigate to the "Settings" page and click on the "Display" tab, you should see t
{% include 'img.html' %}
{% endwith %}

The drop-down list let's you select any other color theme found in your static folder (see next section to find out how to [add color themes](#add-color-themes)). Once selected, click on the "Apply Theme" button for the new color theme to be activated.
The drop-down list let's you select any other color theme found in your static folder (see next section to find out how to [add color themes](#add-color-theme)). Once selected, click on the "Apply Theme" button for the new color theme to be activated.

!!! info "Per-user Setting"
Color themes are "user specific" which means that changing the color theme in your own settings won't affect other users.
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/order/return_order.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ While [line items](#line-items) must reference a particular stock item, extra li

## Return Order Reports

Custom [reports](../report/return_order.md) can be generated against each Return Order.
Custom [reports](../report/templates.md) can be generated against each Return Order.

### Calendar view

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/releases/0.1.6.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Refer to the [report documentation](../report/report.md) for further information
!!! warning "LaTeX Support"
LaTeX report templates are no longer supported for a number of technical and ideological reasons

[#1292](https://github.com/inventree/InvenTree/pull/1292) adds support for build order / work order reports. Refer to the [build report documentation](../report/build.md) for further information.
[#1292](https://github.com/inventree/InvenTree/pull/1292) adds support for build order / work order reports. Refer to the [report documentation](../report/templates.md) for further information.

### Inherited BOM Items

Expand Down
Loading

0 comments on commit aa39582

Please sign in to comment.