2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-05 14:58:50 +00:00

Merge branch 'master' of https://github.com/inventree/InvenTree into style-fixes

This commit is contained in:
Matthias Mair 2022-05-21 23:57:41 +02:00
commit 5805685c48
28 changed files with 296 additions and 483 deletions

View File

@ -13,10 +13,7 @@ from django.http.response import StreamingHttpResponse
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
class InvenTreeAPITestCase(APITestCase): class UserMixin:
"""
Base class for running InvenTree API tests
"""
# User information # User information
username = 'testuser' username = 'testuser'
@ -53,37 +50,49 @@ class InvenTreeAPITestCase(APITestCase):
self.user.save() self.user.save()
for role in self.roles: # Assign all roles if set
self.assignRole(role) if self.roles == 'all':
self.assignRole(assign_all=True)
# else filter the roles
else:
for role in self.roles:
self.assignRole(role)
if self.auto_login: if self.auto_login:
self.client.login(username=self.username, password=self.password) self.client.login(username=self.username, password=self.password)
def assignRole(self, role): def assignRole(self, role=None, assign_all: bool = False):
""" """
Set the user roles for the registered user Set the user roles for the registered user
""" """
# role is of the format 'rule.permission' e.g. 'part.add' # role is of the format 'rule.permission' e.g. 'part.add'
rule, perm = role.split('.') if not assign_all and role:
rule, perm = role.split('.')
for ruleset in self.group.rule_sets.all(): for ruleset in self.group.rule_sets.all():
if ruleset.name == rule: if assign_all or ruleset.name == rule:
if perm == 'view': if assign_all or perm == 'view':
ruleset.can_view = True ruleset.can_view = True
elif perm == 'change': elif assign_all or perm == 'change':
ruleset.can_change = True ruleset.can_change = True
elif perm == 'delete': elif assign_all or perm == 'delete':
ruleset.can_delete = True ruleset.can_delete = True
elif perm == 'add': elif assign_all or perm == 'add':
ruleset.can_add = True ruleset.can_add = True
ruleset.save() ruleset.save()
break break
class InvenTreeAPITestCase(UserMixin, APITestCase):
"""
Base class for running InvenTree API tests
"""
def getActions(self, url): def getActions(self, url):
""" """
Return a dict of the 'actions' available at a given endpoint. Return a dict of the 'actions' available at a given endpoint.

View File

@ -4,13 +4,12 @@ only used for testing the js files! - This file is omited from coverage
""" """
import os # pragma: no cover import os # pragma: no cover
import pathlib # pragma: no cover import pathlib
from django.contrib.auth import get_user_model # pragma: no cover from InvenTree.helpers import InvenTreeTestCase # pragma: no cover
from django.test import TestCase # pragma: no cover
class RenderJavascriptFiles(TestCase): # pragma: no cover class RenderJavascriptFiles(InvenTreeTestCase): # pragma: no cover
""" """
A unit test to "render" javascript files. A unit test to "render" javascript files.
@ -18,18 +17,6 @@ class RenderJavascriptFiles(TestCase): # pragma: no cover
we need the fully-rendered files for linting and static tests. we need the fully-rendered files for linting and static tests.
""" """
def setUp(self):
user = get_user_model()
self.user = user.objects.create_user(
username='testuser',
password='testpassword',
email='user@gmail.com',
)
self.client.login(username='testuser', password='testpassword')
def download_file(self, filename, prefix): def download_file(self, filename, prefix):
url = os.path.join(prefix, filename) url = os.path.join(prefix, filename)

View File

@ -12,6 +12,7 @@ from wsgiref.util import FileWrapper
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.core.exceptions import FieldError, ValidationError from django.core.exceptions import FieldError, ValidationError
from django.http import StreamingHttpResponse from django.http import StreamingHttpResponse
from django.test import TestCase
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from djmoney.money import Money from djmoney.money import Money
@ -21,6 +22,7 @@ import InvenTree.version
from common.models import InvenTreeSetting from common.models import InvenTreeSetting
from common.settings import currency_code_default from common.settings import currency_code_default
from .api_tester import UserMixin
from .settings import MEDIA_URL, STATIC_URL from .settings import MEDIA_URL, STATIC_URL
@ -779,3 +781,7 @@ def inheritors(cls):
subcls.add(child) subcls.add(child)
work.append(child) work.append(child)
return subcls return subcls
class InvenTreeTestCase(UserMixin, TestCase):
pass

View File

@ -2,18 +2,16 @@
from base64 import b64encode from base64 import b64encode
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
from InvenTree.api_tester import InvenTreeAPITestCase from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.helpers import InvenTreeTestCase
from users.models import RuleSet from users.models import RuleSet
class HTMLAPITests(TestCase): class HTMLAPITests(InvenTreeTestCase):
""" """
Test that we can access the REST API endpoints via the HTML interface. Test that we can access the REST API endpoints via the HTML interface.
@ -21,33 +19,7 @@ class HTMLAPITests(TestCase):
which raised an AssertionError when using the HTML API interface, which raised an AssertionError when using the HTML API interface,
while the regular JSON interface continued to work as expected. while the regular JSON interface continued to work as expected.
""" """
roles = 'all'
def setUp(self):
super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password')
def test_part_api(self): def test_part_api(self):
url = reverse('api-part-list') url = reverse('api-part-list')

View File

