diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py
index bc852b4faa..7714b42306 100644
--- a/InvenTree/report/models.py
+++ b/InvenTree/report/models.py
@@ -567,8 +567,7 @@ def rename_asset(instance, filename):
 
 
 class ReportAsset(models.Model):
-    """
-    Asset file for use in report templates.
+    """Asset file for use in report templates.
     For example, an image to use in a header file.
     Uploaded asset files appear in MEDIA_ROOT/report/assets,
     and can be loaded in a template using the {% report_asset <filename> %} tag.
diff --git a/InvenTree/report/templatetags/barcode.py b/InvenTree/report/templatetags/barcode.py
index 8d8397d50a..1abf0b1eea 100644
--- a/InvenTree/report/templatetags/barcode.py
+++ b/InvenTree/report/templatetags/barcode.py
@@ -1,6 +1,4 @@
-"""
-Template tags for rendering various barcodes
-"""
+"""Template tags for rendering various barcodes"""
 
 import base64
 from io import BytesIO
@@ -14,12 +12,10 @@ register = template.Library()
 
 
 def image_data(img, fmt='PNG'):
-    """
-    Convert an image into HTML renderable data
+    """Convert an image into HTML renderable data
 
     Returns a string ``data:image/FMT;base64,xxxxxxxxx`` which can be rendered to an <img> tag
     """
-
     buffered = BytesIO()
     img.save(buffered, format=fmt)
 
@@ -30,8 +26,7 @@ def image_data(img, fmt='PNG'):
 
 @register.simple_tag()
 def qrcode(data, **kwargs):
-    """
-    Return a byte-encoded QR code image
+    """Return a byte-encoded QR code image
 
     Optional kwargs
     ---------------
@@ -39,7 +34,6 @@ def qrcode(data, **kwargs):
     fill_color: Fill color (default = black)
     back_color: Background color (default = white)
     """
