mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-30 04:26:44 +00:00
* 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>
188 lines
7.9 KiB
Markdown
188 lines
7.9 KiB
Markdown
---
|
|
title: Label Mixin
|
|
---
|
|
|
|
## LabelPrintingMixin
|
|
|
|
The `LabelPrintingMixin` class allows plugins to provide custom label printing functionality. The specific implementation of a label printing plugin is quite flexible, allowing for the following functions (as a starting point):
|
|
|
|
- Printing a single label to a file, and allowing user to download
|
|
- Combining multiple labels onto a single page
|
|
- Supporting proprietary label sheet formats
|
|
- Offloading label printing to an external printer
|
|
|
|
### Entry Point
|
|
|
|
When printing labels against a particular plugin, the entry point is the `print_labels` method. The default implementation of this method iterates over each of the provided items, renders a PDF, and calls the `print_label` method for each item, providing the rendered PDF data.
|
|
|
|
Both the `print_labels` and `print_label` methods may be overridden by a plugin, allowing for complex functionality to be achieved.
|
|
|
|
For example, the `print_labels` method could be reimplemented to merge all labels into a single larger page, and return a single page for printing.
|
|
|
|
### Return Type
|
|
|
|
The `print_labels` method *must* return a JsonResponse object. If the method does not return such a response, an error will be raised by the server.
|
|
|
|
### File Generation
|
|
|
|
If the label printing plugin generates a real file, it should be stored as a `LabelOutput` instance in the database, and returned in the JsonResponse result under the 'file' key.
|
|
|
|
For example, the built-in `InvenTreeLabelPlugin` plugin generates a PDF file which contains all the provided labels concatenated together. A snippet of the code is shown below (refer to the source code for full details):
|
|
|
|
```python
|
|
# Save the generated file to the database
|
|
output = LabelOutput.objects.create(
|
|
label=output_file,
|
|
user=request.user
|
|
)
|
|
|
|
return JsonResponse({
|
|
'file': output.label.url,
|
|
'success': True,
|
|
'message': f'{len(items)} labels generated'
|
|
})
|
|
```
|
|
|
|
### Background Printing
|
|
|
|
For some label printing processes (such as offloading printing to an external networked printer) it may be preferable to utilize the background worker process, and not block the front-end server.
|
|
The plugin provides an easy method to offload printing to the background thread.
|
|
|
|
Simply override the class attribute `BLOCKING_PRINT` as follows:
|
|
|
|
```python
|
|
class MyPrinterPlugin(LabelPrintingMixin, InvenTreePlugin):
|
|
BLOCKING_PRINT = False
|
|
```
|
|
|
|
If the `print_labels` method is not changed, this will run the `print_label` method in a background worker thread.
|
|
|
|
!!! info "Example Plugin"
|
|
Check out the [inventree-brother-plugin](https://github.com/inventree/inventree-brother-plugin) which provides native support for the Brother QL and PT series of networked label printers
|
|
|
|
!!! tip "Custom Code"
|
|
If your plugin overrides the `print_labels` method, you will have to ensure that the label printing is correctly offloaded to the background worker. Look at the `offload_label` method of the plugin mixin class for how this can be achieved.
|
|
|
|
### Printing options
|
|
|
|
A printing plugin can define custom options as a serializer class called `PrintingOptionsSerializer` that get shown on the printing screen and get passed to the `print_labels`/`print_label` function as a kwarg called `printing_options`. This can be used to e.g. let the user dynamically select the orientation of the label, the color mode, ... for each print job.
|
|
The following simple example shows how to implement an orientation select. For more information about how to define fields, refer to the django rest framework (DRF) [documentation](https://www.django-rest-framework.org/api-guide/fields/).
|
|
|
|
```py
|
|
from rest_framework import serializers
|
|
|
|
class MyLabelPrinter(LabelPrintingMixin, InvenTreePlugin):
|
|
...
|
|
|
|
class PrintingOptionsSerializer(serializers.Serializer):
|
|
orientation = serializers.ChoiceField(choices=[
|
|
("landscape", "Landscape"),
|
|
("portrait", "Portrait"),
|
|
])
|
|
|
|
def print_label(self, **kwargs):
|
|
print(kwargs["printing_options"]) # -> {"orientation": "landscape"}
|
|
...
|
|
```
|
|
|
|
!!! tip "Dynamically return a serializer instance"
|
|
If your plugin wants to dynamically expose options based on the request, you can implement the `get_printing_options_serializer` function which by default returns an instance
|
|
of the `PrintingOptionsSerializer` class if defined.
|
|
|
|
### Helper Methods
|
|
|
|
The plugin class provides a number of additional helper methods which may be useful for generating labels:
|
|
|
|
| Method | Description |
|
|
| --- | --- |
|
|
| render_to_pdf | Render label template to an in-memory PDF object |
|
|
| render_to_html | Render label template to a raw HTML string |
|
|
| render_to_png | Convert PDF data to an in-memory PNG image |
|
|
|
|
!!! info "Use the Source"
|
|
These methods are available for more complex implementations - refer to the source code for more information!
|
|
|
|
### Merging Labels
|
|
|
|
To merge (combine) multiple labels into a single output (for example printing multiple labels on a single sheet of paper), the plugin must override the `print_labels` method and implement the required functionality.
|
|
|
|
## Integration
|
|
|
|
### Web Integration
|
|
|
|
If label printing plugins are enabled, they are able to be used directly from the InvenTree web interface:
|
|
|
|
{% with id="label_print", url="plugin/print_label_select_plugin.png", description="Print label via plugin" %}
|
|
{% include 'img.html' %}
|
|
{% endwith %}
|
|
|
|
### App Integration
|
|
|
|
Label printing plugins also allow direct printing of labels via the [mobile app](../../app/stock.md#print-label)
|
|
|
|
## Implementation
|
|
|
|
Plugins which implement the `LabelPrintingMixin` mixin class can be implemented by simply providing a `print_label` method.
|
|
|
|
### Simple Example
|
|
|
|
```python
|
|
from dummy_printer import printer_backend
|
|
|
|
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!
|
|
"""
|
|
|
|
NAME = "MyLabelPrinter"
|
|
SLUG = "mylabel"
|
|
TITLE = "A dummy printer"
|
|
|
|
# Set BLOCKING_PRINT to false to return immediately
|
|
BLOCKING_PRINT = False
|
|
|
|
def print_label(self, **kwargs):
|
|
"""
|
|
Send the label to the printer
|
|
|
|
kwargs:
|
|
pdf_file: The PDF file object of the rendered label (WeasyTemplateResponse object)
|
|
pdf_data: Raw PDF data of the rendered label
|
|
filename: The filename of this PDF label
|
|
label_instance: The instance of the label model which triggered the print_label() method
|
|
item_instance: The instance of the database model against which the label is printed
|
|
user: The user who triggered this print job
|
|
width: The expected width of the label (in mm)
|
|
height: The expected height of the label (in mm)
|
|
printing_options: The printing options set for this print job defined in the PrintingOptionsSerializer
|
|
"""
|
|
|
|
width = kwargs['width']
|
|
height = kwargs['height']
|
|
|
|
# This dummy printer supports printing of raw image files
|
|
printer_backend.print(png_file, w=width, h=height)
|
|
```
|
|
|
|
### Default Plugin
|
|
|
|
InvenTree supplies the `InvenTreeLabelPlugin` out of the box, which generates a PDF file which is then available for immediate download by the user.
|
|
|
|
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.
|
|
|
|
Other arguments provided to the `print_label` function are documented in the code sample above.
|