From bb8b85c3752c4e97668e0e7e0e880415f55a272b Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 23 Aug 2021 21:44:12 +1000 Subject: [PATCH] Separate purchase_price and purchase_price_currency for StockItem serializer - Add "purchase_price_string" for a read-only stringified representation - Unit testing --- InvenTree/stock/fixtures/stock.yaml | 2 + InvenTree/stock/serializers.py | 34 ++++++++++++---- InvenTree/stock/test_api.py | 61 +++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 8 deletions(-) diff --git a/InvenTree/stock/fixtures/stock.yaml b/InvenTree/stock/fixtures/stock.yaml index 00d3920205..25458a28e1 100644 --- a/InvenTree/stock/fixtures/stock.yaml +++ b/InvenTree/stock/fixtures/stock.yaml @@ -12,6 +12,8 @@ tree_id: 0 lft: 0 rght: 0 + purchase_price: 123 + purchase_price_currency: AUD # 5,000 screws in the bathroom - model: stock.stockitem diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index e7ec2fd291..535321ca80 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -4,6 +4,8 @@ JSON serializers for Stock app from rest_framework import serializers +from django.utils.translation import ugettext_lazy as _ + from .models import StockItem, StockLocation from .models import StockItemTracking from .models import StockItemAttachment @@ -22,9 +24,11 @@ from decimal import Decimal from datetime import datetime, timedelta import common.models +from common.settings import currency_code_default, currency_code_mappings + from company.serializers import SupplierPartSerializer from part.serializers import PartBriefSerializer -from InvenTree.serializers import UserSerializerBrief, InvenTreeModelSerializer +from InvenTree.serializers import UserSerializerBrief, InvenTreeModelSerializer, InvenTreeMoneySerializer from InvenTree.serializers import InvenTreeAttachmentSerializer, InvenTreeAttachmentSerializerField @@ -139,17 +143,28 @@ class StockItemSerializer(InvenTreeModelSerializer): required_tests = serializers.IntegerField(source='required_test_count', read_only=True, required=False) - purchase_price = serializers.SerializerMethodField() + purchase_price = InvenTreeMoneySerializer( + label=_('Purchase Price'), + max_digits=19, decimal_places=4, + allow_null=True + ) + + purchase_price_currency = serializers.ChoiceField( + choices=currency_code_mappings(), + default=currency_code_default, + label=_('Currency'), + ) + + purchase_price_string = serializers.SerializerMethodField() + + def get_purchase_price_string(self, obj): + + return str(obj.purchase_price) if obj.purchase_price else '-' purchase_order_reference = serializers.CharField(source='purchase_order.reference', read_only=True) sales_order_reference = serializers.CharField(source='sales_order.reference', read_only=True) - def get_purchase_price(self, obj): - """ Return purchase_price (Money field) as string (includes currency) """ - - return str(obj.purchase_price) if obj.purchase_price else '-' - def __init__(self, *args, **kwargs): part_detail = kwargs.pop('part_detail', False) @@ -208,9 +223,12 @@ class StockItemSerializer(InvenTreeModelSerializer): 'uid', 'updated', 'purchase_price', + 'purchase_price_currency', + 'purchase_price_string', ] - """ These fields are read-only in this context. + """ + These fields are read-only in this context. They can be updated by accessing the appropriate API endpoints """ read_only_fields = [ diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 74f9505c4a..4822eeaeab 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -428,6 +428,67 @@ class StockItemTest(StockAPITestCase): self.assertEqual(response.data['expiry_date'], expiry.isoformat()) + def test_purchase_price(self): + """ + Test that we can correctly read and adjust purchase price information via the API + """ + + url = reverse('api-stock-detail', kwargs={'pk': 1}) + + data = self.get(url, expected_code=200).data + + # Check fixture values + self.assertEqual(data['purchase_price'], '123.0000') + self.assertEqual(data['purchase_price_currency'], 'AUD') + self.assertEqual(data['purchase_price_string'], 'A$123.0000') + + # Update just the amount + data = self.patch( + url, + { + 'purchase_price': 456 + }, + expected_code=200 + ).data + + self.assertEqual(data['purchase_price'], '456.0000') + self.assertEqual(data['purchase_price_currency'], 'AUD') + + # Update the currency + data = self.patch( + url, + { + 'purchase_price_currency': 'NZD', + }, + expected_code=200 + ).data + + self.assertEqual(data['purchase_price_currency'], 'NZD') + + # Clear the price field + data = self.patch( + url, + { + 'purchase_price': None, + }, + expected_code=200 + ).data + + self.assertEqual(data['purchase_price'], None) + self.assertEqual(data['purchase_price_string'], '-') + + # Invalid currency code + data = self.patch( + url, + { + 'purchase_price_currency': 'xyz', + }, + expected_code=400 + ) + + data = self.get(url).data + self.assertEqual(data['purchase_price_currency'], 'NZD') + class StocktakeTest(StockAPITestCase): """