2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-11 07:24:15 +00:00

Docstring checks in QC checks (#3089)

* Add pre-commit to the stack

* exclude static

* Add locales to excludes

* fix style errors

* rename pipeline steps

* also wait on precommit

* make template matching simpler

* Use the same code for python setup everywhere

* use step and cache for python setup

* move regular settings up into general envs

* just use full update

* Use invoke instead of static references

* make setup actions more similar

* use python3

* refactor names to be similar

* fix runner version

* fix references

* remove incidential change

* use matrix for os

* Github can't do this right now

* ignore docstyle errors

* Add seperate docstring test

* update flake call

* do not fail on docstring

* refactor setup into workflow

* update reference

* switch to action

* resturcture

* add bash statements

* remove os from cache

* update input checks

* make code cleaner

* fix boolean

* no relative paths

* install wheel by python

* switch to install

* revert back to simple wheel

* refactor import export tests

* move setup keys back to not disturbe tests

* remove docstyle till that is fixed

* update references

* continue on error

* add docstring test

* use relativ action references

* Change step / job docstrings

* update to merge

* reformat comments 1

* fix docstrings 2

* fix docstrings 3

* fix docstrings 4

* fix docstrings 5

* fix docstrings 6

* fix docstrings 7

* fix docstrings 8

* fix docstirns 9

* fix docstrings 10

* docstring adjustments

* update the remaining docstrings

* small docstring changes

* fix function name

* update support files for docstrings

* Add missing args to docstrings

* Remove outdated function

* Add docstrings for the 'build' app

* Make API code cleaner

* add more docstrings for plugin app

* Remove dead code for plugin settings
No idea what that was even intended for

* ignore __init__ files for docstrings

* More docstrings

* Update docstrings for the 'part' directory

* Fixes for related_part functionality

* Fix removed stuff from merge 99676ee

* make more consistent

* Show statistics for docstrings

* add more docstrings

* move specific register statements to make them clearer to understant

* More docstrings for common

* and more docstrings

* and more

* simpler call

* docstrings for notifications

* docstrings for common/tests

* Add docs for common/models

* Revert "move specific register statements to make them clearer to understant"

This reverts commit ca96654622.

* use typing here

* Revert "Make API code cleaner"

This reverts commit 24fb68bd3e.

* docstring updates for the 'users' app

* Add generic Meta info to simple Meta classes

* remove unneeded unique_together statements

* More simple metas

* Remove unnecessary format specifier

* Remove extra json format specifiers

* Add docstrings for the 'plugin' app

* Docstrings for the 'label' app

* Add missing docstrings for the 'report' app

* Fix build test regression

* Fix top-level files

* docstrings for InvenTree/InvenTree

* reduce unneeded code

* add docstrings

* and more docstrings

* more docstrings

* more docstrings for stock

* more docstrings

* docstrings for order/views

* Docstrings for various files in the 'order' app

* Docstrings for order/test_api.py

* Docstrings for order/serializers.py

* Docstrings for order/admin.py

* More docstrings for the order app

* Add docstrings for the 'company' app

* Add unit tests for rebuilding the reference fields

* Prune out some more dead code

* remove more dead code

Co-authored-by: Oliver Walters <oliver.henry.walters@gmail.com>
This commit is contained in:
Matthias Mair
2022-06-01 17:37:39 +02:00
committed by GitHub
parent 66a6915213
commit 0c97a50e47
223 changed files with 4414 additions and 6978 deletions

View File

@ -1,6 +1,4 @@
"""
Provides a JSON API for the Part app
"""
"""Provides a JSON API for the Part app."""
import datetime
from decimal import Decimal, InvalidOperation
@ -41,7 +39,7 @@ from .models import (BomItem, BomItemSubstitute, Part, PartAttachment,
class CategoryList(generics.ListCreateAPIView):
""" API endpoint for accessing a list of PartCategory objects.
"""API endpoint for accessing a list of PartCategory objects.
- GET: Return a list of PartCategory objects
- POST: Create a new PartCategory object
@ -51,7 +49,7 @@ class CategoryList(generics.ListCreateAPIView):
serializer_class = part_serializers.CategorySerializer
def get_serializer_context(self):
"""Add extra context data to the serializer for the PartCategoryList endpoint"""
ctx = super().get_serializer_context()
try:
@ -63,11 +61,10 @@ class CategoryList(generics.ListCreateAPIView):
return ctx
def filter_queryset(self, queryset):
"""
Custom filtering:
"""Custom filtering:
- Allow filtering by "null" parent to retrieve top-level part categories
"""
queryset = super().filter_queryset(queryset)
params = self.request.query_params
@ -158,15 +155,13 @@ class CategoryList(generics.ListCreateAPIView):
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
"""
API endpoint for detail view of a single PartCategory object
"""
"""API endpoint for detail view of a single PartCategory object."""
serializer_class = part_serializers.CategorySerializer
queryset = PartCategory.objects.all()
def get_serializer_context(self):
"""Add extra context to the serializer for the CategoryDetail endpoint"""
ctx = super().get_serializer_context()
try:
@ -178,7 +173,7 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
return ctx
def update(self, request, *args, **kwargs):
"""Perform 'update' function and mark this part as 'starred' (or not)"""
if 'starred' in request.data:
starred = str2bool(request.data.get('starred', False))
@ -190,16 +185,17 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
class CategoryMetadata(generics.RetrieveUpdateAPIView):
"""API endpoint for viewing / updating PartCategory metadata"""
"""API endpoint for viewing / updating PartCategory metadata."""
def get_serializer(self, *args, **kwargs):
"""Return a MetadataSerializer pointing to the referenced PartCategory instance"""
return MetadataSerializer(PartCategory, *args, **kwargs)
queryset = PartCategory.objects.all()
class CategoryParameterList(generics.ListAPIView):
""" API endpoint for accessing a list of PartCategoryParameterTemplate objects.
"""API endpoint for accessing a list of PartCategoryParameterTemplate objects.
- GET: Return a list of PartCategoryParameterTemplate objects
"""
@ -208,13 +204,12 @@ class CategoryParameterList(generics.ListAPIView):
serializer_class = part_serializers.CategoryParameterTemplateSerializer
def get_queryset(self):
"""
Custom filtering:
"""Custom filtering:
- Allow filtering by "null" parent to retrieve all categories parameter templates
- Allow filtering by category
- Allow traversing all parent categories
"""
queryset = super().get_queryset()
params = self.request.query_params
@ -241,9 +236,7 @@ class CategoryParameterList(generics.ListAPIView):
class CategoryTree(generics.ListAPIView):
"""
API endpoint for accessing a list of PartCategory objects ready for rendering a tree.
"""
"""API endpoint for accessing a list of PartCategory objects ready for rendering a tree."""
queryset = PartCategory.objects.all()
serializer_class = part_serializers.CategoryTree
@ -258,18 +251,14 @@ class CategoryTree(generics.ListAPIView):
class PartSalePriceDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Detail endpoint for PartSellPriceBreak model
"""
"""Detail endpoint for PartSellPriceBreak model."""
queryset = PartSellPriceBreak.objects.all()
serializer_class = part_serializers.PartSalePriceSerializer
class PartSalePriceList(generics.ListCreateAPIView):
"""
API endpoint for list view of PartSalePriceBreak model
"""
"""API endpoint for list view of PartSalePriceBreak model."""
queryset = PartSellPriceBreak.objects.all()
serializer_class = part_serializers.PartSalePriceSerializer
@ -284,18 +273,14 @@ class PartSalePriceList(generics.ListCreateAPIView):
class PartInternalPriceDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Detail endpoint for PartInternalPriceBreak model
"""
"""Detail endpoint for PartInternalPriceBreak model."""
queryset = PartInternalPriceBreak.objects.all()
serializer_class = part_serializers.PartInternalPriceSerializer
class PartInternalPriceList(generics.ListCreateAPIView):
"""
API endpoint for list view of PartInternalPriceBreak model
"""
"""API endpoint for list view of PartInternalPriceBreak model."""
queryset = PartInternalPriceBreak.objects.all()
serializer_class = part_serializers.PartInternalPriceSerializer
@ -311,9 +296,7 @@ class PartInternalPriceList(generics.ListCreateAPIView):
class PartAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
"""
API endpoint for listing (and creating) a PartAttachment (file upload).
"""
"""API endpoint for listing (and creating) a PartAttachment (file upload)."""
queryset = PartAttachment.objects.all()
serializer_class = part_serializers.PartAttachmentSerializer
@ -328,38 +311,30 @@ class PartAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
class PartAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin):
"""
Detail endpoint for PartAttachment model
"""
"""Detail endpoint for PartAttachment model."""
queryset = PartAttachment.objects.all()
serializer_class = part_serializers.PartAttachmentSerializer
class PartTestTemplateDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Detail endpoint for PartTestTemplate model
"""
"""Detail endpoint for PartTestTemplate model."""
queryset = PartTestTemplate.objects.all()
serializer_class = part_serializers.PartTestTemplateSerializer
class PartTestTemplateList(generics.ListCreateAPIView):
"""
API endpoint for listing (and creating) a PartTestTemplate.
"""
"""API endpoint for listing (and creating) a PartTestTemplate."""
queryset = PartTestTemplate.objects.all()
serializer_class = part_serializers.PartTestTemplateSerializer
def filter_queryset(self, queryset):
"""
Filter the test list queryset.
"""Filter the test list queryset.
If filtering by 'part', we include results for any parts "above" the specified part.
"""
queryset = super().filter_queryset(queryset)
params = self.request.query_params
@ -390,15 +365,13 @@ class PartTestTemplateList(generics.ListCreateAPIView):
class PartThumbs(generics.ListAPIView):
"""
API endpoint for retrieving information on available Part thumbnails
"""
"""API endpoint for retrieving information on available Part thumbnails."""
queryset = Part.objects.all()
serializer_class = part_serializers.PartThumbSerializer
def get_queryset(self):
"""Return a queryset which exlcudes any parts without images"""
queryset = super().get_queryset()
# Get all Parts which have an associated image
@ -407,11 +380,10 @@ class PartThumbs(generics.ListAPIView):
return queryset
def list(self, request, *args, **kwargs):
"""
Serialize the available Part images.
"""Serialize the available Part images.
- Images may be used for multiple parts!
"""
queryset = self.filter_queryset(self.get_queryset())
# Return the most popular parts first
@ -436,7 +408,7 @@ class PartThumbs(generics.ListAPIView):
class PartThumbsUpdate(generics.RetrieveUpdateAPIView):
""" API endpoint for updating Part thumbnails"""
"""API endpoint for updating Part thumbnails."""
queryset = Part.objects.all()
serializer_class = part_serializers.PartThumbSerializerUpdate
@ -447,8 +419,7 @@ class PartThumbsUpdate(generics.RetrieveUpdateAPIView):
class PartScheduling(generics.RetrieveAPIView):
"""
API endpoint for delivering "scheduling" information about a given part via the API.
"""API endpoint for delivering "scheduling" information about a given part via the API.
Returns a chronologically ordered list about future "scheduled" events,
concerning stock levels for the part:
@ -462,7 +433,7 @@ class PartScheduling(generics.RetrieveAPIView):
queryset = Part.objects.all()
def retrieve(self, request, *args, **kwargs):
"""Return scheduling information for the referenced Part instance"""
today = datetime.datetime.now().date()
part = self.get_object()
@ -470,13 +441,12 @@ class PartScheduling(generics.RetrieveAPIView):
schedule = []
def add_schedule_entry(date, quantity, title, label, url):
"""
Check if a scheduled entry should be added:
"""Check if a scheduled entry should be added:
- date must be non-null
- date cannot be in the "past"
- quantity must not be zero
"""
if date and date >= today and quantity != 0:
schedule.append({
'date': date,
@ -583,25 +553,22 @@ class PartScheduling(generics.RetrieveAPIView):
class PartMetadata(generics.RetrieveUpdateAPIView):
"""
API endpoint for viewing / updating Part metadata
"""
"""API endpoint for viewing / updating Part metadata."""
def get_serializer(self, *args, **kwargs):
"""Returns a MetadataSerializer instance pointing to the referenced Part"""
return MetadataSerializer(Part, *args, **kwargs)
queryset = Part.objects.all()
class PartSerialNumberDetail(generics.RetrieveAPIView):
"""
API endpoint for returning extra serial number information about a particular part
"""
"""API endpoint for returning extra serial number information about a particular part."""
queryset = Part.objects.all()
def retrieve(self, request, *args, **kwargs):
"""Return serial number information for the referenced Part instance"""
part = self.get_object()
# Calculate the "latest" serial number
@ -621,15 +588,13 @@ class PartSerialNumberDetail(generics.RetrieveAPIView):
class PartCopyBOM(generics.CreateAPIView):
"""
API endpoint for duplicating a BOM
"""
"""API endpoint for duplicating a BOM."""
queryset = Part.objects.all()
serializer_class = part_serializers.PartCopyBOMSerializer
def get_serializer_context(self):
"""Add custom information to the serializer context for this endpoint"""
ctx = super().get_serializer_context()
try:
@ -641,13 +606,13 @@ class PartCopyBOM(generics.CreateAPIView):
class PartValidateBOM(generics.RetrieveUpdateAPIView):
"""
API endpoint for 'validating' the BOM for a given Part
"""
"""API endpoint for 'validating' the BOM for a given Part."""
class BOMValidateSerializer(serializers.ModelSerializer):
"""Simple serializer class for validating a single BomItem instance"""
class Meta:
"""Metaclass defines serializer fields"""
model = Part
fields = [
'checksum',
@ -667,6 +632,7 @@ class PartValidateBOM(generics.RetrieveUpdateAPIView):
)
def validate_valid(self, valid):
"""Check that the 'valid' input was flagged"""
if not valid:
raise ValidationError(_('This option must be selected'))
@ -675,7 +641,7 @@ class PartValidateBOM(generics.RetrieveUpdateAPIView):
serializer_class = BOMValidateSerializer
def update(self, request, *args, **kwargs):
"""Validate the referenced BomItem instance"""
part = self.get_object()
partial = kwargs.pop('partial', False)
@ -691,7 +657,7 @@ class PartValidateBOM(generics.RetrieveUpdateAPIView):
class PartDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single Part object """
"""API endpoint for detail view of a single Part object."""
queryset = Part.objects.all()
serializer_class = part_serializers.PartSerializer
@ -699,6 +665,7 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView):
starred_parts = None
def get_queryset(self, *args, **kwargs):
"""Return an annotated queryset object for the PartDetail endpoint"""
queryset = super().get_queryset(*args, **kwargs)
queryset = part_serializers.PartSerializer.annotate_queryset(queryset)
@ -706,7 +673,7 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView):
return queryset
def get_serializer(self, *args, **kwargs):
"""Return a serializer instance for the PartDetail endpoint"""
# By default, include 'category_detail' information in the detail view
try:
kwargs['category_detail'] = str2bool(self.request.query_params.get('category_detail', True))
@ -726,7 +693,11 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView):
return self.serializer_class(*args, **kwargs)
def destroy(self, request, *args, **kwargs):
# Retrieve part
"""Delete a Part instance via the API
- If the part is 'active' it cannot be deleted
- It must first be marked as 'inactive'
"""
part = Part.objects.get(pk=int(kwargs['pk']))
# Check if inactive
if not part.active:
@ -734,16 +705,14 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView):
return super(PartDetail, self).destroy(request, *args, **kwargs)
else:
# Return 405 error
message = f'Part \'{part.name}\' (pk = {part.pk}) is active: cannot delete'
message = 'Part is active: cannot delete'
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED, data=message)
def update(self, request, *args, **kwargs):
"""
Custom update functionality for Part instance.
"""Custom update functionality for Part instance.
- If the 'starred' field is provided, update the 'starred' status against current user
"""
if 'starred' in request.data:
starred = str2bool(request.data.get('starred', False))
@ -755,8 +724,8 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView):
class PartFilter(rest_filters.FilterSet):
"""
Custom filters for the PartList endpoint.
"""Custom filters for the PartList endpoint.
Uses the django_filters extension framework
"""
@ -764,7 +733,7 @@ class PartFilter(rest_filters.FilterSet):
has_ipn = rest_filters.BooleanFilter(label='Has IPN', method='filter_has_ipn')
def filter_has_ipn(self, queryset, name, value):
"""Filter by whether the Part has an IPN (internal part number) or not"""
value = str2bool(value)
if value:
@ -791,10 +760,7 @@ class PartFilter(rest_filters.FilterSet):
low_stock = rest_filters.BooleanFilter(label='Low stock', method='filter_low_stock')
def filter_low_stock(self, queryset, name, value):
"""
Filter by "low stock" status
"""
"""Filter by "low stock" status."""
value = str2bool(value)
if value:
@ -812,7 +778,7 @@ class PartFilter(rest_filters.FilterSet):
has_stock = rest_filters.BooleanFilter(label='Has stock', method='filter_has_stock')
def filter_has_stock(self, queryset, name, value):
"""Filter by whether the Part has any stock"""
value = str2bool(value)
if value:
@ -826,7 +792,7 @@ class PartFilter(rest_filters.FilterSet):
unallocated_stock = rest_filters.BooleanFilter(label='Unallocated stock', method='filter_unallocated_stock')
def filter_unallocated_stock(self, queryset, name, value):
"""Filter by whether the Part has unallocated stock"""
value = str2bool(value)
if value:
@ -854,8 +820,7 @@ class PartFilter(rest_filters.FilterSet):
class PartList(APIDownloadMixin, generics.ListCreateAPIView):
"""
API endpoint for accessing a list of Part objects
"""API endpoint for accessing a list of Part objects.
- GET: Return list of objects
- POST: Create a new Part object
@ -882,7 +847,7 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
starred_parts = None
def get_serializer(self, *args, **kwargs):
"""Return a serializer instance for this endpoint"""
# Ensure the request context is passed through
kwargs['context'] = self.get_serializer_context()
@ -904,6 +869,7 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
return self.serializer_class(*args, **kwargs)
def download_queryset(self, queryset, export_format):
"""Download the filtered queryset as a data file"""
dataset = PartResource().export(queryset=queryset)
filedata = dataset.export(export_format)
@ -912,14 +878,10 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
return DownloadFile(filedata, filename)
def list(self, request, *args, **kwargs):
"""
Overide the 'list' method, as the PartCategory objects are
very expensive to serialize!
"""Overide the 'list' method, as the PartCategory objects are very expensive to serialize!
So we will serialize them first, and keep them in memory,
so that they do not have to be serialized multiple times...
So we will serialize them first, and keep them in memory, so that they do not have to be serialized multiple times...
"""
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
@ -980,12 +942,10 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
@transaction.atomic
def create(self, request, *args, **kwargs):
"""
We wish to save the user who created this part!
"""We wish to save the user who created this part!
Note: Implementation copied from DRF class CreateModelMixin
"""
# TODO: Unit tests for this function!
serializer = self.get_serializer(data=request.data)
@ -1128,18 +1088,14 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self, *args, **kwargs):
"""Return an annotated queryset object"""
queryset = super().get_queryset(*args, **kwargs)
queryset = part_serializers.PartSerializer.annotate_queryset(queryset)
return queryset
def filter_queryset(self, queryset):
"""
Perform custom filtering of the queryset.
We overide the DRF filter_fields here because
"""
"""Perform custom filtering of the queryset"""
params = self.request.query_params
queryset = super().filter_queryset(queryset)
@ -1392,15 +1348,13 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
class PartRelatedList(generics.ListCreateAPIView):
"""
API endpoint for accessing a list of PartRelated objects
"""
"""API endpoint for accessing a list of PartRelated objects."""
queryset = PartRelated.objects.all()
serializer_class = part_serializers.PartRelationSerializer
def filter_queryset(self, queryset):
"""Custom queryset filtering"""
queryset = super().filter_queryset(queryset)
params = self.request.query_params
@ -1421,16 +1375,14 @@ class PartRelatedList(generics.ListCreateAPIView):
class PartRelatedDetail(generics.RetrieveUpdateDestroyAPIView):
"""
API endpoint for accessing detail view of a PartRelated object
"""
"""API endpoint for accessing detail view of a PartRelated object."""
queryset = PartRelated.objects.all()
serializer_class = part_serializers.PartRelationSerializer
class PartParameterTemplateList(generics.ListCreateAPIView):
""" API endpoint for accessing a list of PartParameterTemplate objects.
"""API endpoint for accessing a list of PartParameterTemplate objects.
- GET: Return list of PartParameterTemplate objects
- POST: Create a new PartParameterTemplate object
@ -1454,10 +1406,7 @@ class PartParameterTemplateList(generics.ListCreateAPIView):
]
def filter_queryset(self, queryset):
"""
Custom filtering for the PartParameterTemplate API
"""
"""Custom filtering for the PartParameterTemplate API."""
queryset = super().filter_queryset(queryset)
params = self.request.query_params
@ -1493,7 +1442,7 @@ class PartParameterTemplateList(generics.ListCreateAPIView):
class PartParameterList(generics.ListCreateAPIView):
""" API endpoint for accessing a list of PartParameter objects
"""API endpoint for accessing a list of PartParameter objects.
- GET: Return list of PartParameter objects
- POST: Create a new PartParameter object
@ -1513,18 +1462,14 @@ class PartParameterList(generics.ListCreateAPIView):
class PartParameterDetail(generics.RetrieveUpdateDestroyAPIView):
"""
API endpoint for detail view of a single PartParameter object
"""
"""API endpoint for detail view of a single PartParameter object."""
queryset = PartParameter.objects.all()
serializer_class = part_serializers.PartParameterSerializer
class BomFilter(rest_filters.FilterSet):
"""
Custom filters for the BOM list
"""
"""Custom filters for the BOM list."""
# Boolean filters for BOM item
optional = rest_filters.BooleanFilter(label='BOM line is optional')
@ -1542,8 +1487,7 @@ class BomFilter(rest_filters.FilterSet):
validated = rest_filters.BooleanFilter(label='BOM line has been validated', method='filter_validated')
def filter_validated(self, queryset, name, value):
# Work out which lines have actually been validated
"""Filter by which lines have actually been validated"""
pks = []
value = str2bool(value)
@ -1565,8 +1509,7 @@ class BomFilter(rest_filters.FilterSet):
class BomList(generics.ListCreateAPIView):
"""
API endpoint for accessing a list of BomItem objects.
"""API endpoint for accessing a list of BomItem objects.
- GET: Return list of BomItem objects
- POST: Create a new BomItem object
@ -1577,6 +1520,7 @@ class BomList(generics.ListCreateAPIView):
filterset_class = BomFilter
def list(self, request, *args, **kwargs):
"""Return serialized list response for this endpoint"""
queryset = self.filter_queryset(self.get_queryset())
@ -1602,6 +1546,13 @@ class BomList(generics.ListCreateAPIView):
return Response(data)
def get_serializer(self, *args, **kwargs):
"""Return the serializer instance for this API endpoint
If requested, extra detail fields are annotated to the queryset:
- part_detail
- sub_part_detail
- include_pricing
"""
# Do we wish to include extra detail?
try:
@ -1626,7 +1577,7 @@ class BomList(generics.ListCreateAPIView):
return self.serializer_class(*args, **kwargs)
def get_queryset(self, *args, **kwargs):
"""Return the queryset object for this endpoint"""
queryset = super().get_queryset(*args, **kwargs)
queryset = self.get_serializer_class().setup_eager_loading(queryset)
@ -1635,7 +1586,7 @@ class BomList(generics.ListCreateAPIView):
return queryset
def filter_queryset(self, queryset):
"""Custom query filtering for the BomItem list API"""
queryset = super().filter_queryset(queryset)
params = self.request.query_params
@ -1716,18 +1667,13 @@ class BomList(generics.ListCreateAPIView):
return queryset
def include_pricing(self):
"""
Determine if pricing information should be included in the response
"""
"""Determine if pricing information should be included in the response."""
pricing_default = InvenTreeSetting.get_setting('PART_SHOW_PRICE_IN_BOM')
return str2bool(self.request.query_params.get('include_pricing', pricing_default))
def annotate_pricing(self, queryset):
"""
Add part pricing information to the queryset
"""
"""Add part pricing information to the queryset."""
# Annotate with purchase prices
queryset = queryset.annotate(
purchase_price_min=Min('sub_part__stock_items__purchase_price'),
@ -1742,8 +1688,7 @@ class BomList(generics.ListCreateAPIView):
).values('pk', 'sub_part', 'purchase_price', 'purchase_price_currency')
def convert_price(price, currency, decimal_places=4):
""" Convert price field, returns Money field """
"""Convert price field, returns Money field."""
price_adjusted = None
# Get default currency from settings
@ -1796,8 +1741,7 @@ class BomList(generics.ListCreateAPIView):
class BomImportUpload(generics.CreateAPIView):
"""
API endpoint for uploading a complete Bill of Materials.
"""API endpoint for uploading a complete Bill of Materials.
It is assumed that the BOM has been extracted from a file using the BomExtract endpoint.
"""
@ -1806,10 +1750,7 @@ class BomImportUpload(generics.CreateAPIView):
serializer_class = part_serializers.BomImportUploadSerializer
def create(self, request, *args, **kwargs):
"""
Custom create function to return the extracted data
"""
"""Custom create function to return the extracted data."""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
@ -1821,31 +1762,27 @@ class BomImportUpload(generics.CreateAPIView):
class BomImportExtract(generics.CreateAPIView):
"""
API endpoint for extracting BOM data from a BOM file.
"""
"""API endpoint for extracting BOM data from a BOM file."""
queryset = Part.objects.none()
serializer_class = part_serializers.BomImportExtractSerializer
class BomImportSubmit(generics.CreateAPIView):
"""
API endpoint for submitting BOM data from a BOM file
"""
"""API endpoint for submitting BOM data from a BOM file."""
queryset = BomItem.objects.none()
serializer_class = part_serializers.BomImportSubmitSerializer
class BomDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single BomItem object """
"""API endpoint for detail view of a single BomItem object."""
queryset = BomItem.objects.all()
serializer_class = part_serializers.BomItemSerializer
def get_queryset(self, *args, **kwargs):
"""Prefetch related fields for this queryset"""
queryset = super().get_queryset(*args, **kwargs)
queryset = self.get_serializer_class().setup_eager_loading(queryset)
@ -1855,19 +1792,17 @@ class BomDetail(generics.RetrieveUpdateDestroyAPIView):
class BomItemValidate(generics.UpdateAPIView):
""" API endpoint for validating a BomItem """
"""API endpoint for validating a BomItem."""
# Very simple serializers
class BomItemValidationSerializer(serializers.Serializer):
"""Simple serializer for passing a single boolean field"""
valid = serializers.BooleanField(default=False)
queryset = BomItem.objects.all()
serializer_class = BomItemValidationSerializer
def update(self, request, *args, **kwargs):
""" Perform update request """
"""Perform update request."""
partial = kwargs.pop('partial', False)
valid = request.data.get('valid', False)
@ -1884,9 +1819,7 @@ class BomItemValidate(generics.UpdateAPIView):
class BomItemSubstituteList(generics.ListCreateAPIView):
"""
API endpoint for accessing a list of BomItemSubstitute objects
"""
"""API endpoint for accessing a list of BomItemSubstitute objects."""
serializer_class = part_serializers.BomItemSubstituteSerializer
queryset = BomItemSubstitute.objects.all()
@ -1904,9 +1837,7 @@ class BomItemSubstituteList(generics.ListCreateAPIView):
class BomItemSubstituteDetail(generics.RetrieveUpdateDestroyAPIView):
"""
API endpoint for detail view of a single BomItemSubstitute object
"""
"""API endpoint for detail view of a single BomItemSubstitute object."""
queryset = BomItemSubstitute.objects.all()
serializer_class = part_serializers.BomItemSubstituteSerializer