@ -1,11 +1,11 @@
"""Tests for middleware functions""" """Tests for middleware functions"""
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
class MiddlewareTests(TestCase):
class MiddlewareTests(InvenTreeTestCase):
"""Test for middleware functions""" """Test for middleware functions"""
def check_path(self, url, code=200, **kwargs): def check_path(self, url, code=200, **kwargs):
@ -13,15 +13,6 @@ class MiddlewareTests(TestCase):
self.assertEqual(response.status_code, code) self.assertEqual(response.status_code, code)
return response return response
def setUp(self):
super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user(username='username', email='user@email.com', password='password')
self.client.login(username='username', password='password')
def test_AuthRequiredMiddleware(self): def test_AuthRequiredMiddleware(self):
"""Test the auth middleware""" """Test the auth middleware"""

View File

@ -5,28 +5,17 @@ Unit tests for the main web views
import os import os
import re import re
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
class ViewTests(TestCase):
class ViewTests(InvenTreeTestCase):
""" Tests for various top-level views """ """ Tests for various top-level views """
username = 'test_user' username = 'test_user'
password = 'test_pass' password = 'test_pass'
def setUp(self):
# Create a user
self.user = get_user_model().objects.create_user(self.username, 'user@email.com', self.password)
self.user.set_password(self.password)
self.user.save()
result = self.client.login(username=self.username, password=self.password)
self.assertEqual(result, True)
def test_api_doc(self): def test_api_doc(self):
""" Test that the api-doc view works """ """ Test that the api-doc view works """

View File

@ -450,18 +450,12 @@ class TestStatus(TestCase):
self.assertEqual(ready.isImportingData(), False) self.assertEqual(ready.isImportingData(), False)
class TestSettings(TestCase): class TestSettings(helpers.InvenTreeTestCase):
""" """
Unit tests for settings Unit tests for settings
""" """
def setUp(self) -> None: superuser = True
self.user_mdl = get_user_model()
# Create a user for auth
user = get_user_model()
self.user = user.objects.create_superuser('testuser1', 'test1@testing.com', 'password1')
self.client.login(username='testuser1', password='password1')
def in_env_context(self, envs={}): def in_env_context(self, envs={}):
"""Patch the env to include the given dict""" """Patch the env to include the given dict"""
@ -476,8 +470,9 @@ class TestSettings(TestCase):
@override_settings(TESTING_ENV=True) @override_settings(TESTING_ENV=True)
def test_set_user_to_few(self): def test_set_user_to_few(self):
user_model = get_user_model()
# add shortcut # add shortcut
user_count = self.user_mdl.objects.count user_count = user_model.objects.count
# enable testing mode # enable testing mode
settings.TESTING_ENV = True settings.TESTING_ENV = True
@ -499,14 +494,18 @@ class TestSettings(TestCase):
}) })
self.assertEqual(user_count(), 2) self.assertEqual(user_count(), 2)
username2 = 'testuser1'
email2 = 'test1@testing.com'
password2 = 'password1'
# create user manually # create user manually
self.user_mdl.objects.create_user('testuser', 'test@testing.com', 'password') user_model.objects.create_user(username2, email2, password2)
self.assertEqual(user_count(), 3) self.assertEqual(user_count(), 3)
# check it will not be created again # check it will not be created again
self.run_reload({ self.run_reload({
'INVENTREE_ADMIN_USER': 'testuser', 'INVENTREE_ADMIN_USER': username2,
'INVENTREE_ADMIN_EMAIL': 'test@testing.com', 'INVENTREE_ADMIN_EMAIL': email2,
'INVENTREE_ADMIN_PASSWORD': 'password', 'INVENTREE_ADMIN_PASSWORD': password2,
}) })
self.assertEqual(user_count(), 3) self.assertEqual(user_count(), 3)
@ -541,7 +540,7 @@ class TestSettings(TestCase):
# with env set # with env set
with self.in_env_context({'INVENTREE_CONFIG_FILE': 'my_special_conf.yaml'}): with self.in_env_context({'INVENTREE_CONFIG_FILE': 'my_special_conf.yaml'}):
self.assertIn('inventree/inventree/my_special_conf.yaml', config.get_config_file().lower()) self.assertIn('inventree/my_special_conf.yaml', config.get_config_file().lower())
def test_helpers_plugin_file(self): def test_helpers_plugin_file(self):
# normal run - not configured # normal run - not configured
@ -567,18 +566,11 @@ class TestSettings(TestCase):
self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321') self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321')
class TestInstanceName(TestCase): class TestInstanceName(helpers.InvenTreeTestCase):
""" """
Unit tests for instance name Unit tests for instance name
""" """
def setUp(self):
# Create a user for auth
user = get_user_model()
self.user = user.objects.create_superuser('testuser', 'test@testing.com', 'password')
self.client.login(username='testuser', password='password')
def test_instance_name(self): def test_instance_name(self):
# default setting # default setting

View File

