mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 21:25:42 +00:00 
			
		
		
		
	[PUI] Part allocations (#8458)
* Add new backend filters for BuildLine API * PUI: Better display of part allocations against build orders * Add 'order_outstanding' filter to SalesOrderLineItem API * Add new table showing outstanding SalesOrder allocations against a part * Update playwright test * Cleanup * Bump API version * Add more table columns * Tweak UsedInTable * Another table tweak * Tweak playwright tests
This commit is contained in:
		| @@ -1,13 +1,17 @@ | ||||
| """InvenTree API version information.""" | ||||
|  | ||||
| # InvenTree API version | ||||
| INVENTREE_API_VERSION = 278 | ||||
| INVENTREE_API_VERSION = 279 | ||||
|  | ||||
| """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" | ||||
|  | ||||
|  | ||||
| INVENTREE_API_TEXT = """ | ||||
|  | ||||
| v279 - 2024-11-09 : https://github.com/inventree/InvenTree/pull/8458 | ||||
|     - Adds "order_outstanding" and "part" filters to the BuildLine API endpoint | ||||
|     - Adds "order_outstanding" filter to the SalesOrderLineItem API endpoint | ||||
|  | ||||
| v278 - 2024-11-07 : https://github.com/inventree/InvenTree/pull/8445 | ||||
|     - Updates to the SalesOrder API endpoints | ||||
|     - Add "shipment count" information to the SalesOrder API endpoints | ||||
|   | ||||
| @@ -357,6 +357,23 @@ class BuildLineFilter(rest_filters.FilterSet): | ||||
|     tracked = rest_filters.BooleanFilter(label=_('Tracked'), field_name='bom_item__sub_part__trackable') | ||||
|     testable = rest_filters.BooleanFilter(label=_('Testable'), field_name='bom_item__sub_part__testable') | ||||
|  | ||||
|     part = rest_filters.ModelChoiceFilter( | ||||
|         queryset=part.models.Part.objects.all(), | ||||
|         label=_('Part'), | ||||
|         field_name='bom_item__sub_part', | ||||
|     ) | ||||
|  | ||||
|     order_outstanding = rest_filters.BooleanFilter( | ||||
|         label=_('Order Outstanding'), | ||||
|         method='filter_order_outstanding' | ||||
|     ) | ||||
|  | ||||
|     def filter_order_outstanding(self, queryset, name, value): | ||||
|         """Filter by whether the associated BuildOrder is 'outstanding'.""" | ||||
|         if str2bool(value): | ||||
|             return queryset.filter(build__status__in=BuildStatusGroups.ACTIVE_CODES) | ||||
|         return queryset.exclude(build__status__in=BuildStatusGroups.ACTIVE_CODES) | ||||
|  | ||||
|     allocated = rest_filters.BooleanFilter(label=_('Allocated'), method='filter_allocated') | ||||
|  | ||||
|     def filter_allocated(self, queryset, name, value): | ||||
| @@ -383,12 +400,28 @@ class BuildLineFilter(rest_filters.FilterSet): | ||||
|         return queryset.exclude(flt) | ||||
|  | ||||
|  | ||||
|  | ||||
| class BuildLineEndpoint: | ||||
|     """Mixin class for BuildLine API endpoints.""" | ||||
|  | ||||
|     queryset = BuildLine.objects.all() | ||||
|     serializer_class = build.serializers.BuildLineSerializer | ||||
|  | ||||
|     def get_serializer(self, *args, **kwargs): | ||||
|         """Return the serializer instance for this endpoint.""" | ||||
|  | ||||
|         kwargs['context'] = self.get_serializer_context() | ||||
|  | ||||
|         try: | ||||
|             params = self.request.query_params | ||||
|  | ||||
|             kwargs['part_detail'] = str2bool(params.get('part_detail', True)) | ||||
|             kwargs['build_detail'] = str2bool(params.get('build_detail', False)) | ||||
|         except AttributeError: | ||||
|             pass | ||||
|  | ||||
|         return self.serializer_class(*args, **kwargs) | ||||
|  | ||||
|     def get_source_build(self) -> Build: | ||||
|         """Return the source Build object for the BuildLine queryset. | ||||
|  | ||||
|   | ||||
| @@ -1278,8 +1278,6 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali | ||||
|             'pk', | ||||
|             'build', | ||||
|             'bom_item', | ||||
|             'bom_item_detail', | ||||
|             'part_detail', | ||||
|             'quantity', | ||||
|  | ||||
|             # Build detail fields | ||||
| @@ -1315,6 +1313,11 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali | ||||
|             # Extra fields only for data export | ||||
|             'part_description', | ||||
|             'part_category_name', | ||||
|  | ||||
|             # Extra detail (related field) serializers | ||||
|             'bom_item_detail', | ||||
|             'part_detail', | ||||
|             'build_detail', | ||||
|         ] | ||||
|  | ||||
|         read_only_fields = [ | ||||
| @@ -1323,6 +1326,19 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali | ||||
|             'allocations', | ||||
|         ] | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         """Determine which extra details fields should be included""" | ||||
|         part_detail = kwargs.pop('part_detail', True) | ||||
|         build_detail = kwargs.pop('build_detail', False) | ||||
|  | ||||
|         super().__init__(*args, **kwargs) | ||||
|  | ||||
|         if not part_detail: | ||||
|             self.fields.pop('part_detail', None) | ||||
|  | ||||
|         if not build_detail: | ||||
|             self.fields.pop('build_detail', None) | ||||
|  | ||||
|     # Build info fields | ||||
|     build_reference = serializers.CharField(source='build.reference', label=_('Build Reference'), read_only=True) | ||||
|  | ||||
| @@ -1362,6 +1378,7 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali | ||||
|     ) | ||||
|  | ||||
|     part_detail = part_serializers.PartBriefSerializer(source='bom_item.sub_part', many=False, read_only=True, pricing=False) | ||||
|     build_detail = BuildSerializer(source='build', part_detail=False, many=False, read_only=True) | ||||
|  | ||||
|     # Annotated (calculated) fields | ||||
|  | ||||
| @@ -1404,9 +1421,13 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali | ||||
|         """ | ||||
|         queryset = queryset.select_related( | ||||
|             'build', | ||||
|             'build__part', | ||||
|             'build__part__pricing_data', | ||||
|             'bom_item', | ||||
|             'bom_item__part', | ||||
|             'bom_item__part__pricing_data', | ||||
|             'bom_item__sub_part', | ||||
|             'bom_item__sub_part__pricing_data' | ||||
|         ) | ||||
|  | ||||
|         # Pre-fetch related fields | ||||
|   | ||||
| @@ -816,6 +816,17 @@ class SalesOrderLineItemFilter(LineItemFilter): | ||||
|  | ||||
|         return queryset.exclude(order__status__in=SalesOrderStatusGroups.COMPLETE) | ||||
|  | ||||
|     order_outstanding = rest_filters.BooleanFilter( | ||||
|         label=_('Order Outstanding'), method='filter_order_outstanding' | ||||
|     ) | ||||
|  | ||||
|     def filter_order_outstanding(self, queryset, name, value): | ||||
|         """Filter by whether the order is 'outstanding' or not.""" | ||||
|         if str2bool(value): | ||||
|             return queryset.filter(order__status__in=SalesOrderStatusGroups.OPEN) | ||||
|  | ||||
|         return queryset.exclude(order__status__in=SalesOrderStatusGroups.OPEN) | ||||
|  | ||||
|  | ||||
| class SalesOrderLineItemMixin: | ||||
|     """Mixin class for SalesOrderLineItem endpoints.""" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user