mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
c0a18ef244
@ -42,6 +42,8 @@ class InvenTreeBarcodePlugin(BarcodePlugin):
|
|||||||
elif type(self.data) is str:
|
elif type(self.data) is str:
|
||||||
try:
|
try:
|
||||||
self.data = json.loads(self.data)
|
self.data = json.loads(self.data)
|
||||||
|
if type(self.data) is not dict:
|
||||||
|
return False
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
@ -56,6 +56,34 @@ class BarcodeAPITest(APITestCase):
|
|||||||
self.assertIn('plugin', data)
|
self.assertIn('plugin', data)
|
||||||
self.assertIsNone(data['plugin'])
|
self.assertIsNone(data['plugin'])
|
||||||
|
|
||||||
|
def test_integer_barcode(self):
|
||||||
|
|
||||||
|
response = self.postBarcode(self.scan_url, '123456789')
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
data = response.data
|
||||||
|
self.assertIn('error', data)
|
||||||
|
|
||||||
|
self.assertIn('barcode_data', data)
|
||||||
|
self.assertIn('hash', data)
|
||||||
|
self.assertIn('plugin', data)
|
||||||
|
self.assertIsNone(data['plugin'])
|
||||||
|
|
||||||
|
def test_array_barcode(self):
|
||||||
|
|
||||||
|
response = self.postBarcode(self.scan_url, "['foo', 'bar']")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
data = response.data
|
||||||
|
self.assertIn('error', data)
|
||||||
|
|
||||||
|
self.assertIn('barcode_data', data)
|
||||||
|
self.assertIn('hash', data)
|
||||||
|
self.assertIn('plugin', data)
|
||||||
|
self.assertIsNone(data['plugin'])
|
||||||
|
|
||||||
def test_barcode_generation(self):
|
def test_barcode_generation(self):
|
||||||
|
|
||||||
item = StockItem.objects.get(pk=522)
|
item = StockItem.objects.get(pk=522)
|
||||||
|
@ -2,30 +2,20 @@
|
|||||||
JSON serializers for Part app
|
JSON serializers for Part app
|
||||||
"""
|
"""
|
||||||
import imghdr
|
import imghdr
|
||||||
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
from .models import Part, PartStar
|
|
||||||
|
|
||||||
from .models import PartCategory
|
|
||||||
from .models import BomItem
|
|
||||||
from .models import PartParameter, PartParameterTemplate
|
|
||||||
from .models import PartAttachment
|
|
||||||
from .models import PartTestTemplate
|
|
||||||
from .models import PartSellPriceBreak
|
|
||||||
|
|
||||||
from stock.models import StockItem
|
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from sql_util.utils import SubquerySum, SubqueryCount
|
|
||||||
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
|
from InvenTree.serializers import (InvenTreeAttachmentSerializerField,
|
||||||
|
InvenTreeModelSerializer)
|
||||||
|
from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus
|
||||||
|
from rest_framework import serializers
|
||||||
|
from sql_util.utils import SubqueryCount, SubquerySum
|
||||||
|
from stock.models import StockItem
|
||||||
|
|
||||||
from InvenTree.status_codes import PurchaseOrderStatus, BuildStatus
|
from .models import (BomItem, Part, PartAttachment, PartCategory,
|
||||||
from InvenTree.serializers import InvenTreeModelSerializer
|
PartParameter, PartParameterTemplate, PartSellPriceBreak,
|
||||||
from InvenTree.serializers import InvenTreeAttachmentSerializerField
|
PartStar, PartTestTemplate)
|
||||||
|
|
||||||
|
|
||||||
class CategorySerializer(InvenTreeModelSerializer):
|
class CategorySerializer(InvenTreeModelSerializer):
|
||||||
@ -41,6 +31,7 @@ class CategorySerializer(InvenTreeModelSerializer):
|
|||||||
'pk',
|
'pk',
|
||||||
'name',
|
'name',
|
||||||
'description',
|
'description',
|
||||||
|
'default_location',
|
||||||
'pathstring',
|
'pathstring',
|
||||||
'url',
|
'url',
|
||||||
'parent',
|
'parent',
|
||||||
@ -304,6 +295,7 @@ class PartSerializer(InvenTreeModelSerializer):
|
|||||||
'category_detail',
|
'category_detail',
|
||||||
'component',
|
'component',
|
||||||
'description',
|
'description',
|
||||||
|
'default_location',
|
||||||
'full_name',
|
'full_name',
|
||||||
'image',
|
'image',
|
||||||
'in_stock',
|
'in_stock',
|
||||||
|
@ -324,8 +324,31 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
serializer_class = StockItemSerializer
|
serializer_class = StockItemSerializer
|
||||||
queryset = StockItem.objects.all()
|
queryset = StockItem.objects.all()
|
||||||
|
|
||||||
# TODO - Override the 'create' method for this view,
|
def create(self, request, *args, **kwargs):
|
||||||
# to allow the user to be recorded when a new StockItem object is created
|
"""
|
||||||
|
Create a new StockItem object via the API.
|
||||||
|
|
||||||
|
We override the default 'create' implementation.
|
||||||
|
|
||||||
|
If a location is *not* specified, but the linked *part* has a default location,
|
||||||
|
we can pre-fill the location automatically.
|
||||||
|
"""
|
||||||
|
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
|
item = serializer.save()
|
||||||
|
|
||||||
|
# A location was *not* specified - try to infer it
|
||||||
|
if 'location' not in request.data:
|
||||||
|
location = item.part.get_default_location()
|
||||||
|
if location is not None:
|
||||||
|
item.location = location
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
# Return a response
|
||||||
|
headers = self.get_success_headers(serializer.data)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -93,7 +93,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
{% if item.uid %}
|
{% if item.uid %}
|
||||||
<li><a href='#' id='unlink-barcode'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li>
|
<li><a href='#' id='unlink-barcode'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a href='#' id='link-barcode'><span class='fas fa-link'></span> {% trans "Link Barcode" %}</a></li>\
|
<li><a href='#' id='link-barcode'><span class='fas fa-link'></span> {% trans "Link Barcode" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -97,6 +97,53 @@ class StockItemTest(StockAPITestCase):
|
|||||||
response = self.client.get(self.list_url, format='json')
|
response = self.client.get(self.list_url, format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
def test_create_default_location(self):
|
||||||
|
"""
|
||||||
|
Test the default location functionality,
|
||||||
|
if a 'location' is not specified in the creation request.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The part 'R_4K7_0603' (pk=4) has a default location specified
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
self.list_url,
|
||||||
|
data={
|
||||||
|
'part': 4,
|
||||||
|
'quantity': 10
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
self.assertEqual(response.data['location'], 2)
|
||||||
|
|
||||||
|
# What if we explicitly set the location to a different value?
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
self.list_url,
|
||||||
|
data={
|
||||||
|
'part': 4,
|
||||||
|
'quantity': 20,
|
||||||
|
'location': 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
self.assertEqual(response.data['location'], 1)
|
||||||
|
|
||||||
|
# And finally, what if we set the location explicitly to None?
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
self.list_url,
|
||||||
|
data={
|
||||||
|
'part': 4,
|
||||||
|
'quantity': 20,
|
||||||
|
'location': '',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
self.assertEqual(response.data['location'], None)
|
||||||
|
|
||||||
def test_stock_item_create(self):
|
def test_stock_item_create(self):
|
||||||
"""
|
"""
|
||||||
Test creation of a StockItem via the API
|
Test creation of a StockItem via the API
|
||||||
|
Loading…
Reference in New Issue
Block a user