mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-29 20:30:39 +00:00 
			
		
		
		
	Merge branch 'master' of git://github.com/inventree/InvenTree into color_themes
This commit is contained in:
		| @@ -6,7 +6,7 @@ from InvenTree.settings import * | ||||
|  | ||||
| # Override the 'test' database | ||||
| if 'test' in sys.argv: | ||||
|     eprint('InvenTree: Running tests - Using MySQL test database') | ||||
|     eprint('InvenTree: Running tests - Using PostGreSQL test database') | ||||
|      | ||||
|     DATABASES['default'] = { | ||||
|         # Ensure postgresql backend is being used | ||||
|   | ||||
| @@ -78,6 +78,56 @@ class PartDetailTest(PartViewTestCase): | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertTrue(response.context['editing_enabled']) | ||||
|  | ||||
|     def test_part_detail_from_ipn(self): | ||||
|         """ | ||||
|         Test that we can retrieve a part detail page from part IPN: | ||||
|         - if no part with matching IPN -> return part index | ||||
|         - if unique IPN match -> return part detail page | ||||
|         - if multiple IPN matches -> return part index | ||||
|         """ | ||||
|         ipn_test = 'PART-000000-AA' | ||||
|         pk = 1 | ||||
|  | ||||
|         def test_ipn_match(index_result=False, detail_result=False): | ||||
|             index_redirect = False | ||||
|             detail_redirect = False | ||||
|  | ||||
|             response = self.client.get(reverse('part-detail-from-ipn', args=(ipn_test,))) | ||||
|  | ||||
|             # Check for PartIndex redirect | ||||
|             try: | ||||
|                 if response.url == '/part/': | ||||
|                     index_redirect = True | ||||
|             except AttributeError: | ||||
|                 pass | ||||
|  | ||||
|             # Check for PartDetail redirect | ||||
|             try: | ||||
|                 if response.context['part'].pk == pk: | ||||
|                     detail_redirect = True | ||||
|             except TypeError: | ||||
|                 pass | ||||
|  | ||||
|             self.assertEqual(index_result, index_redirect) | ||||
|             self.assertEqual(detail_result, detail_redirect) | ||||
|  | ||||
|         # Test no match | ||||
|         test_ipn_match(index_result=True, detail_result=False) | ||||
|  | ||||
|         # Test unique match | ||||
|         part = Part.objects.get(pk=pk) | ||||
|         part.IPN = ipn_test | ||||
|         part.save() | ||||
|  | ||||
|         test_ipn_match(index_result=False, detail_result=True) | ||||
|  | ||||
|         # Test multiple matches | ||||
|         part = Part.objects.get(pk=pk + 1) | ||||
|         part.IPN = ipn_test | ||||
|         part.save() | ||||
|  | ||||
|         test_ipn_match(index_result=True, detail_result=False) | ||||
|  | ||||
|     def test_bom_download(self): | ||||
|         """ Test downloading a BOM for a valid part """ | ||||
|  | ||||
|   | ||||
| @@ -99,7 +99,7 @@ part_urls = [ | ||||
|     # Export data for multiple parts | ||||
|     url(r'^export/', views.PartExport.as_view(), name='part-export'), | ||||
|  | ||||
|     # Individual part | ||||
|     # Individual part using pk | ||||
|     url(r'^(?P<pk>\d+)/', include(part_detail_urls)), | ||||
|  | ||||
|     # Part category | ||||
| @@ -124,6 +124,9 @@ part_urls = [ | ||||
|     # Bom Items | ||||
|     url(r'^bom/(?P<pk>\d+)/', include(part_bom_urls)), | ||||
|  | ||||
|     # Individual part using IPN as slug | ||||
|     url(r'^(?P<slug>[-\w]+)/', views.PartDetailFromIPN.as_view(), name='part-detail-from-ipn'), | ||||
|  | ||||
|     # Top level part list (display top level parts and categories) | ||||
|     url(r'^.*$', views.PartIndex.as_view(), name='part-index'), | ||||
| ] | ||||
|   | ||||
| @@ -663,6 +663,43 @@ class PartDetail(DetailView): | ||||
|         return context | ||||
|  | ||||
|  | ||||
| class PartDetailFromIPN(PartDetail): | ||||
|     slug_field = 'IPN' | ||||
|     slug_url_kwarg = 'slug' | ||||
|  | ||||
|     def get_object(self): | ||||
|         """ Return Part object which IPN field matches the slug value """ | ||||
|         queryset = self.get_queryset() | ||||
|         # Get slug | ||||
|         slug = self.kwargs.get(self.slug_url_kwarg) | ||||
|  | ||||
|         if slug is not None: | ||||
|             slug_field = self.get_slug_field() | ||||
|             # Filter by the slug value | ||||
|             queryset = queryset.filter(**{slug_field: slug}) | ||||
|  | ||||
|             try: | ||||
|                 # Get unique part from queryset | ||||
|                 part = queryset.get() | ||||
|                 # Return Part object | ||||
|                 return part | ||||
|             except queryset.model.MultipleObjectsReturned: | ||||
|                 pass | ||||
|             except queryset.model.DoesNotExist: | ||||
|                 pass | ||||
|          | ||||
|         return None | ||||
|  | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         """ Attempt to match slug to a Part, else redirect to PartIndex view """ | ||||
|         self.object = self.get_object() | ||||
|  | ||||
|         if not self.object: | ||||
|             return HttpResponseRedirect(reverse('part-index')) | ||||
|  | ||||
|         return super(PartDetailFromIPN, self).get(request, *args, **kwargs) | ||||
|  | ||||
|  | ||||
| class PartQRCode(QRCodeView): | ||||
|     """ View for displaying a QR code for a Part object """ | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user