From 8539532bf4786cd00db969699aea264b116c390c Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 21 Apr 2025 23:28:17 +0330 Subject: [PATCH 01/10] str for detail product --- backend/product/models.py | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/backend/product/models.py b/backend/product/models.py index 1a1ca6b..f044d5a 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -4,6 +4,7 @@ from account.models import User from django.urls import reverse import requests from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError class MainCategoryModel(models.Model): name = models.CharField(max_length=50, verbose_name='نام دسته بندی') @@ -218,8 +219,8 @@ class ProductDetailModel(models.Model): class Meta: verbose_name = 'جزیات محصول' verbose_name_plural = 'جزیات محصول ها' - # def __str__(self): - # return f'جزيیات محصول {self.product}' + def __str__(self): + return f'جزيیات محصول {self.detail_category.title} - {self.detail.title}' class ProductVariant(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول') @@ -272,21 +273,3 @@ class ProductVariant(models.Model): def save(self, *args, **kwargs): self.set_or_update_price() super().save(*args, **kwargs) - - def get_toman_price_after_discount(self): - return self.price * ((100 - self.discount) / 100) - - @classmethod - def update_all_prices(cls): - print('calling the update all prices ') - dollor_object, _ = DollorModel.objects.get_or_create(unique_filed='unique') - print(dollor_object.price) - dollor_object.update_price() - dollor_object.save() - dollor_price = dollor_object.price - print(dollor_object.price) - print('classmethod dollor price update ') - products = cls.objects.all() - for product in products: - product.set_or_update_price(dollor_price=dollor_price) - product.save() \ No newline at end of file From c84e5150f833c6af4827ce14b71358b49d1822fc Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 22 Apr 2025 02:41:11 +0330 Subject: [PATCH 02/10] contact us model view and admin functionality --- backend/core/settings/unfold_conf.py | 6 +++++ backend/core/views.py | 4 +++- backend/templates/formula/service.html | 23 +++++++++++++++++- backend/ticket/admin.py | 9 +++++++ .../ticket/migrations/0020_contactusmodel.py | 24 +++++++++++++++++++ .../0021_alter_contactusmodel_type.py | 18 ++++++++++++++ ...2_alter_contactusmodel_options_and_more.py | 22 +++++++++++++++++ backend/ticket/models.py | 24 ++++++++++++++++++- backend/ticket/serializers.py | 10 ++++++-- backend/ticket/urls.py | 1 + backend/ticket/views.py | 17 ++++++++++--- backend/utils/admin.py | 5 +++- 12 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 backend/ticket/migrations/0020_contactusmodel.py create mode 100644 backend/ticket/migrations/0021_alter_contactusmodel_type.py create mode 100644 backend/ticket/migrations/0022_alter_contactusmodel_options_and_more.py diff --git a/backend/core/settings/unfold_conf.py b/backend/core/settings/unfold_conf.py index 23bf662..44f5e63 100644 --- a/backend/core/settings/unfold_conf.py +++ b/backend/core/settings/unfold_conf.py @@ -239,6 +239,12 @@ UNFOLD = { "badge": "utils.admin.new_ticket_count", }, + { + "title": _("ارتباط با ما"), + "icon": "perm_phone_msg", + "link": reverse_lazy("admin:ticket_contactusmodel_changelist"), + "badge": "utils.admin.new_contact_us_count", + }, ], }, { diff --git a/backend/core/views.py b/backend/core/views.py index be623df..9894f4e 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -8,7 +8,7 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic import RedirectView, TemplateView from unfold.views import UnfoldModelAdminViewMixin from order.models import OrderModel -from ticket.models import Ticket +from ticket.models import Ticket, ContactUsModel from account.models import SecurityBreachAttemptModel import json @@ -19,9 +19,11 @@ def dashboard_callback(request, context): pending_count = OrderModel.objects.filter(status='ADMIN_PENDING').count() open_tickets_count = Ticket.objects.filter(status__in=['open', 'in_progress']).count() + open_contact_us_count = ContactUsModel.objects.filter(is_reviewed=False).count() context.update(random_data()) context.update({'pending_count': pending_count}) context.update({'open_tickets_count': open_tickets_count}) + context.update({'open_contact_us_count': open_contact_us_count}) return context diff --git a/backend/templates/formula/service.html b/backend/templates/formula/service.html index 57856a4..ca6cc92 100644 --- a/backend/templates/formula/service.html +++ b/backend/templates/formula/service.html @@ -39,4 +39,25 @@ {% endcomponent %} -{% endif %} \ No newline at end of file +{% endif %} +{% if open_contact_us_count%} + + +
+
+

