feat: add profit and special discount fields to ProductVariant model
- Updated ProductVariant model to include 'profit' and 'special_discount_percent' fields. - Added corresponding fields in the admin interface for ProductVariant. - Created migration to add new fields to the database. feat: implement special discount code functionality in cart - Added composables for submitting and deleting special discount codes. - Updated CartSummary and CartItem components to handle special discount codes. - Enhanced API endpoints to support special discount operations. - Updated global types to include special discount code details in the cart.
This commit is contained in:
+70
-37
@@ -1,3 +1,4 @@
|
||||
from account.models import SpecialDiscountCode
|
||||
from django.db import models, transaction
|
||||
from account.models import User, UserAddressModel, PushSubscription
|
||||
from product.models import ProductModel, ProductVariant, ProductImageModel
|
||||
@@ -47,6 +48,8 @@ class Cart(models.Model):
|
||||
related_name='carts', null=True, verbose_name='ادرس')
|
||||
discount_code = models.ForeignKey(
|
||||
DiscountCode, on_delete=models.PROTECT, null=True, blank=True, verbose_name="کدتخفیف")
|
||||
special_discount_code = models.ForeignKey(
|
||||
SpecialDiscountCode, on_delete=models.PROTECT, null=True, blank=True, verbose_name="کدتخفیف خاص")
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'سبد خرید'
|
||||
@@ -58,6 +61,7 @@ class Cart(models.Model):
|
||||
def clear_cart(self):
|
||||
self.items.all().delete()
|
||||
self.discount_code = None
|
||||
self.special_discount_code = None
|
||||
self.save()
|
||||
|
||||
@property
|
||||
@@ -71,10 +75,17 @@ class Cart(models.Model):
|
||||
def items_discount_amount(self):
|
||||
return int(sum(item.item_discount_amount for item in self.items.all()))
|
||||
|
||||
@property
|
||||
def special_discount_total(self):
|
||||
"""Sum of all special discounts from cart items when special_discount_code is applied."""
|
||||
if self.special_discount_code:
|
||||
return int(sum(item.item_special_discount_amount for item in self.items.all()))
|
||||
return 0
|
||||
|
||||
@property
|
||||
def total_before_tax(self):
|
||||
return self.cart_total - (self.discount_code_amount + self.items_discount_amount)
|
||||
|
||||
return self.cart_total - (self.discount_code_amount + self.items_discount_amount + self.special_discount_total)
|
||||
|
||||
@property
|
||||
def tax_amount(self):
|
||||
return int(self.total_before_tax * settings.DEFAULT_TAX_RATE / 100)
|
||||
@@ -102,6 +113,7 @@ class CartItem(models.Model):
|
||||
quantity = models.PositiveIntegerField(default=1)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
# special_discount_amount = models.BigIntegerField(default=0, verbose_name='مقدار تخفیف ویژه', help_text='تخفیف محاسبه شده از سود تنوع')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'ایتم سبد خرید'
|
||||
@@ -111,22 +123,37 @@ class CartItem(models.Model):
|
||||
def __str__(self):
|
||||
return f"{self.quantity} x {self.product_variant.product.name} in cart {self.cart.id}"
|
||||
|
||||
@property
|
||||
def special_discount_amount(self):
|
||||
"""Calculate special discount for this cart item based on variant profit and special_discount_percent."""
|
||||
if hasattr(self.cart, 'special_discount_code') and self.cart.special_discount_code:
|
||||
return self.product_variant.special_discount_amount_per_unit * self.quantity
|
||||
return 0
|
||||
|
||||
@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 item_special_discount_amount(self):
|
||||
"""Calculate special discount for this cart item based on variant profit and special_discount_percent."""
|
||||
if hasattr(self.cart, 'special_discount_code') and self.cart.special_discount_code:
|
||||
return self.product_variant.special_discount_amount_per_unit * self.quantity
|
||||
return 0
|
||||
|
||||
@property
|
||||
def price_after_discount(self):
|
||||
return self.price_before_discount - self.item_discount_amount
|
||||
return self.price_before_discount - self.item_discount_amount - self.item_special_discount_amount
|
||||
|
||||
@property
|
||||
def discount(self):
|
||||
return self.product_variant.discount
|
||||
|
||||
|
||||
class OrderModel(models.Model):
|
||||
objects = jmodels.jManager()
|
||||
STATUS_CHOICES = [
|
||||
@@ -155,9 +182,12 @@ class OrderModel(models.Model):
|
||||
null=True, blank=True, verbose_name='قیمت نهایی')
|
||||
cart_total = models.BigIntegerField(
|
||||
null=True, blank=True, verbose_name='کل سبد خرید')
|
||||
special_discount_total = models.BigIntegerField(
|
||||
null=True, blank=True, verbose_name='مجموع تخفیف ویژه')
|
||||
|
||||
cart = models.ForeignKey(
|
||||
Cart, on_delete=models.CASCADE, null=True, blank=True)
|
||||
|
||||
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, null=True, blank=True)
|
||||
|
||||
is_stock_rolled_back = models.BooleanField(
|
||||
default=False, verbose_name="موجودی برگردانده شده")
|
||||
|
||||
@@ -169,36 +199,37 @@ class OrderModel(models.Model):
|
||||
verbose_name_plural = 'سفارشات'
|
||||
|
||||
def rollback_stock(self):
|
||||
"""
|
||||
Rollback stock quantities for all items in this order
|
||||
Returns True if successful, False otherwise
|
||||
"""
|
||||
if self.is_stock_rolled_back:
|
||||
return False
|
||||
|
||||
# if not self.cart:
|
||||
# return False
|
||||
|
||||
try:
|
||||
# Get all cart items and rollback their stock
|
||||
for order_item in self.items.all():
|
||||
product = order_item.product
|
||||
# Add back the quantity to stock
|
||||
product.in_stock += order_item.quantity
|
||||
product.save()
|
||||
|
||||
# Mark as rolled back
|
||||
self.is_stock_rolled_back = True
|
||||
self.save(update_fields=['is_stock_rolled_back'])
|
||||
self.status = 'CANCELED'
|
||||
self.save()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# Log the error if you have logging setup
|
||||
# logger.error(f"Failed to rollback stock for order {self.pk}: {e}")
|
||||
return False
|
||||
"""
|
||||
Rollback stock quantities for all items in this order
|
||||
Returns True if successful, False otherwise
|
||||
"""
|
||||
if self.is_stock_rolled_back:
|
||||
return False
|
||||
|
||||
# if not self.cart:
|
||||
# return False
|
||||
|
||||
try:
|
||||
# Get all cart items and rollback their stock
|
||||
for order_item in self.items.all():
|
||||
product = order_item.product
|
||||
# Add back the quantity to stock
|
||||
product.in_stock += order_item.quantity
|
||||
product.save()
|
||||
|
||||
# Mark as rolled back
|
||||
self.is_stock_rolled_back = True
|
||||
self.save(update_fields=['is_stock_rolled_back'])
|
||||
self.status = 'CANCELED'
|
||||
self.save()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# Log the error if you have logging setup
|
||||
# logger.error(f"Failed to rollback stock for order {self.pk}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
class OrderItemModel(models.Model):
|
||||
order = models.ForeignKey(
|
||||
@@ -208,6 +239,8 @@ class OrderItemModel(models.Model):
|
||||
product = models.ForeignKey(
|
||||
ProductVariant, on_delete=models.PROTECT, verbose_name="محصول")
|
||||
discount_percent = models.SmallIntegerField(verbose_name='درصد تخفیف')
|
||||
special_discount_amount = models.BigIntegerField(
|
||||
default=0, verbose_name='مقدار تخفیف ویژه')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'ایتم سبد خرید'
|
||||
|
||||
Reference in New Issue
Block a user