feat: added product batches and provider models
This commit is contained in:
@@ -6,6 +6,8 @@ from shop.api.v1.viewsets import (
|
||||
ProductPriceViewSet,
|
||||
OrderViewSet,
|
||||
OrderLineViewSet,
|
||||
ProviderViewSet,
|
||||
ProductBatchViewSet,
|
||||
)
|
||||
|
||||
|
||||
@@ -13,8 +15,10 @@ router = DefaultRouter()
|
||||
|
||||
router.register("taxes", TaxViewSet)
|
||||
router.register("customers", CustomerViewSet)
|
||||
router.register("providers", ProviderViewSet)
|
||||
router.register("products", ProductViewSet)
|
||||
router.register("product-prices", ProductPriceViewSet)
|
||||
router.register("product-batches", ProductBatchViewSet)
|
||||
router.register("orders", OrderViewSet)
|
||||
router.register("orders/(?P<order_id>[^/.]+)/lines", OrderLineViewSet)
|
||||
|
||||
|
||||
+59
-22
@@ -1,28 +1,16 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from files.api.v1.serializers import FileUploadSerializer
|
||||
from shop.models import Product, ProductPrice, Customer, Tax, OrderLine, Order
|
||||
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
images = FileUploadSerializer(many=True, read_only=True)
|
||||
price = serializers.SerializerMethodField()
|
||||
|
||||
def get_price(self, product):
|
||||
last_price = product.prices.last()
|
||||
|
||||
return ProductPriceSerializer(last_price).data
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = (
|
||||
"name",
|
||||
"description",
|
||||
"stock",
|
||||
"is_digital_asset",
|
||||
"images",
|
||||
"price",
|
||||
)
|
||||
from shop.models import (
|
||||
Product,
|
||||
ProductPrice,
|
||||
Customer,
|
||||
Tax,
|
||||
OrderLine,
|
||||
Order,
|
||||
ProductBatch,
|
||||
Provider,
|
||||
)
|
||||
|
||||
|
||||
class TaxSerializer(serializers.ModelSerializer):
|
||||
@@ -47,6 +35,39 @@ class ProductPriceSerializer(serializers.ModelSerializer):
|
||||
)
|
||||
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
images = FileUploadSerializer(many=True, read_only=True)
|
||||
price = ProductPriceSerializer()
|
||||
|
||||
def get_price(self, product):
|
||||
last_price = product.prices.last()
|
||||
|
||||
return ProductPriceSerializer(last_price).data
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = (
|
||||
"name",
|
||||
"description",
|
||||
"stock",
|
||||
"is_digital_asset",
|
||||
"images",
|
||||
"price",
|
||||
)
|
||||
|
||||
|
||||
class ProductBatchSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ProductBatch
|
||||
fields = (
|
||||
"code",
|
||||
"product",
|
||||
"quantity",
|
||||
"creation_date",
|
||||
"expiration_date",
|
||||
)
|
||||
|
||||
|
||||
class CustomerSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Customer
|
||||
@@ -63,6 +84,22 @@ class CustomerSerializer(serializers.ModelSerializer):
|
||||
)
|
||||
|
||||
|
||||
class ProviderSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Provider
|
||||
fields = (
|
||||
"vat_id",
|
||||
"name",
|
||||
"email",
|
||||
"phone",
|
||||
"address",
|
||||
"city",
|
||||
"state",
|
||||
"country",
|
||||
"zip",
|
||||
)
|
||||
|
||||
|
||||
class OrderSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Order
|
||||
|
||||
+22
-1
@@ -7,8 +7,19 @@ from shop.api.v1.serializers import (
|
||||
TaxSerializer,
|
||||
OrderSerializer,
|
||||
OrderLineSerializer,
|
||||
ProviderSerializer,
|
||||
ProductBatchSerializer,
|
||||
)
|
||||
from shop.models import (
|
||||
Product,
|
||||
ProductPrice,
|
||||
Customer,
|
||||
Tax,
|
||||
Order,
|
||||
OrderLine,
|
||||
Provider,
|
||||
ProductBatch,
|
||||
)
|
||||
from shop.models import Product, ProductPrice, Customer, Tax, Order, OrderLine
|
||||
|
||||
|
||||
class ProductViewSet(ModelViewSet):
|
||||
@@ -21,11 +32,21 @@ class ProductPriceViewSet(ModelViewSet):
|
||||
queryset = ProductPrice.objects.all()
|
||||
|
||||
|
||||
class ProductBatchViewSet(ModelViewSet):
|
||||
serializer_class = ProductBatchSerializer
|
||||
queryset = ProductBatch.objects.all()
|
||||
|
||||
|
||||
class CustomerViewSet(ModelViewSet):
|
||||
serializer_class = CustomerSerializer
|
||||
queryset = Customer.objects.all()
|
||||
|
||||
|
||||
class ProviderViewSet(ModelViewSet):
|
||||
serializer_class = ProviderSerializer
|
||||
queryset = Provider.objects.all()
|
||||
|
||||
|
||||
class TaxViewSet(ModelViewSet):
|
||||
serializer_class = TaxSerializer
|
||||
queryset = Tax.objects.all()
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
# Generated by Django 5.0.3 on 2024-05-12 23:18
|
||||
|
||||
import django.db.models.deletion
|
||||
from decimal import Decimal
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("shop", "0002_remove_product_unit_order_status_product_images_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Provider",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"vat_id",
|
||||
models.CharField(
|
||||
max_length=32,
|
||||
unique=True,
|
||||
verbose_name="Documento de identidad",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=64, verbose_name="Nombre")),
|
||||
(
|
||||
"email",
|
||||
models.EmailField(
|
||||
max_length=254, verbose_name="E-mail de contacto"
|
||||
),
|
||||
),
|
||||
(
|
||||
"phone",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
max_length=16,
|
||||
null=True,
|
||||
verbose_name="Teléfono de contacto",
|
||||
),
|
||||
),
|
||||
("address", models.CharField(max_length=255, verbose_name="Dirección")),
|
||||
("city", models.CharField(max_length=64, verbose_name="Ciudad")),
|
||||
("state", models.CharField(max_length=64, verbose_name="Región")),
|
||||
("country", models.CharField(max_length=64, verbose_name="País")),
|
||||
("zip", models.CharField(max_length=32, verbose_name="Código postal")),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Proveedor",
|
||||
"verbose_name_plural": "Proveedores",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ProductBatch",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"code",
|
||||
models.CharField(
|
||||
db_index=True, max_length=32, unique=True, verbose_name="Código"
|
||||
),
|
||||
),
|
||||
(
|
||||
"quantity",
|
||||
models.DecimalField(
|
||||
decimal_places=4,
|
||||
default=Decimal("1"),
|
||||
max_digits=13,
|
||||
verbose_name="Cantidad",
|
||||
),
|
||||
),
|
||||
(
|
||||
"creation_date",
|
||||
models.DateTimeField(
|
||||
auto_now_add=True, verbose_name="Fecha de creación"
|
||||
),
|
||||
),
|
||||
(
|
||||
"expiration_date",
|
||||
models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Fecha de caducidad / consumo preferente",
|
||||
),
|
||||
),
|
||||
(
|
||||
"product",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="shop.product",
|
||||
verbose_name="Producto",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
+57
-1
@@ -60,7 +60,7 @@ class ProductPrice(models.Model):
|
||||
return f"{self.price} - {self.tax.code}"
|
||||
|
||||
@property
|
||||
def price_with_tax(self):
|
||||
def price_with_tax(self) -> Decimal:
|
||||
tax_value = self.price * Decimal(self.tax.value / 100)
|
||||
return round(self.price + tax_value, 2)
|
||||
|
||||
@@ -69,6 +69,30 @@ class ProductPrice(models.Model):
|
||||
verbose_name_plural = _("Precio de producto")
|
||||
|
||||
|
||||
class ProductBatch(models.Model):
|
||||
code = models.CharField(
|
||||
max_length=32, unique=True, db_index=True, verbose_name=_("Código")
|
||||
)
|
||||
product = models.ForeignKey(
|
||||
"shop.Product", on_delete=models.PROTECT, verbose_name=_("Producto")
|
||||
)
|
||||
quantity = models.DecimalField(
|
||||
max_digits=13,
|
||||
decimal_places=4,
|
||||
default=Decimal("1"),
|
||||
verbose_name=_("Cantidad"),
|
||||
)
|
||||
creation_date = models.DateTimeField(
|
||||
auto_now_add=True, verbose_name=_("Fecha de creación")
|
||||
)
|
||||
expiration_date = models.DateField(
|
||||
blank=True, null=True, verbose_name=_("Fecha de caducidad / consumo preferente")
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.code} - {self.product.name} - {self.quantity}"
|
||||
|
||||
|
||||
class Tax(models.Model):
|
||||
code = models.CharField(
|
||||
max_length=8, blank=False, unique=True, verbose_name=_("Código de impuesto")
|
||||
@@ -112,6 +136,38 @@ class Customer(models.Model):
|
||||
verbose_name_plural = _("Clientes")
|
||||
|
||||
|
||||
class Provider(models.Model):
|
||||
vat_id = models.CharField(
|
||||
max_length=32,
|
||||
blank=False,
|
||||
unique=True,
|
||||
verbose_name=_("Documento de identidad"),
|
||||
)
|
||||
name = models.CharField(max_length=64, blank=False, verbose_name=_("Nombre"))
|
||||
|
||||
email = models.EmailField(blank=False, verbose_name=_("E-mail de contacto"))
|
||||
phone = models.CharField(
|
||||
max_length=16,
|
||||
blank=True,
|
||||
null=True,
|
||||
default="",
|
||||
verbose_name=_("Teléfono de contacto"),
|
||||
)
|
||||
|
||||
address = models.CharField(max_length=255, blank=False, verbose_name=_("Dirección"))
|
||||
city = models.CharField(max_length=64, blank=False, verbose_name=_("Ciudad"))
|
||||
state = models.CharField(max_length=64, blank=False, verbose_name=_("Región"))
|
||||
country = models.CharField(max_length=64, blank=False, verbose_name=_("País"))
|
||||
zip = models.CharField(max_length=32, blank=False, verbose_name=_("Código postal"))
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.vat_id} - {self.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Proveedor")
|
||||
verbose_name_plural = _("Proveedores")
|
||||
|
||||
|
||||
class OrderLine(models.Model):
|
||||
order = models.ForeignKey(
|
||||
"shop.Order",
|
||||
|
||||
Reference in New Issue
Block a user