from django.core.validators import MinValueValidator from django.db import models from django.urls import reverse from django.utils.text import slugify class ProductCategory(models.Model): name = models.CharField(max_length=120, unique=True) slug = models.SlugField(max_length=140, unique=True, blank=True) description = models.TextField(blank=True) accent = models.CharField(max_length=20, default="#00D1FF") icon = models.CharField(max_length=40, default="bi-cpu") is_active = models.BooleanField(default=True) sort_order = models.PositiveIntegerField(default=0) class Meta: ordering = ["sort_order", "name"] verbose_name = "categoría de producto" verbose_name_plural = "categorías de productos" def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs) def __str__(self): return self.name class Product(models.Model): category = models.ForeignKey(ProductCategory, on_delete=models.PROTECT, related_name="products") name = models.CharField(max_length=160) slug = models.SlugField(max_length=180, unique=True, blank=True) short_description = models.CharField(max_length=240) description = models.TextField() price_from = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0)]) delivery_time = models.CharField(max_length=80, default="A convenir") is_featured = models.BooleanField(default=False) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["category__sort_order", "name"] verbose_name = "producto/servicio" verbose_name_plural = "productos y servicios" def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs) def get_absolute_url(self): return reverse("product_detail", kwargs={"slug": self.slug}) def __str__(self): return self.name class PaymentConfirmation(models.Model): METHOD_TRANSFERMOVIL = "transfermovil" METHOD_ENZONA = "enzona" METHOD_QR = "qr" METHOD_BANK = "transferencia" PAYMENT_METHODS = [ (METHOD_TRANSFERMOVIL, "Transfermóvil"), (METHOD_ENZONA, "Enzona"), (METHOD_QR, "Código QR"), (METHOD_BANK, "Transferencia bancaria"), ] STATUS_PENDING = "pendiente" STATUS_APPROVED = "aprobado" STATUS_REJECTED = "rechazado" STATUS_CHOICES = [ (STATUS_PENDING, "Pendiente"), (STATUS_APPROVED, "Aprobado"), (STATUS_REJECTED, "Rechazado"), ] product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, blank=True, related_name="payment_confirmations") customer_name = models.CharField(max_length=140) customer_phone = models.CharField(max_length=40) customer_email = models.EmailField(blank=True) amount = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(1)]) method = models.CharField(max_length=30, choices=PAYMENT_METHODS) reference = models.CharField(max_length=120) note = models.TextField(blank=True) receipt = models.FileField(upload_to="payment_receipts/", blank=True) status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_PENDING) admin_note = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) reviewed_at = models.DateTimeField(null=True, blank=True) class Meta: ordering = ["-created_at"] verbose_name = "confirmación de pago" verbose_name_plural = "confirmaciones de pago" def __str__(self): return f"{self.customer_name} · {self.get_method_display()} · {self.amount}"