from decimal import Decimal from uuid import uuid4 from django.db import models from django.utils import timezone from django.utils.text import gettext_lazy as _ class Product(models.Model): name = models.CharField( max_length=96, blank=False, null=False, verbose_name=_("Nombre"), ) description = models.CharField( max_length=1000, blank=True, default="", verbose_name=_("Descripción"), ) stock = models.DecimalField( max_digits=13, decimal_places=4, default=Decimal("0"), verbose_name=_("Stock"), ) is_digital_asset = models.BooleanField(default=False) url = models.URLField(blank=True, verbose_name=_('URL de descarga')) def __str__(self): return self.name class Meta: verbose_name = _("Producto") verbose_name_plural = _("Productos") class ProductPrice(models.Model): price = models.DecimalField( max_digits=11, decimal_places=2, verbose_name=_("Precio") ) date = models.DateTimeField(default=timezone.now, verbose_name=_("Fecha")) product = models.ForeignKey( "shop.Product", on_delete=models.CASCADE, verbose_name=_("Producto"), related_name="prices", ) tax = models.ForeignKey( "shop.Tax", on_delete=models.PROTECT, verbose_name=_("Impuesto aplicable"), ) def __str__(self): return f"{self.price} - {self.tax.code}" @property def price_with_tax(self): tax_value = self.price * (self.tax.value / 100) return round(self.price + tax_value, 2) class Meta: verbose_name = _("Precio de producto") verbose_name_plural = _("Precio de producto") class Tax(models.Model): code = models.CharField( max_length=8, blank=False, unique=True, verbose_name=_("Código de impuesto") ) value = models.PositiveIntegerField( null=False, blank=False, verbose_name=_("Valor entero (porcentaje)") ) def __str__(self): return f"{self.code} - {self.value}%" class Meta: verbose_name = _("Impuesto") verbose_name_plural = _("Impuestos") class Customer(models.Model): vat_id = models.CharField( max_length=32, blank=False, unique=True, verbose_name=_("Documento de identidad"), ) first_name = models.CharField(max_length=64, blank=False, verbose_name=_("Nombre")) last_name = models.CharField( max_length=64, blank=False, verbose_name=_("Apellidos") ) email = models.EmailField(blank=False, verbose_name=_("E-mail")) 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.first_name} {self.last_name}" class Meta: verbose_name = _("Cliente") verbose_name_plural = _("Clientes") 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, null=False, blank=False, verbose_name=_("Producto"), ) quantity = models.DecimalField( max_digits=13, decimal_places=4, default=Decimal("1"), null=False, blank=False, verbose_name=_("Cantidad"), ) # Precio del producto en el momento en el que se crea el pedido price = models.DecimalField( max_digits=13, decimal_places=4, verbose_name=_("Precio") ) # base_total = quantity * price base_total = models.DecimalField( max_digits=13, decimal_places=4, default=Decimal("0"), null=False, blank=False, verbose_name=_("Total sin impuestos"), ) # Valor entero del impuesto en el momento en el que se crea el pedido tax_value = models.PositiveIntegerField( null=False, blank=False, verbose_name=_("Valor de impuestos") ) # taxes = price * quantity * (tax_value / 100) taxes = models.DecimalField( max_digits=13, decimal_places=4, verbose_name=_("Impuestos") ) # total = base_total + taxes total = models.DecimalField( max_digits=13, decimal_places=4, verbose_name=_("Total") ) def __str__(self): return f"{self.product.name} - {self.quantity} - {self.price}" class Meta: verbose_name = _("Línea de pedido") verbose_name_plural = _("Líneas de pedido") class Order(models.Model): class Statuses(models.TextChoices): STATUS_PENDING = "PEN", _("Pendiente de pago") STATUS_PAID = "PAI", _("Pagado") STATUS_READY = "RDY", _("Preparado") STATUS_TO_BE_SENT = "TBS", _("Listo para ser enviado") STATUS_SENT = "SNT", _("Enviado") STATUS_DELIVERED = "DLV", _("Entregado") STATUS_FINISHED = "FIN", _("Finalizado") STATUS_CANCELED = "CAN", _("Cancelado") STATUS_RETURNED = "RTN", _("Devuelto") uuid = models.UUIDField(default=uuid4, verbose_name=_("UUID"), db_index=True) status = models.CharField( max_length=3, default=Statuses.STATUS_PENDING, verbose_name=_("Estado") ) creation_date = models.DateTimeField( auto_now_add=True, verbose_name=_("Fecha de creación") ) last_modification_date = models.DateTimeField( auto_now=True, verbose_name=_("Fecha de última modificación") ) base_total = models.DecimalField( default=Decimal("0"), max_digits=13, decimal_places=2, verbose_name=_("Base imponible"), ) total = models.DecimalField( default=Decimal("0"), max_digits=13, decimal_places=2, verbose_name=_("Total") ) # Customer reference customer = models.ForeignKey( "shop.Customer", on_delete=models.PROTECT, verbose_name=_("Cliente") ) # Billing information billing_address = models.CharField( max_length=255, blank=False, verbose_name=_("Dirección de facturación") ) billing_city = models.CharField( max_length=64, blank=False, verbose_name=_("Ciudad de facturación") ) billing_state = models.CharField( max_length=64, blank=False, verbose_name=_("Región de facturación") ) billing_country = models.CharField( max_length=64, blank=False, verbose_name=_("País de facturación") ) billing_zip = models.CharField( max_length=32, blank=False, verbose_name=_("Código postal de facturación") ) # Shipping information shipping_address = models.CharField( max_length=255, blank=False, verbose_name=_("Dirección") ) shipping_city = models.CharField( max_length=64, blank=False, verbose_name=_("Ciudad") ) shipping_state = models.CharField( max_length=64, blank=False, verbose_name=_("Región") ) shipping_country = models.CharField( max_length=64, blank=False, verbose_name=_("País") ) shipping_zip = models.CharField( max_length=32, blank=False, verbose_name=_("Código postal") ) contact_phone = models.CharField( max_length=32, blank=True, verbose_name=_("Teléfono de contacto") ) def calculate_total_from_lines(self): self.base_total = self.lines.aggregate(base_total=models.Sum("base_total")).get( "base_total" ) self.total = self.lines.aggregate(base_total=models.Sum("total")).get( "base_total" ) self.save() class Meta: verbose_name = _("Pedido") verbose_name_plural = _("Pedidos")