From 9f2c55d2d62ae4f5b13011bf859e8d3bf5ff6500 Mon Sep 17 00:00:00 2001 From: Bobbe <34186858+30350n@users.noreply.github.com> Date: Tue, 17 Oct 2023 15:48:30 +0200 Subject: [PATCH] Allow stock items to be reallocated for build items (#5693) * Allow stock items to be reallocated for build items * Refactor create check * Fix quantity calculation, Add tests --- InvenTree/build/serializers.py | 14 +++---- InvenTree/build/test_api.py | 74 ++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index 428ec25cc5..df6fa1b213 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -866,10 +866,6 @@ class BuildAllocationItemSerializer(serializers.Serializer): 'output': _('Build output cannot be specified for allocation of untracked parts'), }) - # Check if this allocation would be unique - if BuildItem.objects.filter(build_line=build_line, stock_item=stock_item, install_into=output).exists(): - raise ValidationError(_('This stock item has already been allocated to this build output')) - return data @@ -914,12 +910,16 @@ class BuildAllocationSerializer(serializers.Serializer): try: # Create a new BuildItem to allocate stock - BuildItem.objects.create( + build_item, created = BuildItem.objects.get_or_create( build_line=build_line, stock_item=stock_item, - quantity=quantity, - install_into=output + install_into=output, ) + if created: + build_item.quantity = quantity + else: + build_item.quantity += quantity + build_item.save() except (ValidationError, DjangoValidationError) as exc: # Catch model errors and re-throw as DRF errors raise ValidationError(detail=serializers.as_serializer_error(exc)) diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py index c01f633fad..fd082dd44b 100644 --- a/InvenTree/build/test_api.py +++ b/InvenTree/build/test_api.py @@ -753,6 +753,80 @@ class BuildAllocationTest(BuildAPITest): self.assertEqual(allocation.bom_item.pk, 1) self.assertEqual(allocation.stock_item.pk, 2) + def test_reallocate(self): + """Test reallocating an existing built item with the same stock item. + + This should increment the quantity of the existing BuildItem object + """ + + # Find the correct BuildLine + si = StockItem.objects.get(pk=2) + + right_line = None + for line in self.build.build_lines.all(): + if line.bom_item.sub_part.pk == si.part.pk: + right_line = line + break + + self.post( + self.url, + { + "items": [ + { + "build_line": right_line.pk, + "stock_item": 2, + "quantity": 3000, + } + ] + }, + expected_code=201 + ) + + # A new BuildItem should have been created + self.assertEqual(self.n + 1, BuildItem.objects.count()) + + allocation = BuildItem.objects.last() + + self.assertEqual(allocation.quantity, 3000) + self.assertEqual(allocation.bom_item.pk, 1) + self.assertEqual(allocation.stock_item.pk, 2) + + # Try to allocate more than the required quantity (this should fail) + self.post( + self.url, + { + "items": [ + { + "build_line": right_line.pk, + "stock_item": 2, + "quantity": 2001, + } + ] + }, + expected_code=400 + ) + + allocation.refresh_from_db() + self.assertEqual(allocation.quantity, 3000) + + # Try to allocate the remaining items + self.post( + self.url, + { + "items": [ + { + "build_line": right_line.pk, + "stock_item": 2, + "quantity": 2000, + } + ] + }, + expected_code=201 + ) + + allocation.refresh_from_db() + self.assertEqual(allocation.quantity, 5000) + class BuildOverallocationTest(BuildAPITest): """Unit tests for over allocation of stock items against a build order.