diff --git a/backend/home/views.py b/backend/home/views.py index eeb8e40..99817bb 100644 --- a/backend/home/views.py +++ b/backend/home/views.py @@ -24,11 +24,20 @@ class HomeView(APIView): sliders = SliderModel.objects.all() slider_ser = SliderSerializer(instance=sliders, many=True, context={'request': request}) - main_categories = MainCategoryModel.objects.all() + main_categories = MainCategoryModel.objects.filter(show_in_home=True) main_category_ser = MainCategorySerializer(instance=main_categories, many=True, context={'request': request}) - products_to_show = ProductModel.objects.filter(show=True) - product_ser = DynamicProductSerializer(instance=products_to_show, many=True, context={'request': request, 'view_type': 'list'}) + top_seller_products = ProductModel.objects.filter(show_in_top_seller=True) + top_seller_products_ser = DynamicProductSerializer(instance=top_seller_products, many=True, context={'request': request, 'view_type': 'list'}) + + lot_of_discount_products = ProductModel.objects.filter(show_in_lot_of_discount=True) + lot_of_discount_products_ser = DynamicProductSerializer(instance=lot_of_discount_products, many=True, context={'request': request, 'view_type': 'list'}) + + most_viewed_products = ProductModel.objects.filter(show_in_most_viewed=True) + most_viewed_products_ser = DynamicProductSerializer(instance=most_viewed_products, many=True, context={'request': request, 'view_type': 'list'}) + + trends_products = ProductModel.objects.filter(show_in_trends=True) + trends_products_ser = DynamicProductSerializer(instance=trends_products, many=True, context={'request': request, 'view_type': 'list'}) home_image = HomeImageModel.objects.all().first() home_image_ser = HomeImageSerializer(instance=home_image, context={'request': request}) @@ -39,7 +48,11 @@ class HomeView(APIView): response = { 'sliders': slider_ser.data, 'main_categories': main_category_ser.data, - 'products': product_ser.data, + 'products': [], + 'top_seller_products': top_seller_products_ser.data, + 'lot_of_discount_products': lot_of_discount_products_ser.data, + 'most_viewed_products': most_viewed_products_ser.data, + 'trends_products': trends_products_ser.data, 'difreance_section': home_image_ser.data, 'show_case_slider': show_cases_ser.data } diff --git a/backend/product/admin.py b/backend/product/admin.py index 94fab0b..c3684e7 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -12,6 +12,7 @@ from unfold.widgets import UnfoldAdminColorInputWidget from unfold.decorators import action, display from utils.admin import ModelAdmin from django.shortcuts import redirect, render +from django.utils.html import format_html from .permissions import ProductDetailCategoryPermission, ProductAdminPermission, ProductVariantAdminPermission, ProductVariantInlineAdminPermission, InPackItemsAdminPermission, AttributeTypeAdminPermission, AttributeValueAdminPermission from django import forms @@ -295,16 +296,16 @@ class ProductModelAdmin(ProductAdminPermission, ModelAdmin, ImportExportModelAdm inlines = [ProductVariantInLine] readonly_fields = ('slug', 'created_at') search_fields = ['name', 'description', ] - list_filter = ['show', ('category', RelatedDropdownFilter), 'show_in_bot', ('category__parent', RelatedDropdownFilter)] + list_filter = [('category', RelatedDropdownFilter), 'show_in_bot', ('category__parent', RelatedDropdownFilter)] list_filter_submit = True autocomplete_fields = ['related_products', 'shop', 'category'] # compressed_fields = True warn_unsaved_form = True # list_per_page = 2 actions_list = ['redirect_to_learn', 'update_products_price'] - list_display = ['display_image', 'shop__shop_name','display_price', 'view', 'show', 'rating', 'category', 'created_at'] + list_display = ['display_image', 'shop__shop_name','display_price', 'view', 'rating', 'category', 'created_at' ,'show_in_website', ] fieldsets = ( - ('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'image', 'related_products', 'show', 'shop', 'show_in_bot', 'bot_banner'), "classes": ["tab"],}), + ('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'image', 'related_products','show_in_trends', 'show_in_most_viewed', 'show_in_lot_of_discount', 'show_in_top_seller', 'shop', 'show_in_bot', 'bot_banner'), "classes": ["tab"],}), ('فیلد های سيو', {'fields': ('meta_description', 'meta_keywords', 'meta_rating', 'slug'), "classes": ["tab"],}), ('فیلد های مربوط به کاربر', {'fields': ('rating', 'view',), "classes": ["tab"],}), # ('فیلد های ایتم های پک', {'fields': ('in_pack_items', ), "classes": ["tab"],}) @@ -324,13 +325,18 @@ class ProductModelAdmin(ProductAdminPermission, ModelAdmin, ImportExportModelAdm if request.user.is_superuser: return ['slug', 'created_at'] else: - return ['show_in_bot', 'bot_banner', 'created_at', 'show', 'meta_description', 'meta_keywords', 'meta_rating', 'rating', 'view', 'slug'] + return ['show_in_bot', 'bot_banner', 'created_at', 'show_in_top_seller','show_in_trends', 'show_in_most_viewed', 'show_in_lot_of_discount','meta_description', 'meta_keywords', 'meta_rating', 'rating', 'view', 'slug'] def display_price(self, obj): if obj.variants.all().first(): return obj.variants.all().first().price display_price.short_description = 'قیمت تومانی' + def show_in_website(self, obj): + url = f"https://heymlz.com/product/{obj.slug}" + return format_html('نمایش', url) + show_in_website.short_description = 'نمایش در سایت' + @display(description='محصول', header=True) def display_image(self, instance): if instance and instance.variants.first() and instance.variants.first().images.first(): @@ -398,15 +404,6 @@ class ProductModelAdmin(ProductAdminPermission, ModelAdmin, ImportExportModelAdm actions = ['bulk_update_subcategory_action'] - # @display( - # description=("نمایش در صفحه ی اصلی"), - # label={ - # True: "danger", - # False: "success", - # }, - # ) - # def display_show(self, instance): - # return instance.show @admin.register(MainCategoryModel) diff --git a/backend/product/migrations/0071_maincategorymodel_show_in_home.py b/backend/product/migrations/0071_maincategorymodel_show_in_home.py new file mode 100644 index 0000000..12a5446 --- /dev/null +++ b/backend/product/migrations/0071_maincategorymodel_show_in_home.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.2 on 2026-02-20 15:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0070_enable_pg_trgm'), + ] + + operations = [ + migrations.AddField( + model_name='maincategorymodel', + name='show_in_home', + field=models.BooleanField(default=False, verbose_name='نمایش در خانه'), + ), + ] diff --git a/backend/product/migrations/0072_remove_productmodel_product_show_idx_and_more.py b/backend/product/migrations/0072_remove_productmodel_product_show_idx_and_more.py new file mode 100644 index 0000000..60d91fb --- /dev/null +++ b/backend/product/migrations/0072_remove_productmodel_product_show_idx_and_more.py @@ -0,0 +1,58 @@ +# Generated by Django 5.1.2 on 2026-02-20 15:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0034_add_telegram_chat_id_to_shop'), + ('product', '0071_maincategorymodel_show_in_home'), + ] + + operations = [ + migrations.RemoveIndex( + model_name='productmodel', + name='product_show_idx', + ), + migrations.RemoveField( + model_name='productmodel', + name='show', + ), + migrations.AddField( + model_name='productmodel', + name='show_in_lot_of_discount', + field=models.BooleanField(default=False, verbose_name='نمایش در پر تخفیف ها'), + ), + migrations.AddField( + model_name='productmodel', + name='show_in_most_viewed', + field=models.BooleanField(default=False, verbose_name='نمایش در پر بازدید ها'), + ), + migrations.AddField( + model_name='productmodel', + name='show_in_top_seller', + field=models.BooleanField(default=False, verbose_name='نمایش در پر فروش ها'), + ), + migrations.AddField( + model_name='productmodel', + name='show_in_trends', + field=models.BooleanField(default=False, verbose_name='نمایش در ترند ها'), + ), + migrations.AddIndex( + model_name='productmodel', + index=models.Index(fields=['show_in_trends'], name='product_show_in_trends_idx'), + ), + migrations.AddIndex( + model_name='productmodel', + index=models.Index(fields=['show_in_most_viewed'], name='product_most_viewed_idx'), + ), + migrations.AddIndex( + model_name='productmodel', + index=models.Index(fields=['show_in_lot_of_discount'], name='product_lot_of_discount_idx'), + ), + migrations.AddIndex( + model_name='productmodel', + index=models.Index(fields=['show_in_top_seller'], name='product_show_in_top_seller_idx'), + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index 33fc412..1492992 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -58,6 +58,7 @@ class MainCategoryModel(models.Model): blank=True, null=True, verbose_name='ویدیو') parent = models.ForeignKey(UnitCategoryModel, on_delete=models.SET_NULL, related_name='maincategorys', verbose_name='دسته‌بندی والد', null=True) + show_in_home = models.BooleanField(default=False, verbose_name='نمایش در خانه') class Meta: verbose_name = "دسته‌بندی اصلی" verbose_name_plural = "دسته‌بندی‌هااصلی" @@ -180,7 +181,10 @@ class ProductModel(models.Model): description = models.TextField(verbose_name='توضیحات') image = models.ImageField(upload_to='product_main/', null=True, blank=True) rating = models.PositiveIntegerField(default=0, verbose_name='امتیاز') - show = models.BooleanField(default=False, verbose_name='نمایش در خانه') + show_in_trends = models.BooleanField(default=False, verbose_name='نمایش در ترند ها') + show_in_most_viewed = models.BooleanField(default=False, verbose_name='نمایش در پر بازدید ها') + show_in_lot_of_discount = models.BooleanField(default=False, verbose_name='نمایش در پر تخفیف ها') + show_in_top_seller = models.BooleanField(default=False, verbose_name='نمایش در پر فروش ها') view = models.IntegerField(default=0, verbose_name='بازدید') slug = models.SlugField(max_length=255, unique=True, blank=True, null=True, allow_unicode=True, verbose_name='نام یکتا', help_text="این فیلد را خالی بگذارید") @@ -223,7 +227,10 @@ class ProductModel(models.Model): models.Index(fields=['category'], name='product_category_idx'), models.Index(fields=['name'], name='product_name_idx'), models.Index(fields=['created_at'], name='product_created_at_idx'), - models.Index(fields=['show'], name='product_show_idx'), + models.Index(fields=['show_in_trends'], name='product_show_in_trends_idx'), + models.Index(fields=['show_in_most_viewed'], name='product_most_viewed_idx'), + models.Index(fields=['show_in_lot_of_discount'], name='product_lot_of_discount_idx'), + models.Index(fields=['show_in_top_seller'], name='product_show_in_top_seller_idx'), models.Index(fields=['category', 'created_at'], name='product_category_created_idx'), models.Index(fields=['category', 'name'], diff --git a/factor/factor.html b/factor/factor.html new file mode 100644 index 0000000..e389370 --- /dev/null +++ b/factor/factor.html @@ -0,0 +1,393 @@ + + + + + + صورت‌حساب الکترونیکی - فروشگاه هیملز + + + + +
+ +
+ +
+ QR +
+ + +
+
صورت حساب الکترونیکی
+
+ Logo +
+
فروشگاه هیملز
+
+ + +
+
فروشگاه
هی ملز
+ +
+
+
+ فرستنده :مقدار +
+
+ شناسه ملی :مقدار +
+
+ شماره ثبت :مقدار +
+
+ شماره مجوز :مقدار +
+
+ نشانی شرکت :مقدار +
+
+ کد پستی :مقدار +
+
+ تلفن و فکس :مقدار +
+
+
+ +
+
+
+ شماره فاکتور :مقدار +
+
تاریخ :مقدار
+
+ شماره پیگیری :مقدار +
+
+
+
+ + +
+
خریدار
+
+
+
خریدار :مقدار
+
+ شماره ملی :مقدار +
+
+ شماره تماس :مقدار +
+
+ کد پستی :مقدار +
+
نشانی :مقدار
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ردیفشناسه کالا یا خدماتشرح کالا یا خدماتتعدادمبلغ واحد (تومان)مبلغ کل (تومان)تخفیف (تومان)مبلغ کل پس از تخفیف (تومان)جمع مالیات و عوارض ارزش افزوده (تومان)جمع کل پس از تخفیف و مالیات و عوارض (تومان)
1---------------------------
جمع کل---------------------
+ جمع کل پس از کسر تخفیف با احتساب مالیات و عوارض (تومان) + ---
+ +
+
+ مهر و امضای فروشگاه :مقدار +
+
+ تاریخ تحویل :مقدار +
+
+ ساعت تحویل :مقدار +
+
+ روش های پرداخت :مقدار +
+
+ مهر و امضای خریدار :مقدار +
+
+
+
+ + diff --git a/factor/logo-pattern.png b/factor/logo-pattern.png new file mode 100644 index 0000000..f9f12fe Binary files /dev/null and b/factor/logo-pattern.png differ diff --git a/factor/logo2.png b/factor/logo2.png new file mode 100644 index 0000000..0a0ef47 Binary files /dev/null and b/factor/logo2.png differ diff --git a/factor/qr-code.png b/factor/qr-code.png new file mode 100644 index 0000000..c8cbf60 Binary files /dev/null and b/factor/qr-code.png differ diff --git a/frontend/components/global/product-detail/ProductsSlider.vue b/frontend/components/global/product-detail/ProductsSlider.vue index d2593c2..401149f 100644 --- a/frontend/components/global/product-detail/ProductsSlider.vue +++ b/frontend/components/global/product-detail/ProductsSlider.vue @@ -27,12 +27,12 @@ const onSwiper = (swiper: SwiperClass) => {