Merge branch 'master' of https://github.com/inventree/InvenTree into plugin-2037

This commit is contained in:
Matthias 2021-12-02 17:16:26 +01:00
commit 329b00ae07
No known key found for this signature in database
GPG Key ID: F50EF5741D33E076
15 changed files with 136 additions and 47 deletions

View File

@ -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

View File

@ -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

2
.gitignore vendored
View File

@ -77,8 +77,6 @@ dev/
locale_stats.json locale_stats.json
# node.js # node.js
package-lock.json
package.json
node_modules/ node_modules/
# maintenance locker # maintenance locker

View File

@ -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):

View File

@ -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,

View 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),
),
]

View File

@ -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
""" """

View 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),
),
]

View File

@ -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
""" """

View File

@ -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')

View File

@ -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

View File

@ -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:

View File

@ -40,8 +40,8 @@
<link rel="stylesheet" href="{% static 'bootstrap-table/extensions/group-by-v2/bootstrap-table-group-by.css' %}"> <link rel="stylesheet" href="{% static 'bootstrap-table/extensions/group-by-v2/bootstrap-table-group-by.css' %}">
<link rel="stylesheet" href="{% static 'bootstrap-table/extensions/filter-control/bootstrap-table-filter-control.css' %}"> <link rel="stylesheet" href="{% static 'bootstrap-table/extensions/filter-control/bootstrap-table-filter-control.css' %}">
<link rel='stylesheet' href='{% static "treegrid/css/jquery.treegrid.css" %}'> <link rel='stylesheet' href='{% static "treegrid/css/jquery.treegrid.css" %}'>
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}"> <link rel="stylesheet" href="{% static 'fontawesome/css/brands.min.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}"> <link rel="stylesheet" href="{% static 'fontawesome/css/solid.min.css' %}">
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}"> <link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
<link rel="stylesheet" href="{% static 'select2/css/select2-bootstrap-5-theme.css' %}"> <link rel="stylesheet" href="{% static 'select2/css/select2-bootstrap-5-theme.css' %}">
<link rel="stylesheet" href="{% static 'fullcalendar/main.css' %}"> <link rel="stylesheet" href="{% static 'fullcalendar/main.css' %}">

View File

@ -153,12 +153,7 @@ function partFields(options={}) {
delete fields['default_expiry']; delete fields['default_expiry'];
} }
// Additional fields when "creating" a new part if (options.create || options.duplicate) {
if (options.create) {
// No supplier parts available yet
delete fields['default_supplier'];
if (global_settings.PART_CREATE_INITIAL) { if (global_settings.PART_CREATE_INITIAL) {
fields.initial_stock = { fields.initial_stock = {
@ -187,6 +182,13 @@ function partFields(options={}) {
group: 'create', group: 'create',
}; };
} }
}
// Additional fields when "creating" a new part
if (options.create) {
// No supplier parts available yet
delete fields['default_supplier'];
fields.copy_category_parameters = { fields.copy_category_parameters = {
type: 'boolean', type: 'boolean',
@ -349,6 +351,10 @@ function duplicatePart(pk, options={}) {
duplicate: pk, duplicate: pk,
}); });
if (fields.initial_stock_location) {
fields.initial_stock_location.value = data.default_location;
}
// Remove "default_supplier" field // Remove "default_supplier" field
delete fields['default_supplier']; delete fields['default_supplier'];

7
package.json Normal file
View File

@ -0,0 +1,7 @@
{
"dependencies": {
"eslint": "^8.3.0",
"eslint-config-google": "^0.14.0",
"markuplint": "^1.11.4"
}
}