+ confirmation_number + ارتباط با ما جدید داری + {{ open_contact_us_count }} +

+
+ +
+ {% component "unfold/components/flex.html" with class="flex-col gap-4 lg:flex-row" %} + {% component "unfold/components/button.html" with href="/secret-admin/ticket/contactusmodel/" %} + نمایش ارتباط با ما ها + {% endcomponent %} + {% endcomponent %} +
+
+{% endif %} diff --git a/backend/ticket/admin.py b/backend/ticket/admin.py index 1426233..bc50d27 100644 --- a/backend/ticket/admin.py +++ b/backend/ticket/admin.py @@ -18,6 +18,15 @@ class MessageInline(TabularInline): model = Message extra = 1 +@admin.register(ContactUsModel) +class ContactUsAdmin(ModelAdmin): + list_filter = ['type', 'is_reviewed'] + list_display = ['full_name', 'phone', 'email', 'message', 'is_reviewed'] + compressed_fields = True + warn_unsaved_form = True + readonly_fields = ['full_name', 'email', 'phone', 'type', 'message', ] + + @admin.register(Ticket) class TicketAdmin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm diff --git a/backend/ticket/migrations/0020_contactusmodel.py b/backend/ticket/migrations/0020_contactusmodel.py new file mode 100644 index 0000000..d2bd2be --- /dev/null +++ b/backend/ticket/migrations/0020_contactusmodel.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.2 on 2025-04-21 22:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ticket', '0019_alter_attachment_options'), + ] + + operations = [ + migrations.CreateModel( + name='ContactUsModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('full_name', models.CharField(max_length=50, verbose_name='نام و نام خانوادگی')), + ('email', models.EmailField(max_length=254, verbose_name='ایمیل')), + ('phone', models.CharField(max_length=30)), + ('type', models.CharField(choices=[('ORDER', 'پیگیری سفارش'), ('SUGGESTION', 'پیشنهادات'), ('COMPLAINT', 'انتقادات')], max_length=20, verbose_name='نوع')), + ('message', models.TextField(verbose_name='پیام')), + ], + ), + ] diff --git a/backend/ticket/migrations/0021_alter_contactusmodel_type.py b/backend/ticket/migrations/0021_alter_contactusmodel_type.py new file mode 100644 index 0000000..59c5790 --- /dev/null +++ b/backend/ticket/migrations/0021_alter_contactusmodel_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.2 on 2025-04-21 22:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ticket', '0020_contactusmodel'), + ] + + operations = [ + migrations.AlterField( + model_name='contactusmodel', + name='type', + field=models.CharField(choices=[('ORDER_FOLLOW_UP', 'پیگیری سفارش'), ('SUGGESTION', 'پیشنهادات'), ('COMPLAINT', 'انتقادات')], max_length=20, verbose_name='نوع'), + ), + ] diff --git a/backend/ticket/migrations/0022_alter_contactusmodel_options_and_more.py b/backend/ticket/migrations/0022_alter_contactusmodel_options_and_more.py new file mode 100644 index 0000000..537844b --- /dev/null +++ b/backend/ticket/migrations/0022_alter_contactusmodel_options_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 5.1.2 on 2025-04-21 22:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ticket', '0021_alter_contactusmodel_type'), + ] + + operations = [ + migrations.AlterModelOptions( + name='contactusmodel', + options={'verbose_name': 'ارتباط با ما', 'verbose_name_plural': 'ارتباط با ما ها '}, + ), + migrations.AddField( + model_name='contactusmodel', + name='is_reviewed', + field=models.BooleanField(default=False), + ), + ] diff --git a/backend/ticket/models.py b/backend/ticket/models.py index 0941fe3..a6b89a4 100644 --- a/backend/ticket/models.py +++ b/backend/ticket/models.py @@ -73,4 +73,26 @@ class Message(models.Model): class Meta: verbose_name = 'پیام تیکت' - verbose_name_plural = 'پیام های تیکت' \ No newline at end of file + verbose_name_plural = 'پیام های تیکت' + + +class ContactUsModel(models.Model): + full_name = models.CharField(max_length=50, verbose_name='نام و نام خانوادگی') + email = models.EmailField(max_length=254, verbose_name='ایمیل') + phone = models.CharField(max_length=30, verbose_name='شماره تماس') + FEEDBACK_TYPES = [ + ('ORDER_FOLLOW_UP', 'پیگیری سفارش'), + ('SUGGESTION', 'پیشنهادات'), + ('COMPLAINT', 'انتقادات'), + ] + + type = models.CharField(max_length=20, choices=FEEDBACK_TYPES, verbose_name='نوع') + message = models.TextField(verbose_name='پیام') + is_reviewed = models.BooleanField(default=False, verbose_name='بررسی شده') + + def __str__(self): + return f'{self.full_name} - {self.message[:15]}...' + + class Meta: + verbose_name = 'ارتباط با ما' + verbose_name_plural = 'ارتباط با ما ها ' \ No newline at end of file diff --git a/backend/ticket/serializers.py b/backend/ticket/serializers.py index d99a8d2..f4af17d 100644 --- a/backend/ticket/serializers.py +++ b/backend/ticket/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import Ticket, Message, Attachment +from .models import Ticket, Message, Attachment, ContactUsModel from django.utils.timezone import localtime from order.serializers import OrderListSerializer from order.serializers import OrderModel @@ -88,4 +88,10 @@ class TicketListSerializer(serializers.ModelSerializer): return obj.get_status_display() def get_ticket_category(self, obj): - return obj.get_ticket_category_display() \ No newline at end of file + return obj.get_ticket_category_display() + + +class ContactUsSerializer(serializers.ModelSerializer): + class Meta: + model = ContactUsModel + fields = ['full_name', 'email', 'phone', 'type', 'message'] \ No newline at end of file diff --git a/backend/ticket/urls.py b/backend/ticket/urls.py index c3a47f5..50eed91 100644 --- a/backend/ticket/urls.py +++ b/backend/ticket/urls.py @@ -6,6 +6,7 @@ urlpatterns = [ path('', views.TicketListView.as_view(), name='ticket-list'), path('', views.TicketDetailView.as_view(), name='ticket-detail'), path('message/create', views.MessageCreateView.as_view(), name='message-create'), + path('contact-us/create', views.CreateContactUsView.as_view(), name='contact-us-create'), path('attachment/create', views.AttachmentUploadView.as_view(), name='attachment-upload'), path('attachment/delete/', views.AttachmentDeleteView.as_view(), name='attachment-upload'), ] \ No newline at end of file diff --git a/backend/ticket/views.py b/backend/ticket/views.py index ac6fdae..e669864 100644 --- a/backend/ticket/views.py +++ b/backend/ticket/views.py @@ -2,7 +2,7 @@ from rest_framework import generics, permissions from rest_framework.response import Response from rest_framework.views import APIView from .models import Ticket, Message, Attachment -from .serializers import TicketListSerializer, MessageSerializer, TicketSerializer, AttachmentSerializer +from .serializers import TicketListSerializer, MessageSerializer, TicketSerializer, AttachmentSerializer, ContactUsSerializer from utils.pagination import StructurePagination from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes from rest_framework.permissions import IsAuthenticated @@ -56,7 +56,6 @@ class TicketCreateView(APIView): permission_classes = [permissions.IsAuthenticated] def post(self, request): new_ticket_ser = self.serializer_class(data=request.data, context={'request': request}) - message = request.data.get('message', None) if new_ticket_ser.is_valid(): new_ticket_ser.save(customer=request.user) return Response(new_ticket_ser.data, status=status.HTTP_201_CREATED) @@ -159,4 +158,16 @@ class UpdateTicketStatusView(APIView): return Response({"error": "Invalid status"}, status=400) ticket.status = new_status ticket.save() - return Response({"message": "Ticket status updated successfully"}) \ No newline at end of file + return Response({"message": "Ticket status updated successfully"}) + + +class CreateContactUsView(APIView): + serializer_class = ContactUsSerializer + permission_classes = [permissions.AllowAny] + def post(self, request): + contact_us_ser = self.serializer_class(data=request.data, context={'request': request}) + if contact_us_ser.is_valid(): + contact_us_ser.save() + return Response(contact_us_ser.data, status=status.HTTP_201_CREATED) + else: + return Response(contact_us_ser.errors, status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/backend/utils/admin.py b/backend/utils/admin.py index 1107fab..82c4d05 100644 --- a/backend/utils/admin.py +++ b/backend/utils/admin.py @@ -1,6 +1,6 @@ from order.models import OrderModel from product.models import DollorModel, CommentModel -from ticket.models import Ticket +from ticket.models import Ticket, ContactUsModel from home.models import LearnVideoModel from account.models import SecurityBreachAttemptModel @@ -24,6 +24,9 @@ def new_learn_video_count(request): def new_attck_count(request): return SecurityBreachAttemptModel.objects.filter(viewd=False).count() +def new_contact_us_count(request): + return ContactUsModel.objects.filter(is_reviewed=False).count() + from django.contrib import admin, messages from unfold.admin import ModelAdmin from home.models import LearnVideoModel From 500814b610752820294afe9d0f5e6eb6a3f5b204 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 22 Apr 2025 02:48:35 +0330 Subject: [PATCH 03/10] database comment added --- backend/.env.local | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/backend/.env.local b/backend/.env.local index 4cb8221..2678574 100644 --- a/backend/.env.local +++ b/backend/.env.local @@ -28,4 +28,16 @@ SMS_API_KEY = '' VAPID_PRIVATE_KEY = 'NajogmGTsGsZ_dfURrjUpgsm5fui-s5AzruBQgMh_I4' -OPENAI_API_KEY = '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' \ No newline at end of file +OPENAI_API_KEY = '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' + + +# DATABASES = { +# 'default': { +# 'ENGINE': 'django.db.backends.postgresql', +# 'NAME': 'hshop', +# 'USER': 'byeto', +# 'PASSWORD': 'vuhbyq-cypMu0-sirbon', +# 'HOST': '185.110.189.208', +# 'PORT': '5434', +# } +# } \ No newline at end of file From 5d17038f9be6b4ba76531960cd7d3400411f616f Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 22 Apr 2025 03:01:04 +0330 Subject: [PATCH 04/10] ProductDetailModel debug and ticket migrations push --- ...lter_productdetailmodel_detail_category.py | 20 ++++++++++++++++ backend/product/models.py | 4 ++-- ...ter_contactusmodel_is_reviewed_and_more.py | 23 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 backend/product/migrations/0036_alter_productdetailmodel_detail_category.py create mode 100644 backend/ticket/migrations/0023_alter_contactusmodel_is_reviewed_and_more.py diff --git a/backend/product/migrations/0036_alter_productdetailmodel_detail_category.py b/backend/product/migrations/0036_alter_productdetailmodel_detail_category.py new file mode 100644 index 0000000..1ae6eb5 --- /dev/null +++ b/backend/product/migrations/0036_alter_productdetailmodel_detail_category.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.2 on 2025-04-21 23:30 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0035_alter_attributetype_options_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='productdetailmodel', + name='detail_category', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='product.productdetailcategory', verbose_name='دسته بندی جزيات'), + preserve_default=False, + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index f044d5a..e3459e7 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -213,14 +213,14 @@ class ProductImageModel(models.Model): class ProductDetailModel(models.Model): - detail_category = models.ForeignKey(ProductDetailCategory, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات', blank=True, null=True) + detail_category = models.ForeignKey(ProductDetailCategory, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات') detail = models.ManyToManyField(DetailModel, verbose_name='جزيات ها') class Meta: verbose_name = 'جزیات محصول' verbose_name_plural = 'جزیات محصول ها' def __str__(self): - return f'جزيیات محصول {self.detail_category.title} - {self.detail.title}' + return f'جزيیات محصول {self.detail_category.title}' class ProductVariant(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول') diff --git a/backend/ticket/migrations/0023_alter_contactusmodel_is_reviewed_and_more.py b/backend/ticket/migrations/0023_alter_contactusmodel_is_reviewed_and_more.py new file mode 100644 index 0000000..e798399 --- /dev/null +++ b/backend/ticket/migrations/0023_alter_contactusmodel_is_reviewed_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.2 on 2025-04-21 23:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ticket', '0022_alter_contactusmodel_options_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='contactusmodel', + name='is_reviewed', + field=models.BooleanField(default=False, verbose_name='بررسی شده'), + ), + migrations.AlterField( + model_name='contactusmodel', + name='phone', + field=models.CharField(max_length=30, verbose_name='شماره تماس'), + ), + ] From 044bed9c00a52448b963ae617afab2c5d9107e16 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 22 Apr 2025 03:09:07 +0330 Subject: [PATCH 05/10] udpate product detail name filed --- backend/core/settings/unfold_conf.py | 5 +++++ backend/product/admin.py | 6 +++--- .../0037_productdetailmodel_name.py | 19 +++++++++++++++++++ backend/product/models.py | 3 ++- 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 backend/product/migrations/0037_productdetailmodel_name.py diff --git a/backend/core/settings/unfold_conf.py b/backend/core/settings/unfold_conf.py index 44f5e63..a143954 100644 --- a/backend/core/settings/unfold_conf.py +++ b/backend/core/settings/unfold_conf.py @@ -268,6 +268,11 @@ UNFOLD = { "icon": "photo_prints", "link": reverse_lazy("admin:product_productvariant_changelist"), }, + { + "title": _("بخش جزيیات محصول"), + "icon": "subject", + "link": reverse_lazy("admin:product_productdetailmodel_changelist"), + }, ], }, diff --git a/backend/product/admin.py b/backend/product/admin.py index a7d6e19..14f7458 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin, messages +from product.tasks import update_prices from .models import * from unfold.admin import TabularInline, StackedInline from home.models import LearnVideoModel @@ -122,7 +123,7 @@ class DetailModelAdmin(ModelAdmin, ImportExportModelAdmin): class ProductDetailModel1Admin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm - search_fields = ['detail_category__title'] + search_fields = ['detail_category__title', 'name'] compressed_fields = True warn_unsaved_form = True @@ -216,8 +217,7 @@ class ProductModelAdmin(ModelAdmin, ImportExportModelAdmin): @action(description=f"اپدیت قیمت ها") def update_products_price(self, request): - print('from the button') - ProductVariant.update_all_prices() + # update_prices() messages.success(request, f"قیمت {ProductVariant.objects.all().count()} تنوع محصول اپدیت شد") return redirect("admin:product_productmodel_changelist") diff --git a/backend/product/migrations/0037_productdetailmodel_name.py b/backend/product/migrations/0037_productdetailmodel_name.py new file mode 100644 index 0000000..c93a035 --- /dev/null +++ b/backend/product/migrations/0037_productdetailmodel_name.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.2 on 2025-04-21 23:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0036_alter_productdetailmodel_detail_category'), + ] + + operations = [ + migrations.AddField( + model_name='productdetailmodel', + name='name', + field=models.CharField(default=1, help_text='این متن فقط برای راحتی در استفاده از پنل ادمین میباشد', max_length=50, verbose_name='نام جزيیات'), + preserve_default=False, + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index e3459e7..1a87333 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -213,6 +213,7 @@ class ProductImageModel(models.Model): class ProductDetailModel(models.Model): + name = models.CharField(max_length=50, verbose_name='نام جزيیات', help_text='این متن فقط برای راحتی در استفاده از پنل ادمین میباشد') detail_category = models.ForeignKey(ProductDetailCategory, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات') detail = models.ManyToManyField(DetailModel, verbose_name='جزيات ها') @@ -220,7 +221,7 @@ class ProductDetailModel(models.Model): verbose_name = 'جزیات محصول' verbose_name_plural = 'جزیات محصول ها' def __str__(self): - return f'جزيیات محصول {self.detail_category.title}' + return f'جزيیات محصول {self.detail_category.title} - {self.name}' class ProductVariant(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول') From 50f5d19aa346d83817050a18706d15f4fed655db Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 22 Apr 2025 03:11:53 +0330 Subject: [PATCH 06/10] debug import --- backend/product/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/product/admin.py b/backend/product/admin.py index 14f7458..80ac965 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin, messages -from product.tasks import update_prices +# from product.tasks import update_prices from .models import * from unfold.admin import TabularInline, StackedInline from home.models import LearnVideoModel From 764c2625157f87f2ce7d4c9f3fcc957a3bdc1a55 Mon Sep 17 00:00:00 2001 From: marzban-dev Date: Tue, 22 Apr 2025 18:24:11 +0330 Subject: [PATCH 07/10] Updated --- ...ent-progress.gif => heymlz-payment-progress.gif} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename frontend/public/img/heymlz/{payment-progress.gif => heymlz-payment-progress.gif} (100%) diff --git a/frontend/public/img/heymlz/payment-progress.gif b/frontend/public/img/heymlz/heymlz-payment-progress.gif similarity index 100% rename from frontend/public/img/heymlz/payment-progress.gif rename to frontend/public/img/heymlz/heymlz-payment-progress.gif From 0e1369146f4274c988ccf4a6f25ca1626a5d555a Mon Sep 17 00:00:00 2001 From: marzban-dev Date: Tue, 22 Apr 2025 18:24:17 +0330 Subject: [PATCH 08/10] Updated --- frontend/components/cart/checkout/PaymentPendingModal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/cart/checkout/PaymentPendingModal.vue b/frontend/components/cart/checkout/PaymentPendingModal.vue index b6ff9b6..75a6c7c 100644 --- a/frontend/components/cart/checkout/PaymentPendingModal.vue +++ b/frontend/components/cart/checkout/PaymentPendingModal.vue @@ -47,7 +47,7 @@ const visible = computed({ >
From c79a5ee1ca09a783c21091117899c8c9c710dff4 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 22 Apr 2025 20:54:20 +0330 Subject: [PATCH 09/10] rebuild of detail of product --- backend/product/admin.py | 11 ++++++- .../migrations/0038_detailmodel_name.py | 19 +++++++++++ ...move_productdetailmodel_detail_and_more.py | 24 ++++++++++++++ .../0040_remove_detailmodel_name.py | 17 ++++++++++ backend/product/models.py | 32 +++++++++---------- backend/product/serializers.py | 6 ++-- 6 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 backend/product/migrations/0038_detailmodel_name.py create mode 100644 backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py create mode 100644 backend/product/migrations/0040_remove_detailmodel_name.py diff --git a/backend/product/admin.py b/backend/product/admin.py index 80ac965..1f1b709 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -119,6 +119,14 @@ class DetailModelAdmin(ModelAdmin, ImportExportModelAdmin): "widget": ArrayWidget, } } + +class DetailInLine(StackedInline): + model = DetailModel + extra = 0 + show_change_link = True + min_num = 1 + max_num = 4 + @admin.register(ProductDetailModel) class ProductDetailModel1Admin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm @@ -126,7 +134,8 @@ class ProductDetailModel1Admin(ModelAdmin, ImportExportModelAdmin): search_fields = ['detail_category__title', 'name'] compressed_fields = True warn_unsaved_form = True - + autocomplete_fields = ['detail_category',] + inlines = [DetailInLine] formfield_overrides = { ArrayField: { "widget": ArrayWidget, diff --git a/backend/product/migrations/0038_detailmodel_name.py b/backend/product/migrations/0038_detailmodel_name.py new file mode 100644 index 0000000..33082ac --- /dev/null +++ b/backend/product/migrations/0038_detailmodel_name.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.2 on 2025-04-22 16:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0037_productdetailmodel_name'), + ] + + operations = [ + migrations.AddField( + model_name='detailmodel', + name='name', + field=models.CharField(default='', help_text='این فیلد فقط برای راحتی در استفاده و جست و جو در پنل ادمین میباشد و در وبسایت نمایش نخواهد داده شد', max_length=50, verbose_name='نام چزيیات'), + preserve_default=False, + ), + ] diff --git a/backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py b/backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py new file mode 100644 index 0000000..909f196 --- /dev/null +++ b/backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.2 on 2025-04-22 17:02 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0038_detailmodel_name'), + ] + + operations = [ + migrations.RemoveField( + model_name='productdetailmodel', + name='detail', + ), + migrations.AddField( + model_name='detailmodel', + name='detail_model', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='product.productdetailmodel', verbose_name='دسته بندی جزيات'), + preserve_default=False, + ), + ] diff --git a/backend/product/migrations/0040_remove_detailmodel_name.py b/backend/product/migrations/0040_remove_detailmodel_name.py new file mode 100644 index 0000000..d12ad16 --- /dev/null +++ b/backend/product/migrations/0040_remove_detailmodel_name.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.2 on 2025-04-22 17:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0039_remove_productdetailmodel_detail_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='detailmodel', + name='name', + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index 1a87333..7d8c160 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -129,18 +129,6 @@ class ProductModel(models.Model): -class DetailModel(models.Model): - title = models.CharField(max_length=50, verbose_name='عنوان') - detail_text1 = models.CharField(max_length=150 , verbose_name='متن جزیات ۱') - detail_text2 = models.CharField(max_length=150 , verbose_name='متن جزیات ۲', blank=True, null=True) - detail_text3 = models.CharField(max_length=150 , verbose_name='متن جزیات ۳', blank=True, null=True) - detail_text4 = models.CharField(max_length=150 , verbose_name='متن جزیات ۴', blank=True, null=True) - def __str__(self): - return self.title - - class Meta: - verbose_name = 'مدل جزیات' - verbose_name_plural = 'مدل های جزیات' class ProductDetailCategory(models.Model): @@ -176,8 +164,6 @@ class CommentModel(models.Model): def __str__(self): return f"{self.user}-{self.content[:30]}" - - class AttributeType(models.Model): name = models.CharField(verbose_name='نام نوع متغییر', max_length=100) @@ -199,7 +185,6 @@ class AttributeValue(models.Model): def __str__(self): return f"{self.attribute_type}: {self.value}" - class ProductImageModel(models.Model): name = models.CharField(max_length=30, verbose_name='نام عکس') image = models.ImageField(upload_to='product_images/') @@ -215,7 +200,6 @@ class ProductImageModel(models.Model): class ProductDetailModel(models.Model): name = models.CharField(max_length=50, verbose_name='نام جزيیات', help_text='این متن فقط برای راحتی در استفاده از پنل ادمین میباشد') detail_category = models.ForeignKey(ProductDetailCategory, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات') - detail = models.ManyToManyField(DetailModel, verbose_name='جزيات ها') class Meta: verbose_name = 'جزیات محصول' @@ -223,6 +207,22 @@ class ProductDetailModel(models.Model): def __str__(self): return f'جزيیات محصول {self.detail_category.title} - {self.name}' + +class DetailModel(models.Model): + title = models.CharField(max_length=50, verbose_name='عنوان') + detail_text1 = models.CharField(max_length=150 , verbose_name='متن جزیات ۱') + detail_text2 = models.CharField(max_length=150 , verbose_name='متن جزیات ۲', blank=True, null=True) + detail_text3 = models.CharField(max_length=150 , verbose_name='متن جزیات ۳', blank=True, null=True) + detail_text4 = models.CharField(max_length=150 , verbose_name='متن جزیات ۴', blank=True, null=True) + detail_model = models.ForeignKey(ProductDetailModel, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات', related_name='details') + def __str__(self): + return f'{self.title}' + + class Meta: + verbose_name = 'مدل جزیات' + verbose_name_plural = 'مدل های جزیات' + + class ProductVariant(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول') product_attributes = models.ManyToManyField(AttributeValue, verbose_name='ویژگی‌ها', related_name='variant') diff --git a/backend/product/serializers.py b/backend/product/serializers.py index 984b8f0..af7cf93 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -10,14 +10,14 @@ from django.contrib.auth.models import AnonymousUser class DetailSerializer(serializers.ModelSerializer): class Meta: model = DetailModel - fields = '__all__' + exclude = ['detail_model'] class ProductDetailSerializer(serializers.ModelSerializer): - detail = DetailSerializer(many=True, read_only=True) + details = DetailSerializer(many=True, read_only=True) detail_category = serializers.StringRelatedField() class Meta: model = ProductDetailModel - fields = "__all__" + exclude = ['name'] class AttributeTypeSerialzier(serializers.ModelSerializer): From 07c779d52492e39ccb1cce5b8cd35c816d8deaa3 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 22 Apr 2025 21:34:51 +0330 Subject: [PATCH 10/10] FIX migration file --- .../0039_remove_productdetailmodel_detail_and_more.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py b/backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py index 909f196..ce6f375 100644 --- a/backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py +++ b/backend/product/migrations/0039_remove_productdetailmodel_detail_and_more.py @@ -18,7 +18,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='detailmodel', name='detail_model', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='product.productdetailmodel', verbose_name='دسته بندی جزيات'), + field=models.ForeignKey(default=2, on_delete=django.db.models.deletion.CASCADE, to='product.productdetailmodel', verbose_name='دسته بندی جزيات'), preserve_default=False, ), ]