Fix export of order data (#4714)

* Adds extra unit test for exporting sales orders

- Exporting sales orders to .xls currently throws exception

* Fix 'total_price' field when exporting orders

* Fix for unit test
This commit is contained in:
Oliver 2023-04-28 06:54:50 +10:00 committed by GitHub
parent f6021c4749
commit f6831558a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 11 deletions

View File

@ -265,8 +265,7 @@ class InvenTreeAPITestCase(ExchangeRateMixin, UserMixin, APITestCase):
"""Download a file from the server, and return an in-memory file.""" """Download a file from the server, and return an in-memory file."""
response = self.client.get(url, data=data, format='json') response = self.client.get(url, data=data, format='json')
if expected_code is not None: self.checkResponse(url, 'DOWNLOAD_FILE', expected_code, response)
self.assertEqual(response.status_code, expected_code)
# Check that the response is of the correct type # Check that the response is of the correct type
if not isinstance(response, StreamingHttpResponse): if not isinstance(response, StreamingHttpResponse):

View File

@ -24,6 +24,32 @@ class ProjectCodeResourceMixin:
return '' return ''
class TotalPriceResourceMixin:
"""Mixin for exporting total price data"""
total_price = Field(attribute='total_price', column_name=_('Total Price'))
def dehydrate_total_price(self, order):
"""Return the total price amount, not the object itself"""
if order.total_price:
return order.total_price.amount
else:
return ''
class PriceResourceMixin:
"""Mixin for 'price' field"""
price = Field(attribute='price', column_name=_('Price'))
def dehydrate_price(self, line):
"""Return the price amount, not the object itself"""
if line.price:
return line.price.amount
else:
return ''
# region general classes # region general classes
class GeneralExtraLineAdmin: class GeneralExtraLineAdmin:
"""Admin class template for the 'ExtraLineItem' models""" """Admin class template for the 'ExtraLineItem' models"""
@ -108,7 +134,7 @@ class SalesOrderAdmin(ImportExportModelAdmin):
autocomplete_fields = ('customer',) autocomplete_fields = ('customer',)
class PurchaseOrderResource(ProjectCodeResourceMixin, InvenTreeResource): class PurchaseOrderResource(ProjectCodeResourceMixin, TotalPriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of PurchaseOrder data.""" """Class for managing import / export of PurchaseOrder data."""
class Meta: class Meta:
@ -127,7 +153,7 @@ class PurchaseOrderResource(ProjectCodeResourceMixin, InvenTreeResource):
overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True) overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True)
class PurchaseOrderLineItemResource(InvenTreeResource): class PurchaseOrderLineItemResource(PriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of PurchaseOrderLineItem data.""" """Class for managing import / export of PurchaseOrderLineItem data."""
class Meta: class Meta:
@ -146,7 +172,7 @@ class PurchaseOrderLineItemResource(InvenTreeResource):
SKU = Field(attribute='part__SKU', readonly=True) SKU = Field(attribute='part__SKU', readonly=True)
class PurchaseOrderExtraLineResource(InvenTreeResource): class PurchaseOrderExtraLineResource(PriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of PurchaseOrderExtraLine data.""" """Class for managing import / export of PurchaseOrderExtraLine data."""
class Meta(GeneralExtraLineMeta): class Meta(GeneralExtraLineMeta):
@ -155,7 +181,7 @@ class PurchaseOrderExtraLineResource(InvenTreeResource):
model = models.PurchaseOrderExtraLine model = models.PurchaseOrderExtraLine
class SalesOrderResource(ProjectCodeResourceMixin, InvenTreeResource): class SalesOrderResource(ProjectCodeResourceMixin, TotalPriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of SalesOrder data.""" """Class for managing import / export of SalesOrder data."""
class Meta: class Meta:
@ -174,7 +200,7 @@ class SalesOrderResource(ProjectCodeResourceMixin, InvenTreeResource):
overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True) overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True)
class SalesOrderLineItemResource(InvenTreeResource): class SalesOrderLineItemResource(PriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of SalesOrderLineItem data.""" """Class for managing import / export of SalesOrderLineItem data."""
class Meta: class Meta:
@ -203,7 +229,7 @@ class SalesOrderLineItemResource(InvenTreeResource):
return '' return ''
class SalesOrderExtraLineResource(InvenTreeResource): class SalesOrderExtraLineResource(PriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of SalesOrderExtraLine data.""" """Class for managing import / export of SalesOrderExtraLine data."""
class Meta(GeneralExtraLineMeta): class Meta(GeneralExtraLineMeta):
@ -290,7 +316,7 @@ class SalesOrderAllocationAdmin(ImportExportModelAdmin):
autocomplete_fields = ('line', 'shipment', 'item',) autocomplete_fields = ('line', 'shipment', 'item',)
class ReturnOrderResource(ProjectCodeResourceMixin, InvenTreeResource): class ReturnOrderResource(ProjectCodeResourceMixin, TotalPriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of ReturnOrder data""" """Class for managing import / export of ReturnOrder data"""
class Meta: class Meta:
@ -327,7 +353,7 @@ class ReturnOrderAdmin(ImportExportModelAdmin):
] ]
class ReturnOrderLineItemResource(InvenTreeResource): class ReturnOrderLineItemResource(PriceResourceMixin, InvenTreeResource):
"""Class for managing import / export of ReturnOrderLineItem data""" """Class for managing import / export of ReturnOrderLineItem data"""
class Meta: class Meta:
@ -350,7 +376,7 @@ class ReturnOrderLineItemAdmin(ImportExportModelAdmin):
] ]
class ReturnOrderExtraLineClass(InvenTreeResource): class ReturnOrderExtraLineClass(PriceResourceMixin, InvenTreeResource):
"""Class for managing import/export of ReturnOrderExtraLine data""" """Class for managing import/export of ReturnOrderExtraLine data"""
class Meta(GeneralExtraLineMeta): class Meta(GeneralExtraLineMeta):

View File

@ -1452,6 +1452,28 @@ class SalesOrderTest(OrderTest):
self.assertGreaterEqual(n_events, 1) self.assertGreaterEqual(n_events, 1)
self.assertEqual(number_orders_incl_complete, n_events) self.assertEqual(number_orders_incl_complete, n_events)
def test_export(self):
"""Test we can export the SalesOrder list"""
n = models.SalesOrder.objects.count()
# Check there are some sales orders
self.assertGreater(n, 0)
for order in models.SalesOrder.objects.all():
# Reconstruct the total price
order.save()
# Download file, check we get a 200 response
for fmt in ['csv', 'xls', 'xlsx']:
self.download_file(
reverse('api-so-list'),
{'export': fmt},
decode=True if fmt == 'csv' else False,
expected_code=200,
expected_fn=f"InvenTree_SalesOrders.{fmt}"
)
class SalesOrderLineItemTest(OrderTest): class SalesOrderLineItemTest(OrderTest):
"""Tests for the SalesOrderLineItem API.""" """Tests for the SalesOrderLineItem API."""