mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds an endpoint for calling the plugin code to "locate" something
This commit is contained in:
parent
9b7c26ec9c
commit
57f3efe758
@ -13,13 +13,18 @@ from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters
|
||||
|
||||
from rest_framework import permissions
|
||||
from rest_framework.exceptions import ParseError, NotFound
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from InvenTree.tasks import offload_task
|
||||
|
||||
from .views import AjaxView
|
||||
from .version import inventreeVersion, inventreeApiVersion, inventreeInstanceName
|
||||
from .status import is_worker_running
|
||||
|
||||
from stock.models import StockItem, StockLocation
|
||||
|
||||
from plugin import registry
|
||||
|
||||
|
||||
@ -114,7 +119,75 @@ class ActionPluginView(APIView):
|
||||
return Response(plugin.get_response())
|
||||
|
||||
# If we got to here, no matching action was found
|
||||
return Response({
|
||||
raise NotFound({
|
||||
'error': _("No matching action found"),
|
||||
"action": action,
|
||||
})
|
||||
|
||||
|
||||
class LocatePluginView(APIView):
|
||||
"""
|
||||
Endpoint for using a custom plugin to identify or 'locate' a stock item or location
|
||||
"""
|
||||
|
||||
permission_classes = [
|
||||
permissions.IsAuthenticated,
|
||||
]
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
# Which plugin to we wish to use?
|
||||
plugin = request.data.get('plugin', None)
|
||||
|
||||
if not plugin:
|
||||
raise ParseError("'plugin' field must be supplied")
|
||||
|
||||
# Check that the plugin exists, and supports the 'locate' mixin
|
||||
plugins = registry.with_mixin('locate')
|
||||
|
||||
if plugin not in [p.slug for p in plugins]:
|
||||
raise ParseError(f"Plugin '{plugin}' is not installed, or does not support the location mixin")
|
||||
|
||||
# StockItem to identify
|
||||
item_pk= request.data.get('item', None)
|
||||
|
||||
# StockLocation to identify
|
||||
location_pk = request.data.get('location', None)
|
||||
|
||||
if not item_pk and not location_pk:
|
||||
raise ParseError("Must supply either 'item' or 'location' parameter")
|
||||
|
||||
data = {
|
||||
"success": "Identification plugin activated",
|
||||
"plugin": plugin,
|
||||
}
|
||||
|
||||
# StockItem takes priority
|
||||
if item_pk:
|
||||
try:
|
||||
item = StockItem.objects.get(pk=item_pk)
|
||||
|
||||
offload_task('plugin.registry.call_function', plugin, 'locate_stock_item', item_pk)
|
||||
|
||||
data['item'] = item_pk
|
||||
|
||||
return Response(data)
|
||||
|
||||
except StockItem.DoesNotExist:
|
||||
raise NotFound("StockItem matching PK '{item}' not found")
|
||||
|
||||
elif location_pk:
|
||||
try:
|
||||
location = StockItem.objects.get(pk=location_pk)
|
||||
|
||||
offload_task('plugin.registry.call_function', plugin, 'locate_stock_location', location_pk)
|
||||
|
||||
data['location'] = location_pk
|
||||
|
||||
return Response(data)
|
||||
|
||||
except StockLocation.DoesNotExist:
|
||||
raise NotFound("StockLocation matching PK {'location'} not found")
|
||||
|
||||
else:
|
||||
raise NotFound()
|
||||
|
@ -45,7 +45,7 @@ from .views import DynamicJsView
|
||||
from .views import NotificationsView
|
||||
|
||||
from .api import InfoView, NotFoundView
|
||||
from .api import ActionPluginView
|
||||
from .api import ActionPluginView, LocatePluginView
|
||||
|
||||
from users.api import user_urls
|
||||
|
||||
@ -75,6 +75,7 @@ apipatterns += [
|
||||
|
||||
# Plugin endpoints
|
||||
re_path(r'^action/', ActionPluginView.as_view(), name='api-action-plugin'),
|
||||
re_path(r'^locate/', LocatePluginView.as_view(), name='api-locate-plugin'),
|
||||
|
||||
# Webhook enpoint
|
||||
path('', include(common_api_urls)),
|
||||
|
@ -473,6 +473,8 @@ class LocateMixin:
|
||||
Note: A custom implemenation could always change this behaviour
|
||||
"""
|
||||
|
||||
logger.info(f"LocateMixin: Attempting to locate StockItem pk={item_pk}")
|
||||
|
||||
from stock.models import StockItem
|
||||
|
||||
try:
|
||||
@ -482,6 +484,7 @@ class LocateMixin:
|
||||
self.locate_stock_location(item.location.pk)
|
||||
|
||||
except StockItem.DoesNotExist:
|
||||
logger.warning("LocateMixin: StockItem pk={item_pk} not found")
|
||||
pass
|
||||
|
||||
def locate_stock_location(self, location_pk):
|
||||
|
@ -520,6 +520,14 @@ $("#barcode-scan-into-location").click(function() {
|
||||
});
|
||||
});
|
||||
|
||||
{% if plugins_enabled %}
|
||||
$('#locate-item-button').click(function() {
|
||||
locateItemOrLocation({
|
||||
item: {{ item.pk }},
|
||||
});
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
function itemAdjust(action) {
|
||||
|
||||
inventreeGet(
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
/* exported
|
||||
installPlugin,
|
||||
locateItemOrLocation
|
||||
*/
|
||||
|
||||
function installPlugin() {
|
||||
@ -24,3 +25,50 @@ function installPlugin() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function locateItemOrLocation(options={}) {
|
||||
|
||||
if (!options.item && !options.location) {
|
||||
console.error("locateItemOrLocation: Either 'item' or 'location' must be provided!");
|
||||
return;
|
||||
}
|
||||
|
||||
function performLocate(plugin) {
|
||||
inventreePut(
|
||||
'{% url "api-locate-plugin" %}',
|
||||
{
|
||||
plugin: plugin,
|
||||
item: options.item,
|
||||
location: options.location,
|
||||
},
|
||||
{
|
||||
method: 'POST',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Request the list of available 'locate' plugins
|
||||
inventreeGet(
|
||||
'{% url "api-plugin-list" %}',
|
||||
{
|
||||
mixin: 'locate',
|
||||
},
|
||||
{
|
||||
success: function(plugins) {
|
||||
// No 'locate' plugins are available!
|
||||
if (plugins.length == 0) {
|
||||
console.warn("No 'locate' plugins are available");
|
||||
} else if (plugins.length == 1) {
|
||||
// Only a single locate plugin is available
|
||||
performLocate(plugins[0].key);
|
||||
} else {
|
||||
// More than 1 location plugin available
|
||||
// Select from a list
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user