Merge branch 'master' of https://github.com/inventree/InvenTree into add-report-check

This commit is contained in:
Matthias 2022-05-11 04:19:18 +02:00
commit b7087b83b5
No known key found for this signature in database
GPG Key ID: AB6D0E6C4CB65093
9 changed files with 90 additions and 23 deletions

View File

@ -4,11 +4,15 @@ InvenTree API version information
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 46 INVENTREE_API_VERSION = 47
""" """
Increment this API version number whenever there is a significant change to the API that any clients need to know about Increment this API version number whenever there is a significant change to the API that any clients need to know about
v47 -> 2022-05-10 : https://github.com/inventree/InvenTree/pull/2964
- Fixes barcode API error response when scanning a StockItem which does not exist
- Fixes barcode API error response when scanning a StockLocation which does not exist
v46 -> 2022-05-09 v46 -> 2022-05-09
- Fixes read permissions on settings API - Fixes read permissions on settings API
- Allows non-staff users to read global settings via the API - Allows non-staff users to read global settings via the API

View File

@ -49,6 +49,8 @@ from InvenTree import validators
from InvenTree.models import InvenTreeTree, InvenTreeAttachment, DataImportMixin from InvenTree.models import InvenTreeTree, InvenTreeAttachment, DataImportMixin
from InvenTree.fields import InvenTreeURLField from InvenTree.fields import InvenTreeURLField
from InvenTree.helpers import decimal2string, normalize, decimal2money from InvenTree.helpers import decimal2string, normalize, decimal2money
import InvenTree.ready
import InvenTree.tasks import InvenTree.tasks
from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus, SalesOrderStatus from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus, SalesOrderStatus
@ -2292,7 +2294,7 @@ def after_save_part(sender, instance: Part, created, **kwargs):
Function to be executed after a Part is saved Function to be executed after a Part is saved
""" """
if not created: if not created and not InvenTree.ready.isImportingData():
# Check part stock only if we are *updating* the part (not creating it) # Check part stock only if we are *updating* the part (not creating it)
# Run this check in the background # Run this check in the background

View File

