mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-17 12:35:46 +00:00
[PUI] Add view of all defined units to Admin center (#8040)
* Add API endpoint for all defined units Fixes #7858 * render all units in API * bump API * Add display for all units * remove logging * fix types * ignore favicon errors * fix for new pint version * add tests * prove against units that are not defined * append trailing slash to url * make pagination disableable again
This commit is contained in:
@ -1,13 +1,16 @@
|
||||
"""InvenTree API version information."""
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 251
|
||||
INVENTREE_API_VERSION = 252
|
||||
|
||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||
|
||||
|
||||
INVENTREE_API_TEXT = """
|
||||
|
||||
v252 - 2024-09-30 : https://github.com/inventree/InvenTree/pull/8035
|
||||
- Add endpoint for listing all known units
|
||||
|
||||
v251 - 2024-09-06 : https://github.com/inventree/InvenTree/pull/8018
|
||||
- Adds "attach_to_model" field to the ReporTemplate model
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Provides a JSON API for common components."""
|
||||
|
||||
import json
|
||||
from typing import Type
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
@ -19,6 +20,7 @@ from django_q.tasks import async_task
|
||||
from djmoney.contrib.exchange.models import ExchangeBackend, Rate
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from error_report.models import Error
|
||||
from pint._typing import UnitLike
|
||||
from rest_framework import permissions, serializers
|
||||
from rest_framework.exceptions import NotAcceptable, NotFound, PermissionDenied
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
@ -27,6 +29,7 @@ from rest_framework.views import APIView
|
||||
|
||||
import common.models
|
||||
import common.serializers
|
||||
import InvenTree.conversion
|
||||
from common.icons import get_icon_packs
|
||||
from common.settings import get_global_setting
|
||||
from generic.states.api import urlpattern as generic_states_api_urls
|
||||
@ -533,6 +536,36 @@ class CustomUnitDetail(RetrieveUpdateDestroyAPI):
|
||||
permission_classes = [permissions.IsAuthenticated, IsStaffOrReadOnly]
|
||||
|
||||
|
||||
class AllUnitList(ListAPI):
|
||||
"""List of all defined units."""
|
||||
|
||||
serializer_class = common.serializers.AllUnitListResponseSerializer
|
||||
permission_classes = [permissions.IsAuthenticated, IsStaffOrReadOnly]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""Return a list of all available units."""
|
||||
reg = InvenTree.conversion.get_unit_registry()
|
||||
all_units = {k: self.get_unit(reg, k) for k in reg}
|
||||
data = {
|
||||
'default_system': reg.default_system,
|
||||
'available_systems': dir(reg.sys),
|
||||
'available_units': {k: v for k, v in all_units.items() if v},
|
||||
}
|
||||
return Response(data)
|
||||
|
||||
def get_unit(self, reg, k):
|
||||
"""Parse a unit from the registry."""
|
||||
if not hasattr(reg, k):
|
||||
return None
|
||||
unit: Type[UnitLike] = getattr(reg, k)
|
||||
return {
|
||||
'name': k,
|
||||
'is_alias': reg.get_name(k) == k,
|
||||
'compatible_units': [str(a) for a in unit.compatible_units()],
|
||||
'isdimensionless': unit.dimensionless,
|
||||
}
|
||||
|
||||
|
||||
class ErrorMessageList(BulkDeleteMixin, ListAPI):
|
||||
"""List view for server error messages."""
|
||||
|
||||
@ -900,6 +933,7 @@ common_api_urls = [
|
||||
path('', CustomUnitDetail.as_view(), name='api-custom-unit-detail')
|
||||
]),
|
||||
),
|
||||
path('all/', AllUnitList.as_view(), name='api-all-unit-list'),
|
||||
path('', CustomUnitList.as_view(), name='api-custom-unit-list'),
|
||||
]),
|
||||
),
|
||||
|
@ -382,6 +382,22 @@ class CustomUnitSerializer(DataImportExportSerializerMixin, InvenTreeModelSerial
|
||||
fields = ['pk', 'name', 'symbol', 'definition']
|
||||
|
||||
|
||||
class AllUnitListResponseSerializer(serializers.Serializer):
|
||||
"""Serializer for the AllUnitList."""
|
||||
|
||||
class Unit(serializers.Serializer):
|
||||
"""Serializer for the AllUnitListResponseSerializer."""
|
||||
|
||||
name = serializers.CharField()
|
||||
is_alias = serializers.BooleanField()
|
||||
compatible_units = serializers.ListField(child=serializers.CharField())
|
||||
isdimensionless = serializers.BooleanField()
|
||||
|
||||
default_system = serializers.CharField()
|
||||
available_systems = serializers.ListField(child=serializers.CharField())
|
||||
available_units = Unit(many=True)
|
||||
|
||||
|
||||
class ErrorMessageSerializer(InvenTreeModelSerializer):
|
||||
"""DRF serializer for server error messages."""
|
||||
|
||||
|
@ -1495,6 +1495,14 @@ class CustomUnitAPITest(InvenTreeAPITestCase):
|
||||
for name in invalid_name_values:
|
||||
self.patch(url, {'name': name}, expected_code=400)
|
||||
|
||||
def test_api(self):
|
||||
"""Test the CustomUnit API."""
|
||||
response = self.get(reverse('api-all-unit-list'))
|
||||
self.assertIn('default_system', response.data)
|
||||
self.assertIn('available_systems', response.data)
|
||||
self.assertIn('available_units', response.data)
|
||||
self.assertEqual(len(response.data['available_units']) > 100, True)
|
||||
|
||||
|
||||
class ContentTypeAPITest(InvenTreeAPITestCase):
|
||||
"""Unit tests for the ContentType API."""
|
||||
|
Reference in New Issue
Block a user