Add duplicate field to more model types
- Company - ManufacturerPart - SupplierPart - SalesOrderShipment
This commit is contained in:
parent
5061e6b935
commit
2c94854253
|
|
@ -7,7 +7,7 @@ INVENTREE_API_VERSION = 514
|
|||
INVENTREE_API_TEXT = """
|
||||
|
||||
v514 -> 2026-07-02 : https://github.com/inventree/InvenTree/pull/12294
|
||||
- Adds "duplicate" field to the BuildOrder API endpoint, allowing duplication options to be specified when creating a new build
|
||||
- Adds "duplicate" field to the BuildOrder, Company, ManufacturerPart, SupplierPart and SalesOrderShipment API endpoints
|
||||
- Order duplication options: renames "order_id" field to "original", which now performs primary-key validation
|
||||
- Part duplication options: renames "part" field to "original"
|
||||
|
||||
|
|
|
|||
|
|
@ -68,9 +68,6 @@ class BuildSerializer(
|
|||
):
|
||||
"""Serializes a Build object."""
|
||||
|
||||
export_exclude_fields = ['duplicate']
|
||||
import_exclude_fields = ['duplicate']
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""JSON serializers for Company app."""
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import Prefetch
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
|
@ -14,6 +15,7 @@ from importer.registry import register_importer
|
|||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.ready import isGeneratingSchema
|
||||
from InvenTree.serializers import (
|
||||
DuplicateOptionsSerializer,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
|
|
@ -118,6 +120,8 @@ class CompanySerializer(
|
|||
|
||||
import_exclude_fields = ['image']
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
|
|
@ -132,6 +136,7 @@ class CompanySerializer(
|
|||
'email',
|
||||
'currency',
|
||||
'contact',
|
||||
'duplicate',
|
||||
'link',
|
||||
'image',
|
||||
'active',
|
||||
|
|
@ -191,6 +196,23 @@ class CompanySerializer(
|
|||
|
||||
parameters = common.filters.enable_parameters_filter()
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(Company.objects.all(), copy_parameters=True)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Create a new Company instance, optionally copying data from an existing company."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
@register_importer()
|
||||
class ContactSerializer(DataImportExportSerializerMixin, InvenTreeModelSerializer):
|
||||
|
|
@ -217,6 +239,8 @@ class ManufacturerPartSerializer(
|
|||
):
|
||||
"""Serializer for ManufacturerPart object."""
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
|
|
@ -229,6 +253,7 @@ class ManufacturerPartSerializer(
|
|||
'manufacturer',
|
||||
'manufacturer_detail',
|
||||
'description',
|
||||
'duplicate',
|
||||
'MPN',
|
||||
'link',
|
||||
'barcode_hash',
|
||||
|
|
@ -241,6 +266,25 @@ class ManufacturerPartSerializer(
|
|||
|
||||
parameters = common.filters.enable_parameters_filter()
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
ManufacturerPart.objects.all(), copy_parameters=True
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Create a new ManufacturerPart instance, optionally copying data from an existing instance."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
part_detail = OptionalField(
|
||||
serializer_class=part_serializers.PartBriefSerializer,
|
||||
serializer_kwargs={
|
||||
|
|
@ -323,6 +367,8 @@ class SupplierPartSerializer(
|
|||
|
||||
export_exclude_fields = ['tags']
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
export_child_fields = [
|
||||
'part_detail.name',
|
||||
'part_detail.description',
|
||||
|
|
@ -339,6 +385,7 @@ class SupplierPartSerializer(
|
|||
'available',
|
||||
'availability_updated',
|
||||
'description',
|
||||
'duplicate',
|
||||
'in_stock',
|
||||
'on_order',
|
||||
'link',
|
||||
|
|
@ -494,6 +541,10 @@ class SupplierPartSerializer(
|
|||
# Date fields
|
||||
updated = serializers.DateTimeField(allow_null=True, read_only=True)
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
SupplierPart.objects.all(), copy_parameters=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Annotate the SupplierPart queryset with extra fields.
|
||||
|
|
@ -522,8 +573,11 @@ class SupplierPartSerializer(
|
|||
|
||||
return response
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Extract manufacturer data and process ManufacturerPart."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
# Extract 'available' quantity from the serializer
|
||||
available = validated_data.pop('available', None)
|
||||
|
||||
|
|
@ -541,6 +595,12 @@ class SupplierPartSerializer(
|
|||
kwargs = {'manufacturer': manufacturer, 'MPN': MPN}
|
||||
supplier_part.save(**kwargs)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
supplier_part.copy_parameters_from(original)
|
||||
|
||||
return supplier_part
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from taggit.serializers import TagListSerializerField
|
|||
import data_exporter.serializers
|
||||
import data_exporter.tasks
|
||||
import InvenTree.exceptions
|
||||
import InvenTree.serializers
|
||||
from common.models import DataOutput
|
||||
from InvenTree.helpers import str2bool
|
||||
from InvenTree.tasks import offload_task
|
||||
|
|
@ -64,6 +65,14 @@ class DataExportSerializerMixin:
|
|||
# Exclude fields which are not required for data export
|
||||
for field in self.get_export_exclude_fields(**kwargs):
|
||||
self.fields.pop(field, None)
|
||||
|
||||
# Duplication options are never used for data export
|
||||
for field in [
|
||||
name
|
||||
for name, field in self.fields.items()
|
||||
if isinstance(field, InvenTree.serializers.DuplicateOptionsSerializer)
|
||||
]:
|
||||
self.fields.pop(field, None)
|
||||
else:
|
||||
# Exclude fields which are only used for data export
|
||||
for field in self.get_export_only_fields(**kwargs):
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
from rest_framework import fields, serializers
|
||||
from taggit.serializers import TagListSerializerField
|
||||
|
||||
import InvenTree.serializers
|
||||
|
||||
|
||||
class DataImportSerializerMixin:
|
||||
"""Mixin class for adding data import functionality to a DRF serializer."""
|
||||
|
|
@ -41,6 +43,14 @@ class DataImportSerializerMixin:
|
|||
for field in self.get_import_exclude_fields(**kwargs):
|
||||
self.fields.pop(field, None)
|
||||
|
||||
# Duplication options are never used for data import
|
||||
for field in [
|
||||
name
|
||||
for name, field in self.fields.items()
|
||||
if isinstance(field, InvenTree.serializers.DuplicateOptionsSerializer)
|
||||
]:
|
||||
self.fields.pop(field, None)
|
||||
|
||||
else:
|
||||
# Exclude fields which are only used for data import
|
||||
for field in self.get_import_only_fields(**kwargs):
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ class AbstractOrderSerializer(
|
|||
):
|
||||
"""Abstract serializer class which provides fields common to all order types."""
|
||||
|
||||
export_exclude_fields = ['notes', 'duplicate']
|
||||
export_exclude_fields = ['notes']
|
||||
|
||||
import_exclude_fields = ['notes', 'duplicate']
|
||||
import_exclude_fields = ['notes']
|
||||
|
||||
# Number of line items in this order
|
||||
line_items = serializers.IntegerField(
|
||||
|
|
@ -1379,6 +1379,8 @@ class SalesOrderShipmentSerializer(
|
|||
):
|
||||
"""Serializer for the SalesOrderShipment class."""
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
|
|
@ -1391,6 +1393,7 @@ class SalesOrderShipmentSerializer(
|
|||
'shipment_address',
|
||||
'delivery_date',
|
||||
'checked_by',
|
||||
'duplicate',
|
||||
'reference',
|
||||
'tracking_number',
|
||||
'invoice_number',
|
||||
|
|
@ -1475,6 +1478,25 @@ class SalesOrderShipmentSerializer(
|
|||
|
||||
tags = common.filters.enable_tags_filter()
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.SalesOrderShipment.objects.all(), copy_parameters=True
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Create a new SalesOrderShipment instance, optionally copying data from an existing shipment."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
class SalesOrderAllocationSerializer(
|
||||
FilterableSerializerMixin, InvenTreeModelSerializer
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ class PartSerializer(
|
|||
Used when displaying all details of a single component.
|
||||
"""
|
||||
|
||||
import_exclude_fields = ['creation_date', 'creation_user', 'duplicate']
|
||||
import_exclude_fields = ['creation_date', 'creation_user']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass defining serializer fields."""
|
||||
|
|
|
|||
Loading…
Reference in New Issue