Coverage for src/backend/InvenTree/report/serializers.py: 88%
65 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
1"""API serializers for the reporting models."""
3from django.utils.translation import gettext_lazy as _
5from rest_framework import serializers
7import plugin.serializers
8import report.helpers
9import report.models
10from InvenTree.serializers import (
11 InvenTreeAttachmentSerializerField,
12 InvenTreeModelSerializer,
13)
14from users.serializers import UserSerializer
17class ReportSerializerBase(InvenTreeModelSerializer):
18 """Base serializer class for report and label templates."""
20 def __init__(self, *args, **kwargs):
21 """Override the constructor for the ReportSerializerBase.
23 The primary goal here is to ensure that the 'choices' attribute
24 is set correctly for the 'model_type' field.
25 """
26 super().__init__(*args, **kwargs)
28 if len(self.fields['model_type'].choices) == 0: 28 ↛ exitline 28 didn't return from function '__init__' because the condition on line 28 was always true
29 self.fields['model_type'].choices = report.helpers.report_model_options()
31 def save(self, **kwargs):
32 """Override the save method to capture the user information."""
33 user = self.context.get('request').user
35 if not user or not user.is_authenticated: 35 ↛ 36line 35 didn't jump to line 36 because the condition on line 35 was never true
36 raise PermissionError(
37 _('User must be authenticated to save report templates')
38 )
40 instance = super().save(**kwargs)
41 instance.updated_by = user
42 instance.save(increment_revision=False)
44 return instance
46 @staticmethod
47 def base_fields():
48 """Base serializer field set."""
49 return [
50 'pk',
51 'name',
52 'description',
53 'model_type',
54 'template',
55 'filters',
56 'filename_pattern',
57 'enabled',
58 'revision',
59 'attach_to_model',
60 'updated',
61 'updated_by',
62 'updated_by_detail',
63 ]
65 template = InvenTreeAttachmentSerializerField(required=True)
67 revision = serializers.IntegerField(read_only=True)
69 # Note: The choices are overridden at run-time
70 model_type = serializers.ChoiceField(
71 label=_('Model Type'),
72 choices=report.helpers.report_model_options(),
73 required=True,
74 allow_blank=False,
75 allow_null=False,
76 )
78 updated_by_detail = UserSerializer(
79 source='updated_by', read_only=True, allow_null=True, many=False
80 )
83class ReportTemplateSerializer(ReportSerializerBase):
84 """Serializer class for report template model."""
86 class Meta:
87 """Metaclass options."""
89 model = report.models.ReportTemplate
90 fields = [
91 *ReportSerializerBase.base_fields(),
92 'page_size',
93 'landscape',
94 'merge',
95 ]
97 page_size = serializers.ChoiceField(
98 required=False,
99 default=report.helpers.report_page_size_default(),
100 choices=report.helpers.report_page_size_options(),
101 )
104class ReportPrintSerializer(serializers.Serializer):
105 """Serializer class for printing a report."""
107 class Meta:
108 """Metaclass options."""
110 fields = ['template', 'items']
112 template = serializers.PrimaryKeyRelatedField(
113 queryset=report.models.ReportTemplate.objects.filter(enabled=True),
114 many=False,
115 required=True,
116 allow_null=False,
117 label=_('Template'),
118 help_text=_('Select report template'),
119 )
121 items = serializers.ListField(
122 child=serializers.IntegerField(),
123 required=True,
124 allow_empty=False,
125 label=_('Items'),
126 help_text=_('List of item primary keys to include in the report'),
127 )
130class LabelPrintSerializer(serializers.Serializer):
131 """Serializer class for printing a label."""
133 # List of extra plugin field names
134 plugin_fields = []
136 class Meta:
137 """Metaclass options."""
139 fields = ['template', 'items', 'plugin']
141 def __init__(self, *args, **kwargs):
142 """Override the constructor to add the extra plugin fields."""
143 # Reset to a known state
144 self.Meta.fields = ['template', 'items', 'plugin']
146 if plugin_serializer := kwargs.pop('plugin_serializer', None): 146 ↛ 147line 146 didn't jump to line 147 because the condition on line 146 was never true
147 for key, field in plugin_serializer.fields.items():
148 self.Meta.fields.append(key)
149 setattr(self, key, field)
151 super().__init__(*args, **kwargs)
153 template = serializers.PrimaryKeyRelatedField(
154 queryset=report.models.LabelTemplate.objects.filter(enabled=True),
155 many=False,
156 required=True,
157 allow_null=False,
158 label=_('Template'),
159 help_text=_('Select label template'),
160 )
162 # Plugin field - note that we use the 'key' (not the pk) for lookup
163 plugin = plugin.serializers.PluginRelationSerializer(
164 many=False,
165 required=False,
166 allow_null=False,
167 label=_('Printing Plugin'),
168 help_text=_('Select plugin to use for label printing'),
169 )
171 items = serializers.ListField(
172 child=serializers.IntegerField(),
173 required=True,
174 allow_empty=False,
175 label=_('Items'),
176 help_text=_('List of item primary keys to include in the report'),
177 )
180class LabelTemplateSerializer(ReportSerializerBase):
181 """Serializer class for label template model."""
183 class Meta:
184 """Metaclass options."""
186 model = report.models.LabelTemplate
187 fields = [*ReportSerializerBase.base_fields(), 'width', 'height']
190class ReportSnippetSerializer(InvenTreeModelSerializer):
191 """Serializer class for the ReportSnippet model."""
193 class Meta:
194 """Metaclass options."""
196 model = report.models.ReportSnippet
198 fields = ['pk', 'snippet', 'description']
200 snippet = InvenTreeAttachmentSerializerField()
203class ReportAssetSerializer(InvenTreeModelSerializer):
204 """Serializer class for the ReportAsset model."""
206 class Meta:
207 """Meta class options."""
209 model = report.models.ReportAsset
210 fields = ['pk', 'asset', 'description']
212 asset = InvenTreeAttachmentSerializerField()