Compare commits
6 Commits
cfe2f68305
...
ca08955b38
| Author | SHA1 | Date | |
|---|---|---|---|
| ca08955b38 | |||
| a9c7e15e02 | |||
| 433f1ff180 | |||
| 72ade66fe1 | |||
| bae34e02c2 | |||
| d5d16d7cc8 |
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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']
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user