feat: added creation endpoints

This commit is contained in:
2024-03-25 00:23:03 +01:00
parent 6b04fe7e23
commit 43338ceeec
16 changed files with 287 additions and 97 deletions
+1
View File
@@ -9,4 +9,5 @@ urlpatterns = [
"swagger/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"
),
path("redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"),
path("shop/", include("shop.api.v1.routers")),
]
+10 -1
View File
@@ -1,5 +1,5 @@
from django.contrib import admin
from shop.models import Product, ProductPrice, OrderLine, Order, Tax
from shop.models import Product, ProductPrice, OrderLine, Order, Tax, Customer
from unfold.admin import ModelAdmin
@@ -35,6 +35,15 @@ class TaxAdmin(ModelAdmin):
)
@admin.register(Customer)
class CustomerAdmin(ModelAdmin):
list_display = (
"vat_id",
"first_name",
"last_name",
)
@admin.register(OrderLine)
class OrderLineAdmin(ModelAdmin):
autocomplete_fields = ("product",)
View File
View File
+22
View File
@@ -0,0 +1,22 @@
from rest_framework.routers import DefaultRouter
from shop.api.v1.viewsets import (
TaxViewSet,
CustomerViewSet,
ProductViewSet,
ProductPriceViewSet,
OrderViewSet,
OrderLineViewSet,
)
router = DefaultRouter()
router.register("taxes", TaxViewSet)
router.register("customers", CustomerViewSet)
router.register("product", ProductViewSet)
router.register("product-prices", ProductPriceViewSet)
router.register("orders", OrderViewSet)
router.register("orders/(?P<order_id>[^/.]+)/lines", OrderLineViewSet)
urlpatterns = router.urls
+99
View File
@@ -0,0 +1,99 @@
from rest_framework import serializers
from shop.models import Product, ProductPrice, Customer, Tax, OrderLine, Order
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = (
"name",
"description",
"stock",
"unit",
)
class ProductPriceSerializer(serializers.ModelSerializer):
class Meta:
model = ProductPrice
fields = (
"price",
"date",
"product",
)
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = (
"vat_id",
"first_name",
"last_name",
"email",
"address",
"city",
"state",
"country",
"zip",
)
class TaxSerializer(serializers.ModelSerializer):
class Meta:
model = Tax
fields = (
"code",
"value",
)
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = (
"uuid",
"creation_date",
"last_modification_date",
"base_total",
"total",
"customer",
"billing_address",
"billing_city",
"billing_state",
"billing_country",
"billing_zip",
"shipping_address",
"shipping_city",
"shipping_state",
"shipping_country",
"shipping_zip",
"contact_phone",
)
read_only_fields = (
"uuid",
"base_total",
"total",
)
class OrderLineSerializer(serializers.ModelSerializer):
class Meta:
model = OrderLine
fields = (
"product",
"quantity",
"order",
"price",
"base_total",
"total",
"taxes",
"tax_value",
)
read_only_fields = (
"price",
"base_total",
"total",
"taxes",
"tax_value",
)
+45
View File
@@ -0,0 +1,45 @@
from rest_framework.viewsets import ModelViewSet
from shop.api.v1.serializers import (
ProductSerializer,
ProductPriceSerializer,
CustomerSerializer,
TaxSerializer,
OrderSerializer,
OrderLineSerializer,
)
from shop.models import Product, ProductPrice, Customer, Tax, Order, OrderLine
class ProductViewSet(ModelViewSet):
serializer_class = ProductSerializer
queryset = Product.objects.all()
class ProductPriceViewSet(ModelViewSet):
serializer_class = ProductPriceSerializer
queryset = ProductPrice.objects.all()
class CustomerViewSet(ModelViewSet):
serializer_class = CustomerSerializer
queryset = Customer.objects.all()
class TaxViewSet(ModelViewSet):
serializer_class = TaxSerializer
queryset = Tax.objects.all()
class OrderViewSet(ModelViewSet):
serializer_class = OrderSerializer
queryset = Order.objects.all()
lookup_field = "uuid"
class OrderLineViewSet(ModelViewSet):
serializer_class = OrderLineSerializer
queryset = OrderLine.objects.all()
def get_queryset(self):
return super().get_queryset().filter(order_id=self.kwargs.get("order_id"))
+73 -67
View File
@@ -1,7 +1,8 @@
# Generated by Django 5.0.3 on 2024-03-24 18:23
# Generated by Django 5.0.3 on 2024-03-24 22:50
import django.db.models.deletion
import django.utils.timezone
import uuid
from decimal import Decimal
from django.db import migrations, models
@@ -50,64 +51,6 @@ class Migration(migrations.Migration):
"verbose_name_plural": "Clientes",
},
),
migrations.CreateModel(
name="OrderLine",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"quantity",
models.DecimalField(
decimal_places=4,
default=Decimal("1"),
max_digits=13,
verbose_name="Cantidad",
),
),
(
"price",
models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Precio"
),
),
(
"base_total",
models.DecimalField(
decimal_places=4,
default=Decimal("0"),
max_digits=13,
verbose_name="Total sin impuestos",
),
),
(
"tax_value",
models.PositiveIntegerField(verbose_name="Valor de impuestos"),
),
(
"taxes",
models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Impuestos"
),
),
(
"total",
models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Total"
),
),
],
options={
"verbose_name": "Línea de pedido",
"verbose_name_plural": "Líneas de pedido",
},
),
migrations.CreateModel(
name="Product",
fields=[
@@ -196,6 +139,7 @@ class Migration(migrations.Migration):
verbose_name="ID",
),
),
("uuid", models.UUIDField(default=uuid.uuid4, verbose_name="UUID")),
(
"creation_date",
models.DateTimeField(
@@ -288,25 +232,87 @@ class Migration(migrations.Migration):
verbose_name="Cliente",
),
),
(
"lines",
models.ManyToManyField(to="shop.orderline", verbose_name="Líneas"),
),
],
options={
"verbose_name": "Pedido",
"verbose_name_plural": "Pedidos",
},
),
migrations.AddField(
model_name="orderline",
name="product",
field=models.ForeignKey(
migrations.CreateModel(
name="OrderLine",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"quantity",
models.DecimalField(
decimal_places=4,
default=Decimal("1"),
max_digits=13,
verbose_name="Cantidad",
),
),
(
"price",
models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Precio"
),
),
(
"base_total",
models.DecimalField(
decimal_places=4,
default=Decimal("0"),
max_digits=13,
verbose_name="Total sin impuestos",
),
),
(
"tax_value",
models.PositiveIntegerField(verbose_name="Valor de impuestos"),
),
(
"taxes",
models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Impuestos"
),
),
(
"total",
models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Total"
),
),
(
"order",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="lines",
to="shop.order",
verbose_name="Pedido",
),
),
(
"product",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="shop.product",
verbose_name="Producto",
),
),
],
options={
"verbose_name": "Línea de pedido",
"verbose_name_plural": "Líneas de pedido",
},
),
migrations.CreateModel(
name="ProductPrice",
fields=[
+8 -1
View File
@@ -1,4 +1,5 @@
from decimal import Decimal
from uuid import uuid4
from django.db import models
from django.utils import timezone
@@ -108,6 +109,12 @@ class Customer(models.Model):
class OrderLine(models.Model):
order = models.ForeignKey(
"shop.Order",
on_delete=models.CASCADE,
related_name="lines",
verbose_name=_("Pedido"),
)
product = models.ForeignKey(
"shop.Product",
on_delete=models.CASCADE,
@@ -163,7 +170,7 @@ class OrderLine(models.Model):
class Order(models.Model):
lines = models.ManyToManyField("shop.OrderLine", verbose_name=_("Líneas"))
uuid = models.UUIDField(default=uuid4, verbose_name=_("UUID"), db_index=True)
creation_date = models.DateTimeField(
auto_now_add=True, verbose_name=_("Fecha de creación")
)
+21 -18
View File
@@ -1,6 +1,6 @@
from decimal import Decimal
from rest_framework.test import APITestCase as TestCase
from shop.models import Product, ProductPrice, OrderLine, Tax, Customer
from shop.models import Product, ProductPrice, Tax, Customer
from shop.utils import create_order_line_for_product, create_order
@@ -45,25 +45,8 @@ class ShopModelsTest(TestCase):
country="Tatooine",
)
l1 = create_order_line_for_product(
self.potatoes,
quantity=Decimal("1.5"),
tax=self.tax,
)
l2 = create_order_line_for_product(
self.gasoline,
quantity=Decimal("40"),
tax=self.tax,
)
l3 = create_order_line_for_product(
self.usb_c,
quantity=Decimal("1.00"),
tax=self.tax,
)
order = create_order(
customer=self.customer,
lines=OrderLine.objects.all(),
billing_address=self.customer.address,
billing_city=self.customer.city,
billing_state=self.customer.state,
@@ -71,5 +54,25 @@ class ShopModelsTest(TestCase):
billing_country=self.customer.country,
)
l1 = create_order_line_for_product(
self.potatoes,
quantity=Decimal("1.5"),
tax=self.tax,
order=order,
)
l2 = create_order_line_for_product(
self.gasoline,
quantity=Decimal("40"),
tax=self.tax,
order=order,
)
l3 = create_order_line_for_product(
self.usb_c,
quantity=Decimal("1.00"),
tax=self.tax,
order=order,
)
order.calculate_total_from_lines()
assert order.total == l1.total + l2.total + l3.total
assert order.base_total == l1.base_total + l2.base_total + l3.base_total
+4 -6
View File
@@ -5,12 +5,15 @@ from shop.models import OrderLine, Tax, Product, Order, Customer
from django.db.models import QuerySet
def create_order_line_for_product(product: Product, quantity: Decimal, tax: Tax):
def create_order_line_for_product(
product: Product, quantity: Decimal, tax: Tax, order: Order
):
price = product.prices.last().price
base_total = round(price * quantity, 2)
taxes = round(base_total * (tax.value / Decimal("100")), 2)
return OrderLine.objects.create(
order=order,
product=product,
quantity=quantity,
price=price,
@@ -23,7 +26,6 @@ def create_order_line_for_product(product: Product, quantity: Decimal, tax: Tax)
def create_order(
customer: Customer,
lines: Iterable,
billing_address: str,
billing_city: str,
billing_state: str,
@@ -61,8 +63,4 @@ def create_order(
shipping_zip=shipping_zip,
)
for line in lines:
order.lines.add(line)
order.calculate_total_from_lines()
return order
View File
View File
View File
View File
View File