@ -2,10 +2,6 @@ from datetime import datetime, timedelta
from django.urls import reverse from django.urls import reverse
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from rest_framework.test import APITestCase
from rest_framework import status from rest_framework import status
from part.models import Part from part.models import Part
@ -16,7 +12,7 @@ from InvenTree.status_codes import BuildStatus
from InvenTree.api_tester import InvenTreeAPITestCase from InvenTree.api_tester import InvenTreeAPITestCase
class TestBuildAPI(APITestCase): class TestBuildAPI(InvenTreeAPITestCase):
""" """
Series of tests for the Build DRF API Series of tests for the Build DRF API
- Tests for Build API - Tests for Build API
@ -30,25 +26,11 @@ class TestBuildAPI(APITestCase):
'build', 'build',
] ]
def setUp(self): roles = [
# Create a user for auth 'build.change',
user = get_user_model() 'build.add',
self.user = user.objects.create_user('testuser', 'test@testing.com', 'password') 'build.delete',
]
g = Group.objects.create(name='builders')
self.user.groups.add(g)
for rule in g.rule_sets.all():
if rule.name == 'build':
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
g.save()
self.client.login(username='testuser', password='password')
def test_get_build_list(self): def test_get_build_list(self):
""" """

View File

@ -1,18 +1,16 @@
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from datetime import datetime, timedelta from datetime import datetime, timedelta
from InvenTree.helpers import InvenTreeTestCase
from .models import Build from .models import Build
from stock.models import StockItem from stock.models import StockItem
from InvenTree.status_codes import BuildStatus from InvenTree.status_codes import BuildStatus
class BuildTestSimple(TestCase): class BuildTestSimple(InvenTreeTestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -21,27 +19,11 @@ class BuildTestSimple(TestCase):
'build', 'build',
] ]
def setUp(self): roles = [
# Create a user for auth 'build.change',
user = get_user_model() 'build.add',
user.objects.create_user('testuser', 'test@testing.com', 'password') 'build.delete',
]
self.user = user.objects.get(username='testuser')
g = Group.objects.create(name='builders')
self.user.groups.add(g)
for rule in g.rule_sets.all():
if rule.name == 'build':
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
g.save()
self.client.login(username='testuser', password='password')
def test_build_objects(self): def test_build_objects(self):
# Ensure the Build objects were correctly created # Ensure the Build objects were correctly created
@ -106,7 +88,7 @@ class BuildTestSimple(TestCase):
self.assertEqual(build.status, BuildStatus.CANCELLED) self.assertEqual(build.status, BuildStatus.CANCELLED)
class TestBuildViews(TestCase): class TestBuildViews(InvenTreeTestCase):
""" Tests for Build app views """ """ Tests for Build app views """
fixtures = [ fixtures = [
@ -116,28 +98,15 @@ class TestBuildViews(TestCase):
'build', 'build',
] ]
roles = [
'build.change',
'build.add',
'build.delete',
]
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user('username', 'user@email.com', 'password')
g = Group.objects.create(name='builders')
self.user.groups.add(g)
for rule in g.rule_sets.all():
if rule.name == 'build':
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
g.save()
self.client.login(username='username', password='password')
# Create a build output for build # 1 # Create a build output for build # 1
self.build = Build.objects.get(pk=1) self.build = Build.objects.get(pk=1)

View File

@ -3,12 +3,11 @@ import json
from datetime import timedelta from datetime import timedelta
from http import HTTPStatus from http import HTTPStatus
from django.contrib.auth import get_user_model
from django.test import Client, TestCase from django.test import Client, TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.api_tester import InvenTreeAPITestCase from InvenTree.api_tester import InvenTreeAPITestCase
from InvenTree.helpers import str2bool from InvenTree.helpers import InvenTreeTestCase, str2bool
from plugin import registry from plugin import registry
from plugin.models import NotificationUserSetting, PluginConfig from plugin.models import NotificationUserSetting, PluginConfig
@ -19,7 +18,7 @@ from .models import (ColorTheme, InvenTreeSetting, InvenTreeUserSetting,
CONTENT_TYPE_JSON = 'application/json' CONTENT_TYPE_JSON = 'application/json'
class SettingsTest(TestCase): class SettingsTest(InvenTreeTestCase):
""" """
Tests for the 'settings' model Tests for the 'settings' model
""" """
@ -28,16 +27,6 @@ class SettingsTest(TestCase):
'settings', 'settings',
] ]
def setUp(self):
user = get_user_model()
self.user = user.objects.create_user('username', 'user@email.com', 'password')
self.user.is_staff = True
self.user.save()
self.client.login(username='username', password='password')
def test_settings_objects(self): def test_settings_objects(self):
# There should be two settings objects in the database # There should be two settings objects in the database

View File

@ -1,12 +1,11 @@
""" Unit tests for Company views (see views.py) """ """ Unit tests for Company views (see views.py) """
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
class CompanyViewTestBase(TestCase):
class CompanyViewTestBase(InvenTreeTestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -17,32 +16,7 @@ class CompanyViewTestBase(TestCase):
'supplier_part', 'supplier_part',
] ]
def setUp(self): roles = 'all'
super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password')
class CompanyViewTest(CompanyViewTestBase): class CompanyViewTest(CompanyViewTestBase):

View File

