Allow offloading of label printing to the configured plugin

This commit is contained in:
Oliver 2022-03-24 14:57:01 +11:00
parent f1f07a1977
commit 6c25a5805d
4 changed files with 111 additions and 28 deletions

View File

@ -1,12 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from io import BytesIO
from PIL import Image
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
from django.conf.urls import url, include from django.conf.urls import url, include
from django.core.exceptions import ValidationError, FieldError from django.core.exceptions import ValidationError, FieldError
from django.http import HttpResponse from django.http import HttpResponse, JsonResponse
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
@ -14,6 +17,7 @@ from rest_framework import generics, filters
from rest_framework.response import Response from rest_framework.response import Response
import InvenTree.helpers import InvenTree.helpers
from InvenTree.tasks import offload_task
import common.models import common.models
from plugin.registry import registry from plugin.registry import registry
@ -102,6 +106,8 @@ class LabelPrintMixin:
label_name = "label.pdf" label_name = "label.pdf"
label_names = []
# Merge one or more PDF files into a single download # Merge one or more PDF files into a single download
for item in items_to_print: for item in items_to_print:
label = self.get_object() label = self.get_object()
@ -109,6 +115,8 @@ class LabelPrintMixin:
label_name = label.generate_filename(request) label_name = label.generate_filename(request)
label_names.append(label_name)
if debug_mode: if debug_mode:
outputs.append(label.render_as_string(request)) outputs.append(label.render_as_string(request))
else: else:
@ -117,7 +125,46 @@ class LabelPrintMixin:
if not label_name.endswith(".pdf"): if not label_name.endswith(".pdf"):
label_name += ".pdf" label_name += ".pdf"
if debug_mode: if plugin is not None:
"""
Label printing is to be handled by a plugin,
rather than being exported to PDF.
In this case, we do the following:
- Individually generate each label, exporting as an image file
- Pass all the images through to the label printing plugin
- Return a JSON response indicating that the printing has been offloaded
"""
for output in outputs:
"""
For each output, we generate a temporary image file,
which will then get sent to the printer
"""
# Generate a png image at 300dpi
(img_data, w, h) = output.get_document().write_png(resolution=300)
# Construct a BytesIO object, which can be read by pillow
img_bytes = BytesIO(img_data)
image = Image.open(img_bytes)
# Offload a background task to print the provided label
offload_task(
'plugin.events.print_label',
plugin.plugin_slug(),
image
)
return JsonResponse({
'plugin': plugin.plugin_slug(),
'labels': label_names,
})
elif debug_mode:
""" """
Contatenate all rendered templates into a single HTML string, Contatenate all rendered templates into a single HTML string,
and return the string as a HTML response. and return the string as a HTML response.
@ -126,6 +173,7 @@ class LabelPrintMixin:
html = "\n".join(outputs) html = "\n".join(outputs)
return HttpResponse(html) return HttpResponse(html)
else: else:
""" """
Concatenate all rendered pages into a single PDF object, Concatenate all rendered pages into a single PDF object,

View File

@ -415,15 +415,6 @@ class LabelPrintingMixin:
def get_printer_name(self): def get_printer_name(self):
return self.PRINTER_NAME return self.PRINTER_NAME
def print_labels(self, labels, **kwargs):
"""
Print multiple labels.
Default implementation is to call print_label() for each label,
but it can be overridden if desired.
"""
for label in labels:
self.print_label(label, **kwargs)
def print_label(self, label, **kwargs): def print_label(self, label, **kwargs):
""" """
Callback to print a single label Callback to print a single label

View File

@ -95,7 +95,11 @@ def process_event(plugin_slug, event, *args, **kwargs):
logger.info(f"Plugin '{plugin_slug}' is processing triggered event '{event}'") logger.info(f"Plugin '{plugin_slug}' is processing triggered event '{event}'")
plugin = registry.plugins[plugin_slug] plugin = registry.plugins.get(plugin_slug, None)
if plugin is None:
logger.error(f"Could not find matching plugin for '{plugin_slug}'")
return
plugin.process_event(event, *args, **kwargs) plugin.process_event(event, *args, **kwargs)
@ -186,3 +190,25 @@ def after_delete(sender, instance, **kwargs):
model=sender.__name__, model=sender.__name__,
table=table, table=table,
) )
def print_label(plugin_slug, label_image, **kwargs):
"""
Print label with the provided plugin.
This task is nominally handled by the background worker.
Arguments:
plugin_slug: The unique slug (key) of the plugin
label_image: A PIL.Image image object to be printed
"""
logger.info(f"Plugin '{plugin_slug}' is printing a label")
plugin = registry.plugins.get(plugin_slug, None)
if plugin is None:
logger.error(f"Could not find matching plugin for '{plugin_slug}'")
return
plugin.print_label(label_image)

View File

@ -14,11 +14,41 @@
*/ */
/* exported /* exported
printLabels,
printPartLabels, printPartLabels,
printStockItemLabels, printStockItemLabels,
printStockLocationLabels, printStockLocationLabels,
*/ */
/*
* Perform the "print" action.
*/
function printLabels(url, plugin=null) {
if (plugin) {
// If a plugin is provided, do not redirect the browser.
// Instead, perform an API request and display a message
url = url + `plugin=${plugin}`;
inventreeGet(url, {}, {
success: function(response) {
showMessage(
'{% trans "Labels sent to printer" %}',
{
style: 'success',
}
);
}
});
} else {
window.location.href = url;
}
}
function printStockItemLabels(items) { function printStockItemLabels(items) {
/** /**
* Print stock item labels for the given stock items * Print stock item labels for the given stock items
@ -67,18 +97,15 @@ function printStockItemLabels(items) {
href += `items[]=${item}&`; href += `items[]=${item}&`;
}); });
if (data.plugin) { printLabels(href, data.plugin);
href += `plugin=${data.plugin}`; }
}
);
}
}
);
} }
window.location.href = href;
}
}
);
}
}
);
}
function printStockLocationLabels(locations) { function printStockLocationLabels(locations) {
@ -124,11 +151,7 @@ function printStockLocationLabels(locations) {
href += `locations[]=${location}&`; href += `locations[]=${location}&`;
}); });
if (data.plugin) { printLabels(href, data.plugin);
href += `plugin=${data.plugin}`;
}
window.location.href = href;
} }
} }
); );
@ -186,11 +209,7 @@ function printPartLabels(parts) {
url += `parts[]=${part}&`; url += `parts[]=${part}&`;
}); });
if (data.plugin) { printLabels(href, data.plugin);
href += `plugin=${data.plugin}`;
}
window.location.href = url;
} }
} }
); );
@ -234,7 +253,6 @@ function selectLabel(labels, items, options={}) {
var plugin_selection = ''; var plugin_selection = '';
if (plugins.length > 0) { if (plugins.length > 0) {
plugin_selection =` plugin_selection =`
<div class='form-group'> <div class='form-group'>