mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	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
This commit is contained in:
		@@ -866,10 +866,6 @@ class BuildAllocationItemSerializer(serializers.Serializer):
 | 
				
			|||||||
                'output': _('Build output cannot be specified for allocation of untracked parts'),
 | 
					                '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
 | 
					        return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -914,12 +910,16 @@ class BuildAllocationSerializer(serializers.Serializer):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    # Create a new BuildItem to allocate stock
 | 
					                    # Create a new BuildItem to allocate stock
 | 
				
			||||||
                    BuildItem.objects.create(
 | 
					                    build_item, created = BuildItem.objects.get_or_create(
 | 
				
			||||||
                        build_line=build_line,
 | 
					                        build_line=build_line,
 | 
				
			||||||
                        stock_item=stock_item,
 | 
					                        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:
 | 
					                except (ValidationError, DjangoValidationError) as exc:
 | 
				
			||||||
                    # Catch model errors and re-throw as DRF errors
 | 
					                    # Catch model errors and re-throw as DRF errors
 | 
				
			||||||
                    raise ValidationError(detail=serializers.as_serializer_error(exc))
 | 
					                    raise ValidationError(detail=serializers.as_serializer_error(exc))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -753,6 +753,80 @@ class BuildAllocationTest(BuildAPITest):
 | 
				
			|||||||
        self.assertEqual(allocation.bom_item.pk, 1)
 | 
					        self.assertEqual(allocation.bom_item.pk, 1)
 | 
				
			||||||
        self.assertEqual(allocation.stock_item.pk, 2)
 | 
					        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):
 | 
					class BuildOverallocationTest(BuildAPITest):
 | 
				
			||||||
    """Unit tests for over allocation of stock items against a build order.
 | 
					    """Unit tests for over allocation of stock items against a build order.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user