mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Fix a few warnings in api generation (#6836)
* remove unuses api method * update API docstrings to be more acurate * updated typing for fields * upate serializer to avoid collision * fix typing for API generation * fix ModelChoiceFilter inference * fix typing for manufacturer * bump API version * fix test * fix type checker warnings * fix api path
This commit is contained in:
parent
c04ab12fc5
commit
9a0c978f2f
@ -91,7 +91,7 @@ class VersionView(APIView):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class VersionSerializer(serializers.Serializer):
|
class VersionInformationSerializer(serializers.Serializer):
|
||||||
"""Serializer for a single version."""
|
"""Serializer for a single version."""
|
||||||
|
|
||||||
version = serializers.CharField()
|
version = serializers.CharField()
|
||||||
@ -101,21 +101,21 @@ class VersionSerializer(serializers.Serializer):
|
|||||||
latest = serializers.BooleanField()
|
latest = serializers.BooleanField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class for VersionSerializer."""
|
"""Meta class for VersionInformationSerializer."""
|
||||||
|
|
||||||
fields = ['version', 'date', 'gh', 'text', 'latest']
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class VersionApiSerializer(serializers.Serializer):
|
class VersionApiSerializer(serializers.Serializer):
|
||||||
"""Serializer for the version api endpoint."""
|
"""Serializer for the version api endpoint."""
|
||||||
|
|
||||||
VersionSerializer(many=True)
|
VersionInformationSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
class VersionTextView(ListAPI):
|
class VersionTextView(ListAPI):
|
||||||
"""Simple JSON endpoint for InvenTree version text."""
|
"""Simple JSON endpoint for InvenTree version text."""
|
||||||
|
|
||||||
serializer_class = VersionSerializer
|
serializer_class = VersionInformationSerializer
|
||||||
|
|
||||||
permission_classes = [permissions.IsAdminUser]
|
permission_classes = [permissions.IsAdminUser]
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 184
|
INVENTREE_API_VERSION = 185
|
||||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
INVENTREE_API_TEXT = """
|
INVENTREE_API_TEXT = """
|
||||||
|
|
||||||
|
v185 - 2024-03-24 : https://github.com/inventree/InvenTree/pull/6836
|
||||||
|
- Remove /plugin/activate endpoint
|
||||||
|
- Update docstrings and typing for various API endpoints (no functional changes)
|
||||||
|
|
||||||
v184 - 2024-03-17 : https://github.com/inventree/InvenTree/pull/10464
|
v184 - 2024-03-17 : https://github.com/inventree/InvenTree/pull/10464
|
||||||
- Add additional fields for tests (start/end datetime, test station)
|
- Add additional fields for tests (start/end datetime, test station)
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class SettingsSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
typ = serializers.CharField(read_only=True)
|
typ = serializers.CharField(read_only=True)
|
||||||
|
|
||||||
def get_choices(self, obj):
|
def get_choices(self, obj) -> list:
|
||||||
"""Returns the choices available for a given item."""
|
"""Returns the choices available for a given item."""
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ class CompanyDetail(RetrieveUpdateDestroyAPI):
|
|||||||
|
|
||||||
|
|
||||||
class CompanyAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
class CompanyAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
"""API endpoint for the CompanyAttachment model."""
|
"""API endpoint for listing, creating and bulk deleting a CompanyAttachment."""
|
||||||
|
|
||||||
queryset = CompanyAttachment.objects.all()
|
queryset = CompanyAttachment.objects.all()
|
||||||
serializer_class = CompanyAttachmentSerializer
|
serializer_class = CompanyAttachmentSerializer
|
||||||
@ -215,7 +215,7 @@ class ManufacturerPartDetail(RetrieveUpdateDestroyAPI):
|
|||||||
|
|
||||||
|
|
||||||
class ManufacturerPartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
class ManufacturerPartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
"""API endpoint for listing (and creating) a ManufacturerPartAttachment (file upload)."""
|
"""API endpoint for listing, creating and bulk deleting a ManufacturerPartAttachment (file upload)."""
|
||||||
|
|
||||||
queryset = ManufacturerPartAttachment.objects.all()
|
queryset = ManufacturerPartAttachment.objects.all()
|
||||||
serializer_class = ManufacturerPartAttachmentSerializer
|
serializer_class = ManufacturerPartAttachmentSerializer
|
||||||
|
@ -629,7 +629,7 @@ class PurchaseOrderExtraLineDetail(RetrieveUpdateDestroyAPI):
|
|||||||
|
|
||||||
|
|
||||||
class SalesOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
class SalesOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
"""API endpoint for listing (and creating) a SalesOrderAttachment (file upload)."""
|
"""API endpoint for listing, creating and bulk deleting a SalesOrderAttachment (file upload)."""
|
||||||
|
|
||||||
queryset = models.SalesOrderAttachment.objects.all()
|
queryset = models.SalesOrderAttachment.objects.all()
|
||||||
serializer_class = serializers.SalesOrderAttachmentSerializer
|
serializer_class = serializers.SalesOrderAttachmentSerializer
|
||||||
@ -1097,7 +1097,7 @@ class SalesOrderShipmentComplete(CreateAPI):
|
|||||||
|
|
||||||
|
|
||||||
class PurchaseOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
class PurchaseOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
"""API endpoint for listing (and creating) a PurchaseOrderAttachment (file upload)."""
|
"""API endpoint for listing, creating and bulk deleting) a PurchaseOrderAttachment (file upload)."""
|
||||||
|
|
||||||
queryset = models.PurchaseOrderAttachment.objects.all()
|
queryset = models.PurchaseOrderAttachment.objects.all()
|
||||||
serializer_class = serializers.PurchaseOrderAttachmentSerializer
|
serializer_class = serializers.PurchaseOrderAttachmentSerializer
|
||||||
@ -1363,7 +1363,7 @@ class ReturnOrderExtraLineDetail(RetrieveUpdateDestroyAPI):
|
|||||||
|
|
||||||
|
|
||||||
class ReturnOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
class ReturnOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
"""API endpoint for listing (and creating) a ReturnOrderAttachment (file upload)."""
|
"""API endpoint for listing, creating and bulk deleting a ReturnOrderAttachment (file upload)."""
|
||||||
|
|
||||||
queryset = models.ReturnOrderAttachment.objects.all()
|
queryset = models.ReturnOrderAttachment.objects.all()
|
||||||
serializer_class = serializers.ReturnOrderAttachmentSerializer
|
serializer_class = serializers.ReturnOrderAttachmentSerializer
|
||||||
|
@ -10,6 +10,8 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from django_filters import rest_framework as rest_filters
|
from django_filters import rest_framework as rest_filters
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import permissions, serializers, status
|
from rest_framework import permissions, serializers, status
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@ -214,6 +216,7 @@ class CategoryFilter(rest_filters.FilterSet):
|
|||||||
help_text=_('Exclude sub-categories under the specified category'),
|
help_text=_('Exclude sub-categories under the specified category'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_exclude_tree(self, queryset, name, value):
|
def filter_exclude_tree(self, queryset, name, value):
|
||||||
"""Exclude all sub-categories under the specified category."""
|
"""Exclude all sub-categories under the specified category."""
|
||||||
# Exclude the specified category
|
# Exclude the specified category
|
||||||
@ -406,7 +409,7 @@ class PartInternalPriceList(ListCreateAPI):
|
|||||||
|
|
||||||
|
|
||||||
class PartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
class PartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
"""API endpoint for listing (and creating) a PartAttachment (file upload)."""
|
"""API endpoint for listing, creating and bulk deleting a PartAttachment (file upload)."""
|
||||||
|
|
||||||
queryset = PartAttachment.objects.all()
|
queryset = PartAttachment.objects.all()
|
||||||
serializer_class = part_serializers.PartAttachmentSerializer
|
serializer_class = part_serializers.PartAttachmentSerializer
|
||||||
@ -1003,6 +1006,7 @@ class PartFilter(rest_filters.FilterSet):
|
|||||||
method='filter_convert_from',
|
method='filter_convert_from',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_convert_from(self, queryset, name, part):
|
def filter_convert_from(self, queryset, name, part):
|
||||||
"""Limit the queryset to valid conversion options for the specified part."""
|
"""Limit the queryset to valid conversion options for the specified part."""
|
||||||
conversion_options = part.get_conversion_options()
|
conversion_options = part.get_conversion_options()
|
||||||
@ -1017,6 +1021,7 @@ class PartFilter(rest_filters.FilterSet):
|
|||||||
method='filter_exclude_tree',
|
method='filter_exclude_tree',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_exclude_tree(self, queryset, name, part):
|
def filter_exclude_tree(self, queryset, name, part):
|
||||||
"""Exclude all parts and variants 'down' from the specified part from the queryset."""
|
"""Exclude all parts and variants 'down' from the specified part from the queryset."""
|
||||||
children = part.get_descendants(include_self=True)
|
children = part.get_descendants(include_self=True)
|
||||||
@ -1027,6 +1032,7 @@ class PartFilter(rest_filters.FilterSet):
|
|||||||
label='Ancestor', queryset=Part.objects.all(), method='filter_ancestor'
|
label='Ancestor', queryset=Part.objects.all(), method='filter_ancestor'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_ancestor(self, queryset, name, part):
|
def filter_ancestor(self, queryset, name, part):
|
||||||
"""Limit queryset to descendants of the specified ancestor part."""
|
"""Limit queryset to descendants of the specified ancestor part."""
|
||||||
descendants = part.get_descendants(include_self=False)
|
descendants = part.get_descendants(include_self=False)
|
||||||
@ -1044,6 +1050,7 @@ class PartFilter(rest_filters.FilterSet):
|
|||||||
label='In BOM Of', queryset=Part.objects.all(), method='filter_in_bom'
|
label='In BOM Of', queryset=Part.objects.all(), method='filter_in_bom'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_in_bom(self, queryset, name, part):
|
def filter_in_bom(self, queryset, name, part):
|
||||||
"""Limit queryset to parts in the BOM for the specified part."""
|
"""Limit queryset to parts in the BOM for the specified part."""
|
||||||
bom_parts = part.get_parts_in_bom()
|
bom_parts = part.get_parts_in_bom()
|
||||||
@ -1528,6 +1535,7 @@ class PartParameterTemplateFilter(rest_filters.FilterSet):
|
|||||||
queryset=Part.objects.all(), method='filter_part', label=_('Part')
|
queryset=Part.objects.all(), method='filter_part', label=_('Part')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_part(self, queryset, name, part):
|
def filter_part(self, queryset, name, part):
|
||||||
"""Filter queryset to include only PartParameterTemplates which are referenced by a part."""
|
"""Filter queryset to include only PartParameterTemplates which are referenced by a part."""
|
||||||
parameters = PartParameter.objects.filter(part=part)
|
parameters = PartParameter.objects.filter(part=part)
|
||||||
@ -1541,6 +1549,7 @@ class PartParameterTemplateFilter(rest_filters.FilterSet):
|
|||||||
label=_('Category'),
|
label=_('Category'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_category(self, queryset, name, category):
|
def filter_category(self, queryset, name, category):
|
||||||
"""Filter queryset to include only PartParameterTemplates which are referenced by parts in this category."""
|
"""Filter queryset to include only PartParameterTemplates which are referenced by parts in this category."""
|
||||||
cats = category.get_descendants(include_self=True)
|
cats = category.get_descendants(include_self=True)
|
||||||
@ -1828,6 +1837,7 @@ class BomFilter(rest_filters.FilterSet):
|
|||||||
queryset=Part.objects.all(), method='filter_uses', label=_('Uses')
|
queryset=Part.objects.all(), method='filter_uses', label=_('Uses')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_uses(self, queryset, name, part):
|
def filter_uses(self, queryset, name, part):
|
||||||
"""Filter the queryset based on the specified part."""
|
"""Filter the queryset based on the specified part."""
|
||||||
return queryset.filter(part.get_used_in_bom_item_filter())
|
return queryset.filter(part.get_used_in_bom_item_filter())
|
||||||
|
@ -466,7 +466,6 @@ plugin_api_urls = [
|
|||||||
# Plugin management
|
# Plugin management
|
||||||
path('reload/', PluginReload.as_view(), name='api-plugin-reload'),
|
path('reload/', PluginReload.as_view(), name='api-plugin-reload'),
|
||||||
path('install/', PluginInstall.as_view(), name='api-plugin-install'),
|
path('install/', PluginInstall.as_view(), name='api-plugin-install'),
|
||||||
path('activate/', PluginActivate.as_view(), name='api-plugin-activate'),
|
|
||||||
# Registry status
|
# Registry status
|
||||||
path(
|
path(
|
||||||
'status/',
|
'status/',
|
||||||
|
@ -90,12 +90,19 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
def test_plugin_activate(self):
|
def test_plugin_activate(self):
|
||||||
"""Test the plugin activate."""
|
"""Test the plugin activate."""
|
||||||
test_plg = self.plugin_confs.first()
|
test_plg = self.plugin_confs.first()
|
||||||
|
assert test_plg is not None
|
||||||
|
|
||||||
def assert_plugin_active(self, active):
|
def assert_plugin_active(self, active):
|
||||||
self.assertEqual(PluginConfig.objects.all().first().active, active)
|
plgs = PluginConfig.objects.all().first()
|
||||||
|
assert plgs is not None
|
||||||
|
self.assertEqual(plgs.active, active)
|
||||||
|
|
||||||
# Should not work - not a superuser
|
# Should not work - not a superuser
|
||||||
response = self.client.post(reverse('api-plugin-activate'), {}, follow=True)
|
response = self.client.post(
|
||||||
|
reverse('api-plugin-detail-activate', kwargs={'pk': test_plg.pk}),
|
||||||
|
{},
|
||||||
|
follow=True,
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
# Make user superuser
|
# Make user superuser
|
||||||
@ -109,7 +116,7 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
# Activate plugin with detail url
|
# Activate plugin with detail url
|
||||||
assert_plugin_active(self, False)
|
assert_plugin_active(self, False)
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
reverse('api-plugin-detail-activate', kwargs={'pk': test_plg.id}),
|
reverse('api-plugin-detail-activate', kwargs={'pk': test_plg.pk}),
|
||||||
{},
|
{},
|
||||||
follow=True,
|
follow=True,
|
||||||
)
|
)
|
||||||
@ -123,7 +130,9 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
# Activate plugin
|
# Activate plugin
|
||||||
assert_plugin_active(self, False)
|
assert_plugin_active(self, False)
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
reverse('api-plugin-activate'), {'pk': test_plg.pk}, follow=True
|
reverse('api-plugin-detail-activate', kwargs={'pk': test_plg.pk}),
|
||||||
|
{},
|
||||||
|
follow=True,
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
assert_plugin_active(self, True)
|
assert_plugin_active(self, True)
|
||||||
@ -133,6 +142,8 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
url = reverse('admin:plugin_pluginconfig_changelist')
|
url = reverse('admin:plugin_pluginconfig_changelist')
|
||||||
|
|
||||||
test_plg = self.plugin_confs.first()
|
test_plg = self.plugin_confs.first()
|
||||||
|
assert test_plg is not None
|
||||||
|
|
||||||
# deactivate plugin
|
# deactivate plugin
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
url,
|
url,
|
||||||
@ -181,6 +192,8 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
"""Test the PluginConfig model."""
|
"""Test the PluginConfig model."""
|
||||||
# check mixin registry
|
# check mixin registry
|
||||||
plg = self.plugin_confs.first()
|
plg = self.plugin_confs.first()
|
||||||
|
assert plg is not None
|
||||||
|
|
||||||
mixin_dict = plg.mixins()
|
mixin_dict = plg.mixins()
|
||||||
self.assertIn('base', mixin_dict)
|
self.assertIn('base', mixin_dict)
|
||||||
self.assertDictContainsSubset(
|
self.assertDictContainsSubset(
|
||||||
@ -190,6 +203,8 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
# check reload on save
|
# check reload on save
|
||||||
with self.assertWarns(Warning) as cm:
|
with self.assertWarns(Warning) as cm:
|
||||||
plg_inactive = self.plugin_confs.filter(active=False).first()
|
plg_inactive = self.plugin_confs.filter(active=False).first()
|
||||||
|
assert plg_inactive is not None
|
||||||
|
|
||||||
plg_inactive.active = True
|
plg_inactive.active = True
|
||||||
plg_inactive.save()
|
plg_inactive.save()
|
||||||
self.assertEqual(cm.warning.args[0], 'A reload was triggered')
|
self.assertEqual(cm.warning.args[0], 'A reload was triggered')
|
||||||
@ -208,7 +223,7 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
|
|
||||||
# Wrong with pk
|
# Wrong with pk
|
||||||
with self.assertRaises(NotFound) as exc:
|
with self.assertRaises(NotFound) as exc:
|
||||||
check_plugin(plugin_slug=None, plugin_pk='123')
|
check_plugin(plugin_slug=None, plugin_pk=123)
|
||||||
self.assertEqual(str(exc.exception.detail), "Plugin '123' not installed")
|
self.assertEqual(str(exc.exception.detail), "Plugin '123' not installed")
|
||||||
|
|
||||||
def test_plugin_settings(self):
|
def test_plugin_settings(self):
|
||||||
@ -219,6 +234,8 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
|
|
||||||
# Activate the 'sample' plugin via the API
|
# Activate the 'sample' plugin via the API
|
||||||
cfg = PluginConfig.objects.filter(key='sample').first()
|
cfg = PluginConfig.objects.filter(key='sample').first()
|
||||||
|
assert cfg is not None
|
||||||
|
|
||||||
url = reverse('api-plugin-detail-activate', kwargs={'pk': cfg.pk})
|
url = reverse('api-plugin-detail-activate', kwargs={'pk': cfg.pk})
|
||||||
self.client.patch(url, {}, expected_code=200)
|
self.client.patch(url, {}, expected_code=200)
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ from django.urls import include, path
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from django_filters import rest_framework as rest_filters
|
from django_filters import rest_framework as rest_filters
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
@ -480,9 +482,17 @@ class StockFilter(rest_filters.FilterSet):
|
|||||||
# Relationship filters
|
# Relationship filters
|
||||||
manufacturer = rest_filters.ModelChoiceFilter(
|
manufacturer = rest_filters.ModelChoiceFilter(
|
||||||
label='Manufacturer',
|
label='Manufacturer',
|
||||||
queryset=Company.objects.filter(is_manufacturer=True),
|
queryset=Company.objects.all(),
|
||||||
field_name='manufacturer_part__manufacturer',
|
method='filter_manufacturer',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
|
def filter_manufacturer(self, queryset, name, company):
|
||||||
|
"""Filter by manufacturer."""
|
||||||
|
return queryset.filter(
|
||||||
|
Q(is_manufacturer=True) & Q(manufacturer_part__manufacturer=company)
|
||||||
|
)
|
||||||
|
|
||||||
supplier = rest_filters.ModelChoiceFilter(
|
supplier = rest_filters.ModelChoiceFilter(
|
||||||
label='Supplier',
|
label='Supplier',
|
||||||
queryset=Company.objects.filter(is_supplier=True),
|
queryset=Company.objects.filter(is_supplier=True),
|
||||||
@ -725,6 +735,7 @@ class StockFilter(rest_filters.FilterSet):
|
|||||||
label='Ancestor', queryset=StockItem.objects.all(), method='filter_ancestor'
|
label='Ancestor', queryset=StockItem.objects.all(), method='filter_ancestor'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_ancestor(self, queryset, name, ancestor):
|
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))
|
return queryset.filter(parent__in=ancestor.get_descendants(include_self=True))
|
||||||
@ -735,6 +746,7 @@ class StockFilter(rest_filters.FilterSet):
|
|||||||
method='filter_category',
|
method='filter_category',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_category(self, queryset, name, category):
|
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)
|
child_categories = category.get_descendants(include_self=True)
|
||||||
@ -745,6 +757,7 @@ class StockFilter(rest_filters.FilterSet):
|
|||||||
label=_('BOM Item'), queryset=BomItem.objects.all(), method='filter_bom_item'
|
label=_('BOM Item'), queryset=BomItem.objects.all(), method='filter_bom_item'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_bom_item(self, queryset, name, bom_item):
|
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())
|
return queryset.filter(bom_item.get_stock_filter())
|
||||||
@ -753,6 +766,7 @@ class StockFilter(rest_filters.FilterSet):
|
|||||||
label=_('Part Tree'), queryset=Part.objects.all(), method='filter_part_tree'
|
label=_('Part Tree'), queryset=Part.objects.all(), method='filter_part_tree'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_part_tree(self, queryset, name, part_tree):
|
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)
|
return queryset.filter(part__tree_id=part_tree.tree_id)
|
||||||
@ -761,6 +775,7 @@ class StockFilter(rest_filters.FilterSet):
|
|||||||
label=_('Company'), queryset=Company.objects.all(), method='filter_company'
|
label=_('Company'), queryset=Company.objects.all(), method='filter_company'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
def filter_company(self, queryset, name, company):
|
def filter_company(self, queryset, name, company):
|
||||||
"""Filter by company (either manufacturer or supplier)."""
|
"""Filter by company (either manufacturer or supplier)."""
|
||||||
return queryset.filter(
|
return queryset.filter(
|
||||||
@ -813,6 +828,7 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
|
|||||||
|
|
||||||
- GET: Return a list of all StockItem objects (with optional query filters)
|
- GET: Return a list of all StockItem objects (with optional query filters)
|
||||||
- POST: Create a new StockItem
|
- POST: Create a new StockItem
|
||||||
|
- DELETE: Delete multiple StockItem objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
serializer_class = StockSerializers.StockItemSerializer
|
serializer_class = StockSerializers.StockItemSerializer
|
||||||
@ -1199,7 +1215,7 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
|
|||||||
|
|
||||||
|
|
||||||
class StockAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
class StockAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
"""API endpoint for listing (and creating) a StockItemAttachment (file upload)."""
|
"""API endpoint for listing, creating and bulk deleting a StockItemAttachment (file upload)."""
|
||||||
|
|
||||||
queryset = StockItemAttachment.objects.all()
|
queryset = StockItemAttachment.objects.all()
|
||||||
serializer_class = StockSerializers.StockItemAttachmentSerializer
|
serializer_class = StockSerializers.StockItemAttachmentSerializer
|
||||||
|
@ -29,11 +29,11 @@ class PreferredSerializer(serializers.Serializer):
|
|||||||
pui = serializers.SerializerMethodField(read_only=True)
|
pui = serializers.SerializerMethodField(read_only=True)
|
||||||
cui = serializers.SerializerMethodField(read_only=True)
|
cui = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
def get_pui(self, obj):
|
def get_pui(self, obj) -> bool:
|
||||||
"""Return true if preferred method is PUI."""
|
"""Return true if preferred method is PUI."""
|
||||||
return obj['preferred_method'] == 'pui'
|
return obj['preferred_method'] == 'pui'
|
||||||
|
|
||||||
def get_cui(self, obj):
|
def get_cui(self, obj) -> bool:
|
||||||
"""Return true if preferred method is CUI."""
|
"""Return true if preferred method is CUI."""
|
||||||
return obj['preferred_method'] == 'cui'
|
return obj['preferred_method'] == 'cui'
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user