From 239138a1b5db9462948518f0345c82991c838209 Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Thu, 19 May 2022 18:58:33 +1000 Subject: [PATCH 01/28] Added page actions menu item --- .../order/templates/order/sales_order_base.html | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 5593918a38..25357c86c2 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -57,6 +57,9 @@ src="{% static 'img/blank_image.png' %}" <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> {% if order.status == SalesOrderStatus.PENDING %} + {% if order.pending_shipment_count > 0 %} + <li><a class='dropdown-item' href='#' id='complete-order-shipments'><span class='fas fa-truck'></span> {% trans "Complete Shipments" %}</a></li> + {% endif %} <li><a class='dropdown-item' href='#' id='cancel-order'><span class='fas fa-times-circle icon-red'></span> {% trans "Cancel order" %}</a></li> {% endif %} </ul> @@ -223,6 +226,16 @@ $("#edit-order").click(function() { }); }); +$("#complete-order-shipments").click(function() { + + completeShipments( + {{ order.pk }}, + { + reload: true, + } + ); +}); + $("#cancel-order").click(function() { cancelSalesOrder( From f2a3b4ab1fc603c3f509b0ff2a8ca37218b183df Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Fri, 20 May 2022 16:28:34 +1000 Subject: [PATCH 02/28] Changed completeShipment reload to optional --- InvenTree/templates/js/translated/order.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index 53dead4b60..e6a18db96b 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -69,7 +69,7 @@ function salesOrderShipmentFields(options={}) { /* * Complete a shipment */ -function completeShipment(shipment_id) { +function completeShipment(shipment_id, options={}) { // Request the list of stock items which will be shipped inventreeGet(`/api/order/so/shipment/${shipment_id}/`, {}, { @@ -139,7 +139,7 @@ function completeShipment(shipment_id) { $('#pending-shipments-table').bootstrapTable('refresh'); $('#completed-shipments-table').bootstrapTable('refresh'); }, - reload: true + reload: !!options.reload }); } }); From c6b9585c02152bb15423ee0c5991e5ddae0cc51a Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Fri, 20 May 2022 18:28:02 +1000 Subject: [PATCH 03/28] Fixed typo --- InvenTree/templates/js/translated/modals.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/templates/js/translated/modals.js b/InvenTree/templates/js/translated/modals.js index 464006ae12..023fcd26ce 100644 --- a/InvenTree/templates/js/translated/modals.js +++ b/InvenTree/templates/js/translated/modals.js @@ -99,7 +99,7 @@ function createNewModal(options={}) { $(modal_name).focus(); if (options.hideCloseButton) { - $(modal_name).find('#modal-form-cancel').hide(); + $(modal_name).find('#modal-form-close').hide(); } if (options.preventSubmit || options.hideSubmitButton) { From af0901d06cc56d865db0ebb01c67d99591888efb Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Fri, 20 May 2022 19:30:19 +1000 Subject: [PATCH 04/28] Changed complete shipments button to always show --- InvenTree/order/templates/order/sales_order_base.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 25357c86c2..83ba6d9614 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -57,9 +57,7 @@ src="{% static 'img/blank_image.png' %}" <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> {% if order.status == SalesOrderStatus.PENDING %} - {% if order.pending_shipment_count > 0 %} <li><a class='dropdown-item' href='#' id='complete-order-shipments'><span class='fas fa-truck'></span> {% trans "Complete Shipments" %}</a></li> - {% endif %} <li><a class='dropdown-item' href='#' id='cancel-order'><span class='fas fa-times-circle icon-red'></span> {% trans "Cancel order" %}</a></li> {% endif %} </ul> From 0d5dea3e6d123e52bce3249e239a44716fbb53df Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 12:12:32 +0200 Subject: [PATCH 05/28] refactor test setup --- InvenTree/InvenTree/api_tester.py | 25 ++++---- InvenTree/InvenTree/ci_render_js.py | 21 ++----- InvenTree/InvenTree/helpers.py | 6 ++ InvenTree/InvenTree/test_api.py | 36 +---------- InvenTree/InvenTree/test_middleware.py | 16 +---- InvenTree/InvenTree/test_views.py | 17 +----- InvenTree/InvenTree/tests.py | 20 +----- InvenTree/build/test_api.py | 27 ++------ InvenTree/build/tests.py | 61 +++++-------------- InvenTree/common/tests.py | 15 +---- InvenTree/company/test_views.py | 37 ++--------- InvenTree/part/test_bom_export.py | 34 ++--------- InvenTree/part/test_part.py | 48 +++------------ InvenTree/part/test_views.py | 29 +-------- .../plugin/base/integration/test_mixins.py | 27 +------- InvenTree/stock/test_views.py | 38 ++---------- InvenTree/stock/tests.py | 15 ++--- InvenTree/users/tests.py | 13 +--- 18 files changed, 90 insertions(+), 395 deletions(-) diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index 34976ffbfe..992ecead21 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -12,10 +12,7 @@ from django.contrib.auth.models import Group from rest_framework.test import APITestCase -class InvenTreeAPITestCase(APITestCase): - """ - Base class for running InvenTree API tests - """ +class UserMixin: # User information username = 'testuser' @@ -53,12 +50,12 @@ class InvenTreeAPITestCase(APITestCase): self.user.save() for role in self.roles: - self.assignRole(role) + self.assignRole(role, self.roles == ['all']) if self.auto_login: self.client.login(username=self.username, password=self.password) - def assignRole(self, role): + def assignRole(self, role, assign_all: bool = False): """ Set the user roles for the registered user """ @@ -69,20 +66,26 @@ class InvenTreeAPITestCase(APITestCase): for ruleset in self.group.rule_sets.all(): - if ruleset.name == rule: + if ruleset.name == rule or assign_all: - if perm == 'view': + if perm == 'view' or assign_all: ruleset.can_view = True - elif perm == 'change': + elif perm == 'change' or assign_all: ruleset.can_change = True - elif perm == 'delete': + elif perm == 'delete' or assign_all: ruleset.can_delete = True - elif perm == 'add': + elif perm == 'add' or assign_all: ruleset.can_add = True ruleset.save() break + +class InvenTreeAPITestCase(UserMixin, APITestCase): + """ + Base class for running InvenTree API tests + """ + def getActions(self, url): """ Return a dict of the 'actions' available at a given endpoint. diff --git a/InvenTree/InvenTree/ci_render_js.py b/InvenTree/InvenTree/ci_render_js.py index 94530db096..272272b9ae 100644 --- a/InvenTree/InvenTree/ci_render_js.py +++ b/InvenTree/InvenTree/ci_render_js.py @@ -3,14 +3,13 @@ Pull rendered copies of the templated only used for testing the js files! - This file is omited from coverage """ -from django.test import TestCase # pragma: no cover -from django.contrib.auth import get_user_model # pragma: no cover - import os # pragma: no cover -import pathlib # pragma: no cover +import pathlib + +from InvenTree.InvenTree.helpers import InvenTreeTestCate # pragma: no cover -class RenderJavascriptFiles(TestCase): # pragma: no cover +class RenderJavascriptFiles(InvenTreeTestCate): # pragma: no cover """ 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. """ - 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): url = os.path.join(prefix, filename) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 9e6e24acb8..009c6b1b51 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -14,8 +14,10 @@ from wsgiref.util import FileWrapper from django.http import StreamingHttpResponse from django.core.exceptions import ValidationError, FieldError from django.utils.translation import gettext_lazy as _ +from django.test import TestCase from django.contrib.auth.models import Permission +from InvenTree.InvenTree.api_tester import UserMixin import InvenTree.version @@ -781,3 +783,7 @@ def inheritors(cls): subcls.add(child) work.append(child) return subcls + + +class InvenTreeTestCate(UserMixin, TestCase): + pass diff --git a/InvenTree/InvenTree/test_api.py b/InvenTree/InvenTree/test_api.py index f55dfbcda2..105f32b489 100644 --- a/InvenTree/InvenTree/test_api.py +++ b/InvenTree/InvenTree/test_api.py @@ -2,12 +2,8 @@ from rest_framework import status -from django.test import TestCase - -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group - from django.urls import reverse +from InvenTree.InvenTree.helpers import InvenTreeTestCate from InvenTree.api_tester import InvenTreeAPITestCase @@ -16,7 +12,7 @@ from users.models import RuleSet from base64 import b64encode -class HTMLAPITests(TestCase): +class HTMLAPITests(InvenTreeTestCate): """ Test that we can access the REST API endpoints via the HTML interface. @@ -24,33 +20,7 @@ class HTMLAPITests(TestCase): which raised an AssertionError when using the HTML API interface, while the regular JSON interface continued to work as expected. """ - - 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') + roles = ['all'] def test_part_api(self): url = reverse('api-part-list') diff --git a/InvenTree/InvenTree/test_middleware.py b/InvenTree/InvenTree/test_middleware.py index bced2eb079..8aecdbd750 100644 --- a/InvenTree/InvenTree/test_middleware.py +++ b/InvenTree/InvenTree/test_middleware.py @@ -1,12 +1,11 @@ """Tests for middleware functions""" -from django.test import TestCase - -from django.contrib.auth import get_user_model from django.urls import reverse +from InvenTree.InvenTree.helpers import InvenTreeTestCate -class MiddlewareTests(TestCase): + +class MiddlewareTests(InvenTreeTestCate): """Test for middleware functions""" def check_path(self, url, code=200, **kwargs): @@ -14,15 +13,6 @@ class MiddlewareTests(TestCase): self.assertEqual(response.status_code, code) 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): """Test the auth middleware""" diff --git a/InvenTree/InvenTree/test_views.py b/InvenTree/InvenTree/test_views.py index 0a145ec508..0498b82965 100644 --- a/InvenTree/InvenTree/test_views.py +++ b/InvenTree/InvenTree/test_views.py @@ -5,28 +5,17 @@ Unit tests for the main web views import re import os -from django.test import TestCase from django.urls import reverse -from django.contrib.auth import get_user_model + +from InvenTree.InvenTree.helpers import InvenTreeTestCate -class ViewTests(TestCase): +class ViewTests(InvenTreeTestCate): """ Tests for various top-level views """ username = 'test_user' 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): """ Test that the api-doc view works """ diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 26b50a0eca..9df10d8d63 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -7,7 +7,6 @@ from unittest import mock from django.test import TestCase, override_settings import django.core.exceptions as django_exceptions from django.core.exceptions import ValidationError -from django.contrib.auth import get_user_model from django.conf import settings from djmoney.money import Money @@ -457,18 +456,12 @@ class TestStatus(TestCase): self.assertEqual(ready.isImportingData(), False) -class TestSettings(TestCase): +class TestSettings(helpers.InvenTreeTestCate): """ Unit tests for settings """ - def setUp(self) -> None: - 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') + superuser = True def in_env_context(self, envs={}): """Patch the env to include the given dict""" @@ -574,18 +567,11 @@ class TestSettings(TestCase): self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321') -class TestInstanceName(TestCase): +class TestInstanceName(helpers.InvenTreeTestCate): """ 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): # default setting diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py index 4ba54e9c73..a736b01cad 100644 --- a/InvenTree/build/test_api.py +++ b/InvenTree/build/test_api.py @@ -2,9 +2,6 @@ from datetime import datetime, timedelta 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 @@ -30,25 +27,11 @@ class TestBuildAPI(APITestCase): 'build', ] - def setUp(self): - # Create a user for auth - user = get_user_model() - self.user = user.objects.create_user('testuser', 'test@testing.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='testuser', password='password') + roles = [ + 'build.change', + 'build.add', + 'build.delete', + ] def test_get_build_list(self): """ diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index d3c0c41112..d49f9eafe8 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -1,18 +1,16 @@ -from django.test import TestCase 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 InvenTree.InvenTree.helpers import InvenTreeTestCate + from .models import Build from stock.models import StockItem from InvenTree.status_codes import BuildStatus -class BuildTestSimple(TestCase): +class BuildTestSimple(InvenTreeTestCate): fixtures = [ 'category', @@ -21,27 +19,11 @@ class BuildTestSimple(TestCase): 'build', ] - def setUp(self): - # Create a user for auth - user = get_user_model() - user.objects.create_user('testuser', 'test@testing.com', 'password') - - 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') + rules = [ + 'build.change', + 'build.add', + 'build.delete', + ] def test_build_objects(self): # Ensure the Build objects were correctly created @@ -106,7 +88,7 @@ class BuildTestSimple(TestCase): self.assertEqual(build.status, BuildStatus.CANCELLED) -class TestBuildViews(TestCase): +class TestBuildViews(InvenTreeTestCate): """ Tests for Build app views """ fixtures = [ @@ -116,28 +98,15 @@ class TestBuildViews(TestCase): 'build', ] + rules = [ + 'build.change', + 'build.add', + 'build.delete', + ] + def setUp(self): 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 self.build = Build.objects.get(pk=1) diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index 7f6f6dbe40..c74436988a 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -4,11 +4,10 @@ import json from datetime import timedelta from django.test import TestCase, Client -from django.contrib.auth import get_user_model from django.urls import reverse from InvenTree.api_tester import InvenTreeAPITestCase -from InvenTree.helpers import str2bool +from InvenTree.helpers import InvenTreeTestCate, str2bool from plugin.models import NotificationUserSetting, PluginConfig from plugin import registry @@ -18,7 +17,7 @@ from .api import WebhookView CONTENT_TYPE_JSON = 'application/json' -class SettingsTest(TestCase): +class SettingsTest(InvenTreeTestCate): """ Tests for the 'settings' model """ @@ -27,16 +26,6 @@ class SettingsTest(TestCase): '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): # There should be two settings objects in the database diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index 29900236bf..036bf76916 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -1,12 +1,11 @@ """ Unit tests for Company views (see views.py) """ -from django.test import TestCase from django.urls import reverse -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group + +from InvenTree.InvenTree.helpers import InvenTreeTestCate -class CompanyViewTestBase(TestCase): +class CompanyViewTestBase(InvenTreeTestCate): fixtures = [ 'category', @@ -17,33 +16,9 @@ class CompanyViewTestBase(TestCase): 'supplier_part', ] - 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') - + rules = [ + 'all', + ] class CompanyViewTest(CompanyViewTestBase): """ diff --git a/InvenTree/part/test_bom_export.py b/InvenTree/part/test_bom_export.py index 4ae0b88269..1f50c2d990 100644 --- a/InvenTree/part/test_bom_export.py +++ b/InvenTree/part/test_bom_export.py @@ -4,14 +4,12 @@ Unit testing for BOM export functionality import csv -from django.test import TestCase - from django.urls import reverse -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group + +from InvenTree.InvenTree.helpers import InvenTreeTestCate -class BomExportTest(TestCase): +class BomExportTest(InvenTreeTestCate): fixtures = [ 'category', @@ -20,33 +18,11 @@ class BomExportTest(TestCase): 'bom', ] + 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') - self.url = reverse('bom-download', kwargs={'pk': 100}) def test_bom_template(self): diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 2df3c10b01..8e0ba67e22 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -3,13 +3,14 @@ from allauth.account.models import EmailAddress from django.conf import settings -from django.contrib.auth import get_user_model from django.test import TestCase from django.core.exceptions import ValidationError import os +from InvenTree.InvenTree.helpers import InvenTreeTestCate + from .models import Part, PartCategory, PartCategoryStar, PartStar, PartTestTemplate from .models import rename_part_image from .templatetags import inventree_extras @@ -21,15 +22,9 @@ from common.models import InvenTreeSetting, InvenTreeUserSetting, NotificationEn from common.notifications import storage, UIMessageNotification -class TemplateTagTest(TestCase): +class TemplateTagTest(InvenTreeTestCate): """ 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): self.assertEqual(int(inventree_extras.define(3)), 3) @@ -330,24 +325,13 @@ class TestTemplateTest(TestCase): self.assertEqual(variant.getTestTemplates().count(), n + 1) -class PartSettingsTest(TestCase): +class PartSettingsTest(InvenTreeTestCate): """ 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. """ - 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): """ Helper function to create a simple part @@ -461,7 +445,7 @@ class PartSettingsTest(TestCase): Part.objects.create(name='abc', revision='6', description='A part', IPN=' ') -class PartSubscriptionTests(TestCase): +class PartSubscriptionTests(InvenTreeTestCate): fixtures = [ 'location', @@ -470,15 +454,7 @@ class PartSubscriptionTests(TestCase): ] 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 - ) + super().setUp() # electronics / IC / MCU self.category = PartCategory.objects.get(pk=4) @@ -578,7 +554,7 @@ class PartSubscriptionTests(TestCase): self.assertTrue(self.part.is_starred_by(self.user)) -class BaseNotificationIntegrationTest(TestCase): +class BaseNotificationIntegrationTest(InvenTreeTestCate): """ Integration test for notifications """ fixtures = [ @@ -589,15 +565,7 @@ class BaseNotificationIntegrationTest(TestCase): ] 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 - ) + super().setUp() # Add Mailadress EmailAddress.objects.create(user=self.user, email='test@testing.com') diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 2171a09b17..9ce25b79e7 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -2,8 +2,6 @@ from django.test import TestCase from django.urls import reverse -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group from .models import Part @@ -19,34 +17,11 @@ class PartViewTestCase(TestCase): 'supplier_part', ] + 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') - - class PartListTest(PartViewTestCase): def test_part_index(self): diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index c1afa39fc2..bedfe0420c 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -4,7 +4,6 @@ from django.test import TestCase from django.conf import settings from django.urls import include, re_path, reverse from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group from error_report.models import Error @@ -261,32 +260,8 @@ class PanelMixinTests(TestCase): 'stock', ] - def setUp(self): - super().setUp() + roles = ['all'] - # 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): """Test that the sample panel plugin is installed""" diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py index d656201f81..8e304ee322 100644 --- a/InvenTree/stock/test_views.py +++ b/InvenTree/stock/test_views.py @@ -1,14 +1,13 @@ """ Unit tests for Stock views (see views.py) """ -from django.test import TestCase from django.urls import reverse -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group + +from InvenTree.InvenTree.helpers import InvenTreeTestCate # from common.models import InvenTreeSetting -class StockViewTestCase(TestCase): +class StockViewTestCase(InvenTreeTestCate): fixtures = [ 'category', @@ -19,36 +18,7 @@ class StockViewTestCase(TestCase): 'stock', ] - 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.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') - + roles = ['all'] class StockListTest(StockViewTestCase): """ Tests for Stock list views """ diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py index 97639b15bd..287a1645e6 100644 --- a/InvenTree/stock/tests.py +++ b/InvenTree/stock/tests.py @@ -1,9 +1,8 @@ -from django.test import TestCase from django.db.models import Sum -from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError import datetime +from InvenTree.InvenTree.helpers import InvenTreeTestCate from InvenTree.status_codes import StockHistoryCode @@ -14,7 +13,7 @@ from part.models import Part from build.models import Build -class StockTest(TestCase): +class StockTest(InvenTreeTestCate): """ Tests to ensure that the stock location tree functions correcly """ @@ -29,6 +28,8 @@ class StockTest(TestCase): ] def setUp(self): + super().setUp() + # Extract some shortcuts from the fixtures self.home = StockLocation.objects.get(name='Home') self.bathroom = StockLocation.objects.get(name='Bathroom') @@ -39,14 +40,6 @@ class StockTest(TestCase): self.drawer2 = StockLocation.objects.get(name='Drawer_2') 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 Part.objects.rebuild() StockItem.objects.rebuild() diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py index 9dc90f5d2c..c850508f93 100644 --- a/InvenTree/users/tests.py +++ b/InvenTree/users/tests.py @@ -1,10 +1,10 @@ from django.test import TestCase from django.apps import apps from django.urls import reverse -from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from rest_framework.authtoken.models import Token +from InvenTree.InvenTree.helpers import InvenTreeTestCate from users.models import RuleSet, Owner @@ -160,20 +160,11 @@ class RuleSetModelTest(TestCase): self.assertEqual(group.permissions.count(), 0) -class OwnerModelTest(TestCase): +class OwnerModelTest(InvenTreeTestCate): """ 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): response = self.client.get(endpoint, filters, format='json') self.assertEqual(response.status_code, status_code) From 3a1996dd48a20c7c95b340263276d6d447995cf8 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 12:32:25 +0200 Subject: [PATCH 06/28] PEP fix --- .pre-commit-config.yaml | 4 ---- InvenTree/company/test_views.py | 1 + InvenTree/part/test_views.py | 1 + InvenTree/plugin/base/integration/test_mixins.py | 1 - InvenTree/stock/test_views.py | 1 + 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1dc2ba3f70..48e530b22b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,3 @@ repos: rev: '4.0.1' hooks: - id: flake8 -- repo: https://github.com/pycqa/isort - rev: '5.10.1' - hooks: - - id: isort diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index 036bf76916..38957f2e4a 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -20,6 +20,7 @@ class CompanyViewTestBase(InvenTreeTestCate): 'all', ] + class CompanyViewTest(CompanyViewTestBase): """ Tests for various 'Company' views diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 9ce25b79e7..2971c032e0 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -22,6 +22,7 @@ class PartViewTestCase(TestCase): def setUp(self): super().setUp() + class PartListTest(PartViewTestCase): def test_part_index(self): diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index bedfe0420c..d9be17fde0 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -262,7 +262,6 @@ class PanelMixinTests(TestCase): roles = ['all'] - def test_installed(self): """Test that the sample panel plugin is installed""" diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py index 8e304ee322..ab9b467672 100644 --- a/InvenTree/stock/test_views.py +++ b/InvenTree/stock/test_views.py @@ -20,6 +20,7 @@ class StockViewTestCase(InvenTreeTestCate): roles = ['all'] + class StockListTest(StockViewTestCase): """ Tests for Stock list views """ From 42d325e7ca642ed3f09ce7868e92308ec61569b1 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 12:33:28 +0200 Subject: [PATCH 07/28] fix spelling --- InvenTree/build/tests.py | 4 ++-- InvenTree/company/test_views.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index d49f9eafe8..0f21f63887 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -19,7 +19,7 @@ class BuildTestSimple(InvenTreeTestCate): 'build', ] - rules = [ + roles = [ 'build.change', 'build.add', 'build.delete', @@ -98,7 +98,7 @@ class TestBuildViews(InvenTreeTestCate): 'build', ] - rules = [ + roles = [ 'build.change', 'build.add', 'build.delete', diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index 38957f2e4a..b7773ea14f 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -16,7 +16,7 @@ class CompanyViewTestBase(InvenTreeTestCate): 'supplier_part', ] - rules = [ + roles = [ 'all', ] From e8287f02d472624e99d63ada498a2b2e9a28ec6a Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 12:33:51 +0200 Subject: [PATCH 08/28] rename --- InvenTree/InvenTree/ci_render_js.py | 4 ++-- InvenTree/InvenTree/helpers.py | 2 +- InvenTree/InvenTree/test_api.py | 4 ++-- InvenTree/InvenTree/test_middleware.py | 4 ++-- InvenTree/InvenTree/test_views.py | 4 ++-- InvenTree/InvenTree/tests.py | 4 ++-- InvenTree/build/tests.py | 6 +++--- InvenTree/common/tests.py | 4 ++-- InvenTree/company/test_views.py | 4 ++-- InvenTree/part/test_bom_export.py | 4 ++-- InvenTree/part/test_part.py | 10 +++++----- InvenTree/stock/test_views.py | 4 ++-- InvenTree/stock/tests.py | 4 ++-- InvenTree/users/tests.py | 4 ++-- 14 files changed, 31 insertions(+), 31 deletions(-) diff --git a/InvenTree/InvenTree/ci_render_js.py b/InvenTree/InvenTree/ci_render_js.py index 272272b9ae..306fa94f95 100644 --- a/InvenTree/InvenTree/ci_render_js.py +++ b/InvenTree/InvenTree/ci_render_js.py @@ -6,10 +6,10 @@ only used for testing the js files! - This file is omited from coverage import os # pragma: no cover import pathlib -from InvenTree.InvenTree.helpers import InvenTreeTestCate # pragma: no cover +from InvenTree.InvenTree.helpers import InvenTreeTestCase # pragma: no cover -class RenderJavascriptFiles(InvenTreeTestCate): # pragma: no cover +class RenderJavascriptFiles(InvenTreeTestCase): # pragma: no cover """ A unit test to "render" javascript files. diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 009c6b1b51..e85484f594 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -785,5 +785,5 @@ def inheritors(cls): return subcls -class InvenTreeTestCate(UserMixin, TestCase): +class InvenTreeTestCase(UserMixin, TestCase): pass diff --git a/InvenTree/InvenTree/test_api.py b/InvenTree/InvenTree/test_api.py index 105f32b489..cfe47cbeda 100644 --- a/InvenTree/InvenTree/test_api.py +++ b/InvenTree/InvenTree/test_api.py @@ -3,7 +3,7 @@ from rest_framework import status from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase from InvenTree.api_tester import InvenTreeAPITestCase @@ -12,7 +12,7 @@ from users.models import RuleSet from base64 import b64encode -class HTMLAPITests(InvenTreeTestCate): +class HTMLAPITests(InvenTreeTestCase): """ Test that we can access the REST API endpoints via the HTML interface. diff --git a/InvenTree/InvenTree/test_middleware.py b/InvenTree/InvenTree/test_middleware.py index 8aecdbd750..8d1e652d18 100644 --- a/InvenTree/InvenTree/test_middleware.py +++ b/InvenTree/InvenTree/test_middleware.py @@ -2,10 +2,10 @@ from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase -class MiddlewareTests(InvenTreeTestCate): +class MiddlewareTests(InvenTreeTestCase): """Test for middleware functions""" def check_path(self, url, code=200, **kwargs): diff --git a/InvenTree/InvenTree/test_views.py b/InvenTree/InvenTree/test_views.py index 0498b82965..bb8901719d 100644 --- a/InvenTree/InvenTree/test_views.py +++ b/InvenTree/InvenTree/test_views.py @@ -7,10 +7,10 @@ import os from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase -class ViewTests(InvenTreeTestCate): +class ViewTests(InvenTreeTestCase): """ Tests for various top-level views """ username = 'test_user' diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 9df10d8d63..335c29c742 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -456,7 +456,7 @@ class TestStatus(TestCase): self.assertEqual(ready.isImportingData(), False) -class TestSettings(helpers.InvenTreeTestCate): +class TestSettings(helpers.InvenTreeTestCase): """ Unit tests for settings """ @@ -567,7 +567,7 @@ class TestSettings(helpers.InvenTreeTestCate): self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321') -class TestInstanceName(helpers.InvenTreeTestCate): +class TestInstanceName(helpers.InvenTreeTestCase): """ Unit tests for instance name """ diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index 0f21f63887..8e4c7ce6b5 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -2,7 +2,7 @@ from django.urls import reverse from datetime import datetime, timedelta -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase from .models import Build from stock.models import StockItem @@ -10,7 +10,7 @@ from stock.models import StockItem from InvenTree.status_codes import BuildStatus -class BuildTestSimple(InvenTreeTestCate): +class BuildTestSimple(InvenTreeTestCase): fixtures = [ 'category', @@ -88,7 +88,7 @@ class BuildTestSimple(InvenTreeTestCate): self.assertEqual(build.status, BuildStatus.CANCELLED) -class TestBuildViews(InvenTreeTestCate): +class TestBuildViews(InvenTreeTestCase): """ Tests for Build app views """ fixtures = [ diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index b27b940965..6f8643e936 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -7,7 +7,7 @@ from django.test import TestCase, Client from django.urls import reverse from InvenTree.api_tester import InvenTreeAPITestCase -from InvenTree.helpers import InvenTreeTestCate, str2bool +from InvenTree.helpers import InvenTreeTestCase, str2bool from plugin.models import NotificationUserSetting, PluginConfig from plugin import registry @@ -17,7 +17,7 @@ from .api import WebhookView CONTENT_TYPE_JSON = 'application/json' -class SettingsTest(InvenTreeTestCate): +class SettingsTest(InvenTreeTestCase): """ Tests for the 'settings' model """ diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index b7773ea14f..2e66ef9307 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -2,10 +2,10 @@ from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase -class CompanyViewTestBase(InvenTreeTestCate): +class CompanyViewTestBase(InvenTreeTestCase): fixtures = [ 'category', diff --git a/InvenTree/part/test_bom_export.py b/InvenTree/part/test_bom_export.py index 1f50c2d990..5f3d173ce6 100644 --- a/InvenTree/part/test_bom_export.py +++ b/InvenTree/part/test_bom_export.py @@ -6,10 +6,10 @@ import csv from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase -class BomExportTest(InvenTreeTestCate): +class BomExportTest(InvenTreeTestCase): fixtures = [ 'category', diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 8e0ba67e22..56fb85b8f1 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -9,7 +9,7 @@ from django.core.exceptions import ValidationError import os -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase from .models import Part, PartCategory, PartCategoryStar, PartStar, PartTestTemplate from .models import rename_part_image @@ -22,7 +22,7 @@ from common.models import InvenTreeSetting, InvenTreeUserSetting, NotificationEn from common.notifications import storage, UIMessageNotification -class TemplateTagTest(InvenTreeTestCate): +class TemplateTagTest(InvenTreeTestCase): """ Tests for the custom template tag code """ def test_define(self): @@ -325,7 +325,7 @@ class TestTemplateTest(TestCase): self.assertEqual(variant.getTestTemplates().count(), n + 1) -class PartSettingsTest(InvenTreeTestCate): +class PartSettingsTest(InvenTreeTestCase): """ Tests to ensure that the user-configurable default values work as expected. @@ -445,7 +445,7 @@ class PartSettingsTest(InvenTreeTestCate): Part.objects.create(name='abc', revision='6', description='A part', IPN=' ') -class PartSubscriptionTests(InvenTreeTestCate): +class PartSubscriptionTests(InvenTreeTestCase): fixtures = [ 'location', @@ -554,7 +554,7 @@ class PartSubscriptionTests(InvenTreeTestCate): self.assertTrue(self.part.is_starred_by(self.user)) -class BaseNotificationIntegrationTest(InvenTreeTestCate): +class BaseNotificationIntegrationTest(InvenTreeTestCase): """ Integration test for notifications """ fixtures = [ diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py index ab9b467672..20a5feabd0 100644 --- a/InvenTree/stock/test_views.py +++ b/InvenTree/stock/test_views.py @@ -2,12 +2,12 @@ from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase # from common.models import InvenTreeSetting -class StockViewTestCase(InvenTreeTestCate): +class StockViewTestCase(InvenTreeTestCase): fixtures = [ 'category', diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py index 287a1645e6..63742df650 100644 --- a/InvenTree/stock/tests.py +++ b/InvenTree/stock/tests.py @@ -2,7 +2,7 @@ from django.db.models import Sum from django.core.exceptions import ValidationError import datetime -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase from InvenTree.status_codes import StockHistoryCode @@ -13,7 +13,7 @@ from part.models import Part from build.models import Build -class StockTest(InvenTreeTestCate): +class StockTest(InvenTreeTestCase): """ Tests to ensure that the stock location tree functions correcly """ diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py index c850508f93..502aecd996 100644 --- a/InvenTree/users/tests.py +++ b/InvenTree/users/tests.py @@ -4,7 +4,7 @@ from django.urls import reverse from django.contrib.auth.models import Group from rest_framework.authtoken.models import Token -from InvenTree.InvenTree.helpers import InvenTreeTestCate +from InvenTree.InvenTree.helpers import InvenTreeTestCase from users.models import RuleSet, Owner @@ -160,7 +160,7 @@ class RuleSetModelTest(TestCase): self.assertEqual(group.permissions.count(), 0) -class OwnerModelTest(InvenTreeTestCate): +class OwnerModelTest(InvenTreeTestCase): """ Some simplistic tests to ensure the Owner model is setup correctly. """ From b99a9306ce70e6db2c8d65c1f5218c8b8cab6ab5 Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Fri, 20 May 2022 20:37:23 +1000 Subject: [PATCH 09/28] Added onSuccess support to completeShipment --- InvenTree/templates/js/translated/order.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index e6a18db96b..a6d8cbdc0d 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -126,7 +126,7 @@ function completeShipment(shipment_id, options={}) { constructForm(`/api/order/so/shipment/${shipment_id}/ship/`, { method: 'POST', - title: '{% trans "Complete Shipment" %}', + title: `{% trans "Complete Shipment" %} ${shipment.reference}`, fields: { tracking_number: {}, }, @@ -138,6 +138,10 @@ function completeShipment(shipment_id, options={}) { $('#so-lines-table').bootstrapTable('refresh'); $('#pending-shipments-table').bootstrapTable('refresh'); $('#completed-shipments-table').bootstrapTable('refresh'); + + if (options.onSuccess instanceof Function) { + options.onSuccess(data); + } }, reload: !!options.reload }); @@ -147,7 +151,7 @@ function completeShipment(shipment_id, options={}) { /* * Launches a modal form to mark a PurchaseOrder as "complete" -*/ + */ function completePurchaseOrder(order_id, options={}) { constructForm( From 04ce4fa6970ef1066fd9ae0ec21d9427a6f15da2 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 12:38:15 +0200 Subject: [PATCH 10/28] readd config --- .pre-commit-config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 48e530b22b..1dc2ba3f70 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,3 +13,7 @@ repos: rev: '4.0.1' hooks: - id: flake8 +- repo: https://github.com/pycqa/isort + rev: '5.10.1' + hooks: + - id: isort From a6f7a29817ef1e61461b16dbb9c45f4a36ffb972 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 12:48:03 +0200 Subject: [PATCH 11/28] fix import path --- InvenTree/InvenTree/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index e85484f594..34ce1439c8 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -17,7 +17,7 @@ from django.utils.translation import gettext_lazy as _ from django.test import TestCase from django.contrib.auth.models import Permission -from InvenTree.InvenTree.api_tester import UserMixin +from .api_tester import UserMixin import InvenTree.version From 9f922f06ffd2eb44fc6cbd19cd48221f4d122166 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 12:53:04 +0200 Subject: [PATCH 12/28] fix more imports --- InvenTree/InvenTree/ci_render_js.py | 2 +- InvenTree/InvenTree/test_api.py | 2 +- InvenTree/InvenTree/test_middleware.py | 2 +- InvenTree/InvenTree/test_views.py | 2 +- InvenTree/build/tests.py | 2 +- InvenTree/company/test_views.py | 2 +- InvenTree/part/test_bom_export.py | 2 +- InvenTree/part/test_part.py | 2 +- InvenTree/stock/test_views.py | 2 +- InvenTree/stock/tests.py | 2 +- InvenTree/users/tests.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/InvenTree/InvenTree/ci_render_js.py b/InvenTree/InvenTree/ci_render_js.py index 306fa94f95..824fe5d7e3 100644 --- a/InvenTree/InvenTree/ci_render_js.py +++ b/InvenTree/InvenTree/ci_render_js.py @@ -6,7 +6,7 @@ only used for testing the js files! - This file is omited from coverage import os # pragma: no cover import pathlib -from InvenTree.InvenTree.helpers import InvenTreeTestCase # pragma: no cover +from InvenTree.helpers import InvenTreeTestCase # pragma: no cover class RenderJavascriptFiles(InvenTreeTestCase): # pragma: no cover diff --git a/InvenTree/InvenTree/test_api.py b/InvenTree/InvenTree/test_api.py index cfe47cbeda..4a5e03ac5a 100644 --- a/InvenTree/InvenTree/test_api.py +++ b/InvenTree/InvenTree/test_api.py @@ -3,7 +3,7 @@ from rest_framework import status from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase from InvenTree.api_tester import InvenTreeAPITestCase diff --git a/InvenTree/InvenTree/test_middleware.py b/InvenTree/InvenTree/test_middleware.py index 8d1e652d18..e1aeca0d03 100644 --- a/InvenTree/InvenTree/test_middleware.py +++ b/InvenTree/InvenTree/test_middleware.py @@ -2,7 +2,7 @@ from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase class MiddlewareTests(InvenTreeTestCase): diff --git a/InvenTree/InvenTree/test_views.py b/InvenTree/InvenTree/test_views.py index bb8901719d..8dac196a1d 100644 --- a/InvenTree/InvenTree/test_views.py +++ b/InvenTree/InvenTree/test_views.py @@ -7,7 +7,7 @@ import os from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase class ViewTests(InvenTreeTestCase): diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index 8e4c7ce6b5..8bd7553a52 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -2,7 +2,7 @@ from django.urls import reverse from datetime import datetime, timedelta -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase from .models import Build from stock.models import StockItem diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index 2e66ef9307..0c135aff88 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -2,7 +2,7 @@ from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase class CompanyViewTestBase(InvenTreeTestCase): diff --git a/InvenTree/part/test_bom_export.py b/InvenTree/part/test_bom_export.py index 5f3d173ce6..38d9bb5db9 100644 --- a/InvenTree/part/test_bom_export.py +++ b/InvenTree/part/test_bom_export.py @@ -6,7 +6,7 @@ import csv from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase class BomExportTest(InvenTreeTestCase): diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 56fb85b8f1..a413159cfe 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -9,7 +9,7 @@ from django.core.exceptions import ValidationError import os -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase from .models import Part, PartCategory, PartCategoryStar, PartStar, PartTestTemplate from .models import rename_part_image diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py index 20a5feabd0..acea850046 100644 --- a/InvenTree/stock/test_views.py +++ b/InvenTree/stock/test_views.py @@ -2,7 +2,7 @@ from django.urls import reverse -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase # from common.models import InvenTreeSetting diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py index 63742df650..95c7646a9d 100644 --- a/InvenTree/stock/tests.py +++ b/InvenTree/stock/tests.py @@ -2,7 +2,7 @@ from django.db.models import Sum from django.core.exceptions import ValidationError import datetime -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase from InvenTree.status_codes import StockHistoryCode diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py index 502aecd996..f296e3194f 100644 --- a/InvenTree/users/tests.py +++ b/InvenTree/users/tests.py @@ -4,7 +4,7 @@ from django.urls import reverse from django.contrib.auth.models import Group from rest_framework.authtoken.models import Token -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase from users.models import RuleSet, Owner From f1ca9d7aa8f95f089edd9d939887dd443d636d2e Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Fri, 20 May 2022 22:22:49 +1000 Subject: [PATCH 13/28] Added div for extra secondary modal buttons --- InvenTree/templates/js/translated/modals.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/InvenTree/templates/js/translated/modals.js b/InvenTree/templates/js/translated/modals.js index 023fcd26ce..cc1212494d 100644 --- a/InvenTree/templates/js/translated/modals.js +++ b/InvenTree/templates/js/translated/modals.js @@ -75,6 +75,9 @@ function createNewModal(options={}) { </div> <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> + <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-${submitClass}' id='modal-form-submit'>{% trans "Submit" %}</button> </div> From 3eb489801951e6739d6e41cf2fccf16b21dcf136 Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Sat, 21 May 2022 00:52:45 +1000 Subject: [PATCH 14/28] Added support for secondary buttons on modals Secondary buttons can be added to modal footers beside Close and Submit Buttons can be linked to callback functions Callback functions can access options arguments passed to constructForm --- InvenTree/templates/js/translated/forms.js | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/InvenTree/templates/js/translated/forms.js b/InvenTree/templates/js/translated/forms.js index d45a2de78c..9e1a7d154d 100644 --- a/InvenTree/templates/js/translated/forms.js +++ b/InvenTree/templates/js/translated/forms.js @@ -561,6 +561,11 @@ function constructFormBody(fields, options) { insertPersistButton(options); } + // Insert secondary buttons (if required) + if (options.buttons) { + insertSecondaryButtons(options); + } + // Display the modal $(modal).modal('show'); @@ -650,6 +655,31 @@ function insertPersistButton(options) { $(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 From c38862b28ce4ea9728332f9f521c60297562a62e Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Sat, 21 May 2022 01:05:54 +1000 Subject: [PATCH 15/28] Added page action to process pending shipments --- .../templates/order/sales_order_base.html | 2 +- InvenTree/templates/js/translated/order.js | 98 ++++++++++++++++++- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 83ba6d9614..af923ab097 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -226,7 +226,7 @@ $("#edit-order").click(function() { $("#complete-order-shipments").click(function() { - completeShipments( + completePendingShipments( {{ order.pk }}, { reload: true, diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index a6d8cbdc0d..b9b6da3b36 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -133,6 +133,7 @@ function completeShipment(shipment_id, options={}) { preFormContent: html, confirm: true, confirmMessage: '{% trans "Confirm Shipment" %}', + buttons: options.buttons, onSuccess: function(data) { // Reload tables $('#so-lines-table').bootstrapTable('refresh'); @@ -143,12 +144,107 @@ function completeShipment(shipment_id, options={}) { options.onSuccess(data); } }, - reload: !!options.reload + 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" */ From f036252fb9c2f3f3522afd0ed9c27237f569bea0 Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Sat, 21 May 2022 01:31:01 +1000 Subject: [PATCH 16/28] Added completePendingShipments to exported section --- InvenTree/templates/js/translated/order.js | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index b9b6da3b36..0c21e368f1 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -24,6 +24,7 @@ cancelSalesOrder, completePurchaseOrder, completeShipment, + completePendingShipments, createSalesOrder, createSalesOrderShipment, editPurchaseOrderLineItem, From a148dbf303a096bc057dcbc9934836482ef27e44 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 17:43:51 +0200 Subject: [PATCH 17/28] refactor 'all' role --- InvenTree/InvenTree/api_tester.py | 24 ++++++++++++------- InvenTree/InvenTree/test_api.py | 2 +- InvenTree/company/test_views.py | 4 +--- InvenTree/part/test_bom_export.py | 2 +- InvenTree/part/test_views.py | 2 +- .../plugin/base/integration/test_mixins.py | 2 +- InvenTree/stock/test_views.py | 2 +- 7 files changed, 21 insertions(+), 17 deletions(-) diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index 992ecead21..c5d96e6bb3 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -49,32 +49,38 @@ class UserMixin: self.user.save() - for role in self.roles: - self.assignRole(role, self.roles == ['all']) + # Assign all roles if set + if self.roles == 'all': + self.assignRole() + # else filter the roles + else: + for role in self.roles: + self.assignRole(role) if self.auto_login: self.client.login(username=self.username, password=self.password) - def assignRole(self, role, assign_all: bool = False): + def assignRole(self, role = None, assign_all: bool = False): """ Set the user roles for the registered user """ # role is of the format 'rule.permission' e.g. 'part.add' - rule, perm = role.split('.') + if not assign_all: + rule, perm = role.split('.') for ruleset in self.group.rule_sets.all(): - if ruleset.name == rule or assign_all: + if assign_all or ruleset.name == rule: - if perm == 'view' or assign_all: + if assign_all or perm == 'view': ruleset.can_view = True - elif perm == 'change' or assign_all: + elif assign_all or perm == 'change': ruleset.can_change = True - elif perm == 'delete' or assign_all: + elif assign_all or perm == 'delete': ruleset.can_delete = True - elif perm == 'add' or assign_all: + elif assign_all or perm == 'add': ruleset.can_add = True ruleset.save() diff --git a/InvenTree/InvenTree/test_api.py b/InvenTree/InvenTree/test_api.py index 4a5e03ac5a..10e2305d07 100644 --- a/InvenTree/InvenTree/test_api.py +++ b/InvenTree/InvenTree/test_api.py @@ -20,7 +20,7 @@ class HTMLAPITests(InvenTreeTestCase): which raised an AssertionError when using the HTML API interface, while the regular JSON interface continued to work as expected. """ - roles = ['all'] + roles = 'all' def test_part_api(self): url = reverse('api-part-list') diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index 0c135aff88..a3ecd1651a 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -16,9 +16,7 @@ class CompanyViewTestBase(InvenTreeTestCase): 'supplier_part', ] - roles = [ - 'all', - ] + roles = 'all' class CompanyViewTest(CompanyViewTestBase): diff --git a/InvenTree/part/test_bom_export.py b/InvenTree/part/test_bom_export.py index 38d9bb5db9..d78ced4b17 100644 --- a/InvenTree/part/test_bom_export.py +++ b/InvenTree/part/test_bom_export.py @@ -18,7 +18,7 @@ class BomExportTest(InvenTreeTestCase): 'bom', ] - roles = ['all'] + roles = 'all' def setUp(self): super().setUp() diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 2971c032e0..f20fc3159f 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -17,7 +17,7 @@ class PartViewTestCase(TestCase): 'supplier_part', ] - roles = ['all'] + roles = 'all' def setUp(self): super().setUp() diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index d9be17fde0..9ccc99528f 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -260,7 +260,7 @@ class PanelMixinTests(TestCase): 'stock', ] - roles = ['all'] + roles = 'all' def test_installed(self): """Test that the sample panel plugin is installed""" diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py index acea850046..dba39334de 100644 --- a/InvenTree/stock/test_views.py +++ b/InvenTree/stock/test_views.py @@ -18,7 +18,7 @@ class StockViewTestCase(InvenTreeTestCase): 'stock', ] - roles = ['all'] + roles = 'all' class StockListTest(StockViewTestCase): From 799af89312bb280e3388e53a405cc95ee858fdf9 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 17:45:04 +0200 Subject: [PATCH 18/28] style fixes --- InvenTree/InvenTree/api_tester.py | 5 +++-- InvenTree/InvenTree/test_api.py | 11 +++++------ InvenTree/plugin/base/integration/test_mixins.py | 10 +++++----- setup.cfg | 4 +--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index c5d96e6bb3..cb5f02cf43 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -6,9 +6,10 @@ import csv import io import re -from django.http.response import StreamingHttpResponse from django.contrib.auth import get_user_model from django.contrib.auth.models import Group +from django.http.response import StreamingHttpResponse + from rest_framework.test import APITestCase @@ -60,7 +61,7 @@ class UserMixin: if self.auto_login: self.client.login(username=self.username, password=self.password) - def assignRole(self, role = None, assign_all: bool = False): + def assignRole(self, role=None, assign_all: bool = False): """ Set the user roles for the registered user """ diff --git a/InvenTree/InvenTree/test_api.py b/InvenTree/InvenTree/test_api.py index 10e2305d07..889ff674b3 100644 --- a/InvenTree/InvenTree/test_api.py +++ b/InvenTree/InvenTree/test_api.py @@ -1,16 +1,15 @@ """ Low level tests for the InvenTree API """ +from base64 import b64encode + +from django.urls import reverse + from rest_framework import status -from django.urls import reverse -from InvenTree.helpers import InvenTreeTestCase - from InvenTree.api_tester import InvenTreeAPITestCase - +from InvenTree.helpers import InvenTreeTestCase from users.models import RuleSet -from base64 import b64encode - class HTMLAPITests(InvenTreeTestCase): """ diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index 9ccc99528f..20a99e71bd 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -1,18 +1,18 @@ """ Unit tests for base mixins for plugins """ -from django.test import TestCase from django.conf import settings -from django.urls import include, re_path, reverse from django.contrib.auth import get_user_model +from django.test import TestCase +from django.urls import include, re_path, reverse from error_report.models import Error from plugin import InvenTreePlugin -from plugin.mixins import AppMixin, SettingsMixin, UrlsMixin, NavigationMixin, APICallMixin -from plugin.urls import PLUGIN_BASE from plugin.helpers import MixinNotImplementedError - +from plugin.mixins import (APICallMixin, AppMixin, NavigationMixin, + SettingsMixin, UrlsMixin) from plugin.registry import registry +from plugin.urls import PLUGIN_BASE class BaseMixinDefinition: diff --git a/setup.cfg b/setup.cfg index 7fcf9718fe..3aa96371ec 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ ignore = # - W605 - invalid escape sequence W605, # - E501 - line too long (82 characters) - E501, + E501, # - E722 - do not use bare except E722, # - C901 - function is too complex @@ -28,6 +28,4 @@ source = ./InvenTree src_paths=InvenTree skip_glob =*/migrations/*.py known_django=django -import_heading_firstparty=InvenTree imports -import_heading_thirdparty=Third-Party imports sections=FUTURE, STDLIB, DJANGO, THIRDPARTY, FIRSTPARTY, LOCALFOLDER From 45a9a4d0c59968747ce71c3ac1faab179dbf1543 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 17:55:11 +0200 Subject: [PATCH 19/28] add in missing class references --- InvenTree/part/test_views.py | 5 +++-- InvenTree/plugin/base/integration/test_mixins.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index f20fc3159f..60fba1fd97 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -1,12 +1,13 @@ """ Unit tests for Part Views (see views.py) """ -from django.test import TestCase from django.urls import reverse +from InvenTree.helpers import InvenTreeTestCase + from .models import Part -class PartViewTestCase(TestCase): +class PartViewTestCase(InvenTreeTestCase): fixtures = [ 'category', diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index 20a99e71bd..f60e6a2802 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -7,6 +7,7 @@ from django.urls import include, re_path, reverse from error_report.models import Error +from InvenTree.helpers import InvenTreeTestCase from plugin import InvenTreePlugin from plugin.helpers import MixinNotImplementedError from plugin.mixins import (APICallMixin, AppMixin, NavigationMixin, @@ -250,7 +251,7 @@ class APICallMixinTest(BaseMixinDefinition, TestCase): self.mixin_wrong2.has_api_call() -class PanelMixinTests(TestCase): +class PanelMixinTests(InvenTreeTestCase): """Test that the PanelMixin plugin operates correctly""" fixtures = [ From 9b15d88d5fdddfe643dbec3885b010153b29a61b Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 18:34:45 +0200 Subject: [PATCH 20/28] fix rule assign --- InvenTree/InvenTree/api_tester.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index cb5f02cf43..935252de5b 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -52,7 +52,7 @@ class UserMixin: # Assign all roles if set if self.roles == 'all': - self.assignRole() + self.assignRole(assign_all=True) # else filter the roles else: for role in self.roles: @@ -68,7 +68,7 @@ class UserMixin: # role is of the format 'rule.permission' e.g. 'part.add' - if not assign_all: + if not assign_all and role: rule, perm = role.split('.') for ruleset in self.group.rule_sets.all(): From 556b7036aafc64e9d2fd8c378b2bf05a7caa1c7c Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 18:42:41 +0200 Subject: [PATCH 21/28] remove repo name from assertations this breaks on other runners (gitlab, azure devops) as they handle repo names in another way --- InvenTree/InvenTree/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 26b50a0eca..b1e06f081a 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -548,7 +548,7 @@ class TestSettings(TestCase): # with env set 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): # normal run - not configured From 43a2442f023f5f89d6b97b5869f5cd91a9baed04 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 18:53:33 +0200 Subject: [PATCH 22/28] add usermodel back in --- InvenTree/InvenTree/tests.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 335c29c742..09278c6f12 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -8,6 +8,7 @@ from django.test import TestCase, override_settings import django.core.exceptions as django_exceptions from django.core.exceptions import ValidationError from django.conf import settings +from django.contrib.auth import get_user_model from djmoney.money import Money from djmoney.contrib.exchange.models import Rate, convert_money @@ -476,8 +477,9 @@ class TestSettings(helpers.InvenTreeTestCase): @override_settings(TESTING_ENV=True) def test_set_user_to_few(self): + user_model = get_user_model() # add shortcut - user_count = self.user_mdl.objects.count + user_count = user_model.objects.count # enable testing mode settings.TESTING_ENV = True @@ -500,7 +502,7 @@ class TestSettings(helpers.InvenTreeTestCase): self.assertEqual(user_count(), 2) # create user manually - self.user_mdl.objects.create_user('testuser', 'test@testing.com', 'password') + user_model.objects.create_user('testuser', 'test@testing.com', 'password') self.assertEqual(user_count(), 3) # check it will not be created again self.run_reload({ From b7a501f42cf17bbce3212d414d265ff8f994fd56 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 19:09:51 +0200 Subject: [PATCH 23/28] log out first --- InvenTree/users/tests.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py index f296e3194f..8a591c7971 100644 --- a/InvenTree/users/tests.py +++ b/InvenTree/users/tests.py @@ -203,11 +203,13 @@ class OwnerModelTest(InvenTreeTestCase): """ Test user APIs """ + self.client.logout() + # not authed self.do_request(reverse('api-owner-list'), {}, 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 self.do_request(reverse('api-owner-list'), {}) # user list with search @@ -220,12 +222,14 @@ class OwnerModelTest(InvenTreeTestCase): """ Test token mechanisms """ + self.client.logout() + token = Token.objects.filter(user=self.user) # not authed 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 response = self.do_request(reverse('api-token'), {}) self.assertEqual(response['token'], token.first().key) From 6ef8c3dc832876241922e718307524bb9490c028 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 19:11:21 +0200 Subject: [PATCH 24/28] run as admin --- InvenTree/part/test_views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 60fba1fd97..21ec6f7909 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -19,6 +19,7 @@ class PartViewTestCase(InvenTreeTestCase): ] roles = 'all' + superuser = True def setUp(self): super().setUp() From 9af0b981e70f70fe5dec9837232a3fe0cf3ef1b8 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 19:14:35 +0200 Subject: [PATCH 25/28] fix class to enable userlogin --- InvenTree/build/test_api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py index a736b01cad..1adf38935e 100644 --- a/InvenTree/build/test_api.py +++ b/InvenTree/build/test_api.py @@ -2,7 +2,6 @@ from datetime import datetime, timedelta from django.urls import reverse -from rest_framework.test import APITestCase from rest_framework import status from part.models import Part @@ -13,7 +12,7 @@ from InvenTree.status_codes import BuildStatus from InvenTree.api_tester import InvenTreeAPITestCase -class TestBuildAPI(APITestCase): +class TestBuildAPI(InvenTreeAPITestCase): """ Series of tests for the Build DRF API - Tests for Build API From 43f714b96c0d5cfb54677e8be109f0bda4d7b24e Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 19:57:13 +0200 Subject: [PATCH 26/28] use variable for values and up the all --- InvenTree/InvenTree/tests.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 09278c6f12..4f34d7fabf 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -501,14 +501,18 @@ class TestSettings(helpers.InvenTreeTestCase): }) self.assertEqual(user_count(), 2) + username2 = 'testuser1' + email2 = 'test1@testing.com' + password2 = 'password1' + # create user manually - user_model.objects.create_user('testuser', 'test@testing.com', 'password') + user_model.objects.create_user(username2, email2, password2) self.assertEqual(user_count(), 3) # check it will not be created again self.run_reload({ - 'INVENTREE_ADMIN_USER': 'testuser', - 'INVENTREE_ADMIN_EMAIL': 'test@testing.com', - 'INVENTREE_ADMIN_PASSWORD': 'password', + 'INVENTREE_ADMIN_USER': username2, + 'INVENTREE_ADMIN_EMAIL': email2, + 'INVENTREE_ADMIN_PASSWORD': password2, }) self.assertEqual(user_count(), 3) From e1ff4b6e873eeef71e9121d8b702c4d9b6458173 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Fri, 20 May 2022 23:01:20 +0200 Subject: [PATCH 27/28] more class use --- InvenTree/order/test_views.py | 36 ++++++------------- InvenTree/plugin/base/action/test_action.py | 10 ++---- .../plugin/base/barcodes/test_barcode.py | 11 ++---- .../plugin/base/integration/test_mixins.py | 9 ++--- .../builtin/action/test_simpleactionplugin.py | 13 +++---- .../barcodes/test_inventree_barcode.py | 13 ++----- .../plugin/samples/integration/test_sample.py | 12 ++----- 7 files changed, 28 insertions(+), 76 deletions(-) diff --git a/InvenTree/order/test_views.py b/InvenTree/order/test_views.py index e38ea7ecef..aad0fed25d 100644 --- a/InvenTree/order/test_views.py +++ b/InvenTree/order/test_views.py @@ -1,12 +1,11 @@ """ Unit tests for Order views (see views.py) """ -from django.test import TestCase from django.urls import reverse -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group + +from InvenTree.helpers import InvenTreeTestCase -class OrderViewTestCase(TestCase): +class OrderViewTestCase(InvenTreeTestCase): fixtures = [ 'category', @@ -19,27 +18,14 @@ class OrderViewTestCase(TestCase): 'order', ] - def setUp(self): - super().setUp() - - # Create a user - user = get_user_model().objects.create_user('username', 'user@email.com', 'password') - - # Ensure that the user has the correct permissions! - 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') + roles = [ + 'purchase_order.change', + 'purchase_order.add', + 'purchase_order.delete', + 'sales_order.change', + 'sales_order.add', + 'sales_order.delete', + ] class OrderListTest(OrderViewTestCase): diff --git a/InvenTree/plugin/base/action/test_action.py b/InvenTree/plugin/base/action/test_action.py index 16790ccd62..84482da4f7 100644 --- a/InvenTree/plugin/base/action/test_action.py +++ b/InvenTree/plugin/base/action/test_action.py @@ -1,8 +1,8 @@ """ Unit tests for action plugins """ from django.test import TestCase -from django.contrib.auth import get_user_model +from InvenTree.InvenTree.helpers import InvenTreeTestCase from plugin import InvenTreePlugin from plugin.mixins import ActionMixin @@ -65,15 +65,9 @@ class ActionMixinTests(TestCase): }) -class APITests(TestCase): +class APITests(InvenTreeTestCase): """ 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): """Check the possible errors with post""" diff --git a/InvenTree/plugin/base/barcodes/test_barcode.py b/InvenTree/plugin/base/barcodes/test_barcode.py index 43a713a57b..15deb2665c 100644 --- a/InvenTree/plugin/base/barcodes/test_barcode.py +++ b/InvenTree/plugin/base/barcodes/test_barcode.py @@ -4,16 +4,15 @@ Unit tests for Barcode endpoints """ -from django.contrib.auth import get_user_model from django.urls import reverse -from rest_framework.test import APITestCase from rest_framework import status +from InvenTree.InvenTree.api_tester import InvenTreeAPITestCase from stock.models import StockItem -class BarcodeAPITest(APITestCase): +class BarcodeAPITest(InvenTreeAPITestCase): fixtures = [ 'category', @@ -23,11 +22,7 @@ class BarcodeAPITest(APITestCase): ] 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') + super().setUp() self.scan_url = reverse('api-barcode-scan') self.assign_url = reverse('api-barcode-link') diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index f60e6a2802..9759e0f00d 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -1,7 +1,6 @@ """ Unit tests for base mixins for plugins """ from django.conf import settings -from django.contrib.auth import get_user_model from django.test import TestCase from django.urls import include, re_path, reverse @@ -24,7 +23,7 @@ class BaseMixinDefinition: 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_NAME = 'settings' MIXIN_ENABLE_CHECK = 'has_settings' @@ -40,9 +39,7 @@ class SettingsMixinTest(BaseMixinDefinition, TestCase): pass self.mixin_nothing = NoSettingsCls() - user = get_user_model() - self.test_user = user.objects.create_user('testuser', 'test@testing.com', 'password') - self.test_user.is_staff = True + super().setUp() def test_function(self): # settings variable @@ -54,7 +51,7 @@ class SettingsMixinTest(BaseMixinDefinition, TestCase): self.assertEqual(self.mixin_nothing.get_setting('ABCD'), '') # 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') # no setting diff --git a/InvenTree/plugin/builtin/action/test_simpleactionplugin.py b/InvenTree/plugin/builtin/action/test_simpleactionplugin.py index 92e1affa67..0cadc27d9f 100644 --- a/InvenTree/plugin/builtin/action/test_simpleactionplugin.py +++ b/InvenTree/plugin/builtin/action/test_simpleactionplugin.py @@ -1,20 +1,15 @@ """ Unit tests for action plugins """ -from django.test import TestCase -from django.contrib.auth import get_user_model - +from InvenTree.InvenTree.helpers import InvenTreeTestCase from plugin.builtin.action.simpleactionplugin import SimpleActionPlugin -class SimpleActionPluginTests(TestCase): +class SimpleActionPluginTests(InvenTreeTestCase): """ Tests for SampleIntegrationPlugin """ def setUp(self): - # Create a user for auth - user = get_user_model() - self.test_user = user.objects.create_user('testuser', 'test@testing.com', 'password') + super().setUp() - self.client.login(username='testuser', password='password') self.plugin = SimpleActionPlugin() def test_name(self): @@ -33,7 +28,7 @@ class SimpleActionPluginTests(TestCase): "action": 'simple', "result": True, "info": { - "user": "testuser", + "user": self.username, "hello": "world", }, } diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py index 1424d89ff2..0c1a91ed6a 100644 --- a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- """Unit tests for InvenTreeBarcodePlugin""" -from django.contrib.auth import get_user_model from django.urls import reverse -from rest_framework.test import APITestCase from rest_framework import status +from InvenTree.InvenTree.api_tester import InvenTreeAPITestCase -class TestInvenTreeBarcode(APITestCase): + +class TestInvenTreeBarcode(InvenTreeAPITestCase): fixtures = [ 'category', @@ -17,13 +17,6 @@ class TestInvenTreeBarcode(APITestCase): '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): """ Test all possible error cases for assigment action diff --git a/InvenTree/plugin/samples/integration/test_sample.py b/InvenTree/plugin/samples/integration/test_sample.py index 733e443638..1d477144a3 100644 --- a/InvenTree/plugin/samples/integration/test_sample.py +++ b/InvenTree/plugin/samples/integration/test_sample.py @@ -1,19 +1,11 @@ """ Unit tests for action plugins """ -from django.test import TestCase -from django.contrib.auth import get_user_model +from InvenTree.InvenTree.helpers import InvenTreeTestCase -class SampleIntegrationPluginTests(TestCase): +class SampleIntegrationPluginTests(InvenTreeTestCase): """ 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): """check the function of the custom sample plugin """ response = self.client.get('/plugin/sample/ho/he/') From 22adc372423f4879982be1d791bd6a5cb0ba17d0 Mon Sep 17 00:00:00 2001 From: Matthias Mair <code@mjmair.com> Date: Sat, 21 May 2022 02:40:45 +0200 Subject: [PATCH 28/28] fix import --- InvenTree/plugin/base/action/test_action.py | 2 +- InvenTree/plugin/base/barcodes/test_barcode.py | 2 +- InvenTree/plugin/builtin/action/test_simpleactionplugin.py | 2 +- InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py | 2 +- InvenTree/plugin/samples/integration/test_sample.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/InvenTree/plugin/base/action/test_action.py b/InvenTree/plugin/base/action/test_action.py index 84482da4f7..5678a0d44e 100644 --- a/InvenTree/plugin/base/action/test_action.py +++ b/InvenTree/plugin/base/action/test_action.py @@ -2,7 +2,7 @@ from django.test import TestCase -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase from plugin import InvenTreePlugin from plugin.mixins import ActionMixin diff --git a/InvenTree/plugin/base/barcodes/test_barcode.py b/InvenTree/plugin/base/barcodes/test_barcode.py index 15deb2665c..4b66f8b208 100644 --- a/InvenTree/plugin/base/barcodes/test_barcode.py +++ b/InvenTree/plugin/base/barcodes/test_barcode.py @@ -8,7 +8,7 @@ from django.urls import reverse from rest_framework import status -from InvenTree.InvenTree.api_tester import InvenTreeAPITestCase +from InvenTree.api_tester import InvenTreeAPITestCase from stock.models import StockItem diff --git a/InvenTree/plugin/builtin/action/test_simpleactionplugin.py b/InvenTree/plugin/builtin/action/test_simpleactionplugin.py index 0cadc27d9f..e645dea85c 100644 --- a/InvenTree/plugin/builtin/action/test_simpleactionplugin.py +++ b/InvenTree/plugin/builtin/action/test_simpleactionplugin.py @@ -1,6 +1,6 @@ """ Unit tests for action plugins """ -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase from plugin.builtin.action.simpleactionplugin import SimpleActionPlugin diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py index 0c1a91ed6a..0bc855aa24 100644 --- a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py @@ -5,7 +5,7 @@ from django.urls import reverse from rest_framework import status -from InvenTree.InvenTree.api_tester import InvenTreeAPITestCase +from InvenTree.api_tester import InvenTreeAPITestCase class TestInvenTreeBarcode(InvenTreeAPITestCase): diff --git a/InvenTree/plugin/samples/integration/test_sample.py b/InvenTree/plugin/samples/integration/test_sample.py index 1d477144a3..577aa5812e 100644 --- a/InvenTree/plugin/samples/integration/test_sample.py +++ b/InvenTree/plugin/samples/integration/test_sample.py @@ -1,6 +1,6 @@ """ Unit tests for action plugins """ -from InvenTree.InvenTree.helpers import InvenTreeTestCase +from InvenTree.helpers import InvenTreeTestCase class SampleIntegrationPluginTests(InvenTreeTestCase):