-
     # Construct "default" values
     params = dict(
         box_size=20,
@@ -63,10 +57,7 @@ def qrcode(data, **kwargs):
 
 @register.simple_tag()
 def barcode(data, barcode_class='code128', **kwargs):
-    """
-    Render a barcode
-    """
-
+    """Render a barcode"""
     constructor = python_barcode.get_barcode_class(barcode_class)
 
     data = str(data).zfill(constructor.digits)
diff --git a/InvenTree/report/templatetags/report.py b/InvenTree/report/templatetags/report.py
index 8a14501933..7d6be7d836 100644
--- a/InvenTree/report/templatetags/report.py
+++ b/InvenTree/report/templatetags/report.py
@@ -1,6 +1,4 @@
-"""
-Custom template tags for report generation
-"""
+"""Custom template tags for report generation"""
 
 import os
 
@@ -19,10 +17,7 @@ register = template.Library()
 
 @register.simple_tag()
 def asset(filename):
-    """
-    Return fully-qualified path for an upload report asset file.
-    """
-
+    """Return fully-qualified path for an upload report asset file."""
     # If in debug mode, return URL to the image, not a local file
     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')
 
@@ -38,10 +33,7 @@ def asset(filename):
 
 @register.simple_tag()
 def part_image(part):
-    """
-    Return a fully-qualified path for a part image
-    """
-
+    """Return a fully-qualified path for a part image"""
     # If in debug mode, return URL to the image, not a local file
     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')
 
@@ -75,10 +67,7 @@ def part_image(part):
 
 @register.simple_tag()
 def company_image(company):
-    """
-    Return a fully-qualified path for a company image
-    """
-
+    """Return a fully-qualified path for a company image"""
     # If in debug mode, return the URL to the image, not a local file
     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')
 
@@ -108,15 +97,13 @@ def company_image(company):
 
 @register.simple_tag()
 def internal_link(link, text):
-    """
-    Make a <a></a> href which points to an InvenTree URL.
+    """Make a <a></a> href which points to an InvenTree URL.
 
     Important Note: This only works if the INVENTREE_BASE_URL parameter is set!
 
     If the INVENTREE_BASE_URL parameter is not configured,
     the text will be returned (unlinked)
     """
-
     text = str(text)
 
     url = InvenTree.helpers.construct_absolute_url(link)
diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py
index 38fbb491bf..9d5508b249 100644
--- a/InvenTree/report/tests.py
+++ b/InvenTree/report/tests.py
@@ -36,10 +36,7 @@ class ReportTest(InvenTreeAPITestCase):
         super().setUp()
 
     def copyReportTemplate(self, filename, description):
-        """
-        Copy the provided report template into the required media directory
-        """
-
+        """Copy the provided report template into the required media directory"""
         src_dir = os.path.join(
             os.path.dirname(os.path.realpath(__file__)),
             'templates',
@@ -81,10 +78,7 @@ class ReportTest(InvenTreeAPITestCase):
         )
 
     def test_list_endpoint(self):
-        """
-        Test that the LIST endpoint works for each report
-        """
-
+        """Test that the LIST endpoint works for each report"""
         if not self.list_url:
             return
 
@@ -135,10 +129,7 @@ class TestReportTest(ReportTest):
         return super().setUp()
 
     def test_print(self):
-        """
-        Printing tests for the TestReport
-        """
-
+        """Printing tests for the TestReport"""
         report = self.model.objects.first()
 
         url = reverse(self.print_url, kwargs={'pk': report.pk})
@@ -177,10 +168,7 @@ class BuildReportTest(ReportTest):
         return super().setUp()
 
     def test_print(self):
-        """
-        Printing tests for the BuildReport
-        """
-
+        """Printing tests for the BuildReport"""
         report = self.model.objects.first()
 
         url = reverse(self.print_url, kwargs={'pk': report.pk})
diff --git a/InvenTree/script/translation_stats.py b/InvenTree/script/translation_stats.py
index e96708d1f2..36032ed1e0 100644
--- a/InvenTree/script/translation_stats.py
+++ b/InvenTree/script/translation_stats.py
@@ -1,6 +1,4 @@
-"""
-This script calculates translation coverage for various languages
-"""
+"""This script calculates translation coverage for various languages"""
 
 import json
 import os
diff --git a/InvenTree/stock/__init__.py b/InvenTree/stock/__init__.py
index 6970329be1..524da0600c 100644
--- a/InvenTree/stock/__init__.py
+++ b/InvenTree/stock/__init__.py
@@ -1,5 +1,4 @@
-"""
-The Stock module is responsible for Stock management.
+"""The Stock module is responsible for Stock management.
 
 It includes models for:
 
diff --git a/InvenTree/stock/admin.py b/InvenTree/stock/admin.py
index 85d7b7afe0..85561c9786 100644
--- a/InvenTree/stock/admin.py
+++ b/InvenTree/stock/admin.py
@@ -15,7 +15,7 @@ from .models import (StockItem, StockItemAttachment, StockItemTestResult,
 
 
 class LocationResource(ModelResource):
-    """ Class for managing StockLocation data import/export """
+    """Class for managing StockLocation data import/export"""
 
     parent = Field(attribute='parent', widget=widgets.ForeignKeyWidget(StockLocation))
 
@@ -42,9 +42,7 @@ class LocationResource(ModelResource):
 
 
 class LocationInline(admin.TabularInline):
-    """
-    Inline for sub-locations
-    """
+    """Inline for sub-locations"""
     model = StockLocation
 
 
@@ -66,7 +64,7 @@ class LocationAdmin(ImportExportModelAdmin):
 
 
 class StockItemResource(ModelResource):
-    """ Class for managing StockItem data import/export """
+    """Class for managing StockItem data import/export"""
 
     # Custom managers for ForeignKey fields
     part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py
index 4bc21df5a9..56b316eb50 100644
--- a/InvenTree/stock/api.py
+++ b/InvenTree/stock/api.py
@@ -1,6 +1,4 @@
-"""
-JSON API for the Stock app
-"""
+"""JSON API for the Stock app"""
 
 from collections import OrderedDict
 from datetime import datetime, timedelta
@@ -39,7 +37,7 @@ from stock.models import (StockItem, StockItemAttachment, StockItemTestResult,
 
 
 class StockDetail(generics.RetrieveUpdateDestroyAPIView):
-    """ API detail endpoint for Stock object
+    """API detail endpoint for Stock object
 
     get:
     Return a single StockItem object
@@ -89,7 +87,7 @@ class StockMetadata(generics.RetrieveUpdateAPIView):
 
 
 class StockItemContextMixin:
-    """ Mixin class for adding StockItem object to serializer context """
+    """Mixin class for adding StockItem object to serializer context"""
 
     def get_serializer_context(self):
 
@@ -105,17 +103,14 @@ class StockItemContextMixin:
 
 
 class StockItemSerialize(StockItemContextMixin, generics.CreateAPIView):
-    """
-    API endpoint for serializing a stock item
-    """
+    """API endpoint for serializing a stock item"""
 
     queryset = StockItem.objects.none()
     serializer_class = StockSerializers.SerializeStockItemSerializer
 
 
 class StockItemInstall(StockItemContextMixin, generics.CreateAPIView):
-    """
-    API endpoint for installing a particular stock item into this stock item.
+    """API endpoint for installing a particular stock item into this stock item.
 
     - stock_item.part must be in the BOM for this part
     - stock_item must currently be "in stock"
@@ -127,17 +122,14 @@ class StockItemInstall(StockItemContextMixin, generics.CreateAPIView):
 
 
 class StockItemUninstall(StockItemContextMixin, generics.CreateAPIView):
-    """
-    API endpoint for removing (uninstalling) items from this item
-    """
+    """API endpoint for removing (uninstalling) items from this item"""
 
     queryset = StockItem.objects.none()
     serializer_class = StockSerializers.UninstallStockItemSerializer
 
 
 class StockAdjustView(generics.CreateAPIView):
-    """
-    A generic class for handling stocktake actions.
+    """A generic class for handling stocktake actions.
 
     Subclasses exist for:
 
@@ -159,41 +151,31 @@ class StockAdjustView(generics.CreateAPIView):
 
 
 class StockCount(StockAdjustView):
-    """
-    Endpoint for counting stock (performing a stocktake).
-    """
+    """Endpoint for counting stock (performing a stocktake)."""
 
     serializer_class = StockSerializers.StockCountSerializer
 
 
 class StockAdd(StockAdjustView):
-    """
-    Endpoint for adding a quantity of stock to an existing StockItem
-    """
+    """Endpoint for adding a quantity of stock to an existing StockItem"""
 
     serializer_class = StockSerializers.StockAddSerializer
 
 
 class StockRemove(StockAdjustView):
-    """
-    Endpoint for removing a quantity of stock from an existing StockItem.
-    """
+    """Endpoint for removing a quantity of stock from an existing StockItem."""
 
     serializer_class = StockSerializers.StockRemoveSerializer
 
 
 class StockTransfer(StockAdjustView):
-    """
-    API endpoint for performing stock movements
-    """
+    """API endpoint for performing stock movements"""
 
     serializer_class = StockSerializers.StockTransferSerializer
 
 
 class StockAssign(generics.CreateAPIView):
-    """
-    API endpoint for assigning stock to a particular customer
-    """
+    """API endpoint for assigning stock to a particular customer"""
 
     queryset = StockItem.objects.all()
     serializer_class = StockSerializers.StockAssignmentSerializer
@@ -208,9 +190,7 @@ class StockAssign(generics.CreateAPIView):
 
 
 class StockMerge(generics.CreateAPIView):
-    """
-    API endpoint for merging multiple stock items
-    """
+    """API endpoint for merging multiple stock items"""
 
     queryset = StockItem.objects.none()
     serializer_class = StockSerializers.StockMergeSerializer
@@ -222,8 +202,7 @@ class StockMerge(generics.CreateAPIView):
 
 
 class StockLocationList(generics.ListCreateAPIView):
-    """
-    API endpoint for list view of StockLocation objects:
+    """API endpoint for list view of StockLocation objects:
 
     - GET: Return list of StockLocation objects
     - POST: Create a new StockLocation
@@ -233,11 +212,9 @@ class StockLocationList(generics.ListCreateAPIView):
     serializer_class = StockSerializers.LocationSerializer
 
     def filter_queryset(self, queryset):
-        """
-        Custom filtering:
+        """Custom filtering:
         - Allow filtering by "null" parent to retrieve top-level stock locations
         """
-
         queryset = super().filter_queryset(queryset)
 
         params = self.request.query_params
@@ -319,10 +296,7 @@ class StockLocationList(generics.ListCreateAPIView):
 
 
 class StockLocationTree(generics.ListAPIView):
-    """
-    API endpoint for accessing a list of StockLocation objects,
-    ready for rendering as a tree
-    """
+    """API endpoint for accessing a list of StockLocation objects, ready for rendering as a tree"""
 
     queryset = StockLocation.objects.all()
     serializer_class = StockSerializers.LocationTreeSerializer
@@ -337,9 +311,7 @@ class StockLocationTree(generics.ListAPIView):
 
 
 class StockFilter(rest_filters.FilterSet):
-    """
-    FilterSet for StockItem LIST API
-    """
+    """FilterSet for StockItem LIST API"""
 
     # Part name filters
     name = rest_filters.CharFilter(label='Part name (case insensitive)', field_name='part__name', lookup_expr='iexact')
@@ -372,12 +344,10 @@ class StockFilter(rest_filters.FilterSet):
     available = rest_filters.BooleanFilter(label='Available', method='filter_available')
 
     def filter_available(self, queryset, name, value):
-        """
-        Filter by whether the StockItem is "available" or not.
+        """Filter by whether the StockItem is "available" or not.
 
         Here, "available" means that the allocated quantity is less than the total quantity
         """
-
         if str2bool(value):
             # The 'quantity' field is greater than the calculated 'allocated' field
             queryset = queryset.filter(Q(quantity__gt=F('allocated')))
@@ -401,10 +371,7 @@ class StockFilter(rest_filters.FilterSet):
     serialized = rest_filters.BooleanFilter(label='Has serial number', method='filter_serialized')
 
     def filter_serialized(self, queryset, name, value):
-        """
-        Filter by whether the StockItem has a serial number (or not)
-        """
-
+        """Filter by whether the StockItem has a serial number (or not)"""
         q = Q(serial=None) | Q(serial='')
 
         if str2bool(value):
@@ -417,10 +384,7 @@ class StockFilter(rest_filters.FilterSet):
     has_batch = rest_filters.BooleanFilter(label='Has batch code', method='filter_has_batch')
 
     def filter_has_batch(self, queryset, name, value):
-        """
-        Filter by whether the StockItem has a batch code (or not)
-        """
-
+        """Filter by whether the StockItem has a batch code (or not)"""
         q = Q(batch=None) | Q(batch='')
 
         if str2bool(value):
@@ -433,12 +397,10 @@ class StockFilter(rest_filters.FilterSet):
     tracked = rest_filters.BooleanFilter(label='Tracked', method='filter_tracked')
 
     def filter_tracked(self, queryset, name, value):
-        """
-        Filter by whether this stock item is *tracked*, meaning either:
+        """Filter by whether this stock item is *tracked*, meaning either:
         - It has a serial number
         - It has a batch code
         """
-
         q_batch = Q(batch=None) | Q(batch='')
         q_serial = Q(serial=None) | Q(serial='')
 
@@ -452,10 +414,7 @@ class StockFilter(rest_filters.FilterSet):
     installed = rest_filters.BooleanFilter(label='Installed in other stock item', method='filter_installed')
 
     def filter_installed(self, queryset, name, value):
-        """
-        Filter stock items by "belongs_to" field being empty
-        """
-
+        """Filter stock items by "belongs_to" field being empty"""
         if str2bool(value):
             queryset = queryset.exclude(belongs_to=None)
         else:
@@ -502,7 +461,7 @@ class StockFilter(rest_filters.FilterSet):
 
 
 class StockList(APIDownloadMixin, generics.ListCreateAPIView):
-    """ API endpoint for list view of Stock objects
+    """API endpoint for list view of Stock objects
 
     - GET: Return a list of all StockItem objects (with optional query filters)
     - POST: Create a new StockItem
@@ -520,15 +479,13 @@ class StockList(APIDownloadMixin, generics.ListCreateAPIView):
         return ctx
 
     def create(self, request, *args, **kwargs):
-        """
-        Create a new StockItem object via the API.
+        """Create a new StockItem object via the API.
 
         We override the default 'create' implementation.
 
         If a location is *not* specified, but the linked *part* has a default location,
         we can pre-fill the location automatically.
         """
-
         user = request.user
 
         # Copy the request data, to side-step "mutability" issues
@@ -643,8 +600,8 @@ class StockList(APIDownloadMixin, generics.ListCreateAPIView):
             return Response(response_data, status=status.HTTP_201_CREATED, headers=self.get_success_headers(serializer.data))
 
     def download_queryset(self, queryset, export_format):
-        """
-        Download this queryset as a file.
+        """Download this queryset as a file.
+
         Uses the APIDownloadMixin mixin class
         """
         dataset = StockItemResource().export(queryset=queryset)
@@ -659,13 +616,11 @@ class StockList(APIDownloadMixin, generics.ListCreateAPIView):
         return DownloadFile(filedata, filename)
 
     def list(self, request, *args, **kwargs):
-        """
-        Override the 'list' method, as the StockLocation objects
+        """Override the 'list' method, as the StockLocation objects
         are very expensive to serialize.
 
         So, we fetch and serialize the required StockLocation objects only as required.
         """
-
         queryset = self.filter_queryset(self.get_queryset())
 
         params = request.query_params
@@ -775,9 +730,7 @@ class StockList(APIDownloadMixin, generics.ListCreateAPIView):
         return queryset
 
     def filter_queryset(self, queryset):
-        """
-        Custom filtering for the StockItem queryset
-        """
+        """Custom filtering for the StockItem queryset"""
 
         params = self.request.query_params
 
@@ -1090,9 +1043,7 @@ class StockList(APIDownloadMixin, generics.ListCreateAPIView):
 
 
 class StockAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
-    """
-    API endpoint for listing (and creating) a StockItemAttachment (file upload)
-    """
+    """API endpoint for listing (and creating) a StockItemAttachment (file upload)"""
 
     queryset = StockItemAttachment.objects.all()
     serializer_class = StockSerializers.StockItemAttachmentSerializer
@@ -1109,27 +1060,21 @@ class StockAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
 
 
 class StockAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin):
-    """
-    Detail endpoint for StockItemAttachment
-    """
+    """Detail endpoint for StockItemAttachment"""
 
     queryset = StockItemAttachment.objects.all()
     serializer_class = StockSerializers.StockItemAttachmentSerializer
 
 
 class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView):
-    """
-    Detail endpoint for StockItemTestResult
-    """
+    """Detail endpoint for StockItemTestResult"""
 
     queryset = StockItemTestResult.objects.all()
     serializer_class = StockSerializers.StockItemTestResultSerializer
 
 
 class StockItemTestResultList(generics.ListCreateAPIView):
-    """
-    API endpoint for listing (and creating) a StockItemTestResult object.
-    """
+    """API endpoint for listing (and creating) a StockItemTestResult object."""
 
     queryset = StockItemTestResult.objects.all()
     serializer_class = StockSerializers.StockItemTestResultSerializer
@@ -1205,8 +1150,7 @@ class StockItemTestResultList(generics.ListCreateAPIView):
         return self.serializer_class(*args, **kwargs)
 
     def perform_create(self, serializer):
-        """
-        Create a new test result object.
+        """Create a new test result object.
 
         Also, check if an attachment was uploaded alongside the test result,
         and save it to the database if it were.
@@ -1219,16 +1163,14 @@ class StockItemTestResultList(generics.ListCreateAPIView):
 
 
 class StockTrackingDetail(generics.RetrieveAPIView):
-    """
-    Detail API endpoint for StockItemTracking model
-    """
+    """Detail API endpoint for StockItemTracking model"""
 
     queryset = StockItemTracking.objects.all()
     serializer_class = StockSerializers.StockTrackingSerializer
 
 
 class StockTrackingList(generics.ListAPIView):
-    """ API endpoint for list view of StockItemTracking objects.
+    """API endpoint for list view of StockItemTracking objects.
 
     StockItemTracking objects are read-only
     (they are created by internal model functionality)
@@ -1320,7 +1262,7 @@ class StockTrackingList(generics.ListAPIView):
             return Response(data)
 
     def create(self, request, *args, **kwargs):
-        """ Create a new StockItemTracking object
+        """Create a new StockItemTracking object
 
         Here we override the default 'create' implementation,
         to save the user information associated with the request object.
@@ -1374,7 +1316,7 @@ class LocationMetadata(generics.RetrieveUpdateAPIView):
 
 
 class LocationDetail(generics.RetrieveUpdateDestroyAPIView):
-    """ API endpoint for detail view of StockLocation object
+    """API endpoint for detail view of StockLocation object
 
     - GET: Return a single StockLocation object
     - PATCH: Update a StockLocation object
diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py
index 7e615b5eae..847cd875a5 100644
--- a/InvenTree/stock/forms.py
+++ b/InvenTree/stock/forms.py
@@ -1,6 +1,4 @@
-"""
-Django Forms for interacting with Stock app
-"""
+"""Django Forms for interacting with Stock app"""
 
 from InvenTree.forms import HelperForm
 
@@ -8,8 +6,7 @@ from .models import StockItem, StockItemTracking
 
 
 class ReturnStockItemForm(HelperForm):
-    """
-    Form for manually returning a StockItem into stock
+    """Form for manually returning a StockItem into stock
 
     TODO: This could be a simple API driven form!
     """
@@ -22,8 +19,7 @@ class ReturnStockItemForm(HelperForm):
 
 
 class ConvertStockItemForm(HelperForm):
-    """
-    Form for converting a StockItem to a variant of its current part.
+    """Form for converting a StockItem to a variant of its current part.
 
     TODO: Migrate this form to the modern API forms interface
     """
@@ -36,8 +32,7 @@ class ConvertStockItemForm(HelperForm):
 
 
 class TrackingEntryForm(HelperForm):
-    """
-    Form for creating / editing a StockItemTracking object.
+    """Form for creating / editing a StockItemTracking object.
 
     Note: 2021-05-11 - This form is not currently used - should delete?
     """
diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py
index 3faea832d9..be0ab4117d 100644
--- a/InvenTree/stock/models.py
+++ b/InvenTree/stock/models.py
@@ -1,6 +1,4 @@
-"""
-Stock database model definitions
-"""
+"""Stock database model definitions"""
 
 import os
 from datetime import datetime, timedelta
@@ -40,17 +38,16 @@ from users.models import Owner
 
 
 class StockLocation(MetadataMixin, InvenTreeTree):
-    """ Organization tree for StockItem objects
+    """Organization tree for StockItem objects.
+
     A "StockLocation" can be considered a warehouse, or storage location
     Stock locations can be heirarchical as required
     """
 
     def delete(self, *args, **kwargs):
-        """
-        Custom model deletion routine, which updates any child locations or items.
+        """Custom model deletion routine, which updates any child locations or items.
         This must be handled within a transaction.atomic(), otherwise the tree structure is damaged
         """
-
         with transaction.atomic():
 
             parent = self.parent
@@ -84,12 +81,10 @@ class StockLocation(MetadataMixin, InvenTreeTree):
                               related_name='stock_locations')
 
     def get_location_owner(self):