@ -57,6 +57,7 @@ src="{% static 'img/blank_image.png' %}"
<ul class='dropdown-menu' role='menu'> <ul class='dropdown-menu' role='menu'>
<li><a class='dropdown-item' href='#' id='edit-order'><span class='fas fa-edit icon-green'></span> {% trans "Edit order" %}</a></li> <li><a class='dropdown-item' href='#' id='edit-order'><span class='fas fa-edit icon-green'></span> {% trans "Edit order" %}</a></li>
{% if order.status == SalesOrderStatus.PENDING %} {% if order.status == SalesOrderStatus.PENDING %}
<li><a class='dropdown-item' href='#' id='complete-order-shipments'><span class='fas fa-truck'></span> {% trans "Complete Shipments" %}</a></li>
<li><a class='dropdown-item' href='#' id='cancel-order'><span class='fas fa-times-circle icon-red'></span> {% trans "Cancel order" %}</a></li> <li><a class='dropdown-item' href='#' id='cancel-order'><span class='fas fa-times-circle icon-red'></span> {% trans "Cancel order" %}</a></li>
{% endif %} {% endif %}
</ul> </ul>
@ -223,6 +224,16 @@ $("#edit-order").click(function() {
}); });
}); });
$("#complete-order-shipments").click(function() {
completePendingShipments(
{{ order.pk }},
{
reload: true,
}
);
});
$("#cancel-order").click(function() { $("#cancel-order").click(function() {
cancelSalesOrder( cancelSalesOrder(

View File

@ -1,12 +1,11 @@
""" Unit tests for Order views (see views.py) """ """ Unit tests for Order views (see views.py) """
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
class OrderViewTestCase(TestCase):
class OrderViewTestCase(InvenTreeTestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -19,27 +18,14 @@ class OrderViewTestCase(TestCase):
'order', 'order',
] ]
def setUp(self): roles = [
super().setUp() 'purchase_order.change',
'purchase_order.add',
# Create a user 'purchase_order.delete',
user = get_user_model().objects.create_user('username', 'user@email.com', 'password') 'sales_order.change',
'sales_order.add',
# Ensure that the user has the correct permissions! 'sales_order.delete',
g = Group.objects.create(name='orders') ]
user.groups.add(g)
for rule in g.rule_sets.all():
if rule.name in ['purchase_order', 'sales_order']:
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
g.save()
self.client.login(username='username', password='password')
class OrderListTest(OrderViewTestCase): class OrderListTest(OrderViewTestCase):

View File

@ -4,13 +4,12 @@ Unit testing for BOM export functionality
import csv import csv
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
class BomExportTest(TestCase):
class BomExportTest(InvenTreeTestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -19,33 +18,11 @@ class BomExportTest(TestCase):
'bom', 'bom',
] ]
roles = 'all'
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password')
self.url = reverse('bom-download', kwargs={'pk': 100}) self.url = reverse('bom-download', kwargs={'pk': 100})
def test_bom_template(self): def test_bom_template(self):

View File

@ -3,7 +3,6 @@
import os import os
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.test import TestCase from django.test import TestCase
@ -14,21 +13,16 @@ from common.models import (InvenTreeSetting, InvenTreeUserSetting,
NotificationEntry, NotificationMessage) NotificationEntry, NotificationMessage)
from common.notifications import UIMessageNotification, storage from common.notifications import UIMessageNotification, storage
from InvenTree import version from InvenTree import version
from InvenTree.helpers import InvenTreeTestCase
from .models import (Part, PartCategory, PartCategoryStar, PartStar, from .models import (Part, PartCategory, PartCategoryStar, PartStar,
PartTestTemplate, rename_part_image) PartTestTemplate, rename_part_image)
from .templatetags import inventree_extras from .templatetags import inventree_extras
class TemplateTagTest(TestCase): class TemplateTagTest(InvenTreeTestCase):
""" Tests for the custom template tag code """ """ Tests for the custom template tag code """
def setUp(self):
# Create a user for auth
user = get_user_model()
self.user = user.objects.create_user('testuser', 'test@testing.com', 'password')
self.client.login(username='testuser', password='password')
def test_define(self): def test_define(self):
self.assertEqual(int(inventree_extras.define(3)), 3) self.assertEqual(int(inventree_extras.define(3)), 3)
@ -329,24 +323,13 @@ class TestTemplateTest(TestCase):
self.assertEqual(variant.getTestTemplates().count(), n + 1) self.assertEqual(variant.getTestTemplates().count(), n + 1)
class PartSettingsTest(TestCase): class PartSettingsTest(InvenTreeTestCase):
""" """
Tests to ensure that the user-configurable default values work as expected. Tests to ensure that the user-configurable default values work as expected.
Some fields for the Part model can have default values specified by the user. Some fields for the Part model can have default values specified by the user.
""" """
def setUp(self):
# Create a user for auth
user = get_user_model()
self.user = user.objects.create_user(
username='testuser',
email='test@testing.com',
password='password',
is_staff=True
)
def make_part(self): def make_part(self):
""" """
Helper function to create a simple part Helper function to create a simple part
@ -460,7 +443,7 @@ class PartSettingsTest(TestCase):
Part.objects.create(name='abc', revision='6', description='A part', IPN=' ') Part.objects.create(name='abc', revision='6', description='A part', IPN=' ')
class PartSubscriptionTests(TestCase): class PartSubscriptionTests(InvenTreeTestCase):
fixtures = [ fixtures = [
'location', 'location',
@ -469,15 +452,7 @@ class PartSubscriptionTests(TestCase):
] ]
def setUp(self): def setUp(self):
# Create a user for auth super().setUp()
user = get_user_model()
self.user = user.objects.create_user(
username='testuser',
email='test@testing.com',
password='password',
is_staff=True
)
# electronics / IC / MCU # electronics / IC / MCU
self.category = PartCategory.objects.get(pk=4) self.category = PartCategory.objects.get(pk=4)
@ -577,7 +552,7 @@ class PartSubscriptionTests(TestCase):
self.assertTrue(self.part.is_starred_by(self.user)) self.assertTrue(self.part.is_starred_by(self.user))
class BaseNotificationIntegrationTest(TestCase): class BaseNotificationIntegrationTest(InvenTreeTestCase):
""" Integration test for notifications """ """ Integration test for notifications """
fixtures = [ fixtures = [
@ -588,15 +563,7 @@ class BaseNotificationIntegrationTest(TestCase):
] ]
def setUp(self): def setUp(self):
# Create a user for auth super().setUp()
user = get_user_model()
self.user = user.objects.create_user(
username='testuser',
email='test@testing.com',
password='password',
is_staff=True
)
# Add Mailadress # Add Mailadress
EmailAddress.objects.create(user=self.user, email='test@testing.com') EmailAddress.objects.create(user=self.user, email='test@testing.com')

View File

@ -1,14 +1,13 @@
""" Unit tests for Part Views (see views.py) """ """ Unit tests for Part Views (see views.py) """
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
from .models import Part from .models import Part
class PartViewTestCase(TestCase): class PartViewTestCase(InvenTreeTestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -19,33 +18,12 @@ class PartViewTestCase(TestCase):
'supplier_part', 'supplier_part',
] ]
roles = 'all'
superuser = True
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password')
class PartListTest(PartViewTestCase): class PartListTest(PartViewTestCase):

View File

@ -1,8 +1,8 @@
""" Unit tests for action plugins """ """ Unit tests for action plugins """
from django.contrib.auth import get_user_model
from django.test import TestCase from django.test import TestCase
from InvenTree.helpers import InvenTreeTestCase
from plugin import InvenTreePlugin from plugin import InvenTreePlugin
from plugin.mixins import ActionMixin from plugin.mixins import ActionMixin
@ -65,15 +65,9 @@ class ActionMixinTests(TestCase):
}) })
class APITests(TestCase): class APITests(InvenTreeTestCase):
""" Tests for action api """ """ Tests for action api """
def setUp(self):
# Create a user for auth
user = get_user_model()
self.test_user = user.objects.create_user('testuser', 'test@testing.com', 'password')
self.client.login(username='testuser', password='password')
def test_post_errors(self): def test_post_errors(self):
"""Check the possible errors with post""" """Check the possible errors with post"""

