diff --git a/src/backend/InvenTree/build/models.py b/src/backend/InvenTree/build/models.py index e633c3c791f..21e1977d10f 100644 --- a/src/backend/InvenTree/build/models.py +++ b/src/backend/InvenTree/build/models.py @@ -940,7 +940,7 @@ def create_build_output(self, quantity, **kwargs): StockHistoryCode.BUILD_OUTPUT_CREATED, user, deltas={ - 'quantity': quantity, + 'quantity': float(quantity), 'buildorder': self.pk, 'batch': batch, 'location': location.pk if location else None diff --git a/src/backend/InvenTree/build/test_api.py b/src/backend/InvenTree/build/test_api.py index f3feee051ad..222d93787f5 100644 --- a/src/backend/InvenTree/build/test_api.py +++ b/src/backend/InvenTree/build/test_api.py @@ -1269,6 +1269,86 @@ def test_sub_builds(self): self.assertEqual(len(builds), 20) +class BuildOutputCreateTest(BuildAPITest): + """Unit test for creating build output via API.""" + + def test_create_serialized_output(self): + """Create a serialized build output via the API.""" + + build_id = 1 + + url = reverse('api-build-output-create', kwargs={'pk': build_id}) + + build = Build.objects.get(pk=build_id) + part = build.part + + n_outputs = build.output_count + n_items = part.stock_items.count() + + # Post with invalid data + response = self.post( + url, + data={ + 'quantity': 10, + 'serial_numbers': '1-100', + }, + expected_code=400 + ) + + self.assertIn('Group range 1-100 exceeds allowed quantity (10)', str(response.data['serial_numbers'])) + + # Build outputs have not increased + self.assertEqual(n_outputs, build.output_count) + + # Stock items have not increased + self.assertEqual(n_items, part.stock_items.count()) + + response = self.post( + url, + data={ + 'quantity': 5, + 'serial_numbers': '1,2,3-5', + }, + expected_code=201 + ) + + # Build outputs have incdeased + self.assertEqual(n_outputs + 5, build.output_count) + + # Stock items have increased + self.assertEqual(n_items + 5, part.stock_items.count()) + + # Serial numbers have been created + for sn in range(1, 6): + self.assertTrue(part.stock_items.filter(serial=sn).exists()) + + def test_create_unserialized_output(self): + """Create an unserialized build output via the API.""" + + build_id = 1 + url = reverse('api-build-output-create', kwargs={'pk': build_id}) + + build = Build.objects.get(pk=build_id) + part = build.part + + n_outputs = build.output_count + n_items = part.stock_items.count() + + # Create a single new output + self.post( + url, + data={ + 'quantity': 10, + }, + expected_code=201 + ) + + # Build outputs have increased + self.assertEqual(n_outputs + 1, build.output_count) + + # Stock items have increased + self.assertEqual(n_items + 1, part.stock_items.count()) + class BuildOutputScrapTest(BuildAPITest): """Unit tests for scrapping build outputs""" diff --git a/src/backend/InvenTree/order/models.py b/src/backend/InvenTree/order/models.py index 7901cd31d2b..91186be139d 100644 --- a/src/backend/InvenTree/order/models.py +++ b/src/backend/InvenTree/order/models.py @@ -873,7 +873,7 @@ def receive_line_item( deltas=tracking_info, location=location, purchaseorder=self, - quantity=quantity, + quantity=float(quantity), ) # Update the number of parts received against the particular line item