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:
Parsa Nazer
2025-11-15 11:00:33 +03:30
parent 030976044c
commit d29ed8e35b
19 changed files with 718 additions and 208 deletions
+4
View File
@@ -15,7 +15,11 @@ from django.template.loader import render_to_string
from folium import Map, Marker
from unfold.decorators import action, display
from django.utils.html import format_html
from account.models import SpecialDiscountCode
@admin.register(SpecialDiscountCode)
class SpecialDiscountCodeAdmin(ModelAdmin):
pass
class UserAddressInLine(TabularInline):
model = UserAddressModel
+17
View File
@@ -61,6 +61,15 @@ class User(AbstractBaseUser, PermissionsMixin):
# def groups(self):
# return None
def generate_special_code(self):
"""Generate and save a unique special code for the user if missing."""
# simple deterministic code based on phone and timestamp hash
base = f"{self.phone}-{timezone.now().timestamp()}"
code = hashlib.sha256(base.encode()).hexdigest()[:12].upper()
return code
@property
def full_name(self):
if self.first_name and self.last_name:
@@ -120,6 +129,14 @@ class User(AbstractBaseUser, PermissionsMixin):
return self.phone
class SpecialDiscountCode(models.Model):
user = models.OneToOneField(User, on_delete=models.PROTECT, related_name='spital_code')
code = models.CharField(max_length=12, unique=True)
def __str__(self):
return f'{self.user} - {self.code}'
class ShopModel(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='shop', verbose_name='کاربر')
+1 -1
View File
@@ -80,7 +80,7 @@ class SendOTPView(APIView):
except User.DoesNotExist:
return Response({'detail': 'user not found'}, status=status.HTTP_404_NOT_FOUND)
except Exception as e:
return Response({'detail': f'error: {e} مشتی فعلا برو تو غمت نباشه تا بعدا یه کاریش بکنم', 'otp_code': otp}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response({'detail': f'error: {e} مشتی فعلا برو تو غمت نباشه تا بعدا یه کاریش بکنم', 'otp_code': otp}, status=status.HTTP_200_OK)
# return Response({'detail': f'An error occurred: {e}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@extend_schema_view(
post=extend_schema(tags=['authentication'])