View File

@ -4,16 +4,15 @@
Unit tests for Barcode endpoints Unit tests for Barcode endpoints
""" """
from django.contrib.auth import get_user_model
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase
from InvenTree.api_tester import InvenTreeAPITestCase
from stock.models import StockItem from stock.models import StockItem
class BarcodeAPITest(APITestCase): class BarcodeAPITest(InvenTreeAPITestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -23,11 +22,7 @@ class BarcodeAPITest(APITestCase):
] ]
def setUp(self): def setUp(self):
# Create a user for auth super().setUp()
user = get_user_model()
user.objects.create_user('testuser', 'test@testing.com', 'password')
self.client.login(username='testuser', password='password')
self.scan_url = reverse('api-barcode-scan') self.scan_url = reverse('api-barcode-scan')
self.assign_url = reverse('api-barcode-link') self.assign_url = reverse('api-barcode-link')

View File

@ -1,13 +1,12 @@
""" Unit tests for base mixins for plugins """ """ Unit tests for base mixins for plugins """
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase from django.test import TestCase
from django.urls import include, re_path, reverse from django.urls import include, re_path, reverse
from error_report.models import Error from error_report.models import Error
from InvenTree.helpers import InvenTreeTestCase
from plugin import InvenTreePlugin from plugin import InvenTreePlugin
from plugin.helpers import MixinNotImplementedError from plugin.helpers import MixinNotImplementedError
from plugin.mixins import (APICallMixin, AppMixin, NavigationMixin, from plugin.mixins import (APICallMixin, AppMixin, NavigationMixin,
@ -24,7 +23,7 @@ class BaseMixinDefinition:
self.assertIn(self.MIXIN_HUMAN_NAME, [item['human_name'] for item in self.mixin.registered_mixins]) self.assertIn(self.MIXIN_HUMAN_NAME, [item['human_name'] for item in self.mixin.registered_mixins])
class SettingsMixinTest(BaseMixinDefinition, TestCase): class SettingsMixinTest(BaseMixinDefinition, InvenTreeTestCase):
MIXIN_HUMAN_NAME = 'Settings' MIXIN_HUMAN_NAME = 'Settings'
MIXIN_NAME = 'settings' MIXIN_NAME = 'settings'
MIXIN_ENABLE_CHECK = 'has_settings' MIXIN_ENABLE_CHECK = 'has_settings'
@ -40,9 +39,7 @@ class SettingsMixinTest(BaseMixinDefinition, TestCase):
pass pass
self.mixin_nothing = NoSettingsCls() self.mixin_nothing = NoSettingsCls()
user = get_user_model() super().setUp()
self.test_user = user.objects.create_user('testuser', 'test@testing.com', 'password')
self.test_user.is_staff = True
def test_function(self): def test_function(self):
# settings variable # settings variable
@ -54,7 +51,7 @@ class SettingsMixinTest(BaseMixinDefinition, TestCase):
self.assertEqual(self.mixin_nothing.get_setting('ABCD'), '') self.assertEqual(self.mixin_nothing.get_setting('ABCD'), '')
# right setting # right setting
self.mixin.set_setting('SETTING1', '12345', self.test_user) self.mixin.set_setting('SETTING1', '12345', self.user)
self.assertEqual(self.mixin.get_setting('SETTING1'), '12345') self.assertEqual(self.mixin.get_setting('SETTING1'), '12345')
# no setting # no setting
@ -251,7 +248,7 @@ class APICallMixinTest(BaseMixinDefinition, TestCase):
self.mixin_wrong2.has_api_call() self.mixin_wrong2.has_api_call()
class PanelMixinTests(TestCase): class PanelMixinTests(InvenTreeTestCase):
"""Test that the PanelMixin plugin operates correctly""" """Test that the PanelMixin plugin operates correctly"""
fixtures = [ fixtures = [
@ -261,32 +258,7 @@ class PanelMixinTests(TestCase):
'stock', 'stock',
] ]
def setUp(self): roles = 'all'
super().setUp()
# Create a user which has all the privelages
user = get_user_model()
self.user = user.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password')
def test_installed(self): def test_installed(self):
"""Test that the sample panel plugin is installed""" """Test that the sample panel plugin is installed"""

View File

@ -1,20 +1,15 @@
""" Unit tests for action plugins """ """ Unit tests for action plugins """
from django.contrib.auth import get_user_model from InvenTree.helpers import InvenTreeTestCase
from django.test import TestCase
from plugin.builtin.action.simpleactionplugin import SimpleActionPlugin from plugin.builtin.action.simpleactionplugin import SimpleActionPlugin
class SimpleActionPluginTests(TestCase): class SimpleActionPluginTests(InvenTreeTestCase):
""" Tests for SampleIntegrationPlugin """ """ Tests for SampleIntegrationPlugin """
def setUp(self): def setUp(self):
# Create a user for auth super().setUp()
user = get_user_model()
self.test_user = user.objects.create_user('testuser', 'test@testing.com', 'password')
self.client.login(username='testuser', password='password')
self.plugin = SimpleActionPlugin() self.plugin = SimpleActionPlugin()
def test_name(self): def test_name(self):
@ -33,7 +28,7 @@ class SimpleActionPluginTests(TestCase):
"action": 'simple', "action": 'simple',
"result": True, "result": True,
"info": { "info": {
"user": "testuser", "user": self.username,
"hello": "world", "hello": "world",
}, },
} }

