mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge branch 'inventree:master' into matmair/issue2279
This commit is contained in:
commit
c7b6dc5929
@ -315,7 +315,7 @@ def WrapWithQuotes(text, quote='"'):
|
||||
return text
|
||||
|
||||
|
||||
def MakeBarcode(object_name, object_pk, object_data={}, **kwargs):
|
||||
def MakeBarcode(object_name, object_pk, object_data=None, **kwargs):
|
||||
""" Generate a string for a barcode. Adds some global InvenTree parameters.
|
||||
|
||||
Args:
|
||||
@ -327,6 +327,8 @@ def MakeBarcode(object_name, object_pk, object_data={}, **kwargs):
|
||||
Returns:
|
||||
json string of the supplied data plus some other data
|
||||
"""
|
||||
if object_data is None:
|
||||
object_data = {}
|
||||
|
||||
url = kwargs.get('url', False)
|
||||
brief = kwargs.get('brief', True)
|
||||
|
@ -109,14 +109,14 @@ class BarcodeScan(APIView):
|
||||
# No plugin is found!
|
||||
# However, the hash of the barcode may still be associated with a StockItem!
|
||||
else:
|
||||
hash = hash_barcode(barcode_data)
|
||||
result_hash = hash_barcode(barcode_data)
|
||||
|
||||
response['hash'] = hash
|
||||
response['hash'] = result_hash
|
||||
response['plugin'] = None
|
||||
|
||||
# Try to look for a matching StockItem
|
||||
try:
|
||||
item = StockItem.objects.get(uid=hash)
|
||||
item = StockItem.objects.get(uid=result_hash)
|
||||
serializer = StockItemSerializer(item, part_detail=True, location_detail=True, supplier_part_detail=True)
|
||||
response['stockitem'] = serializer.data
|
||||
response['url'] = reverse('stock-item-detail', kwargs={'pk': item.id})
|
||||
@ -182,8 +182,8 @@ class BarcodeAssign(APIView):
|
||||
# Matching plugin was found
|
||||
if plugin is not None:
|
||||
|
||||
hash = plugin.hash()
|
||||
response['hash'] = hash
|
||||
result_hash = plugin.hash()
|
||||
response['hash'] = result_hash
|
||||
response['plugin'] = plugin.name
|
||||
|
||||
# Ensure that the barcode does not already match a database entry
|
||||
@ -208,14 +208,14 @@ class BarcodeAssign(APIView):
|
||||
match_found = True
|
||||
|
||||
else:
|
||||
hash = hash_barcode(barcode_data)
|
||||
result_hash = hash_barcode(barcode_data)
|
||||
|
||||
response['hash'] = hash
|
||||
response['hash'] = result_hash
|
||||
response['plugin'] = None
|
||||
|
||||
# Lookup stock item by hash
|
||||
try:
|
||||
item = StockItem.objects.get(uid=hash)
|
||||
item = StockItem.objects.get(uid=result_hash)
|
||||
response['error'] = _('Barcode hash already matches Stock Item')
|
||||
match_found = True
|
||||
except StockItem.DoesNotExist:
|
||||
|
@ -124,12 +124,12 @@ class BarcodeAPITest(APITestCase):
|
||||
|
||||
self.assertIn('success', data)
|
||||
|
||||
hash = data['hash']
|
||||
result_hash = data['hash']
|
||||
|
||||
# Read the item out from the database again
|
||||
item = StockItem.objects.get(pk=522)
|
||||
|
||||
self.assertEqual(hash, item.uid)
|
||||
self.assertEqual(result_hash, item.uid)
|
||||
|
||||
# Ensure that the same UID cannot be assigned to a different stock item!
|
||||
response = self.client.post(
|
||||
|
@ -193,7 +193,7 @@ class BuildOutputCompleteTest(BuildAPITest):
|
||||
self.assertTrue('accept_unallocated' in response.data)
|
||||
|
||||
# Accept unallocated stock
|
||||
response = self.post(
|
||||
self.post(
|
||||
finish_url,
|
||||
{
|
||||
'accept_unallocated': True,
|
||||
|
@ -67,7 +67,6 @@ class WebhookView(CsrfExemptMixin, APIView):
|
||||
message,
|
||||
)
|
||||
|
||||
# return results
|
||||
data = self.webhook.get_return(payload, headers, request)
|
||||
return HttpResponse(data)
|
||||
|
||||
|
@ -9,8 +9,6 @@ import os
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
# from company.models import ManufacturerPart, SupplierPart
|
||||
|
||||
|
||||
class FileManager:
|
||||
""" Class for managing an uploaded file """
|
||||
|
@ -1480,11 +1480,9 @@ class WebhookEndpoint(models.Model):
|
||||
|
||||
def process_webhook(self):
|
||||
if self.token:
|
||||
self.token = self.token
|
||||
self.verify = VerificationMethod.TOKEN
|
||||
# TODO make a object-setting
|
||||
if self.secret:
|
||||
self.secret = self.secret
|
||||
self.verify = VerificationMethod.HMAC
|
||||
# TODO make a object-setting
|
||||
return True
|
||||
@ -1494,6 +1492,7 @@ class WebhookEndpoint(models.Model):
|
||||
|
||||
# no token
|
||||
if self.verify == VerificationMethod.NONE:
|
||||
# do nothing as no method was chosen
|
||||
pass
|
||||
|
||||
# static token
|
||||
|
@ -10,6 +10,8 @@ from django.contrib.auth import get_user_model
|
||||
from .models import InvenTreeSetting, WebhookEndpoint, WebhookMessage, NotificationEntry
|
||||
from .api import WebhookView
|
||||
|
||||
CONTENT_TYPE_JSON = 'application/json'
|
||||
|
||||
|
||||
class SettingsTest(TestCase):
|
||||
"""
|
||||
@ -105,7 +107,7 @@ class WebhookMessageTests(TestCase):
|
||||
def test_missing_token(self):
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
)
|
||||
|
||||
assert response.status_code == HTTPStatus.FORBIDDEN
|
||||
@ -116,7 +118,7 @@ class WebhookMessageTests(TestCase):
|
||||
def test_bad_token(self):
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
**{'HTTP_TOKEN': '1234567fghj'},
|
||||
)
|
||||
|
||||
@ -126,7 +128,7 @@ class WebhookMessageTests(TestCase):
|
||||
def test_bad_url(self):
|
||||
response = self.client.post(
|
||||
'/api/webhook/1234/',
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
)
|
||||
|
||||
assert response.status_code == HTTPStatus.NOT_FOUND
|
||||
@ -135,7 +137,7 @@ class WebhookMessageTests(TestCase):
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data="{'this': 123}",
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
**{'HTTP_TOKEN': str(self.endpoint_def.token)},
|
||||
)
|
||||
|
||||
@ -152,7 +154,7 @@ class WebhookMessageTests(TestCase):
|
||||
# check
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
)
|
||||
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
@ -167,7 +169,7 @@ class WebhookMessageTests(TestCase):
|
||||
# check
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
)
|
||||
|
||||
assert response.status_code == HTTPStatus.FORBIDDEN
|
||||
@ -182,7 +184,7 @@ class WebhookMessageTests(TestCase):
|
||||
# check
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
**{'HTTP_TOKEN': str('68MXtc/OiXdA5e2Nq9hATEVrZFpLb3Zb0oau7n8s31I=')},
|
||||
)
|
||||
|
||||
@ -193,7 +195,7 @@ class WebhookMessageTests(TestCase):
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={"this": "is a message"},
|
||||
content_type='application/json',
|
||||
content_type=CONTENT_TYPE_JSON,
|
||||
**{'HTTP_TOKEN': str(self.endpoint_def.token)},
|
||||
)
|
||||
|
||||
|
@ -92,5 +92,4 @@ class OrderMatchItemForm(MatchItemForm):
|
||||
default_amount=clean_decimal(row.get('purchase_price', '')),
|
||||
)
|
||||
|
||||
# return default
|
||||
return super().get_special_field(col_guess, row, file_manager)
|
||||
|
@ -446,10 +446,10 @@ class PartSerialNumberDetail(generics.RetrieveAPIView):
|
||||
}
|
||||
|
||||
if latest is not None:
|
||||
next = increment(latest)
|
||||
next_serial = increment(latest)
|
||||
|
||||
if next != increment:
|
||||
data['next'] = next
|
||||
if next_serial != increment:
|
||||
data['next'] = next_serial
|
||||
|
||||
return Response(data)
|
||||
|
||||
|
@ -75,7 +75,6 @@ class BomMatchItemForm(MatchItemForm):
|
||||
})
|
||||
)
|
||||
|
||||
# return default
|
||||
return super().get_special_field(col_guess, row, file_manager)
|
||||
|
||||
|
||||
|
@ -1530,15 +1530,15 @@ class Part(MPTTModel):
|
||||
returns a string representation of a hash object which can be compared with a stored value
|
||||
"""
|
||||
|
||||
hash = hashlib.md5(str(self.id).encode())
|
||||
result_hash = hashlib.md5(str(self.id).encode())
|
||||
|
||||
# List *all* BOM items (including inherited ones!)
|
||||
bom_items = self.get_bom_items().all().prefetch_related('sub_part')
|
||||
|
||||
for item in bom_items:
|
||||
hash.update(str(item.get_item_hash()).encode())
|
||||
result_hash.update(str(item.get_item_hash()).encode())
|
||||
|
||||
return str(hash.digest())
|
||||
return str(result_hash.digest())
|
||||
|
||||
def is_bom_valid(self):
|
||||
""" Check if the BOM is 'valid' - if the calculated checksum matches the stored value
|
||||
@ -2188,9 +2188,7 @@ def after_save_part(sender, instance: Part, created, **kwargs):
|
||||
Function to be executed after a Part is saved
|
||||
"""
|
||||
|
||||
if created:
|
||||
pass
|
||||
else:
|
||||
if not created:
|
||||
# Check part stock only if we are *updating* the part (not creating it)
|
||||
|
||||
# Run this check in the background
|
||||
@ -2678,18 +2676,18 @@ class BomItem(models.Model):
|
||||
"""
|
||||
|
||||
# Seed the hash with the ID of this BOM item
|
||||
hash = hashlib.md5(str(self.id).encode())
|
||||
result_hash = hashlib.md5(str(self.id).encode())
|
||||
|
||||
# Update the hash based on line information
|
||||
hash.update(str(self.sub_part.id).encode())
|
||||
hash.update(str(self.sub_part.full_name).encode())
|
||||
hash.update(str(self.quantity).encode())
|
||||
hash.update(str(self.note).encode())
|
||||
hash.update(str(self.reference).encode())
|
||||
hash.update(str(self.optional).encode())
|
||||
hash.update(str(self.inherited).encode())
|
||||
result_hash.update(str(self.sub_part.id).encode())
|
||||
result_hash.update(str(self.sub_part.full_name).encode())
|
||||
result_hash.update(str(self.quantity).encode())
|
||||
result_hash.update(str(self.note).encode())
|
||||
result_hash.update(str(self.reference).encode())
|
||||
result_hash.update(str(self.optional).encode())
|
||||
result_hash.update(str(self.inherited).encode())
|
||||
|
||||
return str(hash.digest())
|
||||
return str(result_hash.digest())
|
||||
|
||||
def validate_hash(self, valid=True):
|
||||
""" Mark this item as 'valid' (store the checksum hash).
|
||||
|
@ -293,7 +293,7 @@ def progress_bar(val, max, *args, **kwargs):
|
||||
Render a progress bar element
|
||||
"""
|
||||
|
||||
id = kwargs.get('id', 'progress-bar')
|
||||
item_id = kwargs.get('id', 'progress-bar')
|
||||
|
||||
if val > max:
|
||||
style = 'progress-bar-over'
|
||||
@ -317,7 +317,7 @@ def progress_bar(val, max, *args, **kwargs):
|
||||
style_tags.append(f'max-width: {max_width};')
|
||||
|
||||
html = f"""
|
||||
<div id='{id}' class='progress' style='{" ".join(style_tags)}'>
|
||||
<div id='{item_id}' class='progress' style='{" ".join(style_tags)}'>
|
||||
<div class='progress-bar {style}' role='progressbar' aria-valuemin='0' aria-valuemax='100' style='width:{percent}%'></div>
|
||||
<div class='progress-value'>{val} / {max}</div>
|
||||
</div>
|
||||
|
@ -31,8 +31,8 @@ class TemplateTagTest(TestCase):
|
||||
self.assertEqual(type(inventree_extras.inventree_version()), str)
|
||||
|
||||
def test_hash(self):
|
||||
hash = inventree_extras.inventree_commit_hash()
|
||||
self.assertGreater(len(hash), 5)
|
||||
result_hash = inventree_extras.inventree_commit_hash()
|
||||
self.assertGreater(len(result_hash), 5)
|
||||
|
||||
def test_date(self):
|
||||
d = inventree_extras.inventree_commit_date()
|
||||
|
@ -1,7 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class SupplierPartTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
@ -25,8 +25,8 @@ def hash_barcode(barcode_data):
|
||||
|
||||
barcode_data = ''.join(list(printable_chars))
|
||||
|
||||
hash = hashlib.md5(str(barcode_data).encode())
|
||||
return str(hash.hexdigest())
|
||||
result_hash = hashlib.md5(str(barcode_data).encode())
|
||||
return str(result_hash.hexdigest())
|
||||
|
||||
|
||||
class BarcodeMixin:
|
||||
|
@ -173,8 +173,8 @@ class IntegrationPluginBase(MixinBase, plugin_base.InvenTreePluginBase):
|
||||
"""
|
||||
License of plugin
|
||||
"""
|
||||
license = getattr(self, 'LICENSE', None)
|
||||
return license
|
||||
lic = getattr(self, 'LICENSE', None)
|
||||
return lic
|
||||
# endregion
|
||||
|
||||
@property
|
||||
|
@ -94,10 +94,8 @@ class PluginConfig(models.Model):
|
||||
ret = super().save(force_insert, force_update, *args, **kwargs)
|
||||
|
||||
if not reload:
|
||||
if self.active is False and self.__org_active is True:
|
||||
registry.reload_plugins()
|
||||
|
||||
elif self.active is True and self.__org_active is False:
|
||||
if (self.active is False and self.__org_active is True) or \
|
||||
(self.active is True and self.__org_active is False):
|
||||
registry.reload_plugins()
|
||||
|
||||
return ret
|
||||
|
@ -390,6 +390,10 @@ class PluginsRegistry:
|
||||
logger.warning("activate_integration_schedule failed, database not ready")
|
||||
|
||||
def deactivate_integration_schedule(self):
|
||||
"""
|
||||
Deactivate ScheduleMixin
|
||||
currently nothing is done
|
||||
"""
|
||||
pass
|
||||
|
||||
def activate_integration_app(self, plugins, force_reload=False):
|
||||
|
@ -1022,7 +1022,7 @@ class StockItem(MPTTModel):
|
||||
def has_tracking_info(self):
|
||||
return self.tracking_info_count > 0
|
||||
|
||||
def add_tracking_entry(self, entry_type, user, deltas={}, notes='', **kwargs):
|
||||
def add_tracking_entry(self, entry_type, user, deltas=None, notes='', **kwargs):
|
||||
"""
|
||||
Add a history tracking entry for this StockItem
|
||||
|
||||
@ -1033,6 +1033,8 @@ class StockItem(MPTTModel):
|
||||
notes - User notes associated with this tracking entry
|
||||
url - Optional URL associated with this tracking entry
|
||||
"""
|
||||
if deltas is None:
|
||||
deltas = {}
|
||||
|
||||
# Has a location been specified?
|
||||
location = kwargs.get('location', None)
|
||||
|
Loading…
Reference in New Issue
Block a user