Further barcode work

- Simplify InvenTree barcode format
- Create base-clas for plugin
This commit is contained in:
Oliver Walters 2020-04-14 21:30:43 +10:00
parent 70589b06e1
commit 4a615e05ae
9 changed files with 127 additions and 49 deletions

View File

@ -5,7 +5,9 @@ Main JSON interface views
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.http import JsonResponse
from rest_framework.response import Response
from rest_framework.views import APIView
@ -14,6 +16,11 @@ from .version import inventreeVersion, inventreeInstanceName
from plugins import plugins as inventree_plugins
# Load barcode plugins
print("INFO: Loading plugins")
barcode_plugins = inventree_plugins.load_barcode_plugins()
class InfoView(AjaxView):
""" Simple JSON endpoint for InvenTree information.
@ -45,19 +52,46 @@ class BarcodeScanView(APIView):
def post(self, request, *args, **kwargs):
data = {
'barcode': 'Hello world',
}
response = None
plugins = inventree_plugins.load_barcode_plugins()
barcode_data = request.data
for plugin in plugins:
print("Testing plugin:", plugin.PLUGIN_NAME)
if plugin().validate_barcode(request.data):
print("success!")
print("Barcode data:")
print(barcode_data)
return Response({
'success': 'OK',
'data': data,
'post': request.data,
})
if type(barcode_data) is not dict:
response = {
'error': _('Barcode data could not be parsed'),
}
else:
# Look for a barcode plugin that knows how to handle the data
for plugin_class in barcode_plugins:
plugin = plugin_class()
if plugin.validate_barcode(barcode_data):
# Plugin should return a dict response
response = plugin.decode_barcode(barcode_data)
if type(response) is dict:
response['success'] = _('Barcode successfully decoded')
else:
response = {
'error': _('Barcode plugin returned incorrect response')
}
response['plugin'] = plugin.get_name()
break
if response is None:
response = {
'error': _('Unknown barcode format'),
}
# Include the original barcode data
response['barcode_data'] = barcode_data
return Response(response)

View File

@ -172,7 +172,7 @@ def WrapWithQuotes(text, quote='"'):
return text
def MakeBarcode(object_type, object_id, object_url, data={}):
def MakeBarcode(object_name, object_data):
""" Generate a string for a barcode. Adds some global InvenTree parameters.
Args:
@ -185,13 +185,12 @@ def MakeBarcode(object_type, object_id, object_url, data={}):
json string of the supplied data plus some other data
"""
# Add in some generic InvenTree data
data['type'] = object_type
data['id'] = object_id
data['url'] = object_url
data['tool'] = 'InvenTree'
data['instance'] = inventreeInstanceName()
data['version'] = inventreeVersion()
data = {
'tool': 'InvenTree',
'version': inventreeVersion(),
'instance': inventreeInstanceName(),
object_name: object_data
}
return json.dumps(data, sort_keys=True)

View File

@ -113,15 +113,15 @@ class TestMakeBarcode(TestCase):
def test_barcode(self):
data = {
'animal': 'cat',
'legs': 3,
'noise': 'purr'
}
bc = helpers.MakeBarcode(
"part",
{
"id": 3,
"url": "www.google.com",
}
)
bc = helpers.MakeBarcode("part", 3, "www.google.com", data)
self.assertIn('animal', bc)
self.assertIn('part', bc)
self.assertIn('tool', bc)
self.assertIn('"tool": "InvenTree"', bc)

View File

@ -478,11 +478,11 @@ class Part(models.Model):
""" Return a JSON string for formatting a barcode for this Part object """
return helpers.MakeBarcode(
"Part",
self.id,
reverse('api-part-detail', kwargs={'pk': self.id}),
"part",
{
'name': self.name,
"id": self.id,
"name": self.full_name,
"url": reverse('api-part-detail', kwargs={'pk': self.id}),
}
)

View File

@ -1,19 +1,25 @@
# -*- coding: utf-8 -*-
import plugins.plugin as plugin
class BarcodePlugin:
class BarcodePlugin(plugin.InvenTreePlugin):
"""
The BarcodePlugin class is the base class for any barcode plugin.
"""
# Override this for each actual plugin
PLUGIN_NAME = ''
def validate_barcode(self, barcode_data):
"""
Default implementation returns False
"""
return False
def decode_barcode(self, barcode_data):
"""
Decode the barcode, and craft a response
"""
return None
def __init__(self):
pass
plugin.InvenTreePlugin.__init__(self)

View File

@ -8,7 +8,24 @@ class InvenTreeBarcodePlugin(barcode.BarcodePlugin):
PLUGIN_NAME = "InvenTreeBarcodePlugin"
def validate_barcode(self, barcode_data):
"""
An "InvenTree" barcode must include the following tags:
print("testing")
{
'tool': 'InvenTree',
'version': <anything>
}
"""
for key in ['tool', 'version']:
if key not in barcode_data.keys():
return False
if not barcode_data['tool'] == 'InvenTree':
return False
return True
def decode_barcode(self, barcode_data):
pass

View File

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
class InvenTreePlugin():
"""
Base class for a Barcode plugin
"""
# Override the plugin name for each concrete plugin instance
PLUGIN_NAME = ''
def get_name(self):
return self.PLUGIN_NAME
def __init__(self):
pass

View File

@ -52,4 +52,12 @@ def load_barcode_plugins():
Return a list of all registered barcode plugins
"""
return get_plugins(barcode, BarcodePlugin)
plugins = get_plugins(barcode, BarcodePlugin)
if len(plugins) > 0:
print("Discovered {n} barcode plugins:".format(n=len(plugins)))
for bp in plugins:
print(" - {bp}".format(bp=bp.PLUGIN_NAME))
return plugins

View File

@ -44,11 +44,11 @@ class StockLocation(InvenTreeTree):
""" Return a JSON string for formatting a barcode for this StockLocation object """
return helpers.MakeBarcode(
'StockLocation',
self.id,
reverse('api-location-detail', kwargs={'pk': self.id}),
'stocklocation',
{
'name': self.name,
"id": self.id,
"name": self.name,
"url": reverse('api-location-detail', kwargs={'pk': self.id}),
}
)
@ -288,12 +288,10 @@ class StockItem(MPTTModel):
"""
return helpers.MakeBarcode(
'StockItem',
self.id,
reverse('api-stock-detail', kwargs={'pk': self.id}),
"stockitem",
{
'part_id': self.part.id,
'part_name': self.part.full_name
"id": self.id,
"url": reverse('api-stock-detail', kwargs={'pk': self.id}),
}
)