mirror of
https://github.com/inventree/InvenTree.git
synced 2026-08-10 15:36:17 +00:00
Barcode API bugs (#12565)
* Add explicit permission checks for barcode scanning - Previous role_required attribute did not do anything * Additional unit tests
This commit is contained in:
@@ -389,8 +389,6 @@ class BarcodePOAllocate(BarcodeView):
|
|||||||
- A SupplierPart object
|
- A SupplierPart object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
role_required = ['purchase_order.add']
|
|
||||||
|
|
||||||
serializer_class = barcode_serializers.BarcodePOAllocateSerializer
|
serializer_class = barcode_serializers.BarcodePOAllocateSerializer
|
||||||
|
|
||||||
def get_supplier_part(
|
def get_supplier_part(
|
||||||
@@ -444,6 +442,13 @@ class BarcodePOAllocate(BarcodeView):
|
|||||||
|
|
||||||
def handle_barcode(self, barcode: str, request, **kwargs):
|
def handle_barcode(self, barcode: str, request, **kwargs):
|
||||||
"""Scan the provided barcode data."""
|
"""Scan the provided barcode data."""
|
||||||
|
if not check_user_permission(request.user, order.models.PurchaseOrder, 'add'):
|
||||||
|
raise PermissionDenied({
|
||||||
|
'error': _(
|
||||||
|
'You do not have the required permissions for purchase orders'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
# The purchase order is provided as part of the request
|
# The purchase order is provided as part of the request
|
||||||
purchase_order = kwargs.get('purchase_order')
|
purchase_order = kwargs.get('purchase_order')
|
||||||
|
|
||||||
@@ -493,12 +498,17 @@ class BarcodePOReceive(BarcodeView):
|
|||||||
- location: The destination location for the received item (optional)
|
- location: The destination location for the received item (optional)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
role_required = ['purchase_order.add']
|
|
||||||
|
|
||||||
serializer_class = barcode_serializers.BarcodePOReceiveSerializer
|
serializer_class = barcode_serializers.BarcodePOReceiveSerializer
|
||||||
|
|
||||||
def handle_barcode(self, barcode: str, request, **kwargs):
|
def handle_barcode(self, barcode: str, request, **kwargs):
|
||||||
"""Handle a barcode scan for a purchase order item."""
|
"""Handle a barcode scan for a purchase order item."""
|
||||||
|
if not check_user_permission(request.user, order.models.PurchaseOrder, 'add'):
|
||||||
|
raise PermissionDenied({
|
||||||
|
'error': _(
|
||||||
|
'You do not have the required permissions for purchase orders'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
logger.debug("BarcodePOReceive: scanned barcode - '%s'", barcode)
|
logger.debug("BarcodePOReceive: scanned barcode - '%s'", barcode)
|
||||||
|
|
||||||
# Extract optional fields from the dataset
|
# Extract optional fields from the dataset
|
||||||
@@ -667,8 +677,6 @@ class BarcodeSOAllocate(BarcodeView):
|
|||||||
- Quantity
|
- Quantity
|
||||||
"""
|
"""
|
||||||
|
|
||||||
role_required = ['sales_order.add']
|
|
||||||
|
|
||||||
serializer_class = barcode_serializers.BarcodeSOAllocateSerializer
|
serializer_class = barcode_serializers.BarcodeSOAllocateSerializer
|
||||||
|
|
||||||
def get_line_item(self, stock_item, **kwargs):
|
def get_line_item(self, stock_item, **kwargs):
|
||||||
@@ -736,6 +744,11 @@ class BarcodeSOAllocate(BarcodeView):
|
|||||||
line: SalesOrderLineItem ID value (optional)
|
line: SalesOrderLineItem ID value (optional)
|
||||||
shipment: SalesOrderShipment ID value (optional)
|
shipment: SalesOrderShipment ID value (optional)
|
||||||
"""
|
"""
|
||||||
|
if not check_user_permission(request.user, order.models.SalesOrder, 'add'):
|
||||||
|
raise PermissionDenied({
|
||||||
|
'error': _('You do not have the required permissions for sales orders')
|
||||||
|
})
|
||||||
|
|
||||||
logger.debug("BarcodeSOAllocate: scanned barcode - '%s'", barcode)
|
logger.debug("BarcodeSOAllocate: scanned barcode - '%s'", barcode)
|
||||||
|
|
||||||
response = self.scan_barcode(barcode, request, **kwargs)
|
response = self.scan_barcode(barcode, request, **kwargs)
|
||||||
|
|||||||
@@ -256,6 +256,50 @@ class BarcodeAPITest(InvenTreeAPITestCase):
|
|||||||
self.assertIn('object does not exist', str(response.data[k]))
|
self.assertIn('object does not exist', str(response.data[k]))
|
||||||
|
|
||||||
|
|
||||||
|
class POAllocateTest(InvenTreeAPITestCase):
|
||||||
|
"""Unit tests for the barcode endpoint for allocating items to a purchase order."""
|
||||||
|
|
||||||
|
fixtures = ['category', 'company', 'part', 'location', 'stock']
|
||||||
|
roles = ['part.view']
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
"""Setup for all tests."""
|
||||||
|
super().setUpTestData()
|
||||||
|
|
||||||
|
cls.supplier = company.models.Company.objects.filter(is_supplier=True).first()
|
||||||
|
cls.purchase_order = order.models.PurchaseOrder.objects.create(
|
||||||
|
supplier=cls.supplier
|
||||||
|
)
|
||||||
|
|
||||||
|
def postBarcode(self, barcode, expected_code=None, **kwargs):
|
||||||
|
"""Post barcode and return results."""
|
||||||
|
data = {'barcode': barcode, **kwargs}
|
||||||
|
|
||||||
|
response = self.post(
|
||||||
|
reverse('api-barcode-po-allocate'), data=data, expected_code=expected_code
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.data
|
||||||
|
|
||||||
|
def test_permission_denied(self):
|
||||||
|
"""A user without the 'purchase_order.add' role cannot allocate against a PO via barcode scan."""
|
||||||
|
response = self.postBarcode(
|
||||||
|
'abcde', purchase_order=self.purchase_order.pk, expected_code=403
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn('do not have the required permissions', str(response['error']))
|
||||||
|
|
||||||
|
# Once the role is granted, the request proceeds past the permission check
|
||||||
|
# (still fails with 400, as 'abcde' does not match any barcode plugin -
|
||||||
|
# but that is a *different* error to the permission check above)
|
||||||
|
self.assignRole('purchase_order.add')
|
||||||
|
|
||||||
|
self.postBarcode(
|
||||||
|
'abcde', purchase_order=self.purchase_order.pk, expected_code=400
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SOAllocateTest(InvenTreeAPITestCase):
|
class SOAllocateTest(InvenTreeAPITestCase):
|
||||||
"""Unit tests for the barcode endpoint for allocating items to a sales order."""
|
"""Unit tests for the barcode endpoint for allocating items to a sales order."""
|
||||||
|
|
||||||
@@ -309,6 +353,36 @@ class SOAllocateTest(InvenTreeAPITestCase):
|
|||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
|
def test_permission_denied(self):
|
||||||
|
"""A user without the 'sales_order.add' role cannot allocate stock via barcode scan."""
|
||||||
|
self.clearRoles()
|
||||||
|
|
||||||
|
response = self.post(
|
||||||
|
reverse('api-barcode-so-allocate'),
|
||||||
|
data={
|
||||||
|
'barcode': self.stock_item.format_barcode(),
|
||||||
|
'sales_order': self.sales_order.pk,
|
||||||
|
},
|
||||||
|
expected_code=403,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn(
|
||||||
|
'do not have the required permissions', str(response.data['error'])
|
||||||
|
)
|
||||||
|
|
||||||
|
# No allocation should have been created
|
||||||
|
self.assertEqual(self.line_item.allocated_quantity(), 0)
|
||||||
|
|
||||||
|
# Restore the required roles - the request should now succeed
|
||||||
|
self.assignRole('sales_order.add')
|
||||||
|
self.assignRole('stock.view')
|
||||||
|
|
||||||
|
self.postBarcode(
|
||||||
|
self.stock_item.format_barcode(),
|
||||||
|
sales_order=self.sales_order.pk,
|
||||||
|
expected_code=200,
|
||||||
|
)
|
||||||
|
|
||||||
def test_no_data(self):
|
def test_no_data(self):
|
||||||
"""Test when no data is provided."""
|
"""Test when no data is provided."""
|
||||||
result = self.postBarcode('', expected_code=400)
|
result = self.postBarcode('', expected_code=400)
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ class SupplierBarcodeTests(InvenTreeAPITestCase):
|
|||||||
class SupplierBarcodePOReceiveTests(InvenTreeAPITestCase):
|
class SupplierBarcodePOReceiveTests(InvenTreeAPITestCase):
|
||||||
"""Tests barcode scanning to receive a purchase order item."""
|
"""Tests barcode scanning to receive a purchase order item."""
|
||||||
|
|
||||||
roles = ['stock.view', 'stock_location.view']
|
roles = ['stock.view', 'stock_location.view', 'purchase_order.add']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Create supplier part and purchase_order."""
|
"""Create supplier part and purchase_order."""
|
||||||
@@ -257,6 +257,21 @@ class SupplierBarcodePOReceiveTests(InvenTreeAPITestCase):
|
|||||||
mouser_plugin = registry.get_plugin('mouserplugin')
|
mouser_plugin = registry.get_plugin('mouserplugin')
|
||||||
mouser_plugin.set_setting('SUPPLIER_ID', mouser.pk)
|
mouser_plugin.set_setting('SUPPLIER_ID', mouser.pk)
|
||||||
|
|
||||||
|
def test_permission_denied(self):
|
||||||
|
"""A user without the 'purchase_order.add' role cannot receive stock via barcode scan."""
|
||||||
|
url = reverse('api-barcode-po-receive')
|
||||||
|
|
||||||
|
self.clearRoles()
|
||||||
|
|
||||||
|
response = self.post(url, data={'barcode': DIGIKEY_BARCODE}, expected_code=403)
|
||||||
|
|
||||||
|
self.assertIn(
|
||||||
|
'do not have the required permissions', str(response.data['error'])
|
||||||
|
)
|
||||||
|
|
||||||
|
# No stock should have been received
|
||||||
|
self.assertFalse(StockItem.objects.filter(part__name='Test Part').exists())
|
||||||
|
|
||||||
def test_receive(self):
|
def test_receive(self):
|
||||||
"""Test receiving an item from a barcode."""
|
"""Test receiving an item from a barcode."""
|
||||||
url = reverse('api-barcode-po-receive')
|
url = reverse('api-barcode-po-receive')
|
||||||
|
|||||||
Reference in New Issue
Block a user