Compare commits

...

6 Commits

6 changed files with 55 additions and 13 deletions

View File

@ -26,6 +26,12 @@ class UserSerializer(serializers.ModelSerializer):
return obj.invited_users_with_orders.count() return obj.invited_users_with_orders.count()
class UserSimpleSerializer(UserSerializer):
class Meta:
model = UserSerializer.Meta.model
fields = ('id', 'email', 'phone', 'role', 'name', 'lastname', 'surname')
def non_zero_validator(value): def non_zero_validator(value):
if value == 0: if value == 0:
raise serializers.ValidationError("Value cannot be zero") raise serializers.ValidationError("Value cannot be zero")

View File

@ -1,5 +1,6 @@
from functools import reduce from functools import reduce
from django_filters import DateFromToRangeFilter as _DateFromToRangeFilter
from rest_framework.fields import DecimalField from rest_framework.fields import DecimalField
@ -11,3 +12,11 @@ class PriceField(DecimalField):
def deep_get(dictionary, *keys, default=None): def deep_get(dictionary, *keys, default=None):
"""Get value from a nested dictionary (JSON)""" """Get value from a nested dictionary (JSON)"""
return reduce(lambda d, key: d.get(key, None) if isinstance(d, dict) else default, keys, dictionary) return reduce(lambda d, key: d.get(key, None) if isinstance(d, dict) else default, keys, dictionary)
class DateFromToRangeFilter(_DateFromToRangeFilter):
""" DateFromToRangeFilter with replaced after/before suffixes to from/to """
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.field.widget.suffixes = ['from', 'to']

View File

@ -1,5 +1,6 @@
from django_filters import rest_framework as filters from django_filters import rest_framework as filters
from poizonstore.utils import DateFromToRangeFilter
from .models import Checklist, Gift from .models import Checklist, Gift
@ -18,9 +19,12 @@ class ChecklistFilter(filters.FilterSet):
status = filters.MultipleChoiceFilter(choices=Checklist.Status.CHOICES) status = filters.MultipleChoiceFilter(choices=Checklist.Status.CHOICES)
delivery_code = filters.CharFilter(method='filter_delivery_code') delivery_code = filters.CharFilter(method='filter_delivery_code')
created_at = DateFromToRangeFilter()
status_updated_at = DateFromToRangeFilter()
class Meta: class Meta:
model = Checklist model = Checklist
fields = ('status', 'delivery_code') fields = ('status', 'delivery_code', 'created_at', 'status_updated_at')
def filter_delivery_code(self, queryset, name, value): def filter_delivery_code(self, queryset, name, value):
return queryset.filter(poizon_tracking__iendswith=value) return queryset.filter(poizon_tracking__iendswith=value)

View File

@ -3,7 +3,7 @@ from drf_extra_fields.fields import Base64ImageField
from rest_framework import serializers from rest_framework import serializers
from bonus_program.models import BonusProgram from bonus_program.models import BonusProgram
from account.serializers import UserSerializer from account.serializers import UserSimpleSerializer
from utils.exceptions import CRMException from utils.exceptions import CRMException
from store.models import Checklist, Category, PaymentMethod, Promocode, Image, Gift from store.models import Checklist, Category, PaymentMethod, Promocode, Image, Gift
from store.utils import get_primary_key_related_model from store.utils import get_primary_key_related_model
@ -94,7 +94,7 @@ class ChecklistSerializer(serializers.ModelSerializer):
commission_rub = PriceField(read_only=True) commission_rub = PriceField(read_only=True)
customer = get_primary_key_related_model(UserSerializer, required=False, allow_null=True) customer = get_primary_key_related_model(UserSimpleSerializer, required=False, allow_null=True)
receiver_name = serializers.CharField(required=False, allow_null=True) receiver_name = serializers.CharField(required=False, allow_null=True)
receiver_phone = serializers.CharField(required=False, allow_null=True) receiver_phone = serializers.CharField(required=False, allow_null=True)
@ -193,6 +193,17 @@ class ChecklistSerializer(serializers.ModelSerializer):
) )
class ChecklistListSerializer(ChecklistSerializer):
class Meta:
model = ChecklistSerializer.Meta.model
fields = ('id', 'status',
'category', 'brand', 'model', 'size', 'preview_image_url',
'price_yuan', 'price_rub', 'full_price', 'real_price',
'comment',
'poizon_tracking', 'cdek_tracking', 'delivery', 'delivery_display',
'created_at', 'status_updated_at')
class ClientChecklistSerializerMixin: class ClientChecklistSerializerMixin:
def validate(self, attrs): def validate(self, attrs):
gift = attrs.get('gift') gift = attrs.get('gift')

View File

