mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-27 21:16:48 +00:00
Label printing fix (#489)
* Add check for modern label printing interface * Update getLabelTemplates * Fix typo * Refactor / simplify * Revert parameter type * Update version number and release notes * Refactor label printing function - Will require some cleanup in the future - Still needs testing * Fix for modern printing * Typo fix
This commit is contained in:
parent
91cb24c74c
commit
3c0bca276d
@ -1,3 +1,9 @@
|
||||
### 0.15.0 - May 2024
|
||||
---
|
||||
|
||||
- Support modern label printing API
|
||||
- Updated translations
|
||||
|
||||
### 0.14.3 - April 2024
|
||||
---
|
||||
|
||||
|
@ -345,6 +345,9 @@ class InvenTreeAPI {
|
||||
// Does the server support "active" status on Company and SupplierPart API endpoints?
|
||||
bool get supportsCompanyActiveStatus => isConnected() && apiVersion >= 189;
|
||||
|
||||
// Does the server support the "modern" (consolidated) label printing API?
|
||||
bool get supportsModenLabelPrinting => isConnected() && apiVersion >= 197;
|
||||
|
||||
// Cached list of plugins (refreshed when we connect to the server)
|
||||
List<InvenTreePlugin> _plugins = [];
|
||||
|
||||
|
@ -64,6 +64,9 @@ class InvenTreeModel {
|
||||
// Note: If the WEB_URL is the same (except for /api/) as URL then just leave blank
|
||||
String get WEB_URL => "";
|
||||
|
||||
// Return the "model type" of this model
|
||||
String get MODEL_TYPE => "";
|
||||
|
||||
// Helper function to set a value in the JSON data
|
||||
void setValue(String key, dynamic value) {
|
||||
jsondata[key] = value;
|
||||
|
@ -196,6 +196,9 @@ class InvenTreePart extends InvenTreeModel {
|
||||
@override
|
||||
String get URL => "part/";
|
||||
|
||||
@override
|
||||
String get MODEL_TYPE => "part";
|
||||
|
||||
@override
|
||||
List<String> get rolesRequired => ["part"];
|
||||
|
||||
|
@ -20,6 +20,9 @@ class InvenTreePurchaseOrder extends InvenTreeOrder {
|
||||
@override
|
||||
String get URL => "order/po/";
|
||||
|
||||
@override
|
||||
String get MODEL_TYPE => "purchaseorder";
|
||||
|
||||
@override
|
||||
List<String> get rolesRequired => ["purchase_order"];
|
||||
|
||||
|
@ -23,6 +23,9 @@ class InvenTreeSalesOrder extends InvenTreeOrder {
|
||||
@override
|
||||
String get URL => "order/so/";
|
||||
|
||||
@override
|
||||
String get MODEL_TYPE => "salesorder";
|
||||
|
||||
@override
|
||||
List<String> get rolesRequired => ["sales_order"];
|
||||
|
||||
|
@ -142,6 +142,9 @@ class InvenTreeStockItem extends InvenTreeModel {
|
||||
@override
|
||||
String get URL => "stock/";
|
||||
|
||||
@override
|
||||
String get MODEL_TYPE => "stockitem";
|
||||
|
||||
@override
|
||||
List<String> get rolesRequired => ["stock"];
|
||||
|
||||
@ -649,6 +652,9 @@ class InvenTreeStockLocation extends InvenTreeModel {
|
||||
@override
|
||||
String get URL => "stock/location/";
|
||||
|
||||
@override
|
||||
String get MODEL_TYPE => "stocklocation";
|
||||
|
||||
@override
|
||||
List<String> get rolesRequired => ["stock_location"];
|
||||
|
||||
|
175
lib/labels.dart
175
lib/labels.dart
@ -6,50 +6,18 @@ import "package:inventree/api_form.dart";
|
||||
import "package:inventree/l10.dart";
|
||||
import "package:inventree/widget/snacks.dart";
|
||||
|
||||
/*
|
||||
* Discover which label templates are available for a given item
|
||||
*/
|
||||
Future<List<Map<String, dynamic>>> getLabelTemplates(
|
||||
String labelType,
|
||||
Map<String, String> data,
|
||||
) async {
|
||||
|
||||
if (!InvenTreeAPI().isConnected() || !InvenTreeAPI().supportsMixin("labels")) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter by active plugins
|
||||
data["enabled"] = "true";
|
||||
|
||||
List<Map<String, dynamic>> labels = [];
|
||||
|
||||
await InvenTreeAPI().get(
|
||||
"/label/${labelType}/",
|
||||
params: data,
|
||||
).then((APIResponse response) {
|
||||
if (response.isValid() && response.statusCode == 200) {
|
||||
for (var label in response.resultsList()) {
|
||||
if (label is Map<String, dynamic>) {
|
||||
labels.add(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Select a particular label, from a provided list of options,
|
||||
* and print against the selected instances.
|
||||
*
|
||||
*/
|
||||
Future<void> selectAndPrintLabel(
|
||||
BuildContext context,
|
||||
List<Map<String, dynamic>> labels,
|
||||
String labelType,
|
||||
String labelQuery,
|
||||
) async {
|
||||
BuildContext context,
|
||||
List<Map<String, dynamic>> labels,
|
||||
int instanceId,
|
||||
String labelType,
|
||||
String labelQuery,
|
||||
) async {
|
||||
|
||||
if (!InvenTreeAPI().isConnected()) {
|
||||
return;
|
||||
@ -91,7 +59,7 @@ Future<void> selectAndPrintLabel(
|
||||
for (var plugin in plugins) {
|
||||
plugin_options.add({
|
||||
"display_name": plugin.humanName,
|
||||
"value": plugin.key
|
||||
"value": InvenTreeAPI().supportsModenLabelPrinting ? plugin.pk : plugin.key
|
||||
});
|
||||
}
|
||||
|
||||
@ -124,38 +92,113 @@ Future<void> selectAndPrintLabel(
|
||||
icon: FontAwesomeIcons.print,
|
||||
onSuccess: (Map<String, dynamic> data) async {
|
||||
int labelId = (data["label"] ?? -1) as int;
|
||||
String pluginKey = (data["plugin"] ?? "") as String;
|
||||
var pluginKey = data["plugin"];
|
||||
|
||||
if (labelId != -1 && pluginKey.isNotEmpty) {
|
||||
String url = "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}";
|
||||
bool result = false;
|
||||
|
||||
if (labelId != -1 && pluginKey != null) {
|
||||
|
||||
showLoadingOverlay(context);
|
||||
|
||||
InvenTreeAPI().get(url).then((APIResponse response) {
|
||||
hideLoadingOverlay();
|
||||
if (response.isValid() && response.statusCode == 200) {
|
||||
if (InvenTreeAPI().supportsModenLabelPrinting) {
|
||||
|
||||
var data = response.asMap();
|
||||
|
||||
if (data.containsKey("file")) {
|
||||
var label_file = (data["file"] ?? "") as String;
|
||||
|
||||
// Attempt to open remote file
|
||||
InvenTreeAPI().downloadFile(label_file);
|
||||
} else {
|
||||
showSnackIcon(
|
||||
L10().printLabelSuccess,
|
||||
success: true
|
||||
);
|
||||
// Modern label printing API uses a POST request to a single API endpoint.
|
||||
await InvenTreeAPI().post(
|
||||
"/label/print/",
|
||||
body: {
|
||||
"plugin": pluginKey,
|
||||
"template": labelId,
|
||||
"items": [instanceId]
|
||||
}
|
||||
).then((APIResponse response) {
|
||||
hideLoadingOverlay();
|
||||
|
||||
if (response.isValid() && response.statusCode >= 200 &&
|
||||
response.statusCode <= 201) {
|
||||
var data = response.asMap();
|
||||
|
||||
if (data.containsKey("output")) {
|
||||
var label_file = (data["output"] ?? "") as String;
|
||||
|
||||
// Attempt to open generated file
|
||||
InvenTreeAPI().downloadFile(label_file);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
showSnackIcon(
|
||||
L10().printLabelFailure,
|
||||
success: false,
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Legacy label printing API
|
||||
// Uses a GET request to a specially formed URL which depends on the parameters
|
||||
String url = "/label/${labelType}/${labelId}/print/?${labelQuery}&plugin=${pluginKey}";
|
||||
await InvenTreeAPI().get(url).then((APIResponse response) {
|
||||
hideLoadingOverlay();
|
||||
if (response.isValid() && response.statusCode == 200) {
|
||||
var data = response.asMap();
|
||||
if (data.containsKey("file")) {
|
||||
var label_file = (data["file"] ?? "") as String;
|
||||
|
||||
// Attempt to open remote file
|
||||
InvenTreeAPI().downloadFile(label_file);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (result) {
|
||||
showSnackIcon(
|
||||
L10().printLabelSuccess,
|
||||
success: true
|
||||
);
|
||||
} else {
|
||||
showSnackIcon(
|
||||
L10().printLabelFailure,
|
||||
success: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Discover which label templates are available for a given item
|
||||
*/
|
||||
Future<List<Map<String, dynamic>>> getLabelTemplates(
|
||||
String labelType,
|
||||
Map<String, String> data,
|
||||
) async {
|
||||
|
||||
if (!InvenTreeAPI().isConnected() || !InvenTreeAPI().supportsMixin("labels")) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter by active plugins
|
||||
data["enabled"] = "true";
|
||||
|
||||
String url = "/label/template/";
|
||||
|
||||
if (InvenTreeAPI().supportsModenLabelPrinting) {
|
||||
data["model_type"] = labelType;
|
||||
} else {
|
||||
// Legacy label printing API endpoint
|
||||
url = "/label/${labelType}/";
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> labels = [];
|
||||
|
||||
await InvenTreeAPI().get(
|
||||
url,
|
||||
params: data,
|
||||
).then((APIResponse response) {
|
||||
if (response.isValid() && response.statusCode == 200) {
|
||||
for (var label in response.resultsList()) {
|
||||
if (label is Map<String, dynamic>) {
|
||||
labels.add(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return labels;
|
||||
}
|
@ -194,7 +194,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
|
||||
tiles.add(
|
||||
ListTile(
|
||||
title: Text(L10().documentation),
|
||||
subtitle: Text("https://docs.inventree.org"),
|
||||
subtitle: Text("https://docs.inventree.org/app"),
|
||||
leading: FaIcon(FontAwesomeIcons.book, color: COLOR_ACTION),
|
||||
onTap: () {
|
||||
_openDocs();
|
||||
|
@ -129,6 +129,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
selectAndPrintLabel(
|
||||
context,
|
||||
labels,
|
||||
widget.part.pk,
|
||||
"part",
|
||||
"part=${widget.part.pk}"
|
||||
);
|
||||
@ -248,9 +249,16 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
allowLabelPrinting &= api.supportsMixin("labels");
|
||||
|
||||
if (allowLabelPrinting) {
|
||||
_labels = await getLabelTemplates("part", {
|
||||
"part": widget.part.pk.toString(),
|
||||
});
|
||||
|
||||
String model_type = api.supportsModenLabelPrinting ? InvenTreePart().MODEL_TYPE : "part";
|
||||
String item_key = api.supportsModenLabelPrinting ? "items" : "part";
|
||||
|
||||
_labels = await getLabelTemplates(
|
||||
model_type,
|
||||
{
|
||||
item_key: widget.part.pk.toString()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
|
@ -193,6 +193,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
selectAndPrintLabel(
|
||||
context,
|
||||
labels,
|
||||
widget.location!.pk,
|
||||
"location",
|
||||
"location=${widget.location!.pk}"
|
||||
);
|
||||
@ -247,9 +248,16 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
if (allowLabelPrinting) {
|
||||
|
||||
if (widget.location != null) {
|
||||
_labels = await getLabelTemplates("location", {
|
||||
"location": widget.location!.pk.toString()
|
||||
});
|
||||
|
||||
String model_type = api.supportsModenLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "location";
|
||||
String item_key = api.supportsModenLabelPrinting ? "items" : "location";
|
||||
|
||||
_labels = await getLabelTemplates(
|
||||
model_type,
|
||||
{
|
||||
item_key: widget.location!.pk.toString()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
selectAndPrintLabel(
|
||||
context,
|
||||
labels,
|
||||
widget.item.pk,
|
||||
"stock",
|
||||
"item=${widget.item.pk}"
|
||||
);
|
||||
@ -264,10 +265,17 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
|
||||
// Request information on labels available for this stock item
|
||||
if (allowLabelPrinting) {
|
||||
|
||||
String model_type = api.supportsModenLabelPrinting ? InvenTreeStockLocation().MODEL_TYPE : "stock";
|
||||
String item_key = api.supportsModenLabelPrinting ? "items" : "item";
|
||||
|
||||
// Clear the existing labels list
|
||||
_labels = await getLabelTemplates("stock", {
|
||||
"item": widget.item.pk.toString()
|
||||
});
|
||||
_labels = await getLabelTemplates(
|
||||
model_type,
|
||||
{
|
||||
item_key: widget.item.pk.toString()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
name: inventree
|
||||
description: InvenTree stock management
|
||||
|
||||
version: 0.14.3+81
|
||||
version: 0.15.0+82
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.5 <3.13.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user