@ -84,7 +84,7 @@ class InvenTreeBarcodePlugin(BarcodeMixin, plugin.integration.IntegrationPluginB
item = StockItem.objects.get(pk=pk) item = StockItem.objects.get(pk=pk)
return item return item
except (ValueError, StockItem.DoesNotExist): # pragma: no cover except (ValueError, StockItem.DoesNotExist): # pragma: no cover
raise ValidationError({k, "Stock item does not exist"}) raise ValidationError({k: "Stock item does not exist"})
return None return None
@ -112,7 +112,7 @@ class InvenTreeBarcodePlugin(BarcodeMixin, plugin.integration.IntegrationPluginB
loc = StockLocation.objects.get(pk=pk) loc = StockLocation.objects.get(pk=pk)
return loc return loc
except (ValueError, StockLocation.DoesNotExist): # pragma: no cover except (ValueError, StockLocation.DoesNotExist): # pragma: no cover
raise ValidationError({k, "Stock location does not exist"}) raise ValidationError({k: "Stock location does not exist"})
return None return None
@ -133,12 +133,12 @@ class InvenTreeBarcodePlugin(BarcodeMixin, plugin.integration.IntegrationPluginB
try: try:
pk = self.data[k]['id'] pk = self.data[k]['id']
except (AttributeError, KeyError): except (AttributeError, KeyError):
raise ValidationError({k, 'id parameter not supplied'}) raise ValidationError({k: 'id parameter not supplied'})
try: try:
part = Part.objects.get(pk=pk) part = Part.objects.get(pk=pk)
return part return part
except (ValueError, Part.DoesNotExist): # pragma: no cover except (ValueError, Part.DoesNotExist): # pragma: no cover
raise ValidationError({k, 'Part does not exist'}) raise ValidationError({k: 'Part does not exist'})
return None return None

View File

@ -17,7 +17,7 @@ from django.dispatch.dispatcher import receiver
from common.models import InvenTreeSetting from common.models import InvenTreeSetting
import common.notifications import common.notifications
from InvenTree.ready import canAppAccessDatabase from InvenTree.ready import canAppAccessDatabase, isImportingData
from InvenTree.tasks import offload_task from InvenTree.tasks import offload_task
from plugin.registry import registry from plugin.registry import registry
@ -113,6 +113,10 @@ def allow_table_event(table_name):
We *do not* want events to be fired for some tables! We *do not* want events to be fired for some tables!
""" """
if isImportingData():
# Prevent table events during the data import process
return False
table_name = table_name.lower().strip() table_name = table_name.lower().strip()
# Ignore any tables which start with these prefixes # Ignore any tables which start with these prefixes

View File

@ -6,6 +6,6 @@
<em>This location has no sublocations!</em> <em>This location has no sublocations!</em>
<ul> <ul>
<li><b>Location Name</b>: {{ location.name }}</li> <li><strong>Location Name</strong>: {{ location.name }}</li>
<li><b>Location Path</b>: {{ location.pathstring }}</li> <li><strong>Location Path</strong>: {{ location.pathstring }}</li>
</ul> </ul>

View File

@ -86,6 +86,22 @@ class BarcodeAPITest(APITestCase):
self.assertIn('barcode_data', response.data) self.assertIn('barcode_data', response.data)
self.assertEqual(response.data['part']['pk'], 1) self.assertEqual(response.data['part']['pk'], 1)
def test_invalid_part(self):
"""Test response for invalid part"""
response = self.client.post(
self.scan_url,
{
'barcode': {
'part': 999999999,
}
},
format='json'
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.data['part'], 'Part does not exist')
def test_find_stock_item(self): def test_find_stock_item(self):
""" """
Test that we can lookup a stock item based on ID Test that we can lookup a stock item based on ID
@ -106,6 +122,23 @@ class BarcodeAPITest(APITestCase):
self.assertIn('barcode_data', response.data) self.assertIn('barcode_data', response.data)
self.assertEqual(response.data['stockitem']['pk'], 1) self.assertEqual(response.data['stockitem']['pk'], 1)
def test_invalid_item(self):
"""Test response for invalid stock item"""
response = self.client.post(
self.scan_url,
{
'barcode': {
'stockitem': 999999999,
}
},
format='json'
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.data['stockitem'], 'Stock item does not exist')
def test_find_location(self): def test_find_location(self):
""" """
Test that we can lookup a stock location based on ID Test that we can lookup a stock location based on ID
@ -126,6 +159,23 @@ class BarcodeAPITest(APITestCase):
self.assertIn('barcode_data', response.data) self.assertIn('barcode_data', response.data)
self.assertEqual(response.data['stocklocation']['pk'], 1) self.assertEqual(response.data['stocklocation']['pk'], 1)
def test_invalid_location(self):
"""Test response for an invalid location"""
response = self.client.post(
self.scan_url,
{
'barcode': {
'stocklocation': 999999999,
}
},
format='json'
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.data['stocklocation'], 'Stock location does not exist')
def test_integer_barcode(self): def test_integer_barcode(self):
response = self.postBarcode(self.scan_url, '123456789') response = self.postBarcode(self.scan_url, '123456789')

View File

@ -30,7 +30,8 @@ from mptt.managers import TreeManager
from decimal import Decimal, InvalidOperation from decimal import Decimal, InvalidOperation
from datetime import datetime, timedelta from datetime import datetime, timedelta
from InvenTree import helpers import InvenTree.helpers
import InvenTree.ready
import InvenTree.tasks import InvenTree.tasks
import common.models import common.models
@ -137,7 +138,7 @@ class StockLocation(InvenTreeTree):
def format_barcode(self, **kwargs): def format_barcode(self, **kwargs):
""" Return a JSON string for formatting a barcode for this StockLocation object """ """ Return a JSON string for formatting a barcode for this StockLocation object """
return helpers.MakeBarcode( return InvenTree.helpers.MakeBarcode(
'stocklocation', 'stocklocation',
self.pk, self.pk,
{ {
@ -577,7 +578,7 @@ class StockItem(MPTTModel):
Voltagile data (e.g. stock quantity) should be looked up using the InvenTree API (as it may change) Voltagile data (e.g. stock quantity) should be looked up using the InvenTree API (as it may change)
""" """
return helpers.MakeBarcode( return InvenTree.helpers.MakeBarcode(
"stockitem", "stockitem",
self.id, self.id,
{ {
@ -1775,7 +1776,7 @@ class StockItem(MPTTModel):
sn=self.serial) sn=self.serial)
else: else:
s = '{n} x {part}'.format( s = '{n} x {part}'.format(
n=helpers.decimal2string(self.quantity), n=InvenTree.helpers.decimal2string(self.quantity),
part=self.part.full_name) part=self.part.full_name)
if self.location: if self.location:
@ -1783,7 +1784,7 @@ class StockItem(MPTTModel):
if self.purchase_order: if self.purchase_order:
s += " ({pre}{po})".format( s += " ({pre}{po})".format(
pre=helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"), pre=InvenTree.helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"),
po=self.purchase_order, po=self.purchase_order,
) )
@ -1851,7 +1852,7 @@ class StockItem(MPTTModel):
result_map = {} result_map = {}
for result in results: for result in results:
key = helpers.generateTestKey(result.test) key = InvenTree.helpers.generateTestKey(result.test)
result_map[key] = result result_map[key] = result
# Do we wish to "cascade" and include test results from installed stock items? # Do we wish to "cascade" and include test results from installed stock items?
@ -1898,7 +1899,7 @@ class StockItem(MPTTModel):
failed = 0 failed = 0
for test in required: for test in required:
key = helpers.generateTestKey(test.test_name) key = InvenTree.helpers.generateTestKey(test.test_name)
if key in results: if key in results:
result = results[key] result = results[key]
@ -1949,7 +1950,7 @@ class StockItem(MPTTModel):
# Attempt to validate report filter (skip if invalid) # Attempt to validate report filter (skip if invalid)
try: try:
filters = helpers.validateFilterString(test_report.filters) filters = InvenTree.helpers.validateFilterString(test_report.filters)
if item_query.filter(**filters).exists(): if item_query.filter(**filters).exists():
reports.append(test_report) reports.append(test_report)
except (ValidationError, FieldError): except (ValidationError, FieldError):
@ -1977,7 +1978,7 @@ class StockItem(MPTTModel):
for lbl in label.models.StockItemLabel.objects.filter(enabled=True): for lbl in label.models.StockItemLabel.objects.filter(enabled=True):
try: try:
filters = helpers.validateFilterString(lbl.filters) filters = InvenTree.helpers.validateFilterString(lbl.filters)
if item_query.filter(**filters).exists(): if item_query.filter(**filters).exists():
labels.append(lbl) labels.append(lbl)
@ -2016,6 +2017,7 @@ def after_delete_stock_item(sender, instance: StockItem, **kwargs):
Function to be executed after a StockItem object is deleted Function to be executed after a StockItem object is deleted
""" """
if not InvenTree.ready.isImportingData():
# Run this check in the background # Run this check in the background
InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part) InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part)
@ -2026,6 +2028,7 @@ def after_save_stock_item(sender, instance: StockItem, created, **kwargs):
Hook function to be executed after StockItem object is saved/updated Hook function to be executed after StockItem object is saved/updated
""" """
if not InvenTree.ready.isImportingData():
# Run this check in the background # Run this check in the background
InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part) InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part)
@ -2170,7 +2173,7 @@ class StockItemTestResult(models.Model):
@property @property
def key(self): def key(self):
return helpers.generateTestKey(self.test) return InvenTree.helpers.generateTestKey(self.test)
stock_item = models.ForeignKey( stock_item = models.ForeignKey(
StockItem, StockItem,

View File

@ -1056,6 +1056,7 @@ function loadBuildOutputTable(build_info, options={}) {
'{% url "api-stock-test-result-list" %}', '{% url "api-stock-test-result-list" %}',
{ {
build: build_info.pk, build: build_info.pk,
ordering: '-date',
}, },
{ {
success: function(results) { success: function(results) {

View File

@ -95,6 +95,9 @@ RUN echo "Downloading InvenTree from ${INVENTREE_GIT_REPO}"
RUN git clone --branch ${INVENTREE_GIT_BRANCH} --depth 1 ${INVENTREE_GIT_REPO} ${INVENTREE_HOME} RUN git clone --branch ${INVENTREE_GIT_BRANCH} --depth 1 ${INVENTREE_GIT_REPO} ${INVENTREE_HOME}
# Ref: https://github.blog/2022-04-12-git-security-vulnerability-announced/
RUN git config --global --add safe.directory ${INVENTREE_HOME}
# Checkout against a particular git tag # Checkout against a particular git tag
RUN if [ -n "${INVENTREE_GIT_TAG}" ] ; then cd ${INVENTREE_HOME} && git fetch --all --tags && git checkout tags/${INVENTREE_GIT_TAG} -b v${INVENTREE_GIT_TAG}-branch ; fi RUN if [ -n "${INVENTREE_GIT_TAG}" ] ; then cd ${INVENTREE_HOME} && git fetch --all --tags && git checkout tags/${INVENTREE_GIT_TAG} -b v${INVENTREE_GIT_TAG}-branch ; fi