feat: added lots of tests
This commit is contained in:
@@ -9,7 +9,7 @@ urlpatterns = [
|
|||||||
"swagger/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"
|
"swagger/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"
|
||||||
),
|
),
|
||||||
path("redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"),
|
path("redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"),
|
||||||
path("shop/", include("shop.api.v1.routers")),
|
path("shop/", include("shop.api.v1.routers", namespace="shop")),
|
||||||
path("files/", include("files.api.v1.urls")),
|
path("files/", include("files.api.v1.urls", namespace="files")),
|
||||||
path("auth/", include("users.api.v1.urls")),
|
path("auth/", include("users.api.v1.urls", namespace="auth")),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ from rest_framework.routers import DefaultRouter
|
|||||||
|
|
||||||
from files.api.v1.views import FileUploadViewSet
|
from files.api.v1.views import FileUploadViewSet
|
||||||
|
|
||||||
|
|
||||||
|
app_name = "files"
|
||||||
|
|
||||||
|
|
||||||
router = DefaultRouter(trailing_slash=True)
|
router = DefaultRouter(trailing_slash=True)
|
||||||
router.register("", FileUploadViewSet)
|
router.register("", FileUploadViewSet)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
[pytest]
|
[pytest]
|
||||||
DJANGO_SETTINGS_MODULE = config.settings.develop
|
DJANGO_SETTINGS_MODULE = config.settings.base
|
||||||
addopts = --ignore=src
|
addopts = --ignore=src
|
||||||
|
|||||||
@@ -11,13 +11,16 @@ from shop.api.v1.viewsets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
app_name = "shop"
|
||||||
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
|
|
||||||
router.register("taxes", TaxViewSet)
|
router.register("taxes", TaxViewSet)
|
||||||
router.register("customers", CustomerViewSet)
|
router.register("customers", CustomerViewSet)
|
||||||
router.register("providers", ProviderViewSet)
|
router.register("providers", ProviderViewSet)
|
||||||
router.register("products", ProductViewSet)
|
router.register("products", ProductViewSet)
|
||||||
router.register("product-prices", ProductPriceViewSet)
|
router.register("products/(?P<product_id>[^/.]+)/prices", ProductPriceViewSet)
|
||||||
router.register("product-batches", ProductBatchViewSet)
|
router.register("product-batches", ProductBatchViewSet)
|
||||||
router.register("orders", OrderViewSet)
|
router.register("orders", OrderViewSet)
|
||||||
router.register("orders/(?P<order_id>[^/.]+)/lines", OrderLineViewSet)
|
router.register("orders/(?P<order_id>[^/.]+)/lines", OrderLineViewSet)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from django.utils import timezone
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from files.api.v1.serializers import FileUploadSerializer
|
from files.api.v1.serializers import FileUploadSerializer
|
||||||
@@ -17,6 +18,7 @@ class TaxSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Tax
|
model = Tax
|
||||||
fields = (
|
fields = (
|
||||||
|
"id",
|
||||||
"code",
|
"code",
|
||||||
"value",
|
"value",
|
||||||
)
|
)
|
||||||
@@ -35,15 +37,20 @@ class ProductPriceSerializer(serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateProductPriceSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ProductPrice
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"price",
|
||||||
|
"tax",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProductSerializer(serializers.ModelSerializer):
|
class ProductSerializer(serializers.ModelSerializer):
|
||||||
images = FileUploadSerializer(many=True, read_only=True)
|
images = FileUploadSerializer(many=True, read_only=True)
|
||||||
price = ProductPriceSerializer()
|
price = ProductPriceSerializer()
|
||||||
|
|
||||||
def get_price(self, product):
|
|
||||||
last_price = product.prices.last()
|
|
||||||
|
|
||||||
return ProductPriceSerializer(last_price).data
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Product
|
model = Product
|
||||||
fields = (
|
fields = (
|
||||||
@@ -56,10 +63,49 @@ class ProductSerializer(serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateProductSerializer(serializers.ModelSerializer):
|
||||||
|
price = serializers.DecimalField(
|
||||||
|
max_digits=13, decimal_places=4, required=False, write_only=True
|
||||||
|
)
|
||||||
|
tax = serializers.PrimaryKeyRelatedField(
|
||||||
|
queryset=Tax.objects.all(), write_only=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
instance = Product.objects.create(
|
||||||
|
name=validated_data.get("name"),
|
||||||
|
description=validated_data.get("description"),
|
||||||
|
stock=validated_data.get("stock"),
|
||||||
|
is_digital_asset=validated_data.get("is_digital_asset"),
|
||||||
|
url=validated_data.get("url"),
|
||||||
|
)
|
||||||
|
ProductPrice.objects.create(
|
||||||
|
product=instance,
|
||||||
|
date=timezone.now(),
|
||||||
|
price=validated_data.get("price"),
|
||||||
|
tax=validated_data.get("tax"),
|
||||||
|
)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Product
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"stock",
|
||||||
|
"is_digital_asset",
|
||||||
|
"url",
|
||||||
|
"price",
|
||||||
|
"tax",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProductBatchSerializer(serializers.ModelSerializer):
|
class ProductBatchSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProductBatch
|
model = ProductBatch
|
||||||
fields = (
|
fields = (
|
||||||
|
"id",
|
||||||
"code",
|
"code",
|
||||||
"product",
|
"product",
|
||||||
"quantity",
|
"quantity",
|
||||||
@@ -72,6 +118,7 @@ class CustomerSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Customer
|
model = Customer
|
||||||
fields = (
|
fields = (
|
||||||
|
"id",
|
||||||
"vat_id",
|
"vat_id",
|
||||||
"first_name",
|
"first_name",
|
||||||
"last_name",
|
"last_name",
|
||||||
@@ -88,6 +135,7 @@ class ProviderSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = (
|
fields = (
|
||||||
|
"id",
|
||||||
"vat_id",
|
"vat_id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
|||||||
+40
-1
@@ -1,4 +1,9 @@
|
|||||||
|
from django.db.models.deletion import ProtectedError
|
||||||
|
from django.utils.text import gettext_lazy as _
|
||||||
|
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
|
from rest_framework.permissions import IsAdminUser
|
||||||
|
|
||||||
from shop.api.v1.serializers import (
|
from shop.api.v1.serializers import (
|
||||||
ProductSerializer,
|
ProductSerializer,
|
||||||
@@ -9,6 +14,8 @@ from shop.api.v1.serializers import (
|
|||||||
OrderLineSerializer,
|
OrderLineSerializer,
|
||||||
ProviderSerializer,
|
ProviderSerializer,
|
||||||
ProductBatchSerializer,
|
ProductBatchSerializer,
|
||||||
|
CreateProductSerializer,
|
||||||
|
CreateProductPriceSerializer,
|
||||||
)
|
)
|
||||||
from shop.models import (
|
from shop.models import (
|
||||||
Product,
|
Product,
|
||||||
@@ -21,15 +28,47 @@ from shop.models import (
|
|||||||
ProductBatch,
|
ProductBatch,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from shop.api.v1.permissions import ProductPermissions, ProductPricePermissions
|
||||||
|
|
||||||
|
|
||||||
class ProductViewSet(ModelViewSet):
|
class ProductViewSet(ModelViewSet):
|
||||||
serializer_class = ProductSerializer
|
serializer_class = ProductSerializer
|
||||||
queryset = Product.objects.all()
|
queryset = Product.objects.prefetch_related("prices").all()
|
||||||
|
permission_classes = (
|
||||||
|
IsAdminUser,
|
||||||
|
ProductPermissions,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == "create":
|
||||||
|
return CreateProductSerializer
|
||||||
|
return self.serializer_class
|
||||||
|
|
||||||
|
def perform_destroy(self, instance):
|
||||||
|
try:
|
||||||
|
super().perform_destroy(instance)
|
||||||
|
except ProtectedError:
|
||||||
|
raise ValidationError(_("No se puede borrar el producto"))
|
||||||
|
|
||||||
|
|
||||||
class ProductPriceViewSet(ModelViewSet):
|
class ProductPriceViewSet(ModelViewSet):
|
||||||
serializer_class = ProductPriceSerializer
|
serializer_class = ProductPriceSerializer
|
||||||
queryset = ProductPrice.objects.all()
|
queryset = ProductPrice.objects.all()
|
||||||
|
permission_classes = (
|
||||||
|
IsAdminUser,
|
||||||
|
ProductPricePermissions,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return super().get_queryset().filter(product_id=self.kwargs.get("product_id"))
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == "create":
|
||||||
|
return CreateProductPriceSerializer
|
||||||
|
return self.serializer_class
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
serializer.save(product_id=self.kwargs.get("product_id"))
|
||||||
|
|
||||||
|
|
||||||
class ProductBatchViewSet(ModelViewSet):
|
class ProductBatchViewSet(ModelViewSet):
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ class Product(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def price(self):
|
||||||
|
return self.prices.last()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Producto")
|
verbose_name = _("Producto")
|
||||||
verbose_name_plural = _("Productos")
|
verbose_name_plural = _("Productos")
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ from rest_framework_simplejwt.views import (
|
|||||||
token_verify,
|
token_verify,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
app_name = "auth"
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("login/", token_obtain_pair, name="login"),
|
path("login/", token_obtain_pair, name="login"),
|
||||||
path("refresh/", token_refresh, name="refresh_jwt"),
|
path("refresh/", token_refresh, name="refresh_jwt"),
|
||||||
|
|||||||
Reference in New Issue
Block a user