diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 935a0bed37..ac6e268f78 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -12,11 +12,16 @@ import common.models INVENTREE_SW_VERSION = "0.6.0 dev" # InvenTree API version -INVENTREE_API_VERSION = 17 +INVENTREE_API_VERSION = 18 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v18 -> 2021-11-15 + - Adds the ability to filter BomItem API by "uses" field + - This returns a list of all BomItems which "use" the specified part + - Includes inherited BomItem objects + v17 -> 2021-11-09 - Adds API endpoints for GLOBAL and USER settings objects - Ref: https://github.com/inventree/InvenTree/pull/2275 diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index b08834445c..052adfbec3 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -832,18 +832,6 @@ class PartList(generics.ListCreateAPIView): queryset = super().filter_queryset(queryset) - # Filter by "uses" query - Limit to parts which use the provided part - uses = params.get('uses', None) - - if uses: - try: - uses = Part.objects.get(pk=uses) - - queryset = queryset.filter(uses.get_used_in_filter()) - - except (ValueError, Part.DoesNotExist): - pass - # Exclude specific part ID values? exclude_id = [] @@ -1211,6 +1199,54 @@ class BomList(generics.ListCreateAPIView): except (ValueError, Part.DoesNotExist): pass + """ + Filter by 'uses'? + + Here we pass a part ID and return BOM items for any assemblies which "use" (or "require") that part. + + There are multiple ways that an assembly can "use" a sub-part: + + A) Directly specifying the sub_part in a BomItem field + B) Specifing a "template" part with inherited=True + C) Allowing variant parts to be substituted + D) Allowing direct substitute parts to be specified + + - BOM items which are "inherited" by parts which are variants of the master BomItem + """ + uses = params.get('uses', None) + + if uses is not None: + + try: + # Extract the part we are interested in + uses_part = Part.objects.get(pk=uses) + + # Construct the database query in multiple parts + + # A) Direct specification of sub_part + q_A = Q(sub_part=uses_part) + + # B) BomItem is inherited and points to a "parent" of this part + parents = uses_part.get_ancestors(include_self=False) + + q_B = Q( + inherited=True, + sub_part__in=parents + ) + + # C) Substitution of variant parts + # TODO + + # D) Specification of individual substitutes + # TODO + + q = q_A | q_B + + queryset = queryset.filter(q) + + except (ValueError, Part.DoesNotExist): + pass + if self.include_pricing(): queryset = self.annotate_pricing(queryset)