update cart logic
This commit is contained in:
+111
-67
@@ -6,9 +6,11 @@ from django_jalali.db import models as jmodels
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class DiscountCode(models.Model):
|
||||
code = models.CharField(max_length=50, verbose_name='کد تخفیف')
|
||||
percent = models.DecimalField(max_digits=4, decimal_places=2, verbose_name='درصد')
|
||||
percent = models.DecimalField(
|
||||
max_digits=4, decimal_places=2, verbose_name='درصد')
|
||||
quantity = models.PositiveIntegerField(verbose_name='تعداد')
|
||||
expiration_date = models.DateTimeField(verbose_name='تاریخ انقضا')
|
||||
|
||||
@@ -33,11 +35,96 @@ class DiscountCode(models.Model):
|
||||
print('log later bug')
|
||||
|
||||
|
||||
class Cart(models.Model):
|
||||
user = models.OneToOneField(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='carts'
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
address = models.ForeignKey(UserAddressModel, on_delete=models.SET_NULL,
|
||||
related_name='carts', null=True, verbose_name='ادرس')
|
||||
discount_code = models.ForeignKey(
|
||||
DiscountCode, on_delete=models.PROTECT, null=True, blank=True, verbose_name="کدتخفیف")
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'سبد خرید'
|
||||
verbose_name_plural = 'سبد های خرید'
|
||||
|
||||
def __str__(self):
|
||||
return f"Cart for {self.user.email}"
|
||||
|
||||
@property
|
||||
def discount_code_amount(self):
|
||||
if self.discount_code:
|
||||
return int(int(self.cart_total - self.items_discount_amount) * (self.discount_code.percent / 100))
|
||||
else:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def items_discount_amount(self):
|
||||
return int(sum(item.item_discount_amount for item in self.items.all()))
|
||||
|
||||
@property
|
||||
def total_before_tax(self):
|
||||
return self.cart_total - (self.discount_code_amount + self.items_discount_amount)
|
||||
|
||||
@property
|
||||
def tax_amount(self):
|
||||
return int(self.total_before_tax * settings.DEFAULT_TAX_RATE / 100)
|
||||
|
||||
@property
|
||||
def cart_total(self):
|
||||
return sum(item.price_before_discount for item in self.items.all())
|
||||
|
||||
@property
|
||||
def final_price(self):
|
||||
return self.total_before_tax + self.tax_amount
|
||||
|
||||
|
||||
class CartItem(models.Model):
|
||||
cart = models.ForeignKey(
|
||||
Cart,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='items'
|
||||
)
|
||||
product_variant = models.ForeignKey(
|
||||
ProductVariant,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='cart_items'
|
||||
)
|
||||
quantity = models.PositiveIntegerField(default=1)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'ایتم سبد خرید'
|
||||
verbose_name_plural = 'ایتم های سبد خرید'
|
||||
unique_together = ('cart', 'product_variant')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.quantity} x {self.product_variant.product.name} in cart {self.cart.id}"
|
||||
|
||||
@property
|
||||
def price_before_discount(self):
|
||||
return self.quantity * self.product_variant.price_before_discount
|
||||
|
||||
@property
|
||||
def item_discount_amount(self):
|
||||
return self.product_variant.discount_amount * self.quantity
|
||||
|
||||
@property
|
||||
def price_after_discount(self):
|
||||
return self.price_before_discount - self.item_discount_amount
|
||||
|
||||
@property
|
||||
def discount(self):
|
||||
return self.product_variant.discount
|
||||
|
||||
class OrderModel(models.Model):
|
||||
objects = jmodels.jManager()
|
||||
STATUS_CHOICES = [
|
||||
('CART', 'در سبد خرید'),
|
||||
('ADMIN_PENDING', 'در انتظار تایید'),
|
||||
('PENDING', 'درحال پردازش'),
|
||||
('POSTED', 'ارسال شده'),
|
||||
@@ -45,17 +132,25 @@ class OrderModel(models.Model):
|
||||
('CANCELED', 'لغو شده'),
|
||||
('REFUNDED', 'مرجوع شده'),
|
||||
]
|
||||
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='orders', verbose_name='کاربر')
|
||||
address = models.ForeignKey(UserAddressModel, on_delete=models.SET_NULL, related_name='orders', null=True, verbose_name='ادرس')
|
||||
created_at = jmodels.jDateField(blank=True, null=True, verbose_name="تاریخ ثبت سفارش")
|
||||
user = models.ForeignKey(User, on_delete=models.SET_NULL,
|
||||
null=True, related_name='orders', verbose_name='کاربر')
|
||||
address = models.ForeignKey(UserAddressModel, on_delete=models.SET_NULL,
|
||||
related_name='orders', null=True, verbose_name='ادرس')
|
||||
created_at = jmodels.jDateField(
|
||||
blank=True, null=True, verbose_name="تاریخ ثبت سفارش")
|
||||
is_paid = models.BooleanField(default=False, verbose_name="وضعیت پرداخت")
|
||||
discount_code = models.ForeignKey(DiscountCode, on_delete=models.PROTECT, null=True, blank=True, verbose_name="کدتخفیف")
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='CART', verbose_name="وضعیت سفارش")
|
||||
discount_amount = models.BigIntegerField(null=True, blank=True, verbose_name='مقدار کد تخفیف')
|
||||
discount_code = models.ForeignKey(
|
||||
DiscountCode, on_delete=models.PROTECT, null=True, blank=True, verbose_name="کدتخفیف")
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES,
|
||||
default='ADMIN_PENDING', verbose_name="وضعیت سفارش")
|
||||
discount_amount = models.BigIntegerField(
|
||||
null=True, blank=True, verbose_name='مقدار کد تخفیف')
|
||||
tax = models.BigIntegerField(null=True, blank=True, verbose_name='مالیات')
|
||||
final_price = models.BigIntegerField(null=True, blank=True, verbose_name='قیمت نهایی')
|
||||
cart_total = models.BigIntegerField(null=True, blank=True, verbose_name='کل سبد خرید')
|
||||
|
||||
final_price = models.BigIntegerField(
|
||||
null=True, blank=True, verbose_name='قیمت نهایی')
|
||||
cart_total = models.BigIntegerField(
|
||||
null=True, blank=True, verbose_name='کل سبد خرید')
|
||||
|
||||
def __str__(self):
|
||||
return f'سفارش: {self.pk + 1000}'
|
||||
|
||||
@@ -64,69 +159,18 @@ class OrderModel(models.Model):
|
||||
verbose_name_plural = 'سفارشات'
|
||||
|
||||
|
||||
|
||||
def _cal_discount_amount(self, cart_total):
|
||||
discount_percent = self.discount_code.percent if self.discount_code else 0
|
||||
return int(cart_total * discount_percent / 100)
|
||||
|
||||
def _cal_tax(self, cart_total, discount_amount):
|
||||
tax_rate = getattr(settings, 'DEFAULT_TAX_RATE', 20)
|
||||
return int((cart_total - discount_amount) * tax_rate / 100)
|
||||
|
||||
def _cal_cart_total(self):
|
||||
from django.db.models import Sum, F, FloatField
|
||||
return self.items.aggregate(
|
||||
total=Sum(F('price') * (1 - F('discount_percent')/100) * F('quantity'),
|
||||
output_field=FloatField()
|
||||
)).get('total') or 0
|
||||
|
||||
def _cal_final_price(self, cart_total, discount_amount, tax):
|
||||
return cart_total - discount_amount + tax
|
||||
|
||||
def update_order(self):
|
||||
if self.status == 'CART':
|
||||
cart_total = self._cal_cart_total()
|
||||
discount_amount = self._cal_discount_amount(cart_total)
|
||||
self.discount_amount = discount_amount
|
||||
self.cart_total = cart_total
|
||||
tax = self._cal_tax(cart_total, discount_amount)
|
||||
self.tax = tax
|
||||
self.final_price = self._cal_final_price(cart_total, discount_amount, tax)
|
||||
self.save()
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
class OrderItemModel(models.Model):
|
||||
order = models.ForeignKey(OrderModel, on_delete=models.CASCADE, related_name='items', verbose_name='سفارش')
|
||||
order = models.ForeignKey(
|
||||
OrderModel, on_delete=models.CASCADE, related_name='items', verbose_name='سفارش')
|
||||
quantity = models.PositiveSmallIntegerField(verbose_name="تعداد")
|
||||
price = models.BigIntegerField(verbose_name='قیمت')
|
||||
product = models.ForeignKey(ProductVariant, on_delete=models.PROTECT, verbose_name="محصول")
|
||||
product = models.ForeignKey(
|
||||
ProductVariant, on_delete=models.PROTECT, verbose_name="محصول")
|
||||
discount_percent = models.SmallIntegerField(verbose_name='درصد تخفیف')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'ایتم سبد خرید'
|
||||
verbose_name_plural = 'ایتم های سبد خرید'
|
||||
|
||||
|
||||
def set_or_update_fields(self):
|
||||
self.price = self.product.price
|
||||
self.discount_percent = self.product.discount
|
||||
|
||||
def __str__(self):
|
||||
return f'({self.product}) - ({self.order.user})'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.clean()
|
||||
self.set_or_update_fields()
|
||||
super().save(*args, **kwargs)
|
||||
self.order.update_order()
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.clean()
|
||||
order = self.order
|
||||
super().delete(*args, **kwargs)
|
||||
order.update_order()
|
||||
|
||||
def clean(self):
|
||||
if self.pk and self.order.status != "CART":
|
||||
raise ValidationError("ایتم ها فقط در حالت سبد خرید قابل ادیت هستند")
|
||||
Reference in New Issue
Block a user