2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-03-20 03:04:41 +00:00

Refactor part parameter exporter plugin

- Any model which supports parameters can use this now
- Update documentation
This commit is contained in:
Oliver Walters
2025-11-30 02:37:38 +00:00
parent 27fe60722d
commit db468afaa5
7 changed files with 131 additions and 163 deletions

View File

@@ -0,0 +1,98 @@
"""Custom exporter for Parameter data."""
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from plugin import InvenTreePlugin
from plugin.mixins import DataExportMixin
class ParameterExportOptionsSerializer(serializers.Serializer):
"""Custom export options for the ParameterExporter plugin."""
export_exclude_inactive_parameters = serializers.BooleanField(
default=True,
label=_('Exclude Inactive'),
help_text=_('Exclude parameters which are inactive'),
)
class ParameterExporter(DataExportMixin, InvenTreePlugin):
"""Builtin plugin for exporting Parameter data.
Extends the export process, to include all associated Parameter data.
"""
NAME = 'Parameter Exporter'
SLUG = 'parameter-exporter'
TITLE = _('Parameter Exporter')
DESCRIPTION = _('Exporter for model parameter data')
VERSION = '2.0.0'
AUTHOR = _('InvenTree contributors')
ExportOptionsSerializer = ParameterExportOptionsSerializer
def supports_export(
self,
model_class: type,
user=None,
serializer_class=None,
view_class=None,
*args,
**kwargs,
) -> bool:
"""Supported if the base model implements the InvenTreeParameterMixin."""
from InvenTree.models import InvenTreeParameterMixin
return issubclass(model_class, InvenTreeParameterMixin)
def update_headers(self, headers, context, **kwargs):
"""Update headers for the export."""
# Add in a header for each parameter
for pk, name in self.parameters.items():
headers[f'parameter_{pk}'] = str(name)
return headers
def prefetch_queryset(self, queryset):
"""Ensure that the associated parameters are prefetched."""
from InvenTree.models import InvenTreeParameterMixin
queryset = InvenTreeParameterMixin.annotate_parameters(queryset)
return queryset
def export_data(
self, queryset, serializer_class, headers, context, output, **kwargs
):
"""Export parameter data."""
# Extract custom serializer options and cache
queryset = self.prefetch_queryset(queryset)
self.serializer_class = serializer_class
self.exclude_inactive = context.get('export_exclude_inactive_parameters', True)
# Keep a dict of observed parameters against their primary key
self.parameters = {}
# Serialize the queryset using DRF first
rows = self.serializer_class(
queryset, parameters=True, exporting=True, many=True
).data
for row in rows:
# Extract the associated parameters from the serialized data
for parameter in row.get('parameters', []):
template_detail = parameter['template_detail']
template_id = template_detail['pk']
active = template_detail.get('enabled', True)
if not active and self.exclude_inactive:
continue
self.parameters[template_id] = template_detail['name']
row[f'parameter_{template_id}'] = parameter['data']
return rows

View File

@@ -1,132 +0,0 @@
"""Custom exporter for PartParameters."""
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from part.models import Part
from part.serializers import PartSerializer
from plugin import InvenTreePlugin
from plugin.mixins import DataExportMixin
class PartParameterExportOptionsSerializer(serializers.Serializer):
"""Custom export options for the PartParameterExporter plugin."""
export_stock_data = serializers.BooleanField(
default=True, label=_('Stock Data'), help_text=_('Include part stock data')
)
export_pricing_data = serializers.BooleanField(
default=True, label=_('Pricing Data'), help_text=_('Include part pricing data')
)
class PartParameterExporter(DataExportMixin, InvenTreePlugin):
"""Builtin plugin for exporting Part Parameter data.
Extends the "part" export process, to include all associated PartParameter data.
"""
NAME = 'Part Parameter Exporter'
SLUG = 'parameter-exporter'
TITLE = _('Part Parameter Exporter')
DESCRIPTION = _('Exporter for part parameter data')
VERSION = '1.0.0'
AUTHOR = _('InvenTree contributors')
ExportOptionsSerializer = PartParameterExportOptionsSerializer
def supports_export(
self,
model_class: type,
user=None,
serializer_class=None,
view_class=None,
*args,
**kwargs,
) -> bool:
"""Supported if the base model is Part."""
return model_class == Part and serializer_class == PartSerializer
def update_headers(self, headers, context, **kwargs):
"""Update headers for the export."""
if not self.export_stock_data:
# Remove stock data from the headers
for field in [
'allocated_to_build_orders',
'allocated_to_sales_orders',
'available_stock',
'available_substitute_stock',
'available_variant_stock',
'building',
'can_build',
'external_stock',
'in_stock',
'on_order',
'ordering',
'required_for_build_orders',
'required_for_sales_orders',
'stock_item_count',
'total_in_stock',
'unallocated_stock',
'variant_stock',
]:
headers.pop(field, None)
if not self.export_pricing_data:
# Remove pricing data from the headers
for field in [
'pricing_min',
'pricing_max',
'pricing_min_total',
'pricing_max_total',
'pricing_updated',
]:
headers.pop(field, None)
# Add in a header for each part parameter
for pk, name in self.parameters.items():
headers[f'parameter_{pk}'] = str(name)
return headers
def prefetch_queryset(self, queryset):
"""Ensure that the part parameters are prefetched."""
queryset = queryset.prefetch_related(
'parameters_list', 'parameters_list__template'
)
return queryset
def export_data(
self, queryset, serializer_class, headers, context, output, **kwargs
):
"""Export part and parameter data."""
# Extract custom serializer options and cache
self.export_stock_data = context.get('export_stock_data', True)
self.export_pricing_data = context.get('export_pricing_data', True)
queryset = self.prefetch_queryset(queryset)
self.serializer_class = serializer_class
# Keep a dict of observed part parameters against their primary key
self.parameters = {}
# Serialize the queryset using DRF first
parts = self.serializer_class(
queryset, parameters=True, exporting=True, many=True
).data
for part in parts:
# Extract the part parameters from the serialized data
for parameter in part.get('parameters_list', []):
if template := parameter.get('template_detail', None):
template_id = template['pk']
if template_id not in self.parameters:
self.parameters[template_id] = template['name']
part[f'parameter_{template_id}'] = parameter['data']
return parts