-        """
-        Get the closest "owner" for this location.
+        """Get the closest "owner" for this location.
 
         Start at this location, and traverse "up" the location tree until we find an owner
         """
-
         for loc in self.get_ancestors(include_self=True, ascending=True):
             if loc.owner is not None:
                 return loc.owner
@@ -97,10 +92,7 @@ class StockLocation(MetadataMixin, InvenTreeTree):
         return None
 
     def check_ownership(self, user):
-        """
-        Check if the user "owns" (is one of the owners of) the location.
-        """
-
+        """Check if the user "owns" (is one of the owners of) the location."""
         # Superuser accounts automatically "own" everything
         if user.is_superuser:
             return True
@@ -124,8 +116,7 @@ class StockLocation(MetadataMixin, InvenTreeTree):
         return reverse('stock-location-detail', kwargs={'pk': self.id})
 
     def format_barcode(self, **kwargs):
-        """ Return a JSON string for formatting a barcode for this StockLocation object """
-
+        """Return a JSON string for formatting a barcode for this StockLocation object"""
         return InvenTree.helpers.MakeBarcode(
             'stocklocation',
             self.pk,
@@ -138,18 +129,15 @@ class StockLocation(MetadataMixin, InvenTreeTree):
 
     @property
     def barcode(self):
-        """
-        Brief payload data (e.g. for labels)
-        """
+        """Brief payload data (e.g. for labels)"""
         return self.format_barcode(brief=True)
 
     def get_stock_items(self, cascade=True):
-        """ Return a queryset for all stock items under this category.
+        """Return a queryset for all stock items under this category.
 
         Args:
             cascade: If True, also look under sublocations (default = True)
         """
-
         if cascade:
             query = StockItem.objects.filter(location__in=self.getUniqueChildren(include_self=True))
         else:
@@ -158,13 +146,11 @@ class StockLocation(MetadataMixin, InvenTreeTree):
         return query
 
     def stock_item_count(self, cascade=True):
-        """ Return the number of StockItem objects which live in or under this category
-        """
-
+        """Return the number of StockItem objects which live in or under this category"""
         return self.get_stock_items(cascade).count()
 
     def has_items(self, cascade=True):
-        """ Return True if there are StockItems existing in this category.
+        """Return True if there are StockItems existing in this category.
 
         Args:
             cascade: If True, also search an sublocations (default = True)
@@ -173,15 +159,14 @@ class StockLocation(MetadataMixin, InvenTreeTree):
 
     @property
     def item_count(self):
-        """ Simply returns the number of stock items in this location.
-        Required for tree view serializer.
-        """
+        """Simply returns the number of stock items in this location.
+
+        Required for tree view serializer."""
         return self.stock_item_count()
 
 
 class StockItemManager(TreeManager):
-    """
-    Custom database manager for the StockItem class.
+    """Custom database manager for the StockItem class.
 
     StockItem querysets will automatically prefetch related fields.
     """
@@ -205,13 +190,11 @@ class StockItemManager(TreeManager):
 
 
 def generate_batch_code():
-    """
-    Generate a default 'batch code' for a new StockItem.
+    """Generate a default 'batch code' for a new StockItem.
 
     This uses the value of the 'STOCK_BATCH_CODE_TEMPLATE' setting (if configured),
     which can be passed through a simple template.
     """
-
     batch_template = common.models.InvenTreeSetting.get_setting('STOCK_BATCH_CODE_TEMPLATE', '')
 
     now = datetime.now()
@@ -231,8 +214,7 @@ def generate_batch_code():
 
 
 class StockItem(MetadataMixin, MPTTModel):
-    """
-    A StockItem object represents a quantity of physical instances of a part.
+    """A StockItem object represents a quantity of physical instances of a part.
 
     Attributes:
         parent: Link to another StockItem from which this StockItem was created
@@ -290,11 +272,10 @@ class StockItem(MetadataMixin, MPTTModel):
     EXPIRED_FILTER = IN_STOCK_FILTER & ~Q(expiry_date=None) & Q(expiry_date__lt=datetime.now().date())
 
     def update_serial_number(self):
-        """
-        Update the 'serial_int' field, to be an integer representation of the serial number.
+        """Update the 'serial_int' field, to be an integer representation of the serial number.
+
         This is used for efficient numerical sorting
         """
-
         serial = getattr(self, 'serial', '')
 
         # Default value if we cannot convert to an integer
@@ -309,8 +290,7 @@ class StockItem(MetadataMixin, MPTTModel):
         self.serial_int = serial_int
 
     def get_next_serialized_item(self, include_variants=True, reverse=False):
-        """
-        Get the "next" serial number for the part this stock item references.
+        """Get the "next" serial number for the part this stock item references.
 
         e.g. if this stock item has a serial number 100, we may return the stock item with serial number 101
 
@@ -322,9 +302,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
         Returns:
             A StockItem object matching the requirements, or None
-
         """
-
         if not self.serialized:
             return None
 
@@ -358,13 +336,11 @@ class StockItem(MetadataMixin, MPTTModel):
         return None
 
     def save(self, *args, **kwargs):
-        """
-        Save this StockItem to the database. Performs a number of checks:
+        """Save this StockItem to the database. Performs a number of checks:
 
         - Unique serial number requirement
         - Adds a transaction note when the item is first created.
         """
-
         self.validate_unique()
         self.clean()
 
@@ -433,16 +409,15 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @property
     def serialized(self):
-        """ Return True if this StockItem is serialized """
+        """Return True if this StockItem is serialized"""
         return self.serial is not None and len(str(self.serial).strip()) > 0 and self.quantity == 1
 
     def validate_unique(self, exclude=None):
-        """
-        Test that this StockItem is "unique".
+        """Test that this StockItem is "unique".
+
         If the StockItem is serialized, the same serial number.
         cannot exist for the same part (or part tree).
         """
-
         super(StockItem, self).validate_unique(exclude)
 
         # If the serial number is set, make sure it is not a duplicate
@@ -459,7 +434,7 @@ class StockItem(MetadataMixin, MPTTModel):
                 raise ValidationError({"serial": _("StockItem with this serial number already exists")})
 
     def clean(self):
-        """ Validate the StockItem object (separate to field validation)
+        """Validate the StockItem object (separate to field validation)
 
         The following validation checks are performed:
 
@@ -467,7 +442,6 @@ class StockItem(MetadataMixin, MPTTModel):
         - The 'part' does not belong to itself
         - Quantity must be 1 if the StockItem has a serial number
         """
-
         super().clean()
 
         # Strip serial number field
@@ -563,7 +537,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return self.part.full_name
 
     def format_barcode(self, **kwargs):
-        """ Return a JSON string for formatting a barcode for this StockItem.
+        """Return a JSON string for formatting a barcode for this StockItem.
         Can be used to perform lookup of a stockitem using barcode
 
         Contains the following data:
@@ -572,7 +546,6 @@ class StockItem(MetadataMixin, MPTTModel):
 
         Voltagile data (e.g. stock quantity) should be looked up using the InvenTree API (as it may change)
         """
-
         return InvenTree.helpers.MakeBarcode(
             "stockitem",
             self.id,
@@ -586,9 +559,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @property
     def barcode(self):
-        """
-        Brief payload data (e.g. for labels)
-        """
+        """Brief payload data (e.g. for labels)"""
         return self.format_barcode(brief=True)
 
     uid = models.CharField(blank=True, max_length=128, help_text=("Unique identifier field"))
@@ -753,11 +724,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def convert_to_variant(self, variant, user, notes=None):
-        """
-        Convert this StockItem instance to a "variant",
-        i.e. change the "part" reference field
-        """
-
+        """Convert this StockItem instance to a "variant", i.e. change the "part" reference field"""
         if not variant:
             # Ignore null values
             return
@@ -779,14 +746,12 @@ class StockItem(MetadataMixin, MPTTModel):
         )
 
     def get_item_owner(self):
-        """
-        Return the closest "owner" for this StockItem.
+        """Return the closest "owner" for this StockItem.
 
         - If the item has an owner set, return that
         - If the item is "in stock", check the StockLocation
         - Otherwise, return None
         """
-
         if self.owner is not None:
             return self.owner
 
@@ -799,10 +764,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return None
 
     def check_ownership(self, user):
-        """
-        Check if the user "owns" (or is one of the owners of) the item
-        """
-
+        """Check if the user "owns" (or is one of the owners of) the item"""
         # Superuser accounts automatically "own" everything
         if user.is_superuser:
             return True
@@ -821,8 +783,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return user in owner.get_related_owners(include_group=True)
 
     def is_stale(self):
-        """
-        Returns True if this Stock item is "stale".
+        """Returns True if this Stock item is "stale".
 
         To be "stale", the following conditions must be met:
 
@@ -830,7 +791,6 @@ class StockItem(MetadataMixin, MPTTModel):
         - Expiry date will "expire" within the configured stale date
         - The StockItem is otherwise "in stock"
         """
-
         if self.expiry_date is None:
             return False
 
@@ -849,8 +809,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return self.expiry_date < expiry_date
 
     def is_expired(self):
-        """
-        Returns True if this StockItem is "expired".
+        """Returns True if this StockItem is "expired".
 
         To be "expired", the following conditions must be met:
 
@@ -858,7 +817,6 @@ class StockItem(MetadataMixin, MPTTModel):
         - Expiry date is "in the past"
         - The StockItem is otherwise "in stock"
         """
-
         if self.expiry_date is None:
             return False
 
@@ -870,13 +828,11 @@ class StockItem(MetadataMixin, MPTTModel):
         return self.expiry_date < today
 
     def clearAllocations(self):
-        """
-        Clear all order allocations for this StockItem:
+        """Clear all order allocations for this StockItem:
 
         - SalesOrder allocations
         - Build allocations
         """
-
         # Delete outstanding SalesOrder allocations
         self.sales_order_allocations.all().delete()
 
@@ -884,8 +840,7 @@ class StockItem(MetadataMixin, MPTTModel):
         self.allocations.all().delete()
 
     def allocateToCustomer(self, customer, quantity=None, order=None, user=None, notes=None):
-        """
-        Allocate a StockItem to a customer.
+        """Allocate a StockItem to a customer.
 
         This action can be called by the following processes:
         - Completion of a SalesOrder
