Allow searching of BOM List API endpoint (#3296)

* Allow searching of BOM List API endpoint

* Bump API version

* Adds ordering field options to BOM List API endpoint

* Add some unit testing for new API features

* Fixes for unit tests
This commit is contained in:
Oliver 2022-07-06 10:09:58 +10:00 committed by GitHub
parent 1235d47eca
commit 0787264930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 1 deletions

View File

@ -7,6 +7,9 @@ INVENTREE_API_VERSION = 61
""" """
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
v62 -> 2022-07-05 : https://github.com/inventree/InvenTree/pull/3296
- Allows search on BOM List API endpoint
v61 -> 2022-06-12 : https://github.com/inventree/InvenTree/pull/3183 v61 -> 2022-06-12 : https://github.com/inventree/InvenTree/pull/3183
- Migrate the "Convert Stock Item" form class to use the API - Migrate the "Convert Stock Item" form class to use the API
- There is now an API endpoint for converting a stock item to a valid variant - There is now an API endpoint for converting a stock item to a valid variant

View File

@ -24,6 +24,7 @@ from common.models import InvenTreeSetting
from company.models import Company, ManufacturerPart, SupplierPart from company.models import Company, ManufacturerPart, SupplierPart
from InvenTree.api import (APIDownloadMixin, AttachmentMixin, from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
ListCreateDestroyAPIView) ListCreateDestroyAPIView)
from InvenTree.filters import InvenTreeOrderingFilter
from InvenTree.helpers import DownloadFile, increment, isNull, str2bool from InvenTree.helpers import DownloadFile, increment, isNull, str2bool
from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI, RetrieveAPI, from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI, RetrieveAPI,
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI, RetrieveUpdateAPI, RetrieveUpdateDestroyAPI,
@ -1756,12 +1757,32 @@ class BomList(ListCreateDestroyAPIView):
filter_backends = [ filter_backends = [
DjangoFilterBackend, DjangoFilterBackend,
filters.SearchFilter, filters.SearchFilter,
filters.OrderingFilter, InvenTreeOrderingFilter,
] ]
filterset_fields = [ filterset_fields = [
] ]
search_fields = [
'reference',
'sub_part__name',
'sub_part__description',
'sub_part__IPN',
'sub_part__revision',
'sub_part__keywords',
'sub_part__category__name',
]
ordering_fields = [
'quantity',
'sub_part',
'available_stock',
]
ordering_field_aliases = {
'sub_part': 'sub_part__name',
}
class BomImportUpload(CreateAPI): class BomImportUpload(CreateAPI):
"""API endpoint for uploading a complete Bill of Materials. """API endpoint for uploading a complete Bill of Materials.

View File

@ -24,6 +24,7 @@
part: 100 part: 100
sub_part: 5 sub_part: 5
quantity: 25 quantity: 25
reference: ABCDE
# 3 x Orphan # 3 x Orphan
- model: part.bomitem - model: part.bomitem
@ -32,6 +33,7 @@
part: 100 part: 100
sub_part: 50 sub_part: 50
quantity: 3 quantity: 3
reference: VWXYZ
- model: part.bomitem - model: part.bomitem
pk: 5 pk: 5
@ -39,6 +41,7 @@
part: 1 part: 1
sub_part: 5 sub_part: 5
quantity: 3 quantity: 3
reference: LMNOP
# Make "Assembly" from "Bob" # Make "Assembly" from "Bob"
- model: part.bomitem - model: part.bomitem

View File

@ -1647,6 +1647,102 @@ class BomItemTest(InvenTreeAPITestCase):
for key in ['available_stock', 'available_substitute_stock']: for key in ['available_stock', 'available_substitute_stock']:
self.assertTrue(key in el) self.assertTrue(key in el)
def test_bom_list_search(self):
"""Test that we can search the BOM list API endpoint"""
url = reverse('api-bom-list')
response = self.get(url, expected_code=200)
self.assertEqual(len(response.data), 6)
# Limit the results with a search term
response = self.get(
url,
{
'search': '0805',
},
expected_code=200,
)
self.assertEqual(len(response.data), 3)
# Search by 'reference' field
for q in ['ABCDE', 'LMNOP', 'VWXYZ']:
response = self.get(
url,
{
'search': q,
},
expected_code=200
)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['reference'], q)
# Search by nonsense data
response = self.get(
url,
{
'search': 'xxxxxxxxxxxxxxxxx',
},
expected_code=200
)
self.assertEqual(len(response.data), 0)
def test_bom_list_ordering(self):
"""Test that the BOM list results can be ordered"""
url = reverse('api-bom-list')
# Order by increasing quantity
response = self.get(
f"{url}?ordering=+quantity",
expected_code=200
)
self.assertEqual(len(response.data), 6)
q1 = response.data[0]['quantity']
q2 = response.data[-1]['quantity']
self.assertTrue(q1 < q2)
# Order by decreasing quantity
response = self.get(
f"{url}?ordering=-quantity",
expected_code=200,
)
self.assertEqual(q1, response.data[-1]['quantity'])
self.assertEqual(q2, response.data[0]['quantity'])
# Now test ordering by 'sub_part' (which is actually 'sub_part__name')
response = self.get(
url,
{
'ordering': 'sub_part',
'sub_part_detail': True,
},
expected_code=200,
)
n1 = response.data[0]['sub_part_detail']['name']
n2 = response.data[-1]['sub_part_detail']['name']
response = self.get(
url,
{
'ordering': '-sub_part',
'sub_part_detail': True,
},
expected_code=200,
)
self.assertEqual(n1, response.data[-1]['sub_part_detail']['name'])
self.assertEqual(n2, response.data[0]['sub_part_detail']['name'])
def test_get_bom_detail(self): def test_get_bom_detail(self):
"""Get the detail view for a single BomItem object.""" """Get the detail view for a single BomItem object."""
url = reverse('api-bom-item-detail', kwargs={'pk': 3}) url = reverse('api-bom-item-detail', kwargs={'pk': 3})