252 lines
9.1 KiB
Python
252 lines
9.1 KiB
Python
from django.db.transaction import atomic
|
|
from drf_extra_fields.fields import Base64ImageField
|
|
from rest_framework import serializers
|
|
|
|
from bonus_program.models import BonusProgram
|
|
from account.serializers import UserSerializer
|
|
from utils.exceptions import CRMException
|
|
from store.models import Checklist, Category, PaymentMethod, Promocode, Image, Gift
|
|
from store.utils import get_primary_key_related_model
|
|
from poizonstore.utils import PriceField
|
|
|
|
|
|
class ImageSerializer(serializers.ModelSerializer):
|
|
image = Base64ImageField()
|
|
|
|
class Meta:
|
|
model = Image
|
|
fields = ('image',)
|
|
|
|
|
|
class ImageListSerializer(serializers.ListSerializer):
|
|
child = ImageSerializer()
|
|
|
|
def to_internal_value(self, data):
|
|
if isinstance(data, list):
|
|
data = [{"image": x} for x in data]
|
|
return super().to_internal_value(data)
|
|
|
|
def to_representation(self, data):
|
|
images = super().to_representation(data)
|
|
return [image['image'] for image in images]
|
|
|
|
|
|
class CategoryChecklistSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = Category
|
|
fields = ('id', 'name')
|
|
|
|
|
|
class CategorySerializer(serializers.ModelSerializer):
|
|
chinarush = PriceField(source='delivery_price_CN_RU')
|
|
|
|
class Meta:
|
|
model = Category
|
|
fields = ('id', 'name', 'chinarush', 'commission')
|
|
|
|
|
|
class CategoryFullSerializer(CategorySerializer):
|
|
children = serializers.SerializerMethodField()
|
|
|
|
def get_children(self, obj):
|
|
return CategoryFullSerializer(obj.get_children(), many=True).data
|
|
|
|
class Meta:
|
|
model = CategorySerializer.Meta.model
|
|
fields = CategorySerializer.Meta.fields + ('children',)
|
|
|
|
|
|
class GiftSerializer(serializers.ModelSerializer):
|
|
image = Base64ImageField(required=False, allow_null=True)
|
|
min_price = PriceField()
|
|
|
|
class Meta:
|
|
model = Gift
|
|
fields = ('id', 'name', 'image', 'min_price', 'available_count')
|
|
|
|
|
|
class ChecklistSerializer(serializers.ModelSerializer):
|
|
id = serializers.CharField(read_only=True)
|
|
manager_id = serializers.PrimaryKeyRelatedField(read_only=True, allow_null=True)
|
|
link = serializers.URLField(source='product_link', required=False)
|
|
category = get_primary_key_related_model(CategoryChecklistSerializer, required=False, allow_null=True)
|
|
|
|
size = serializers.CharField(required=False, allow_null=True)
|
|
|
|
image = ImageListSerializer(source='main_images', required=False)
|
|
preview_image_url = serializers.ImageField(read_only=True)
|
|
|
|
promocode = serializers.SlugRelatedField(slug_field='name', queryset=Promocode.objects.active(),
|
|
required=False, allow_null=True)
|
|
|
|
use_bonuses = serializers.BooleanField(write_only=True, default=False)
|
|
gift = get_primary_key_related_model(GiftSerializer, required=False, allow_null=True)
|
|
|
|
yuan_rate = PriceField(read_only=True)
|
|
price_yuan = PriceField(required=False)
|
|
price_rub = serializers.IntegerField(read_only=True)
|
|
|
|
delivery_price_CN = PriceField(read_only=True)
|
|
delivery_price_CN_RU = PriceField(read_only=True)
|
|
|
|
full_price = PriceField(read_only=True)
|
|
real_price = PriceField(required=False, allow_null=True)
|
|
|
|
commission_rub = PriceField(read_only=True)
|
|
|
|
customer = get_primary_key_related_model(UserSerializer, required=False, allow_null=True)
|
|
|
|
receiver_name = serializers.CharField(required=False, allow_null=True)
|
|
receiver_phone = serializers.CharField(required=False, allow_null=True)
|
|
|
|
is_split_payment = serializers.BooleanField(required=False)
|
|
payment_method = serializers.SlugRelatedField(slug_field='slug',
|
|
queryset=PaymentMethod.objects.all(),
|
|
required=False, allow_null=True)
|
|
payment_proof = Base64ImageField(required=False, allow_null=True)
|
|
split_payment_proof = Base64ImageField(required=False, allow_null=True)
|
|
receipt = Base64ImageField(required=False, allow_null=True)
|
|
poizon_tracking = serializers.CharField(required=False, allow_null=True)
|
|
cdek_tracking = serializers.CharField(required=False, allow_null=True)
|
|
delivery = serializers.ChoiceField(choices=Checklist.DeliveryType.CHOICES, required=False, allow_null=True)
|
|
delivery_display = serializers.CharField(source='get_delivery_display', read_only=True)
|
|
|
|
created_at = serializers.DateTimeField(read_only=True)
|
|
status_updated_at = serializers.DateTimeField(read_only=True)
|
|
|
|
def _collect_images_by_fields(self, validated_data):
|
|
images = {}
|
|
for k in ('main_images',):
|
|
if k in validated_data:
|
|
images[k] = validated_data.pop(k)
|
|
|
|
return images
|
|
|
|
def _create_main_images(self, instance, images):
|
|
if images is None:
|
|
return
|
|
|
|
img_objs = [Image(image=img['image'], type=Image.DEFAULT) for img in images]
|
|
img_objs = Image.objects.bulk_create(img_objs)
|
|
instance.images.set(img_objs)
|
|
instance.generate_preview(next(iter(img_objs), None))
|
|
|
|
@atomic
|
|
def create(self, validated_data):
|
|
images = self._collect_images_by_fields(validated_data)
|
|
|
|
# Managers can create orders with arbitrary customers
|
|
# Client orders are created with client's account
|
|
user = self.context['request'].user
|
|
if not user.is_manager or validated_data.get('customer') is None:
|
|
validated_data['customer'] = user
|
|
|
|
use_bonuses = validated_data.pop('use_bonuses')
|
|
|
|
instance = super().create(validated_data)
|
|
self._create_main_images(instance, images.get('main_images'))
|
|
|
|
if use_bonuses:
|
|
BonusProgram.spend_bonuses(order=instance)
|
|
|
|
return instance
|
|
|
|
def update(self, instance, validated_data):
|
|
images = self._collect_images_by_fields(validated_data)
|
|
|
|
# Perform update
|
|
instance: Checklist = super().update(instance, validated_data)
|
|
|
|
self._create_main_images(instance, images.get('main_images'))
|
|
|
|
# Invalidate prefetched images
|
|
delattr(instance, '_images')
|
|
|
|
if instance.status == Checklist.Status.NEW:
|
|
has_payment_info = instance.payment_proof is not None and instance.payment_method is not None
|
|
if has_payment_info:
|
|
instance.status = Checklist.Status.PAYMENT
|
|
instance.save()
|
|
|
|
return instance
|
|
|
|
@staticmethod
|
|
def get_image(obj: Checklist):
|
|
return obj.images.all()
|
|
|
|
class Meta:
|
|
model = Checklist
|
|
fields = ('id', 'status', 'manager_id', 'link',
|
|
'category',
|
|
'brand', 'model', 'size',
|
|
'image',
|
|
'preview_image_url',
|
|
'yuan_rate', 'price_yuan', 'price_rub', 'delivery_price_CN', 'delivery_price_CN_RU', 'commission_rub',
|
|
'promocode', 'gift', 'use_bonuses', 'bonus_used',
|
|
'comment',
|
|
'full_price', 'real_price',
|
|
'customer',
|
|
'receiver_name', 'receiver_phone',
|
|
'is_split_payment', 'payment_method', 'payment_proof', 'split_payment_proof', 'split_accepted', 'receipt',
|
|
'poizon_tracking', 'cdek_tracking', 'cdek_barcode_pdf', 'delivery', 'delivery_display',
|
|
'created_at', 'status_updated_at', 'buy_time_remaining'
|
|
)
|
|
|
|
|
|
class ClientChecklistSerializerMixin:
|
|
def validate(self, attrs):
|
|
gift = attrs.get('gift')
|
|
if gift is not None:
|
|
if self.instance.price_yuan < gift.min_price:
|
|
raise CRMException("Can't add gift: price of order < min_price of gift")
|
|
|
|
if gift.available_count == 0:
|
|
raise CRMException("Gift is not available")
|
|
|
|
return attrs
|
|
|
|
|
|
class ClientCreateChecklistSerializer(ClientChecklistSerializerMixin, ChecklistSerializer):
|
|
status = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = ChecklistSerializer.Meta.model
|
|
fields = ChecklistSerializer.Meta.fields
|
|
writable_fields = {
|
|
'link',
|
|
'brand', 'model', 'size', 'category',
|
|
'price_yuan', 'use_bonuses',
|
|
'comment',
|
|
}
|
|
read_only_fields = tuple(set(ChecklistSerializer.Meta.fields) - writable_fields)
|
|
|
|
def get_status(self, obj):
|
|
return Checklist.Status.DRAFT
|
|
|
|
|
|
class ClientUpdateChecklistSerializer(ClientChecklistSerializerMixin, ChecklistSerializer):
|
|
class Meta:
|
|
model = ChecklistSerializer.Meta.model
|
|
fields = ChecklistSerializer.Meta.fields
|
|
|
|
writable_fields = {
|
|
'comment',
|
|
'payment_proof', 'payment_method',
|
|
'delivery',
|
|
'receiver_name', 'receiver_phone',
|
|
'gift', 'cdek_barcode_pdf'
|
|
}
|
|
read_only_fields = tuple(set(ChecklistSerializer.Meta.fields) - writable_fields)
|
|
|
|
|
|
class PaymentMethodSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = PaymentMethod
|
|
fields = ('slug', 'name', 'requisites', 'cardnumber')
|
|
|
|
|
|
class PromocodeSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = Promocode
|
|
fields = ('id', 'name', 'discount', 'free_delivery', 'no_comission', 'is_active')
|