@@ -898,7 +853,6 @@ class StockItem(MetadataMixin, MPTTModel):
             user: User that performed the action
             notes: Notes field
         """
-
         if quantity is None:
             quantity = self.quantity
 
@@ -936,10 +890,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return item
 
     def returnFromCustomer(self, location, user=None, **kwargs):
-        """
-        Return stock item from customer, back into the specified location.
-        """
-
+        """Return stock item from customer, back into the specified location."""
         notes = kwargs.get('notes', '')
 
         tracking_info = {}
@@ -972,10 +923,7 @@ class StockItem(MetadataMixin, MPTTModel):
     infinite = models.BooleanField(default=False)
 
     def is_allocated(self):
-        """
-        Return True if this StockItem is allocated to a SalesOrder or a Build
-        """
-
+        """Return True if this StockItem is allocated to a SalesOrder or a Build"""
         # TODO - For now this only checks if the StockItem is allocated to a SalesOrder
         # TODO - In future, once the "build" is working better, check this too
 
@@ -988,10 +936,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return False
 
     def build_allocation_count(self):
-        """
-        Return the total quantity allocated to builds
-        """
-
+        """Return the total quantity allocated to builds"""
         query = self.allocations.aggregate(q=Coalesce(Sum('quantity'), Decimal(0)))
 
         total = query['q']
@@ -1002,10 +947,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return total
 
     def sales_order_allocation_count(self):
-        """
-        Return the total quantity allocated to SalesOrders
-        """
-
+        """Return the total quantity allocated to SalesOrders"""
         query = self.sales_order_allocations.aggregate(q=Coalesce(Sum('quantity'), Decimal(0)))
 
         total = query['q']
@@ -1016,31 +958,24 @@ class StockItem(MetadataMixin, MPTTModel):
         return total
 
     def allocation_count(self):
-        """
-        Return the total quantity allocated to builds or orders
-        """
-
+        """Return the total quantity allocated to builds or orders"""
         bo = self.build_allocation_count()
         so = self.sales_order_allocation_count()
 
         return bo + so
 
     def unallocated_quantity(self):
-        """
-        Return the quantity of this StockItem which is *not* allocated
-        """
-
+        """Return the quantity of this StockItem which is *not* allocated"""
         return max(self.quantity - self.allocation_count(), 0)
 
     def can_delete(self):
-        """ Can this stock item be deleted? It can NOT be deleted under the following circumstances:
+        """Can this stock item be deleted? It can NOT be deleted under the following circumstances:
 
         - Has installed stock items
         - Is installed inside another StockItem
         - It has been assigned to a SalesOrder
         - It has been assigned to a BuildOrder
         """
-
         if self.installed_item_count() > 0:
             return False
 
@@ -1050,15 +985,13 @@ class StockItem(MetadataMixin, MPTTModel):
         return True
 
     def get_installed_items(self, cascade=False):
-        """
-        Return all stock items which are *installed* in this one!
+        """Return all stock items which are *installed* in this one!
 
         Args:
             cascade - Include items which are installed in items which are installed in items
 
         Note: This function is recursive, and may result in a number of database hits!
         """
-
         installed = set()
 
         items = StockItem.objects.filter(belongs_to=self)
@@ -1085,16 +1018,12 @@ class StockItem(MetadataMixin, MPTTModel):
         return installed
 
     def installed_item_count(self):
-        """
-        Return the number of stock items installed inside this one.
-        """
-
+        """Return the number of stock items installed inside this one."""
         return self.installed_parts.count()
 
     @transaction.atomic
     def installStockItem(self, other_item, quantity, user, notes):
-        """
-        Install another stock item into this stock item.
+        """Install another stock item into this stock item.
 
         Args
             other_item: The stock item to install into this stock item
@@ -1102,7 +1031,6 @@ class StockItem(MetadataMixin, MPTTModel):
             user: The user performing the operation
             notes: Any notes associated with the operation
         """
-
         # Cannot be already installed in another stock item!
         if self.belongs_to is not None:
             return False
@@ -1139,15 +1067,13 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def uninstall_into_location(self, location, user, notes):
-        """
-        Uninstall this stock item from another item, into a location.
+        """Uninstall this stock item from another item, into a location.
 
         Args:
             location: The stock location where the item will be moved
             user: The user performing the operation
             notes: Any notes associated with the operation
         """
-
         # If the stock item is not installed in anything, ignore
         if self.belongs_to is None:
             return False
@@ -1184,24 +1110,22 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @property
     def children(self):
-        """ Return a list of the child items which have been split from this stock item """
+        """Return a list of the child items which have been split from this stock item"""
         return self.get_descendants(include_self=False)
 
     @property
     def child_count(self):
-        """ Return the number of 'child' items associated with this StockItem.
-        A child item is one which has been split from this one.
-        """
+        """Return the number of 'child' items associated with this StockItem.
+
+        A child item is one which has been split from this one."""
         return self.children.count()
 
     @property
     def in_stock(self):
-        """
-        Returns True if this item is in stock.
+        """Returns True if this item is in stock.
 
         See also: IN_STOCK_FILTER
         """
-
         query = StockItem.objects.filter(pk=self.pk)
 
         query = query.filter(StockItem.IN_STOCK_FILTER)
@@ -1210,14 +1134,12 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @property
     def can_adjust_location(self):
-        """
-        Returns True if the stock location can be "adjusted" for this part
+        """Returns True if the stock location can be "adjusted" for this part
 
         Cannot be adjusted if:
         - Has been delivered to a customer
         - Has been installed inside another StockItem
         """
-
         if self.customer is not None:
             return False
 
@@ -1238,8 +1160,7 @@ class StockItem(MetadataMixin, MPTTModel):
         return self.tracking_info_count > 0
 
     def add_tracking_entry(self, entry_type, user, deltas=None, notes='', **kwargs):
-        """
-        Add a history tracking entry for this StockItem
+        """Add a history tracking entry for this StockItem
 
         Args:
             entry_type - Integer code describing the "type" of historical action (see StockHistoryCode)
@@ -1276,7 +1197,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def serializeStock(self, quantity, serials, user, notes='', location=None):
-        """ Split this stock item into unique serial numbers.
+        """Split this stock item into unique serial numbers.
 
         - Quantity can be less than or equal to the quantity of the stock item
         - Number of serial numbers must match the quantity
@@ -1289,7 +1210,6 @@ class StockItem(MetadataMixin, MPTTModel):
             notes: Optional notes for tracking
             location: If specified, serialized items will be placed in the given location
         """
-
         # Cannot serialize stock that is already serialized!
         if self.serialized:
             return
@@ -1360,8 +1280,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def copyHistoryFrom(self, other):
-        """ Copy stock history from another StockItem """
-
+        """Copy stock history from another StockItem"""
         for item in other.tracking_info.all():
 
             item.item = self
@@ -1370,8 +1289,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def copyTestResultsFrom(self, other, filters={}):
-        """ Copy all test results from another StockItem """
-
+        """Copy all test results from another StockItem"""
         for result in other.test_results.all().filter(**filters):
 
             # Create a copy of the test result by nulling-out the pk
@@ -1380,10 +1298,7 @@ class StockItem(MetadataMixin, MPTTModel):
             result.save()
 
     def can_merge(self, other=None, raise_error=False, **kwargs):
-        """
-        Check if this stock item can be merged into another stock item
-        """
-
+        """Check if this stock item can be merged into another stock item"""
         allow_mismatched_suppliers = kwargs.get('allow_mismatched_suppliers', False)
 
         allow_mismatched_status = kwargs.get('allow_mismatched_status', False)
@@ -1437,8 +1352,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def merge_stock_items(self, other_items, raise_error=False, **kwargs):
-        """
-        Merge another stock item into this one; the two become one!
+        """Merge another stock item into this one; the two become one!
 
         *This* stock item subsumes the other, which is essentially deleted:
 
@@ -1446,7 +1360,6 @@ class StockItem(MetadataMixin, MPTTModel):
         - Tracking history for the *other* item is deleted
         - Any allocations (build order, sales order) are moved to this StockItem
         """
-
         if len(other_items) == 0:
             return
 
@@ -1499,7 +1412,8 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def splitStock(self, quantity, location, user, **kwargs):
-        """ Split this stock item into two items, in the same location.
+        """Split this stock item into two items, in the same location.
+
         Stock tracking notes for this StockItem will be duplicated,
         and added to the new StockItem.
 
@@ -1511,7 +1425,6 @@ class StockItem(MetadataMixin, MPTTModel):
             The provided quantity will be subtracted from this item and given to the new one.
             The new item will have a different StockItem ID, while this will remain the same.
         """
-
         notes = kwargs.get('notes', '')
         code = kwargs.get('code', StockHistoryCode.SPLIT_FROM_PARENT)
 
@@ -1576,7 +1489,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def move(self, location, notes, user, **kwargs):
-        """ Move part to a new location.
+        """Move part to a new location.
 
         If less than the available quantity is to be moved,
         a new StockItem is created, with the defined quantity,
@@ -1590,7 +1503,6 @@ class StockItem(MetadataMixin, MPTTModel):
             kwargs:
                 quantity: If provided, override the quantity (default = total stock quantity)
         """
-
         try:
             quantity = Decimal(kwargs.get('quantity', self.quantity))
         except InvalidOperation:
@@ -1636,7 +1548,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def updateQuantity(self, quantity):
-        """ Update stock quantity for this item.
+        """Update stock quantity for this item.
 
         If the quantity has reached zero, this StockItem will be deleted.
 
@@ -1644,7 +1556,6 @@ class StockItem(MetadataMixin, MPTTModel):
             - True if the quantity was saved
             - False if the StockItem was deleted
         """
-
         # Do not adjust quantity of a serialized part
         if self.serialized:
             return
@@ -1669,11 +1580,10 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def stocktake(self, count, user, notes=''):
-        """ Perform item stocktake.
+        """Perform item stocktake.
         When the quantity of an item is counted,
         record the date of stocktake
         """
-
         try:
             count = Decimal(count)
         except InvalidOperation:
@@ -1700,11 +1610,10 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def add_stock(self, quantity, user, notes=''):
-        """ Add items to stock
+        """Add items to stock
         This function can be called by initiating a ProjectRun,
         or by manually adding the items to the stock location
         """
-
         # Cannot add items to a serialized part
         if self.serialized:
             return False
@@ -1734,10 +1643,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def take_stock(self, quantity, user, notes='', code=StockHistoryCode.STOCK_REMOVE):
-        """
-        Remove items from stock
-        """
-
+        """Remove items from stock"""
         # Cannot remove items from a serialized part
         if self.serialized:
             return False
@@ -1787,13 +1693,7 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @transaction.atomic
     def clear_test_results(self, **kwargs):
-        """
-        Remove all test results
-
-        kwargs:
-            TODO
-        """
-
+        """Remove all test results"""
         # All test results
         results = self.test_results.all()
 
@@ -1802,15 +1702,13 @@ class StockItem(MetadataMixin, MPTTModel):
         results.delete()
 
     def getTestResults(self, test=None, result=None, user=None):
-        """
-        Return all test results associated with this StockItem.
+        """Return all test results associated with this StockItem.
 
         Optionally can filter results by:
         - Test name
         - Test result
         - User
         """
-
         results = self.test_results
 
         if test:
@@ -1828,15 +1726,13 @@ class StockItem(MetadataMixin, MPTTModel):
         return results
 
     def testResultMap(self, **kwargs):
-        """
-        Return a map of test-results using the test name as the key.
+        """Return a map of test-results using the test name as the key.
         Where multiple test results exist for a given name,
         the *most recent* test is used.
 
         This map is useful for rendering to a template (e.g. a test report),
         as all named tests are accessible.
         """
