diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index c42f52ec1a..e843422f63 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -584,7 +584,7 @@ class BuildItem(models.Model): errors = {} try: - if self.stock_item.part not in self.build.part.required_parts(): + if self.stock_item.part not in self.build.part.getRequiredParts(recursive=False): errors['stock_item'] = [_("Selected stock item not found in BOM for part '{p}'".format(p=self.build.part.full_name))] if self.quantity > self.stock_item.quantity: diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index 70905b1b4f..ff1befcfc3 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -493,7 +493,7 @@ class BuildItemDelete(AjaxDeleteView): class BuildItemCreate(AjaxCreateView): """ - View for allocating a StockItems to a build output. + View for allocating a StockItems to a build output. """ model = BuildItem @@ -591,13 +591,20 @@ class BuildItemCreate(AjaxCreateView): pass # Exclude StockItem objects which are already allocated to this build and part - stock_filter = stock_filter.exclude(id__in=[item.stock_item.id for item in BuildItem.objects.filter(build=build_id, stock_item__part=part_id)]) + stock_filter = stock_filter.exclude( + id__in=[ + item.stock_item.id for item in BuildItem.objects.filter(build=build_id, stock_item__part=part_id) + ] + ) except Part.DoesNotExist: self.part = None pass - form.fields['stock_item'].query = stock_filter + else: + self.part = None + + form.fields['stock_item'].queryset = stock_filter self.available_stock = stock_filter.all() @@ -708,13 +715,12 @@ class BuildItemEdit(AjaxUpdateView): } def get_form(self): - """ Create form for editing a BuildItem. + """ + Create form for editing a BuildItem. - Limit the StockItem options to items that match the part """ - build_item = self.get_object() - form = super(BuildItemEdit, self).get_form() # Hide fields which we do not wish the user to edit diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index b289b3e0ad..ddf612da92 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -931,13 +931,26 @@ class Part(MPTTModel): self.bom_items.all().delete() - def required_parts(self): - """ Return a list of parts required to make this part (list of BOM items) """ - parts = [] + def getRequiredParts(self, recursive=False, parts=set()): + """ + Return a list of parts required to make this part (i.e. BOM items). + + Args: + recursive: If True iterate down through sub-assemblies + parts: Set of parts already found (to prevent recursion issues) + """ + + for bom_item in self.bom_items.all().select_related('sub_part'): + + sub_part = bom_item.sub_part + + if sub_part not in parts: + + parts.add(sub_part) + + if recursive: + sub_part.getRequiredParts(recursive=True, parts=parts) - for bom in self.bom_items.all().select_related('sub_part'): - parts.append(bom.sub_part) - return parts def get_allowed_bom_items(self): diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index a1ce33df51..c7ad280d8e 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -2127,7 +2127,7 @@ class BomItemCreate(AjaxCreateView): query = query.filter(active=True) # Eliminate any options that are already in the BOM! - query = query.exclude(id__in=[item.id for item in part.required_parts()]) + query = query.exclude(id__in=[item.id for item in part.getRequiredParts()]) form.fields['sub_part'].queryset = query @@ -2195,7 +2195,7 @@ class BomItemEdit(AjaxUpdateView): except ValueError: sub_part_id = -1 - existing = [item.pk for item in part.required_parts()] + existing = [item.pk for item in part.getRequiredParts()] if sub_part_id in existing: existing.remove(sub_part_id)