From d8fa4dd5e197690416f90d467810029a070784d9 Mon Sep 17 00:00:00 2001 From: Pablo Moreno Date: Mon, 13 May 2024 13:23:01 +0200 Subject: [PATCH] feat: added tests for orders creation --- shop/api/v1/serializers.py | 2 +- shop/api/v1/viewsets.py | 39 +++++- shop/tests/test_api_orders.py | 183 +++++++++++++++++++++++++ shop/tests/test_api_product_batches.py | 2 +- shop/tests/test_api_product_prices.py | 3 +- 5 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 shop/tests/test_api_orders.py diff --git a/shop/api/v1/serializers.py b/shop/api/v1/serializers.py index ab75fec..eb69e06 100644 --- a/shop/api/v1/serializers.py +++ b/shop/api/v1/serializers.py @@ -181,9 +181,9 @@ class OrderLineSerializer(serializers.ModelSerializer): class Meta: model = OrderLine fields = ( + "id", "product", "quantity", - "order", "price", "base_total", "total", diff --git a/shop/api/v1/viewsets.py b/shop/api/v1/viewsets.py index 8cfdb7c..31b5804 100644 --- a/shop/api/v1/viewsets.py +++ b/shop/api/v1/viewsets.py @@ -1,5 +1,9 @@ +from decimal import Decimal + from django.db.models.deletion import ProtectedError from django.utils.text import gettext_lazy as _ +from django.shortcuts import get_object_or_404 +from django.db import transaction from rest_framework.viewsets import ModelViewSet from rest_framework.exceptions import ValidationError @@ -101,5 +105,38 @@ class OrderLineViewSet(ModelViewSet): serializer_class = OrderLineSerializer queryset = OrderLine.objects.all() + def perform_create(self, serializer): + with transaction.atomic(): + order = get_object_or_404(Order, uuid=self.kwargs.get('order_id')) + product = serializer.validated_data.get('product') + price = product.prices.last() + tax = price.tax.value + quantity = serializer.validated_data.get('quantity') + base_total = quantity * price.price + taxes = base_total * (tax / Decimal('100')) + total = base_total + taxes + + instance = serializer.save( + order=order, + price=price.price, + base_total=base_total, + tax_value=tax, + taxes=taxes, + total=total, + ) + + order.base_total += instance.base_total + order.total += instance.total + order.save() + + def perform_destroy(self, instance): + order = instance.order + + with transaction.atomic(): + order.base_total -= instance.base_total + order.total -= instance.total + instance.delete() + order.save() + def get_queryset(self): - return super().get_queryset().filter(order_id=self.kwargs.get("order_id")) + return super().get_queryset().select_related('order').filter(order__uuid=self.kwargs.get("order_id")) diff --git a/shop/tests/test_api_orders.py b/shop/tests/test_api_orders.py new file mode 100644 index 0000000..7bd525b --- /dev/null +++ b/shop/tests/test_api_orders.py @@ -0,0 +1,183 @@ +from decimal import Decimal + +from rest_framework import status +from rest_framework.test import APITestCase + +from config.tests.mixins import TestUserAuthenticationMixin +from shop.models import Product, ProductPrice, Tax, Customer + + +class TestOrdersAPI(APITestCase, TestUserAuthenticationMixin): + model_name = "productprice" + + def setUp(self): + self.create_user() + self.tax = Tax.objects.create( + code="IVA", + value=21, + ) + self.customer = Customer.objects.create( + vat_id="11111111H", + first_name="Darth", + last_name="Maull", + email="darth@maul.com", + address="Dathomir", + city="Dathomir", + state="Dathomir", + country="Dathomir", + zip="00001", + ) + self.create_products() + + def create_products(self): + self.product = Product.objects.create( + name="Papafritas", + description="Las mejores papafritas", + is_digital_asset=False, + url="", + ) + + ProductPrice.objects.create( + product=self.product, + price=Decimal("1.20"), + tax=self.tax, + ) + + def test_create_retrieve_order(self): + self.login() + + response = self.client.post( + f"/api/v1/shop/orders/", + { + "customer": self.customer.pk, + "billing_address": self.customer.address, + "billing_city": self.customer.city, + "billing_state": self.customer.state, + "billing_country": self.customer.country, + "billing_zip": self.customer.zip, + "shipping_address": self.customer.address, + "shipping_city": self.customer.city, + "shipping_state": self.customer.state, + "shipping_country": self.customer.country, + "shipping_zip": self.customer.zip, + "contact_phone": "612345678", + } + ) + + assert response.status_code == status.HTTP_201_CREATED + pk = response.data.get('uuid') + + response = self.client.get(f"/api/v1/shop/orders/{pk}/") + assert response.status_code == status.HTTP_200_OK + + def test_create_retrieve_order_with_lines(self): + self.login() + + response = self.client.post( + f"/api/v1/shop/orders/", + { + "customer": self.customer.pk, + "billing_address": self.customer.address, + "billing_city": self.customer.city, + "billing_state": self.customer.state, + "billing_country": self.customer.country, + "billing_zip": self.customer.zip, + "shipping_address": self.customer.address, + "shipping_city": self.customer.city, + "shipping_state": self.customer.state, + "shipping_country": self.customer.country, + "shipping_zip": self.customer.zip, + "contact_phone": "612345678", + } + ) + + assert response.status_code == status.HTTP_201_CREATED + pk = response.data.get('uuid') + + response = self.client.get(f"/api/v1/shop/orders/{pk}/") + assert response.status_code == status.HTTP_200_OK + assert Decimal(response.data.get('base_total')) == Decimal('0.00') + assert Decimal(response.data.get('total')) == Decimal('0.00') + + response = self.client.post( + f"/api/v1/shop/orders/{pk}/lines/", + { + "product": self.product.pk, + "quantity": "5", + } + ) + + assert response.status_code == status.HTTP_201_CREATED + response = self.client.get(f"/api/v1/shop/orders/{pk}/lines/") + assert len(response.data.get('results')) == 1 + + response = self.client.get(f"/api/v1/shop/orders/{pk}/") + assert response.status_code == status.HTTP_200_OK + + assert Decimal(response.data.get('base_total')) == Decimal('6.00') + assert Decimal(response.data.get('total')) == Decimal('6.00') + (Decimal('6.00') * Decimal('0.21')) + + def test_create_delete_order_with_lines(self): + self.login() + + # Create order + response = self.client.post( + f"/api/v1/shop/orders/", + { + "customer": self.customer.pk, + "billing_address": self.customer.address, + "billing_city": self.customer.city, + "billing_state": self.customer.state, + "billing_country": self.customer.country, + "billing_zip": self.customer.zip, + "shipping_address": self.customer.address, + "shipping_city": self.customer.city, + "shipping_state": self.customer.state, + "shipping_country": self.customer.country, + "shipping_zip": self.customer.zip, + "contact_phone": "612345678", + } + ) + + assert response.status_code == status.HTTP_201_CREATED + pk = response.data.get('uuid') + + response = self.client.get(f"/api/v1/shop/orders/{pk}/") + assert response.status_code == status.HTTP_200_OK + + # Assert order is created with 0.00€ + assert Decimal(response.data.get('base_total')) == Decimal('0.00') + assert Decimal(response.data.get('total')) == Decimal('0.00') + + # Create order line + response = self.client.post( + f"/api/v1/shop/orders/{pk}/lines/", + { + "product": self.product.pk, + "quantity": "5", + } + ) + + line_pk = response.data.get('id') + + assert response.status_code == status.HTTP_201_CREATED + response = self.client.get(f"/api/v1/shop/orders/{pk}/lines/") + assert len(response.data.get('results')) == 1 + + response = self.client.get(f"/api/v1/shop/orders/{pk}/") + assert response.status_code == status.HTTP_200_OK + + # Assert order totals are set + assert Decimal(response.data.get('base_total')) == Decimal('6.00') + assert Decimal(response.data.get('total')) == Decimal('6.00') + (Decimal('6.00') * Decimal('0.21')) + + # Delete line + response = self.client.delete(f"/api/v1/shop/orders/{pk}/lines/{line_pk}/") + assert response.status_code == status.HTTP_204_NO_CONTENT + + response = self.client.get(f"/api/v1/shop/orders/{pk}/") + assert response.status_code == status.HTTP_200_OK + + # Assert order totals are 0.00 + assert Decimal(response.data.get('base_total')) == Decimal('0.00') + assert Decimal(response.data.get('total')) == Decimal('0.00') diff --git a/shop/tests/test_api_product_batches.py b/shop/tests/test_api_product_batches.py index 9d34c4b..11cb160 100644 --- a/shop/tests/test_api_product_batches.py +++ b/shop/tests/test_api_product_batches.py @@ -4,7 +4,7 @@ from rest_framework import status from rest_framework.test import APITestCase from config.tests.mixins import TestUserAuthenticationMixin -from shop.models import Product, ProductBatch +from shop.models import Product class TestProductBatchesAPI(APITestCase, TestUserAuthenticationMixin): diff --git a/shop/tests/test_api_product_prices.py b/shop/tests/test_api_product_prices.py index f33598e..2f0d92c 100644 --- a/shop/tests/test_api_product_prices.py +++ b/shop/tests/test_api_product_prices.py @@ -2,10 +2,9 @@ from decimal import Decimal from rest_framework import status from rest_framework.test import APITestCase -from django.utils import timezone from config.tests.mixins import TestUserAuthenticationMixin -from shop.models import Product, ProductPrice, Tax, ProductBatch +from shop.models import Product, ProductPrice, Tax class TestProductPricessAPI(APITestCase, TestUserAuthenticationMixin):