-
         # Do we wish to include test results from installed items?
         include_installed = kwargs.pop('include_installed', False)
 
@@ -1867,15 +1763,11 @@ class StockItem(MetadataMixin, MPTTModel):
         return result_map
 
     def testResultList(self, **kwargs):
-        """
-        Return a list of test-result objects for this StockItem
-        """
-
+        """Return a list of test-result objects for this StockItem"""
         return self.testResultMap(**kwargs).values()
 
     def requiredTestStatus(self):
-        """
-        Return the status of the tests required for this StockItem.
+        """Return the status of the tests required for this StockItem.
 
         return:
             A dict containing the following items:
@@ -1883,7 +1775,6 @@ class StockItem(MetadataMixin, MPTTModel):
             - passed: Number of tests that have passed
             - failed: Number of tests that have failed
         """
-
         # All the tests required by the part object
         required = self.part.getRequiredTests()
 
@@ -1912,31 +1803,21 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @property
     def required_test_count(self):
-        """
-        Return the number of 'required tests' for this StockItem
-        """
+        """Return the number of 'required tests' for this StockItem"""
         return self.part.getRequiredTests().count()
 
     def hasRequiredTests(self):
-        """
-        Return True if there are any 'required tests' associated with this StockItem
-        """
+        """Return True if there are any 'required tests' associated with this StockItem"""
         return self.part.getRequiredTests().count() > 0
 
     def passedAllRequiredTests(self):
-        """
-        Returns True if this StockItem has passed all required tests
-        """
-
+        """Returns True if this StockItem has passed all required tests"""
         status = self.requiredTestStatus()
 
         return status['passed'] >= status['total']
 
     def available_test_reports(self):
-        """
-        Return a list of TestReport objects which match this StockItem.
-        """
-
+        """Return a list of TestReport objects which match this StockItem."""
         reports = []
 
         item_query = StockItem.objects.filter(pk=self.pk)
@@ -1955,17 +1836,11 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @property
     def has_test_reports(self):
-        """
-        Return True if there are test reports available for this stock item
-        """
-
+        """Return True if there are test reports available for this stock item"""
         return len(self.available_test_reports()) > 0
 
     def available_labels(self):
-        """
-        Return a list of Label objects which match this StockItem
-        """
-
+        """Return a list of Label objects which match this StockItem"""
         labels = []
 
         item_query = StockItem.objects.filter(pk=self.pk)
@@ -1984,22 +1859,17 @@ class StockItem(MetadataMixin, MPTTModel):
 
     @property
     def has_labels(self):
-        """
-        Return True if there are any label templates available for this stock item
-        """
-
+        """Return True if there are any label templates available for this stock item"""
         return len(self.available_labels()) > 0
 
 
 @receiver(pre_delete, sender=StockItem, dispatch_uid='stock_item_pre_delete_log')
 def before_delete_stock_item(sender, instance, using, **kwargs):
-    """
-    Receives pre_delete signal from StockItem object.
+    """Receives pre_delete signal from StockItem object.
 
     Before a StockItem is deleted, ensure that each child object is updated,
     to point to the new parent item.
     """
-
     # Update each StockItem parent field
     for child in instance.children.all():
         child.parent = instance.parent
@@ -2008,9 +1878,7 @@ def before_delete_stock_item(sender, instance, using, **kwargs):
 
 @receiver(post_delete, sender=StockItem, dispatch_uid='stock_item_post_delete_log')
 def after_delete_stock_item(sender, instance: StockItem, **kwargs):
-    """
-    Function to be executed after a StockItem object is deleted
-    """
+    """Function to be executed after a StockItem object is deleted"""
     from part import tasks as part_tasks
 
     if not InvenTree.ready.isImportingData():
@@ -2020,9 +1888,7 @@ def after_delete_stock_item(sender, instance: StockItem, **kwargs):
 
 @receiver(post_save, sender=StockItem, dispatch_uid='stock_item_post_save_log')
 def after_save_stock_item(sender, instance: StockItem, created, **kwargs):
-    """
-    Hook function to be executed after StockItem object is saved/updated
-    """
+    """Hook function to be executed after StockItem object is saved/updated"""
     from part import tasks as part_tasks
 
     if not InvenTree.ready.isImportingData():
@@ -2050,8 +1916,7 @@ class StockItemAttachment(InvenTreeAttachment):
 
 
 class StockItemTracking(models.Model):
-    """
-    Stock tracking entry - used for tracking history of a particular StockItem
+    """Stock tracking entry - used for tracking history of a particular StockItem
 
     Note: 2021-05-11
     The legacy StockTrackingItem model contained very litle information about the "history" of the item.
@@ -2114,8 +1979,7 @@ def rename_stock_item_test_result_attachment(instance, filename):
 
 
 class StockItemTestResult(models.Model):
-    """
-    A StockItemTestResult records results of custom tests against individual StockItem objects.
+    """A StockItemTestResult records results of custom tests against individual StockItem objects.
     This is useful for tracking unit acceptance tests, and particularly useful when integrated
     with automated testing setups.
 
diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py
index 920052a0ec..44f0946194 100644
--- a/InvenTree/stock/serializers.py
+++ b/InvenTree/stock/serializers.py
@@ -1,6 +1,4 @@
-"""
-JSON serializers for Stock app
-"""
+"""JSON serializers for Stock app"""
 
 from datetime import datetime, timedelta
 from decimal import Decimal
@@ -29,9 +27,7 @@ from .models import (StockItem, StockItemAttachment, StockItemTestResult,
 
 
 class LocationBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer):
-    """
-    Provides a brief serializer for a StockLocation object
-    """
+    """Provides a brief serializer for a StockLocation object"""
 
     class Meta:
         model = StockLocation
@@ -43,7 +39,7 @@ class LocationBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 
 
 class StockItemSerializerBrief(InvenTree.serializers.InvenTreeModelSerializer):
-    """ Brief serializers for a StockItem """
+    """Brief serializers for a StockItem"""
 
     location_name = serializers.CharField(source='location', read_only=True)
     part_name = serializers.CharField(source='part.full_name', read_only=True)
@@ -71,7 +67,7 @@ class StockItemSerializerBrief(InvenTree.serializers.InvenTreeModelSerializer):
 
 
 class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
-    """ Serializer for a StockItem:
+    """Serializer for a StockItem:
 
     - Includes serialization for the linked part
     - Includes serialization for the item location
@@ -88,11 +84,7 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 
     @staticmethod
     def annotate_queryset(queryset):
-        """
-        Add some extra annotations to the queryset,
-        performing database queries as efficiently as possible.
-        """
-
+        """Add some extra annotations to the queryset, performing database queries as efficiently as possible."""
         # Annotate the queryset with the total allocated to sales orders
         queryset = queryset.annotate(
             allocated=Coalesce(
@@ -257,8 +249,7 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 
 
 class SerializeStockItemSerializer(serializers.Serializer):
-    """
-    A DRF serializer for "serializing" a StockItem.
+    """A DRF serializer for "serializing" a StockItem.
 
     (Sorry for the confusing naming...)
 
@@ -284,9 +275,7 @@ class SerializeStockItemSerializer(serializers.Serializer):
     )
 
     def validate_quantity(self, quantity):
-        """
-        Validate that the quantity value is correct
-        """
+        """Validate that the quantity value is correct"""
 
         item = self.context['item']
 
@@ -323,9 +312,7 @@ class SerializeStockItemSerializer(serializers.Serializer):
     )
 
     def validate(self, data):
-        """
-        Check that the supplied serial numbers are valid
-        """
+        """Check that the supplied serial numbers are valid"""
 
         data = super().validate(data)
 
@@ -381,9 +368,7 @@ class SerializeStockItemSerializer(serializers.Serializer):
 
 
 class InstallStockItemSerializer(serializers.Serializer):
-    """
-    Serializer for installing a stock item into a given part
-    """
+    """Serializer for installing a stock item into a given part"""
 
     stock_item = serializers.PrimaryKeyRelatedField(
         queryset=StockItem.objects.all(),
@@ -401,9 +386,7 @@ class InstallStockItemSerializer(serializers.Serializer):
     )
 
     def validate_stock_item(self, stock_item):
-        """
-        Validate the selected stock item
-        """
+        """Validate the selected stock item"""
 
         if not stock_item.in_stock:
             # StockItem must be in stock to be "installed"
@@ -419,7 +402,7 @@ class InstallStockItemSerializer(serializers.Serializer):
         return stock_item
 
     def save(self):
-        """ Install the selected stock item into this one """
+        """Install the selected stock item into this one"""
 
         data = self.validated_data
 
@@ -438,9 +421,7 @@ class InstallStockItemSerializer(serializers.Serializer):
 
 
 class UninstallStockItemSerializer(serializers.Serializer):
