mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-01 03:00:54 +00:00
move barcodes to plugin
This commit is contained in:
144
InvenTree/plugin/builtin/barcodes/inventree_barcode.py
Normal file
144
InvenTree/plugin/builtin/barcodes/inventree_barcode.py
Normal file
@ -0,0 +1,144 @@
|
||||
"""
|
||||
The InvenTreeBarcodePlugin validates barcodes generated by InvenTree itself.
|
||||
It can be used as a template for developing third-party barcode plugins.
|
||||
|
||||
The data format is very simple, and maps directly to database objects,
|
||||
via the "id" parameter.
|
||||
|
||||
Parsing an InvenTree barcode simply involves validating that the
|
||||
references model objects actually exist in the database.
|
||||
"""
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
|
||||
import plugin.integration
|
||||
from .mixins import BarcodeMixin
|
||||
|
||||
from stock.models import StockItem, StockLocation
|
||||
from part.models import Part
|
||||
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
|
||||
class InvenTreeBarcodePlugin(BarcodeMixin, plugin.integration.IntegrationPluginBase):
|
||||
|
||||
PLUGIN_NAME = "InvenTreeBarcode"
|
||||
|
||||
def validate(self):
|
||||
"""
|
||||
An "InvenTree" barcode must be a jsonnable-dict with the following tags:
|
||||
|
||||
{
|
||||
'tool': 'InvenTree',
|
||||
'version': <anything>
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
# The data must either be dict or be able to dictified
|
||||
if type(self.data) is dict:
|
||||
pass
|
||||
elif type(self.data) is str:
|
||||
try:
|
||||
self.data = json.loads(self.data)
|
||||
if type(self.data) is not dict:
|
||||
return False
|
||||
except json.JSONDecodeError:
|
||||
return False
|
||||
else:
|
||||
return False # pragma: no cover
|
||||
|
||||
# If any of the following keys are in the JSON data,
|
||||
# let's go ahead and assume that the code is a valid InvenTree one...
|
||||
|
||||
for key in ['tool', 'version', 'InvenTree', 'stockitem', 'stocklocation', 'part']:
|
||||
if key in self.data.keys():
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def getStockItem(self):
|
||||
|
||||
for k in self.data.keys():
|
||||
if k.lower() == 'stockitem':
|
||||
|
||||
data = self.data[k]
|
||||
|
||||
pk = None
|
||||
|
||||
# Initially try casting to an integer
|
||||
try:
|
||||
pk = int(data)
|
||||
except (TypeError, ValueError): # pragma: no cover
|
||||
pk = None
|
||||
|
||||
if pk is None: # pragma: no cover
|
||||
try:
|
||||
pk = self.data[k]['id']
|
||||
except (AttributeError, KeyError):
|
||||
raise ValidationError({k: "id parameter not supplied"})
|
||||
|
||||
try:
|
||||
item = StockItem.objects.get(pk=pk)
|
||||
return item
|
||||
except (ValueError, StockItem.DoesNotExist): # pragma: no cover
|
||||
raise ValidationError({k, "Stock item does not exist"})
|
||||
|
||||
return None
|
||||
|
||||
def getStockLocation(self):
|
||||
|
||||
for k in self.data.keys():
|
||||
if k.lower() == 'stocklocation':
|
||||
|
||||
pk = None
|
||||
|
||||
# First try simple integer lookup
|
||||
try:
|
||||
pk = int(self.data[k])
|
||||
except (TypeError, ValueError): # pragma: no cover
|
||||
pk = None
|
||||
|
||||
if pk is None: # pragma: no cover
|
||||
# Lookup by 'id' field
|
||||
try:
|
||||
pk = self.data[k]['id']
|
||||
except (AttributeError, KeyError):
|
||||
raise ValidationError({k: "id parameter not supplied"})
|
||||
|
||||
try:
|
||||
loc = StockLocation.objects.get(pk=pk)
|
||||
return loc
|
||||
except (ValueError, StockLocation.DoesNotExist): # pragma: no cover
|
||||
raise ValidationError({k, "Stock location does not exist"})
|
||||
|
||||
return None
|
||||
|
||||
def getPart(self):
|
||||
|
||||
for k in self.data.keys():
|
||||
if k.lower() == 'part':
|
||||
|
||||
pk = None
|
||||
|
||||
# Try integer lookup first
|
||||
try:
|
||||
pk = int(self.data[k])
|
||||
except (TypeError, ValueError): # pragma: no cover
|
||||
pk = None
|
||||
|
||||
if pk is None: # pragma: no cover
|
||||
try:
|
||||
pk = self.data[k]['id']
|
||||
except (AttributeError, KeyError):
|
||||
raise ValidationError({k, 'id parameter not supplied'})
|
||||
|
||||
try:
|
||||
part = Part.objects.get(pk=pk)
|
||||
return part
|
||||
except (ValueError, Part.DoesNotExist): # pragma: no cover
|
||||
raise ValidationError({k, 'Part does not exist'})
|
||||
|
||||
return None
|
62
InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py
Normal file
62
InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py
Normal file
@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Unit tests for InvenTreeBarcodePlugin"""
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.urls import reverse
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
from rest_framework import status
|
||||
|
||||
|
||||
class TestInvenTreeBarcode(APITestCase):
|
||||
|
||||
fixtures = [
|
||||
'category',
|
||||
'part',
|
||||
'location',
|
||||
'stock'
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
# Create a user for auth
|
||||
user = get_user_model()
|
||||
user.objects.create_user('testuser', 'test@testing.com', 'password')
|
||||
|
||||
self.client.login(username='testuser', password='password')
|
||||
|
||||
def test_errors(self):
|
||||
"""
|
||||
Test all possible error cases for assigment action
|
||||
"""
|
||||
|
||||
def test_assert_error(barcode_data):
|
||||
response = self.client.post(
|
||||
reverse('api-barcode-link'), format='json',
|
||||
data={
|
||||
'barcode': barcode_data,
|
||||
'stockitem': 521
|
||||
}
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('error', response.data)
|
||||
|
||||
# test with already existing stock
|
||||
test_assert_error('{"stockitem": 521}')
|
||||
|
||||
# test with already existing stock location
|
||||
test_assert_error('{"stocklocation": 7}')
|
||||
|
||||
# test with already existing part location
|
||||
test_assert_error('{"part": 10004}')
|
||||
|
||||
# test with hash
|
||||
test_assert_error('{"blbla": 10004}')
|
||||
|
||||
def test_scan(self):
|
||||
"""
|
||||
Test that a barcode can be scanned
|
||||
"""
|
||||
|
||||
response = self.client.post(reverse('api-barcode-scan'), format='json', data={'barcode': 'blbla=10004'})
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('success', response.data)
|
Reference in New Issue
Block a user