mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Allow offloading of label printing to the configured plugin
This commit is contained in:
parent
f1f07a1977
commit
6c25a5805d
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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'>
|
||||||
|
Loading…
Reference in New Issue
Block a user