@ -14,13 +14,13 @@ from rest_framework.response import Response
from external_api.cdek import CDEKClient, CDEKWebhookTypes, CDEK_STATUS_TO_ORDER_STATUS from external_api.cdek import CDEKClient, CDEKWebhookTypes, CDEK_STATUS_TO_ORDER_STATUS
from external_api.poizon import PoizonClient from external_api.poizon import PoizonClient
from utils.exceptions import CRMException from utils.exceptions import CRMException, Forbidden
from store.filters import GiftFilter, ChecklistFilter from store.filters import GiftFilter, ChecklistFilter
from store.models import Checklist, Category, PaymentMethod, Promocode, Gift from store.models import Checklist, Category, PaymentMethod, Promocode, Gift
from core.models import GlobalSettings from core.models import GlobalSettings
from store.serializers import (ChecklistSerializer, CategorySerializer, CategoryFullSerializer, from store.serializers import (ChecklistSerializer, CategorySerializer, CategoryFullSerializer,
PaymentMethodSerializer, PromocodeSerializer, ClientUpdateChecklistSerializer, PaymentMethodSerializer, PromocodeSerializer, ClientUpdateChecklistSerializer,
GiftSerializer, ClientCreateChecklistSerializer) GiftSerializer, ClientCreateChecklistSerializer, ChecklistListSerializer)
from account.permissions import ReadOnly, IsManager, IsAdmin from account.permissions import ReadOnly, IsManager, IsAdmin
@ -63,7 +63,7 @@ class ChecklistAPI(viewsets.ModelViewSet):
super().permission_denied(request, **kwargs) super().permission_denied(request, **kwargs)
def get_serializer_class(self): def get_serializer_class(self):
# Managers have a full set of fields # Managers have a full set of fields for editing
if getattr(self.request.user, 'is_manager', False) or self.action == 'retrieve': if getattr(self.request.user, 'is_manager', False) or self.action == 'retrieve':
return ChecklistSerializer return ChecklistSerializer
@ -75,15 +75,17 @@ class ChecklistAPI(viewsets.ModelViewSet):
elif self.action in ['update', 'partial_update', 'destroy']: elif self.action in ['update', 'partial_update', 'destroy']:
return ClientUpdateChecklistSerializer return ClientUpdateChecklistSerializer
# Simplified list serializer
elif self.action == "list":
return ChecklistListSerializer
# Fallback to error # Fallback to error
self.permission_denied(self.request, **self.kwargs) self.permission_denied(self.request, **self.kwargs)
def get_permissions(self): def get_permissions(self):
if self.action in ['list', 'update', 'partial_update']: if self.action == 'retrieve':
self.permission_classes = [IsManager]
elif self.action == 'retrieve':
self.permission_classes = [AllowAny] self.permission_classes = [AllowAny]
elif self.action in ['create', 'destroy']: elif self.action in ['create', 'list', 'update', 'partial_update', 'destroy']:
self.permission_classes = [IsAuthenticated] self.permission_classes = [IsAuthenticated]
return super().get_permissions() return super().get_permissions()
@ -92,15 +94,21 @@ class ChecklistAPI(viewsets.ModelViewSet):
# Non-managers can cancel orders only in certain statuses # Non-managers can cancel orders only in certain statuses
if (not getattr(self.request.user, 'is_manager', False) if (not getattr(self.request.user, 'is_manager', False)
and obj.status not in Checklist.Status.CANCELLABLE_ORDER_STATUSES): and obj.status not in Checklist.Status.CANCELLABLE_ORDER_STATUSES):
raise CRMException("Can't delete the order") raise Forbidden("Can't delete the order")
obj.cancel() obj.cancel()
def get_queryset(self): def get_queryset(self):
return Checklist.objects.with_base_related() \ qs = Checklist.objects.with_base_related() \
.annotate_bonus_used() \ .annotate_bonus_used() \
.default_ordering() .default_ordering()
# Non-managers can list only their own orders
if not getattr(self.request.user, 'is_manager', False):
qs = qs.filter(customer_id=self.request.user.id)
return qs
def get_object(self): def get_object(self):
obj: Checklist = super().get_object() obj: Checklist = super().get_object()
@ -126,9 +134,10 @@ class CategoryAPI(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.Updat
class PaymentMethodsAPI(mixins.ListModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet): class PaymentMethodsAPI(mixins.ListModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
serializer_class = PaymentMethodSerializer serializer_class = PaymentMethodSerializer
permission_classes = [IsManager | ReadOnly] permission_classes = [IsAdmin | ReadOnly]
lookup_field = 'slug' lookup_field = 'slug'
queryset = PaymentMethod.objects.all() queryset = PaymentMethod.objects.all()
pagination_class = None
class PromoCodeAPI(viewsets.ModelViewSet): class PromoCodeAPI(viewsets.ModelViewSet):

View File

@ -12,4 +12,7 @@ class CRMException(APIException):
self.detail = {'error': detail} self.detail = {'error': detail}
class Forbidden(CRMException):
status_code = status.HTTP_403_FORBIDDEN
# TODO: exceptions with a same template: ok / error_code / error_message # TODO: exceptions with a same template: ok / error_code / error_message