+ statistics by clients
+ cdek_tracking + checklist create API + some permissions * Cleanup
This commit is contained in:
parent
369dbf31ae
commit
4511a65b7f
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.admin import display
|
||||
|
||||
from .models import Category, Checklist, GlobalSettings, PaymentMethod, PromoCode, User, Image
|
||||
from .models import Category, Checklist, GlobalSettings, PaymentMethod, Promocode, User, Image
|
||||
|
||||
|
||||
@admin.register(User)
|
||||
|
|
@ -21,8 +22,12 @@ class ImageAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(Checklist)
|
||||
class ChecklistAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'date', 'price_rub', 'commission_rub')
|
||||
filter_horizontal = ('images',)
|
||||
list_display = ('id', 'brand', 'model', 'price_rub', 'commission_rub', 'date', 'status_display')
|
||||
ordering = ('-status_updated_at', '-created_at')
|
||||
|
||||
@display(description='Статус')
|
||||
def status_display(self, obj: Checklist):
|
||||
return obj.get_status_display()
|
||||
|
||||
def date(self, obj: Checklist):
|
||||
return obj.status_updated_at or obj.created_at
|
||||
|
|
@ -41,7 +46,7 @@ class PaymentMethodAdmin(admin.ModelAdmin):
|
|||
list_display = ('name', 'slug')
|
||||
|
||||
|
||||
@admin.register(PromoCode)
|
||||
@admin.register(Promocode)
|
||||
class PromoCodeAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'discount', 'free_delivery', 'no_comission')
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ from rest_framework.exceptions import APIException
|
|||
|
||||
|
||||
class CRMException(APIException):
|
||||
status_code = status.HTTP_400_BAD_REQUEST
|
||||
|
||||
def __init__(self, detail=None):
|
||||
if detail is None:
|
||||
detail = self.default_detail
|
||||
|
|
|
|||
|
|
@ -130,12 +130,15 @@ class User(AbstractUser):
|
|||
return concat_not_null_values(self.last_name, self.first_name, self.middle_name)
|
||||
|
||||
|
||||
class PromoCode(models.Model):
|
||||
class Promocode(models.Model):
|
||||
name = models.CharField('Название', max_length=100, unique=True)
|
||||
discount = models.DecimalField('Скидка', max_digits=10, decimal_places=2,)
|
||||
free_delivery = models.BooleanField('Бесплатная доставка', default=False) # freedelivery
|
||||
no_comission = models.BooleanField('Без комиссии', default=False) # nocomission
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Промокод'
|
||||
verbose_name_plural = 'Промокоды'
|
||||
|
|
@ -155,9 +158,11 @@ class PaymentMethod(models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
@cleanup.select
|
||||
class Image(models.Model):
|
||||
image = models.ImageField(upload_to='checklist_images')
|
||||
is_preview = models.BooleanField(default=False)
|
||||
checklist = models.ForeignKey('Checklist', on_delete=models.CASCADE, related_name='images')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Изображение'
|
||||
|
|
@ -168,6 +173,8 @@ class Image(models.Model):
|
|||
|
||||
|
||||
def generate_checklist_id():
|
||||
""" Generate unique id for Checklist """
|
||||
|
||||
all_ids = Checklist.objects.all().values_list('id', flat=True)
|
||||
allowed_chars = string.ascii_letters + string.digits
|
||||
|
||||
|
|
@ -226,18 +233,6 @@ class Checklist(models.Model):
|
|||
(COMPLETED, 'Завершен'),
|
||||
)
|
||||
|
||||
# Payment types
|
||||
class PaymentType:
|
||||
ALFA = "alfa"
|
||||
TINKOFF = "tink"
|
||||
RAIFFEISEN = "raif"
|
||||
|
||||
CHOICES = (
|
||||
(ALFA, 'Альфа-Банк'),
|
||||
(TINKOFF, 'Тинькофф Банк'),
|
||||
(RAIFFEISEN, 'Райффайзен Банк'),
|
||||
)
|
||||
|
||||
# Delivery
|
||||
class DeliveryType:
|
||||
PICKUP = "pickup"
|
||||
|
|
@ -249,7 +244,7 @@ class Checklist(models.Model):
|
|||
)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
status_updated_at = models.DateTimeField('Дата обновления статуса заказа')
|
||||
status_updated_at = models.DateTimeField('Дата обновления статуса заказа', auto_now_add=True)
|
||||
id = models.CharField(primary_key=True, max_length=settings.CHECKLIST_ID_LENGTH,
|
||||
default=generate_checklist_id, editable=False)
|
||||
status = models.CharField('Статус заказа', max_length=15, choices=Status.CHOICES, default=Status.NEW)
|
||||
|
|
@ -263,14 +258,12 @@ class Checklist(models.Model):
|
|||
model = models.CharField('Модель', max_length=100, null=True, blank=True)
|
||||
size = models.CharField('Размер', max_length=30, null=True, blank=True)
|
||||
|
||||
images = models.ManyToManyField('Image', verbose_name='Картинки', blank=True)
|
||||
|
||||
# curencycurency2
|
||||
price_yuan = models.DecimalField('Цена в юанях', max_digits=10, decimal_places=2, default=0)
|
||||
# TODO: replace by parser
|
||||
# TODO: replace real_price by parser
|
||||
real_price = models.DecimalField('Реальная цена', max_digits=10, decimal_places=2, null=True, blank=True)
|
||||
|
||||
# TODO: choose from PromoCode table
|
||||
# TODO: choose from Promocode table
|
||||
# promo
|
||||
promocode = models.CharField('Промокод', max_length=100, null=True, blank=True)
|
||||
comment = models.CharField('Комментарий', max_length=200, null=True, blank=True)
|
||||
|
|
@ -296,7 +289,8 @@ class Checklist(models.Model):
|
|||
|
||||
delivery = models.CharField('Тип доставки', max_length=10, choices=DeliveryType.CHOICES, null=True, blank=True)
|
||||
# trackid
|
||||
track_number = models.CharField('Трек-номер', max_length=100, null=True, blank=True)
|
||||
poizon_tracking = models.CharField('Трек-номер Poizon', max_length=100, null=True, blank=True)
|
||||
cdek_tracking = models.CharField('Трек-номер СДЭК', max_length=100, null=True, blank=True)
|
||||
|
||||
objects = ChecklistQuerySet.as_manager()
|
||||
|
||||
|
|
@ -359,9 +353,9 @@ class Checklist(models.Model):
|
|||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.id:
|
||||
old_obj = Checklist.objects.get(id=self.id)
|
||||
old_obj = Checklist.objects.filter(id=self.id).first()
|
||||
# If status was updated, update status_updated_at field
|
||||
if self.status != old_obj.status:
|
||||
if old_obj and self.status != old_obj.status:
|
||||
self.status_updated_at = timezone.now()
|
||||
|
||||
# Create preview image
|
||||
|
|
@ -375,11 +369,10 @@ class Checklist(models.Model):
|
|||
preview.save(image_io, format='JPEG')
|
||||
|
||||
# Create Image model and save it
|
||||
image_obj = Image(is_preview=True)
|
||||
image_obj = Image(is_preview=True, checklist_id=self.id)
|
||||
image_obj.image.save(name=f'{self.id}_preview.jpg',
|
||||
content=ContentFile(image_io.getvalue()),
|
||||
save=True)
|
||||
self.images.add(image_obj)
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import base64
|
||||
|
||||
from django.contrib.auth import authenticate
|
||||
from django.core.files.base import ContentFile
|
||||
from drf_extra_fields.fields import Base64ImageField
|
||||
from rest_framework import serializers
|
||||
|
||||
from store.exceptions import CRMException, InvalidCredentialsException
|
||||
from store.models import User, Checklist, GlobalSettings, Category, PaymentMethod, PromoCode, Image
|
||||
from store.models import User, Checklist, GlobalSettings, Category, PaymentMethod, Promocode, Image
|
||||
|
||||
|
||||
class LoginSerializer(serializers.Serializer):
|
||||
|
|
@ -44,12 +48,14 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class ImageSerializer(serializers.ModelSerializer):
|
||||
image = Base64ImageField()
|
||||
|
||||
class Meta:
|
||||
model = Image
|
||||
fields = ('image', )
|
||||
fields = ('image',)
|
||||
|
||||
|
||||
class OrderImageListSerializer(serializers.ListSerializer):
|
||||
class ChecklistImageListSerializer(serializers.ListSerializer):
|
||||
child = ImageSerializer()
|
||||
|
||||
def to_representation(self, data):
|
||||
|
|
@ -59,44 +65,54 @@ class OrderImageListSerializer(serializers.ListSerializer):
|
|||
|
||||
class ChecklistSerializer(serializers.ModelSerializer):
|
||||
id = serializers.CharField(read_only=True)
|
||||
managerid = serializers.CharField(source='manager.manager_id', required=False, allow_null=True)
|
||||
managerid = serializers.CharField(source='manager.manager_id', read_only=True)
|
||||
link = serializers.URLField(source='product_link', required=False)
|
||||
category = serializers.SlugRelatedField(slug_field='slug', queryset=Category.objects.all())
|
||||
image = OrderImageListSerializer(source='main_images')
|
||||
previewimage = serializers.ImageField(source='preview_image_url')
|
||||
|
||||
# TODO: choose from PromoCode table
|
||||
# image = Base64ImageField(source='images', many=True, queryset=Image.objects.all())
|
||||
previewimage = serializers.ImageField(source='preview_image_url', read_only=True)
|
||||
|
||||
# TODO: choose from Promocode table
|
||||
promo = serializers.CharField(source='promocode', required=False)
|
||||
|
||||
currency = serializers.SerializerMethodField('get_yuan_rate')
|
||||
curencycurency2 = serializers.DecimalField(source='price_yuan', max_digits=10, decimal_places=2)
|
||||
currency3 = serializers.DecimalField(source='price_rub', max_digits=10, decimal_places=2, read_only=True)
|
||||
chinadelivery = serializers.SerializerMethodField('get_delivery_price_CN')
|
||||
chinadelivery2 = serializers.DecimalField(source='delivery_price_CN_RU', max_digits=10, decimal_places=2, read_only=True)
|
||||
fullprice = serializers.DecimalField(source='full_price', max_digits=10, decimal_places=2)
|
||||
realprice = serializers.DecimalField(source='real_price', max_digits=10, decimal_places=2)
|
||||
comission = serializers.SerializerMethodField('get_comission')
|
||||
currency3 = serializers.DecimalField(source='price_rub', read_only=True, max_digits=10, decimal_places=2)
|
||||
chinadelivery = serializers.SerializerMethodField('get_delivery_price_CN', read_only=True)
|
||||
chinadelivery2 = serializers.DecimalField(source='delivery_price_CN_RU', read_only=True, max_digits=10,
|
||||
decimal_places=2)
|
||||
fullprice = serializers.DecimalField(source='full_price', read_only=True, max_digits=10, decimal_places=2)
|
||||
realprice = serializers.DecimalField(source='real_price', required=False, allow_null=True, max_digits=10,
|
||||
decimal_places=2)
|
||||
comission = serializers.SerializerMethodField('get_comission', read_only=True)
|
||||
|
||||
buyername = serializers.CharField(source='buyer_name')
|
||||
buyerphone = serializers.CharField(source='buyer_phone')
|
||||
tg = serializers.CharField(source='buyer_telegram')
|
||||
buyername = serializers.CharField(source='buyer_name', required=False, allow_null=True)
|
||||
buyerphone = serializers.CharField(source='buyer_phone', required=False, allow_null=True)
|
||||
tg = serializers.CharField(source='buyer_telegram', required=False, allow_null=True)
|
||||
|
||||
receivername = serializers.CharField(source='receiver_name')
|
||||
reveiverphone = serializers.CharField(source='receiver_phone')
|
||||
receivername = serializers.CharField(source='receiver_name', required=False, allow_null=True)
|
||||
reveiverphone = serializers.CharField(source='receiver_phone', required=False, allow_null=True)
|
||||
|
||||
paymenttype = serializers.SlugRelatedField(source='payment_method', slug_field='slug', queryset=PaymentMethod.objects.all())
|
||||
paymentproovement = serializers.ImageField(source='payment_proof')
|
||||
checkphoto = serializers.ImageField(source='cheque_photo')
|
||||
trackid = serializers.CharField(source='track_number')
|
||||
delivery = serializers.CharField(source='get_delivery_display')
|
||||
paymenttype = serializers.SlugRelatedField(source='payment_method', slug_field='slug',
|
||||
queryset=PaymentMethod.objects.all(),
|
||||
required=False, allow_null=True)
|
||||
paymentproovement = serializers.ImageField(source='payment_proof', required=False, allow_null=True)
|
||||
checkphoto = serializers.ImageField(source='cheque_photo', required=False, allow_null=True)
|
||||
trackid = serializers.CharField(source='poizon_tracking', required=False, allow_null=True)
|
||||
cdek_tracking = serializers.CharField(required=False, allow_null=True)
|
||||
delivery = serializers.CharField(source='get_delivery_display', required=False, allow_null=True)
|
||||
|
||||
startDate = serializers.DateTimeField(source='created_at')
|
||||
currentDate = serializers.DateTimeField(source='status_updated_at')
|
||||
startDate = serializers.DateTimeField(source='created_at', read_only=True)
|
||||
currentDate = serializers.DateTimeField(source='status_updated_at', read_only=True)
|
||||
|
||||
@staticmethod
|
||||
def get_yuan_rate(obj: Checklist):
|
||||
return GlobalSettings.load().yuan_rate
|
||||
|
||||
@staticmethod
|
||||
def get_image(obj: Checklist):
|
||||
return obj.images.all()
|
||||
|
||||
@staticmethod
|
||||
def get_delivery_price_CN(obj: Checklist):
|
||||
return GlobalSettings.load().delivery_price_CN
|
||||
|
|
@ -110,7 +126,7 @@ class ChecklistSerializer(serializers.ModelSerializer):
|
|||
fields = ('id', 'status', 'managerid', 'link',
|
||||
'category', 'subcategory',
|
||||
'brand', 'model', 'size',
|
||||
'image',
|
||||
# 'image',
|
||||
'previewimage',
|
||||
'currency', 'curencycurency2', 'currency3', 'chinadelivery', 'chinadelivery2', 'comission',
|
||||
'promo',
|
||||
|
|
@ -119,7 +135,7 @@ class ChecklistSerializer(serializers.ModelSerializer):
|
|||
'buyername', 'buyerphone', 'tg',
|
||||
'receivername', 'reveiverphone',
|
||||
'paymenttype', 'paymentproovement', 'checkphoto',
|
||||
'trackid', 'delivery',
|
||||
'trackid', 'cdek_tracking', 'delivery',
|
||||
'startDate', 'currentDate',
|
||||
)
|
||||
|
||||
|
|
@ -171,5 +187,5 @@ class PromocodeSerializer(serializers.ModelSerializer):
|
|||
nocomission = serializers.BooleanField(source='no_comission')
|
||||
|
||||
class Meta:
|
||||
model = PromoCode
|
||||
model = Promocode
|
||||
fields = ('name', 'discount', 'freedelivery', 'nocomission')
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ router = DefaultRouter()
|
|||
|
||||
# FIXME: renamed
|
||||
router.register(r'statistics', views.StatisticsAPI, basename='statistics')
|
||||
router.register(r'cdek', views.CDEKAPI, basename='cdek')
|
||||
|
||||
urlpatterns = [
|
||||
path("login/", views.LoginAPI.as_view()),
|
||||
|
|
|
|||
118
store/views.py
118
store/views.py
|
|
@ -1,20 +1,23 @@
|
|||
import calendar
|
||||
import json
|
||||
from collections import OrderedDict, defaultdict
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import login
|
||||
from django.db.models import F, Count, Q, Sum
|
||||
from django.db.models import F, Count, Q, Sum, Value, Subquery
|
||||
from django.utils import timezone
|
||||
from rest_framework import generics, permissions, mixins, status, viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
from cdek.api import CDEKClient
|
||||
from store.exceptions import CRMException
|
||||
from store.models import User, Checklist, GlobalSettings, Category, PaymentMethod, PromoCode
|
||||
from store.models import User, Checklist, GlobalSettings, Category, PaymentMethod, Promocode
|
||||
from store.serializers import (UserSerializer, LoginSerializer, ChecklistSerializer, GlobalSettingsYuanRateSerializer,
|
||||
CategorySerializer, GlobalSettingsPriceSerializer, PaymentMethodSerializer,
|
||||
PromocodeSerializer, GlobalSettingsPickupSerializer)
|
||||
from utils.permissions import ReadOnly
|
||||
|
||||
|
||||
class UserAPI(mixins.ListModelMixin, mixins.RetrieveModelMixin, generics.GenericAPIView):
|
||||
|
|
@ -53,8 +56,9 @@ class LoginAPI(generics.GenericAPIView):
|
|||
return Response(serializer.data)
|
||||
|
||||
|
||||
class ChecklistAPI(mixins.ListModelMixin, mixins.RetrieveModelMixin, generics.GenericAPIView):
|
||||
class ChecklistAPI(mixins.ListModelMixin, mixins.CreateModelMixin, mixins.RetrieveModelMixin, generics.GenericAPIView):
|
||||
serializer_class = ChecklistSerializer
|
||||
permission_classes = [IsAuthenticated | ReadOnly]
|
||||
lookup_field = 'id'
|
||||
filterset_fields = ['status', ]
|
||||
search_fields = ['id', 'track_id', 'buyer_phone', 'full_price']
|
||||
|
|
@ -76,6 +80,9 @@ class ChecklistAPI(mixins.ListModelMixin, mixins.RetrieveModelMixin, generics.Ge
|
|||
|
||||
return obj
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
return self.create(request, *args, **kwargs)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'id' in kwargs:
|
||||
return self.retrieve(request, *args, **kwargs)
|
||||
|
|
@ -129,8 +136,7 @@ class CategoryAPI(generics.GenericAPIView):
|
|||
'prices': GlobalSettingsPriceSerializer(global_settings).data,
|
||||
})
|
||||
|
||||
# FIXME: use PATCH method for updates
|
||||
def post(self, request, *args, **kwargs):
|
||||
def patch(self, request, *args, **kwargs):
|
||||
data = json.loads(request.body)
|
||||
if not all(k in data for k in ("category", "chinarush")):
|
||||
raise CRMException('category and chinarush is required')
|
||||
|
|
@ -146,8 +152,7 @@ class CategoryAPI(generics.GenericAPIView):
|
|||
class PricesAPI(generics.GenericAPIView):
|
||||
serializer_class = GlobalSettingsPriceSerializer
|
||||
|
||||
# FIXME: use PATCH method for updates
|
||||
def post(self, request, *args, **kwargs):
|
||||
def patch(self, request, *args, **kwargs):
|
||||
data = json.loads(request.body)
|
||||
|
||||
instance = GlobalSettings.load()
|
||||
|
|
@ -160,6 +165,7 @@ class PricesAPI(generics.GenericAPIView):
|
|||
|
||||
class PickupAPI(generics.GenericAPIView):
|
||||
serializer_class = GlobalSettingsPickupSerializer
|
||||
permission_classes = [IsAuthenticated | ReadOnly]
|
||||
|
||||
def get_object(self):
|
||||
return GlobalSettings.load()
|
||||
|
|
@ -193,8 +199,7 @@ class PaymentMethodsAPI(generics.GenericAPIView):
|
|||
|
||||
return Response(data)
|
||||
|
||||
# FIXME: use PATCH method for updates
|
||||
def post(self, request, *args, **kwargs):
|
||||
def patch(self, request, *args, **kwargs):
|
||||
data = json.loads(request.body)
|
||||
if 'type' not in data:
|
||||
raise CRMException('type is required')
|
||||
|
|
@ -212,7 +217,7 @@ class PromoCodeAPI(mixins.CreateModelMixin, generics.GenericAPIView):
|
|||
lookup_field = 'name'
|
||||
|
||||
def get_queryset(self):
|
||||
return PromoCode.objects.all()
|
||||
return Promocode.objects.all()
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
qs = self.get_queryset()
|
||||
|
|
@ -245,8 +250,6 @@ class StatisticsAPI(viewsets.GenericViewSet):
|
|||
global_settings = GlobalSettings.load()
|
||||
yuan_rate = global_settings.yuan_rate
|
||||
|
||||
completed_filter = Q(status=Checklist.Status.COMPLETED)
|
||||
|
||||
# Prepare query to collect the stats
|
||||
qs = self.get_queryset() \
|
||||
.annotate_price_rub() \
|
||||
|
|
@ -307,51 +310,72 @@ class StatisticsAPI(viewsets.GenericViewSet):
|
|||
|
||||
return Response(result)
|
||||
|
||||
# TODO: implement stats_by_clients
|
||||
@action(url_path='clients', detail=False, methods=['get'])
|
||||
def stats_by_clients(self, request, *args, **kwargs):
|
||||
def _create_stats(data: dict):
|
||||
return {
|
||||
"moreone": data.get('moreone', 0),
|
||||
"moretwo": data.get('moretwo', 0),
|
||||
"morethree": data.get('morethree', 0),
|
||||
"morefour": data.get('morefour', 0),
|
||||
"morefive": data.get('morefive', 0),
|
||||
"moreten": data.get('moreten', 0),
|
||||
"moretwentyfive": data.get('moretwentyfive', 0),
|
||||
"morefifty": data.get('morefifty', 0),
|
||||
}
|
||||
options = {
|
||||
"moreone": 1,
|
||||
"moretwo": 2,
|
||||
"morethree": 3,
|
||||
"morefour": 4,
|
||||
"morefive": 5,
|
||||
"moreten": 10,
|
||||
"moretwentyfive": 25,
|
||||
"morefifty": 50,
|
||||
}
|
||||
|
||||
def _filter_for_count(count):
|
||||
return Count('buyer_phone',
|
||||
filter=Q(buyer_phone__in=Checklist.objects.values('buyer_phone')
|
||||
.annotate(total_orders=Count('id'))
|
||||
.filter(total_orders__gt=count)
|
||||
.values('buyer_phone')
|
||||
))
|
||||
def _create_empty_stats():
|
||||
return {k: set() for k in options.keys()}
|
||||
|
||||
qs = self.get_queryset() \
|
||||
.values('month') \
|
||||
.annotate(
|
||||
moreone=_filter_for_count(1),
|
||||
moretwo=_filter_for_count(2),
|
||||
morethree=_filter_for_count(3),
|
||||
morefour=_filter_for_count(4),
|
||||
morefive=_filter_for_count(5),
|
||||
moreten=_filter_for_count(10),
|
||||
moretwentyfive=_filter_for_count(25),
|
||||
morefifty=_filter_for_count(50),
|
||||
)
|
||||
.filter(buyer_phone__isnull=False) \
|
||||
.values('month', 'buyer_phone') \
|
||||
.annotate(order_count=Count('id')) \
|
||||
.filter(order_count__gt=1) \
|
||||
.order_by('month')
|
||||
|
||||
result = {}
|
||||
# Add empty stats
|
||||
for i in range(1, 13):
|
||||
month = calendar.month_name[i]
|
||||
result[month] = _create_stats(dict())
|
||||
month_name = calendar.month_name[i]
|
||||
result[month_name] = _create_empty_stats()
|
||||
|
||||
# Add actual stats
|
||||
for stat in qs:
|
||||
month = calendar.month_name[stat['month']]
|
||||
result[month] = _create_stats(stat)
|
||||
month_name = calendar.month_name[stat['month']]
|
||||
|
||||
for key, size in reversed(options.items()):
|
||||
if stat['order_count'] > size:
|
||||
result[month_name][key].add(stat['buyer_phone'])
|
||||
break
|
||||
|
||||
return Response(result)
|
||||
|
||||
|
||||
class CDEKAPI(viewsets.GenericViewSet):
|
||||
client = CDEKClient(settings.CDEK_CLIENT_ID, settings.CDEK_CLIENT_SECRET)
|
||||
|
||||
@action(url_path='orders', detail=False, methods=['get'])
|
||||
def get_order_info(self, request, *args, **kwargs):
|
||||
im_number = request.query_params.get('im_number')
|
||||
if not im_number:
|
||||
raise CRMException('im_number is required')
|
||||
|
||||
r = self.client.get_order_info(im_number)
|
||||
return Response(r.json())
|
||||
|
||||
@action(url_path='orders', detail=False, methods=['post'])
|
||||
def create_order(self, request, *args, **kwargs):
|
||||
order_data = request.data
|
||||
if not order_data:
|
||||
raise CRMException('json data is required')
|
||||
|
||||
r = self.client.create_order(order_data)
|
||||
return Response(r.json())
|
||||
|
||||
@action(url_path='calculator/tariff', detail=False, methods=['post'])
|
||||
def calculate_tariff(self, request, *args, **kwargs):
|
||||
data = request.data
|
||||
if not data:
|
||||
raise CRMException('json data is required')
|
||||
r = self.client.calculate_tariff(data)
|
||||
return Response(r.json())
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
from rest_framework import permissions
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.permissions import BasePermission, SAFE_METHODS
|
||||
|
||||
|
||||
class CsrfExemptSessionAuthentication(SessionAuthentication):
|
||||
def enforce_csrf(self, request):
|
||||
# To not perform the csrf check previously happening
|
||||
return
|
||||
|
||||
|
||||
class ReadOnly(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
return request.method in SAFE_METHODS
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user