From dd9dfb3704f97724e70da8360c0240de4363836d Mon Sep 17 00:00:00 2001 From: phzhik Date: Tue, 31 Oct 2023 16:50:45 +0400 Subject: [PATCH] + Gift --- store/admin.py | 7 ++++- store/filters.py | 14 +++++++++ .../migrations/0045_gift_alter_image_type.py | 31 +++++++++++++++++++ ...046_checklist_gift_alter_gift_min_price.py | 24 ++++++++++++++ store/models.py | 20 +++++++++++- store/serializers.py | 14 +++++++-- store/urls.py | 1 + store/views.py | 12 +++++-- 8 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 store/filters.py create mode 100644 store/migrations/0045_gift_alter_image_type.py create mode 100644 store/migrations/0046_checklist_gift_alter_gift_min_price.py diff --git a/store/admin.py b/store/admin.py index 88d1cd4..8d1a1c6 100644 --- a/store/admin.py +++ b/store/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from django.contrib.admin import display from mptt.admin import MPTTModelAdmin -from .models import Category, Checklist, GlobalSettings, PaymentMethod, Promocode, User, Image +from .models import Category, Checklist, GlobalSettings, PaymentMethod, Promocode, User, Image, Gift @admin.register(User) @@ -52,5 +52,10 @@ class PromoCodeAdmin(admin.ModelAdmin): list_display = ('name', 'discount', 'free_delivery', 'no_comission') +@admin.register(Gift) +class GiftAdmin(admin.ModelAdmin): + list_display = ('name', 'min_price') + + diff --git a/store/filters.py b/store/filters.py new file mode 100644 index 0000000..72700e4 --- /dev/null +++ b/store/filters.py @@ -0,0 +1,14 @@ +from django_filters import rest_framework as filters + +from .models import Gift + + +class GiftFilter(filters.FilterSet): + for_price = filters.NumberFilter(method='filter_for_price') + + class Meta: + model = Gift + fields = ('for_price',) + + def filter_for_price(self, queryset, name, value): + return queryset.filter(min_price__lte=value) diff --git a/store/migrations/0045_gift_alter_image_type.py b/store/migrations/0045_gift_alter_image_type.py new file mode 100644 index 0000000..6db0e2e --- /dev/null +++ b/store/migrations/0045_gift_alter_image_type.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.2 on 2023-10-25 15:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0044_checklist_split_accepted'), + ] + + operations = [ + migrations.CreateModel( + name='Gift', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, verbose_name='Название')), + ('image', models.ImageField(blank=True, null=True, upload_to='gifts/', verbose_name='Фото')), + ('min_price', models.DecimalField(decimal_places=2, default=0, help_text='от какой суммы доступен подарок', max_digits=10, verbose_name='Минимальная цена')), + ], + options={ + 'verbose_name': 'Подарок', + 'verbose_name_plural': 'Подарки', + }, + ), + migrations.AlterField( + model_name='image', + name='type', + field=models.PositiveSmallIntegerField(choices=[(0, 'Изображение'), (1, 'Превью'), (2, 'Документ'), (3, 'Подарок')], default=0, verbose_name='Тип'), + ), + ] diff --git a/store/migrations/0046_checklist_gift_alter_gift_min_price.py b/store/migrations/0046_checklist_gift_alter_gift_min_price.py new file mode 100644 index 0000000..55c2abe --- /dev/null +++ b/store/migrations/0046_checklist_gift_alter_gift_min_price.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.2 on 2023-10-25 15:43 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0045_gift_alter_image_type'), + ] + + operations = [ + migrations.AddField( + model_name='checklist', + name='gift', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='store.gift', verbose_name='Подарок'), + ), + migrations.AlterField( + model_name='gift', + name='min_price', + field=models.DecimalField(decimal_places=2, default=0, help_text='от какой суммы доступен подарок', max_digits=10, verbose_name='Минимальная цена в юанях'), + ), + ] diff --git a/store/models.py b/store/models.py index 4970ac3..47bb055 100644 --- a/store/models.py +++ b/store/models.py @@ -204,17 +204,20 @@ class Image(models.Model): DEFAULT = 0 PREVIEW = 1 DOC = 2 + GIFT = 3 TYPE_CHOICES = ( (DEFAULT, 'Изображение'), (PREVIEW, 'Превью'), (DOC, 'Документ'), + (GIFT, 'Подарок'), ) TYPE_TO_UPLOAD_PATH = { DEFAULT: 'checklist_images/', PREVIEW: 'checklist_images/', DOC: 'docs/', + GIFT: 'gifts/', } image = models.ImageField('Файл изображения', upload_to=image_upload_path) @@ -228,6 +231,19 @@ class Image(models.Model): return f"{self.get_type_display()}: {getattr(self.image, 'name', '')}" +class Gift(models.Model): + name = models.CharField('Название', max_length=100) + image = models.ImageField('Фото', upload_to=Image.TYPE_TO_UPLOAD_PATH[Image.GIFT], null=True, blank=True) + min_price = models.DecimalField('Минимальная цена в юанях', help_text='от какой суммы доступен подарок', max_digits=10, decimal_places=2, default=0) + + def __str__(self): + return self.name + + class Meta: + verbose_name = 'Подарок' + verbose_name_plural = 'Подарки' + + def generate_checklist_id(): """ Generate unique id for Checklist """ @@ -242,7 +258,8 @@ def generate_checklist_id(): class ChecklistQuerySet(models.QuerySet): def with_base_related(self): - return self.select_related('manager', 'category', 'payment_method', 'promocode', 'price_snapshot')\ + return self.select_related('manager', 'category', 'payment_method', + 'promocode', 'price_snapshot', 'gift') \ .prefetch_related(Prefetch('images', to_attr='_images')) def default_ordering(self): @@ -341,6 +358,7 @@ class Checklist(models.Model): # promo promocode = models.ForeignKey('Promocode', verbose_name='Промокод', on_delete=models.PROTECT, null=True, blank=True) + gift = models.ForeignKey('Gift', verbose_name='Подарок', on_delete=models.PROTECT, null=True, blank=True) comment = models.CharField('Комментарий', max_length=200, null=True, blank=True) # buyername diff --git a/store/serializers.py b/store/serializers.py index 90a8f91..3d3cf20 100644 --- a/store/serializers.py +++ b/store/serializers.py @@ -1,7 +1,7 @@ from drf_extra_fields.fields import Base64ImageField from rest_framework import serializers -from store.models import User, Checklist, GlobalSettings, Category, PaymentMethod, Promocode, Image +from store.models import User, Checklist, GlobalSettings, Category, PaymentMethod, Promocode, Image, Gift from store.utils import get_primary_key_related_model @@ -63,6 +63,14 @@ class CategoryFullSerializer(CategorySerializer): fields = CategorySerializer.Meta.fields + ('children',) +class GiftSerializer(serializers.ModelSerializer): + image = Base64ImageField(required=False, allow_null=True) + + class Meta: + model = Gift + fields = ('id', 'name', 'image', 'min_price') + + class ChecklistSerializer(serializers.ModelSerializer): id = serializers.CharField(read_only=True) managerid = serializers.PrimaryKeyRelatedField(source='manager_id', read_only=True, allow_null=True) @@ -77,6 +85,8 @@ class ChecklistSerializer(serializers.ModelSerializer): promo = serializers.SlugRelatedField(source='promocode', slug_field='name', queryset=Promocode.objects.active(), required=False, allow_null=True) + gift = get_primary_key_related_model(GiftSerializer, required=False, allow_null=True) + currency = serializers.DecimalField(source='yuan_rate', read_only=True, max_digits=10, decimal_places=2) curencycurency2 = serializers.DecimalField(source='price_yuan', required=False, max_digits=10, decimal_places=2) currency3 = serializers.IntegerField(source='price_rub', read_only=True) @@ -165,7 +175,7 @@ class ChecklistSerializer(serializers.ModelSerializer): 'image', 'previewimage', 'currency', 'curencycurency2', 'currency3', 'chinadelivery', 'chinadelivery2', 'commission', - 'promo', + 'promo', 'gift', 'comment', 'fullprice', 'realprice', 'buyername', 'buyerphone', 'tg', diff --git a/store/urls.py b/store/urls.py index 7f2b265..c96ac00 100644 --- a/store/urls.py +++ b/store/urls.py @@ -8,6 +8,7 @@ router = DefaultRouter() router.register(r'statistics', views.StatisticsAPI, basename='statistics') router.register(r'cdek', views.CDEKAPI, basename='cdek') +router.register(r'gifts', views.GiftAPI, basename='gifts') urlpatterns = [ path("checklist/", views.ChecklistAPI.as_view()), diff --git a/store/views.py b/store/views.py index 8eea6c4..1357676 100644 --- a/store/views.py +++ b/store/views.py @@ -13,10 +13,11 @@ from rest_framework.response import Response from external_api.cdek import CDEKClient from store.exceptions import CRMException -from store.models import Checklist, GlobalSettings, Category, PaymentMethod, Promocode +from store.filters import GiftFilter +from store.models import Checklist, GlobalSettings, Category, PaymentMethod, Promocode, Gift from store.serializers import (ChecklistSerializer, CategorySerializer, CategoryFullSerializer, PaymentMethodSerializer, GlobalSettingsSerializer, - PromocodeSerializer, AnonymousUserChecklistSerializer) + PromocodeSerializer, AnonymousUserChecklistSerializer, GiftSerializer) from utils.permissions import ReadOnly @@ -184,6 +185,13 @@ class PromoCodeAPI(mixins.CreateModelMixin, generics.GenericAPIView): return Response(status=status.HTTP_204_NO_CONTENT) +class GiftAPI(viewsets.ModelViewSet): + queryset = Gift.objects.all() + serializer_class = GiftSerializer + permission_classes = [IsAuthenticated | ReadOnly] + filterset_class = GiftFilter + + class StatisticsAPI(viewsets.GenericViewSet): def get_queryset(self): return Checklist.objects.all() \