-    """
-    API serializers for uninstalling an installed item from a stock item
-    """
+    """API serializers for uninstalling an installed item from a stock item"""
 
     class Meta:
         fields = [
@@ -480,9 +461,7 @@ class UninstallStockItemSerializer(serializers.Serializer):
 
 
 class LocationTreeSerializer(InvenTree.serializers.InvenTreeModelSerializer):
-    """
-    Serializer for a simple tree view
-    """
+    """Serializer for a simple tree view"""
 
     class Meta:
         model = StockLocation
@@ -494,8 +473,7 @@ class LocationTreeSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 
 
 class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
-    """ Detailed information about a stock location
-    """
+    """Detailed information about a stock location"""
 
     url = serializers.CharField(source='get_absolute_url', read_only=True)
 
@@ -519,7 +497,7 @@ class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 
 
 class StockItemAttachmentSerializer(InvenTree.serializers.InvenTreeAttachmentSerializer):
-    """ Serializer for StockItemAttachment model """
+    """Serializer for StockItemAttachment model"""
 
     def __init__(self, *args, **kwargs):
         user_detail = kwargs.pop('user_detail', False)
@@ -556,7 +534,7 @@ class StockItemAttachmentSerializer(InvenTree.serializers.InvenTreeAttachmentSer
 
 
 class StockItemTestResultSerializer(InvenTree.serializers.InvenTreeModelSerializer):
-    """ Serializer for the StockItemTestResult model """
+    """Serializer for the StockItemTestResult model"""
 
     user_detail = InvenTree.serializers.UserSerializerBrief(source='user', read_only=True)
 
@@ -597,7 +575,7 @@ class StockItemTestResultSerializer(InvenTree.serializers.InvenTreeModelSerializ
 
 
 class StockTrackingSerializer(InvenTree.serializers.InvenTreeModelSerializer):
-    """ Serializer for StockItemTracking model """
+    """Serializer for StockItemTracking model"""
 
     def __init__(self, *args, **kwargs):
 
@@ -644,8 +622,7 @@ class StockTrackingSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 
 
 class StockAssignmentItemSerializer(serializers.Serializer):
-    """
-    Serializer for a single StockItem with in StockAssignment request.
+    """Serializer for a single StockItem with in StockAssignment request.
 
     Here, the particular StockItem is being assigned (manually) to a customer
 
@@ -688,8 +665,7 @@ class StockAssignmentItemSerializer(serializers.Serializer):
 
 
 class StockAssignmentSerializer(serializers.Serializer):
-    """
-    Serializer for assigning one (or more) stock items to a customer.
+    """Serializer for assigning one (or more) stock items to a customer.
 
     This is a manual assignment process, separate for (for example) a Sales Order
     """
@@ -765,8 +741,7 @@ class StockAssignmentSerializer(serializers.Serializer):
 
 
 class StockMergeItemSerializer(serializers.Serializer):
-    """
-    Serializer for a single StockItem within the StockMergeSerializer class.
+    """Serializer for a single StockItem within the StockMergeSerializer class.
 
     Here, the individual StockItem is being checked for merge compatibility.
     """
@@ -793,9 +768,7 @@ class StockMergeItemSerializer(serializers.Serializer):
 
 
 class StockMergeSerializer(serializers.Serializer):
-    """
-    Serializer for merging two (or more) stock items together
-    """
+    """Serializer for merging two (or more) stock items together"""
 
     class Meta:
         fields = [
@@ -879,8 +852,8 @@ class StockMergeSerializer(serializers.Serializer):
         return data
 
     def save(self):
-        """
-        Actually perform the stock merging action.
+        """Actually perform the stock merging action.
+
         At this point we are confident that the merge can take place
         """
 
@@ -908,8 +881,7 @@ class StockMergeSerializer(serializers.Serializer):
 
 
 class StockAdjustmentItemSerializer(serializers.Serializer):
-    """
-    Serializer for a single StockItem within a stock adjument request.
+    """Serializer for a single StockItem within a stock adjument request.
 
     Fields:
         - item: StockItem object
@@ -940,9 +912,7 @@ class StockAdjustmentItemSerializer(serializers.Serializer):
 
 
 class StockAdjustmentSerializer(serializers.Serializer):
-    """
-    Base class for managing stock adjustment actions via the API
-    """
+    """Base class for managing stock adjustment actions via the API"""
 
     class Meta:
         fields = [
@@ -972,9 +942,7 @@ class StockAdjustmentSerializer(serializers.Serializer):
 
 
 class StockCountSerializer(StockAdjustmentSerializer):
-    """
-    Serializer for counting stock items
-    """
+    """Serializer for counting stock items"""
 
     def save(self):
 
@@ -998,9 +966,7 @@ class StockCountSerializer(StockAdjustmentSerializer):
 
 
 class StockAddSerializer(StockAdjustmentSerializer):
-    """
-    Serializer for adding stock to stock item(s)
-    """
+    """Serializer for adding stock to stock item(s)"""
 
     def save(self):
 
@@ -1023,9 +989,7 @@ class StockAddSerializer(StockAdjustmentSerializer):
 
 
 class StockRemoveSerializer(StockAdjustmentSerializer):
-    """
-    Serializer for removing stock from stock item(s)
-    """
+    """Serializer for removing stock from stock item(s)"""
 
     def save(self):
 
@@ -1048,9 +1012,7 @@ class StockRemoveSerializer(StockAdjustmentSerializer):
 
 
 class StockTransferSerializer(StockAdjustmentSerializer):
-    """
-    Serializer for transferring (moving) stock item(s)
-    """
+    """Serializer for transferring (moving) stock item(s)"""
 
     location = serializers.PrimaryKeyRelatedField(
         queryset=StockLocation.objects.all(),
diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py
index 87d8bfaada..af02a57d63 100644
--- a/InvenTree/stock/test_api.py
+++ b/InvenTree/stock/test_api.py
@@ -1,6 +1,4 @@
-"""
-Unit testing for the Stock API
-"""
+"""Unit testing for the Stock API"""
 
 import io
 import os
@@ -47,9 +45,7 @@ class StockAPITestCase(InvenTreeAPITestCase):
 
 
 class StockLocationTest(StockAPITestCase):
-    """
-    Series of API tests for the StockLocation API
-    """
+    """Series of API tests for the StockLocation API"""
     list_url = reverse('api-location-list')
 
     def setUp(self):
@@ -76,16 +72,12 @@ class StockLocationTest(StockAPITestCase):
 
 
 class StockItemListTest(StockAPITestCase):
-    """
-    Tests for the StockItem API LIST endpoint
-    """
+    """Tests for the StockItem API LIST endpoint"""
 
     list_url = reverse('api-stock-list')
 
     def get_stock(self, **kwargs):
-        """
-        Filter stock and return JSON object
-        """
+        """Filter stock and return JSON object"""
 
         response = self.client.get(self.list_url, format='json', data=kwargs)
 
@@ -95,18 +87,14 @@ class StockItemListTest(StockAPITestCase):
         return response.data
 
     def test_get_stock_list(self):
-        """
-        List *all* StockItem objects.
-        """
+        """List *all* StockItem objects."""
 
         response = self.get_stock()
 
         self.assertEqual(len(response), 29)
 
     def test_filter_by_part(self):
-        """
-        Filter StockItem by Part reference
-        """
+        """Filter StockItem by Part reference"""
 
         response = self.get_stock(part=25)
 
@@ -117,17 +105,13 @@ class StockItemListTest(StockAPITestCase):
         self.assertEqual(len(response), 12)
 
     def test_filter_by_IPN(self):
-        """
-        Filter StockItem by IPN reference
-        """
+        """Filter StockItem by IPN reference"""
 
         response = self.get_stock(IPN="R.CH")
         self.assertEqual(len(response), 3)
 
     def test_filter_by_location(self):
-        """
-        Filter StockItem by StockLocation reference
-        """
+        """Filter StockItem by StockLocation reference"""
 
         response = self.get_stock(location=5)
         self.assertEqual(len(response), 1)
@@ -142,9 +126,7 @@ class StockItemListTest(StockAPITestCase):
         self.assertEqual(len(response), 18)
 
     def test_filter_by_depleted(self):
-        """
-        Filter StockItem by depleted status
-        """
+        """Filter StockItem by depleted status"""
 
         response = self.get_stock(depleted=1)
         self.assertEqual(len(response), 1)
@@ -153,9 +135,7 @@ class StockItemListTest(StockAPITestCase):
         self.assertEqual(len(response), 28)
 
     def test_filter_by_in_stock(self):
-        """
-        Filter StockItem by 'in stock' status
-        """
+        """Filter StockItem by 'in stock' status"""
 
         response = self.get_stock(in_stock=1)
         self.assertEqual(len(response), 26)
@@ -164,9 +144,7 @@ class StockItemListTest(StockAPITestCase):
         self.assertEqual(len(response), 3)
 
     def test_filter_by_status(self):
-        """
-        Filter StockItem by 'status' field
-        """
+        """Filter StockItem by 'status' field"""
 
         codes = {
             StockStatus.OK: 27,
@@ -183,17 +161,13 @@ class StockItemListTest(StockAPITestCase):
             self.assertEqual(len(response), num)
 
     def test_filter_by_batch(self):
-        """
-        Filter StockItem by batch code
-        """
+        """Filter StockItem by batch code"""
 
         response = self.get_stock(batch='B123')
         self.assertEqual(len(response), 1)
 
     def test_filter_by_serialized(self):
-        """
-        Filter StockItem by serialized status
-        """
+        """Filter StockItem by serialized status"""
 
         response = self.get_stock(serialized=1)
         self.assertEqual(len(response), 12)
@@ -208,9 +182,7 @@ class StockItemListTest(StockAPITestCase):
             self.assertIsNone(item['serial'])
 
     def test_filter_by_has_batch(self):
-        """
-        Test the 'has_batch' filter, which tests if the stock item has been assigned a batch code
-        """
+        """Test the 'has_batch' filter, which tests if the stock item has been assigned a batch code"""
 
         with_batch = self.get_stock(has_batch=1)
         without_batch = self.get_stock(has_batch=0)
@@ -227,8 +199,7 @@ class StockItemListTest(StockAPITestCase):
             self.assertTrue(item['batch'] in [None, ''])
 
     def test_filter_by_tracked(self):
-        """
-        Test the 'tracked' filter.
+        """Test the 'tracked' filter.
         This checks if the stock item has either a batch code *or* a serial number
         """
 
@@ -248,9 +219,7 @@ class StockItemListTest(StockAPITestCase):
             self.assertTrue(item['batch'] in blank and item['serial'] in blank)
 
     def test_filter_by_expired(self):
-        """
-        Filter StockItem by expiry status
-        """
+        """Filter StockItem by expiry status"""
 
         # First, we can assume that the 'stock expiry' feature is disabled
         response = self.get_stock(expired=1)
@@ -289,9 +258,7 @@ class StockItemListTest(StockAPITestCase):
         self.assertEqual(len(response), 25)
 
     def test_paginate(self):
-        """
-        Test that we can paginate results correctly
-        """
+        """Test that we can paginate results correctly"""
 
         for n in [1, 5, 10]:
             response = self.get_stock(limit=n)
@@ -321,9 +288,7 @@ class StockItemListTest(StockAPITestCase):
         return dataset
 
     def test_export(self):
-        """
-        Test exporting of Stock data via the API
-        """
+        """Test exporting of Stock data via the API"""
 
         dataset = self.export_data({})
 
@@ -361,9 +326,7 @@ class StockItemListTest(StockAPITestCase):
 
 
 class StockItemTest(StockAPITestCase):
-    """
-    Series of API tests for the StockItem API
-    """
+    """Series of API tests for the StockItem API"""
 
     list_url = reverse('api-stock-list')
 
@@ -376,8 +339,7 @@ class StockItemTest(StockAPITestCase):
         StockLocation.objects.create(name='C', description='location c', parent=top)
 
     def test_create_default_location(self):
-        """
-        Test the default location functionality,
+        """Test the default location functionality,
         if a 'location' is not specified in the creation request.
         """
 
@@ -423,9 +385,7 @@ class StockItemTest(StockAPITestCase):
         self.assertEqual(response.data['location'], None)
 
     def test_stock_item_create(self):
-        """
-        Test creation of a StockItem via the API
-        """
+        """Test creation of a StockItem via the API"""
 
         # POST with an empty part reference
 
@@ -476,9 +436,7 @@ class StockItemTest(StockAPITestCase):
         )
 
     def test_creation_with_serials(self):
-        """
-        Test that serialized stock items can be created via the API,
-        """
+        """Test that serialized stock items can be created via the API."""
 
         trackable_part = part.models.Part.objects.create(
             name='My part',
@@ -587,9 +545,7 @@ class StockItemTest(StockAPITestCase):
         self.assertEqual(response.data['expiry_date'], expiry.isoformat())
 
     def test_purchase_price(self):
-        """
-        Test that we can correctly read and adjust purchase price information via the API
-        """
+        """Test that we can correctly read and adjust purchase price information via the API"""
 
         url = reverse('api-stock-detail', kwargs={'pk': 1})
 
@@ -648,7 +604,7 @@ class StockItemTest(StockAPITestCase):
         self.assertEqual(data['purchase_price_currency'], 'NZD')
 
     def test_install(self):
-        """ Test that stock item can be installed into antoher item, via the API """
+        """Test that stock item can be installed into antoher item, via the API"""
 
         # Select the "parent" stock item
         parent_part = part.models.Part.objects.get(pk=100)
@@ -731,15 +687,10 @@ class StockItemTest(StockAPITestCase):
 
 
 class StocktakeTest(StockAPITestCase):
-    """
-    Series of tests for the Stocktake API
-    """
+    """Series of tests for the Stocktake API"""
 
     def test_action(self):
-        """
-        Test each stocktake action endpoint,
-        for validation
-        """
+        """Test each stocktake action endpoint, for validation"""
 
         for endpoint in ['api-stock-count', 'api-stock-add', 'api-stock-remove']:
 
@@ -796,9 +747,7 @@ class StocktakeTest(StockAPITestCase):
             self.assertContains(response, 'Ensure this value is greater than or equal to 0', status_code=status.HTTP_400_BAD_REQUEST)
 
     def test_transfer(self):
-        """
-        Test stock transfers
-        """
+        """Test stock transfers"""
 
         data = {
             'items': [
@@ -825,9 +774,7 @@ class StocktakeTest(StockAPITestCase):
 
 
 class StockItemDeletionTest(StockAPITestCase):
-    """
-    Tests for stock item deletion via the API
-    """
+    """Tests for stock item deletion via the API"""
 
     def test_delete(self):
 
@@ -974,8 +921,7 @@ class StockTestResultTest(StockAPITestCase):
 
 
 class StockAssignTest(StockAPITestCase):
-    """
-    Unit tests for the stock assignment API endpoint,
+    """Unit tests for the stock assignment API endpoint,
     where stock items are manually assigned to a customer
     """
 
@@ -1083,9 +1029,7 @@ class StockAssignTest(StockAPITestCase):
 
 
 class StockMergeTest(StockAPITestCase):
-    """
-    Unit tests for merging stock items via the API
-    """
+    """Unit tests for merging stock items via the API"""
 
     URL = reverse('api-stock-merge')
 
@@ -1117,9 +1061,7 @@ class StockMergeTest(StockAPITestCase):
         )
 
     def test_missing_data(self):
-        """
-        Test responses which are missing required data
-        """
+        """Test responses which are missing required data"""
 
         # Post completely empty
 
@@ -1145,9 +1087,7 @@ class StockMergeTest(StockAPITestCase):
         self.assertIn('At least two stock items', str(data))
 
     def test_invalid_data(self):
-        """
-        Test responses which have invalid data
-        """
+        """Test responses which have invalid data"""
 
         # Serialized stock items should be rejected
         data = self.post(
@@ -1229,9 +1169,7 @@ class StockMergeTest(StockAPITestCase):
         self.assertIn('Stock items must refer to the same supplier part', str(data))
 
     def test_valid_merge(self):
-        """
-        Test valid merging of stock items
-        """
+        """Test valid merging of stock items"""
 
         # Check initial conditions
         n = StockItem.objects.filter(part=self.part).count()
diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py
index dba39334de..48f1126395 100644
--- a/InvenTree/stock/test_views.py
+++ b/InvenTree/stock/test_views.py
@@ -1,4 +1,4 @@
-""" Unit tests for Stock views (see views.py) """
+"""Unit tests for Stock views (see views.py)"""
 
 from django.urls import reverse
 
@@ -22,7 +22,7 @@ class StockViewTestCase(InvenTreeTestCase):
 
 
 class StockListTest(StockViewTestCase):
-    """ Tests for Stock list views """
+    """Tests for Stock list views"""
 
     def test_stock_index(self):
         response = self.client.get(reverse('stock-index'))
@@ -30,10 +30,10 @@ class StockListTest(StockViewTestCase):
 
 
 class StockOwnershipTest(StockViewTestCase):
-    """ Tests for stock ownership views """
+    """Tests for stock ownership views"""
 
     def setUp(self):
-        """ Add another user for ownership tests """
+        """Add another user for ownership tests"""
 
     """
     TODO: Refactor this following test to use the new API form
diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py
index fed4b9858e..a89817aa9d 100644
--- a/InvenTree/stock/tests.py
+++ b/InvenTree/stock/tests.py
@@ -13,9 +13,7 @@ from .models import (StockItem, StockItemTestResult, StockItemTracking,
 
 
 class StockTest(InvenTreeTestCase):
-    """
-    Tests to ensure that the stock location tree functions correcly
-    """
+    """Tests to ensure that the stock location tree functions correcly"""
 
     fixtures = [
         'category',
@@ -44,10 +42,7 @@ class StockTest(InvenTreeTestCase):
         StockItem.objects.rebuild()
 
     def test_expiry(self):
-        """
-        Test expiry date functionality for StockItem model.
-        """
-
+        """Test expiry date functionality for StockItem model."""
         today = datetime.datetime.now().date()
 
         item = StockItem.objects.create(
@@ -78,10 +73,7 @@ class StockTest(InvenTreeTestCase):
         self.assertTrue(item.is_expired())
 
     def test_is_building(self):
-        """
-        Test that the is_building flag does not count towards stock.
-        """
-
+        """Test that the is_building flag does not count towards stock."""
         part = Part.objects.get(pk=1)
 
         # Record the total stock count
@@ -197,7 +189,6 @@ class StockTest(InvenTreeTestCase):
 
     def test_move(self):
         """ Test stock movement functions """
-
         # Move 4,000 screws to the bathroom
         it = StockItem.objects.get(pk=1)
         self.assertNotEqual(it.location, self.bathroom)
@@ -339,10 +330,7 @@ class StockTest(InvenTreeTestCase):
             w2 = StockItem.objects.get(pk=101)
 
     def test_serials(self):
-        """
-        Tests for stock serialization
-        """
-
+        """Tests for stock serialization"""
         p = Part.objects.create(
             name='trackable part',
             description='trackable part',
@@ -373,10 +361,7 @@ class StockTest(InvenTreeTestCase):
         self.assertTrue(item.serialized)
 
     def test_big_serials(self):
-        """
-        Unit tests for "large" serial numbers which exceed integer encoding
-        """
-
+        """Unit tests for "large" serial numbers which exceed integer encoding"""
         p = Part.objects.create(
             name='trackable part',
             description='trackable part',
@@ -451,11 +436,10 @@ class StockTest(InvenTreeTestCase):
         self.assertEqual(item_prev.serial_int, 99)
 
     def test_serialize_stock_invalid(self):
-        """
-        Test manual serialization of parts.
+        """Test manual serialization of parts.
+
         Each of these tests should fail
         """
-
         # Test serialization of non-serializable part
         item = StockItem.objects.get(pk=1234)
 
@@ -480,8 +464,7 @@ class StockTest(InvenTreeTestCase):
             item.serializeStock(3, "hello", self.user)
 
     def test_serialize_stock_valid(self):
-        """ Perform valid stock serializations """
-
+        """Perform valid stock serializations"""
         # There are 10 of these in stock
         # Item will deplete when deleted
         item = StockItem.objects.get(pk=100)
@@ -517,8 +500,8 @@ class StockTest(InvenTreeTestCase):
         item.serializeStock(2, [99, 100], self.user)
 
     def test_location_tree(self):
-        """
-        Unit tests for stock location tree structure (MPTT).
+        """Unit tests for stock location tree structure (MPTT).
+
         Ensure that the MPTT structure is rebuilt correctly,
         and the corrent ancestor tree is observed.
 
@@ -686,9 +669,7 @@ class StockTest(InvenTreeTestCase):
 
 
 class VariantTest(StockTest):
-    """
-    Tests for calculation stock counts against templates / variants
-    """
+    """Tests for calculation stock counts against templates / variants"""
 
     def test_variant_stock(self):
         # Check the 'Chair' variant
@@ -769,9 +750,7 @@ class VariantTest(StockTest):
 
 
 class TestResultTest(StockTest):
-    """
-    Tests for the StockItemTestResult model.
-    """
+    """Tests for the StockItemTestResult model."""
 
     def test_test_count(self):
         item = StockItem.objects.get(pk=105)
@@ -898,12 +877,10 @@ class TestResultTest(StockTest):
         self.assertEqual(item3.test_results.count(), 4)
 
     def test_installed_tests(self):
-        """
-        Test test results for stock in stock.
+        """Test test results for stock in stock.
 
         Or, test "test results" for "stock items" installed "inside" a "stock item"
         """
-
         # Get a "master" stock item
         item = StockItem.objects.get(pk=105)
 
diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py
index 3a9ad6c490..6a6b8da44e 100644
--- a/InvenTree/stock/urls.py
+++ b/InvenTree/stock/urls.py
@@ -1,6 +1,4 @@
-"""
-URL lookup for Stock app
-"""
+"""URL lookup for Stock app"""
 
 from django.urls import include, re_path
 
diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py
index 7a0f1ab978..5df3f2a027 100644
--- a/InvenTree/stock/views.py
+++ b/InvenTree/stock/views.py
@@ -1,6 +1,4 @@
-"""
-Django views for interacting with Stock app
-"""
+"""Django views for interacting with Stock app"""
 
 from datetime import datetime
 
@@ -21,8 +19,7 @@ from .models import StockItem, StockItemTracking, StockLocation
 
 
 class StockIndex(InvenTreeRoleMixin, InvenTreePluginViewMixin, ListView):
-    """ StockIndex view loads all StockLocation and StockItem object
-    """
+    """StockIndex view loads all StockLocation and StockItem object"""
     model = StockItem
     template_name = 'stock/location.html'
     context_obect_name = 'locations'
@@ -48,9 +45,7 @@ class StockIndex(InvenTreeRoleMixin, InvenTreePluginViewMixin, ListView):
 
 
 class StockLocationDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
-    """
-    Detailed view of a single StockLocation object
-    """
+    """Detailed view of a single StockLocation object"""
 
     context_object_name = 'location'
     template_name = 'stock/location.html'
@@ -69,9 +64,7 @@ class StockLocationDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailVi
 
 
 class StockItemDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
-    """
-    Detailed view of a single StockItem object
-    """
+    """Detailed view of a single StockItem object"""
 
     context_object_name = 'item'
     template_name = 'stock/item.html'
@@ -103,7 +96,7 @@ class StockItemDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
         return data
 
     def get(self, request, *args, **kwargs):
-        """ check if item exists else return to stock index """
+        """Check if item exists else return to stock index"""
 
         stock_pk = kwargs.get('pk', None)
 
@@ -120,7 +113,7 @@ class StockItemDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
 
 
 class StockLocationQRCode(QRCodeView):
-    """ View for displaying a QR code for a StockLocation object """
+    """View for displaying a QR code for a StockLocation object"""
 
     ajax_form_title = _("Stock Location QR code")
 
@@ -136,9 +129,7 @@ class StockLocationQRCode(QRCodeView):
 
 
 class StockItemReturnToStock(AjaxUpdateView):
-    """
-    View for returning a stock item (which is assigned to a customer) to stock.
-    """
+    """View for returning a stock item (which is assigned to a customer) to stock."""
 
     model = StockItem
     ajax_form_title = _("Return to Stock")
@@ -166,9 +157,7 @@ class StockItemReturnToStock(AjaxUpdateView):
 
 
 class StockItemDeleteTestData(AjaxUpdateView):
-    """
-    View for deleting all test data
-    """
+    """View for deleting all test data"""
 
     model = StockItem
     form_class = ConfirmForm
@@ -203,7 +192,7 @@ class StockItemDeleteTestData(AjaxUpdateView):
 
 
 class StockItemQRCode(QRCodeView):
-    """ View for displaying a QR code for a StockItem object """
+    """View for displaying a QR code for a StockItem object"""
 
     ajax_form_title = _("Stock Item QR Code")
     role_required = 'stock.view'
@@ -218,9 +207,7 @@ class StockItemQRCode(QRCodeView):
 
 
 class StockItemConvert(AjaxUpdateView):
-    """
-    View for 'converting' a StockItem to a variant of its current part.
-    """
+    """View for 'converting' a StockItem to a variant of its current part."""
 
     model = StockItem
     form_class = StockForms.ConvertStockItemForm
@@ -229,9 +216,7 @@ class StockItemConvert(AjaxUpdateView):
     context_object_name = 'item'
 
     def get_form(self):
-        """
-        Filter the available parts.
-        """
+        """Filter the available parts."""
 
         form = super().get_form()
         item = self.get_object()
@@ -289,7 +274,7 @@ class StockItemTrackingDelete(AjaxDeleteView):
 
 
 class StockItemTrackingEdit(AjaxUpdateView):
-    """ View for editing a StockItemTracking object """
+    """View for editing a StockItemTracking object"""
 
     model = StockItemTracking
     ajax_form_title = _('Edit Stock Tracking Entry')
@@ -297,8 +282,7 @@ class StockItemTrackingEdit(AjaxUpdateView):
 
 
 class StockItemTrackingCreate(AjaxCreateView):
-    """ View for creating a new StockItemTracking object.
-    """
+    """View for creating a new StockItemTracking object."""
 
     model = StockItemTracking
     ajax_form_title = _("Add Stock Tracking Entry")
diff --git a/InvenTree/users/admin.py b/InvenTree/users/admin.py
index 2be478fa0e..0e533bb164 100644
--- a/InvenTree/users/admin.py
+++ b/InvenTree/users/admin.py
@@ -14,9 +14,7 @@ User = get_user_model()
 
 
 class RuleSetInline(admin.TabularInline):
-    """
-    Class for displaying inline RuleSet data in the Group admin page.
-    """
+    """Class for displaying inline RuleSet data in the Group admin page."""
 
     model = RuleSet
     can_delete = False
@@ -76,9 +74,7 @@ class InvenTreeGroupAdminForm(forms.ModelForm):
 
 
 class RoleGroupAdmin(admin.ModelAdmin):  # pragma: no cover
-    """
-    Custom admin interface for the Group model
-    """
+    """Custom admin interface for the Group model"""
 
     form = InvenTreeGroupAdminForm
 
@@ -213,9 +209,7 @@ class InvenTreeUserAdmin(UserAdmin):
 
 
 class OwnerAdmin(admin.ModelAdmin):
-    """
-    Custom admin interface for the Owner model
-    """
+    """Custom admin interface for the Owner model"""
     pass
 
 
diff --git a/InvenTree/users/api.py b/InvenTree/users/api.py
index d2b25ceb5b..be8d83b58b 100644
--- a/InvenTree/users/api.py
+++ b/InvenTree/users/api.py
@@ -14,9 +14,7 @@ from users.serializers import OwnerSerializer, UserSerializer
 
 
 class OwnerList(generics.ListAPIView):
-    """
-    List API endpoint for Owner model. Cannot create.
-    """
+    """List API endpoint for Owner model. Cannot create."""
 
     queryset = Owner.objects.all()
     serializer_class = OwnerSerializer
@@ -54,9 +52,7 @@ class OwnerList(generics.ListAPIView):
 
 
 class OwnerDetail(generics.RetrieveAPIView):
-    """
-    Detail API endpoint for Owner model. Cannot edit or delete
-    """
+    """Detail API endpoint for Owner model. Cannot edit or delete"""
 
     queryset = Owner.objects.all()
     serializer_class = OwnerSerializer
@@ -108,7 +104,7 @@ class RoleDetails(APIView):
 
 
 class UserDetail(generics.RetrieveAPIView):
-    """ Detail endpoint for a single user """
+    """Detail endpoint for a single user"""
 
     queryset = User.objects.all()
     serializer_class = UserSerializer
@@ -116,7 +112,7 @@ class UserDetail(generics.RetrieveAPIView):
 
 
 class UserList(generics.ListAPIView):
-    """ List endpoint for detail on all users """
+    """List endpoint for detail on all users"""
 
     queryset = User.objects.all()
     serializer_class = UserSerializer
@@ -135,7 +131,7 @@ class UserList(generics.ListAPIView):
 
 
 class GetAuthToken(APIView):
-    """ Return authentication token for an authenticated user. """
+    """Return authentication token for an authenticated user."""
 
     permission_classes = [
         permissions.IsAuthenticated,
diff --git a/InvenTree/users/models.py b/InvenTree/users/models.py
index be5fac1641..786ed2c081 100644
--- a/InvenTree/users/models.py
+++ b/InvenTree/users/models.py
@@ -221,9 +221,7 @@ class RuleSet(models.Model):
 
     @classmethod
     def check_table_permission(cls, user, table, permission):
-        """
-        Check if the provided user has the specified permission against the table
-        """
+        """Check if the provided user has the specified permission against the table"""
 
         # If the table does *not* require permissions
         if table in cls.RULESET_IGNORE:
@@ -269,7 +267,7 @@ class RuleSet(models.Model):
         )
 
     def __str__(self, debug=False):  # pragma: no cover
-        """ Ruleset string representation """
+        """Ruleset string representation"""
         if debug:
             # Makes debugging easier
             return f'{str(self.group).ljust(15)}: {self.name.title().ljust(15)} | ' \
@@ -296,15 +294,13 @@ class RuleSet(models.Model):
             self.group.save()
 
     def get_models(self):
-        """
-        Return the database tables / models that this ruleset covers.
-        """
+        """Return the database tables / models that this ruleset covers."""
 
         return self.RULESET_MODELS.get(self.name, [])
 
 
 def split_model(model):
-    """get modelname and app from modelstring"""
+    """Get modelname and app from modelstring"""
     *app, model = model.split('_')
 
     # handle models that have
@@ -317,7 +313,7 @@ def split_model(model):
 
 
 def split_permission(app, perm):
-    """split permission string into permission and model"""
+    """Split permission string into permission and model"""
     permission_name, *model = perm.split('_')
     # handle models that have underscores
     if len(model) > 1:  # pragma: no cover
@@ -329,7 +325,6 @@ def split_permission(app, perm):
 
 def update_group_roles(group, debug=False):
     """
-
     Iterates through all of the RuleSets associated with the group,
     and ensures that the correct permissions are either applied or removed from the group.
 
@@ -339,7 +334,6 @@ def update_group_roles(group, debug=False):
     b) Whenver the group object is updated
 
     The RuleSet model has complete control over the permissions applied to any group.
-
     """
 
     if not canAppAccessDatabase(allow_test=True):
@@ -594,24 +588,20 @@ class Owner(models.Model):
     owner = GenericForeignKey('owner_type', 'owner_id')
 
     def __str__(self):
-        """ Defines the owner string representation """
+        """Defines the owner string representation"""
         return f'{self.owner} ({self.owner_type.name})'
 
     def name(self):
-        """
-        Return the 'name' of this owner
-        """
+        """Return the 'name' of this owner"""
         return str(self.owner)
 
     def label(self):
-        """
-        Return the 'type' label of this owner i.e. 'user' or 'group'
-        """
+        """Return the 'type' label of this owner i.e. 'user' or 'group'"""
         return str(self.owner_type.name)
 
     @classmethod
     def create(cls, obj):
-        """ Check if owner exist then create new owner entry """
+        """Check if owner exist then create new owner entry"""
 
         # Check for existing owner
         existing_owner = cls.get_owner(obj)
@@ -627,7 +617,7 @@ class Owner(models.Model):
 
     @classmethod
     def get_owner(cls, user_or_group):
-        """ Get owner instance for a group or user """
+        """Get owner instance for a group or user"""
 
         user_model = get_user_model()
         owner = None
diff --git a/InvenTree/users/serializers.py b/InvenTree/users/serializers.py
index fcf1ed5678..70a80f7d7f 100644
--- a/InvenTree/users/serializers.py
+++ b/InvenTree/users/serializers.py
@@ -10,8 +10,7 @@ from .models import Owner
 
 
 class UserSerializer(InvenTreeModelSerializer):
-    """ Serializer for a User
-    """
+    """Serializer for a User"""
 
     class Meta:
         model = User
@@ -23,9 +22,7 @@ class UserSerializer(InvenTreeModelSerializer):
 
 
 class OwnerSerializer(InvenTreeModelSerializer):
-    """
-    Serializer for an "Owner" (either a "user" or a "group")
-    """
+    """Serializer for an "Owner" (either a "user" or a "group")"""
 
     name = serializers.CharField(read_only=True)
 
diff --git a/InvenTree/users/test_migrations.py b/InvenTree/users/test_migrations.py
index 7bb17d0070..0adffe070b 100644
--- a/InvenTree/users/test_migrations.py
+++ b/InvenTree/users/test_migrations.py
@@ -1,6 +1,4 @@
-"""
-Unit tests for the user model database migrations
-"""
+"""Unit tests for the user model database migrations"""
 
 from django_test_migrations.contrib.unittest_case import MigratorTestCase
 
@@ -8,9 +6,7 @@ from InvenTree import helpers
 
 
 class TestForwardMigrations(MigratorTestCase):
-    """
-    Test entire schema migration sequence for the users app
-    """
+    """Test entire schema migration sequence for the users app"""
 
     migrate_from = ('users', helpers.getOldestMigrationFile('users'))
     migrate_to = ('users', helpers.getNewestMigrationFile('users'))
diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py
index 393b640d2e..0420096cbf 100644
--- a/InvenTree/users/tests.py
+++ b/InvenTree/users/tests.py
@@ -10,9 +10,7 @@ from users.models import Owner, RuleSet
 
 
 class RuleSetModelTest(TestCase):
-    """
-    Some simplistic tests to ensure the RuleSet model is setup correctly.
-    """
+    """Some simplistic tests to ensure the RuleSet model is setup correctly."""
 
     def test_ruleset_models(self):
 
@@ -48,10 +46,7 @@ class RuleSetModelTest(TestCase):
         self.assertEqual(len(empty), 0)
 
     def test_model_names(self):
-        """
-        Test that each model defined in the rulesets is valid,
-        based on the database schema!
-        """
+        """Test that each model defined in the rulesets is valid, based on the database schema!"""
 
         available_models = apps.get_models()
 
@@ -108,9 +103,7 @@ class RuleSetModelTest(TestCase):
         self.assertEqual(len(extra_models), 0)
 
     def test_permission_assign(self):
-        """
-        Test that the permission assigning works!
-        """
+        """Test that the permission assigning works!"""
 
         # Create a new group
         group = Group.objects.create(name="Test group")
@@ -161,9 +154,7 @@ class RuleSetModelTest(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 do_request(self, endpoint, filters, status_code=200):
         response = self.client.get(endpoint, filters, format='json')
@@ -212,9 +203,7 @@ class OwnerModelTest(InvenTreeTestCase):
         self.assertEqual(group_as_owner, None)
 
     def test_api(self):
-        """
-        Test user APIs
-        """
+        """Test user APIs"""
         self.client.logout()
 
         # not authed
@@ -231,9 +220,7 @@ class OwnerModelTest(InvenTreeTestCase):
         # self.do_request(reverse('api-owner-detail', kwargs={'pk': self.user.id}), {})
 
     def test_token(self):
-        """
-        Test token mechanisms
-        """
+        """Test token mechanisms"""
         self.client.logout()
 
         token = Token.objects.filter(user=self.user)