Spaces:
Sleeping
Sleeping
| from django.db import models | |
| from django.db.models.signals import post_save, post_delete | |
| from django.dispatch import receiver | |
| from Accounts.models import Profile | |
| from Boxes.models import MysteryBox | |
| from django.utils.crypto import get_random_string | |
| from django.utils.timezone import now | |
| class Cart(models.Model): | |
| user = models.OneToOneField(Profile, on_delete=models.CASCADE, related_name="cart") | |
| created_at = models.DateTimeField(auto_now_add=True) | |
| def __str__(self): | |
| return f"Cart of {self.user.user.email}" | |
| def total_amount(self): | |
| return sum(item.subtotal for item in self.items.all()) | |
| class CartItem(models.Model): | |
| cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name="items") | |
| box = models.ForeignKey(MysteryBox, on_delete=models.CASCADE) | |
| quantity = models.PositiveIntegerField(default=1) | |
| def __str__(self): | |
| return f"{self.quantity} × {self.box.title}" | |
| def subtotal(self): | |
| return (self.box.price or 0) * (self.quantity or 0) | |
| class Order(models.Model): | |
| STATUS_CHOICES = [ | |
| ("pending", "Pending"), | |
| ("paid", "Paid"), | |
| ("shipped", "Shipped"), | |
| ("delivered", "Delivered"), | |
| ("cancelled", "Cancelled"), | |
| ] | |
| user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="orders") | |
| order_number = models.CharField(max_length=50, unique=True, editable=False) | |
| total_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00) | |
| status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending") | |
| created_at = models.DateTimeField(auto_now_add=True) | |
| def __str__(self): | |
| return f"Order {self.order_number} ({self.user.user.email})" | |
| def save(self, *args, **kwargs): | |
| # Auto-generate order number if missing | |
| if not self.order_number: | |
| self.order_number = f"ORD{now().strftime('%Y%m%d')}{get_random_string(5).upper()}" | |
| super().save(*args, **kwargs) | |
| class OrderItem(models.Model): | |
| order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="items") | |
| box = models.ForeignKey(MysteryBox, on_delete=models.CASCADE) | |
| quantity = models.PositiveIntegerField(default=1) | |
| unit_price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00) | |
| def __str__(self): | |
| return f"{self.quantity} × {self.box.title}" | |
| def subtotal(self): | |
| return (self.unit_price or 0) * (self.quantity or 0) | |
| class Payment(models.Model): | |
| METHOD_CHOICES = [ | |
| ("stripe", "Stripe"), | |
| ("paypal", "PayPal"), | |
| ("razorpay", "Razorpay"), | |
| ("cod", "Cash on Delivery"), | |
| ] | |
| STATUS_CHOICES = [ | |
| ("pending", "Pending"), | |
| ("successful", "Successful"), | |
| ("failed", "Failed"), | |
| ] | |
| order = models.OneToOneField(Order, on_delete=models.CASCADE, related_name="payment") | |
| payment_method = models.CharField(max_length=20, choices=METHOD_CHOICES, default="cod") | |
| transaction_id = models.CharField(max_length=150, blank=True, null=True) | |
| status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending") | |
| paid_at = models.DateTimeField(blank=True, null=True) | |
| def __str__(self): | |
| return f"Payment {self.status} - {self.order.order_number}" | |
| # 🔹 Signals to auto-update Order total when OrderItems change | |
| def update_order_total(sender, instance, **kwargs): | |
| order = instance.order | |
| order.total_amount = sum(item.subtotal for item in order.items.all()) | |
| order.save(update_fields=["total_amount"]) | |