mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	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:
		@@ -24,6 +24,7 @@ from common.models import InvenTreeSetting
 | 
			
		||||
from company.models import Company, ManufacturerPart, SupplierPart
 | 
			
		||||
from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
 | 
			
		||||
                           ListCreateDestroyAPIView)
 | 
			
		||||
from InvenTree.filters import InvenTreeOrderingFilter
 | 
			
		||||
from InvenTree.helpers import DownloadFile, increment, isNull, str2bool
 | 
			
		||||
from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI, RetrieveAPI,
 | 
			
		||||
                              RetrieveUpdateAPI, RetrieveUpdateDestroyAPI,
 | 
			
		||||
@@ -1756,12 +1757,32 @@ class BomList(ListCreateDestroyAPIView):
 | 
			
		||||
    filter_backends = [
 | 
			
		||||
        DjangoFilterBackend,
 | 
			
		||||
        filters.SearchFilter,
 | 
			
		||||
        filters.OrderingFilter,
 | 
			
		||||
        InvenTreeOrderingFilter,
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    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):
 | 
			
		||||
    """API endpoint for uploading a complete Bill of Materials.
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
    part: 100
 | 
			
		||||
    sub_part: 5
 | 
			
		||||
    quantity: 25
 | 
			
		||||
    reference: ABCDE
 | 
			
		||||
 | 
			
		||||
# 3 x Orphan
 | 
			
		||||
- model: part.bomitem
 | 
			
		||||
@@ -32,6 +33,7 @@
 | 
			
		||||
    part: 100
 | 
			
		||||
    sub_part: 50
 | 
			
		||||
    quantity: 3
 | 
			
		||||
    reference: VWXYZ
 | 
			
		||||
 | 
			
		||||
- model: part.bomitem
 | 
			
		||||
  pk: 5
 | 
			
		||||
@@ -39,6 +41,7 @@
 | 
			
		||||
    part: 1
 | 
			
		||||
    sub_part: 5
 | 
			
		||||
    quantity: 3
 | 
			
		||||
    reference: LMNOP
 | 
			
		||||
 | 
			
		||||
# Make "Assembly" from "Bob"
 | 
			
		||||
- model: part.bomitem
 | 
			
		||||
 
 | 
			
		||||
@@ -1647,6 +1647,102 @@ class BomItemTest(InvenTreeAPITestCase):
 | 
			
		||||
            for key in ['available_stock', 'available_substitute_stock']:
 | 
			
		||||
                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):
 | 
			
		||||
        """Get the detail view for a single BomItem object."""
 | 
			
		||||
        url = reverse('api-bom-item-detail', kwargs={'pk': 3})
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user