product varient change list bug fix order item change quantity and remove
This commit is contained in:
@@ -25,6 +25,7 @@ urlpatterns = [
|
|||||||
path('chat/', include('chat.urls')),
|
path('chat/', include('chat.urls')),
|
||||||
path('tickets/', include('ticket.urls')),
|
path('tickets/', include('ticket.urls')),
|
||||||
path('blogs/', include('blog.urls')),
|
path('blogs/', include('blog.urls')),
|
||||||
|
path('order/', include('order.urls')),
|
||||||
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
class DiscountNotAvailableError(Exception):
|
||||||
|
pass
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:07
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('order', '0003_alter_orderitemmodel_product'),
|
||||||
|
('product', '0023_alter_productimagemodel_options_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='orderitemmodel',
|
||||||
|
name='product',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='product.productvariant', verbose_name='محصول'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+11
-8
@@ -1,8 +1,8 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from account.models import User, UserAddressModel
|
from account.models import User, UserAddressModel
|
||||||
from product.models import ProductModel
|
from product.models import ProductModel, ProductVariant
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from .execptions import DiscountNotAvailableError
|
||||||
class DiscountCode(models.Model):
|
class DiscountCode(models.Model):
|
||||||
name = models.CharField(max_length=50, verbose_name='کد تخفیف')
|
name = 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='درصد')
|
||||||
@@ -43,13 +43,15 @@ class OrderModel(models.Model):
|
|||||||
verbose_name = 'سفارش'
|
verbose_name = 'سفارش'
|
||||||
verbose_name_plural = 'سفارشات'
|
verbose_name_plural = 'سفارشات'
|
||||||
|
|
||||||
def total_without_tax(self):
|
# def total_without_tax(self):
|
||||||
return sum(item.total() for item in self.items.all())
|
# return sum(item.total() for item in self.items.all())
|
||||||
|
|
||||||
|
|
||||||
def total_with_discount(self):
|
def total_with_discount(self):
|
||||||
total_with_item_discount = sum(item.total_with_discount() for item in self.items.all())
|
total_with_item_discount = sum(item.total_with_discount() for item in self.items.all())
|
||||||
if self.discount_code and self.discount_code.is_valid():
|
if self.discount_code:
|
||||||
|
if not self.discount_code.is_valid():
|
||||||
|
raise DiscountNotAvailableError('این کد تخفیف دیگر معتبر نیست')
|
||||||
discount_percent = self.discount_code.percent
|
discount_percent = self.discount_code.percent
|
||||||
return total_with_item_discount * ((100 - discount_percent) / 100)
|
return total_with_item_discount * ((100 - discount_percent) / 100)
|
||||||
return total_with_item_discount
|
return total_with_item_discount
|
||||||
@@ -59,7 +61,7 @@ class OrderModel(models.Model):
|
|||||||
return self.total_without_tax() * 0.2
|
return self.total_without_tax() * 0.2
|
||||||
|
|
||||||
def total(self):
|
def total(self):
|
||||||
return self.total_without_tax + self.tax()
|
return self.total_with_discount() + self.tax()
|
||||||
|
|
||||||
def remove_order_item(self, item_pk, quantity):
|
def remove_order_item(self, item_pk, quantity):
|
||||||
pass
|
pass
|
||||||
@@ -75,7 +77,7 @@ class OrderModel(models.Model):
|
|||||||
class OrderItemModel(models.Model):
|
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.SmallIntegerField(verbose_name="تعداد")
|
quantity = models.SmallIntegerField(verbose_name="تعداد")
|
||||||
product = models.ForeignKey(ProductModel, on_delete=models.PROTECT, verbose_name="محصول")
|
product = models.ForeignKey(ProductVariant, on_delete=models.PROTECT, verbose_name="محصول")
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'محصول خریداری شده'
|
verbose_name = 'محصول خریداری شده'
|
||||||
verbose_name_plural = 'محصولات خریداری شده'
|
verbose_name_plural = 'محصولات خریداری شده'
|
||||||
@@ -85,5 +87,6 @@ class OrderItemModel(models.Model):
|
|||||||
|
|
||||||
def total_with_discount(self):
|
def total_with_discount(self):
|
||||||
return self.quantity * self.product.get_toman_price_after_discount()
|
return self.quantity * self.product.get_toman_price_after_discount()
|
||||||
|
def __str__(self):
|
||||||
|
return f'ایتم سبد خرید محصول: {self.product} کاربر {self.order.user}'
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
from .models import OrderItemModel
|
||||||
|
|
||||||
|
|
||||||
|
class OrderItemSerailzier(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = OrderItemModel
|
||||||
|
fields = "__all__"
|
||||||
|
read_only_fields = ('order', 'product')
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
from django.conf.urls.static import static
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
from .views import CartItemViews
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('cart/item/<int:pk>', CartItemViews.as_view(), name='add cart'),
|
||||||
|
]
|
||||||
+66
-1
@@ -1,3 +1,68 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from .execptions import DiscountNotAvailableError
|
||||||
|
from rest_framework.views import APIView, Response
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from product.models import ProductVariant
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from .serializers import OrderItemSerailzier
|
||||||
|
# from cart.models import
|
||||||
|
from rest_framework import status
|
||||||
|
from .models import OrderItemModel, OrderModel
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except DiscountNotAvailableError:
|
||||||
|
pass
|
||||||
|
|
||||||
# Create your views here.
|
"""
|
||||||
|
|
||||||
|
add post
|
||||||
|
remove delete
|
||||||
|
show get
|
||||||
|
|
||||||
|
pay
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CartItemViews(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
serializer_class = OrderItemSerailzier
|
||||||
|
def post(self, request, pk):
|
||||||
|
product_variant = get_object_or_404(ProductVariant, pk=pk)
|
||||||
|
|
||||||
|
cart_order, created = OrderModel.objects.get_or_create(
|
||||||
|
user=request.user,
|
||||||
|
status='CART'
|
||||||
|
)
|
||||||
|
order_item, created = OrderItemModel.objects.get_or_create(
|
||||||
|
order=cart_order,
|
||||||
|
product=product_variant,
|
||||||
|
defaults={'quantity': request.data.get('quantity', 1)}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
order_item.quantity = request.data.get('quantity', 1)
|
||||||
|
order_item.save()
|
||||||
|
|
||||||
|
return Response({'detail': 'it did something'}, status=status.HTTP_201_CREATED)
|
||||||
|
def delete(self, request, pk):
|
||||||
|
product_variant = get_object_or_404(ProductVariant, pk=pk)
|
||||||
|
|
||||||
|
cart_order, created = OrderModel.objects.get_or_create(
|
||||||
|
user=request.user,
|
||||||
|
status='CART'
|
||||||
|
)
|
||||||
|
# order_item, created = OrderItemModel.objects.get_or_create(
|
||||||
|
# order=cart_order,
|
||||||
|
# product=product_variant,
|
||||||
|
# defaults={'quantity': request.data.get('quantity', 1)}
|
||||||
|
# )
|
||||||
|
order_item = get_object_or_404(OrderItemModel, order=cart_order, product=product_variant)
|
||||||
|
order_item.delete()
|
||||||
|
return Response({'detail': 'it did something related to delete'}, status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CartViews(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from unfold.decorators import action, display
|
|||||||
class ProductVariantAdmin(ModelAdmin, ImportExportModelAdmin):
|
class ProductVariantAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||||
import_form_class = ImportForm
|
import_form_class = ImportForm
|
||||||
export_form_class = ExportForm
|
export_form_class = ExportForm
|
||||||
autocomplete_fields = ['attributes']
|
autocomplete_fields = ['product_attributes', 'images', 'in_pack_items']
|
||||||
warn_unsaved_form = True
|
warn_unsaved_form = True
|
||||||
|
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ class ProductVariantInLine(StackedInline):
|
|||||||
show_change_link = True
|
show_change_link = True
|
||||||
tab = True
|
tab = True
|
||||||
min_num = 1
|
min_num = 1
|
||||||
autocomplete_fields = ['attributes', 'in_pack_items', 'images']
|
autocomplete_fields = ['product_attributes', 'in_pack_items', 'images']
|
||||||
# search_fields = ['']
|
# search_fields = ['']
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:35
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0023_alter_productimagemodel_options_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='attributevalue',
|
||||||
|
unique_together=set(),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:39
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0024_alter_attributevalue_unique_together'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='productvariant',
|
||||||
|
name='attributes',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='variant', to='product.attributevalue', verbose_name='ویژگی\u200cها'),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='attributevalue',
|
||||||
|
unique_together={('attribute_type', 'value')},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:40
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0025_alter_productvariant_attributes_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='productvariant',
|
||||||
|
name='attributes',
|
||||||
|
field=models.ManyToManyField(related_name='variant', to='product.attributevalue', verbose_name='ویژگی\u200cها'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0026_alter_productvariant_attributes'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='productvariant',
|
||||||
|
name='attributes',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='variant', to='product.attributevalue', verbose_name='ویژگی\u200cها'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0027_alter_productvariant_attributes'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='productvariant',
|
||||||
|
name='attributes',
|
||||||
|
field=models.ManyToManyField(related_name='variant', to='product.attributevalue', verbose_name='ویژگی\u200cها'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:48
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0028_alter_productvariant_attributes'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='attributevalue',
|
||||||
|
unique_together=set(),
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='attributevalue',
|
||||||
|
name='attribute_type',
|
||||||
|
),
|
||||||
|
]
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-13 20:49
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0029_alter_attributevalue_unique_together_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='productvariant',
|
||||||
|
old_name='attributes',
|
||||||
|
new_name='product_attributes',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='attributevalue',
|
||||||
|
name='attribute_type',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='product.attributetype'),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='attributevalue',
|
||||||
|
unique_together={('attribute_type', 'value')},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -201,7 +201,7 @@ class AttributeValue(models.Model):
|
|||||||
unique_together = ('attribute_type', 'value')
|
unique_together = ('attribute_type', 'value')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.attribute_type.name}: {self.value}"
|
return f"{self.attribute_type}: {self.value}"
|
||||||
|
|
||||||
|
|
||||||
class ProductImageModel(models.Model):
|
class ProductImageModel(models.Model):
|
||||||
@@ -220,7 +220,7 @@ class ProductImageModel(models.Model):
|
|||||||
|
|
||||||
class ProductVariant(models.Model):
|
class ProductVariant(models.Model):
|
||||||
product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول')
|
product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول')
|
||||||
attributes = models.ManyToManyField(AttributeValue, verbose_name='ویژگیها', related_name='variant')
|
product_attributes = models.ManyToManyField(AttributeValue, verbose_name='ویژگیها', related_name='variant')
|
||||||
in_stock = models.PositiveIntegerField(default=0, verbose_name='تعداد موجود')
|
in_stock = models.PositiveIntegerField(default=0, verbose_name='تعداد موجود')
|
||||||
price = models.PositiveIntegerField(default=0, verbose_name='قیمت')
|
price = models.PositiveIntegerField(default=0, verbose_name='قیمت')
|
||||||
min_price = models.PositiveIntegerField(verbose_name='قیمت کف', help_text='این قیمت برای کف قیمتی محصول در نظر گرفته میشود')
|
min_price = models.PositiveIntegerField(verbose_name='قیمت کف', help_text='این قیمت برای کف قیمتی محصول در نظر گرفته میشود')
|
||||||
@@ -242,7 +242,7 @@ class ProductVariant(models.Model):
|
|||||||
verbose_name_plural = 'تنوعهای محصول'
|
verbose_name_plural = 'تنوعهای محصول'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.product.name} - {', '.join(str(attr) for attr in self.attributes.all())}"
|
return f"{self.product.name} - {', '.join(str(attr) for attr in self.product_attributes.all())}"
|
||||||
|
|
||||||
def get_toman_price(self, dollor_price=None):
|
def get_toman_price(self, dollor_price=None):
|
||||||
if not dollor_price:
|
if not dollor_price:
|
||||||
|
|||||||
Reference in New Issue
Block a user