mirror of
https://github.com/inventree/InvenTree.git
synced 2026-03-11 22:54:17 +00:00
Copy order params (#11479)
* Copy parameters when duplicating an order * Add unit test for order parameter duplication * Bunmp API version * Fix test reliability * Disable image fetching for SampleSupplierPlugin - Allow turning on manually - Prevent CI issues due to rate limiting * Revery pypdf.. ???
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
"""InvenTree API version information."""
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 460
|
||||
INVENTREE_API_VERSION = 461
|
||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||
|
||||
INVENTREE_API_TEXT = """
|
||||
|
||||
v461 -> 2026-03-10 : https://github.com/inventree/InvenTree/pull/11479
|
||||
- Adds option to copy parameters when duplicating an order via the API
|
||||
|
||||
v460 -> 2026-02-25 : https://github.com/inventree/InvenTree/pull/11374
|
||||
- Adds "updated_at" field to PurchaseOrder, SalesOrder and ReturnOrder API endpoints
|
||||
- Adds "updated_before" and "updated_after" date filters to all three order list endpoints
|
||||
|
||||
@@ -75,7 +75,7 @@ class DuplicateOrderSerializer(serializers.Serializer):
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = ['order_id', 'copy_lines', 'copy_extra_lines']
|
||||
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')
|
||||
@@ -95,6 +95,13 @@ class DuplicateOrderSerializer(serializers.Serializer):
|
||||
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(
|
||||
DataImportExportSerializerMixin, FilterableSerializerMixin, serializers.Serializer
|
||||
@@ -242,6 +249,7 @@ class AbstractOrderSerializer(
|
||||
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)
|
||||
|
||||
try:
|
||||
copy_from = instance.__class__.objects.get(pk=order_id)
|
||||
@@ -260,6 +268,9 @@ class AbstractOrderSerializer(
|
||||
line.order = instance
|
||||
line.save()
|
||||
|
||||
if copy_parameters:
|
||||
instance.copy_parameters_from(copy_from)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
|
||||
@@ -1574,6 +1574,65 @@ class SalesOrderTest(OrderTest):
|
||||
expected_code=201,
|
||||
)
|
||||
|
||||
def test_so_duplicate(self):
|
||||
"""Test SalesOrder duplication via the API."""
|
||||
from common.models import Parameter, ParameterTemplate
|
||||
|
||||
url = reverse('api-so-list')
|
||||
|
||||
self.assignRole('sales_order.add')
|
||||
|
||||
so = models.SalesOrder.objects.get(pk=1)
|
||||
self.assertEqual(so.status, SalesOrderStatus.PENDING)
|
||||
|
||||
# Add some parameters to the sales order
|
||||
for idx in range(5):
|
||||
template = ParameterTemplate.objects.create(name=f'Template {idx}')
|
||||
|
||||
Parameter.objects.create(
|
||||
template=template,
|
||||
model_type=so.get_content_type(),
|
||||
model_id=so.pk,
|
||||
data=f'Value {idx}',
|
||||
)
|
||||
|
||||
self.assertEqual(so.parameters.count(), 5)
|
||||
|
||||
# Create a duplicate of this sales order
|
||||
# We explicitly specify "copy_parameters" as False, so the duplicated sales order should not have any parameters
|
||||
response = self.post(
|
||||
url,
|
||||
{
|
||||
'reference': 'SO-12345',
|
||||
'customer': so.customer.pk,
|
||||
'duplicate': {'order_id': so.pk, 'copy_parameters': False},
|
||||
},
|
||||
)
|
||||
|
||||
duplicate_id = response.data['pk']
|
||||
duplicate_so = models.SalesOrder.objects.get(pk=duplicate_id)
|
||||
|
||||
self.assertEqual(duplicate_so.reference, 'SO-12345')
|
||||
self.assertEqual(duplicate_so.customer, so.customer)
|
||||
self.assertEqual(duplicate_so.parameters.count(), 0)
|
||||
|
||||
# Duplicate again, with default values for the "duplicate" options (which should result in parameters being copied)
|
||||
response = self.post(
|
||||
url,
|
||||
{
|
||||
'reference': 'SO-12346',
|
||||
'customer': so.customer.pk,
|
||||
'duplicate': {'order_id': so.pk},
|
||||
},
|
||||
)
|
||||
|
||||
duplicate_id = response.data['pk']
|
||||
duplicate_so = models.SalesOrder.objects.get(pk=duplicate_id)
|
||||
|
||||
self.assertEqual(duplicate_so.reference, 'SO-12346')
|
||||
self.assertEqual(duplicate_so.customer, so.customer)
|
||||
self.assertEqual(duplicate_so.parameters.count(), 5)
|
||||
|
||||
def test_so_cancel(self):
|
||||
"""Test API endpoint for cancelling a SalesOrder."""
|
||||
so = models.SalesOrder.objects.get(pk=1)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"""Sample supplier plugin."""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from company.models import Company, ManufacturerPart, SupplierPart, SupplierPriceBreak
|
||||
from part.models import Part
|
||||
from plugin.mixins import SupplierMixin, supplier
|
||||
@@ -13,7 +15,16 @@ class SampleSupplierPlugin(SupplierMixin, InvenTreePlugin):
|
||||
SLUG = 'samplesupplier'
|
||||
TITLE = 'My sample supplier plugin'
|
||||
|
||||
VERSION = '0.0.1'
|
||||
VERSION = '0.0.2'
|
||||
|
||||
SETTINGS = {
|
||||
'DOWNLOAD_IMAGES': {
|
||||
'name': 'Download part images',
|
||||
'description': 'Enable downloading of part images during import (not recommended during testing)',
|
||||
'validator': bool,
|
||||
'default': False,
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the sample supplier plugin."""
|
||||
@@ -108,7 +119,12 @@ class SampleSupplierPlugin(SupplierMixin, InvenTreePlugin):
|
||||
|
||||
# If the part was created, set additional fields
|
||||
if created:
|
||||
if data['image_url']:
|
||||
# Prevent downloading images during testing, as this can lead to unreliable tests
|
||||
if (
|
||||
data['image_url']
|
||||
and not settings.TESTING
|
||||
and self.get_setting('DOWNLOAD_IMAGES')
|
||||
):
|
||||
file, fmt = self.download_image(data['image_url'])
|
||||
filename = f'part_{part.pk}_image.{fmt.lower()}'
|
||||
part.image.save(filename, file)
|
||||
|
||||
@@ -1669,9 +1669,9 @@ pynacl==1.6.2 \
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# paramiko
|
||||
pypdf==6.8.0 \
|
||||
--hash=sha256:2a025080a8dd73f48123c89c57174a5ff3806c71763ee4e49572dc90454943c7 \
|
||||
--hash=sha256:cb7eaeaa4133ce76f762184069a854e03f4d9a08568f0e0623f7ea810407833b
|
||||
pypdf==6.7.5 \
|
||||
--hash=sha256:07ba7f1d6e6d9aa2a17f5452e320a84718d4ce863367f7ede2fd72280349ab13 \
|
||||
--hash=sha256:40bb2e2e872078655f12b9b89e2f900888bb505e88a82150b64f9f34fa25651d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
|
||||
@@ -292,7 +292,8 @@ export function usePurchaseOrderFields({
|
||||
value: duplicateOrderId
|
||||
},
|
||||
copy_lines: {},
|
||||
copy_extra_lines: {}
|
||||
copy_extra_lines: {},
|
||||
copy_parameters: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,7 +91,8 @@ export function useReturnOrderFields({
|
||||
value: false,
|
||||
hidden: true
|
||||
},
|
||||
copy_extra_lines: {}
|
||||
copy_extra_lines: {},
|
||||
copy_parameters: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,7 +90,8 @@ export function useSalesOrderFields({
|
||||
value: duplicateOrderId
|
||||
},
|
||||
copy_lines: {},
|
||||
copy_extra_lines: {}
|
||||
copy_extra_lines: {},
|
||||
copy_parameters: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user