View File

@ -1,14 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Unit tests for InvenTreeBarcodePlugin""" """Unit tests for InvenTreeBarcodePlugin"""
from django.contrib.auth import get_user_model
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase
from InvenTree.api_tester import InvenTreeAPITestCase
class TestInvenTreeBarcode(APITestCase): class TestInvenTreeBarcode(InvenTreeAPITestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -17,13 +17,6 @@ class TestInvenTreeBarcode(APITestCase):
'stock' 'stock'
] ]
def setUp(self):
# Create a user for auth
user = get_user_model()
user.objects.create_user('testuser', 'test@testing.com', 'password')
self.client.login(username='testuser', password='password')
def test_errors(self): def test_errors(self):
""" """
Test all possible error cases for assigment action Test all possible error cases for assigment action

View File

@ -1,19 +1,11 @@
""" Unit tests for action plugins """ """ Unit tests for action plugins """
from django.contrib.auth import get_user_model from InvenTree.helpers import InvenTreeTestCase
from django.test import TestCase
class SampleIntegrationPluginTests(TestCase): class SampleIntegrationPluginTests(InvenTreeTestCase):
""" Tests for SampleIntegrationPlugin """ """ Tests for SampleIntegrationPlugin """
def setUp(self):
# Create a user for auth
user = get_user_model()
user.objects.create_user('testuser', 'test@testing.com', 'password')
self.client.login(username='testuser', password='password')
def test_view(self): def test_view(self):
"""check the function of the custom sample plugin """ """check the function of the custom sample plugin """
response = self.client.get('/plugin/sample/ho/he/') response = self.client.get('/plugin/sample/ho/he/')

View File

@ -1,14 +1,13 @@
""" Unit tests for Stock views (see views.py) """ """ Unit tests for Stock views (see views.py) """
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from InvenTree.helpers import InvenTreeTestCase
# from common.models import InvenTreeSetting # from common.models import InvenTreeSetting
class StockViewTestCase(TestCase): class StockViewTestCase(InvenTreeTestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -19,35 +18,7 @@ class StockViewTestCase(TestCase):
'stock', 'stock',
] ]
def setUp(self): roles = 'all'
super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
self.user.is_staff = True
self.user.save()
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password')
class StockListTest(StockViewTestCase): class StockListTest(StockViewTestCase):

View File

@ -1,11 +1,10 @@
import datetime import datetime
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Sum from django.db.models import Sum
from django.test import TestCase
from build.models import Build from build.models import Build
from InvenTree.helpers import InvenTreeTestCase
from InvenTree.status_codes import StockHistoryCode from InvenTree.status_codes import StockHistoryCode
from part.models import Part from part.models import Part
@ -13,7 +12,7 @@ from .models import (StockItem, StockItemTestResult, StockItemTracking,
StockLocation) StockLocation)
class StockTest(TestCase): class StockTest(InvenTreeTestCase):
""" """
Tests to ensure that the stock location tree functions correcly Tests to ensure that the stock location tree functions correcly
""" """
@ -28,6 +27,8 @@ class StockTest(TestCase):
] ]
def setUp(self): def setUp(self):
super().setUp()
# Extract some shortcuts from the fixtures # Extract some shortcuts from the fixtures
self.home = StockLocation.objects.get(name='Home') self.home = StockLocation.objects.get(name='Home')
self.bathroom = StockLocation.objects.get(name='Bathroom') self.bathroom = StockLocation.objects.get(name='Bathroom')
@ -38,14 +39,6 @@ class StockTest(TestCase):
self.drawer2 = StockLocation.objects.get(name='Drawer_2') self.drawer2 = StockLocation.objects.get(name='Drawer_2')
self.drawer3 = StockLocation.objects.get(name='Drawer_3') self.drawer3 = StockLocation.objects.get(name='Drawer_3')
# Create a user
user = get_user_model()
user.objects.create_user('username', 'user@email.com', 'password')
self.client.login(username='username', password='password')
self.user = user.objects.get(username='username')
# Ensure the MPTT objects are correctly rebuild # Ensure the MPTT objects are correctly rebuild
Part.objects.rebuild() Part.objects.rebuild()
StockItem.objects.rebuild() StockItem.objects.rebuild()

View File

@ -561,6 +561,11 @@ function constructFormBody(fields, options) {
insertPersistButton(options); insertPersistButton(options);
} }
// Insert secondary buttons (if required)
if (options.buttons) {
insertSecondaryButtons(options);
}
// Display the modal // Display the modal
$(modal).modal('show'); $(modal).modal('show');
@ -650,6 +655,31 @@ function insertPersistButton(options) {
$(options.modal).find('#modal-footer-buttons').append(html); $(options.modal).find('#modal-footer-buttons').append(html);
} }
/*
* Add secondary buttons to the left of the close and submit buttons
* with callback functions
*/
function insertSecondaryButtons(options) {
for (var idx = 0; idx < options.buttons.length; idx++) {
var html = `
<button type="button" class="btn btn-outline-secondary" id="modal-form-${options.buttons[idx].name}">
${options.buttons[idx].title}
</button>
`;
$(options.modal).find('#modal-footer-secondary-buttons').append(html);
if (options.buttons[idx].onClick instanceof Function) {
// Copy callback reference to prevent errors if `idx` changes value before execution
var onclick_callback = options.buttons[idx].onClick;
$(options.modal).find(`#modal-form-${options.buttons[idx].name}`).click(function() {
onclick_callback(options);
});
}
}
}
/* /*
* Extract all specified form values as a single object * Extract all specified form values as a single object

View File

@ -75,6 +75,9 @@ function createNewModal(options={}) {
</div> </div>
<span class='flex-item' style='flex-grow: 1;'></span> <span class='flex-item' style='flex-grow: 1;'></span>
<h4><span id='modal-progress-spinner' class='fas fa-circle-notch fa-spin' style='display: none;'></span></h4> <h4><span id='modal-progress-spinner' class='fas fa-circle-notch fa-spin' style='display: none;'></span></h4>
<div id='modal-footer-secondary-buttons'>
<!-- Extra secondary buttons can be inserted here -->
</div>
<button type='button' class='btn btn-secondary' id='modal-form-close' data-bs-dismiss='modal'>{% trans "Cancel" %}</button> <button type='button' class='btn btn-secondary' id='modal-form-close' data-bs-dismiss='modal'>{% trans "Cancel" %}</button>
<button type='button' class='btn btn-${submitClass}' id='modal-form-submit'>{% trans "Submit" %}</button> <button type='button' class='btn btn-${submitClass}' id='modal-form-submit'>{% trans "Submit" %}</button>
</div> </div>
@ -99,7 +102,7 @@ function createNewModal(options={}) {
$(modal_name).focus(); $(modal_name).focus();
if (options.hideCloseButton) { if (options.hideCloseButton) {
$(modal_name).find('#modal-form-cancel').hide(); $(modal_name).find('#modal-form-close').hide();
} }
if (options.preventSubmit || options.hideSubmitButton) { if (options.preventSubmit || options.hideSubmitButton) {

View File

@ -24,6 +24,7 @@
cancelSalesOrder, cancelSalesOrder,
completePurchaseOrder, completePurchaseOrder,
completeShipment, completeShipment,
completePendingShipments,
createSalesOrder, createSalesOrder,
createSalesOrderShipment, createSalesOrderShipment,
editPurchaseOrderLineItem, editPurchaseOrderLineItem,
@ -69,7 +70,7 @@ function salesOrderShipmentFields(options={}) {
/* /*
* Complete a shipment * Complete a shipment
*/ */
function completeShipment(shipment_id) { function completeShipment(shipment_id, options={}) {
// Request the list of stock items which will be shipped // Request the list of stock items which will be shipped
inventreeGet(`/api/order/so/shipment/${shipment_id}/`, {}, { inventreeGet(`/api/order/so/shipment/${shipment_id}/`, {}, {
@ -126,28 +127,128 @@ function completeShipment(shipment_id) {
constructForm(`/api/order/so/shipment/${shipment_id}/ship/`, { constructForm(`/api/order/so/shipment/${shipment_id}/ship/`, {
method: 'POST', method: 'POST',
title: '{% trans "Complete Shipment" %}', title: `{% trans "Complete Shipment" %} ${shipment.reference}`,
fields: { fields: {
tracking_number: {}, tracking_number: {},
}, },
preFormContent: html, preFormContent: html,
confirm: true, confirm: true,
confirmMessage: '{% trans "Confirm Shipment" %}', confirmMessage: '{% trans "Confirm Shipment" %}',
buttons: options.buttons,
onSuccess: function(data) { onSuccess: function(data) {
// Reload tables // Reload tables
$('#so-lines-table').bootstrapTable('refresh'); $('#so-lines-table').bootstrapTable('refresh');
$('#pending-shipments-table').bootstrapTable('refresh'); $('#pending-shipments-table').bootstrapTable('refresh');
$('#completed-shipments-table').bootstrapTable('refresh'); $('#completed-shipments-table').bootstrapTable('refresh');
if (options.onSuccess instanceof Function) {
options.onSuccess(data);
}
}, },
reload: true reload: options.reload
}); });
} }
}); });
} }
/*
* Launches a modal to mark all allocated pending shipments as complete
*/
function completePendingShipments(order_id, options={}) {
var pending_shipments = null;
// Request the list of stock items which will be shipped
inventreeGet(`/api/order/so/shipment/.*`,
{
order: order_id,
shipped: false
},
{
async: false,
success: function(shipments) {
pending_shipments = shipments;
}
}
);
var allocated_shipments = [];
for (var idx = 0; idx < pending_shipments.length; idx++) {
if (pending_shipments[idx].allocations.length > 0) {
allocated_shipments.push(pending_shipments[idx]);
}
}
if (allocated_shipments.length > 0) {
completePendingShipmentsHelper(allocated_shipments, 0, options);
} else {
html = `
<div class='alert alert-block alert-danger'>
`;
if (!pending_shipments.length) {
html += `
{% trans "No pending shipments found" %}
`;
} else {
html += `
{% trans "No stock items have been allocated to pending shipments" %}
`;
}
html += `
</div>
`;
constructForm(`/api/order/so/shipment/0/ship/`, {
method: 'POST',
title: '{% trans "Complete Shipments" %}',
preFormContent: html,
onSubmit: function(fields, options) {
handleFormSuccess(fields, options);
},
closeText: 'Close',
hideSubmitButton: true,
});
}
}
/*
* Recursive helper for opening shipment completion modals
*/
function completePendingShipmentsHelper(shipments, shipment_idx, options={}) {
if (shipment_idx < shipments.length) {
completeShipment(shipments[shipment_idx].pk,
{
buttons: [
{
name: 'skip',
title: `{% trans "Skip" %}`,
onClick: function(form_options) {
if (form_options.modal) {
$(form_options.modal).modal('hide');
}
completePendingShipmentsHelper(shipments, shipment_idx + 1, options);
}
}
],
onSuccess: function(data) {
completePendingShipmentsHelper(shipments, shipment_idx + 1, options);
},
}
);
} else if (options.reload) {
location.reload();
}
}
/* /*
* Launches a modal form to mark a PurchaseOrder as "complete" * Launches a modal form to mark a PurchaseOrder as "complete"
*/ */
function completePurchaseOrder(order_id, options={}) { function completePurchaseOrder(order_id, options={}) {
constructForm( constructForm(

View File

@ -1,11 +1,11 @@
from django.apps import apps from django.apps import apps
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from InvenTree.helpers import InvenTreeTestCase
from users.models import Owner, RuleSet from users.models import Owner, RuleSet
@ -160,20 +160,11 @@ class RuleSetModelTest(TestCase):
self.assertEqual(group.permissions.count(), 0) self.assertEqual(group.permissions.count(), 0)
class OwnerModelTest(TestCase): class OwnerModelTest(InvenTreeTestCase):
""" """
Some simplistic tests to ensure the Owner model is setup correctly. Some simplistic tests to ensure the Owner model is setup correctly.
""" """
def setUp(self):
""" Add users and groups """
# Create a new user
self.user = get_user_model().objects.create_user('username', 'user@email.com', 'password')
# Put the user into a new group
self.group = Group.objects.create(name='new_group')
self.user.groups.add(self.group)
def do_request(self, endpoint, filters, status_code=200): def do_request(self, endpoint, filters, status_code=200):
response = self.client.get(endpoint, filters, format='json') response = self.client.get(endpoint, filters, format='json')
self.assertEqual(response.status_code, status_code) self.assertEqual(response.status_code, status_code)
@ -212,11 +203,13 @@ class OwnerModelTest(TestCase):
""" """
Test user APIs Test user APIs
""" """
self.client.logout()
# not authed # not authed
self.do_request(reverse('api-owner-list'), {}, 401) self.do_request(reverse('api-owner-list'), {}, 401)
self.do_request(reverse('api-owner-detail', kwargs={'pk': self.user.id}), {}, 401) self.do_request(reverse('api-owner-detail', kwargs={'pk': self.user.id}), {}, 401)
self.client.login(username='username', password='password') self.client.login(username=self.username, password=self.password)
# user list # user list
self.do_request(reverse('api-owner-list'), {}) self.do_request(reverse('api-owner-list'), {})
# user list with search # user list with search
@ -229,12 +222,14 @@ class OwnerModelTest(TestCase):
""" """
Test token mechanisms Test token mechanisms
""" """
self.client.logout()
token = Token.objects.filter(user=self.user) token = Token.objects.filter(user=self.user)
# not authed # not authed
self.do_request(reverse('api-token'), {}, 401) self.do_request(reverse('api-token'), {}, 401)
self.client.login(username='username', password='password') self.client.login(username=self.username, password=self.password)
# token get # token get
response = self.do_request(reverse('api-token'), {}) response = self.do_request(reverse('api-token'), {})
self.assertEqual(response['token'], token.first().key) self.assertEqual(response['token'], token.first().key)