mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-01 03:00:54 +00:00
[CI] docstrings (#6172)
* Squashed commit of the following: commit52d7ff0f65
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 23:03:20 2024 +0100 fixed lookup commit0d076eaea8
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 23:03:08 2024 +0100 switched to pathlib for lookup commit473e75eda2
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 22:52:30 2024 +0100 fix wrong url response commitfd74f8d703
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 21:14:38 2024 +0100 switched to ruff for import sorting commitf83fedbbb8
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 21:03:14 2024 +0100 switched to single quotes everywhere commita92442e60e
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:58:23 2024 +0100 added autofixes commitcc66c93136
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:56:47 2024 +0100 enable autoformat commit1f343606ec
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:42:14 2024 +0100 Squashed commit of the following: commitf5cf7b2e78
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:36:57 2024 +0100 fixed reqs commit9d845bee98
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:32:35 2024 +0100 disable autofix/format commitaff5f27148
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:28:50 2024 +0100 adjust checks commit47271cf1ef
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:28:22 2024 +0100 reorder order of operations commite1bf178b40
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:01:09 2024 +0100 adapted ruff settings to better fit code base commitad7d88a6f4
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 19:59:45 2024 +0100 auto fixed docstring commita2e54a760e
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 19:46:35 2024 +0100 fix getattr useage commitcb80c73bc6
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 19:25:09 2024 +0100 fix requirements file commitb7780bbd21
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:42:28 2024 +0100 fix removed sections commit71f1681f55
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:41:21 2024 +0100 fix djlint syntax commita0bcf1bcce
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:35:28 2024 +0100 remove flake8 from code base commit22475b31cc
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:34:56 2024 +0100 remove flake8 from code base commit0413350f14
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:24:39 2024 +0100 moved ruff section commitd90c48a0bf
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:24:24 2024 +0100 move djlint config to pyproject commitc5ce55d511
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:20:39 2024 +0100 added isort again commit42a41d23af
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:19:02 2024 +0100 move config section commit8569233181
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:17:52 2024 +0100 fix codespell error commit2897c6704d
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 17:29:21 2024 +0100 replaced flake8 with ruff mostly for speed improvements * enable docstring checks * fix docstrings * fixed D417 Missing argument description * Squashed commit of the following: commitd3b795824b
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 22:56:17 2024 +0100 fixed source path commit0bac0c19b8
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 22:47:53 2024 +0100 fixed req commit9f61f01d9c
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 22:45:18 2024 +0100 added missing toml req commit91b71ed24a
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:49:50 2024 +0100 moved isort config commit12460b0419
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:43:22 2024 +0100 remove flake8 section from setup.cfg commitf5cf7b2e78
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:36:57 2024 +0100 fixed reqs commit9d845bee98
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:32:35 2024 +0100 disable autofix/format commitaff5f27148
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:28:50 2024 +0100 adjust checks commit47271cf1ef
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:28:22 2024 +0100 reorder order of operations commite1bf178b40
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 20:01:09 2024 +0100 adapted ruff settings to better fit code base commitad7d88a6f4
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 19:59:45 2024 +0100 auto fixed docstring commita2e54a760e
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 19:46:35 2024 +0100 fix getattr useage commitcb80c73bc6
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 19:25:09 2024 +0100 fix requirements file commitb7780bbd21
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:42:28 2024 +0100 fix removed sections commit71f1681f55
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:41:21 2024 +0100 fix djlint syntax commita0bcf1bcce
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:35:28 2024 +0100 remove flake8 from code base commit22475b31cc
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:34:56 2024 +0100 remove flake8 from code base commit0413350f14
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:24:39 2024 +0100 moved ruff section commitd90c48a0bf
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:24:24 2024 +0100 move djlint config to pyproject commitc5ce55d511
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:20:39 2024 +0100 added isort again commit42a41d23af
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:19:02 2024 +0100 move config section commit8569233181
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 18:17:52 2024 +0100 fix codespell error commit2897c6704d
Author: Matthias Mair <code@mjmair.com> Date: Sun Jan 7 17:29:21 2024 +0100 replaced flake8 with ruff mostly for speed improvements * fix pyproject * make docstrings more uniform * auto-format * fix order * revert url change
This commit is contained in:
@ -256,7 +256,7 @@ class StockItemResource(InvenTreeResource):
|
||||
)
|
||||
|
||||
def dehydrate_purchase_price(self, item):
|
||||
"""Render purchase pric as float"""
|
||||
"""Render purchase pric as float."""
|
||||
if item.purchase_price is not None:
|
||||
return float(item.purchase_price.amount)
|
||||
|
||||
|
@ -161,13 +161,13 @@ class StockItemUninstall(StockItemContextMixin, CreateAPI):
|
||||
|
||||
|
||||
class StockItemConvert(StockItemContextMixin, CreateAPI):
|
||||
"""API endpoint for converting a stock item to a variant part"""
|
||||
"""API endpoint for converting a stock item to a variant part."""
|
||||
|
||||
serializer_class = StockSerializers.ConvertStockItemSerializer
|
||||
|
||||
|
||||
class StockItemReturn(StockItemContextMixin, CreateAPI):
|
||||
"""API endpoint for returning a stock item from a customer"""
|
||||
"""API endpoint for returning a stock item from a customer."""
|
||||
|
||||
serializer_class = StockSerializers.ReturnStockItemSerializer
|
||||
|
||||
@ -262,7 +262,7 @@ class StockLocationFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_has_location_type(self, queryset, name, value):
|
||||
"""Filter by whether or not the location has a location type"""
|
||||
"""Filter by whether or not the location has a location type."""
|
||||
if str2bool(value):
|
||||
return queryset.exclude(location_type=None)
|
||||
return queryset.filter(location_type=None)
|
||||
@ -280,7 +280,7 @@ class StockLocationList(APIDownloadMixin, ListCreateAPI):
|
||||
filterset_class = StockLocationFilter
|
||||
|
||||
def download_queryset(self, queryset, export_format):
|
||||
"""Download the filtered queryset as a data file"""
|
||||
"""Download the filtered queryset as a data file."""
|
||||
dataset = LocationResource().export(queryset=queryset)
|
||||
filedata = dataset.export(export_format)
|
||||
filename = f'InvenTree_Locations.{export_format}'
|
||||
@ -288,7 +288,7 @@ class StockLocationList(APIDownloadMixin, ListCreateAPI):
|
||||
return DownloadFile(filedata, filename)
|
||||
|
||||
def get_queryset(self, *args, **kwargs):
|
||||
"""Return annotated queryset for the StockLocationList endpoint"""
|
||||
"""Return annotated queryset for the StockLocationList endpoint."""
|
||||
queryset = super().get_queryset(*args, **kwargs)
|
||||
queryset = StockSerializers.LocationSerializer.annotate_queryset(queryset)
|
||||
return queryset
|
||||
@ -431,7 +431,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
"""FilterSet for StockItem LIST API."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options for this filterset"""
|
||||
"""Metaclass options for this filterset."""
|
||||
|
||||
model = StockItem
|
||||
|
||||
@ -505,7 +505,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
status = rest_filters.NumberFilter(label='Status Code', method='filter_status')
|
||||
|
||||
def filter_status(self, queryset, name, value):
|
||||
"""Filter by integer status code"""
|
||||
"""Filter by integer status code."""
|
||||
return queryset.filter(status=value)
|
||||
|
||||
allocated = rest_filters.BooleanFilter(
|
||||
@ -513,7 +513,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_allocated(self, queryset, name, value):
|
||||
"""Filter by whether or not the stock item is 'allocated'"""
|
||||
"""Filter by whether or not the stock item is 'allocated'."""
|
||||
if str2bool(value):
|
||||
# Filter StockItem with either build allocations or sales order allocations
|
||||
return queryset.filter(
|
||||
@ -527,7 +527,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
expired = rest_filters.BooleanFilter(label='Expired', method='filter_expired')
|
||||
|
||||
def filter_expired(self, queryset, name, value):
|
||||
"""Filter by whether or not the stock item has expired"""
|
||||
"""Filter by whether or not the stock item has expired."""
|
||||
if not common.settings.stock_expiry_enabled():
|
||||
return queryset
|
||||
|
||||
@ -540,7 +540,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_external(self, queryset, name, value):
|
||||
"""Filter by whether or not the stock item is located in an external location"""
|
||||
"""Filter by whether or not the stock item is located in an external location."""
|
||||
if str2bool(value):
|
||||
return queryset.filter(location__external=True)
|
||||
return queryset.exclude(location__external=True)
|
||||
@ -687,7 +687,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_ancestor(self, queryset, name, ancestor):
|
||||
"""Filter based on ancestor stock item"""
|
||||
"""Filter based on ancestor stock item."""
|
||||
return queryset.filter(parent__in=ancestor.get_descendants(include_self=True))
|
||||
|
||||
category = rest_filters.ModelChoiceFilter(
|
||||
@ -697,8 +697,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_category(self, queryset, name, category):
|
||||
"""Filter based on part category"""
|
||||
|
||||
"""Filter based on part category."""
|
||||
child_categories = category.get_descendants(include_self=True)
|
||||
|
||||
return queryset.filter(part__category__in=child_categories)
|
||||
@ -708,8 +707,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_bom_item(self, queryset, name, bom_item):
|
||||
"""Filter based on BOM item"""
|
||||
|
||||
"""Filter based on BOM item."""
|
||||
return queryset.filter(bom_item.get_stock_filter())
|
||||
|
||||
part_tree = rest_filters.ModelChoiceFilter(
|
||||
@ -717,7 +715,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_part_tree(self, queryset, name, part_tree):
|
||||
"""Filter based on part tree"""
|
||||
"""Filter based on part tree."""
|
||||
return queryset.filter(part__tree_id=part_tree.tree_id)
|
||||
|
||||
company = rest_filters.ModelChoiceFilter(
|
||||
@ -725,7 +723,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
)
|
||||
|
||||
def filter_company(self, queryset, name, company):
|
||||
"""Filter by company (either manufacturer or supplier)"""
|
||||
"""Filter by company (either manufacturer or supplier)."""
|
||||
return queryset.filter(
|
||||
Q(supplier_part__supplier=company)
|
||||
| Q(supplier_part__manufacturer_part__manufacturer=company)
|
||||
@ -752,7 +750,6 @@ class StockFilter(rest_filters.FilterSet):
|
||||
|
||||
def filter_stale(self, queryset, name, value):
|
||||
"""Filter by stale stock items."""
|
||||
|
||||
stale_days = common.models.InvenTreeSetting.get_setting('STOCK_STALE_DAYS')
|
||||
|
||||
if stale_days <= 0:
|
||||
@ -1452,7 +1449,7 @@ class LocationDetail(CustomRetrieveUpdateDestroyAPI):
|
||||
serializer_class = StockSerializers.LocationSerializer
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
"""Add extra context to serializer based on provided query parameters"""
|
||||
"""Add extra context to serializer based on provided query parameters."""
|
||||
try:
|
||||
params = self.request.query_params
|
||||
|
||||
@ -1465,14 +1462,13 @@ class LocationDetail(CustomRetrieveUpdateDestroyAPI):
|
||||
return self.serializer_class(*args, **kwargs)
|
||||
|
||||
def get_queryset(self, *args, **kwargs):
|
||||
"""Return annotated queryset for the StockLocationList endpoint"""
|
||||
"""Return annotated queryset for the StockLocationList endpoint."""
|
||||
queryset = super().get_queryset(*args, **kwargs)
|
||||
queryset = StockSerializers.LocationSerializer.annotate_queryset(queryset)
|
||||
return queryset
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
"""Delete a Stock location instance via the API"""
|
||||
|
||||
"""Delete a Stock location instance via the API."""
|
||||
delete_stock_items = str(request.data.get('delete_stock_items', 0)) == '1'
|
||||
delete_sub_locations = str(request.data.get('delete_sub_locations', 0)) == '1'
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
"""Custom query filters for the Stock models"""
|
||||
"""Custom query filters for the Stock models."""
|
||||
|
||||
from django.db.models import F, Func, IntegerField, OuterRef, Q, Subquery
|
||||
from django.db.models.functions import Coalesce
|
||||
|
@ -119,7 +119,7 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
||||
objects = StockLocationManager()
|
||||
|
||||
class Meta:
|
||||
"""Metaclass defines extra model properties"""
|
||||
"""Metaclass defines extra model properties."""
|
||||
|
||||
verbose_name = _('Stock Location')
|
||||
verbose_name_plural = _('Stock Locations')
|
||||
@ -131,7 +131,6 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
||||
|
||||
This must be handled within a transaction.atomic(), otherwise the tree structure is damaged
|
||||
"""
|
||||
|
||||
super().delete(
|
||||
delete_children=kwargs.get('delete_sub_locations', False),
|
||||
delete_items=kwargs.get('delete_stock_items', False),
|
||||
@ -201,8 +200,9 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
||||
|
||||
@icon.setter
|
||||
def icon(self, value):
|
||||
"""Setter to keep model API compatibility. But be careful:
|
||||
"""Setter to keep model API compatibility.
|
||||
|
||||
But be careful:
|
||||
If the field gets loaded as default value by any form which is later saved,
|
||||
the location no longer inherits its icon from the location type.
|
||||
"""
|
||||
@ -243,9 +243,9 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
||||
return owner.is_user_allowed(user, include_group=True)
|
||||
|
||||
def clean(self):
|
||||
"""Custom clean action for the StockLocation model:
|
||||
"""Custom clean action for the StockLocation model.
|
||||
|
||||
- Ensure stock location can't be made structural if stock items already located to them
|
||||
Ensure stock location can't be made structural if stock items already located to them
|
||||
"""
|
||||
if self.pk and self.structural and self.stock_item_count(False) > 0:
|
||||
raise ValidationError(
|
||||
@ -288,7 +288,7 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
||||
return self.stock_item_count()
|
||||
|
||||
def get_items(self, cascade=False):
|
||||
"""Return a queryset for all stock items under this category"""
|
||||
"""Return a queryset for all stock items under this category."""
|
||||
return self.get_stock_items(cascade=cascade)
|
||||
|
||||
|
||||
@ -904,7 +904,7 @@ class StockItem(
|
||||
|
||||
@property
|
||||
def status_text(self):
|
||||
"""Return the text representation of the status field"""
|
||||
"""Return the text representation of the status field."""
|
||||
return StockStatus.text(self.status)
|
||||
|
||||
purchase_price = InvenTreeModelMoneyField(
|
||||
@ -1669,6 +1669,7 @@ class StockItem(
|
||||
Args:
|
||||
quantity: Number of stock items to remove from this entity, and pass to the next
|
||||
location: Where to move the new StockItem to
|
||||
user: User performing the action
|
||||
|
||||
kwargs:
|
||||
notes: Optional notes for tracking
|
||||
@ -1752,7 +1753,7 @@ class StockItem(
|
||||
|
||||
@classmethod
|
||||
def optional_transfer_fields(cls):
|
||||
"""Returns a list of optional fields for a stock transfer"""
|
||||
"""Returns a list of optional fields for a stock transfer."""
|
||||
return ['batch', 'status', 'packaging']
|
||||
|
||||
@transaction.atomic
|
||||
|
@ -218,7 +218,7 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
|
||||
)
|
||||
|
||||
def validate_part(self, part):
|
||||
"""Ensure the provided Part instance is valid"""
|
||||
"""Ensure the provided Part instance is valid."""
|
||||
if part.virtual:
|
||||
raise ValidationError(_('Stock item cannot be created for virtual parts'))
|
||||
|
||||
@ -506,7 +506,6 @@ class InstallStockItemSerializer(serializers.Serializer):
|
||||
|
||||
def validate_quantity(self, quantity):
|
||||
"""Validate the quantity value."""
|
||||
|
||||
if quantity < 1:
|
||||
raise ValidationError(_('Quantity to install must be at least 1'))
|
||||
|
||||
@ -528,8 +527,7 @@ class InstallStockItemSerializer(serializers.Serializer):
|
||||
return stock_item
|
||||
|
||||
def validate(self, data):
|
||||
"""Ensure that the provided dataset is valid"""
|
||||
|
||||
"""Ensure that the provided dataset is valid."""
|
||||
stock_item = data['stock_item']
|
||||
|
||||
quantity = data.get('quantity', stock_item.quantity)
|
||||
@ -596,10 +594,10 @@ class UninstallStockItemSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class ConvertStockItemSerializer(serializers.Serializer):
|
||||
"""DRF serializer class for converting a StockItem to a valid variant part"""
|
||||
"""DRF serializer class for converting a StockItem to a valid variant part."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options"""
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = ['part']
|
||||
|
||||
@ -613,7 +611,7 @@ class ConvertStockItemSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
def validate_part(self, part):
|
||||
"""Ensure that the provided part is a valid option for the stock item"""
|
||||
"""Ensure that the provided part is a valid option for the stock item."""
|
||||
stock_item = self.context['item']
|
||||
valid_options = stock_item.part.get_conversion_options()
|
||||
|
||||
@ -625,8 +623,9 @@ class ConvertStockItemSerializer(serializers.Serializer):
|
||||
return part
|
||||
|
||||
def validate(self, data):
|
||||
"""Ensure that the stock item is valid for conversion:
|
||||
"""Ensure that the stock item is valid for conversion.
|
||||
|
||||
Rules:
|
||||
- If a SupplierPart is assigned, we cannot convert!
|
||||
"""
|
||||
data = super().validate(data)
|
||||
@ -641,7 +640,7 @@ class ConvertStockItemSerializer(serializers.Serializer):
|
||||
return data
|
||||
|
||||
def save(self):
|
||||
"""Save the serializer to convert the StockItem to the selected Part"""
|
||||
"""Save the serializer to convert the StockItem to the selected Part."""
|
||||
data = self.validated_data
|
||||
|
||||
part = data['part']
|
||||
@ -653,10 +652,10 @@ class ConvertStockItemSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class ReturnStockItemSerializer(serializers.Serializer):
|
||||
"""DRF serializer for returning a stock item from a customer"""
|
||||
"""DRF serializer for returning a stock item from a customer."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options"""
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = ['location', 'note']
|
||||
|
||||
@ -677,7 +676,7 @@ class ReturnStockItemSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
def save(self):
|
||||
"""Save the serialzier to return the item into stock"""
|
||||
"""Save the serialzier to return the item into stock."""
|
||||
item = self.context['item']
|
||||
request = self.context['request']
|
||||
|
||||
@ -690,10 +689,10 @@ class ReturnStockItemSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class StockChangeStatusSerializer(serializers.Serializer):
|
||||
"""Serializer for changing status of multiple StockItem objects"""
|
||||
"""Serializer for changing status of multiple StockItem objects."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options"""
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = ['items', 'status', 'note']
|
||||
|
||||
@ -707,7 +706,7 @@ class StockChangeStatusSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
def validate_items(self, items):
|
||||
"""Validate the selected stock items"""
|
||||
"""Validate the selected stock items."""
|
||||
if len(items) == 0:
|
||||
raise ValidationError(_('No stock items selected'))
|
||||
|
||||
@ -728,7 +727,7 @@ class StockChangeStatusSerializer(serializers.Serializer):
|
||||
|
||||
@transaction.atomic
|
||||
def save(self):
|
||||
"""Save the serializer to change the status of the selected stock items"""
|
||||
"""Save the serializer to change the status of the selected stock items."""
|
||||
data = self.validated_data
|
||||
|
||||
items = data['items']
|
||||
@ -837,7 +836,7 @@ class LocationSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
|
||||
read_only_fields = ['barcode_hash', 'icon']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Optionally add or remove extra fields"""
|
||||
"""Optionally add or remove extra fields."""
|
||||
path_detail = kwargs.pop('path_detail', False)
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
@ -847,7 +846,7 @@ class LocationSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Annotate extra information to the queryset"""
|
||||
"""Annotate extra information to the queryset."""
|
||||
# Annotate the number of stock items which exist in this category (including subcategories)
|
||||
queryset = queryset.annotate(items=stock.filters.annotate_location_items())
|
||||
|
||||
|
@ -66,7 +66,7 @@ class StockLocationTest(StockAPITestCase):
|
||||
StockLocation.objects.create(name='top', description='top category')
|
||||
|
||||
def test_list(self):
|
||||
"""Test the StockLocationList API endpoint"""
|
||||
"""Test the StockLocationList API endpoint."""
|
||||
test_cases = [
|
||||
({}, 8, 'no parameters'),
|
||||
({'parent': 1, 'cascade': False}, 2, 'Filter by parent, no cascading'),
|
||||
@ -165,7 +165,7 @@ class StockLocationTest(StockAPITestCase):
|
||||
self.post(self.list_url, data, expected_code=201)
|
||||
|
||||
def test_stock_location_delete(self):
|
||||
"""Test stock location deletion with different parameters"""
|
||||
"""Test stock location deletion with different parameters."""
|
||||
|
||||
class Target(IntEnum):
|
||||
move_sub_locations_to_parent_move_stockitems_to_parent = (0,)
|
||||
@ -294,7 +294,7 @@ class StockLocationTest(StockAPITestCase):
|
||||
self.assertEqual(child.parent, parent_stock_location)
|
||||
|
||||
def test_stock_location_structural(self):
|
||||
"""Test the effectiveness of structural stock locations
|
||||
"""Test the effectiveness of structural stock locations.
|
||||
|
||||
Make sure:
|
||||
- Stock items cannot be created in structural locations
|
||||
@ -530,7 +530,7 @@ class StockItemListTest(StockAPITestCase):
|
||||
return response.data
|
||||
|
||||
def test_top_level_filtering(self):
|
||||
"""Test filtering against "top level" stock location"""
|
||||
"""Test filtering against "top level" stock location."""
|
||||
# No filters, should return *all* items
|
||||
response = self.get(self.list_url, {}, expected_code=200)
|
||||
self.assertEqual(len(response.data), StockItem.objects.count())
|
||||
@ -628,7 +628,7 @@ class StockItemListTest(StockAPITestCase):
|
||||
self.assertEqual(len(response), 1)
|
||||
|
||||
def test_filter_by_company(self):
|
||||
"""Test that we can filter stock items by company"""
|
||||
"""Test that we can filter stock items by company."""
|
||||
for cmp in company.models.Company.objects.all():
|
||||
self.get_stock(company=cmp.pk)
|
||||
|
||||
@ -787,14 +787,14 @@ class StockItemListTest(StockAPITestCase):
|
||||
self.assertEqual(len(dataset), 17)
|
||||
|
||||
def test_filter_by_allocated(self):
|
||||
"""Test that we can filter by "allocated" status:
|
||||
"""Test that we can filter by "allocated" status.
|
||||
|
||||
Rules:
|
||||
- Only return stock items which are 'allocated'
|
||||
- Either to a build order or sales order
|
||||
- Test that the results are "distinct" (no duplicated results)
|
||||
- Ref: https://github.com/inventree/InvenTree/pull/5916
|
||||
"""
|
||||
|
||||
# Create a build order to allocate to
|
||||
assembly = part.models.Part.objects.create(
|
||||
name='F Assembly', description='Assembly for filter test', assembly=True
|
||||
@ -1284,7 +1284,7 @@ class StockItemTest(StockAPITestCase):
|
||||
self.assertEqual(sub_item.location.pk, 1)
|
||||
|
||||
def test_return_from_customer(self):
|
||||
"""Test that we can return a StockItem from a customer, via the API"""
|
||||
"""Test that we can return a StockItem from a customer, via the API."""
|
||||
# Assign item to customer
|
||||
item = StockItem.objects.get(pk=521)
|
||||
customer = company.models.Company.objects.get(pk=4)
|
||||
@ -1316,7 +1316,7 @@ class StockItemTest(StockAPITestCase):
|
||||
self.assertIsNone(item.customer)
|
||||
|
||||
def test_convert_to_variant(self):
|
||||
"""Test that we can convert a StockItem to a variant part via the API"""
|
||||
"""Test that we can convert a StockItem to a variant part via the API."""
|
||||
category = part.models.PartCategory.objects.get(pk=3)
|
||||
|
||||
# First, construct a set of template / variant parts
|
||||
@ -1361,7 +1361,7 @@ class StockItemTest(StockAPITestCase):
|
||||
self.assertEqual(stock_item.part, variant)
|
||||
|
||||
def test_set_status(self):
|
||||
"""Test API endpoint for setting StockItem status"""
|
||||
"""Test API endpoint for setting StockItem status."""
|
||||
url = reverse('api-stock-change-status')
|
||||
|
||||
prt = Part.objects.first()
|
||||
@ -1612,7 +1612,7 @@ class StockTestResultTest(StockAPITestCase):
|
||||
self.assertIsNotNone(response.data['attachment'])
|
||||
|
||||
def test_bulk_delete(self):
|
||||
"""Test that the BulkDelete endpoint works for this model"""
|
||||
"""Test that the BulkDelete endpoint works for this model."""
|
||||
n = StockItemTestResult.objects.count()
|
||||
|
||||
tests = []
|
||||
@ -1849,7 +1849,7 @@ class StockMetadataAPITest(InvenTreeAPITestCase):
|
||||
roles = ['stock.change', 'stock_location.change']
|
||||
|
||||
def metatester(self, apikey, model):
|
||||
"""Generic tester"""
|
||||
"""Generic tester."""
|
||||
modeldata = model.objects.first()
|
||||
|
||||
# Useless test unless a model object is found
|
||||
@ -1875,7 +1875,7 @@ class StockMetadataAPITest(InvenTreeAPITestCase):
|
||||
)
|
||||
|
||||
def test_metadata(self):
|
||||
"""Test all endpoints"""
|
||||
"""Test all endpoints."""
|
||||
for apikey, model in {
|
||||
'api-location-metadata': StockLocation,
|
||||
'api-stock-test-result-metadata': StockItemTestResult,
|
||||
|
@ -1,4 +1,4 @@
|
||||
"""Unit tests for data migrations in the 'stock' app"""
|
||||
"""Unit tests for data migrations in the 'stock' app."""
|
||||
|
||||
from django_test_migrations.contrib.unittest_case import MigratorTestCase
|
||||
|
||||
@ -6,13 +6,13 @@ from InvenTree import unit_test
|
||||
|
||||
|
||||
class TestSerialNumberMigration(MigratorTestCase):
|
||||
"""Test data migration which updates serial numbers"""
|
||||
"""Test data migration which updates serial numbers."""
|
||||
|
||||
migrate_from = ('stock', '0067_alter_stockitem_part')
|
||||
migrate_to = ('stock', unit_test.getNewestMigrationFile('stock'))
|
||||
|
||||
def prepare(self):
|
||||
"""Create initial data for this migration"""
|
||||
"""Create initial data for this migration."""
|
||||
Part = self.old_state.apps.get_model('part', 'part')
|
||||
StockItem = self.old_state.apps.get_model('stock', 'stockitem')
|
||||
|
||||
@ -48,7 +48,7 @@ class TestSerialNumberMigration(MigratorTestCase):
|
||||
self.big_ref_pk = item.pk
|
||||
|
||||
def test_migrations(self):
|
||||
"""Test that the migrations have been applied correctly"""
|
||||
"""Test that the migrations have been applied correctly."""
|
||||
StockItem = self.new_state.apps.get_model('stock', 'stockitem')
|
||||
|
||||
# Check that the serial number integer conversion has been applied correctly
|
||||
@ -68,13 +68,13 @@ class TestSerialNumberMigration(MigratorTestCase):
|
||||
|
||||
|
||||
class TestScheduledForDeletionMigration(MigratorTestCase):
|
||||
"""Test data migration for removing 'scheduled_for_deletion' field"""
|
||||
"""Test data migration for removing 'scheduled_for_deletion' field."""
|
||||
|
||||
migrate_from = ('stock', '0066_stockitem_scheduled_for_deletion')
|
||||
migrate_to = ('stock', unit_test.getNewestMigrationFile('stock'))
|
||||
|
||||
def prepare(self):
|
||||
"""Create some initial stock items"""
|
||||
"""Create some initial stock items."""
|
||||
Part = self.old_state.apps.get_model('part', 'part')
|
||||
StockItem = self.old_state.apps.get_model('stock', 'stockitem')
|
||||
|
||||
@ -128,7 +128,7 @@ class TestScheduledForDeletionMigration(MigratorTestCase):
|
||||
self.assertEqual(StockItem.objects.count(), 29)
|
||||
|
||||
def test_migration(self):
|
||||
"""Test that all stock items were actually removed"""
|
||||
"""Test that all stock items were actually removed."""
|
||||
StockItem = self.new_state.apps.get_model('stock', 'stockitem')
|
||||
|
||||
# All the "scheduled for deletion" items have been removed
|
||||
|
@ -28,10 +28,10 @@ class StockListTest(StockViewTestCase):
|
||||
|
||||
|
||||
class StockDetailTest(StockViewTestCase):
|
||||
"""Unit test for the 'stock detail' page"""
|
||||
"""Unit test for the 'stock detail' page."""
|
||||
|
||||
def test_basic_info(self):
|
||||
"""Test that basic stock item info is rendered"""
|
||||
"""Test that basic stock item info is rendered."""
|
||||
url = reverse('stock-item-detail', kwargs={'pk': 1})
|
||||
|
||||
response = self.client.get(url)
|
||||
|
@ -18,7 +18,7 @@ from .models import StockItem, StockItemTestResult, StockItemTracking, StockLoca
|
||||
|
||||
|
||||
class StockTestBase(InvenTreeTestCase):
|
||||
"""Base class for running Stock tests"""
|
||||
"""Base class for running Stock tests."""
|
||||
|
||||
fixtures = [
|
||||
'category',
|
||||
@ -53,7 +53,7 @@ class StockTest(StockTestBase):
|
||||
"""Tests to ensure that the stock location tree functions correctly."""
|
||||
|
||||
def test_pathstring(self):
|
||||
"""Check that pathstring updates occur as expected"""
|
||||
"""Check that pathstring updates occur as expected."""
|
||||
a = StockLocation.objects.create(name='A')
|
||||
b = StockLocation.objects.create(name='B', parent=a)
|
||||
c = StockLocation.objects.create(name='C', parent=b)
|
||||
@ -128,7 +128,7 @@ class StockTest(StockTestBase):
|
||||
self.assertTrue(d.pathstring.endswith('DDDDDDDD'))
|
||||
|
||||
def test_link(self):
|
||||
"""Test the link URL field validation"""
|
||||
"""Test the link URL field validation."""
|
||||
item = StockItem.objects.get(pk=1)
|
||||
|
||||
# Check that invalid URLs fail
|
||||
@ -163,14 +163,14 @@ class StockTest(StockTestBase):
|
||||
|
||||
@override_settings(EXTRA_URL_SCHEMES=['ssh'])
|
||||
def test_exteneded_schema(self):
|
||||
"""Test that extended URL schemes are allowed"""
|
||||
"""Test that extended URL schemes are allowed."""
|
||||
item = StockItem.objects.get(pk=1)
|
||||
item.link = 'ssh://user:pwd@deb.org:223'
|
||||
item.save()
|
||||
item.full_clean()
|
||||
|
||||
def test_serial_numbers(self):
|
||||
"""Test serial number uniqueness"""
|
||||
"""Test serial number uniqueness."""
|
||||
# Ensure that 'global uniqueness' setting is enabled
|
||||
InvenTreeSetting.set_setting('SERIAL_NUMBER_GLOBALLY_UNIQUE', True, self.user)
|
||||
|
||||
@ -456,7 +456,7 @@ class StockTest(StockTestBase):
|
||||
self.assertFalse(it.add_stock(-10, None))
|
||||
|
||||
def test_allocate_to_customer(self):
|
||||
"""Test allocating stock to a customer"""
|
||||
"""Test allocating stock to a customer."""
|
||||
it = StockItem.objects.get(pk=2)
|
||||
n = it.quantity
|
||||
an = n - 10
|
||||
@ -486,7 +486,7 @@ class StockTest(StockTestBase):
|
||||
self.assertIn('Allocated some stock', track.notes)
|
||||
|
||||
def test_return_from_customer(self):
|
||||
"""Test removing previous allocated stock from customer"""
|
||||
"""Test removing previous allocated stock from customer."""
|
||||
it = StockItem.objects.get(pk=2)
|
||||
|
||||
# First establish total stock for this part
|
||||
@ -887,10 +887,10 @@ class StockTest(StockTestBase):
|
||||
|
||||
|
||||
class StockBarcodeTest(StockTestBase):
|
||||
"""Run barcode tests for the stock app"""
|
||||
"""Run barcode tests for the stock app."""
|
||||
|
||||
def test_stock_item_barcode_basics(self):
|
||||
"""Simple tests for the StockItem barcode integration"""
|
||||
"""Simple tests for the StockItem barcode integration."""
|
||||
item = StockItem.objects.get(pk=1)
|
||||
|
||||
self.assertEqual(StockItem.barcode_model_type(), 'stockitem')
|
||||
@ -906,7 +906,7 @@ class StockBarcodeTest(StockTestBase):
|
||||
self.assertEqual(barcode, '{"stockitem": 1}')
|
||||
|
||||
def test_location_barcode_basics(self):
|
||||
"""Simple tests for the StockLocation barcode integration"""
|
||||
"""Simple tests for the StockLocation barcode integration."""
|
||||
self.assertEqual(StockLocation.barcode_model_type(), 'stocklocation')
|
||||
|
||||
loc = StockLocation.objects.get(pk=1)
|
||||
|
Reference in New Issue
Block a user