2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-18 13:05:42 +00:00

Printing options (#5786)

* Added backend changes to support printing options

* Pass printing options seperatly via kwargs for easier api refactor later

* Implemented printing options in CUI

* Fix js linting

* Use translations for printing dialog

* Added docs

* Remove plugin and template fields from send printing options

* Fix docs

* Added tests

* Fix tests

* Fix options response and added test for it

* Fix tests

* Bump api version

* Update docs

* Apply suggestions from code review

* Fix api change date
This commit is contained in:
Lukas
2023-11-01 14:39:19 +01:00
committed by GitHub
parent 59f17a9885
commit a11418398f
10 changed files with 303 additions and 180 deletions

View File

@ -32,6 +32,7 @@
setFormGroupVisibility,
showFormInput,
selectImportFields,
updateForm,
*/
/**
@ -306,6 +307,7 @@ function constructDeleteForm(fields, options) {
* - hidden: Set to true to hide the field
* - icon: font-awesome icon to display before the field
* - prefix: Custom HTML prefix to display before the field
* - localOnly: If true, this field will only be rendered, but not send to the server
* - data: map of data to fill out field values with
* - focus: Name of field to focus on when modal is displayed
* - preventClose: Set to true to prevent form from closing on success
@ -315,6 +317,7 @@ function constructDeleteForm(fields, options) {
* - reload: Set to true to reload the current page after form success
* - confirm: Set to true to require a "confirm" button
* - confirmText: Text for confirm button (default = "Confirm")
* - disableSuccessMessage: Set to true to suppress the success message if the response contains a success key by accident
*
*/
function constructForm(url, options={}) {
@ -720,6 +723,21 @@ function constructFormBody(fields, options) {
});
}
/**
* This Method updates an existing form by replacing all form fields with the new ones
* @param {*} options new form definition options
*/
function updateForm(options) {
// merge already entered values in the newly constructed form
options.data = extractFormData(options.fields, options);
// remove old submit handlers
$(options.modal).off('click', '#modal-form-submit');
// construct new form
constructFormBody(options.fields, options);
}
// Add a "confirm" checkbox to the modal
// The "submit" button will be disabled unless "confirm" is checked
@ -841,6 +859,7 @@ function submitFormData(fields, options) {
// Ignore visual fields
if (field && field.type == 'candy') continue;
if (field && field.localOnly === true) continue;
if (field) {
@ -1190,7 +1209,7 @@ function handleFormSuccess(response, options) {
}
// Display any messages
if (response && (response.success || options.successMessage)) {
if (!options.disableSuccessMessage && response && (response.success || options.successMessage)) {
showAlertOrCache(
response.success || options.successMessage,
cache,

View File

@ -4,6 +4,8 @@
/* globals
attachSelect,
closeModal,
constructForm,
getFormFieldValue,
inventreeGet,
makeOptionsList,
modalEnable,
@ -13,7 +15,9 @@
modalSubmit,
openModal,
showAlertDialog,
showApiError,
showMessage,
updateForm,
user_settings,
*/
@ -21,137 +25,11 @@
printLabels,
*/
/**
* Present the user with the available labels,
* and allow them to select which label to print.
*
* The intent is that the available labels have been requested
* (via AJAX) from the server.
*/
function selectLabel(labels, items, options={}) {
// Array of available plugins for label printing
var plugins = [];
// Request a list of available label printing plugins from the server
inventreeGet(
`/api/plugins/`,
{
mixin: 'labels',
},
{
async: false,
success: function(response) {
plugins = response;
}
}
);
var plugin_selection = '';
if (plugins.length > 0) {
plugin_selection =`
<div class='form-group'>
<label class='control-label requiredField' for='id_plugin'>
{% trans "Select Printer" %}
</label>
<div class='controls'>
<select id='id_plugin' class='select form-control' name='plugin'>
`;
plugins.forEach(function(plugin) {
var selected = '';
if (user_settings['LABEL_DEFAULT_PRINTER'] == plugin.key) {
selected = ' selected';
}
plugin_selection += `<option value='${plugin.key}' title='${plugin.meta.human_name}'${selected}>${plugin.name} - <small>${plugin.meta.human_name}</small></option>`;
});
plugin_selection += `
</select>
</div>
</div>
`;
}
var modal = options.modal || '#modal-form';
var label_list = makeOptionsList(
labels,
function(item) {
var text = item.name;
if (item.description) {
text += ` - ${item.description}`;
}
return text;
},
function(item) {
return item.pk;
},
null,
function(item) {
if (options.key == 'part')
return item.pk == user_settings.DEFAULT_PART_LABEL_TEMPLATE;
else if (options.key == 'location')
return item.pk == user_settings.DEFAULT_LOCATION_LABEL_TEMPLATE;
else if (options.key == 'item')
return item.pk == user_settings.DEFAULT_ITEM_LABEL_TEMPLATE;
return '';
}
);
// Construct form
var html = '';
if (items.length > 0) {
let item_name = items.length == 1 ? options.singular_name : options.plural_name;
html += `
<div class='alert alert-block alert-info'>
${items.length} ${item_name} {% trans "selected" %}
</div>`;
}
html += `
<form method='post' action='' class='js-modal-form' enctype='multipart/form-data'>
<div class='form-group'>
<label class='control-label requiredField' for='id_label'>
{% trans "Select Label Template" %}
</label>
<div class='controls'>
<select id='id_label' class='select form-control' name='label'>
${label_list}
</select>
</div>
</div>
${plugin_selection}
</form>`;
openModal({
modal: modal,
});
modalEnable(modal, true);
modalShowSubmitButton(modal, true);
modalSetTitle(modal, '{% trans "Select Label Template" %}');
modalSetContent(modal, html);
attachSelect(modal);
modalSubmit(modal, function() {
var label = $(modal).find('#id_label').val();
var plugin = $(modal).find('#id_plugin').val();
closeModal(modal);
if (options.success) {
options.success({
// Return the selected label template and plugin
label: label,
plugin: plugin,
});
}
});
const defaultLabelTemplates = {
part: user_settings.DEFAULT_PART_LABEL_TEMPLATE,
location: user_settings.DEFAULT_LOCATION_LABEL_TEMPLATE,
item: user_settings.DEFAULT_ITEM_LABEL_TEMPLATE,
line: user_settings.DEFAULT_LINE_LABEL_TEMPLATE,
}
@ -166,6 +44,7 @@ function selectLabel(labels, items, options={}) {
* - url: The list URL for the particular template type
* - items: The list of items to be printed
* - key: The key to use in the query parameters
* - plural_name: The plural name of the item type
*/
function printLabels(options) {
@ -183,9 +62,11 @@ function printLabels(options) {
params[options.key] = options.items;
// Request a list of available label templates
// Request a list of available label templates from the server
let labelTemplates = [];
inventreeGet(options.url, params, {
success: function(response) {
async: false,
success: function (response) {
if (response.length == 0) {
showAlertDialog(
'{% trans "No Labels Found" %}',
@ -194,34 +75,121 @@ function printLabels(options) {
return;
}
// Select label template for printing
selectLabel(response, options.items, {
success: function(data) {
let href = `${options.url}${data.label}/print/?`;
options.items.forEach(function(item) {
href += `${options.key}=${item}&`;
});
href += `plugin=${data.plugin}`;
inventreeGet(href, {}, {
success: function(response) {
if (response.file) {
// Download the generated file
window.open(response.file);
} else {
showMessage('{% trans "Labels sent to printer" %}', {
style: 'success',
});
}
}
});
},
plural_name: options.plural_name,
singular_name: options.singular_name,
key: options.key,
});
labelTemplates = response;
}
});
// Request a list of available label printing plugins from the server
let plugins = [];
inventreeGet(`/api/plugins/`, { mixin: 'labels' }, {
async: false,
success: function (response) {
plugins = response;
}
});
let header_html = "";
// show how much items are selected if there is more than one item selected
if (options.items.length > 1) {
header_html += `
<div class='alert alert-block alert-info'>
${options.items.length} ${options.plural_name} {% trans "selected" %}
</div>
`;
}
const updateFormUrl = (formOptions) => {
const plugin = getFormFieldValue("_plugin", formOptions.fields._plugin, formOptions);
const labelTemplate = getFormFieldValue("_label_template", formOptions.fields._label_template, formOptions);
const params = $.param({ plugin, [options.key]: options.items })
formOptions.url = `${options.url}${labelTemplate ?? "1"}/print/?${params}`;
}
const updatePrintingOptions = (formOptions) => {
let printingOptionsRes = null;
$.ajax({
url: formOptions.url,
type: "OPTIONS",
contentType: "application/json",
dataType: "json",
accepts: { json: "application/json" },
async: false,
success: (res) => { printingOptionsRes = res },
error: (xhr) => showApiError(xhr, formOptions.url)
});
const printingOptions = printingOptionsRes.actions.POST || {};
// clear all other options
formOptions.fields = {
_label_template: formOptions.fields._label_template,
_plugin: formOptions.fields._plugin,
}
if (Object.keys(printingOptions).length > 0) {
formOptions.fields = {
...formOptions.fields,
divider: { type: "candy", html: `<hr/><h5>{% trans "Printing Options" %}</h5>` },
...printingOptions,
};
}
// update form
updateForm(formOptions);
}
const printingFormOptions = {
title: options.items.length === 1 ? `{% trans "Print label" %}` : `{% trans "Print labels" %}`,
submitText: `{% trans "Print" %}`,
method: "POST",
disableSuccessMessage: true,
header_html,
fields: {
_label_template: {
label: `{% trans "Select label template" %}`,
type: "choice",
localOnly: true,
value: defaultLabelTemplates[options.key],
choices: labelTemplates.map(t => ({
value: t.pk,
display_name: `${t.name} - <small>${t.description}</small>`,
})),
onEdit: (_value, _name, _field, formOptions) => {
updateFormUrl(formOptions);
}
},
_plugin: {
label: `{% trans "Select plugin" %}`,
type: "choice",
localOnly: true,
value: user_settings.LABEL_DEFAULT_PRINTER || plugins[0].key,
choices: plugins.map(p => ({
value: p.key,
display_name: `${p.name} - <small>${p.meta.human_name}</small>`,
})),
onEdit: (_value, _name, _field, formOptions) => {
updateFormUrl(formOptions);
updatePrintingOptions(formOptions);
}
},
},
onSuccess: (response) => {
if (response.file) {
// Download the generated file
window.open(response.file);
} else {
showMessage('{% trans "Labels sent to printer" %}', {
style: 'success',
});
}
}
};
// construct form
constructForm(null, printingFormOptions);
// fetch the options for the default plugin
updateFormUrl(printingFormOptions);
updatePrintingOptions(printingFormOptions);
}