2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 05:26:47 +00:00

Merge pull request #124 from inventree/identify

Adds support for "locate" plugin
This commit is contained in:
Oliver 2022-05-10 08:28:27 +10:00 committed by GitHub
commit e8bb56ef3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 169 additions and 10 deletions

View File

@ -7,6 +7,7 @@
- Refactor home screen display
- Display unread notifications on home screen
- Fixes duplicated display of units when showing stock quantity
- Adds ability to locate / identify stock items or locations (requires server plugin)
- Improve rendering of home screen when server is not connected
- Adds ability to load global and user settings from the server

View File

@ -22,6 +22,8 @@ import "package:inventree/user_profile.dart";
import "package:inventree/widget/snacks.dart";
import "package:path_provider/path_provider.dart";
import "package:inventree/api_form.dart";
/*
* Class representing an API response from the server
@ -1200,4 +1202,80 @@ class InvenTreeAPI {
}
}
/*
* Send a request to the server to locate / identify either a StockItem or StockLocation
*/
Future<void> locateItemOrLocation(BuildContext context, {int? item, int? location}) async {
var plugins = getPlugins(mixin: "locate");
print("locateItemOrLocation");
if (plugins.isEmpty) {
// TODO: Error message
return;
}
String plugin_name = "";
if (plugins.length == 1) {
plugin_name = plugins.first.key;
} else {
// User selects which plugin to use
List<Map<String, dynamic>> plugin_options = [];
for (var plugin in plugins) {
plugin_options.add({
"display_name": plugin.humanName,
"value": plugin.key,
});
}
Map<String, dynamic> fields = {
"plugin": {
"label": L10().plugin,
"type": "choice",
"value": plugins.first.key,
"choices": plugin_options,
"required": true,
}
};
await launchApiForm(
context,
L10().locateLocation,
"",
fields,
icon: FontAwesomeIcons.searchLocation,
onSuccess: (Map<String, dynamic> data) async {
plugin_name = (data["plugin"] ?? "") as String;
}
);
}
Map<String, dynamic> body = {
"plugin": plugin_name,
};
if (item != null) {
body["item"] = item.toString();
}
if (location != null) {
body["location"] = location.toString();
}
post(
"/api/locate/",
body: body,
expectedStatusCode: 200,
).then((APIResponse response) {
if (response.successful()) {
showSnackIcon(
L10().requestSuccessful,
success: true,
);
}
});
}
}

View File

@ -416,6 +416,9 @@
"keywords": "Keywords",
"@keywords": {},
"labelTemplate": "Label Template",
"@labelTemplate": {},
"lastStocktake": "Last Stocktake",
"@lastStocktake": {},
@ -428,6 +431,12 @@
"lineItems": "Line Items",
"@lineItems": {},
"locateItem": "Locate stock item",
"@locateItem": {},
"locateLocation": "Locate stock location",
"@locateLocation": {},
"locationCreate": "New Location",
"@locationCreate": {},
@ -575,6 +584,18 @@
"printLabel": "Print Label",
"@printLabel": {},
"plugin": "Plugin",
"@plugin": {},
"pluginPrinter": "Printer",
"@pluginPrinter": {},
"pluginSupport": "Plugin Support Enabled",
"@pluginSupport": {},
"pluginSupportDetail": "The server supports custom plugins",
"@pluginSupportDetail": {},
"printLabelFailure": "Label printing failed",
"@printLabelFailure": {},
@ -692,6 +713,9 @@
"request": "Request",
"@request": {},
"requestSuccessful": "Request successful",
"@requestSuccessful": {},
"requestingData": "Requesting Data",
"@requestingData": {},

View File

@ -102,6 +102,18 @@ class InvenTreeAboutWidget extends StatelessWidget {
leading: FaIcon(FontAwesomeIcons.server),
)
);
// Display extra tile if the server supports plugins
if (InvenTreeAPI().pluginsEnabled()) {
tiles.add(
ListTile(
title: Text(L10().pluginSupport),
subtitle: Text(L10().pluginSupportDetail),
leading: FaIcon(FontAwesomeIcons.plug),
)
);
}
} else {
tiles.add(
ListTile(

View File

@ -61,19 +61,51 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
);
*/
if ((location != null) && (InvenTreeAPI().checkPermission("stock_location", "change"))) {
actions.add(
IconButton(
icon: FaIcon(FontAwesomeIcons.edit),
tooltip: L10().edit,
onPressed: () { _editLocationDialog(context); },
)
);
if (location != null) {
// Add "locate" button
if (InvenTreeAPI().supportsMixin("locate")) {
actions.add(
IconButton(
icon: FaIcon(FontAwesomeIcons.searchLocation),
tooltip: L10().locateLocation,
onPressed: () async {
_locateStockLocation(context);
},
)
);
}
// Add "edit" button
if (InvenTreeAPI().checkPermission("stock_location", "change")) {
actions.add(
IconButton(
icon: FaIcon(FontAwesomeIcons.edit),
tooltip: L10().edit,
onPressed: () { _editLocationDialog(context); },
)
);
}
}
return actions;
}
/*
* Request identification of this location
*/
Future<void> _locateStockLocation(BuildContext context) async {
final _loc = location;
if (_loc != null) {
InvenTreeAPI().locateItemOrLocation(context, location: _loc.pk);
}
}
/*
* Launch a dialog form to edit this stock location
*/
void _editLocationDialog(BuildContext context) {
final _loc = location;

View File

@ -67,6 +67,18 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
);
}
if (InvenTreeAPI().supportsMixin("locate")) {
actions.add(
IconButton(
icon: FaIcon(FontAwesomeIcons.searchLocation),
tooltip: L10().locateItem,
onPressed: () async {
InvenTreeAPI().locateItemOrLocation(context, item: item.pk);
},
)
);
}
if (InvenTreeAPI().checkPermission("stock", "change")) {
actions.add(
IconButton(
@ -217,14 +229,14 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
Map<String, dynamic> fields = {
"label": {
"label": "Label Template",
"label": L10().labelTemplate,
"type": "choice",
"value": initial_label,
"choices": label_options,
"required": true,
},
"plugin": {
"label": "Printer",
"label": L10().pluginPrinter,
"type": "choice",
"value": initial_plugin,
"choices": plugin_options,