mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	Merge pull request #1707 from SchrodingersGat/order-api-fixes
Fixes for order API interface
This commit is contained in:
		| @@ -73,22 +73,50 @@ class InvenTreeAPITestCase(APITestCase): | ||||
|                 ruleset.save() | ||||
|                 break | ||||
|  | ||||
|     def get(self, url, data={}, code=200): | ||||
|     def get(self, url, data={}, expected_code=200): | ||||
|         """ | ||||
|         Issue a GET request | ||||
|         """ | ||||
|  | ||||
|         response = self.client.get(url, data, format='json') | ||||
|  | ||||
|         self.assertEqual(response.status_code, code) | ||||
|         if expected_code is not None: | ||||
|             self.assertEqual(response.status_code, expected_code) | ||||
|  | ||||
|         return response | ||||
|  | ||||
|     def post(self, url, data): | ||||
|     def post(self, url, data, expected_code=None): | ||||
|         """ | ||||
|         Issue a POST request | ||||
|         """ | ||||
|  | ||||
|         response = self.client.post(url, data=data, format='json') | ||||
|  | ||||
|         if expected_code is not None: | ||||
|             self.assertEqual(response.status_code, expected_code) | ||||
|  | ||||
|         return response | ||||
|  | ||||
|     def delete(self, url, expected_code=None): | ||||
|         """ | ||||
|         Issue a DELETE request | ||||
|         """ | ||||
|  | ||||
|         response = self.client.delete(url) | ||||
|  | ||||
|         if expected_code is not None: | ||||
|             self.assertEqual(response.status_code, expected_code) | ||||
|  | ||||
|         return response | ||||
|  | ||||
|     def patch(self, url, data, expected_code=None): | ||||
|         """ | ||||
|         Issue a PATCH request | ||||
|         """ | ||||
|  | ||||
|         response = self.client.patch(url, data=data, format='json') | ||||
|  | ||||
|         if expected_code is not None: | ||||
|             self.assertEqual(response.status_code, expected_code) | ||||
|  | ||||
|         return response | ||||
|   | ||||
| @@ -157,7 +157,7 @@ class POList(generics.ListCreateAPIView): | ||||
|     ordering = '-creation_date' | ||||
|  | ||||
|  | ||||
| class PODetail(generics.RetrieveUpdateAPIView): | ||||
| class PODetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ API endpoint for detail view of a PurchaseOrder object """ | ||||
|  | ||||
|     queryset = PurchaseOrder.objects.all() | ||||
| @@ -382,7 +382,7 @@ class SOList(generics.ListCreateAPIView): | ||||
|     ordering = '-creation_date' | ||||
|  | ||||
|  | ||||
| class SODetail(generics.RetrieveUpdateAPIView): | ||||
| class SODetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ | ||||
|     API endpoint for detail view of a SalesOrder object. | ||||
|     """ | ||||
|   | ||||
| @@ -93,8 +93,10 @@ class POSerializer(InvenTreeModelSerializer): | ||||
|         ] | ||||
|  | ||||
|         read_only_fields = [ | ||||
|             'reference', | ||||
|             'status' | ||||
|             'issue_date', | ||||
|             'complete_date', | ||||
|             'creation_date', | ||||
|         ] | ||||
|  | ||||
|  | ||||
| @@ -110,8 +112,9 @@ class POLineItemSerializer(InvenTreeModelSerializer): | ||||
|             self.fields.pop('part_detail') | ||||
|             self.fields.pop('supplier_part_detail') | ||||
|  | ||||
|     quantity = serializers.FloatField() | ||||
|     received = serializers.FloatField() | ||||
|     # TODO: Once https://github.com/inventree/InvenTree/issues/1687 is fixed, remove default values | ||||
|     quantity = serializers.FloatField(default=1) | ||||
|     received = serializers.FloatField(default=0) | ||||
|  | ||||
|     part_detail = PartBriefSerializer(source='get_base_part', many=False, read_only=True) | ||||
|     supplier_part_detail = SupplierPartSerializer(source='part', many=False, read_only=True) | ||||
| @@ -226,8 +229,9 @@ class SalesOrderSerializer(InvenTreeModelSerializer): | ||||
|         ] | ||||
|  | ||||
|         read_only_fields = [ | ||||
|             'reference', | ||||
|             'status' | ||||
|             'status', | ||||
|             'creation_date', | ||||
|             'shipment_date', | ||||
|         ] | ||||
|  | ||||
|  | ||||
| @@ -313,7 +317,9 @@ class SOLineItemSerializer(InvenTreeModelSerializer): | ||||
|     part_detail = PartBriefSerializer(source='part', many=False, read_only=True) | ||||
|     allocations = SalesOrderAllocationSerializer(many=True, read_only=True) | ||||
|  | ||||
|     quantity = serializers.FloatField() | ||||
|     # TODO: Once https://github.com/inventree/InvenTree/issues/1687 is fixed, remove default values | ||||
|     quantity = serializers.FloatField(default=1) | ||||
|  | ||||
|     allocated = serializers.FloatField(source='allocated_quantity', read_only=True) | ||||
|     fulfilled = serializers.FloatField(source='fulfilled_quantity', read_only=True) | ||||
|     sale_price_string = serializers.CharField(source='sale_price', read_only=True) | ||||
|   | ||||
| @@ -110,6 +110,96 @@ class PurchaseOrderTest(OrderTest): | ||||
|  | ||||
|         self.assertEqual(response.status_code, status.HTTP_200_OK) | ||||
|  | ||||
|     def test_po_operations(self): | ||||
|         """ | ||||
|         Test that we can create / edit and delete a PurchaseOrder via the API | ||||
|         """ | ||||
|  | ||||
|         n = PurchaseOrder.objects.count() | ||||
|  | ||||
|         url = reverse('api-po-list') | ||||
|  | ||||
|         # Initially we do not have "add" permission for the PurchaseOrder model, | ||||
|         # so this POST request should return 403 | ||||
|         response = self.post( | ||||
|             url, | ||||
|             { | ||||
|                 'supplier': 1, | ||||
|                 'reference': '123456789-xyz', | ||||
|                 'description': 'PO created via the API', | ||||
|             }, | ||||
|             expected_code=403 | ||||
|         ) | ||||
|  | ||||
|         # And no new PurchaseOrder objects should have been created | ||||
|         self.assertEqual(PurchaseOrder.objects.count(), n) | ||||
|  | ||||
|         # Ok, now let's give this user the correct permission | ||||
|         self.assignRole('purchase_order.add') | ||||
|  | ||||
|         # Initially we do not have "add" permission for the PurchaseOrder model, | ||||
|         # so this POST request should return 403 | ||||
|         response = self.post( | ||||
|             url, | ||||
|             { | ||||
|                 'supplier': 1, | ||||
|                 'reference': '123456789-xyz', | ||||
|                 'description': 'PO created via the API', | ||||
|             }, | ||||
|             expected_code=201 | ||||
|         ) | ||||
|  | ||||
|         self.assertEqual(PurchaseOrder.objects.count(), n + 1) | ||||
|  | ||||
|         pk = response.data['pk'] | ||||
|  | ||||
|         # Try to create a PO with identical reference (should fail!) | ||||
|         response = self.post( | ||||
|             url, | ||||
|             { | ||||
|                 'supplier': 1, | ||||
|                 'reference': '123456789-xyz', | ||||
|                 'description': 'A different description', | ||||
|             }, | ||||
|             expected_code=400 | ||||
|         ) | ||||
|  | ||||
|         self.assertEqual(PurchaseOrder.objects.count(), n + 1) | ||||
|  | ||||
|         url = reverse('api-po-detail', kwargs={'pk': pk}) | ||||
|  | ||||
|         # Get detail info! | ||||
|         response = self.get(url) | ||||
|         self.assertEqual(response.data['pk'], pk) | ||||
|         self.assertEqual(response.data['reference'], '123456789-xyz') | ||||
|  | ||||
|         # Try to alter (edit) the PurchaseOrder | ||||
|         response = self.patch( | ||||
|             url, | ||||
|             { | ||||
|                 'reference': '12345-abc', | ||||
|             }, | ||||
|             expected_code=200 | ||||
|         ) | ||||
|  | ||||
|         # Reference should have changed | ||||
|         self.assertEqual(response.data['reference'], '12345-abc') | ||||
|  | ||||
|         # Now, let's try to delete it! | ||||
|         # Initially, we do *not* have the required permission! | ||||
|         response = self.delete(url, expected_code=403) | ||||
|  | ||||
|         # Now, add the "delete" permission! | ||||
|         self.assignRole("purchase_order.delete") | ||||
|  | ||||
|         response = self.delete(url, expected_code=204) | ||||
|  | ||||
|         # Number of PurchaseOrder objects should have decreased | ||||
|         self.assertEqual(PurchaseOrder.objects.count(), n) | ||||
|  | ||||
|         # And if we try to access the detail view again, it has gone | ||||
|         response = self.get(url, expected_code=404) | ||||
|  | ||||
|  | ||||
| class SalesOrderTest(OrderTest): | ||||
|     """ | ||||
| @@ -158,8 +248,6 @@ class SalesOrderTest(OrderTest): | ||||
|  | ||||
|         response = self.get(url) | ||||
|  | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|         data = response.data | ||||
|  | ||||
|         self.assertEqual(data['pk'], 1) | ||||
| @@ -168,6 +256,87 @@ class SalesOrderTest(OrderTest): | ||||
|  | ||||
|         url = reverse('api-so-attachment-list') | ||||
|  | ||||
|         response = self.get(url) | ||||
|         self.get(url) | ||||
|  | ||||
|         self.assertEqual(response.status_code, status.HTTP_200_OK) | ||||
|     def test_so_operations(self): | ||||
|         """ | ||||
|         Test that we can create / edit and delete a SalesOrder via the API | ||||
|         """ | ||||
|  | ||||
|         n = SalesOrder.objects.count() | ||||
|  | ||||
|         url = reverse('api-so-list') | ||||
|  | ||||
|         # Initially we do not have "add" permission for the SalesOrder model, | ||||
|         # so this POST request should return 403 (denied) | ||||
|         response = self.post( | ||||
|             url, | ||||
|             { | ||||
|                 'customer': 4, | ||||
|                 'reference': '12345', | ||||
|                 'description': 'Sales order', | ||||
|             }, | ||||
|             expected_code=403, | ||||
|         ) | ||||
|  | ||||
|         self.assignRole('sales_order.add') | ||||
|  | ||||
|         # Now we should be able to create a SalesOrder via the API | ||||
|         response = self.post( | ||||
|             url, | ||||
|             { | ||||
|                 'customer': 4, | ||||
|                 'reference': '12345', | ||||
|                 'description': 'Sales order', | ||||
|             }, | ||||
|             expected_code=201 | ||||
|         ) | ||||
|  | ||||
|         # Check that the new order has been created | ||||
|         self.assertEqual(SalesOrder.objects.count(), n + 1) | ||||
|  | ||||
|         # Grab the PK for the newly created SalesOrder | ||||
|         pk = response.data['pk'] | ||||
|  | ||||
|         # Try to create a SO with identical reference (should fail) | ||||
|         response = self.post( | ||||
|             url, | ||||
|             { | ||||
|                 'customer': 4, | ||||
|                 'reference': '12345', | ||||
|                 'description': 'Another sales order', | ||||
|             }, | ||||
|             expected_code=400 | ||||
|         ) | ||||
|  | ||||
|         url = reverse('api-so-detail', kwargs={'pk': pk}) | ||||
|  | ||||
|         # Extract detail info for the SalesOrder | ||||
|         response = self.get(url) | ||||
|         self.assertEqual(response.data['reference'], '12345') | ||||
|  | ||||
|         # Try to alter (edit) the SalesOrder | ||||
|         response = self.patch( | ||||
|             url, | ||||
|             { | ||||
|                 'reference': '12345-a', | ||||
|             }, | ||||
|             expected_code=200 | ||||
|         ) | ||||
|  | ||||
|         # Reference should have changed | ||||
|         self.assertEqual(response.data['reference'], '12345-a') | ||||
|  | ||||
|         # Now, let's try to delete this SalesOrder | ||||
|         # Initially, we do not have the required permission | ||||
|         response = self.delete(url, expected_code=403) | ||||
|  | ||||
|         self.assignRole('sales_order.delete') | ||||
|  | ||||
|         response = self.delete(url, expected_code=204) | ||||
|  | ||||
|         # Check that the number of sales orders has decreased | ||||
|         self.assertEqual(SalesOrder.objects.count(), n) | ||||
|  | ||||
|         # And the resource should no longer be available | ||||
|         response = self.get(url, expected_code=404) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user