mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 13:36:50 +00:00
Merge pull request #124 from inventree/identify
Adds support for "locate" plugin
This commit is contained in:
commit
e8bb56ef3f
@ -7,6 +7,7 @@
|
|||||||
- Refactor home screen display
|
- Refactor home screen display
|
||||||
- Display unread notifications on home screen
|
- Display unread notifications on home screen
|
||||||
- Fixes duplicated display of units when showing stock quantity
|
- 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
|
- Improve rendering of home screen when server is not connected
|
||||||
- Adds ability to load global and user settings from the server
|
- Adds ability to load global and user settings from the server
|
||||||
|
|
||||||
|
78
lib/api.dart
78
lib/api.dart
@ -22,6 +22,8 @@ import "package:inventree/user_profile.dart";
|
|||||||
import "package:inventree/widget/snacks.dart";
|
import "package:inventree/widget/snacks.dart";
|
||||||
import "package:path_provider/path_provider.dart";
|
import "package:path_provider/path_provider.dart";
|
||||||
|
|
||||||
|
import "package:inventree/api_form.dart";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class representing an API response from the server
|
* 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -416,6 +416,9 @@
|
|||||||
"keywords": "Keywords",
|
"keywords": "Keywords",
|
||||||
"@keywords": {},
|
"@keywords": {},
|
||||||
|
|
||||||
|
"labelTemplate": "Label Template",
|
||||||
|
"@labelTemplate": {},
|
||||||
|
|
||||||
"lastStocktake": "Last Stocktake",
|
"lastStocktake": "Last Stocktake",
|
||||||
"@lastStocktake": {},
|
"@lastStocktake": {},
|
||||||
|
|
||||||
@ -428,6 +431,12 @@
|
|||||||
"lineItems": "Line Items",
|
"lineItems": "Line Items",
|
||||||
"@lineItems": {},
|
"@lineItems": {},
|
||||||
|
|
||||||
|
"locateItem": "Locate stock item",
|
||||||
|
"@locateItem": {},
|
||||||
|
|
||||||
|
"locateLocation": "Locate stock location",
|
||||||
|
"@locateLocation": {},
|
||||||
|
|
||||||
"locationCreate": "New Location",
|
"locationCreate": "New Location",
|
||||||
"@locationCreate": {},
|
"@locationCreate": {},
|
||||||
|
|
||||||
@ -575,6 +584,18 @@
|
|||||||
"printLabel": "Print Label",
|
"printLabel": "Print Label",
|
||||||
"@printLabel": {},
|
"@printLabel": {},
|
||||||
|
|
||||||
|
"plugin": "Plugin",
|
||||||
|
"@plugin": {},
|
||||||
|
|
||||||
|
"pluginPrinter": "Printer",
|
||||||
|
"@pluginPrinter": {},
|
||||||
|
|
||||||
|
"pluginSupport": "Plugin Support Enabled",
|
||||||
|
"@pluginSupport": {},
|
||||||
|
|
||||||
|
"pluginSupportDetail": "The server supports custom plugins",
|
||||||
|
"@pluginSupportDetail": {},
|
||||||
|
|
||||||
"printLabelFailure": "Label printing failed",
|
"printLabelFailure": "Label printing failed",
|
||||||
"@printLabelFailure": {},
|
"@printLabelFailure": {},
|
||||||
|
|
||||||
@ -692,6 +713,9 @@
|
|||||||
"request": "Request",
|
"request": "Request",
|
||||||
"@request": {},
|
"@request": {},
|
||||||
|
|
||||||
|
"requestSuccessful": "Request successful",
|
||||||
|
"@requestSuccessful": {},
|
||||||
|
|
||||||
"requestingData": "Requesting Data",
|
"requestingData": "Requesting Data",
|
||||||
"@requestingData": {},
|
"@requestingData": {},
|
||||||
|
|
||||||
|
@ -102,6 +102,18 @@ class InvenTreeAboutWidget extends StatelessWidget {
|
|||||||
leading: FaIcon(FontAwesomeIcons.server),
|
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 {
|
} else {
|
||||||
tiles.add(
|
tiles.add(
|
||||||
ListTile(
|
ListTile(
|
||||||
|
@ -61,7 +61,23 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
|||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((location != null) && (InvenTreeAPI().checkPermission("stock_location", "change"))) {
|
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(
|
actions.add(
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: FaIcon(FontAwesomeIcons.edit),
|
icon: FaIcon(FontAwesomeIcons.edit),
|
||||||
@ -70,10 +86,26 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return actions;
|
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) {
|
void _editLocationDialog(BuildContext context) {
|
||||||
|
|
||||||
final _loc = location;
|
final _loc = location;
|
||||||
|
@ -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")) {
|
if (InvenTreeAPI().checkPermission("stock", "change")) {
|
||||||
actions.add(
|
actions.add(
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -217,14 +229,14 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
|||||||
|
|
||||||
Map<String, dynamic> fields = {
|
Map<String, dynamic> fields = {
|
||||||
"label": {
|
"label": {
|
||||||
"label": "Label Template",
|
"label": L10().labelTemplate,
|
||||||
"type": "choice",
|
"type": "choice",
|
||||||
"value": initial_label,
|
"value": initial_label,
|
||||||
"choices": label_options,
|
"choices": label_options,
|
||||||
"required": true,
|
"required": true,
|
||||||
},
|
},
|
||||||
"plugin": {
|
"plugin": {
|
||||||
"label": "Printer",
|
"label": L10().pluginPrinter,
|
||||||
"type": "choice",
|
"type": "choice",
|
||||||
"value": initial_plugin,
|
"value": initial_plugin,
|
||||||
"choices": plugin_options,
|
"choices": plugin_options,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user