2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-12-14 16:29:57 +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

@@ -21,7 +21,7 @@ The following builtin plugins are available in InvenTree:
| Barcodes | [TME](./barcode_tme.md) | TME barcode support | No |
| Data Export | [BOM Exporter](./bom_exporter.md) | Custom [exporter](../mixins/export.md) for BOM data | Yes |
| Data Export | [InvenTree Exporter](./inventree_exporter.md) | Custom [exporter](../mixins/export.md) for InvenTree data | Yes |
| Data Export | [Parameter Exporter](./part_parameter_exporter.md) | Custom [exporter](../mixins/export.md) for part parameter data | Yes |
| Data Export | [Parameter Exporter](./parameter_exporter.md) | Custom [exporter](../mixins/export.md) for parameter data | Yes |
| Data Export | [Stocktake Exporter](./stocktake_exporter.md) | Custom [exporter](../mixins/export.md) for stocktake data | No |
| Events | [Auto Create Child Builds](./auto_create_builds.md) | Automatically create child build orders for sub-assemblies | No |
| Events | [Auto Issue Orders](./auto_issue.md) | Automatically issue pending orders when target date is reached | No |

View File

@@ -0,0 +1,27 @@
---
title: Parameter Exporter
---
## Parameter Exporter
The **Parameter Exporter** plugin provides custom export functionality for models which support custom [Parameter](../../concepts/parameters.md) data.
It utilizes the [ExporterMixin](../mixins/export.md) mixin to provide a custom export format for part parameter data.
In addition to the standard exported fields, this plugin also exports all associated parameter data for each row of the export.
### Activation
This plugin is a *mandatory* plugin, and is always enabled.
### Plugin Settings
This plugin has no configurable settings.
## Usage
This plugin is used in the same way as the [InvenTree Exporter Plugin](./inventree_exporter.md), but provides a custom export format for part parameter data.
When exporting parameter data, the *Parameter Exporter* plugin is available for selection in the export dialog. When selected, the plugin provides some additional export options to control the data export process.
{{ image("parameter_export_options.png", base="plugin/builtin", title="Parameter Export Options") }}

View File

@@ -1,25 +0,0 @@
---
title: Part Parameter Exporter
---
## Part Parameter Exporter
The **Part Parameter Exporter** plugin provides custom export functionality for [Parameter](../../concepts/parameters.md) data.
It utilizes the [ExporterMixin](../mixins/export.md) mixin to provide a custom export format for part parameter data.
### Activation
This plugin is a *mandatory* plugin, and is always enabled.
### Plugin Settings
This plugin has no configurable settings.
## Usage
This plugin is used in the same way as the [InvenTree Exporter Plugin](./inventree_exporter.md), but provides a custom export format for part parameter data.
When exporting part parameter data, the *Part Parameter Exporter* plugin is available for selection in the export dialog. When selected, the plugin provides some additional export options to control the data export process.
{{ image("parameter_export_options.png", base="plugin/builtin", title="Part Parameter Export Options") }}

View File

@@ -545,11 +545,11 @@ You can add asset images to the reports and labels by using the `{% raw %}{% ass
{% endraw %}
```
## Part Parameters
## Parameters
If you need to load a part parameter for a particular Part, within the context of your template, you can use the `part_parameter` template tag:
If you need to load a parameter value for a particular model instance, within the context of your template, you can use the `parameter` template tag:
::: report.templatetags.report.part_parameter
::: report.templatetags.report.parameter
options:
show_docstring_description: false
show_source: False
@@ -562,7 +562,7 @@ The following example assumes that you have a report or label which contains a v
{% raw %}
{% load report %}
{% part_parameter part "length" as length %}
{% parameter part "length" as length %}
Part: {{ part.name }}<br>
Length: {{ length.data }} [{{ length.units }}]

View File

@@ -239,7 +239,7 @@ nav:
- Export Plugins:
- BOM Exporter: plugins/builtin/bom_exporter.md
- InvenTree Exporter: plugins/builtin/inventree_exporter.md
- Parameter Exporter: plugins/builtin/part_parameter_exporter.md
- Parameter Exporter: plugins/builtin/parameter_exporter.md
- Stocktake Exporter: plugins/builtin/stocktake_exporter.md
- Label Printing:
- Label Printer: plugins/builtin/inventree_label.md

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