Refactor existing implementations
This commit is contained in:
parent
0d16a17fe3
commit
0943733328
|
|
@ -32,6 +32,7 @@ from InvenTree.helpers import extract_serial_numbers, hash_barcode, normalize, s
|
|||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CustomStatusSerializerMixin,
|
||||
DuplicateOptionsSerializer,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
|
|
@ -67,40 +68,6 @@ class TotalPriceMixin(serializers.Serializer):
|
|||
)
|
||||
|
||||
|
||||
class DuplicateOrderSerializer(serializers.Serializer):
|
||||
"""Serializer for specifying options when duplicating an order."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = ['order_id', 'copy_lines', 'copy_extra_lines', 'copy_parameters']
|
||||
|
||||
order_id = serializers.IntegerField(
|
||||
required=True, label=_('Order ID'), help_text=_('ID of the order to duplicate')
|
||||
)
|
||||
|
||||
copy_lines = serializers.BooleanField(
|
||||
required=False,
|
||||
default=True,
|
||||
label=_('Copy Lines'),
|
||||
help_text=_('Copy line items from the original order'),
|
||||
)
|
||||
|
||||
copy_extra_lines = serializers.BooleanField(
|
||||
required=False,
|
||||
default=True,
|
||||
label=_('Copy Extra Lines'),
|
||||
help_text=_('Copy extra line items from the original order'),
|
||||
)
|
||||
|
||||
copy_parameters = serializers.BooleanField(
|
||||
required=False,
|
||||
default=True,
|
||||
label=_('Copy Parameters'),
|
||||
help_text=_('Copy order parameters from the original order'),
|
||||
)
|
||||
|
||||
|
||||
class AbstractOrderSerializer(
|
||||
CustomStatusSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
|
|
@ -195,12 +162,8 @@ class AbstractOrderSerializer(
|
|||
|
||||
created_by = UserSerializer(read_only=True)
|
||||
|
||||
duplicate = DuplicateOrderSerializer(
|
||||
label=_('Duplicate Order'),
|
||||
help_text=_('Specify options for duplicating this order'),
|
||||
required=False,
|
||||
write_only=True,
|
||||
)
|
||||
# Note: The 'duplicate' field must be defined by each concrete serializer class,
|
||||
# as it requires a queryset specific to the order model type
|
||||
|
||||
def validate_reference(self, reference):
|
||||
"""Custom validation for the reference field."""
|
||||
|
|
@ -293,30 +256,21 @@ class AbstractOrderSerializer(
|
|||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
order_id = duplicate.get('order_id', None)
|
||||
copy_lines = duplicate.get('copy_lines', True)
|
||||
copy_extra_lines = duplicate.get('copy_extra_lines', True)
|
||||
copy_parameters = duplicate.get('copy_parameters', True)
|
||||
original = duplicate['original']
|
||||
|
||||
try:
|
||||
copy_from = instance.__class__.objects.get(pk=order_id)
|
||||
except Exception:
|
||||
# If the order ID is invalid, raise a validation error
|
||||
raise ValidationError(_('Invalid order ID'))
|
||||
|
||||
if copy_lines:
|
||||
for line in copy_from.lines.all():
|
||||
if duplicate.get('copy_lines', False):
|
||||
for line in original.lines.all():
|
||||
instance.clean_line_item(line)
|
||||
line.save()
|
||||
|
||||
if copy_extra_lines:
|
||||
for line in copy_from.extra_lines.all():
|
||||
if duplicate.get('copy_extra_lines', False):
|
||||
for line in original.extra_lines.all():
|
||||
line.pk = None
|
||||
line.order = instance
|
||||
line.save()
|
||||
|
||||
if copy_parameters:
|
||||
instance.copy_parameters_from(copy_from)
|
||||
if duplicate.get('copy_parameters', False):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
|
|
@ -452,6 +406,13 @@ class PurchaseOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.PurchaseOrder.objects.all(),
|
||||
copy_lines=True,
|
||||
copy_extra_lines=True,
|
||||
copy_parameters=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Add extra information to the queryset.
|
||||
|
|
@ -1134,6 +1095,13 @@ class SalesOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.SalesOrder.objects.all(),
|
||||
copy_lines=True,
|
||||
copy_extra_lines=True,
|
||||
copy_parameters=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Add extra information to the queryset.
|
||||
|
|
@ -2198,6 +2166,14 @@ class ReturnOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
# Note: line items cannot be duplicated from a ReturnOrder,
|
||||
# as they are linked to specific stock items
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.ReturnOrder.objects.all(),
|
||||
copy_extra_lines=True,
|
||||
copy_parameters=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Custom annotation for the serializer queryset."""
|
||||
|
|
@ -2485,6 +2461,11 @@ class TransferOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
# Note: TransferOrder does not have "extra" line items
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.TransferOrder.objects.all(), copy_lines=True, copy_parameters=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Add extra information to the queryset.
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ class PurchaseOrderTest(OrderTest):
|
|||
|
||||
# Duplicate with non-existent PK to provoke error
|
||||
data['duplicate'] = {
|
||||
'order_id': 10000001,
|
||||
'original': 10000001,
|
||||
'copy_lines': True,
|
||||
'copy_extra_lines': False,
|
||||
}
|
||||
|
|
@ -584,7 +584,7 @@ class PurchaseOrderTest(OrderTest):
|
|||
response = self.post(reverse('api-po-list'), data, expected_code=400)
|
||||
|
||||
data['duplicate'] = {
|
||||
'order_id': 1,
|
||||
'original': 1,
|
||||
'copy_lines': True,
|
||||
'copy_extra_lines': False,
|
||||
}
|
||||
|
|
@ -605,7 +605,7 @@ class PurchaseOrderTest(OrderTest):
|
|||
data['reference'] = 'PO-9998'
|
||||
|
||||
data['duplicate'] = {
|
||||
'order_id': 1,
|
||||
'original': 1,
|
||||
'copy_lines': False,
|
||||
'copy_extra_lines': True,
|
||||
}
|
||||
|
|
@ -1792,7 +1792,7 @@ class SalesOrderTest(OrderTest):
|
|||
{
|
||||
'reference': 'SO-12345',
|
||||
'customer': so.customer.pk,
|
||||
'duplicate': {'order_id': so.pk, 'copy_parameters': False},
|
||||
'duplicate': {'original': so.pk, 'copy_parameters': False},
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -1809,7 +1809,7 @@ class SalesOrderTest(OrderTest):
|
|||
{
|
||||
'reference': 'SO-12346',
|
||||
'customer': so.customer.pk,
|
||||
'duplicate': {'order_id': so.pk},
|
||||
'duplicate': {'original': so.pk},
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -407,67 +407,6 @@ class PartBriefSerializer(
|
|||
)
|
||||
|
||||
|
||||
class DuplicatePartSerializer(serializers.Serializer):
|
||||
"""Serializer for specifying options when duplicating a Part.
|
||||
|
||||
The fields in this serializer control how the Part is duplicated.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = [
|
||||
'part',
|
||||
'copy_image',
|
||||
'copy_bom',
|
||||
'copy_parameters',
|
||||
'copy_notes',
|
||||
'copy_tests',
|
||||
]
|
||||
|
||||
part = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Part.objects.all(),
|
||||
label=_('Original Part'),
|
||||
help_text=_('Select original part to duplicate'),
|
||||
required=True,
|
||||
)
|
||||
|
||||
copy_image = serializers.BooleanField(
|
||||
label=_('Copy Image'),
|
||||
help_text=_('Copy image from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
copy_bom = serializers.BooleanField(
|
||||
label=_('Copy BOM'),
|
||||
help_text=_('Copy bill of materials from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
copy_parameters = serializers.BooleanField(
|
||||
label=_('Copy Parameters'),
|
||||
help_text=_('Copy parameter data from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
copy_notes = serializers.BooleanField(
|
||||
label=_('Copy Notes'),
|
||||
help_text=_('Copy notes from original part'),
|
||||
required=False,
|
||||
default=True,
|
||||
)
|
||||
|
||||
copy_tests = serializers.BooleanField(
|
||||
label=_('Copy Tests'),
|
||||
help_text=_('Copy test templates from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
||||
class InitialStockSerializer(serializers.Serializer):
|
||||
"""Serializer for creating initial stock quantity."""
|
||||
|
||||
|
|
@ -1007,11 +946,42 @@ class PartSerializer(
|
|||
)
|
||||
|
||||
# Extra fields used only for creation of a new Part instance
|
||||
duplicate = DuplicatePartSerializer(
|
||||
duplicate = InvenTree.serializers.DuplicateOptionsSerializer(
|
||||
Part.objects.all(),
|
||||
label=_('Duplicate Part'),
|
||||
help_text=_('Copy initial data from another Part'),
|
||||
write_only=True,
|
||||
required=False,
|
||||
copy_fields=[
|
||||
{
|
||||
'name': 'copy_image',
|
||||
'label': _('Copy Image'),
|
||||
'help_text': _('Copy image from original part'),
|
||||
'default': False,
|
||||
},
|
||||
{
|
||||
'name': 'copy_bom',
|
||||
'label': _('Copy BOM'),
|
||||
'help_text': _('Copy bill of materials from original part'),
|
||||
'default': False,
|
||||
},
|
||||
{
|
||||
'name': 'copy_parameters',
|
||||
'label': _('Copy Parameters'),
|
||||
'help_text': _('Copy parameter data from original part'),
|
||||
'default': False,
|
||||
},
|
||||
{
|
||||
'name': 'copy_notes',
|
||||
'label': _('Copy Notes'),
|
||||
'help_text': _('Copy notes from original part'),
|
||||
'default': True,
|
||||
},
|
||||
{
|
||||
'name': 'copy_tests',
|
||||
'label': _('Copy Tests'),
|
||||
'help_text': _('Copy test templates from original part'),
|
||||
'default': False,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
initial_stock = InitialStockSerializer(
|
||||
|
|
@ -1077,7 +1047,7 @@ class PartSerializer(
|
|||
|
||||
# Copy data from original Part
|
||||
if duplicate:
|
||||
original = duplicate['part']
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_bom', False):
|
||||
instance.copy_bom_from(original)
|
||||
|
|
|
|||
|
|
@ -1649,7 +1649,7 @@ class PartCreationTests(PartAPITestBase):
|
|||
'testable': do_copy,
|
||||
'assembly': do_copy,
|
||||
'duplicate': {
|
||||
'part': 100,
|
||||
'original': 100,
|
||||
'copy_bom': do_copy,
|
||||
'copy_notes': do_copy,
|
||||
'copy_image': do_copy,
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ export function usePartFields({
|
|||
fields.duplicate = {
|
||||
icon: <IconCopy />,
|
||||
children: {
|
||||
part: {
|
||||
original: {
|
||||
value: duplicatePartInstance?.pk,
|
||||
hidden: true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ export function usePurchaseOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
|
|
|
|||
|
|
@ -84,15 +84,10 @@ export function useReturnOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
copy_lines: {
|
||||
// Cannot duplicate lines from a return order!
|
||||
value: false,
|
||||
hidden: true
|
||||
},
|
||||
copy_extra_lines: {},
|
||||
copy_parameters: {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export function useSalesOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
|
|
|
|||
|
|
@ -54,13 +54,12 @@ export function useTransferOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
copy_lines: {},
|
||||
// Transfer Orders don't have extra lines for now...
|
||||
copy_extra_lines: { hidden: true, value: false }
|
||||
copy_parameters: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue