diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 522f09e10a..42c1b84b59 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -574,16 +574,33 @@ class PartScheduling(RetrieveAPI): # Grab a list of BomItem objects that this part might be used in bom_items = BomItem.objects.filter(part.get_used_in_bom_item_filter()) + # Track all outstanding build orders + seen_builds = set() + for bom_item in bom_items: # Find a list of active builds for this BomItem - builds = Build.objects.filter( - status__in=BuildStatus.ACTIVE_CODES, - part=bom_item.part, - ) + if bom_item.inherited: + # An "inherited" BOM item filters down to variant parts also + childs = bom_item.part.get_descendants(include_self=True) + builds = Build.objects.filter( + status__in=BuildStatus.ACTIVE_CODES, + part__in=childs, + ) + else: + builds = Build.objects.filter( + status__in=BuildStatus.ACTIVE_CODES, + part=bom_item.part, + ) for build in builds: + # Ensure we don't double-count any builds + if build in seen_builds: + continue + + seen_builds.add(build) + if bom_item.sub_part.trackable: # Trackable parts are allocated against the outputs required_quantity = build.remaining * bom_item.quantity diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 6048be70e1..ba88979267 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1436,7 +1436,7 @@ class Part(MetadataMixin, MPTTModel): return parts - def get_used_in_bom_item_filter(self, include_inherited=True, include_variants=True, include_substitutes=True): + def get_used_in_bom_item_filter(self, include_variants=True, include_substitutes=True): """Return a BomItem queryset which returns all BomItem instances which refer to *this* part. As the BOM allocation logic is somewhat complicted, there are some considerations: @@ -1454,21 +1454,13 @@ class Part(MetadataMixin, MPTTModel): # Case A: This part is directly specified in a BomItem (we always use this case) query = Q( sub_part=self, - inherited=False, ) - if include_inherited: - query |= Q( - sub_part__in=parents, - inherited=True - ) - if include_variants: # Case B: This part is a *variant* of a part which is specified in a BomItem which allows variants query |= Q( allow_variants=True, sub_part__in=parents, - inherited=False, ) # Case C: This part is a *substitute* of a part which is directly specified in a BomItem