mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	Merge pull request #2402 from matmair/matmair/issue2400
Fix to big / small references
This commit is contained in:
		
							
								
								
									
										9
									
								
								.github/workflows/html.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/html.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -23,11 +23,13 @@ jobs: | |||||||
|       INVENTREE_MEDIA_ROOT: ./media |       INVENTREE_MEDIA_ROOT: ./media | ||||||
|       INVENTREE_STATIC_ROOT: ./static |       INVENTREE_STATIC_ROOT: ./static | ||||||
|     steps: |     steps: | ||||||
|       - name: Install node.js |  | ||||||
|         uses: actions/setup-node@v2 |  | ||||||
|       - run: npm install |  | ||||||
|       - name: Checkout Code |       - name: Checkout Code | ||||||
|         uses: actions/checkout@v2 |         uses: actions/checkout@v2 | ||||||
|  |       - name: Install node.js | ||||||
|  |         uses: actions/setup-node@v2 | ||||||
|  |         with: | ||||||
|  |           node-version: '16' | ||||||
|  |       - run: npm install | ||||||
|       - name: Setup Python |       - name: Setup Python | ||||||
|         uses: actions/setup-python@v2 |         uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
| @@ -41,7 +43,6 @@ jobs: | |||||||
|           invoke static |           invoke static | ||||||
|       - name: Check HTML Files |       - name: Check HTML Files | ||||||
|         run: | |         run: | | ||||||
|           npm install markuplint |  | ||||||
|           npx markuplint InvenTree/build/templates/build/*.html |           npx markuplint InvenTree/build/templates/build/*.html | ||||||
|           npx markuplint InvenTree/company/templates/company/*.html |           npx markuplint InvenTree/company/templates/company/*.html | ||||||
|           npx markuplint InvenTree/order/templates/order/*.html |           npx markuplint InvenTree/order/templates/order/*.html | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								.github/workflows/javascript.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/javascript.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -23,11 +23,13 @@ jobs: | |||||||
|       INVENTREE_MEDIA_ROOT: ./media |       INVENTREE_MEDIA_ROOT: ./media | ||||||
|       INVENTREE_STATIC_ROOT: ./static |       INVENTREE_STATIC_ROOT: ./static | ||||||
|     steps: |     steps: | ||||||
|       - name: Install node.js |  | ||||||
|         uses: actions/setup-node@v2 |  | ||||||
|       - run: npm install |  | ||||||
|       - name: Checkout Code |       - name: Checkout Code | ||||||
|         uses: actions/checkout@v2 |         uses: actions/checkout@v2 | ||||||
|  |       - name: Install node.js | ||||||
|  |         uses: actions/setup-node@v2 | ||||||
|  |         with: | ||||||
|  |           node-version: '16' | ||||||
|  |       - run: npm install | ||||||
|       - name: Setup Python |       - name: Setup Python | ||||||
|         uses: actions/setup-python@v2 |         uses: actions/setup-python@v2 | ||||||
|         with: |         with: | ||||||
| @@ -45,6 +47,5 @@ jobs: | |||||||
|           python check_js_templates.py |           python check_js_templates.py | ||||||
|       - name: Lint Javascript Files |       - name: Lint Javascript Files | ||||||
|         run: | |         run: | | ||||||
|           npm install eslint eslint-config-google |  | ||||||
|           invoke render-js-files |           invoke render-js-files | ||||||
|           npx eslint js_tmp/*.js |           npx eslint js_tmp/*.js | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -78,5 +78,4 @@ locale_stats.json | |||||||
|  |  | ||||||
| # node.js | # node.js | ||||||
| package-lock.json | package-lock.json | ||||||
| package.json |  | ||||||
| node_modules/ | node_modules/ | ||||||
| @@ -49,6 +49,9 @@ class ReferenceIndexingMixin(models.Model): | |||||||
|     """ |     """ | ||||||
|     A mixin for keeping track of numerical copies of the "reference" field. |     A mixin for keeping track of numerical copies of the "reference" field. | ||||||
|  |  | ||||||
|  |     !!DANGER!! always add `ReferenceIndexingSerializerMixin`to all your models serializers to | ||||||
|  |     ensure the reference field is not too big | ||||||
|  |  | ||||||
|     Here, we attempt to convert a "reference" field value (char) to an integer, |     Here, we attempt to convert a "reference" field value (char) to an integer, | ||||||
|     for performing fast natural sorting. |     for performing fast natural sorting. | ||||||
|  |  | ||||||
| @@ -69,22 +72,25 @@ class ReferenceIndexingMixin(models.Model): | |||||||
|  |  | ||||||
|         reference = getattr(self, 'reference', '') |         reference = getattr(self, 'reference', '') | ||||||
|  |  | ||||||
|         # Default value if we cannot convert to an integer |         self.reference_int = extract_int(reference) | ||||||
|         ref_int = 0 |  | ||||||
|  |  | ||||||
|         # Look at the start of the string - can it be "integerized"? |     reference_int = models.BigIntegerField(default=0) | ||||||
|         result = re.match(r"^(\d+)", reference) |  | ||||||
|  |  | ||||||
|         if result and len(result.groups()) == 1: |  | ||||||
|             ref = result.groups()[0] |  | ||||||
|             try: |  | ||||||
|                 ref_int = int(ref) |  | ||||||
|             except: |  | ||||||
|                 ref_int = 0 |  | ||||||
|  |  | ||||||
|         self.reference_int = ref_int | def extract_int(reference): | ||||||
|  |     # Default value if we cannot convert to an integer | ||||||
|  |     ref_int = 0 | ||||||
|  |  | ||||||
|     reference_int = models.IntegerField(default=0) |     # Look at the start of the string - can it be "integerized"? | ||||||
|  |     result = re.match(r"^(\d+)", reference) | ||||||
|  |  | ||||||
|  |     if result and len(result.groups()) == 1: | ||||||
|  |         ref = result.groups()[0] | ||||||
|  |         try: | ||||||
|  |             ref_int = int(ref) | ||||||
|  |         except: | ||||||
|  |             ref_int = 0 | ||||||
|  |     return ref_int | ||||||
|  |  | ||||||
|  |  | ||||||
| class InvenTreeAttachment(models.Model): | class InvenTreeAttachment(models.Model): | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ from django.conf import settings | |||||||
| from django.contrib.auth.models import User | from django.contrib.auth.models import User | ||||||
| from django.core.exceptions import ValidationError as DjangoValidationError | from django.core.exceptions import ValidationError as DjangoValidationError | ||||||
| from django.utils.translation import ugettext_lazy as _ | from django.utils.translation import ugettext_lazy as _ | ||||||
|  | from django.db import models | ||||||
|  |  | ||||||
| from djmoney.contrib.django_rest_framework.fields import MoneyField | from djmoney.contrib.django_rest_framework.fields import MoneyField | ||||||
| from djmoney.money import Money | from djmoney.money import Money | ||||||
| @@ -27,6 +28,8 @@ from rest_framework.fields import empty | |||||||
| from rest_framework.exceptions import ValidationError | from rest_framework.exceptions import ValidationError | ||||||
| from rest_framework.serializers import DecimalField | from rest_framework.serializers import DecimalField | ||||||
|  |  | ||||||
|  | from .models import extract_int | ||||||
|  |  | ||||||
|  |  | ||||||
| class InvenTreeMoneySerializer(MoneyField): | class InvenTreeMoneySerializer(MoneyField): | ||||||
|     """ |     """ | ||||||
| @@ -239,6 +242,17 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): | |||||||
|         return data |         return data | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ReferenceIndexingSerializerMixin(): | ||||||
|  |     """ | ||||||
|  |     This serializer mixin ensures the the reference is not to big / small | ||||||
|  |     for the BigIntegerField | ||||||
|  |     """ | ||||||
|  |     def validate_reference(self, value): | ||||||
|  |         if extract_int(value) > models.BigIntegerField.MAX_BIGINT: | ||||||
|  |             raise serializers.ValidationError('reference is to to big') | ||||||
|  |         return value | ||||||
|  |  | ||||||
|  |  | ||||||
| class InvenTreeAttachmentSerializerField(serializers.FileField): | class InvenTreeAttachmentSerializerField(serializers.FileField): | ||||||
|     """ |     """ | ||||||
|     Override the DRF native FileField serializer, |     Override the DRF native FileField serializer, | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								InvenTree/build/migrations/0034_alter_build_reference_int.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								InvenTree/build/migrations/0034_alter_build_reference_int.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | # Generated by Django 3.2.5 on 2021-12-01 21:39 | ||||||
|  |  | ||||||
|  | from django.db import migrations, models | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  |  | ||||||
|  |     dependencies = [ | ||||||
|  |         ('build', '0033_auto_20211128_0151'), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='build', | ||||||
|  |             name='reference_int', | ||||||
|  |             field=models.BigIntegerField(default=0), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
| @@ -16,7 +16,7 @@ from rest_framework import serializers | |||||||
| from rest_framework.serializers import ValidationError | from rest_framework.serializers import ValidationError | ||||||
|  |  | ||||||
| from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializer | from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializer | ||||||
| from InvenTree.serializers import UserSerializerBrief | from InvenTree.serializers import UserSerializerBrief, ReferenceIndexingSerializerMixin | ||||||
|  |  | ||||||
| import InvenTree.helpers | import InvenTree.helpers | ||||||
| from InvenTree.serializers import InvenTreeDecimalField | from InvenTree.serializers import InvenTreeDecimalField | ||||||
| @@ -32,7 +32,7 @@ from users.serializers import OwnerSerializer | |||||||
| from .models import Build, BuildItem, BuildOrderAttachment | from .models import Build, BuildItem, BuildOrderAttachment | ||||||
|  |  | ||||||
|  |  | ||||||
| class BuildSerializer(InvenTreeModelSerializer): | class BuildSerializer(ReferenceIndexingSerializerMixin, InvenTreeModelSerializer): | ||||||
|     """ |     """ | ||||||
|     Serializes a Build object |     Serializes a Build object | ||||||
|     """ |     """ | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								InvenTree/order/migrations/0054_auto_20211201_2139.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								InvenTree/order/migrations/0054_auto_20211201_2139.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | # Generated by Django 3.2.5 on 2021-12-01 21:39 | ||||||
|  |  | ||||||
|  | from django.db import migrations, models | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  |  | ||||||
|  |     dependencies = [ | ||||||
|  |         ('order', '0053_auto_20211128_0151'), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='purchaseorder', | ||||||
|  |             name='reference_int', | ||||||
|  |             field=models.BigIntegerField(default=0), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='salesorder', | ||||||
|  |             name='reference_int', | ||||||
|  |             field=models.BigIntegerField(default=0), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
| @@ -24,6 +24,7 @@ from InvenTree.serializers import InvenTreeAttachmentSerializer | |||||||
| from InvenTree.serializers import InvenTreeModelSerializer | from InvenTree.serializers import InvenTreeModelSerializer | ||||||
| from InvenTree.serializers import InvenTreeDecimalField | from InvenTree.serializers import InvenTreeDecimalField | ||||||
| from InvenTree.serializers import InvenTreeMoneySerializer | from InvenTree.serializers import InvenTreeMoneySerializer | ||||||
|  | from InvenTree.serializers import ReferenceIndexingSerializerMixin | ||||||
| from InvenTree.status_codes import StockStatus | from InvenTree.status_codes import StockStatus | ||||||
|  |  | ||||||
| from part.serializers import PartBriefSerializer | from part.serializers import PartBriefSerializer | ||||||
| @@ -39,7 +40,7 @@ from .models import SalesOrderAllocation | |||||||
| from users.serializers import OwnerSerializer | from users.serializers import OwnerSerializer | ||||||
|  |  | ||||||
|  |  | ||||||
| class POSerializer(InvenTreeModelSerializer): | class POSerializer(ReferenceIndexingSerializerMixin, InvenTreeModelSerializer): | ||||||
|     """ Serializer for a PurchaseOrder object """ |     """ Serializer for a PurchaseOrder object """ | ||||||
|  |  | ||||||
|     def __init__(self, *args, **kwargs): |     def __init__(self, *args, **kwargs): | ||||||
| @@ -394,7 +395,7 @@ class POAttachmentSerializer(InvenTreeAttachmentSerializer): | |||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| class SalesOrderSerializer(InvenTreeModelSerializer): | class SalesOrderSerializer(ReferenceIndexingSerializerMixin, InvenTreeModelSerializer): | ||||||
|     """ |     """ | ||||||
|     Serializers for the SalesOrder object |     Serializers for the SalesOrder object | ||||||
|     """ |     """ | ||||||
|   | |||||||
| @@ -105,6 +105,25 @@ class PurchaseOrderTest(OrderTest): | |||||||
|         self.assertEqual(data['pk'], 1) |         self.assertEqual(data['pk'], 1) | ||||||
|         self.assertEqual(data['description'], 'Ordering some screws') |         self.assertEqual(data['description'], 'Ordering some screws') | ||||||
|  |  | ||||||
|  |     def test_po_reference(self): | ||||||
|  |         """test that a reference with a too big / small reference is not possible""" | ||||||
|  |         # get permissions | ||||||
|  |         self.assignRole('purchase_order.add') | ||||||
|  |  | ||||||
|  |         url = reverse('api-po-list') | ||||||
|  |         huge_numer = 9223372036854775808 | ||||||
|  |  | ||||||
|  |         # too big | ||||||
|  |         self.post( | ||||||
|  |             url, | ||||||
|  |             { | ||||||
|  |                 'supplier': 1, | ||||||
|  |                 'reference': huge_numer, | ||||||
|  |                 'description': 'PO not created via the API', | ||||||
|  |             }, | ||||||
|  |             expected_code=400 | ||||||
|  |         ) | ||||||
|  |  | ||||||
|     def test_po_attachments(self): |     def test_po_attachments(self): | ||||||
|  |  | ||||||
|         url = reverse('api-po-attachment-list') |         url = reverse('api-po-attachment-list') | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ Stock database model definitions | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| import os | import os | ||||||
| import re |  | ||||||
|  |  | ||||||
| from django.utils.translation import gettext_lazy as _ | from django.utils.translation import gettext_lazy as _ | ||||||
| from django.core.exceptions import ValidationError, FieldError | from django.core.exceptions import ValidationError, FieldError | ||||||
| @@ -39,6 +38,7 @@ import label.models | |||||||
| from InvenTree.status_codes import StockStatus, StockHistoryCode | from InvenTree.status_codes import StockStatus, StockHistoryCode | ||||||
| from InvenTree.models import InvenTreeTree, InvenTreeAttachment | from InvenTree.models import InvenTreeTree, InvenTreeAttachment | ||||||
| from InvenTree.fields import InvenTreeModelMoneyField, InvenTreeURLField | from InvenTree.fields import InvenTreeModelMoneyField, InvenTreeURLField | ||||||
|  | from InvenTree.serializers import extract_int | ||||||
|  |  | ||||||
| from users.models import Owner | from users.models import Owner | ||||||
|  |  | ||||||
| @@ -236,17 +236,7 @@ class StockItem(MPTTModel): | |||||||
|         serial_int = 0 |         serial_int = 0 | ||||||
|  |  | ||||||
|         if serial is not None: |         if serial is not None: | ||||||
|  |             serial_int = extract_int(str(serial)) | ||||||
|             serial = str(serial) |  | ||||||
|  |  | ||||||
|             # Look at the start of the string - can it be "integerized"? |  | ||||||
|             result = re.match(r'^(\d+)', serial) |  | ||||||
|  |  | ||||||
|             if result and len(result.groups()) == 1: |  | ||||||
|                 try: |  | ||||||
|                     serial_int = int(result.groups()[0]) |  | ||||||
|                 except: |  | ||||||
|                     serial_int = 0 |  | ||||||
|  |  | ||||||
|         self.serial_int = serial_int |         self.serial_int = serial_int | ||||||
|  |  | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ from company.serializers import SupplierPartSerializer | |||||||
|  |  | ||||||
| import InvenTree.helpers | import InvenTree.helpers | ||||||
| import InvenTree.serializers | import InvenTree.serializers | ||||||
| from InvenTree.serializers import InvenTreeDecimalField | from InvenTree.serializers import InvenTreeDecimalField, extract_int | ||||||
|  |  | ||||||
| from part.serializers import PartBriefSerializer | from part.serializers import PartBriefSerializer | ||||||
|  |  | ||||||
| @@ -73,6 +73,11 @@ class StockItemSerializerBrief(InvenTree.serializers.InvenTreeModelSerializer): | |||||||
|             'uid', |             'uid', | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |     def validate_serial(self, value): | ||||||
|  |         if extract_int(value) > 2147483647: | ||||||
|  |             raise serializers.ValidationError('serial is to to big') | ||||||
|  |         return value | ||||||
|  |  | ||||||
|  |  | ||||||
| class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer): | class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer): | ||||||
|     """ Serializer for a StockItem: |     """ Serializer for a StockItem: | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "dependencies": { | ||||||
|  |     "eslint": "^8.3.0", | ||||||
|  |     "eslint-config-google": "^0.14.0", | ||||||
|  |     "markuplint": "^1.11.4" | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user